vid_sunx.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // vid_x.c -- general x video driver
  16. #define _BSD
  17. #include <sys/time.h>
  18. #include <sys/types.h>
  19. #include <unistd.h>
  20. #include <signal.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <sys/ipc.h>
  25. #include <sys/shm.h>
  26. #include <X11/Xlib.h>
  27. #include <X11/Xutil.h>
  28. #include <X11/Xatom.h>
  29. #include <X11/keysym.h>
  30. #include <X11/extensions/XShm.h>
  31. #include "quakedef.h"
  32. #include "d_local.h"
  33. cvar_t m_filter = {"m_filter","0", true};
  34. qboolean mouse_avail;
  35. int mouse_buttons=3;
  36. int mouse_oldbuttonstate;
  37. int mouse_buttonstate;
  38. float mouse_x, mouse_y;
  39. float old_mouse_x, old_mouse_y;
  40. int p_mouse_x;
  41. int p_mouse_y;
  42. qboolean mouse_grabbed = false; // we grab it when console is up
  43. int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
  44. byte *VGA_pagebase;
  45. // The following X property format is defined in Motif 1.1's
  46. // Xm/MwmUtils.h, but QUAKE should not depend on that header
  47. // file. Note: Motif 1.2 expanded this structure with
  48. // uninteresting fields (to QUAKE) so just stick with the
  49. // smaller Motif 1.1 structure.
  50. #define MWM_HINTS_DECORATIONS 2
  51. typedef struct
  52. {
  53. long flags;
  54. long functions;
  55. long decorations;
  56. long input_mode;
  57. } MotifWmHints;
  58. #define MAX_COLUMN_SIZE 11
  59. #define MAX_MODEDESCS (MAX_COLUMN_SIZE*3)
  60. typedef struct
  61. {
  62. int modenum;
  63. int iscur;
  64. char desc[256];
  65. } modedesc_t;
  66. extern void M_Menu_Options_f (void);
  67. extern void M_Print (int cx, int cy, char *str);
  68. extern void M_PrintWhite (int cx, int cy, char *str);
  69. extern void M_DrawCharacter (int cx, int line, int num);
  70. extern void M_DrawTransPic (int x, int y, qpic_t *pic);
  71. extern void M_DrawPic (int x, int y, qpic_t *pic);
  72. extern int sb_updates;
  73. extern int x_root, y_root; // root window relative mouse coords
  74. typedef struct
  75. {
  76. int input;
  77. int output;
  78. } keymap_t;
  79. viddef_t vid; // global video state
  80. unsigned short d_8to16table[256];
  81. int num_shades=32;
  82. int d_con_indirect = 0;
  83. int vid_buffersize;
  84. #define STD_EVENT_MASK \
  85. ( KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
  86. PointerMotionMask | EnterWindowMask | LeaveWindowMask | VisibilityChangeMask | \
  87. ExposureMask | StructureNotifyMask )
  88. qboolean x_fullscreen = true;
  89. Display *x_disp = NULL;
  90. int x_screen, x_screen_width, x_screen_height;
  91. int x_center_width, x_center_height;
  92. int x_std_event_mask = STD_EVENT_MASK;
  93. Window x_win, x_root_win;
  94. qboolean mouse_in_window = false;
  95. int global_dx, global_dy;
  96. static qboolean doShm;
  97. static Colormap x_cmap;
  98. static GC x_gc;
  99. static Visual *x_vis;
  100. static XVisualInfo *x_visinfo;
  101. static Atom aHints = 0;
  102. static Atom aWMDelete = 0;
  103. static int x_shmeventtype;
  104. //static XShmSegmentInfo x_shminfo;
  105. static qboolean oktodraw = false;
  106. int XShmQueryExtension(Display *);
  107. int XShmGetEventBase(Display *);
  108. int current_framebuffer;
  109. static XImage *x_framebuffer[2] = { 0, 0 };
  110. static XShmSegmentInfo x_shminfo[2];
  111. static int verbose=1;
  112. static byte current_palette[768];
  113. typedef unsigned short PIXEL16;
  114. typedef unsigned long PIXEL24;
  115. static PIXEL16 st2d_8to16table[256];
  116. static PIXEL24 st2d_8to24table[256];
  117. static int shiftmask_fl=0;
  118. static long r_shift,g_shift,b_shift;
  119. static unsigned long r_mask,g_mask,b_mask;
  120. void shiftmask_init()
  121. {
  122. unsigned int x;
  123. r_mask=x_vis->red_mask;
  124. g_mask=x_vis->green_mask;
  125. b_mask=x_vis->blue_mask;
  126. for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
  127. for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
  128. for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
  129. shiftmask_fl=1;
  130. }
  131. PIXEL16 xlib_rgb16(int r,int g,int b)
  132. {
  133. PIXEL16 p;
  134. if(shiftmask_fl==0) shiftmask_init();
  135. p=0;
  136. if(r_shift>0) {
  137. p=(r<<(r_shift))&r_mask;
  138. } else if(r_shift<0) {
  139. p=(r>>(-r_shift))&r_mask;
  140. } else p|=(r&r_mask);
  141. if(g_shift>0) {
  142. p|=(g<<(g_shift))&g_mask;
  143. } else if(g_shift<0) {
  144. p|=(g>>(-g_shift))&g_mask;
  145. } else p|=(g&g_mask);
  146. if(b_shift>0) {
  147. p|=(b<<(b_shift))&b_mask;
  148. } else if(b_shift<0) {
  149. p|=(b>>(-b_shift))&b_mask;
  150. } else p|=(b&b_mask);
  151. return p;
  152. }
  153. PIXEL24 xlib_rgb24(int r,int g,int b)
  154. {
  155. PIXEL24 p;
  156. if(shiftmask_fl==0) shiftmask_init();
  157. p=0;
  158. if(r_shift>0) {
  159. p=(r<<(r_shift))&r_mask;
  160. } else if(r_shift<0) {
  161. p=(r>>(-r_shift))&r_mask;
  162. } else p|=(r&r_mask);
  163. if(g_shift>0) {
  164. p|=(g<<(g_shift))&g_mask;
  165. } else if(g_shift<0) {
  166. p|=(g>>(-g_shift))&g_mask;
  167. } else p|=(g&g_mask);
  168. if(b_shift>0) {
  169. p|=(b<<(b_shift))&b_mask;
  170. } else if(b_shift<0) {
  171. p|=(b>>(-b_shift))&b_mask;
  172. } else p|=(b&b_mask);
  173. return p;
  174. }
  175. void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
  176. {
  177. int xi,yi;
  178. unsigned char *src;
  179. PIXEL16 *dest;
  180. register int count, n;
  181. if( (x<0)||(y<0) )return;
  182. for (yi = y; yi < (y+height); yi++) {
  183. src = &framebuf->data [yi * framebuf->bytes_per_line];
  184. // Duff's Device
  185. count = width;
  186. n = (count + 7) / 8;
  187. dest = ((PIXEL16 *)src) + x+width - 1;
  188. src += x+width - 1;
  189. switch (count % 8) {
  190. case 0: do { *dest-- = st2d_8to16table[*src--];
  191. case 7: *dest-- = st2d_8to16table[*src--];
  192. case 6: *dest-- = st2d_8to16table[*src--];
  193. case 5: *dest-- = st2d_8to16table[*src--];
  194. case 4: *dest-- = st2d_8to16table[*src--];
  195. case 3: *dest-- = st2d_8to16table[*src--];
  196. case 2: *dest-- = st2d_8to16table[*src--];
  197. case 1: *dest-- = st2d_8to16table[*src--];
  198. } while (--n > 0);
  199. }
  200. // for(xi = (x+width-1); xi >= x; xi--) {
  201. // dest[xi] = st2d_8to16table[src[xi]];
  202. // }
  203. }
  204. }
  205. void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
  206. {
  207. int xi,yi;
  208. unsigned char *src;
  209. PIXEL24 *dest;
  210. register int count, n;
  211. if( (x<0)||(y<0) )return;
  212. for (yi = y; yi < (y+height); yi++) {
  213. src = &framebuf->data [yi * framebuf->bytes_per_line];
  214. // Duff's Device
  215. count = width;
  216. n = (count + 7) / 8;
  217. dest = ((PIXEL24 *)src) + x+width - 1;
  218. src += x+width - 1;
  219. switch (count % 8) {
  220. case 0: do { *dest-- = st2d_8to24table[*src--];
  221. case 7: *dest-- = st2d_8to24table[*src--];
  222. case 6: *dest-- = st2d_8to24table[*src--];
  223. case 5: *dest-- = st2d_8to24table[*src--];
  224. case 4: *dest-- = st2d_8to24table[*src--];
  225. case 3: *dest-- = st2d_8to24table[*src--];
  226. case 2: *dest-- = st2d_8to24table[*src--];
  227. case 1: *dest-- = st2d_8to24table[*src--];
  228. } while (--n > 0);
  229. }
  230. // for(xi = (x+width-1); xi >= x; xi--) {
  231. // dest[xi] = st2d_8to16table[src[xi]];
  232. // }
  233. }
  234. }
  235. /*
  236. ================
  237. D_BeginDirectRect
  238. ================
  239. */
  240. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  241. {
  242. // direct drawing of the "accessing disk" icon isn't supported under Nextstep
  243. }
  244. /*
  245. ================
  246. D_EndDirectRect
  247. ================
  248. */
  249. void D_EndDirectRect (int x, int y, int width, int height)
  250. {
  251. // direct drawing of the "accessing disk" icon isn't supported under Nextstep
  252. }
  253. /*
  254. =================
  255. VID_Gamma_f
  256. Keybinding command
  257. =================
  258. */
  259. byte vid_gamma[256];
  260. void VID_Gamma_f (void)
  261. {
  262. float g, f, inf;
  263. int i;
  264. if (Cmd_Argc () == 2)
  265. {
  266. g = Q_atof (Cmd_Argv(1));
  267. for (i=0 ; i<255 ; i++)
  268. {
  269. f = pow ((i+1)/256.0, g);
  270. inf = f*255 + 0.5;
  271. if (inf < 0)
  272. inf = 0;
  273. if (inf > 255)
  274. inf = 255;
  275. vid_gamma[i] = inf;
  276. }
  277. VID_SetPalette (current_palette);
  278. vid.recalc_refdef = 1; // force a surface cache flush
  279. }
  280. }
  281. // ========================================================================
  282. // Tragic death handler
  283. // ========================================================================
  284. void TragicDeath(int signal_num)
  285. {
  286. //XAutoRepeatOn(x_disp);
  287. VID_Shutdown();
  288. Sys_Error("This death brought to you by the number %d\n", signal_num);
  289. }
  290. // ========================================================================
  291. // makes a null cursor
  292. // ========================================================================
  293. static Cursor CreateNullCursor(Display *display, Window root)
  294. {
  295. Pixmap cursormask;
  296. XGCValues xgc;
  297. GC gc;
  298. XColor dummycolour;
  299. Cursor cursor;
  300. cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
  301. xgc.function = GXclear;
  302. gc = XCreateGC(display, cursormask, GCFunction, &xgc);
  303. XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
  304. dummycolour.pixel = 0;
  305. dummycolour.red = 0;
  306. dummycolour.flags = 04;
  307. cursor = XCreatePixmapCursor(display, cursormask, cursormask,
  308. &dummycolour,&dummycolour, 0,0);
  309. XFreePixmap(display,cursormask);
  310. XFreeGC(display,gc);
  311. return cursor;
  312. }
  313. void ResetFrameBuffer(void)
  314. {
  315. int mem;
  316. int pwidth;
  317. if (x_framebuffer[0])
  318. {
  319. Z_Free(x_framebuffer[0]->data);
  320. // Z_Free(d_pzbuffer);
  321. free(x_framebuffer[0]);
  322. }
  323. pwidth = x_visinfo->depth / 8;
  324. if (pwidth == 3) pwidth = 4;
  325. mem = ((vid.width*pwidth+3)&~3) * vid.height;
  326. // d_pzbuffer = (unsigned short *) Z_Malloc(vid.width*vid.height*
  327. // sizeof(*d_pzbuffer));
  328. d_pzbuffer = (short *) Hunk_HighAllocName(vid.width*vid.height*
  329. sizeof(*d_pzbuffer), "zbuff");
  330. x_framebuffer[0] = XCreateImage( x_disp,
  331. x_vis,
  332. x_visinfo->depth,
  333. ZPixmap,
  334. 0,
  335. Z_Malloc(mem),
  336. vid.width, vid.height,
  337. 32,
  338. 0);
  339. if (!x_framebuffer[0])
  340. Sys_Error("VID: XCreateImage failed\n");
  341. }
  342. void ResetSharedFrameBuffers(void)
  343. {
  344. int size;
  345. int key;
  346. int minsize = getpagesize();
  347. int frm;
  348. // if (d_pzbuffer)
  349. // Z_Free(d_pzbuffer);
  350. d_pzbuffer = Hunk_HighAllocName(vid.width*vid.height*sizeof(*d_pzbuffer),"zbuff");
  351. for (frm=0 ; frm<2 ; frm++)
  352. {
  353. // free up old frame buffer memory
  354. if (x_framebuffer[frm])
  355. {
  356. XShmDetach(x_disp, &x_shminfo[frm]);
  357. free(x_framebuffer[frm]);
  358. shmdt(x_shminfo[frm].shmaddr);
  359. }
  360. // create the image
  361. x_framebuffer[frm] = XShmCreateImage( x_disp,
  362. x_vis,
  363. x_visinfo->depth,
  364. ZPixmap,
  365. 0,
  366. &x_shminfo[frm],
  367. vid.width,
  368. vid.height );
  369. // grab shared memory
  370. size = x_framebuffer[frm]->bytes_per_line
  371. * x_framebuffer[frm]->height;
  372. if (size < minsize)
  373. Sys_Error("VID: Window must use at least %d bytes\n", minsize);
  374. key = random();
  375. x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
  376. if (x_shminfo[frm].shmid==-1)
  377. Sys_Error("VID: Could not get any shared memory\n");
  378. // attach to the shared memory segment
  379. x_shminfo[frm].shmaddr =
  380. (void *) shmat(x_shminfo[frm].shmid, 0, 0);
  381. printf("VID: shared memory id=%d, addr=0x%x\n", x_shminfo[frm].shmid,
  382. (int) x_shminfo[frm].shmaddr);
  383. x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
  384. // get the X server to attach to it
  385. if (!XShmAttach(x_disp, &x_shminfo[frm]))
  386. Sys_Error("VID: XShmAttach() failed\n");
  387. XSync(x_disp, 0);
  388. shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
  389. }
  390. }
  391. void VID_MenuDraw( void )
  392. {
  393. qpic_t *p;
  394. char *ptr;
  395. int i, j, column, row, dup;
  396. char temp[100];
  397. p = Draw_CachePic ("gfx/vidmodes.lmp");
  398. M_DrawPic ( (320-p->width)/2, 4, p);
  399. M_Print (4*8, 36 + MAX_COLUMN_SIZE * 8 + 8, "Video mode switching unavailable");
  400. M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, "Press any key...");
  401. }
  402. void VID_MenuKey( int key ) { M_Menu_Options_f (); }
  403. // Called at startup to set up translation tables, takes 256 8 bit RGB values
  404. // the palette data will go away after the call, so it must be copied off if
  405. // the video driver will need it again
  406. byte surfcache[1024*1024];
  407. //
  408. // VID_SetWindowTitle - set the window and icon titles
  409. //
  410. void VID_SetWindowTitle( Window win, char *pszName )
  411. {
  412. XTextProperty textprop;
  413. XWMHints *wmHints;
  414. // Setup ICCCM properties
  415. textprop.value = (unsigned char *)pszName;
  416. textprop.encoding = XA_STRING;
  417. textprop.format = 8;
  418. textprop.nitems = strlen(pszName);
  419. wmHints = XAllocWMHints();
  420. wmHints->initial_state = NormalState;
  421. wmHints->flags = StateHint;
  422. XSetWMProperties( x_disp, win, &textprop, &textprop,
  423. // Only put WM_COMMAND property on first window.
  424. com_argv, com_argc, NULL, NULL, NULL );
  425. XFree( wmHints );
  426. aWMDelete = XInternAtom( x_disp, "WM_DELETE_WINDOW", False );
  427. XSetWMProtocols( x_disp, win, &aWMDelete, 1 );
  428. }
  429. //
  430. // VID_FullScreen - open the window in full screen mode
  431. //
  432. qboolean VID_FullScreen( Window win )
  433. {
  434. MotifWmHints hints;
  435. XWindowChanges changes;
  436. aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 );
  437. if (aHints == None)
  438. {
  439. Con_Printf( "Could not intern X atom for _MOTIF_WM_HINTS." );
  440. return( false );
  441. }
  442. hints.flags = MWM_HINTS_DECORATIONS;
  443. hints.decorations = 0; // Absolutely no decorations.
  444. XChangeProperty( x_disp, win, aHints, aHints, 32, PropModeReplace, (unsigned char *)&hints, 4 );
  445. changes.x = 0;
  446. changes.y = 0;
  447. changes.width = x_screen_width;
  448. changes.height = x_screen_height;
  449. changes.stack_mode = TopIf;
  450. XConfigureWindow( x_disp, win, CWX | CWY | CWWidth | CWHeight | CWStackMode, &changes);
  451. return( true );
  452. }
  453. void VID_Init (unsigned char *palette)
  454. {
  455. int pnum, i;
  456. XVisualInfo template;
  457. int num_visuals;
  458. int template_mask;
  459. Cmd_AddCommand ("gamma", VID_Gamma_f);
  460. for (i=0 ; i<256 ; i++)
  461. vid_gamma[i] = i;
  462. vid.width = 320;
  463. vid.height = 200;
  464. vid.aspect = 1.0;
  465. vid.numpages = 2;
  466. vid.colormap = host_colormap;
  467. vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  468. //vid.cbits = VID_CBITS;
  469. //vid.grades = VID_GRADES;
  470. srandom(getpid());
  471. verbose=COM_CheckParm("-verbose");
  472. // open the display
  473. x_disp = XOpenDisplay(0);
  474. if (!x_disp)
  475. {
  476. if (getenv("DISPLAY"))
  477. Sys_Error("VID: Could not open display [%s]\n",
  478. getenv("DISPLAY"));
  479. else
  480. Sys_Error("VID: Could not open local display\n");
  481. }
  482. x_screen = XDefaultScreen( x_disp );
  483. x_screen_width = WidthOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
  484. x_screen_height = HeightOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
  485. x_center_width = x_screen_width/2;
  486. x_center_height = x_screen_height/2;
  487. Con_Printf( "Using screen %d: %dx%d\n", x_screen, x_screen_width, x_screen_height );
  488. x_root_win = XRootWindow( x_disp, x_screen );
  489. // catch signals so i can turn on auto-repeat
  490. // we never run full-screen, so no auto-repeat nukage
  491. if (0)
  492. {
  493. struct sigaction sa;
  494. sigaction(SIGINT, 0, &sa);
  495. sa.sa_handler = TragicDeath;
  496. sigaction(SIGINT, &sa, 0);
  497. sigaction(SIGTERM, &sa, 0);
  498. }
  499. //XAutoRepeatOff(x_disp);
  500. // for debugging only
  501. // XSynchronize(x_disp, True);
  502. // check for command-line window size
  503. if ((pnum=COM_CheckParm("-winsize")))
  504. {
  505. if (pnum >= com_argc-2)
  506. Sys_Error("VID: -winsize <width> <height>\n");
  507. vid.width = Q_atoi(com_argv[pnum+1]);
  508. vid.height = Q_atoi(com_argv[pnum+2]);
  509. if (!vid.width || !vid.height)
  510. Sys_Error("VID: Bad window width/height\n");
  511. }
  512. template_mask = 0;
  513. // specify a visual id
  514. if ((pnum=COM_CheckParm("-visualid")))
  515. {
  516. if (pnum >= com_argc-1)
  517. Sys_Error("VID: -visualid <id#>\n");
  518. template.visualid = Q_atoi(com_argv[pnum+1]);
  519. template_mask = VisualIDMask;
  520. }
  521. // If not specified, use default visual
  522. else
  523. {
  524. int screen;
  525. screen = XDefaultScreen(x_disp);
  526. template.visualid =
  527. XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
  528. template_mask = VisualIDMask;
  529. }
  530. // pick a visual- warn if more than one was available
  531. x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
  532. if (num_visuals > 1)
  533. {
  534. printf("Found more than one visual id at depth %d:\n", template.depth);
  535. for (i=0 ; i<num_visuals ; i++)
  536. printf(" -visualid %d\n", (int)(x_visinfo[i].visualid));
  537. }
  538. else if (num_visuals == 0)
  539. {
  540. if (template_mask == VisualIDMask)
  541. Sys_Error("VID: Bad visual id %d\n", template.visualid);
  542. else
  543. Sys_Error("VID: No visuals at depth %d\n", template.depth);
  544. }
  545. if (verbose)
  546. {
  547. printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
  548. printf(" class %d\n", x_visinfo->class);
  549. printf(" screen %d\n", x_visinfo->screen);
  550. printf(" depth %d\n", x_visinfo->depth);
  551. printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask));
  552. printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask));
  553. printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
  554. printf(" colormap_size %d\n", x_visinfo->colormap_size);
  555. printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
  556. }
  557. x_vis = x_visinfo->visual;
  558. // setup attributes for main window
  559. {
  560. int attribmask = CWEventMask | CWColormap | CWBorderPixel;
  561. XSetWindowAttributes attribs;
  562. Colormap tmpcmap;
  563. tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
  564. x_visinfo->screen), x_vis, AllocNone);
  565. attribs.event_mask = x_std_event_mask;
  566. attribs.border_pixel = 0;
  567. attribs.colormap = tmpcmap;
  568. // create the main window
  569. x_win = XCreateWindow( x_disp,
  570. XRootWindow(x_disp, x_visinfo->screen),
  571. 0, 0, // x, y
  572. vid.width, vid.height,
  573. 0, // borderwidth
  574. x_visinfo->depth,
  575. InputOutput,
  576. x_vis,
  577. attribmask,
  578. &attribs );
  579. if (x_visinfo->class != TrueColor)
  580. XFreeColormap(x_disp, tmpcmap);
  581. }
  582. if (x_visinfo->depth == 8)
  583. {
  584. // create and upload the palette
  585. if (x_visinfo->class == PseudoColor)
  586. {
  587. x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
  588. VID_SetPalette(palette);
  589. XSetWindowColormap(x_disp, x_win, x_cmap);
  590. }
  591. }
  592. VID_SetWindowTitle( x_win, "Quake" );
  593. // create the GC
  594. {
  595. XGCValues xgcvalues;
  596. int valuemask = GCGraphicsExposures;
  597. xgcvalues.graphics_exposures = False;
  598. x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
  599. }
  600. // map the window
  601. XMapWindow(x_disp, x_win);
  602. // wait for first exposure event
  603. {
  604. XEvent event;
  605. do
  606. {
  607. XNextEvent(x_disp, &event);
  608. if (event.type == Expose && !event.xexpose.count)
  609. oktodraw = true;
  610. } while (!oktodraw);
  611. }
  612. // now safe to draw
  613. // even if MITSHM is available, make sure it's a local connection
  614. if (XShmQueryExtension(x_disp))
  615. {
  616. char *displayname;
  617. doShm = true;
  618. displayname = (char *) getenv("DISPLAY");
  619. if (displayname)
  620. {
  621. char *d = displayname;
  622. while (*d && (*d != ':')) d++;
  623. if (*d) *d = 0;
  624. if (!(!strcasecmp(displayname, "unix") || !*displayname))
  625. doShm = false;
  626. }
  627. }
  628. if (doShm)
  629. {
  630. x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
  631. ResetSharedFrameBuffers();
  632. }
  633. else
  634. ResetFrameBuffer();
  635. current_framebuffer = 0;
  636. vid.rowbytes = x_framebuffer[0]->bytes_per_line;
  637. vid.buffer = x_framebuffer[0]->data;
  638. vid.conbuffer = x_framebuffer[0]->data;
  639. vid.conrowbytes = vid.rowbytes;
  640. vid.conwidth = vid.width;
  641. vid.conheight = vid.height;
  642. vid.maxwarpwidth = WARP_WIDTH;
  643. vid.maxwarpheight = WARP_HEIGHT;
  644. D_InitCaches (surfcache, sizeof(surfcache));
  645. // XSynchronize(x_disp, False);
  646. vid_menudrawfn = VID_MenuDraw;
  647. vid_menukeyfn = VID_MenuKey;
  648. }
  649. void VID_ShiftPalette(unsigned char *p)
  650. {
  651. VID_SetPalette(p);
  652. }
  653. void VID_SetPalette(unsigned char *palette)
  654. {
  655. int i;
  656. XColor colors[256];
  657. for(i=0;i<256;i++) {
  658. st2d_8to16table[i]= xlib_rgb16(palette[i*3], palette[i*3+1],palette[i*3+2]);
  659. st2d_8to24table[i]= xlib_rgb24(palette[i*3], palette[i*3+1],palette[i*3+2]);
  660. }
  661. if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
  662. {
  663. if (palette != current_palette)
  664. memcpy(current_palette, palette, 768);
  665. for (i=0 ; i<256 ; i++)
  666. {
  667. colors[i].pixel = i;
  668. colors[i].flags = DoRed|DoGreen|DoBlue;
  669. colors[i].red = vid_gamma[palette[i*3]] * 257;
  670. colors[i].green = vid_gamma[palette[i*3+1]] * 257;
  671. colors[i].blue = vid_gamma[palette[i*3+2]] * 257;
  672. }
  673. XStoreColors(x_disp, x_cmap, colors, 256);
  674. }
  675. }
  676. // Called at shutdown
  677. void VID_Shutdown (void)
  678. {
  679. Con_Printf("VID_Shutdown\n");
  680. //XAutoRepeatOn(x_disp);
  681. if (mouse_grabbed) {
  682. /* ungrab the pointer */
  683. XUngrabPointer(x_disp, CurrentTime);
  684. XUndefineCursor(x_disp, x_win);
  685. }
  686. XCloseDisplay(x_disp);
  687. }
  688. int XLateKey(XKeyEvent *ev)
  689. {
  690. int key;
  691. char buf[64];
  692. KeySym keysym;
  693. XLookupString(ev, buf, sizeof buf, &keysym, 0);
  694. switch(keysym)
  695. {
  696. case XK_Page_Up: key = K_PGUP; break;
  697. case XK_Page_Down: key = K_PGDN; break;
  698. case XK_Home: key = K_HOME; break;
  699. case XK_End: key = K_END; break;
  700. case XK_Left: key = K_LEFTARROW; break;
  701. case XK_Right: key = K_RIGHTARROW; break;
  702. case XK_Down: key = K_DOWNARROW; break;
  703. case XK_Up: key = K_UPARROW; break;
  704. case XK_Escape: key = K_ESCAPE; break;
  705. case XK_Return: key = K_ENTER; break;
  706. case XK_Tab: key = K_TAB; break;
  707. case XK_F1: key = K_F1; break;
  708. case XK_F2: key = K_F2; break;
  709. case XK_F3: key = K_F3; break;
  710. case XK_F4: key = K_F4; break;
  711. case XK_F5: key = K_F5; break;
  712. case XK_F6: key = K_F6; break;
  713. case XK_F7: key = K_F7; break;
  714. case XK_F8: key = K_F8; break;
  715. case XK_F9: key = K_F9; break;
  716. case XK_F10: key = K_F10; break;
  717. case XK_F11: key = K_F11; break;
  718. case XK_F12: key = K_F12; break;
  719. case XK_BackSpace:
  720. case XK_Delete: key = K_BACKSPACE; break;
  721. case XK_Pause: key = K_PAUSE; break;
  722. case XK_Shift_L:
  723. case XK_Shift_R: key = K_SHIFT; break;
  724. case XK_Control_L:
  725. case XK_Control_R: key = K_CTRL; break;
  726. case XK_Alt_L:
  727. case XK_Meta_L:
  728. case XK_Alt_R:
  729. case XK_Meta_R: key = K_ALT; break;
  730. // various other keys on the keyboard
  731. case XK_F27: key = K_HOME; break;
  732. case XK_F29: key = K_PGUP; break;
  733. case XK_F33: key = K_END; break;
  734. case XK_F35: key = K_PGDN; break;
  735. case XK_KP_Insert: key = K_INS; break;
  736. default:
  737. key = *buf;
  738. break;
  739. }
  740. return key;
  741. }
  742. struct
  743. {
  744. int key;
  745. int down;
  746. } keyq[64];
  747. int keyq_head=0;
  748. int keyq_tail=0;
  749. int config_notify=0;
  750. int config_notify_width;
  751. int config_notify_height;
  752. void GetEvent(void)
  753. {
  754. XEvent x_event;
  755. XNextEvent(x_disp, &x_event);
  756. switch(x_event.type)
  757. {
  758. case KeyPress:
  759. Key_Event(XLateKey(&x_event.xkey), true);
  760. break;
  761. case KeyRelease:
  762. Key_Event(XLateKey(&x_event.xkey), false);
  763. break;
  764. case ButtonPress:
  765. //printf( "button %d down\n", x_event.xbutton.button );
  766. Key_Event( K_MOUSE1 + x_event.xbutton.button - 1, true );
  767. break;
  768. case ButtonRelease:
  769. //printf( "button %d up\n", x_event.xbutton.button );
  770. Key_Event( K_MOUSE1 + x_event.xbutton.button - 1, false );
  771. break;
  772. case MotionNotify:
  773. if (mouse_avail && mouse_grabbed) {
  774. mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2));
  775. mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2));
  776. //printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n",
  777. // x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y);
  778. /* move the mouse to the window center again */
  779. XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask);
  780. XWarpPointer(x_disp,None,x_win,0,0,0,0, (vid.width/2),(vid.height/2));
  781. XSelectInput(x_disp,x_win, STD_EVENT_MASK);
  782. } else {
  783. mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
  784. mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
  785. p_mouse_x=x_event.xmotion.x;
  786. p_mouse_y=x_event.xmotion.y;
  787. }
  788. break;
  789. case ConfigureNotify:
  790. // printf("config notify\n");
  791. config_notify_width = x_event.xconfigure.width;
  792. config_notify_height = x_event.xconfigure.height;
  793. config_notify = 1;
  794. sb_updates = 0;
  795. break;
  796. case Expose:
  797. sb_updates = 0;
  798. break;
  799. case ClientMessage:
  800. if (x_event.xclient.data.l[0] == aWMDelete) Host_Quit_f();
  801. break;
  802. case EnterNotify:
  803. mouse_in_window = true;
  804. break;
  805. case LeaveNotify:
  806. mouse_in_window = false;
  807. break;
  808. default:
  809. if (doShm && x_event.type == x_shmeventtype)
  810. oktodraw = true;
  811. }
  812. if (mouse_avail) {
  813. if (key_dest == key_game && !mouse_grabbed && mouse_in_window) {
  814. mouse_grabbed = true;
  815. /* grab the pointer */
  816. XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
  817. GrabModeAsync,x_win,None,CurrentTime);
  818. // inviso cursor
  819. XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
  820. } else if ((key_dest != key_game || !mouse_in_window) && mouse_grabbed) {
  821. mouse_grabbed = false;
  822. /* ungrab the pointer */
  823. XUngrabPointer(x_disp, CurrentTime);
  824. XUndefineCursor(x_disp, x_win);
  825. }
  826. }
  827. }
  828. // flushes the given rectangles from the view buffer to the screen
  829. void VID_Update (vrect_t *rects)
  830. {
  831. #if 0
  832. static int count;
  833. static long long s;
  834. long long gethrtime();
  835. if (count == 0)
  836. s = gethrtime();
  837. if (count++ == 50) {
  838. count = 1;
  839. printf("%lf frames/secs\n", 50.0/((double)(gethrtime()-s) / 1e9));
  840. s = gethrtime();
  841. }
  842. #endif
  843. // if the window changes dimension, skip this frame
  844. if (config_notify)
  845. {
  846. printf("config notify\n");
  847. config_notify = 0;
  848. vid.width = config_notify_width & ~3;
  849. vid.height = config_notify_height;
  850. printf("w = %d, h = %d\n", vid.width, vid.height);
  851. if (doShm)
  852. ResetSharedFrameBuffers();
  853. else
  854. ResetFrameBuffer();
  855. vid.rowbytes = x_framebuffer[0]->bytes_per_line;
  856. vid.buffer = x_framebuffer[current_framebuffer]->data;
  857. vid.conbuffer = vid.buffer;
  858. vid.conwidth = vid.width;
  859. vid.conheight = vid.height;
  860. vid.conrowbytes = vid.rowbytes;
  861. vid.recalc_refdef = 1; // force a surface cache flush
  862. return;
  863. }
  864. if (doShm)
  865. {
  866. // long long s, gethrtime();
  867. // s = gethrtime();
  868. while (rects)
  869. {
  870. printf("update: %d,%d (%d,%d)\n", rects->x, rects->y, rects->width, rects->height);
  871. if (x_visinfo->depth == 16)
  872. st2_fixup( x_framebuffer[current_framebuffer],
  873. rects->x, rects->y, rects->width,
  874. rects->height);
  875. else if (x_visinfo->depth == 24)
  876. st3_fixup( x_framebuffer[current_framebuffer],
  877. rects->x, rects->y, rects->width,
  878. rects->height);
  879. if (!XShmPutImage(x_disp, x_win, x_gc,
  880. x_framebuffer[current_framebuffer], rects->x, rects->y,
  881. rects->x, rects->y, rects->width, rects->height, True))
  882. Sys_Error("VID_Update: XShmPutImage failed\n");
  883. oktodraw = false;
  884. while (!oktodraw) GetEvent();
  885. rects = rects->pnext;
  886. }
  887. // printf("%lf\n", (double)(gethrtime()-s)/1.0e9);
  888. current_framebuffer = !current_framebuffer;
  889. vid.buffer = x_framebuffer[current_framebuffer]->data;
  890. vid.conbuffer = vid.buffer;
  891. XSync(x_disp, False);
  892. }
  893. else
  894. {
  895. while (rects)
  896. {
  897. if (x_visinfo->depth == 16)
  898. st2_fixup( x_framebuffer[current_framebuffer],
  899. rects->x, rects->y, rects->width,
  900. rects->height);
  901. else if (x_visinfo->depth == 24)
  902. st3_fixup( x_framebuffer[current_framebuffer],
  903. rects->x, rects->y, rects->width,
  904. rects->height);
  905. XPutImage(x_disp, x_win, x_gc, x_framebuffer[0], rects->x,
  906. rects->y, rects->x, rects->y, rects->width, rects->height);
  907. rects = rects->pnext;
  908. }
  909. XSync(x_disp, False);
  910. }
  911. }
  912. static int dither;
  913. void VID_DitherOn(void)
  914. {
  915. if (dither == 0)
  916. {
  917. vid.recalc_refdef = 1;
  918. dither = 1;
  919. }
  920. }
  921. void VID_DitherOff(void)
  922. {
  923. if (dither)
  924. {
  925. vid.recalc_refdef = 1;
  926. dither = 0;
  927. }
  928. }
  929. void VID_SetDefaultMode( void )
  930. {
  931. }
  932. int I_OpenWindow(void)
  933. {
  934. return 0;
  935. }
  936. void I_EraseWindow(int window)
  937. {
  938. }
  939. void I_DrawCircle(int window, int x, int y, int r)
  940. {
  941. }
  942. void I_DisplayWindow(int window)
  943. {
  944. }
  945. void Sys_SendKeyEvents(void)
  946. {
  947. // get events from x server
  948. if (x_disp)
  949. {
  950. while (XPending(x_disp)) GetEvent();
  951. while (keyq_head != keyq_tail)
  952. {
  953. Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
  954. keyq_tail = (keyq_tail + 1) & 63;
  955. }
  956. }
  957. }
  958. #if 0
  959. char *Sys_ConsoleInput (void)
  960. {
  961. static char text[256];
  962. int len;
  963. fd_set readfds;
  964. int ready;
  965. struct timeval timeout;
  966. timeout.tv_sec = 0;
  967. timeout.tv_usec = 0;
  968. FD_ZERO(&readfds);
  969. FD_SET(0, &readfds);
  970. ready = select(1, &readfds, 0, 0, &timeout);
  971. if (ready>0)
  972. {
  973. len = read (0, text, sizeof(text));
  974. if (len >= 1)
  975. {
  976. text[len-1] = 0; // rip off the /n and terminate
  977. return text;
  978. }
  979. }
  980. return 0;
  981. }
  982. #endif
  983. void IN_Init (void)
  984. {
  985. Cvar_RegisterVariable (&m_filter);
  986. if ( COM_CheckParm ("-nomouse") )
  987. return;
  988. mouse_x = mouse_y = 0.0;
  989. mouse_avail = 1;
  990. }
  991. void IN_Shutdown (void)
  992. {
  993. mouse_avail = 0;
  994. }
  995. void IN_Commands (void)
  996. {
  997. int i;
  998. if (!mouse_avail) return;
  999. for (i=0 ; i<mouse_buttons ; i++) {
  1000. if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
  1001. Key_Event (K_MOUSE1 + i, true);
  1002. if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
  1003. Key_Event (K_MOUSE1 + i, false);
  1004. }
  1005. mouse_oldbuttonstate = mouse_buttonstate;
  1006. }
  1007. void IN_Move (usercmd_t *cmd)
  1008. {
  1009. if (!mouse_avail)
  1010. return;
  1011. if (m_filter.value) {
  1012. mouse_x = (mouse_x + old_mouse_x) * 0.5;
  1013. mouse_y = (mouse_y + old_mouse_y) * 0.5;
  1014. }
  1015. old_mouse_x = mouse_x;
  1016. old_mouse_y = mouse_y;
  1017. mouse_x *= sensitivity.value;
  1018. mouse_y *= sensitivity.value;
  1019. if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
  1020. cmd->sidemove += m_side.value * mouse_x;
  1021. else
  1022. cl.viewangles[YAW] -= m_yaw.value * mouse_x;
  1023. if (in_mlook.state & 1)
  1024. V_StopPitchDrift ();
  1025. if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
  1026. cl.viewangles[PITCH] += m_pitch.value * mouse_y;
  1027. if (cl.viewangles[PITCH] > 80)
  1028. cl.viewangles[PITCH] = 80;
  1029. if (cl.viewangles[PITCH] < -70)
  1030. cl.viewangles[PITCH] = -70;
  1031. } else {
  1032. if ((in_strafe.state & 1) && noclip_anglehack)
  1033. cmd->upmove -= m_forward.value * mouse_y;
  1034. else
  1035. cmd->forwardmove -= m_forward.value * mouse_y;
  1036. }
  1037. mouse_x = mouse_y = 0.0;
  1038. }