1 #include <unistd.h>
2
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <assert.h>
6 #include <sys/ipc.h>
7 #include <sys/shm.h>
8
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
11 #include <X11/keysym.h>
12
13 #include <X11/extensions/XShm.h>
14 /*
15 * Had to dig up XShm.c for this one.
16 * It is in the libXext, but not in the XFree86 headers.
17 */
18 #ifdef NEED_SHMGETEVENTBASE
19 int XShmGetEventBase( Display* dpy );
20 #endif
21
22 #include <stdarg.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26
27 #include <netinet/in.h>
28 #include <errno.h>
29 #include <signal.h>
30
31 #include "doomdef.h"
32
33 #define SHOW_FPS
34
35 #ifdef SHOW_FPS
36 static struct timeval starttime;
37 static long totalframes;
38 static int showfps = 0;
39
reset_framecounter(void)40 static void reset_framecounter(void)
41 {
42 totalframes = 0;
43 gettimeofday(&starttime, NULL);
44 }
45 #endif
46
47 #define POINTER_WARP_COUNTDOWN 1
48
49 static Display *X_display=0;
50 static Window X_mainWindow;
51 static Colormap X_cmap;
52 static Visual *X_visual;
53 static GC X_gc;
54 static XEvent X_event;
55 static int X_screen;
56 static XVisualInfo X_visualinfo;
57 static XImage *image;
58 static int X_width;
59 static int X_height;
60 static int true_color=FALSE;
61 static Screen *screen_intern;
62 static XColor colors[256];
63 static unsigned long *xpixel;
64
65 /* MIT SHared Memory extension. */
66 static boolean doShm;
67
68 static XShmSegmentInfo X_shminfo;
69 static int X_shmeventtype;
70 static int XShm_is_attached=FALSE;
71
72
73 /*
74 * Fake mouse handling.
75 * This cannot work properly w/o DGA.
76 * Needs an invisible mouse cursor at least.
77 */
78 extern long do_grabMouse;
79 static int doPointerWarp = POINTER_WARP_COUNTDOWN;
80
81 /*
82 * Blocky mode,
83 * replace each 320x200 pixel with multiply*multiply pixels.
84 * According to Dave Taylor, it still is a bonehead thing
85 * to use ....
86 */
87 static int multiply=1;
88
89 /*
90 * pointer to palette update function (different for
91 * true- and pseudocolor)
92 */
93 static void (*up_palette)(Colormap,byte *);
94
95 /* truecolor helper routines */
96 static int init_truec_pals(void);
97 static int free_truec_pals(void);
98 static void fill_pal_cache(int,Colormap,byte *);
99 static int get_pal_usage(void);
100
101 static int oldgamma;
102
103 /*#define PALETTE_DEBUG*/
104 #define PALETTE_INFO /* display # of used cache slots at termination */
105 #define MAX_PAL_CACHE 25 /* number of palettes to cache */
106 #define INI_LRU 1000
107 #define MIN_LRU 10
108
109 /* layout of entry in truecolor palette cache */
110 static struct paldef {
111 caddr_t id; /* contains pointer / id of palette */
112 unsigned long *xpix_ptr; /* pointer to matching xpixel table */
113 unsigned int lru;
114 } *pal_cache;
115
116
clr_pal_cache(int index,Colormap cmap)117 static inline void clr_pal_cache(int index,Colormap cmap)
118 {
119 int j;
120
121 for (j=0; j<256; j++) {
122 XFreeColors(X_display,cmap,pal_cache[index].xpix_ptr+j,1,0);
123 }
124 }
125
126 /*
127 * Translates the key currently in X_event
128 */
129
xlatekey(void)130 int xlatekey(void)
131 {
132
133 int rc;
134
135 switch(rc = XKeycodeToKeysym(X_display, X_event.xkey.keycode, 0))
136 {
137 case XK_Delete: rc = KEY_DELETE; break;
138 case XK_Insert: rc = KEY_INSERT; break;
139 case XK_Page_Up: rc = KEY_PAGEUP; break;
140 case XK_Page_Down:rc = KEY_PAGEDOWN; break;
141 case XK_Home: rc = KEY_HOME; break;
142 case XK_End: rc = KEY_END; break;
143 case XK_Left: rc = KEY_LEFTARROW; break;
144 case XK_Right: rc = KEY_RIGHTARROW; break;
145 case XK_Down: rc = KEY_DOWNARROW; break;
146 case XK_Up: rc = KEY_UPARROW; break;
147 case XK_Escape: rc = KEY_ESCAPE; break;
148 case XK_Return: rc = KEY_ENTER; break;
149 case XK_Tab: rc = KEY_TAB; break;
150 case XK_F1: rc = KEY_F1; break;
151 case XK_F2: rc = KEY_F2; break;
152 case XK_F3: rc = KEY_F3; break;
153 case XK_F4: rc = KEY_F4; break;
154 case XK_F5: rc = KEY_F5; break;
155 case XK_F6: rc = KEY_F6; break;
156 case XK_F7: rc = KEY_F7; break;
157 case XK_F8: rc = KEY_F8; break;
158 case XK_F9: rc = KEY_F9; break;
159 case XK_F10: rc = KEY_F10; break;
160 case XK_F11: rc = KEY_F11; break;
161 case XK_F12: rc = KEY_F12; break;
162
163 case XK_BackSpace:rc = KEY_BACKSPACE; break;
164 case XK_Pause: rc = KEY_PAUSE; break;
165
166 case XK_KP_Add:
167 case XK_plus:
168 /* rc = KEY_PLUS; break; !TODO: define in doomdef.h TODO! */
169 case XK_KP_Equal:
170 case XK_equal: rc = KEY_EQUALS; break;
171
172 case XK_KP_Subtract:
173 case XK_minus: rc = KEY_MINUS; break;
174
175 case XK_KP_0: rc = '0'; break;
176 case XK_KP_1: rc = '1'; break;
177 case XK_KP_2: rc = '2'; break;
178 case XK_KP_3: rc = '3'; break;
179 case XK_KP_4: rc = '4'; break;
180 case XK_KP_5: rc = '5'; break;
181 case XK_KP_6: rc = '6'; break;
182 case XK_KP_7: rc = '7'; break;
183 case XK_KP_8: rc = '8'; break;
184 case XK_KP_9: rc = '9'; break;
185
186 /* This is an ugly PC-ism. Better switch to XLookupKeysym() ? */
187 case XK_KP_Insert: rc = '0'; break;
188 case XK_KP_End: rc = '1'; break;
189 case XK_KP_Down: rc = '2'; break;
190 case XK_KP_Page_Down: rc = '3'; break;
191 case XK_KP_Left: rc = '4'; break;
192 case XK_KP_Begin: rc = '5'; break;
193 case XK_KP_Right: rc = '6'; break;
194 case XK_KP_Home: rc = '7'; break;
195 case XK_KP_Up: rc = '8'; break;
196 case XK_KP_Page_Up: rc = '9'; break;
197
198 case XK_Shift_L:
199 case XK_Shift_R:
200 rc = KEY_RSHIFT;
201 break;
202
203 case XK_Control_L:
204 case XK_Control_R:
205 rc = KEY_RCTRL;
206 break;
207
208 case XK_Alt_L:
209 case XK_Meta_L:
210 case XK_Alt_R:
211 case XK_Meta_R:
212 rc = KEY_RALT;
213 break;
214
215 default:
216 if (rc >= XK_space && rc <= XK_asciitilde)
217 rc = rc - XK_space + ' ';
218 if (rc >= 'A' && rc <= 'Z')
219 rc = rc - 'A' + 'a';
220 break;
221 }
222
223 return rc;
224 }
225
I_ShutdownGraphics(void)226 void I_ShutdownGraphics(void)
227 {
228 if (true_color) {
229 #ifdef PALETTE_INFO
230 fprintf(stderr,"TrueColor palette cache: %d/%d entries used.\n",
231 get_pal_usage(),MAX_PAL_CACHE);
232 #endif
233 free_truec_pals();
234 sleep(2);
235 }
236
237 if (XShm_is_attached) {
238 /* Detach from X server */
239 if (!XShmDetach(X_display, &X_shminfo))
240 I_Error("XShmDetach() failed in I_ShutdownGraphics()");
241
242 /* Release shared memory. */
243 shmdt(X_shminfo.shmaddr);
244 shmctl(X_shminfo.shmid, IPC_RMID, 0);
245 }
246
247 /* Paranoia. Yes: needed! */
248 if (image)
249 image->data = NULL;
250 }
251
252
253 /*
254 * I_StartFrame
255 */
I_StartFrame(void)256 void I_StartFrame (void)
257 {
258 /* er? */
259 }
260
261 static int lastmousex = 0;
262 static int lastmousey = 0;
263 static boolean mousemoved = false;
264 static boolean shmFinished;
265
I_GetEvent(void)266 void I_GetEvent(void)
267 {
268
269 event_t event;
270
271 /* put event-grabbing stuff in here */
272 XNextEvent(X_display, &X_event);
273 switch (X_event.type)
274 {
275 case KeyPress:
276 event.type = ev_keydown;
277 event.data1 = xlatekey();
278 #ifdef SHOW_FPS
279 if (event.data1 == KEY_BACKSPACE &&
280 gamestate == GS_LEVEL) {
281 /* Toggle and reset the FPS counter */
282 showfps = !showfps;
283 reset_framecounter();
284 }
285 #endif
286 D_PostEvent(&event);
287 /* fprintf(stderr, "k"); */
288 break;
289 case KeyRelease:
290 event.type = ev_keyup;
291 event.data1 = xlatekey();
292 D_PostEvent(&event);
293 /* fprintf(stderr, "ku"); */
294 break;
295 case ButtonPress:
296 event.type = ev_mouse;
297 event.data1 =
298 (X_event.xbutton.state & Button1Mask)
299 | (X_event.xbutton.state & Button2Mask ? 2 : 0)
300 | (X_event.xbutton.state & Button3Mask ? 4 : 0)
301 | (X_event.xbutton.button == Button1)
302 | (X_event.xbutton.button == Button2 ? 2 : 0)
303 | (X_event.xbutton.button == Button3 ? 4 : 0);
304 event.data2 = event.data3 = 0;
305 D_PostEvent(&event);
306 /* fprintf(stderr, "b"); */
307 break;
308 case ButtonRelease:
309 event.type = ev_mouse;
310 event.data1 =
311 (X_event.xbutton.state & Button1Mask)
312 | (X_event.xbutton.state & Button2Mask ? 2 : 0)
313 | (X_event.xbutton.state & Button3Mask ? 4 : 0);
314 /* suggest parentheses around arithmetic in operand of | */
315 event.data1 =
316 event.data1
317 ^ (X_event.xbutton.button == Button1 ? 1 : 0)
318 ^ (X_event.xbutton.button == Button2 ? 2 : 0)
319 ^ (X_event.xbutton.button == Button3 ? 4 : 0);
320 event.data2 = event.data3 = 0;
321 D_PostEvent(&event);
322 /* fprintf(stderr, "bu"); */
323 break;
324 case MotionNotify:
325 event.type = ev_mouse;
326 event.data1 =
327 (X_event.xmotion.state & Button1Mask)
328 | (X_event.xmotion.state & Button2Mask ? 2 : 0)
329 | (X_event.xmotion.state & Button3Mask ? 4 : 0);
330 event.data2 = (X_event.xmotion.x - lastmousex) << 2;
331 event.data3 = (lastmousey - X_event.xmotion.y) << 2;
332
333 if (event.data2 || event.data3)
334 {
335 lastmousex = X_event.xmotion.x;
336 lastmousey = X_event.xmotion.y;
337 if (X_event.xmotion.x != X_width/2 &&
338 X_event.xmotion.y != X_height/2)
339 {
340 D_PostEvent(&event);
341 /* fprintf(stderr, "m"); */
342 mousemoved = false;
343 } else
344 {
345 mousemoved = true;
346 }
347 }
348 break;
349
350 case Expose:
351 case ConfigureNotify:
352 break;
353
354 default:
355 if (doShm && X_event.type == X_shmeventtype) shmFinished = true;
356 break;
357 }
358 }
359
createnullcursor(Display * display,Window root)360 static Cursor createnullcursor(Display* display,Window root)
361 {
362 Pixmap cursormask;
363 XGCValues xgc;
364 GC gc;
365 XColor dummycolour;
366 Cursor cursor;
367
368 cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
369 xgc.function = GXclear;
370 gc = XCreateGC(display, cursormask, GCFunction, &xgc);
371 XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
372 dummycolour.pixel = 0;
373 dummycolour.red = 0;
374 dummycolour.flags = 04;
375 cursor = XCreatePixmapCursor(display, cursormask, cursormask,
376 &dummycolour,&dummycolour, 0,0);
377 XFreePixmap(display,cursormask);
378 XFreeGC(display,gc);
379 return cursor;
380 }
381
382 /*
383 * I_StartTic
384 */
I_StartTic(void)385 void I_StartTic (void)
386 {
387 if (!X_display)
388 return;
389
390 while (XPending(X_display))
391 I_GetEvent();
392
393 /*
394 * Warp the pointer back to the middle of the window
395 * or it will wander off - that is, the game will
396 * loose input focus within X11.
397 */
398 if (do_grabMouse)
399 {
400 if (!--doPointerWarp)
401 {
402 XWarpPointer( X_display,
403 None,
404 X_mainWindow,
405 0, 0,
406 0, 0,
407 X_width/2, X_height/2);
408
409 doPointerWarp = POINTER_WARP_COUNTDOWN;
410 }
411 }
412
413 mousemoved = false;
414 }
415
416
417 /*
418 * I_FinishUpdate
419 */
I_FinishUpdate(void)420 void I_FinishUpdate (void)
421 {
422 static int lasttic=0;
423 int tics,i,l,l2,c,cc,ll;
424 unsigned char p;
425 long color;
426 boolean devparm=1; /* You can change this to 1 for little dots on the screen ! */
427
428 /* draws little dots on the bottom of the screen */
429 if (devparm) {
430 i = I_GetTime();
431 tics = i - lasttic;
432 lasttic = i;
433 if (tics > 20) tics = 20;
434
435 for (i=0 ; i<tics*2 ; i+=2)
436 screen[ (screenheight-1)*screenwidth + i] = 0xff;
437 for ( ; i<20*2 ; i+=2)
438 screen[ (screenheight-1)*screenwidth + i] = 0x0;
439 }
440
441 /* Filters the first 32 palette-entry-color'd(gray-color) pixels if wanted */
442 if (lifilter && !bilifilter)
443 V_Filter_Screen_linear(screen);
444 if (bilifilter && !lifilter)
445 V_Filter_Screen_bilinear(screen);
446
447 if (true_color) {
448 if (multiply == 1) {
449 for (l=0,l2=0; l<screenheight; l++, l2+=screenwidth) {
450 for (c=0; c<screenwidth; c++) {
451 p=screen[l2+c];
452 color=xpixel[p];
453 XPutPixel(image,c,l,color);
454 }
455 }
456 }
457 else if (multiply == 2) {
458 for (l=0,l2=0; l<screenheight; l++, l2+=screenwidth) {
459 for (c=0; c<screenwidth; c++) {
460 p=screen[l2+c];
461 color=xpixel[p];
462 XPutPixel(image,c+c, l+l, color);
463 XPutPixel(image,c+c+1,l+l, color);
464 XPutPixel(image,c+c, l+l+1,color);
465 XPutPixel(image,c+c+1,l+l+1,color);
466 }
467 }
468 }
469 else if (multiply == 3) {
470 for (l=0,l2=0; l<screenheight; l++, l2+=screenwidth) {
471 for (c=0; c<screenwidth; c++) {
472 p=screen[l2+c];
473 color=xpixel[p];
474 cc=c+c+c; ll=l+l+l;
475 XPutPixel(image,cc, ll, color);
476 XPutPixel(image,cc+1,ll, color);
477 XPutPixel(image,cc+2,ll, color);
478 XPutPixel(image,cc, ll+1,color);
479 XPutPixel(image,cc+1,ll+1,color);
480 XPutPixel(image,cc+2,ll+1,color);
481 XPutPixel(image,cc, ll+2,color);
482 XPutPixel(image,cc+1,ll+2,color);
483 XPutPixel(image,cc+2,ll+2,color);
484 }
485 }
486 }
487 else { /* multiply == 4 */
488 for (l=0,l2=0; l<screenheight; l++, l2+=screenwidth) {
489 for (c=0; c<screenwidth; c++) {
490 p=screen[l2+c];
491 color=xpixel[p];
492 cc=c<<2; ll=l<<2;
493 XPutPixel(image,cc, ll, color);
494 XPutPixel(image,cc+1,ll, color);
495 XPutPixel(image,cc+2,ll, color);
496 XPutPixel(image,cc+3,ll, color);
497 XPutPixel(image,cc, ll+1,color);
498 XPutPixel(image,cc+1,ll+1,color);
499 XPutPixel(image,cc+2,ll+1,color);
500 XPutPixel(image,cc+3,ll+1,color);
501 XPutPixel(image,cc, ll+2,color);
502 XPutPixel(image,cc+1,ll+2,color);
503 XPutPixel(image,cc+2,ll+2,color);
504 XPutPixel(image,cc+3,ll+2,color);
505 XPutPixel(image,cc, ll+3,color);
506 XPutPixel(image,cc+1,ll+3,color);
507 XPutPixel(image,cc+2,ll+3,color);
508 XPutPixel(image,cc+3,ll+3,color);
509 }
510 }
511 }
512 }
513 else { /* not truecolor */
514 /* scales the screen size before blitting it */
515 if (multiply == 2) {
516 unsigned int *olineptrs[2];
517 unsigned int *ilineptr;
518 int x,y;
519 unsigned int twoopixels;
520 unsigned int twomoreopixels;
521 unsigned int fouripixels;
522
523 ilineptr = (unsigned int *) (screen);
524 for (i=0 ; i<2 ; i++)
525 olineptrs[i] = (unsigned int *) &image->data[i*X_width];
526
527 y = screenheight;
528 while (y--) {
529 x = screenwidth;
530 do {
531 fouripixels = *ilineptr++;
532 twoopixels = (fouripixels & 0xff000000)
533 | ((fouripixels>>8) & 0xffff00)
534 | ((fouripixels>>16) & 0xff);
535 twomoreopixels = ((fouripixels<<16) & 0xff000000)
536 | ((fouripixels<<8) & 0xffff00)
537 | (fouripixels & 0xff);
538 #ifdef __BIG_ENDIAN__
539 *olineptrs[0]++ = twoopixels;
540 *olineptrs[1]++ = twoopixels;
541 *olineptrs[0]++ = twomoreopixels;
542 *olineptrs[1]++ = twomoreopixels;
543 #else
544 *olineptrs[0]++ = twomoreopixels;
545 *olineptrs[1]++ = twomoreopixels;
546 *olineptrs[0]++ = twoopixels;
547 *olineptrs[1]++ = twoopixels;
548 #endif
549 } while (x-=4);
550 olineptrs[0] += X_width/4;
551 olineptrs[1] += X_width/4;
552 }
553 }
554 else if (multiply == 3) {
555 unsigned int *olineptrs[3];
556 unsigned int *ilineptr;
557 int x,y;
558 unsigned int fouropixels[3];
559 unsigned int fouripixels;
560
561 ilineptr = (unsigned int *) (screen);
562 for (i=0 ; i<3 ; i++)
563 olineptrs[i] = (unsigned int *) &image->data[i*X_width];
564
565 y = screenheight;
566 while (y--) {
567 x = screenwidth;
568 do {
569 fouripixels = *ilineptr++;
570 fouropixels[0] = (fouripixels & 0xff000000)
571 | ((fouripixels>>8) & 0xff0000)
572 | ((fouripixels>>16) & 0xffff);
573 fouropixels[1] = ((fouripixels<<8) & 0xff000000)
574 | (fouripixels & 0xffff00)
575 | ((fouripixels>>8) & 0xff);
576 fouropixels[2] = ((fouripixels<<16) & 0xffff0000)
577 | ((fouripixels<<8) & 0xff00)
578 | (fouripixels & 0xff);
579 #ifdef __BIG_ENDIAN__
580 *olineptrs[0]++ = fouropixels[0];
581 *olineptrs[1]++ = fouropixels[0];
582 *olineptrs[2]++ = fouropixels[0];
583 *olineptrs[0]++ = fouropixels[1];
584 *olineptrs[1]++ = fouropixels[1];
585 *olineptrs[2]++ = fouropixels[1];
586 *olineptrs[0]++ = fouropixels[2];
587 *olineptrs[1]++ = fouropixels[2];
588 *olineptrs[2]++ = fouropixels[2];
589 #else
590 *olineptrs[0]++ = fouropixels[2];
591 *olineptrs[1]++ = fouropixels[2];
592 *olineptrs[2]++ = fouropixels[2];
593 *olineptrs[0]++ = fouropixels[1];
594 *olineptrs[1]++ = fouropixels[1];
595 *olineptrs[2]++ = fouropixels[1];
596 *olineptrs[0]++ = fouropixels[0];
597 *olineptrs[1]++ = fouropixels[0];
598 *olineptrs[2]++ = fouropixels[0];
599 #endif
600 } while (x-=4);
601 olineptrs[0] += 2*X_width/4;
602 olineptrs[1] += 2*X_width/4;
603 olineptrs[2] += 2*X_width/4;
604 }
605 }
606 else if (multiply == 4) {
607 /* Broken. Gotta fix this some day. */
608 void Expand4(unsigned *, double *);
609 Expand4 ((unsigned *)(screen), (double *) (image->data));
610 }
611 } /* if not truecolor */
612
613 if (doShm) {
614 if (!XShmPutImage(X_display,
615 X_mainWindow,
616 X_gc,
617 image,
618 0, 0,
619 0, 0,
620 X_width,X_height,
621 True))
622 I_Error("XShmPutImage() failed\n");
623
624 /* wait for it to finish and processes all input events */
625 shmFinished = false;
626 do {
627 I_GetEvent();
628 } while (!shmFinished);
629 }
630 else {
631 /* draw the image */
632 XPutImage(X_display,
633 X_mainWindow,
634 X_gc,
635 image,
636 0, 0,
637 0, 0,
638 X_width,X_height);
639
640 /* sync up with server */
641 XSync(X_display, False);
642 }
643 #ifdef SHOW_FPS
644 if (showfps) {
645 struct timeval curtime;
646 double diff;
647 char str[64];
648
649 totalframes++;
650 gettimeofday(&curtime, NULL);
651 diff = (curtime.tv_sec - starttime.tv_sec);
652 diff += ((double)curtime.tv_usec - starttime.tv_usec)/1000000;
653 if (diff != 0) {
654 sprintf(str, "FPS: %.1f", totalframes/diff);
655 XDrawString(X_display, X_mainWindow, X_gc, 0, 16, str,
656 strlen(str));
657 }
658 }
659 #endif
660 }
661
662
663 /*
664 * Palette stuff.
665 *
666 * PseudoColor version
667 */
UploadNewPalette(Colormap cmap,byte * palette)668 static void UploadNewPalette(Colormap cmap, byte *palette)
669 {
670 register int i;
671 register int c;
672 static boolean firstcall = TRUE;
673
674 if (X_visualinfo.class == PseudoColor && X_visualinfo.depth == 8) {
675 /* initialize the colormap */
676 if (firstcall) {
677 firstcall = FALSE;
678 for (i=0 ; i<256 ; i++) {
679 colors[i].pixel = i;
680 colors[i].flags = DoRed|DoGreen|DoBlue;
681 }
682 }
683
684 /* set the X colormap entries */
685 for (i=0 ; i<256 ; i++) {
686 c = gammatable[usegamma][*palette++];
687 colors[i].red = (c<<8) + c;
688 c = gammatable[usegamma][*palette++];
689 colors[i].green = (c<<8) + c;
690 c = gammatable[usegamma][*palette++];
691 colors[i].blue = (c<<8) + c;
692 }
693
694 /* store the colors to the current colormap */
695 XStoreColors(X_display, cmap, colors, 256);
696 }
697 else {
698 fprintf(stderr,"UploadNewPalette: unknown visual type!\n");
699 }
700 }
701
702 /*
703 * Truecolor "palette" update
704 */
UploadNewTruePal(Colormap cmap,byte * palette)705 static void UploadNewTruePal(Colormap cmap, byte *palette)
706 {
707 int least,lru,i,found=FALSE;
708
709 /* use the palette pointer as palette id, i.e. a palette
710 * with another pointer value is assumed to be a different
711 * palette, and, more important, if the pointer is equal,
712 * the palette is assumed to be the same...
713 */
714
715 #ifdef PALETTE_DEBUG
716 fprintf(stderr,"UploadNewTruePal: entered with %p -- gamma %d\n",palette,usegamma);
717 #endif
718
719 if (usegamma != oldgamma) { /* if gamma value changed since last invokation */
720 #ifdef PALETTE_DEBUG
721 fprintf(stderr,"\tnew gamma value -- discarding cache\n");
722 #endif
723 oldgamma=usegamma;
724 for (i=0; i<MAX_PAL_CACHE; i++) { /* discard old palette cache */
725 if (pal_cache[i].id) clr_pal_cache(i,cmap);
726 pal_cache[i].id=0; /* mark entry as empty */
727 }
728 }
729
730 /* search ptr in table */
731 for (i=0; i<MAX_PAL_CACHE; i++) {
732 if (pal_cache[i].id == (caddr_t)palette) {
733 #ifdef PALETTE_DEBUG
734 fprintf(stderr,"\tfound palette, index %d\n",i);
735 #endif
736 xpixel=pal_cache[i].xpix_ptr;
737 pal_cache[i].lru=INI_LRU;
738 found=TRUE;
739 }
740 else {
741 if (pal_cache[i].lru > MIN_LRU) pal_cache[i].lru--;
742 }
743 }
744 if (found) return;
745 #ifdef PALETTE_DEBUG
746 fprintf (stderr,"\tNOT FOUND\n");
747 #endif
748
749 /* palette not yet in my table -- search empty entry */
750 for (i=0, found=FALSE; i<MAX_PAL_CACHE; i++) {
751 if (! pal_cache[i].id) {
752 found=TRUE;
753 break;
754 }
755 }
756 if (found) {
757 #ifdef PALETTE_DEBUG
758 fprintf(stderr,"\tfound empty: index %d\n",i);
759 #endif
760 fill_pal_cache(i,cmap,palette);
761 return;
762 }
763 #ifdef PALETTE_DEBUG
764 fprintf(stderr,"\tno empty entry found \n");
765 #endif
766
767 /* no empty entry -- search a least recently used entry */
768 for (least=-1,i=0,lru=INI_LRU; i<MAX_PAL_CACHE; i++) {
769 if (pal_cache[i].lru < lru) {
770 lru=pal_cache[i].lru;
771 least=i;
772 }
773 }
774 if (least == -1) {
775 fprintf(stderr,"UploadNewTruePal: palette cache inconsistency!\n");
776 return;
777 }
778 #ifdef PALETTE_DEBUG
779 fprintf(stderr,"\treusing entry %d\n",least);
780 #endif
781 clr_pal_cache(least,cmap); /* free old entries */
782 fill_pal_cache(least,cmap,palette); /* alloc new entries */
783 return;
784 }
785
fill_pal_cache(int index,Colormap cmap,byte * palette)786 static void fill_pal_cache(int index,Colormap cmap,byte *palette)
787 {
788 unsigned int i,c;
789 XColor color;
790 void *dummy;
791
792 if (!pal_cache[index].xpix_ptr) { /* memory for palette not yet allocated */
793 {
794 dummy=malloc(256 * sizeof(long));
795 assert(dummy);
796 if (! (pal_cache[index].xpix_ptr=dummy))
797 {
798 fprintf(stderr,"fill_pal_cache: failed to allocate palette buffer\n");
799 return;
800 }
801 }
802 }
803
804 xpixel=pal_cache[index].xpix_ptr;
805 pal_cache[index].id=(caddr_t)palette; /* set id */
806
807 for (i=0; i<256; i++) {
808 color.pixel = 0;
809 color.flags = DoRed|DoGreen|DoBlue;
810 c = gammatable[usegamma][*palette++];
811 color.red = c << 8;
812 c = gammatable[usegamma][*palette++];
813 color.green = c << 8;
814 c = gammatable[usegamma][*palette++];
815 color.blue = c << 8;
816
817 if (XAllocColor(X_display,cmap,&color)) {
818 xpixel[i]=color.pixel;
819 }
820 else {
821 fprintf(stderr,"fill_pal_cache: cannot alloc color %d\n",i);
822 }
823 }
824 }
825
get_pal_usage(void)826 static int get_pal_usage(void)
827 {
828 int i,count=0;
829
830 if (pal_cache)
831 for (i=0; i<MAX_PAL_CACHE; i++)
832 if (pal_cache[i].id)
833 count++;
834 return(count);
835 }
836
init_truec_pals(void)837 static int init_truec_pals(void)
838 {
839 pal_cache=malloc(MAX_PAL_CACHE * sizeof(struct paldef));
840 assert(pal_cache);
841 if (!pal_cache) return(FALSE);
842 memset(pal_cache,0,MAX_PAL_CACHE * sizeof(struct paldef));
843 return(TRUE);
844 }
845
free_truec_pals(void)846 static int free_truec_pals(void)
847 {
848 int i;
849
850 if (pal_cache) {
851 for (i=0; i<MAX_PAL_CACHE; i++) {
852 if (pal_cache[i].xpix_ptr) {
853 clr_pal_cache(i,X_cmap);
854 free(pal_cache[i].xpix_ptr);
855 }
856 }
857 free(pal_cache);
858 }
859 return(TRUE);
860 }
861
862 /*
863 * I_SetPalette
864 */
I_SetPalette(byte * palette)865 void I_SetPalette (byte* palette)
866 {
867 if (up_palette)
868 (up_palette)(X_cmap, palette);
869 else
870 fprintf(stderr,"i_x11: up_palette called before initialization!!!\n");
871 }
872
873
874 /*
875 * This function is probably redundant,
876 * if XShmDetach works properly.
877 * ddt never detached the XShm memory,
878 * thus there might have been stale
879 * handles accumulating.
880 */
grabsharedmemory(size_t size)881 void grabsharedmemory(size_t size)
882 {
883
884 int key = ('d'<<24) | ('o'<<16) | ('o'<<8) | 'm';
885 struct shmid_ds shminfo;
886 int minsize = screenwidth * screenheight; /* 320*200; */
887 int id;
888 int rc;
889 /* UNUSED int done=0; */
890 int pollution=5;
891
892 /* try to use what was here before */
893 do
894 {
895 id = shmget((key_t) key, minsize, 0777); /* just get the id */
896 if (id != -1)
897 {
898 rc=shmctl(id, IPC_STAT, &shminfo); /* get stats on it */
899 if (!rc)
900 {
901 if (shminfo.shm_nattch)
902 {
903 fprintf(stderr, "User %d appears to be running "
904 "Heretic. Is that wise?\n", shminfo.shm_cpid);
905 key++;
906 }
907 else
908 {
909 if (getuid() == shminfo.shm_perm.cuid)
910 {
911 rc = shmctl(id, IPC_RMID, 0);
912 if (!rc)
913 fprintf(stderr,
914 "Was able to kill my old shared memory\n");
915 else
916 I_Error("Was NOT able to kill my old shared memory");
917
918 id = shmget((key_t)key, size, IPC_CREAT|0777);
919 if (id==-1)
920 I_Error("Could not get shared memory");
921
922 rc=shmctl(id, IPC_STAT, &shminfo);
923
924 break;
925
926 }
927 if (size >= shminfo.shm_segsz)
928 {
929 fprintf(stderr,
930 "will use %d's stale shared memory\n",
931 shminfo.shm_cpid);
932 break;
933 }
934 else
935 {
936 fprintf(stderr,
937 "warning: can't use stale "
938 "shared memory belonging to id %d, "
939 "key=0x%x\n",
940 shminfo.shm_cpid, key);
941 key++;
942 }
943 }
944 }
945 else
946 {
947 I_Error("could not get stats on key=%d", key);
948 }
949 }
950 else
951 {
952 id = shmget((key_t)key, size, IPC_CREAT|0777);
953 if (id==-1)
954 {
955 /* extern int errno; */
956 fprintf(stderr, "errno=%d\n", errno);
957 I_Error("Could not get any shared memory");
958 }
959 break;
960 }
961 } while (--pollution);
962
963 if (!pollution)
964 {
965 I_Error("Sorry, system too polluted with stale "
966 "shared memory segments.\n");
967 }
968
969 X_shminfo.shmid = id;
970
971 /* attach to the shared memory segment */
972 image->data = X_shminfo.shmaddr = shmat(id, 0, 0);
973
974 fprintf(stderr, "shared memory id=%d, addr=0x%lx\n", id,
975 (unsigned long) (image->data));
976 }
977
InitGraphLib(void)978 void InitGraphLib(void)
979 {
980 /* not needed, dummy for X11 */
981 }
982
I_InitGraphics(void)983 void I_InitGraphics(void)
984 {
985 char* displayname;
986 char* d;
987 int n;
988 int pnum;
989 int x=0;
990 int y=0;
991 char *dummy_data;
992
993
994 /* warning: char format, different type arg */
995 /*
996 * char xsign=' ';
997 * char ysign=' ';
998 */
999 int oktodraw;
1000 unsigned long attribmask;
1001 XSetWindowAttributes attribs;
1002 XGCValues xgcvalues;
1003 XSizeHints hints = {flags : 0};
1004 int valuemask;
1005 static int firsttime=1;
1006
1007 if (!firsttime)
1008 return;
1009 firsttime = 0;
1010
1011 signal(SIGINT, (void (*)(int)) I_Quit);
1012
1013 if (M_CheckParm("-2"))
1014 multiply = 2;
1015
1016 if (M_CheckParm("-3"))
1017 multiply = 3;
1018
1019 if (M_CheckParm("-4"))
1020 multiply = 4;
1021
1022 if (M_CheckParm("-mode") && multiply != 1) {
1023 multiply=1; /* multiply only works in 320x200 mode yet */
1024 fprintf(stderr,"Screen stretching disabled due to -mode switch\n");
1025 }
1026
1027 X_width = screenwidth * multiply;
1028 X_height = screenheight * multiply;
1029
1030 /* check for command-line display name */
1031 if ((pnum = M_CheckParm("-display")))
1032 displayname = myargv[pnum+1];
1033 else
1034 displayname = 0;
1035
1036 /* check if the user wants to grab the mouse (quite unnice) */
1037 if (!do_grabMouse && M_CheckParm("-grabmouse"))
1038 do_grabMouse = 1;
1039
1040 /* open the display */
1041 X_display = XOpenDisplay(displayname);
1042 if (!X_display)
1043 {
1044 if (displayname)
1045 I_Error("Could not open display [%s]", displayname);
1046 else
1047 I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
1048 }
1049
1050 /* use the default visual */
1051 screen_intern = DefaultScreenOfDisplay(X_display);
1052 X_screen = DefaultScreen(X_display);
1053 if (!XMatchVisualInfo(X_display,X_screen,8,PseudoColor,&X_visualinfo)) {
1054 true_color=TRUE; /* OK, be slower, but try to work.... */
1055 if (XMatchVisualInfo(X_display,X_screen,8,TrueColor,&X_visualinfo)) {
1056 fprintf(stderr,"I_InitGraphics: using 8bit truecolor visual\n");
1057 }
1058 else if (XMatchVisualInfo(X_display,X_screen,16,TrueColor,&X_visualinfo)) {
1059 fprintf(stderr,"I_InitGraphics: using 16bit truecolor visual\n");
1060 }
1061 else if (XMatchVisualInfo(X_display,X_screen,15,TrueColor,&X_visualinfo)) {
1062 fprintf(stderr,"I_InitGraphics: using 15bit truecolor visual\n");
1063 }
1064 else if (XMatchVisualInfo(X_display,X_screen,24,TrueColor,&X_visualinfo)) {
1065 fprintf(stderr,"I_InitGraphics: using 24bit truecolor visual\n");
1066 }
1067 else if (XMatchVisualInfo(X_display,X_screen,32,TrueColor,&X_visualinfo)) {
1068 fprintf(stderr,"I_InitGraphics: using 32bit truecolor visual\n");
1069 }
1070 else {
1071 I_Error("unsupported display type (not 8, 16, 24 or 32bit colors)");
1072 }
1073 }
1074 else {
1075 fprintf(stderr,"I_InitGraphics: using 8bit pseudocolor visual, good!\n");
1076 }
1077 X_visual = X_visualinfo.visual;
1078 X_visual->red_mask=0;
1079 X_visual->blue_mask=0;
1080 X_visual->green_mask=0;
1081
1082 if (!true_color) {
1083 up_palette=UploadNewPalette; /* set update-palette function */
1084 }
1085 else {
1086 up_palette=UploadNewTruePal;
1087 oldgamma=usegamma;
1088 if (!init_truec_pals()) {
1089 I_Error("Truecolor mode: cannot allocate memory for palette cache");
1090 }
1091 }
1092
1093 /* check for the MITSHM extension */
1094 if (!M_CheckParm("-noshm"))
1095 doShm = XShmQueryExtension(X_display);
1096 else {
1097 doShm =FALSE;
1098 fprintf(stderr,"I_InitGraphics: SHM disabled via user request!\n");
1099 }
1100
1101 /* even if it's available, make sure it's a local connection */
1102 if (doShm)
1103 {
1104 if (!displayname) displayname = (char *) getenv("DISPLAY");
1105 if (displayname)
1106 {
1107 d = displayname;
1108 while (*d && (*d != ':')) d++;
1109 if (*d) *d = 0;
1110 if (!(!strcasecmp(displayname, "unix") || !*displayname)) doShm = false;
1111 }
1112 }
1113
1114 if (doShm)
1115 fprintf(stderr, "Using MITSHM extension\n");
1116 else
1117 fprintf(stderr, "MITSHM extension not available, disabled or remote display\n");
1118
1119 /* create the colormap */
1120 if (!true_color)
1121 X_cmap = XCreateColormap(X_display,RootWindow(X_display,X_screen),
1122 X_visual,AllocAll);
1123 else
1124 X_cmap = DefaultColormapOfScreen(screen_intern);
1125
1126 /* setup attributes for main window */
1127 attribmask = CWEventMask | CWColormap | CWBorderPixel;
1128 attribs.event_mask = KeyPressMask
1129 | KeyReleaseMask
1130 /* | PointerMotionMask | ButtonPressMask | ButtonReleaseMask */
1131 | ExposureMask;
1132
1133 attribs.colormap = X_cmap;
1134 attribs.border_pixel = 0;
1135
1136 /* set up position and size hints */
1137 hints.width = X_width;
1138 hints.height = X_height;
1139 hints.min_width = X_width;
1140 hints.max_width = X_width;
1141 hints.min_height = X_height;
1142 hints.max_height = X_height;
1143 hints.flags |= USSize | PMinSize | PMaxSize;
1144
1145 /* check for command-line geometry */
1146 if ((pnum = M_CheckParm("-geometry")))
1147 {
1148 /* not used, really */
1149 unsigned int w, h;
1150 n = XParseGeometry(myargv[pnum + 1], &x, &y, &w, &h);
1151
1152 if (!(n & AllValues))
1153 I_Error("bad -geometry parameter");
1154
1155 if (n & XValue || n & YValue);
1156 hints.flags |= USPosition;
1157
1158 if (n & WidthValue || n & HeightValue)
1159 fprintf(stderr, "Specified width and height ignored.\n");
1160
1161 hints.flags |= PWinGravity;
1162 switch ( n& (XNegative | YNegative))
1163 {
1164 case 0:
1165 hints.win_gravity = NorthWestGravity;
1166 break;
1167 case XNegative:
1168 hints.win_gravity = NorthEastGravity;
1169 break;
1170 case YNegative:
1171 hints.win_gravity = SouthWestGravity;
1172 break;
1173 default:
1174 hints.win_gravity = SouthEastGravity;
1175 break;
1176 }
1177
1178 if ((n & XValue) && (n & XNegative))
1179 x += DisplayWidth(X_display, X_screen) - X_width;
1180 if ((n & YValue) && (n & YNegative))
1181 y += DisplayHeight(X_display, X_screen) - X_height;
1182 }
1183
1184 hints.x = x;
1185 hints.y = y;
1186
1187 /* create the main window */
1188 X_mainWindow = XCreateWindow(X_display,
1189 RootWindow(X_display, X_screen),
1190 x, y,
1191 X_width, X_height,
1192 0, /* borderwidth */
1193 X_visualinfo.depth,
1194 InputOutput,
1195 X_visual,
1196 attribmask,
1197 &attribs);
1198
1199 /* Set the Name of the main XWindow */
1200 XStoreName(X_display, X_mainWindow, "XHeretic ported by A. Werthmann");
1201
1202 /* Set the Name of the Icon */
1203 XSetIconName(X_display, X_mainWindow, "XHeretic");
1204
1205 /* Set window manager hints */
1206 XSetWMNormalHints(X_display, X_mainWindow, &hints);
1207
1208
1209 XDefineCursor(X_display, X_mainWindow,
1210 createnullcursor( X_display, X_mainWindow ) );
1211
1212 /* create the GC */
1213 valuemask = GCGraphicsExposures;
1214 xgcvalues.graphics_exposures = False;
1215 X_gc = XCreateGC(X_display,X_mainWindow,valuemask,&xgcvalues);
1216
1217 /* map the window */
1218 XMapWindow(X_display, X_mainWindow);
1219
1220 /* wait until it is OK to draw */
1221 oktodraw = 0;
1222 while (!oktodraw)
1223 {
1224 XNextEvent(X_display, &X_event);
1225 if (X_event.type == Expose
1226 && !X_event.xexpose.count)
1227 {
1228 oktodraw = 1;
1229 }
1230 }
1231
1232 /* grabs the pointer so it is restricted to this window */
1233 if (do_grabMouse)
1234 XGrabPointer(X_display, X_mainWindow, True,
1235 ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
1236 GrabModeAsync, GrabModeAsync,
1237 X_mainWindow, None, CurrentTime);
1238
1239 if (doShm)
1240 {
1241
1242 X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
1243
1244 /* create the image */
1245 image = XShmCreateImage(X_display,
1246 X_visual,
1247 X_visualinfo.depth,
1248 ZPixmap,
1249 0,
1250 &X_shminfo,
1251 X_width,
1252 X_height);
1253
1254 grabsharedmemory(image->bytes_per_line * image->height);
1255
1256
1257 /*
1258 * UNUSED
1259 * create the shared memory segment
1260 * X_shminfo.shmid = shmget (IPC_PRIVATE,
1261 * image->bytes_per_line * image->height, IPC_CREAT | 0777);
1262 * if (X_shminfo.shmid < 0)
1263 * {
1264 * perror("");
1265 * I_Error("shmget() failed in InitGraphics()");
1266 * }
1267 * fprintf(stderr, "shared memory id=%d\n", X_shminfo.shmid);
1268 * attach to the shared memory segment
1269 * image->data = X_shminfo.shmaddr = shmat(X_shminfo.shmid, 0, 0);
1270 */
1271
1272 if (!image->data)
1273 {
1274 perror("");
1275 I_Error("shmat() failed in InitGraphics()");
1276 }
1277
1278 /* get the X server to attach to it */
1279 if (!XShmAttach(X_display, &X_shminfo))
1280 I_Error("XShmAttach() failed in InitGraphics()");
1281 XShm_is_attached=TRUE;
1282 }
1283 else
1284 {
1285 dummy_data = (char*) malloc(X_width * X_height * 4);
1286 assert(dummy_data);
1287
1288 image = XCreateImage(X_display,
1289 X_visual,
1290 X_visualinfo.depth,
1291 ZPixmap,
1292 0,
1293 dummy_data,
1294 X_width, X_height,
1295 (X_visualinfo.depth == 8) ? 8 : 32,
1296 0 /*X_width * (X_visualinfo.depth >> 3)*/);
1297
1298 }
1299
1300 if (multiply == 1 && !true_color)
1301 screen = (unsigned char *) (image->data);
1302 else
1303 {
1304 screen = (unsigned char *) malloc (screenwidth * screenheight);
1305 assert(screen);
1306 }
1307 }
1308
1309
1310 unsigned int exptable[256];
1311
InitExpand(void)1312 void InitExpand (void)
1313 {
1314 int i;
1315
1316 for (i=0 ; i<256 ; i++)
1317 exptable[i] = i | (i<<8) | (i<<16) | (i<<24);
1318 }
1319
1320 double exptable2[256*256];
1321
InitExpand2(void)1322 void InitExpand2 (void)
1323 {
1324 int i;
1325 int j;
1326 double* exp;
1327 union
1328 {
1329 double d;
1330 unsigned int u[2];
1331 } pixel;
1332
1333 printf ("building exptable2...\n");
1334 exp = exptable2;
1335 for (i=0 ; i<256 ; i++)
1336 {
1337 pixel.u[0] = i | (i<<8) | (i<<16) | (i<<24);
1338 for (j=0 ; j<256 ; j++)
1339 {
1340 pixel.u[1] = j | (j<<8) | (j<<16) | (j<<24);
1341 *exp++ = pixel.d;
1342 }
1343 }
1344 printf ("done.\n");
1345 }
1346
1347 int inited;
1348
1349 void
Expand4(unsigned * lineptr,double * xline)1350 Expand4
1351 ( unsigned* lineptr,
1352 double* xline )
1353 {
1354 double dpixel;
1355 unsigned x;
1356 unsigned y;
1357 unsigned fourpixels;
1358 unsigned step;
1359 double* exp;
1360
1361 exp = exptable2;
1362 if (!inited)
1363 {
1364 inited = 1;
1365 InitExpand2 ();
1366 }
1367
1368
1369 step = 3*screenwidth/2;
1370
1371 y = screenheight-1;
1372 do
1373 {
1374 x = screenwidth;
1375
1376 do
1377 {
1378 fourpixels = lineptr[0];
1379
1380 dpixel = *(double *)( (long)exp + ( (fourpixels&0xffff0000)>>13) );
1381 xline[0] = dpixel;
1382 xline[160] = dpixel;
1383 xline[320] = dpixel;
1384 xline[480] = dpixel;
1385
1386 dpixel = *(double *)( (long)exp + ( (fourpixels&0xffff)<<3 ) );
1387 xline[1] = dpixel;
1388 xline[161] = dpixel;
1389 xline[321] = dpixel;
1390 xline[481] = dpixel;
1391
1392 fourpixels = lineptr[1];
1393
1394 dpixel = *(double *)( (long)exp + ( (fourpixels&0xffff0000)>>13) );
1395 xline[2] = dpixel;
1396 xline[162] = dpixel;
1397 xline[322] = dpixel;
1398 xline[482] = dpixel;
1399
1400 dpixel = *(double *)( (long)exp + ( (fourpixels&0xffff)<<3 ) );
1401 xline[3] = dpixel;
1402 xline[163] = dpixel;
1403 xline[323] = dpixel;
1404 xline[483] = dpixel;
1405
1406 fourpixels = lineptr[2];
1407
1408 dpixel = *(double *)( (long)exp + ( (fourpixels&0xffff0000)>>13) );
1409 xline[4] = dpixel;
1410 xline[164] = dpixel;
1411 xline[324] = dpixel;
1412 xline[484] = dpixel;
1413
1414 dpixel = *(double *)( (long)exp + ( (fourpixels&0xffff)<<3 ) );
1415 xline[5] = dpixel;
1416 xline[165] = dpixel;
1417 xline[325] = dpixel;
1418 xline[485] = dpixel;
1419
1420 fourpixels = lineptr[3];
1421
1422 dpixel = *(double *)( (long)exp + ( (fourpixels&0xffff0000)>>13) );
1423 xline[6] = dpixel;
1424 xline[166] = dpixel;
1425 xline[326] = dpixel;
1426 xline[486] = dpixel;
1427
1428 dpixel = *(double *)( (long)exp + ( (fourpixels&0xffff)<<3 ) );
1429 xline[7] = dpixel;
1430 xline[167] = dpixel;
1431 xline[327] = dpixel;
1432 xline[487] = dpixel;
1433
1434 lineptr+=4;
1435 xline+=8;
1436 } while (x-=16);
1437 xline += step;
1438 } while (y--);
1439 }
1440
I_CheckRes()1441 void I_CheckRes()
1442 {
1443 /* nothing to do... */
1444 }
1445
1446
1447