1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
18 // Revision 1.1 2000/02/29 18:21:04 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
23 // DOOM graphics stuff for X11, UNIX.
25 //-----------------------------------------------------------------------------
36 #include <X11/Xutil.h>
37 #include <X11/keysym.h>
39 #include <X11/extensions/XShm.h>
40 // Had to dig up XShm.c for this one.
41 // It is in the libXext, but not in the XFree86 headers.
43 int XShmGetEventBase( Display
* dpy
); // problems with g++?
48 #include <sys/types.h>
49 #include <sys/socket.h>
51 #include <netinet/in.h>
63 #define POINTER_WARP_COUNTDOWN 1
72 XVisualInfo X_visualinfo
;
77 // MIT SHared Memory extension.
80 XShmSegmentInfo X_shminfo
;
83 // Fake mouse handling.
84 // This cannot work properly w/o DGA.
85 // Needs an invisible mouse cursor at least.
87 int doPointerWarp
= POINTER_WARP_COUNTDOWN
;
90 // replace each 320x200 pixel with multiply*multiply pixels.
91 // According to Dave Taylor, it still is a bonehead thing
93 static int multiply
=1;
97 // Translates the key currently in X_event
105 switch(rc
= XKeycodeToKeysym(X_display
, X_event
.xkey
.keycode
, 0))
107 case XK_Left
: rc
= KEY_LEFTARROW
; break;
108 case XK_Right
: rc
= KEY_RIGHTARROW
; break;
109 case XK_Down
: rc
= KEY_DOWNARROW
; break;
110 case XK_Up
: rc
= KEY_UPARROW
; break;
111 case XK_Escape
: rc
= KEY_ESCAPE
; break;
112 case XK_Return
: rc
= KEY_ENTER
; break;
113 case XK_Tab
: rc
= KEY_TAB
; break;
114 case XK_F1
: rc
= KEY_F1
; break;
115 case XK_F2
: rc
= KEY_F2
; break;
116 case XK_F3
: rc
= KEY_F3
; break;
117 case XK_F4
: rc
= KEY_F4
; break;
118 case XK_F5
: rc
= KEY_F5
; break;
119 case XK_F6
: rc
= KEY_F6
; break;
120 case XK_F7
: rc
= KEY_F7
; break;
121 case XK_F8
: rc
= KEY_F8
; break;
122 case XK_F9
: rc
= KEY_F9
; break;
123 case XK_F10
: rc
= KEY_F10
; break;
124 case XK_F11
: rc
= KEY_F11
; break;
125 case XK_F12
: rc
= KEY_F12
; break;
128 case XK_Delete
: rc
= KEY_BACKSPACE
; break;
130 case XK_Pause
: rc
= KEY_PAUSE
; break;
133 case XK_equal
: rc
= KEY_EQUALS
; break;
136 case XK_minus
: rc
= KEY_MINUS
; break;
156 if (rc
>= XK_space
&& rc
<= XK_asciitilde
)
157 rc
= rc
- XK_space
+ ' ';
158 if (rc
>= 'A' && rc
<= 'Z')
167 void I_ShutdownGraphics(void)
169 // Detach from X server
170 if (!XShmDetach(X_display
, &X_shminfo
))
171 I_Error("XShmDetach() failed in I_ShutdownGraphics()");
173 // Release shared memory.
174 shmdt(X_shminfo
.shmaddr
);
175 shmctl(X_shminfo
.shmid
, IPC_RMID
, 0);
186 void I_StartFrame (void)
192 static int lastmousex
= 0;
193 static int lastmousey
= 0;
194 boolean mousemoved
= false;
197 void I_GetEvent(void)
202 // put event-grabbing stuff in here
203 XNextEvent(X_display
, &X_event
);
204 switch (X_event
.type
)
207 event
.type
= ev_keydown
;
208 event
.data1
= xlatekey();
210 // fprintf(stderr, "k");
213 event
.type
= ev_keyup
;
214 event
.data1
= xlatekey();
216 // fprintf(stderr, "ku");
219 event
.type
= ev_mouse
;
221 (X_event
.xbutton
.state
& Button1Mask
)
222 | (X_event
.xbutton
.state
& Button2Mask
? 2 : 0)
223 | (X_event
.xbutton
.state
& Button3Mask
? 4 : 0)
224 | (X_event
.xbutton
.button
== Button1
)
225 | (X_event
.xbutton
.button
== Button2
? 2 : 0)
226 | (X_event
.xbutton
.button
== Button3
? 4 : 0);
227 event
.data2
= event
.data3
= 0;
229 // fprintf(stderr, "b");
232 event
.type
= ev_mouse
;
234 (X_event
.xbutton
.state
& Button1Mask
)
235 | (X_event
.xbutton
.state
& Button2Mask
? 2 : 0)
236 | (X_event
.xbutton
.state
& Button3Mask
? 4 : 0);
237 // suggest parentheses around arithmetic in operand of |
240 ^ (X_event
.xbutton
.button
== Button1
? 1 : 0)
241 ^ (X_event
.xbutton
.button
== Button2
? 2 : 0)
242 ^ (X_event
.xbutton
.button
== Button3
? 4 : 0);
243 event
.data2
= event
.data3
= 0;
245 // fprintf(stderr, "bu");
248 event
.type
= ev_mouse
;
250 (X_event
.xmotion
.state
& Button1Mask
)
251 | (X_event
.xmotion
.state
& Button2Mask
? 2 : 0)
252 | (X_event
.xmotion
.state
& Button3Mask
? 4 : 0);
253 event
.data2
= (X_event
.xmotion
.x
- lastmousex
) << 2;
254 event
.data3
= (lastmousey
- X_event
.xmotion
.y
) << 2;
256 if (event
.data2
|| event
.data3
)
258 lastmousex
= X_event
.xmotion
.x
;
259 lastmousey
= X_event
.xmotion
.y
;
260 if (X_event
.xmotion
.x
!= X_width
/2 &&
261 X_event
.xmotion
.y
!= X_height
/2)
264 // fprintf(stderr, "m");
274 case ConfigureNotify
:
278 if (doShm
&& X_event
.type
== X_shmeventtype
) shmFinished
= true;
295 cursormask
= XCreatePixmap(display
, root
, 1, 1, 1/*depth*/);
296 xgc
.function
= GXclear
;
297 gc
= XCreateGC(display
, cursormask
, GCFunction
, &xgc
);
298 XFillRectangle(display
, cursormask
, gc
, 0, 0, 1, 1);
299 dummycolour
.pixel
= 0;
301 dummycolour
.flags
= 04;
302 cursor
= XCreatePixmapCursor(display
, cursormask
, cursormask
,
303 &dummycolour
,&dummycolour
, 0,0);
304 XFreePixmap(display
,cursormask
);
312 void I_StartTic (void)
318 while (XPending(X_display
))
321 // Warp the pointer back to the middle of the window
322 // or it will wander off - that is, the game will
323 // loose input focus within X11.
326 if (!--doPointerWarp
)
328 XWarpPointer( X_display
,
333 X_width
/2, X_height
/2);
335 doPointerWarp
= POINTER_WARP_COUNTDOWN
;
347 void I_UpdateNoBlit (void)
355 void I_FinishUpdate (void)
361 // UNUSED static unsigned char *bigscreen=0;
363 // draws little dots on the bottom of the screen
370 if (tics
> 20) tics
= 20;
372 for (i
=0 ; i
<tics
*2 ; i
+=2)
373 screens
[0][ (SCREENHEIGHT
-1)*SCREENWIDTH
+ i
] = 0xff;
374 for ( ; i
<20*2 ; i
+=2)
375 screens
[0][ (SCREENHEIGHT
-1)*SCREENWIDTH
+ i
] = 0x0;
379 // scales the screen size before blitting it
382 unsigned int *olineptrs
[2];
383 unsigned int *ilineptr
;
385 unsigned int twoopixels
;
386 unsigned int twomoreopixels
;
387 unsigned int fouripixels
;
389 ilineptr
= (unsigned int *) (screens
[0]);
390 for (i
=0 ; i
<2 ; i
++)
391 olineptrs
[i
] = (unsigned int *) &image
->data
[i
*X_width
];
399 fouripixels
= *ilineptr
++;
400 twoopixels
= (fouripixels
& 0xff000000)
401 | ((fouripixels
>>8) & 0xffff00)
402 | ((fouripixels
>>16) & 0xff);
403 twomoreopixels
= ((fouripixels
<<16) & 0xff000000)
404 | ((fouripixels
<<8) & 0xffff00)
405 | (fouripixels
& 0xff);
406 #ifdef __BIG_ENDIAN__
407 *olineptrs
[0]++ = twoopixels
;
408 *olineptrs
[1]++ = twoopixels
;
409 *olineptrs
[0]++ = twomoreopixels
;
410 *olineptrs
[1]++ = twomoreopixels
;
412 *olineptrs
[0]++ = twomoreopixels
;
413 *olineptrs
[1]++ = twomoreopixels
;
414 *olineptrs
[0]++ = twoopixels
;
415 *olineptrs
[1]++ = twoopixels
;
418 olineptrs
[0] += X_width
/4;
419 olineptrs
[1] += X_width
/4;
423 else if (multiply
== 3)
425 unsigned int *olineptrs
[3];
426 unsigned int *ilineptr
;
428 unsigned int fouropixels
[3];
429 unsigned int fouripixels
;
431 ilineptr
= (unsigned int *) (screens
[0]);
432 for (i
=0 ; i
<3 ; i
++)
433 olineptrs
[i
] = (unsigned int *) &image
->data
[i
*X_width
];
441 fouripixels
= *ilineptr
++;
442 fouropixels
[0] = (fouripixels
& 0xff000000)
443 | ((fouripixels
>>8) & 0xff0000)
444 | ((fouripixels
>>16) & 0xffff);
445 fouropixels
[1] = ((fouripixels
<<8) & 0xff000000)
446 | (fouripixels
& 0xffff00)
447 | ((fouripixels
>>8) & 0xff);
448 fouropixels
[2] = ((fouripixels
<<16) & 0xffff0000)
449 | ((fouripixels
<<8) & 0xff00)
450 | (fouripixels
& 0xff);
451 #ifdef __BIG_ENDIAN__
452 *olineptrs
[0]++ = fouropixels
[0];
453 *olineptrs
[1]++ = fouropixels
[0];
454 *olineptrs
[2]++ = fouropixels
[0];
455 *olineptrs
[0]++ = fouropixels
[1];
456 *olineptrs
[1]++ = fouropixels
[1];
457 *olineptrs
[2]++ = fouropixels
[1];
458 *olineptrs
[0]++ = fouropixels
[2];
459 *olineptrs
[1]++ = fouropixels
[2];
460 *olineptrs
[2]++ = fouropixels
[2];
462 *olineptrs
[0]++ = fouropixels
[2];
463 *olineptrs
[1]++ = fouropixels
[2];
464 *olineptrs
[2]++ = fouropixels
[2];
465 *olineptrs
[0]++ = fouropixels
[1];
466 *olineptrs
[1]++ = fouropixels
[1];
467 *olineptrs
[2]++ = fouropixels
[1];
468 *olineptrs
[0]++ = fouropixels
[0];
469 *olineptrs
[1]++ = fouropixels
[0];
470 *olineptrs
[2]++ = fouropixels
[0];
473 olineptrs
[0] += 2*X_width
/4;
474 olineptrs
[1] += 2*X_width
/4;
475 olineptrs
[2] += 2*X_width
/4;
479 else if (multiply
== 4)
481 // Broken. Gotta fix this some day.
482 void Expand4(unsigned *, double *);
483 Expand4 ((unsigned *)(screens
[0]), (double *) (image
->data
));
489 if (!XShmPutImage( X_display
,
497 I_Error("XShmPutImage() failed\n");
499 // wait for it to finish and processes all input events
504 } while (!shmFinished
);
511 XPutImage( X_display
,
519 // sync up with server
520 XSync(X_display
, False
);
530 void I_ReadScreen (byte
* scr
)
532 memcpy (scr
, screens
[0], SCREENWIDTH
*SCREENHEIGHT
);
539 static XColor colors
[256];
541 void UploadNewPalette(Colormap cmap
, byte
*palette
)
546 static boolean firstcall
= true;
549 if (X_visualinfo
.c_class
== PseudoColor
&& X_visualinfo
.depth
== 8)
551 if (X_visualinfo
.class == PseudoColor
&& X_visualinfo
.depth
== 8)
554 // initialize the colormap
558 for (i
=0 ; i
<256 ; i
++)
561 colors
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
565 // set the X colormap entries
566 for (i
=0 ; i
<256 ; i
++)
568 c
= gammatable
[usegamma
][*palette
++];
569 colors
[i
].red
= (c
<<8) + c
;
570 c
= gammatable
[usegamma
][*palette
++];
571 colors
[i
].green
= (c
<<8) + c
;
572 c
= gammatable
[usegamma
][*palette
++];
573 colors
[i
].blue
= (c
<<8) + c
;
576 // store the colors to the current colormap
577 XStoreColors(X_display
, cmap
, colors
, 256);
585 void I_SetPalette (byte
* palette
)
587 UploadNewPalette(X_cmap
, palette
);
592 // This function is probably redundant,
593 // if XShmDetach works properly.
594 // ddt never detached the XShm memory,
595 // thus there might have been stale
596 // handles accumulating.
598 void grabsharedmemory(int size
)
601 int key
= ('d'<<24) | ('o'<<16) | ('o'<<8) | 'm';
602 struct shmid_ds shminfo
;
603 int minsize
= 320*200;
606 // UNUSED int done=0;
609 // try to use what was here before
612 id
= shmget((key_t
) key
, minsize
, 0777); // just get the id
615 rc
=shmctl(id
, IPC_STAT
, &shminfo
); // get stats on it
618 if (shminfo
.shm_nattch
)
620 fprintf(stderr
, "User %d appears to be running "
621 "DOOM. Is that wise?\n", shminfo
.shm_cpid
);
626 if (getuid() == shminfo
.shm_perm
.cuid
)
628 rc
= shmctl(id
, IPC_RMID
, 0);
631 "Was able to kill my old shared memory\n");
633 I_Error("Was NOT able to kill my old shared memory");
635 id
= shmget((key_t
)key
, size
, IPC_CREAT
|0777);
637 I_Error("Could not get shared memory");
639 rc
=shmctl(id
, IPC_STAT
, &shminfo
);
644 if (size
>= shminfo
.shm_segsz
)
647 "will use %d's stale shared memory\n",
654 "warning: can't use stale "
655 "shared memory belonging to id %d, "
657 shminfo
.shm_cpid
, key
);
664 I_Error("could not get stats on key=%d", key
);
669 id
= shmget((key_t
)key
, size
, IPC_CREAT
|0777);
673 fprintf(stderr
, "errno=%d\n", errno
);
674 I_Error("Could not get any shared memory");
678 } while (--pollution
);
682 I_Error("Sorry, system too polluted with stale "
683 "shared memory segments.\n");
686 X_shminfo
.shmid
= id
;
688 // attach to the shared memory segment
689 image
->data
= X_shminfo
.shmaddr
= shmat(id
, 0, 0);
691 fprintf(stderr
, "shared memory id=%d, addr=0x%x\n", id
,
692 (int) (image
->data
));
695 void I_InitGraphics(void)
705 // warning: char format, different type arg
710 unsigned long attribmask
;
711 XSetWindowAttributes attribs
;
714 static int firsttime
=1;
720 signal(SIGINT
, (void (*)(int)) I_Quit
);
722 if (M_CheckParm("-2"))
725 if (M_CheckParm("-3"))
728 if (M_CheckParm("-4"))
731 X_width
= SCREENWIDTH
* multiply
;
732 X_height
= SCREENHEIGHT
* multiply
;
734 // check for command-line display name
735 if ( (pnum
=M_CheckParm("-disp")) ) // suggest parentheses around assignment
736 displayname
= myargv
[pnum
+1];
740 // check if the user wants to grab the mouse (quite unnice)
741 grabMouse
= !!M_CheckParm("-grabmouse");
743 // check for command-line geometry
744 if ( (pnum
=M_CheckParm("-geom")) ) // suggest parentheses around assignment
746 // warning: char format, different type arg 3,5
747 n
= sscanf(myargv
[pnum
+1], "%c%d%c%d", &xsign
, &x
, &ysign
, &y
);
759 I_Error("bad -geom parameter");
763 X_display
= XOpenDisplay(displayname
);
767 I_Error("Could not open display [%s]", displayname
);
769 I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
772 // use the default visual
773 X_screen
= DefaultScreen(X_display
);
774 if (!XMatchVisualInfo(X_display
, X_screen
, 8, PseudoColor
, &X_visualinfo
))
775 I_Error("xdoom currently only supports 256-color PseudoColor screens");
776 X_visual
= X_visualinfo
.visual
;
778 // check for the MITSHM extension
779 doShm
= XShmQueryExtension(X_display
);
781 // even if it's available, make sure it's a local connection
784 if (!displayname
) displayname
= (char *) getenv("DISPLAY");
788 while (*d
&& (*d
!= ':')) d
++;
790 if (!(!strcasecmp(displayname
, "unix") || !*displayname
)) doShm
= false;
794 fprintf(stderr
, "Using MITSHM extension\n");
796 // create the colormap
797 X_cmap
= XCreateColormap(X_display
, RootWindow(X_display
,
798 X_screen
), X_visual
, AllocAll
);
800 // setup attributes for main window
801 attribmask
= CWEventMask
| CWColormap
| CWBorderPixel
;
805 // | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
808 attribs
.colormap
= X_cmap
;
809 attribs
.border_pixel
= 0;
811 // create the main window
812 X_mainWindow
= XCreateWindow( X_display
,
813 RootWindow(X_display
, X_screen
),
823 XDefineCursor(X_display
, X_mainWindow
,
824 createnullcursor( X_display
, X_mainWindow
) );
827 valuemask
= GCGraphicsExposures
;
828 xgcvalues
.graphics_exposures
= False
;
829 X_gc
= XCreateGC( X_display
,
835 XMapWindow(X_display
, X_mainWindow
);
837 // wait until it is OK to draw
841 XNextEvent(X_display
, &X_event
);
842 if (X_event
.type
== Expose
843 && !X_event
.xexpose
.count
)
849 // grabs the pointer so it is restricted to this window
851 XGrabPointer(X_display
, X_mainWindow
, True
,
852 ButtonPressMask
|ButtonReleaseMask
|PointerMotionMask
,
853 GrabModeAsync
, GrabModeAsync
,
854 X_mainWindow
, None
, CurrentTime
);
859 X_shmeventtype
= XShmGetEventBase(X_display
) + ShmCompletion
;
862 image
= XShmCreateImage( X_display
,
871 grabsharedmemory(image
->bytes_per_line
* image
->height
);
875 // create the shared memory segment
876 // X_shminfo.shmid = shmget (IPC_PRIVATE,
877 // image->bytes_per_line * image->height, IPC_CREAT | 0777);
878 // if (X_shminfo.shmid < 0)
881 // I_Error("shmget() failed in InitGraphics()");
883 // fprintf(stderr, "shared memory id=%d\n", X_shminfo.shmid);
884 // attach to the shared memory segment
885 // image->data = X_shminfo.shmaddr = shmat(X_shminfo.shmid, 0, 0);
891 I_Error("shmat() failed in InitGraphics()");
894 // get the X server to attach to it
895 if (!XShmAttach(X_display
, &X_shminfo
))
896 I_Error("XShmAttach() failed in InitGraphics()");
901 image
= XCreateImage( X_display
,
906 (char*)malloc(X_width
* X_height
),
914 screens
[0] = (unsigned char *) (image
->data
);
916 screens
[0] = (unsigned char *) malloc (SCREENWIDTH
* SCREENHEIGHT
);
921 unsigned exptable
[256];
923 void InitExpand (void)
927 for (i
=0 ; i
<256 ; i
++)
928 exptable
[i
] = i
| (i
<<8) | (i
<<16) | (i
<<24);
931 double exptable2
[256*256];
933 void InitExpand2 (void)
937 // UNUSED unsigned iexp, jexp;
945 printf ("building exptable2...\n");
947 for (i
=0 ; i
<256 ; i
++)
949 pixel
.u
[0] = i
| (i
<<8) | (i
<<16) | (i
<<24);
950 for (j
=0 ; j
<256 ; j
++)
952 pixel
.u
[1] = j
| (j
<<8) | (j
<<16) | (j
<<24);
981 step
= 3*SCREENWIDTH
/2;
990 fourpixels
= lineptr
[0];
992 dpixel
= *(double *)( (int)exp
+ ( (fourpixels
&0xffff0000)>>13) );
998 dpixel
= *(double *)( (int)exp
+ ( (fourpixels
&0xffff)<<3 ) );
1000 xline
[161] = dpixel
;
1001 xline
[321] = dpixel
;
1002 xline
[481] = dpixel
;
1004 fourpixels
= lineptr
[1];
1006 dpixel
= *(double *)( (int)exp
+ ( (fourpixels
&0xffff0000)>>13) );
1008 xline
[162] = dpixel
;
1009 xline
[322] = dpixel
;
1010 xline
[482] = dpixel
;
1012 dpixel
= *(double *)( (int)exp
+ ( (fourpixels
&0xffff)<<3 ) );
1014 xline
[163] = dpixel
;
1015 xline
[323] = dpixel
;
1016 xline
[483] = dpixel
;
1018 fourpixels
= lineptr
[2];
1020 dpixel
= *(double *)( (int)exp
+ ( (fourpixels
&0xffff0000)>>13) );
1022 xline
[164] = dpixel
;
1023 xline
[324] = dpixel
;
1024 xline
[484] = dpixel
;
1026 dpixel
= *(double *)( (int)exp
+ ( (fourpixels
&0xffff)<<3 ) );
1028 xline
[165] = dpixel
;
1029 xline
[325] = dpixel
;
1030 xline
[485] = dpixel
;
1032 fourpixels
= lineptr
[3];
1034 dpixel
= *(double *)( (int)exp
+ ( (fourpixels
&0xffff0000)>>13) );
1036 xline
[166] = dpixel
;
1037 xline
[326] = dpixel
;
1038 xline
[486] = dpixel
;
1040 dpixel
= *(double *)( (int)exp
+ ( (fourpixels
&0xffff)<<3 ) );
1042 xline
[167] = dpixel
;
1043 xline
[327] = dpixel
;
1044 xline
[487] = dpixel
;