vid_x.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200
  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 <ctype.h>
  18. #include <sys/time.h>
  19. #include <sys/types.h>
  20. #include <unistd.h>
  21. #include <signal.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <sys/ipc.h>
  26. #include <sys/shm.h>
  27. #include <X11/Xlib.h>
  28. #include <X11/Xutil.h>
  29. #include <X11/Xatom.h>
  30. #include <X11/keysym.h>
  31. #include <X11/extensions/XShm.h>
  32. #include "quakedef.h"
  33. #include "d_local.h"
  34. cvar_t _windowed_mouse = {"_windowed_mouse","0", true};
  35. cvar_t m_filter = {"m_filter","0", true};
  36. float old_windowed_mouse;
  37. qboolean mouse_avail;
  38. int mouse_buttons=3;
  39. int mouse_oldbuttonstate;
  40. int mouse_buttonstate;
  41. float mouse_x, mouse_y;
  42. float old_mouse_x, old_mouse_y;
  43. int p_mouse_x;
  44. int p_mouse_y;
  45. int ignorenext;
  46. int bits_per_pixel;
  47. typedef struct
  48. {
  49. int input;
  50. int output;
  51. } keymap_t;
  52. viddef_t vid; // global video state
  53. unsigned short d_8to16table[256];
  54. int num_shades=32;
  55. int d_con_indirect = 0;
  56. int vid_buffersize;
  57. static qboolean doShm;
  58. static Display *x_disp;
  59. static Colormap x_cmap;
  60. static Window x_win;
  61. static GC x_gc;
  62. static Visual *x_vis;
  63. static XVisualInfo *x_visinfo;
  64. //static XImage *x_image;
  65. static int x_shmeventtype;
  66. //static XShmSegmentInfo x_shminfo;
  67. static qboolean oktodraw = false;
  68. int XShmQueryExtension(Display *);
  69. int XShmGetEventBase(Display *);
  70. int current_framebuffer;
  71. static XImage *x_framebuffer[2] = { 0, 0 };
  72. static XShmSegmentInfo x_shminfo[2];
  73. static int verbose=0;
  74. static byte current_palette[768];
  75. static long X11_highhunkmark;
  76. static long X11_buffersize;
  77. int vid_surfcachesize;
  78. void *vid_surfcache;
  79. void (*vid_menudrawfn)(void);
  80. void (*vid_menukeyfn)(int key);
  81. void VID_MenuKey (int key);
  82. typedef unsigned short PIXEL16;
  83. typedef unsigned long PIXEL24;
  84. static PIXEL16 st2d_8to16table[256];
  85. static PIXEL24 st2d_8to24table[256];
  86. static int shiftmask_fl=0;
  87. static long r_shift,g_shift,b_shift;
  88. static unsigned long r_mask,g_mask,b_mask;
  89. void shiftmask_init()
  90. {
  91. unsigned int x;
  92. r_mask=x_vis->red_mask;
  93. g_mask=x_vis->green_mask;
  94. b_mask=x_vis->blue_mask;
  95. for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
  96. for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
  97. for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
  98. shiftmask_fl=1;
  99. }
  100. PIXEL16 xlib_rgb16(int r,int g,int b)
  101. {
  102. PIXEL16 p;
  103. if(shiftmask_fl==0) shiftmask_init();
  104. p=0;
  105. if(r_shift>0) {
  106. p=(r<<(r_shift))&r_mask;
  107. } else if(r_shift<0) {
  108. p=(r>>(-r_shift))&r_mask;
  109. } else p|=(r&r_mask);
  110. if(g_shift>0) {
  111. p|=(g<<(g_shift))&g_mask;
  112. } else if(g_shift<0) {
  113. p|=(g>>(-g_shift))&g_mask;
  114. } else p|=(g&g_mask);
  115. if(b_shift>0) {
  116. p|=(b<<(b_shift))&b_mask;
  117. } else if(b_shift<0) {
  118. p|=(b>>(-b_shift))&b_mask;
  119. } else p|=(b&b_mask);
  120. return p;
  121. }
  122. PIXEL24 xlib_rgb24(int r,int g,int b)
  123. {
  124. PIXEL24 p;
  125. if(shiftmask_fl==0) shiftmask_init();
  126. p=0;
  127. if(r_shift>0) {
  128. p=(r<<(r_shift))&r_mask;
  129. } else if(r_shift<0) {
  130. p=(r>>(-r_shift))&r_mask;
  131. } else p|=(r&r_mask);
  132. if(g_shift>0) {
  133. p|=(g<<(g_shift))&g_mask;
  134. } else if(g_shift<0) {
  135. p|=(g>>(-g_shift))&g_mask;
  136. } else p|=(g&g_mask);
  137. if(b_shift>0) {
  138. p|=(b<<(b_shift))&b_mask;
  139. } else if(b_shift<0) {
  140. p|=(b>>(-b_shift))&b_mask;
  141. } else p|=(b&b_mask);
  142. return p;
  143. }
  144. void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
  145. {
  146. int xi,yi;
  147. unsigned char *src;
  148. PIXEL16 *dest;
  149. register int count, n;
  150. if( (x<0)||(y<0) )return;
  151. for (yi = y; yi < (y+height); yi++) {
  152. src = &framebuf->data [yi * framebuf->bytes_per_line];
  153. // Duff's Device
  154. count = width;
  155. n = (count + 7) / 8;
  156. dest = ((PIXEL16 *)src) + x+width - 1;
  157. src += x+width - 1;
  158. switch (count % 8) {
  159. case 0: do { *dest-- = st2d_8to16table[*src--];
  160. case 7: *dest-- = st2d_8to16table[*src--];
  161. case 6: *dest-- = st2d_8to16table[*src--];
  162. case 5: *dest-- = st2d_8to16table[*src--];
  163. case 4: *dest-- = st2d_8to16table[*src--];
  164. case 3: *dest-- = st2d_8to16table[*src--];
  165. case 2: *dest-- = st2d_8to16table[*src--];
  166. case 1: *dest-- = st2d_8to16table[*src--];
  167. } while (--n > 0);
  168. }
  169. // for(xi = (x+width-1); xi >= x; xi--) {
  170. // dest[xi] = st2d_8to16table[src[xi]];
  171. // }
  172. }
  173. }
  174. void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
  175. {
  176. int xi,yi;
  177. unsigned char *src;
  178. PIXEL24 *dest;
  179. register int count, n;
  180. if( (x<0)||(y<0) )return;
  181. for (yi = y; yi < (y+height); yi++) {
  182. src = &framebuf->data [yi * framebuf->bytes_per_line];
  183. // Duff's Device
  184. count = width;
  185. n = (count + 7) / 8;
  186. dest = ((PIXEL24 *)src) + x+width - 1;
  187. src += x+width - 1;
  188. switch (count % 8) {
  189. case 0: do { *dest-- = st2d_8to24table[*src--];
  190. case 7: *dest-- = st2d_8to24table[*src--];
  191. case 6: *dest-- = st2d_8to24table[*src--];
  192. case 5: *dest-- = st2d_8to24table[*src--];
  193. case 4: *dest-- = st2d_8to24table[*src--];
  194. case 3: *dest-- = st2d_8to24table[*src--];
  195. case 2: *dest-- = st2d_8to24table[*src--];
  196. case 1: *dest-- = st2d_8to24table[*src--];
  197. } while (--n > 0);
  198. }
  199. // for(xi = (x+width-1); xi >= x; xi--) {
  200. // dest[xi] = st2d_8to16table[src[xi]];
  201. // }
  202. }
  203. }
  204. // ========================================================================
  205. // Tragic death handler
  206. // ========================================================================
  207. void TragicDeath(int signal_num)
  208. {
  209. XAutoRepeatOn(x_disp);
  210. XCloseDisplay(x_disp);
  211. Sys_Error("This death brought to you by the number %d\n", signal_num);
  212. }
  213. // ========================================================================
  214. // makes a null cursor
  215. // ========================================================================
  216. static Cursor CreateNullCursor(Display *display, Window root)
  217. {
  218. Pixmap cursormask;
  219. XGCValues xgc;
  220. GC gc;
  221. XColor dummycolour;
  222. Cursor cursor;
  223. cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
  224. xgc.function = GXclear;
  225. gc = XCreateGC(display, cursormask, GCFunction, &xgc);
  226. XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
  227. dummycolour.pixel = 0;
  228. dummycolour.red = 0;
  229. dummycolour.flags = 04;
  230. cursor = XCreatePixmapCursor(display, cursormask, cursormask,
  231. &dummycolour,&dummycolour, 0,0);
  232. XFreePixmap(display,cursormask);
  233. XFreeGC(display,gc);
  234. return cursor;
  235. }
  236. void ResetFrameBuffer(void)
  237. {
  238. int mem;
  239. int pwidth;
  240. if (x_framebuffer[0])
  241. {
  242. free(x_framebuffer[0]->data);
  243. free(x_framebuffer[0]);
  244. }
  245. if (d_pzbuffer)
  246. {
  247. D_FlushCaches ();
  248. Hunk_FreeToHighMark (X11_highhunkmark);
  249. d_pzbuffer = NULL;
  250. }
  251. X11_highhunkmark = Hunk_HighMark ();
  252. // alloc an extra line in case we want to wrap, and allocate the z-buffer
  253. X11_buffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
  254. vid_surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
  255. X11_buffersize += vid_surfcachesize;
  256. d_pzbuffer = Hunk_HighAllocName (X11_buffersize, "video");
  257. if (d_pzbuffer == NULL)
  258. Sys_Error ("Not enough memory for video mode\n");
  259. vid_surfcache = (byte *) d_pzbuffer
  260. + vid.width * vid.height * sizeof (*d_pzbuffer);
  261. D_InitCaches(vid_surfcache, vid_surfcachesize);
  262. pwidth = x_visinfo->depth / 8;
  263. if (pwidth == 3) pwidth = 4;
  264. mem = ((vid.width*pwidth+7)&~7) * vid.height;
  265. x_framebuffer[0] = XCreateImage( x_disp,
  266. x_vis,
  267. x_visinfo->depth,
  268. ZPixmap,
  269. 0,
  270. malloc(mem),
  271. vid.width, vid.height,
  272. 32,
  273. 0);
  274. if (!x_framebuffer[0])
  275. Sys_Error("VID: XCreateImage failed\n");
  276. vid.buffer = (byte*) (x_framebuffer[0]);
  277. vid.conbuffer = vid.buffer;
  278. }
  279. void ResetSharedFrameBuffers(void)
  280. {
  281. int size;
  282. int key;
  283. int minsize = getpagesize();
  284. int frm;
  285. if (d_pzbuffer)
  286. {
  287. D_FlushCaches ();
  288. Hunk_FreeToHighMark (X11_highhunkmark);
  289. d_pzbuffer = NULL;
  290. }
  291. X11_highhunkmark = Hunk_HighMark ();
  292. // alloc an extra line in case we want to wrap, and allocate the z-buffer
  293. X11_buffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
  294. vid_surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
  295. X11_buffersize += vid_surfcachesize;
  296. d_pzbuffer = Hunk_HighAllocName (X11_buffersize, "video");
  297. if (d_pzbuffer == NULL)
  298. Sys_Error ("Not enough memory for video mode\n");
  299. vid_surfcache = (byte *) d_pzbuffer
  300. + vid.width * vid.height * sizeof (*d_pzbuffer);
  301. D_InitCaches(vid_surfcache, vid_surfcachesize);
  302. for (frm=0 ; frm<2 ; frm++)
  303. {
  304. // free up old frame buffer memory
  305. if (x_framebuffer[frm])
  306. {
  307. XShmDetach(x_disp, &x_shminfo[frm]);
  308. free(x_framebuffer[frm]);
  309. shmdt(x_shminfo[frm].shmaddr);
  310. }
  311. // create the image
  312. x_framebuffer[frm] = XShmCreateImage( x_disp,
  313. x_vis,
  314. x_visinfo->depth,
  315. ZPixmap,
  316. 0,
  317. &x_shminfo[frm],
  318. vid.width,
  319. vid.height );
  320. // grab shared memory
  321. size = x_framebuffer[frm]->bytes_per_line
  322. * x_framebuffer[frm]->height;
  323. if (size < minsize)
  324. Sys_Error("VID: Window must use at least %d bytes\n", minsize);
  325. key = random();
  326. x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
  327. if (x_shminfo[frm].shmid==-1)
  328. Sys_Error("VID: Could not get any shared memory\n");
  329. // attach to the shared memory segment
  330. x_shminfo[frm].shmaddr =
  331. (void *) shmat(x_shminfo[frm].shmid, 0, 0);
  332. printf("VID: shared memory id=%d, addr=0x%lx\n", x_shminfo[frm].shmid,
  333. (long) x_shminfo[frm].shmaddr);
  334. x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
  335. // get the X server to attach to it
  336. if (!XShmAttach(x_disp, &x_shminfo[frm]))
  337. Sys_Error("VID: XShmAttach() failed\n");
  338. XSync(x_disp, 0);
  339. shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
  340. }
  341. }
  342. // Called at startup to set up translation tables, takes 256 8 bit RGB values
  343. // the palette data will go away after the call, so it must be copied off if
  344. // the video driver will need it again
  345. void VID_Init (unsigned char *palette)
  346. {
  347. int pnum, i;
  348. XVisualInfo template;
  349. int num_visuals;
  350. int template_mask;
  351. ignorenext=0;
  352. vid.width = 320;
  353. vid.height = 200;
  354. vid.maxwarpwidth = WARP_WIDTH;
  355. vid.maxwarpheight = WARP_HEIGHT;
  356. vid.numpages = 2;
  357. vid.colormap = host_colormap;
  358. // vid.cbits = VID_CBITS;
  359. // vid.grades = VID_GRADES;
  360. vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  361. srandom(getpid());
  362. verbose=COM_CheckParm("-verbose");
  363. // open the display
  364. x_disp = XOpenDisplay(0);
  365. if (!x_disp)
  366. {
  367. if (getenv("DISPLAY"))
  368. Sys_Error("VID: Could not open display [%s]\n",
  369. getenv("DISPLAY"));
  370. else
  371. Sys_Error("VID: Could not open local display\n");
  372. }
  373. // catch signals so i can turn on auto-repeat
  374. {
  375. struct sigaction sa;
  376. sigaction(SIGINT, 0, &sa);
  377. sa.sa_handler = TragicDeath;
  378. sigaction(SIGINT, &sa, 0);
  379. sigaction(SIGTERM, &sa, 0);
  380. }
  381. XAutoRepeatOff(x_disp);
  382. // for debugging only
  383. XSynchronize(x_disp, True);
  384. // check for command-line window size
  385. if ((pnum=COM_CheckParm("-winsize")))
  386. {
  387. if (pnum >= com_argc-2)
  388. Sys_Error("VID: -winsize <width> <height>\n");
  389. vid.width = Q_atoi(com_argv[pnum+1]);
  390. vid.height = Q_atoi(com_argv[pnum+2]);
  391. if (!vid.width || !vid.height)
  392. Sys_Error("VID: Bad window width/height\n");
  393. }
  394. if ((pnum=COM_CheckParm("-width"))) {
  395. if (pnum >= com_argc-1)
  396. Sys_Error("VID: -width <width>\n");
  397. vid.width = Q_atoi(com_argv[pnum+1]);
  398. if (!vid.width)
  399. Sys_Error("VID: Bad window width\n");
  400. }
  401. if ((pnum=COM_CheckParm("-height"))) {
  402. if (pnum >= com_argc-1)
  403. Sys_Error("VID: -height <height>\n");
  404. vid.height = Q_atoi(com_argv[pnum+1]);
  405. if (!vid.height)
  406. Sys_Error("VID: Bad window height\n");
  407. }
  408. template_mask = 0;
  409. // specify a visual id
  410. if ((pnum=COM_CheckParm("-visualid")))
  411. {
  412. if (pnum >= com_argc-1)
  413. Sys_Error("VID: -visualid <id#>\n");
  414. template.visualid = Q_atoi(com_argv[pnum+1]);
  415. template_mask = VisualIDMask;
  416. }
  417. // If not specified, use default visual
  418. else
  419. {
  420. int screen;
  421. screen = XDefaultScreen(x_disp);
  422. template.visualid =
  423. XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
  424. template_mask = VisualIDMask;
  425. }
  426. // pick a visual- warn if more than one was available
  427. x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
  428. if (num_visuals > 1)
  429. {
  430. printf("Found more than one visual id at depth %d:\n", template.depth);
  431. for (i=0 ; i<num_visuals ; i++)
  432. printf(" -visualid %d\n", (int)(x_visinfo[i].visualid));
  433. }
  434. else if (num_visuals == 0)
  435. {
  436. if (template_mask == VisualIDMask)
  437. Sys_Error("VID: Bad visual id %d\n", template.visualid);
  438. else
  439. Sys_Error("VID: No visuals at depth %d\n", template.depth);
  440. }
  441. if (verbose)
  442. {
  443. printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
  444. printf(" screen %d\n", x_visinfo->screen);
  445. printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask));
  446. printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask));
  447. printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
  448. printf(" colormap_size %d\n", x_visinfo->colormap_size);
  449. printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
  450. }
  451. x_vis = x_visinfo->visual;
  452. // setup attributes for main window
  453. {
  454. int attribmask = CWEventMask | CWColormap | CWBorderPixel;
  455. XSetWindowAttributes attribs;
  456. Colormap tmpcmap;
  457. tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
  458. x_visinfo->screen), x_vis, AllocNone);
  459. attribs.event_mask = StructureNotifyMask | KeyPressMask
  460. | KeyReleaseMask | ExposureMask | PointerMotionMask |
  461. ButtonPressMask | ButtonReleaseMask;
  462. attribs.border_pixel = 0;
  463. attribs.colormap = tmpcmap;
  464. // create the main window
  465. x_win = XCreateWindow( x_disp,
  466. XRootWindow(x_disp, x_visinfo->screen),
  467. 0, 0, // x, y
  468. vid.width, vid.height,
  469. 0, // borderwidth
  470. x_visinfo->depth,
  471. InputOutput,
  472. x_vis,
  473. attribmask,
  474. &attribs );
  475. XStoreName( x_disp,x_win,"xquake");
  476. if (x_visinfo->class != TrueColor)
  477. XFreeColormap(x_disp, tmpcmap);
  478. }
  479. if (x_visinfo->depth == 8)
  480. {
  481. // create and upload the palette
  482. if (x_visinfo->class == PseudoColor)
  483. {
  484. x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
  485. VID_SetPalette(palette);
  486. XSetWindowColormap(x_disp, x_win, x_cmap);
  487. }
  488. }
  489. // inviso cursor
  490. XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
  491. // create the GC
  492. {
  493. XGCValues xgcvalues;
  494. int valuemask = GCGraphicsExposures;
  495. xgcvalues.graphics_exposures = False;
  496. x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
  497. }
  498. // map the window
  499. XMapWindow(x_disp, x_win);
  500. // wait for first exposure event
  501. {
  502. XEvent event;
  503. do
  504. {
  505. XNextEvent(x_disp, &event);
  506. if (event.type == Expose && !event.xexpose.count)
  507. oktodraw = true;
  508. } while (!oktodraw);
  509. }
  510. // now safe to draw
  511. // even if MITSHM is available, make sure it's a local connection
  512. if (XShmQueryExtension(x_disp))
  513. {
  514. char *displayname;
  515. doShm = true;
  516. displayname = (char *) getenv("DISPLAY");
  517. if (displayname)
  518. {
  519. char *d = displayname;
  520. while (*d && (*d != ':')) d++;
  521. if (*d) *d = 0;
  522. if (!(!strcasecmp(displayname, "unix") || !*displayname))
  523. doShm = false;
  524. }
  525. }
  526. if (doShm)
  527. {
  528. x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
  529. ResetSharedFrameBuffers();
  530. }
  531. else
  532. ResetFrameBuffer();
  533. current_framebuffer = 0;
  534. vid.rowbytes = x_framebuffer[0]->bytes_per_line;
  535. vid.buffer = x_framebuffer[0]->data;
  536. vid.direct = 0;
  537. vid.conbuffer = x_framebuffer[0]->data;
  538. vid.conrowbytes = vid.rowbytes;
  539. vid.conwidth = vid.width;
  540. vid.conheight = vid.height;
  541. vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
  542. // XSynchronize(x_disp, False);
  543. }
  544. void VID_ShiftPalette(unsigned char *p)
  545. {
  546. VID_SetPalette(p);
  547. }
  548. void VID_SetPalette(unsigned char *palette)
  549. {
  550. int i;
  551. XColor colors[256];
  552. for(i=0;i<256;i++) {
  553. st2d_8to16table[i]= xlib_rgb16(palette[i*3], palette[i*3+1],palette[i*3+2]);
  554. st2d_8to24table[i]= xlib_rgb24(palette[i*3], palette[i*3+1],palette[i*3+2]);
  555. }
  556. if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
  557. {
  558. if (palette != current_palette)
  559. memcpy(current_palette, palette, 768);
  560. for (i=0 ; i<256 ; i++)
  561. {
  562. colors[i].pixel = i;
  563. colors[i].flags = DoRed|DoGreen|DoBlue;
  564. colors[i].red = palette[i*3] * 257;
  565. colors[i].green = palette[i*3+1] * 257;
  566. colors[i].blue = palette[i*3+2] * 257;
  567. }
  568. XStoreColors(x_disp, x_cmap, colors, 256);
  569. }
  570. }
  571. // Called at shutdown
  572. void VID_Shutdown (void)
  573. {
  574. Con_Printf("VID_Shutdown\n");
  575. XAutoRepeatOn(x_disp);
  576. XCloseDisplay(x_disp);
  577. }
  578. int XLateKey(XKeyEvent *ev)
  579. {
  580. int key;
  581. char buf[64];
  582. KeySym keysym;
  583. key = 0;
  584. XLookupString(ev, buf, sizeof buf, &keysym, 0);
  585. switch(keysym)
  586. {
  587. case XK_KP_Page_Up:
  588. case XK_Page_Up: key = K_PGUP; break;
  589. case XK_KP_Page_Down:
  590. case XK_Page_Down: key = K_PGDN; break;
  591. case XK_KP_Home:
  592. case XK_Home: key = K_HOME; break;
  593. case XK_KP_End:
  594. case XK_End: key = K_END; break;
  595. case XK_KP_Left:
  596. case XK_Left: key = K_LEFTARROW; break;
  597. case XK_KP_Right:
  598. case XK_Right: key = K_RIGHTARROW; break;
  599. case XK_KP_Down:
  600. case XK_Down: key = K_DOWNARROW; break;
  601. case XK_KP_Up:
  602. case XK_Up: key = K_UPARROW; break;
  603. case XK_Escape: key = K_ESCAPE; break;
  604. case XK_KP_Enter:
  605. case XK_Return: key = K_ENTER; break;
  606. case XK_Tab: key = K_TAB; break;
  607. case XK_F1: key = K_F1; break;
  608. case XK_F2: key = K_F2; break;
  609. case XK_F3: key = K_F3; break;
  610. case XK_F4: key = K_F4; break;
  611. case XK_F5: key = K_F5; break;
  612. case XK_F6: key = K_F6; break;
  613. case XK_F7: key = K_F7; break;
  614. case XK_F8: key = K_F8; break;
  615. case XK_F9: key = K_F9; break;
  616. case XK_F10: key = K_F10; break;
  617. case XK_F11: key = K_F11; break;
  618. case XK_F12: key = K_F12; break;
  619. case XK_BackSpace: key = K_BACKSPACE; break;
  620. case XK_KP_Delete:
  621. case XK_Delete: key = K_DEL; break;
  622. case XK_Pause: key = K_PAUSE; break;
  623. case XK_Shift_L:
  624. case XK_Shift_R: key = K_SHIFT; break;
  625. case XK_Execute:
  626. case XK_Control_L:
  627. case XK_Control_R: key = K_CTRL; break;
  628. case XK_Alt_L:
  629. case XK_Meta_L:
  630. case XK_Alt_R:
  631. case XK_Meta_R: key = K_ALT; break;
  632. case XK_KP_Begin: key = K_AUX30; break;
  633. case XK_Insert:
  634. case XK_KP_Insert: key = K_INS; break;
  635. case XK_KP_Multiply: key = '*'; break;
  636. case XK_KP_Add: key = '+'; break;
  637. case XK_KP_Subtract: key = '-'; break;
  638. case XK_KP_Divide: key = '/'; break;
  639. #if 0
  640. case 0x021: key = '1';break;/* [!] */
  641. case 0x040: key = '2';break;/* [@] */
  642. case 0x023: key = '3';break;/* [#] */
  643. case 0x024: key = '4';break;/* [$] */
  644. case 0x025: key = '5';break;/* [%] */
  645. case 0x05e: key = '6';break;/* [^] */
  646. case 0x026: key = '7';break;/* [&] */
  647. case 0x02a: key = '8';break;/* [*] */
  648. case 0x028: key = '9';;break;/* [(] */
  649. case 0x029: key = '0';break;/* [)] */
  650. case 0x05f: key = '-';break;/* [_] */
  651. case 0x02b: key = '=';break;/* [+] */
  652. case 0x07c: key = '\'';break;/* [|] */
  653. case 0x07d: key = '[';break;/* [}] */
  654. case 0x07b: key = ']';break;/* [{] */
  655. case 0x022: key = '\'';break;/* ["] */
  656. case 0x03a: key = ';';break;/* [:] */
  657. case 0x03f: key = '/';break;/* [?] */
  658. case 0x03e: key = '.';break;/* [>] */
  659. case 0x03c: key = ',';break;/* [<] */
  660. #endif
  661. default:
  662. key = *(unsigned char*)buf;
  663. if (key >= 'A' && key <= 'Z')
  664. key = key - 'A' + 'a';
  665. // fprintf(stdout, "case 0x0%x: key = ___;break;/* [%c] */\n", keysym);
  666. break;
  667. }
  668. return key;
  669. }
  670. struct
  671. {
  672. int key;
  673. int down;
  674. } keyq[64];
  675. int keyq_head=0;
  676. int keyq_tail=0;
  677. int config_notify=0;
  678. int config_notify_width;
  679. int config_notify_height;
  680. void GetEvent(void)
  681. {
  682. XEvent x_event;
  683. int b;
  684. XNextEvent(x_disp, &x_event);
  685. switch(x_event.type) {
  686. case KeyPress:
  687. keyq[keyq_head].key = XLateKey(&x_event.xkey);
  688. keyq[keyq_head].down = true;
  689. keyq_head = (keyq_head + 1) & 63;
  690. break;
  691. case KeyRelease:
  692. keyq[keyq_head].key = XLateKey(&x_event.xkey);
  693. keyq[keyq_head].down = false;
  694. keyq_head = (keyq_head + 1) & 63;
  695. break;
  696. case MotionNotify:
  697. if (_windowed_mouse.value) {
  698. mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2));
  699. mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2));
  700. //printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n",
  701. // x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y);
  702. /* move the mouse to the window center again */
  703. XSelectInput(x_disp,x_win,StructureNotifyMask|KeyPressMask
  704. |KeyReleaseMask|ExposureMask
  705. |ButtonPressMask
  706. |ButtonReleaseMask);
  707. XWarpPointer(x_disp,None,x_win,0,0,0,0,
  708. (vid.width/2),(vid.height/2));
  709. XSelectInput(x_disp,x_win,StructureNotifyMask|KeyPressMask
  710. |KeyReleaseMask|ExposureMask
  711. |PointerMotionMask|ButtonPressMask
  712. |ButtonReleaseMask);
  713. } else {
  714. mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
  715. mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
  716. p_mouse_x=x_event.xmotion.x;
  717. p_mouse_y=x_event.xmotion.y;
  718. }
  719. break;
  720. case ButtonPress:
  721. b=-1;
  722. if (x_event.xbutton.button == 1)
  723. b = 0;
  724. else if (x_event.xbutton.button == 2)
  725. b = 2;
  726. else if (x_event.xbutton.button == 3)
  727. b = 1;
  728. if (b>=0)
  729. mouse_buttonstate |= 1<<b;
  730. break;
  731. case ButtonRelease:
  732. b=-1;
  733. if (x_event.xbutton.button == 1)
  734. b = 0;
  735. else if (x_event.xbutton.button == 2)
  736. b = 2;
  737. else if (x_event.xbutton.button == 3)
  738. b = 1;
  739. if (b>=0)
  740. mouse_buttonstate &= ~(1<<b);
  741. break;
  742. case ConfigureNotify:
  743. //printf("config notify\n");
  744. config_notify_width = x_event.xconfigure.width;
  745. config_notify_height = x_event.xconfigure.height;
  746. config_notify = 1;
  747. break;
  748. default:
  749. if (doShm && x_event.type == x_shmeventtype)
  750. oktodraw = true;
  751. }
  752. if (old_windowed_mouse != _windowed_mouse.value) {
  753. old_windowed_mouse = _windowed_mouse.value;
  754. if (!_windowed_mouse.value) {
  755. /* ungrab the pointer */
  756. XUngrabPointer(x_disp,CurrentTime);
  757. } else {
  758. /* grab the pointer */
  759. XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
  760. GrabModeAsync,x_win,None,CurrentTime);
  761. }
  762. }
  763. }
  764. // flushes the given rectangles from the view buffer to the screen
  765. void VID_Update (vrect_t *rects)
  766. {
  767. vrect_t full;
  768. // if the window changes dimension, skip this frame
  769. if (config_notify)
  770. {
  771. fprintf(stderr, "config notify\n");
  772. config_notify = 0;
  773. vid.width = config_notify_width & ~7;
  774. vid.height = config_notify_height;
  775. if (doShm)
  776. ResetSharedFrameBuffers();
  777. else
  778. ResetFrameBuffer();
  779. vid.rowbytes = x_framebuffer[0]->bytes_per_line;
  780. vid.buffer = x_framebuffer[current_framebuffer]->data;
  781. vid.conbuffer = vid.buffer;
  782. vid.conwidth = vid.width;
  783. vid.conheight = vid.height;
  784. vid.conrowbytes = vid.rowbytes;
  785. vid.recalc_refdef = 1; // force a surface cache flush
  786. Con_CheckResize();
  787. Con_Clear_f();
  788. return;
  789. }
  790. // force full update if not 8bit
  791. if (x_visinfo->depth != 8) {
  792. extern int scr_fullupdate;
  793. scr_fullupdate = 0;
  794. }
  795. if (doShm)
  796. {
  797. while (rects)
  798. {
  799. if (x_visinfo->depth == 16)
  800. st2_fixup( x_framebuffer[current_framebuffer],
  801. rects->x, rects->y, rects->width,
  802. rects->height);
  803. else if (x_visinfo->depth == 24)
  804. st3_fixup( x_framebuffer[current_framebuffer],
  805. rects->x, rects->y, rects->width,
  806. rects->height);
  807. if (!XShmPutImage(x_disp, x_win, x_gc,
  808. x_framebuffer[current_framebuffer], rects->x, rects->y,
  809. rects->x, rects->y, rects->width, rects->height, True))
  810. Sys_Error("VID_Update: XShmPutImage failed\n");
  811. oktodraw = false;
  812. while (!oktodraw) GetEvent();
  813. rects = rects->pnext;
  814. }
  815. current_framebuffer = !current_framebuffer;
  816. vid.buffer = x_framebuffer[current_framebuffer]->data;
  817. vid.conbuffer = vid.buffer;
  818. XSync(x_disp, False);
  819. }
  820. else
  821. {
  822. while (rects)
  823. {
  824. if (x_visinfo->depth == 16)
  825. st2_fixup( x_framebuffer[current_framebuffer],
  826. rects->x, rects->y, rects->width,
  827. rects->height);
  828. else if (x_visinfo->depth == 24)
  829. st3_fixup( x_framebuffer[current_framebuffer],
  830. rects->x, rects->y, rects->width,
  831. rects->height);
  832. XPutImage(x_disp, x_win, x_gc, x_framebuffer[0], rects->x,
  833. rects->y, rects->x, rects->y, rects->width, rects->height);
  834. rects = rects->pnext;
  835. }
  836. XSync(x_disp, False);
  837. }
  838. }
  839. static int dither;
  840. void VID_DitherOn(void)
  841. {
  842. if (dither == 0)
  843. {
  844. vid.recalc_refdef = 1;
  845. dither = 1;
  846. }
  847. }
  848. void VID_DitherOff(void)
  849. {
  850. if (dither)
  851. {
  852. vid.recalc_refdef = 1;
  853. dither = 0;
  854. }
  855. }
  856. int Sys_OpenWindow(void)
  857. {
  858. return 0;
  859. }
  860. void Sys_EraseWindow(int window)
  861. {
  862. }
  863. void Sys_DrawCircle(int window, int x, int y, int r)
  864. {
  865. }
  866. void Sys_DisplayWindow(int window)
  867. {
  868. }
  869. void Sys_SendKeyEvents(void)
  870. {
  871. // get events from x server
  872. if (x_disp)
  873. {
  874. while (XPending(x_disp)) GetEvent();
  875. while (keyq_head != keyq_tail)
  876. {
  877. Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
  878. keyq_tail = (keyq_tail + 1) & 63;
  879. }
  880. }
  881. }
  882. #if 0
  883. char *Sys_ConsoleInput (void)
  884. {
  885. static char text[256];
  886. int len;
  887. fd_set readfds;
  888. int ready;
  889. struct timeval timeout;
  890. timeout.tv_sec = 0;
  891. timeout.tv_usec = 0;
  892. FD_ZERO(&readfds);
  893. FD_SET(0, &readfds);
  894. ready = select(1, &readfds, 0, 0, &timeout);
  895. if (ready>0)
  896. {
  897. len = read (0, text, sizeof(text));
  898. if (len >= 1)
  899. {
  900. text[len-1] = 0; // rip off the /n and terminate
  901. return text;
  902. }
  903. }
  904. return 0;
  905. }
  906. #endif
  907. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  908. {
  909. // direct drawing of the "accessing disk" icon isn't supported under Linux
  910. }
  911. void D_EndDirectRect (int x, int y, int width, int height)
  912. {
  913. // direct drawing of the "accessing disk" icon isn't supported under Linux
  914. }
  915. void IN_Init (void)
  916. {
  917. Cvar_RegisterVariable (&_windowed_mouse);
  918. Cvar_RegisterVariable (&m_filter);
  919. if ( COM_CheckParm ("-nomouse") )
  920. return;
  921. mouse_x = mouse_y = 0.0;
  922. mouse_avail = 1;
  923. }
  924. void IN_Shutdown (void)
  925. {
  926. mouse_avail = 0;
  927. }
  928. void IN_Commands (void)
  929. {
  930. int i;
  931. if (!mouse_avail) return;
  932. for (i=0 ; i<mouse_buttons ; i++) {
  933. if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
  934. Key_Event (K_MOUSE1 + i, true);
  935. if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
  936. Key_Event (K_MOUSE1 + i, false);
  937. }
  938. mouse_oldbuttonstate = mouse_buttonstate;
  939. }
  940. void IN_Move (usercmd_t *cmd)
  941. {
  942. if (!mouse_avail)
  943. return;
  944. if (m_filter.value) {
  945. mouse_x = (mouse_x + old_mouse_x) * 0.5;
  946. mouse_y = (mouse_y + old_mouse_y) * 0.5;
  947. }
  948. old_mouse_x = mouse_x;
  949. old_mouse_y = mouse_y;
  950. mouse_x *= sensitivity.value;
  951. mouse_y *= sensitivity.value;
  952. if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
  953. cmd->sidemove += m_side.value * mouse_x;
  954. else
  955. cl.viewangles[YAW] -= m_yaw.value * mouse_x;
  956. if (in_mlook.state & 1)
  957. V_StopPitchDrift ();
  958. if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
  959. cl.viewangles[PITCH] += m_pitch.value * mouse_y;
  960. if (cl.viewangles[PITCH] > 80)
  961. cl.viewangles[PITCH] = 80;
  962. if (cl.viewangles[PITCH] < -70)
  963. cl.viewangles[PITCH] = -70;
  964. } else {
  965. if ((in_strafe.state & 1) && noclip_anglehack)
  966. cmd->upmove -= m_forward.value * mouse_y;
  967. else
  968. cmd->forwardmove -= m_forward.value * mouse_y;
  969. }
  970. mouse_x = mouse_y = 0.0;
  971. }