home *** CD-ROM | disk | FTP | other *** search
- // Emacs style mode select -*- C++ -*-
- //-----------------------------------------------------------------------------
- //
- // $Id:$
- //
- // Copyright (C) 1993-1996 by id Software, Inc.
- //
- // This source is available for distribution and/or modification
- // only under the terms of the DOOM Source Code License as
- // published by id Software. All rights reserved.
- //
- // The source is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
- // for more details.
- //
- // $Log:$
- //
- // DESCRIPTION:
- // DOOM graphics stuff for X11, UNIX.
- //
- //-----------------------------------------------------------------------------
-
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
-
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/keysym.h>
-
- #include <X11/extensions/XShm.h>
- // Had to dig up XShm.c for this one.
- // It is in the libXext, but not in the XFree86 headers.
- #ifdef LINUX
- int XShmGetEventBase( Display* dpy ); // problems with g++?
- #endif
-
- #include <stdarg.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/socket.h>
-
- #include <netinet/in.h>
- #include <errnos.h>
-
- #include "doomstat.h"
- #include "i_system.h"
- #include "v_video.h"
- #include "i_video.h"
- #include "i_version.h"
-
- #include "m_argv.h"
- #include "d_main.h"
-
- #include "doomdef.h"
- #include "r_local.h"
- #include "am_map.h"
- #include "f_wipe.h"
- #include "f_finale.h"
-
- #include "z_zone.h"
- #include "i_zoom.h"
-
- #include "video/x11.h"
-
- #define POINTER_WARP_COUNTDOWN 1
-
- void CreateImageBuffer(void);
-
- Display* X_display=0;
- Window X_mainWindow;
- Colormap X_cmap;
- Visual* X_visual;
- GC X_gc;
- XEvent X_event;
- Screen *X_screen;
- XVisualInfo X_visualinfo;
-
- XImage* image;
- int X_width;
- int X_height;
- // MIT SHared Memory extension.
- boolean doShm;
-
- XShmSegmentInfo X_shminfo;
- int X_shmeventtype;
-
- // Fake mouse handling.
- // This cannot work properly w/o DGA.
- // Needs an invisible mouse cursor at least.
- boolean grabMouse;
- int doPointerWarp = POINTER_WARP_COUNTDOWN;
-
- //
- // Translates the key currently in X_event
- //
-
- int xlatekey(void)
- {
- int rc;
-
- switch(rc = XKeycodeToKeysym(X_display, X_event.xkey.keycode, 0))
- {
- case XK_Left: rc = KEY_LEFTARROW; break;
- case XK_Right: rc = KEY_RIGHTARROW;break;
- case XK_Down: rc = KEY_DOWNARROW; break;
- case XK_Up: rc = KEY_UPARROW; break;
- case XK_Escape: rc = KEY_ESCAPE; break;
- case XK_Return: rc = KEY_ENTER; break;
- case XK_Tab: rc = KEY_TAB; break;
- case XK_F1: rc = KEY_F1; break;
- case XK_F2: rc = KEY_F2; break;
- case XK_F3: rc = KEY_F3; break;
- case XK_F4: rc = KEY_F4; break;
- case XK_F5: rc = KEY_F5; break;
- case XK_F6: rc = KEY_F6; break;
- case XK_F7: rc = KEY_F7; break;
- case XK_F8: rc = KEY_F8; break;
- case XK_F9: rc = KEY_F9; break;
- case XK_F10: rc = KEY_F10; break;
- case XK_F11: rc = KEY_F11; break;
- case XK_F12: rc = KEY_F12; break;
-
- case XK_BackSpace:
- case XK_Delete: rc = KEY_BACKSPACE; break;
-
- case XK_Pause: rc = KEY_PAUSE; break;
-
- case XK_KP_Equal:
- case XK_equal: rc = KEY_EQUALS; break;
-
- case XK_KP_Subtract:
- case XK_minus: rc = KEY_MINUS; break;
-
- case XK_Shift_L:
- case XK_Shift_R:
- rc = KEY_RSHIFT;
- break;
-
- case XK_Control_L:
- case XK_Control_R:
- rc = KEY_RCTRL;
- break;
-
- case XK_Alt_L:
- case XK_Meta_L:
- case XK_Alt_R:
- case XK_Meta_R:
- rc = KEY_RALT;
- break;
-
- case XK_KP_End: rc='1'; break;
- case XK_KP_Down: rc='2'; break;
- case XK_KP_Page_Down: rc='3'; break;
- case XK_KP_Left: rc='4'; break;
- case XK_KP_Begin: rc='5'; break;
- case XK_KP_Right: rc='6'; break;
- case XK_KP_Home: rc='7'; break;
- case XK_KP_Up: rc='8'; break;
- case XK_KP_Page_Up: rc='9'; break;
-
- default:
- if (rc >= XK_space && rc <= XK_asciitilde)
- rc = rc - XK_space + ' ';
- if (rc >= 'A' && rc <= 'Z')
- rc = rc - 'A' + 'a';
- break;
- }
-
- return rc;
- }
-
- void I_ShutdownGraphics_x11(void)
- {
- // Detach from X server
- if (!XShmDetach(X_display, &X_shminfo))
- I_Error("XShmDetach() failed in I_ShutdownGraphics()");
-
- // Release shared memory.
- shmdt(X_shminfo.shmaddr);
- shmctl(X_shminfo.shmid, IPC_RMID, 0);
-
- // Paranoia.
- image->data = NULL;
- }
-
- static int lastmousex = 0;
- static int lastmousey = 0;
- boolean mousemoved = false;
- boolean shmFinished;
-
- void I_GetEvent(void)
- {
- event_t event;
-
- // put event-grabbing stuff in here
- XNextEvent(X_display, &X_event);
- switch (X_event.type)
- {
- case KeyPress:
- event.type = ev_keydown;
- event.data1 = xlatekey();
- D_PostEvent(&event);
- // fprintf(stderr, "k");
- break;
- case KeyRelease:
- event.type = ev_keyup;
- event.data1 = xlatekey();
- D_PostEvent(&event);
- // fprintf(stderr, "ku");
- break;
- case ButtonPress:
- event.type = ev_mouse;
- event.data1 =
- (X_event.xbutton.state & Button1Mask)
- | (X_event.xbutton.state & Button2Mask ? 2 : 0)
- | (X_event.xbutton.state & Button3Mask ? 4 : 0)
- | (X_event.xbutton.button == Button1)
- | (X_event.xbutton.button == Button2 ? 2 : 0)
- | (X_event.xbutton.button == Button3 ? 4 : 0);
- event.data2 = event.data3 = 0;
- D_PostEvent(&event);
- // fprintf(stderr, "b");
- break;
- case ButtonRelease:
- if ( I_UpdateMouse == I_UpdateMouse_x11 )
- {
- event.type = ev_mouse;
- event.data1 =
- (X_event.xbutton.state & Button1Mask)
- | (X_event.xbutton.state & Button2Mask ? 2 : 0)
- | (X_event.xbutton.state & Button3Mask ? 4 : 0);
- // suggest parentheses around arithmetic in operand of |
- event.data1 = event.data1
- ^ (X_event.xbutton.button == Button1 ? 1 : 0)
- ^ (X_event.xbutton.button == Button2 ? 2 : 0)
- ^ (X_event.xbutton.button == Button3 ? 4 : 0);
- event.data2 = event.data3 = 0;
- D_PostEvent(&event);
- // fprintf(stderr, "bu");
- }
- break;
- case MotionNotify:
- if ( I_UpdateMouse == I_UpdateMouse_x11)
- {
- event.type = ev_mouse;
- event.data1 =
- (X_event.xmotion.state & Button1Mask)
- | (X_event.xmotion.state & Button2Mask ? 2 : 0)
- | (X_event.xmotion.state & Button3Mask ? 4 : 0);
- event.data2 = (X_event.xmotion.x - lastmousex) << 2;
- event.data3 = (lastmousey - X_event.xmotion.y) << 2;
-
- if (event.data2 || event.data3)
- {
- lastmousex = X_event.xmotion.x;
- lastmousey = X_event.xmotion.y;
- if (X_event.xmotion.x != X_width/2 &&
- X_event.xmotion.y != X_height/2)
- {
- D_PostEvent(&event);
- // fprintf(stderr, "m");
- mousemoved = false;
- } else
- mousemoved = true;
- }
- }
- break;
- //case Expose:
- case ConfigureNotify:
- if (X_event.xany.window==X_mainWindow &&
- (X_width!=X_event.xconfigure.width ||
- X_height!=X_event.xconfigure.height))
- {
- /* Kill old shared memory and image */
- if (doShm)
- {
- XShmDetach (X_display, &X_shminfo);
- shmdt (X_shminfo.shmaddr);
- } else {
- XDestroyImage (image);
- image=NULL;
- }
-
- /* Create new shared memory and image */
- X_width=X_event.xconfigure.width;
- X_height=X_event.xconfigure.height;
-
- CreateImageBuffer();
- }
- break;
- default:
- if (doShm && X_event.type == X_shmeventtype)
- shmFinished = true;
- break;
- }
- }
-
- Cursor createnullcursor( Display* display,Window root )
- {
- Pixmap cursormask;
- XGCValues xgc;
- GC gc;
- XColor dummycolour;
- Cursor cursor;
-
- cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
- xgc.function = GXclear;
- gc = XCreateGC(display, cursormask, GCFunction, &xgc);
- XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
- dummycolour.pixel = 0;
- dummycolour.red = 0;
- dummycolour.flags = 04;
- cursor = XCreatePixmapCursor(display, cursormask, cursormask,
- &dummycolour,&dummycolour, 0,0);
- XFreePixmap(display,cursormask);
- XFreeGC(display,gc);
- return cursor;
- }
-
- //
- // I_StartTic
- //
- void I_UpdateKeyboard_x11 (void)
- {
- if (!X_display)
- return;
-
- while (XPending(X_display))
- I_GetEvent();
- }
-
- void I_UpdateMouse_x11 (void)
- {
- if (!X_display)
- return;
-
- // Warp the pointer back to the middle of the window
- // or it will wander off - that is, the game will
- // loose input focus within X11.
- if (grabMouse)
- {
- if (!--doPointerWarp)
- {
- XWarpPointer( X_display,
- None,
- X_mainWindow,
- 0, 0,
- 0, 0,
- X_width/2, X_height/2);
-
- doPointerWarp = POINTER_WARP_COUNTDOWN;
- }
- }
-
- mousemoved = false;
- }
-
- void I_VidUpdate_x11 (void)
- {
- I_Zoom(screens[0],image->data);
-
- if (doShm)
- {
- if (!XShmPutImage( X_display,
- X_mainWindow,
- X_gc,
- image,
- 0, 0,
- 0, 0,
- X_width, X_height,
- True ))
- I_Error("XShmPutImage() failed\n");
-
- // wait for it to finish and processes all input events
- shmFinished = false;
- do
- {
- I_GetEvent();
- } while (!shmFinished);
- }
- else
- {
- // draw the image
- XPutImage( X_display,
- X_mainWindow,
- X_gc,
- image,
- 0, 0,
- 0, 0,
- X_width, X_height );
-
- // sync up with server
- XSync(X_display, False);
- }
- }
-
- //
- // Palette stuff.
- //
- static XColor colors[256];
-
- //
- // I_SetPalette
- //
- void I_SetPalette256_x11(byte *palette)
- {
- int i,c;
- static boolean firstcall = true;
-
- if (firstcall)
- {
- firstcall = false;
- for (i=0 ; i<256 ; i++)
- {
- colors[i].pixel = i;
- colors[i].flags = DoRed|DoGreen|DoBlue;
- }
- }
-
- for(i = 0; i < 256; i++)
- {
- c = gammatable[usegamma][*palette++];
- colors[i].red = (c<<8) + c;
- c = gammatable[usegamma][*palette++];
- colors[i].green = (c<<8) + c;
- c = gammatable[usegamma][*palette++];
- colors[i].blue = (c<<8) + c;
- }
- XStoreColors(X_display,X_cmap,colors,256);
- }
-
- void I_InitGraphics_x11(void)
- {
- char* displayname;
- char* d;
- int n;
- int pnum;
- int x=0;
- int y=0;
-
- // warning: char format, different type arg
- char xsign=' ';
- char ysign=' ';
-
- int oktodraw;
- unsigned long attribmask;
- XSetWindowAttributes attribs;
- XGCValues xgcvalues;
- int valuemask;
- static int firsttime=1;
-
- if (!firsttime)
- return;
- firsttime = 0;
-
- X_width = SCREENWIDTH;
- X_height = SCREENHEIGHT;
-
- // check for command-line display name
- if ( (pnum=M_CheckParm("-disp")) ) // suggest parentheses around assignment
- displayname = myargv[pnum+1];
- else
- displayname = 0;
-
- // check if the user wants to grab the mouse (quite unnice)
- grabMouse = !!M_CheckParm("-grabmouse");
-
- // check for command-line geometry
- if ( (pnum=M_CheckParm("-geom")) ) // suggest parentheses around assignment
- {
- // warning: char format, different type arg 3,5
- n = sscanf(myargv[pnum+1], "%c%d%c%d", &xsign, &x, &ysign, &y);
-
- if (n==2)
- x = y = 0;
- else if (n==6)
- if (xsign == '-')
- x = -x;
- if (ysign == '-')
- y = -y;
- else
- I_Error("bad -geom parameter");
- }
-
- /* open the display */
- X_display = XOpenDisplay(displayname);
- if (!X_display)
- if (displayname)
- I_Error("Could not open display [%s]", displayname);
- else
- I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
-
- /* use the default visual */
- X_screen = DefaultScreenOfDisplay(X_display);
-
- /* Read screen depth */
- bpp = DefaultDepthOfScreen(X_screen);
- switch (bpp)
- {
- case 8:
- R_DrawColumn=R_DrawColumn8;
- R_DrawColumnLow=R_DrawColumnLow8;
- R_DrawFuzzColumn=R_DrawFuzzColumn8;
- R_DrawFuzzColumnLow=R_DrawFuzzColumnLow8;
- R_DrawTranslatedColumn=R_DrawTranslatedColumn8;
- R_DrawTranslatedColumnLow=R_DrawTranslatedColumnLow8;
- R_DrawSpan=R_DrawSpan8;
- R_DrawSpanLow=R_DrawSpanLow8;
- AM_DrawFline=AM_drawFline8;
- wipe_doMelt=wipe_doMelt8;
- V_DrawPatch=V_DrawPatch8;
- V_DrawPatchFlipped=V_DrawPatchFlipped8;
- F_DrawPatchCol=F_DrawPatchCol8;
- I_Zoom=I_Zoom8;
- pixel_size=1;
- break;
- case 15:
- R_DrawColumn=R_DrawColumn16;
- R_DrawColumnLow=R_DrawColumnLow16;
- R_DrawFuzzColumn=R_DrawFuzzColumn16;
- R_DrawFuzzColumnLow=R_DrawFuzzColumnLow16;
- R_DrawTranslatedColumn=R_DrawTranslatedColumn16;
- R_DrawTranslatedColumnLow=R_DrawTranslatedColumnLow16;
- R_DrawSpan=R_DrawSpan16;
- R_DrawSpanLow=R_DrawSpanLow16;
- AM_DrawFline=AM_drawFline16;
- wipe_doMelt=wipe_doMelt16;
- V_DrawPatch=V_DrawPatch16;
- V_DrawPatchFlipped=V_DrawPatchFlipped16;
- F_DrawPatchCol=F_DrawPatchCol16;
- I_Zoom=I_Zoom16;
- pixel_size=2;
- fuzzmask=0x3DEF3DEF;
- break;
- case 16:
- R_DrawColumn=R_DrawColumn16;
- R_DrawColumnLow=R_DrawColumnLow16;
- R_DrawFuzzColumn=R_DrawFuzzColumn16;
- R_DrawFuzzColumnLow=R_DrawFuzzColumnLow16;
- R_DrawTranslatedColumn=R_DrawTranslatedColumn16;
- R_DrawTranslatedColumnLow=R_DrawTranslatedColumnLow16;
- R_DrawSpan=R_DrawSpan16;
- R_DrawSpanLow=R_DrawSpanLow16;
- AM_DrawFline=AM_drawFline16;
- wipe_doMelt=wipe_doMelt16;
- V_DrawPatch=V_DrawPatch16;
- V_DrawPatchFlipped=V_DrawPatchFlipped16;
- F_DrawPatchCol=F_DrawPatchCol16;
- I_Zoom=I_Zoom16;
- pixel_size=2;
- fuzzmask=0x7BEF7BEF;
- break;
- case 24:
- R_DrawColumn=R_DrawColumn24;
- R_DrawColumnLow=R_DrawColumnLow24;
- R_DrawFuzzColumn=R_DrawFuzzColumn24;
- R_DrawFuzzColumnLow=R_DrawFuzzColumnLow24;
- R_DrawTranslatedColumn=R_DrawTranslatedColumn24;
- R_DrawTranslatedColumnLow=R_DrawTranslatedColumnLow24;
- R_DrawSpan=R_DrawSpan24;
- R_DrawSpanLow=R_DrawSpanLow24;
- AM_DrawFline=AM_drawFline24;
- wipe_doMelt=wipe_doMelt24;
- V_DrawPatch=V_DrawPatch24;
- V_DrawPatchFlipped=V_DrawPatchFlipped24;
- F_DrawPatchCol=F_DrawPatchCol24;
- I_Zoom=I_Zoom24;
- pixel_size=3;
- break;
- case 32:
- R_DrawColumn=R_DrawColumn32;
- R_DrawColumnLow=R_DrawColumnLow32;
- R_DrawFuzzColumn=R_DrawFuzzColumn32;
- R_DrawFuzzColumnLow=R_DrawFuzzColumnLow32;
- R_DrawTranslatedColumn=R_DrawTranslatedColumn32;
- R_DrawTranslatedColumnLow=R_DrawTranslatedColumnLow32;
- R_DrawSpan=R_DrawSpan32;
- R_DrawSpanLow=R_DrawSpanLow32;
- AM_DrawFline=AM_drawFline32;
- wipe_doMelt=wipe_doMelt32;
- V_DrawPatch=V_DrawPatch32;
- V_DrawPatchFlipped=V_DrawPatchFlipped32;
- F_DrawPatchCol=F_DrawPatchCol32;
- I_Zoom=I_Zoom32;
- pixel_size=4;
- fuzzmask=0x007F7F7F;
- break;
- default:
- I_Error("Unknown pixel size for screen\n");
- }
-
- if (bpp==8)
- if (!XMatchVisualInfo(X_display, DefaultScreen(X_display),
- bpp, PseudoColor, &X_visualinfo))
- I_Error("Could not get PseudoColor visual!\n");
- else
- if (!XMatchVisualInfo(X_display, DefaultScreen(X_display),
- bpp, TrueColor, &X_visualinfo))
- I_Error("Could not get TrueColor visual!\n");
-
- X_visual = X_visualinfo.visual;
-
- // check for the MITSHM extension
- doShm = XShmQueryExtension(X_display);
-
- // even if it's available, make sure it's a local connection
- if (doShm)
- {
- if (!displayname)
- displayname = (char *) getenv("DISPLAY");
- if (displayname)
- {
- d = displayname;
- while (*d && (*d != ':'))
- d++;
- if (*d)
- *d = 0;
- if (!(!strcasecmp(displayname, "unix") || !*displayname))
- doShm = false;
- }
- }
-
- // create the colormap
- if (bpp==8)
- X_cmap = XCreateColormap( X_display,
- RootWindowOfScreen(X_screen),
- X_visual,
- AllocAll);
- else
- X_cmap = DefaultColormapOfScreen(X_screen);
-
- // setup attributes for main window
- attribmask = CWEventMask | CWColormap | CWBorderPixel;
- attribs.event_mask = KeyPressMask | KeyReleaseMask
- | StructureNotifyMask | ExposureMask;
- // | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
-
- attribs.colormap = X_cmap;
- attribs.border_pixel = 0;
-
- // create the main window
- X_mainWindow = XCreateWindow( X_display,
- RootWindowOfScreen(X_screen),
- x, y,
- X_width, X_height,
- 0, // borderwidth
- bpp, // depth
- InputOutput,
- X_visual,
- attribmask,
- &attribs );
-
- XDefineCursor(X_display, X_mainWindow,
- createnullcursor( X_display, X_mainWindow ) );
-
- // create the GC
- valuemask = GCGraphicsExposures;
- xgcvalues.graphics_exposures = False;
- X_gc = XCreateGC( X_display,
- X_mainWindow,
- valuemask,
- &xgcvalues );
-
- // map the window
- XMapWindow(X_display, X_mainWindow);
-
- // wait until it is OK to draw
- oktodraw = 0;
- while (!oktodraw)
- {
- XNextEvent(X_display, &X_event);
- if ((X_event.type == Expose) && (!X_event.xexpose.count))
- oktodraw = 1;
- }
-
- // grabs the pointer so it is restricted to this window
- if (grabMouse)
- XGrabPointer(X_display, X_mainWindow, True,
- ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
- GrabModeAsync, GrabModeAsync,X_mainWindow, None, CurrentTime);
-
- if (doShm)
- {
- fprintf(stderr, "Using MITSHM extension\n");
- X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
- }
-
- CreateImageBuffer();
-
- XStoreName (X_display, X_mainWindow, version_name);
- XFlush (X_display);
- }
-
- void CreateImageBuffer(void)
- {
- /* Create new zoom tables */
- I_ZoomInit(X_width,X_height);
-
- if (doShm)
- {
- // create the image
- image = XShmCreateImage( X_display,
- X_visual,
- bpp,
- ZPixmap,
- 0,
- &X_shminfo,
- X_width,
- X_height );
-
- //grabsharedmemory(image->bytes_per_line * image->height);
-
- X_shminfo.shmid = shmget( (key_t) random() /*SHMKEY*/, image->bytes_per_line * image->height, IPC_CREAT|0777);
- if (X_shminfo.shmid==-1)
- I_Error("Could not get any shared memory\n");
-
- // attach to the shared memory segment
- X_shminfo.shmaddr = (void *) shmat(X_shminfo.shmid, 0, 0);
-
- image->data = X_shminfo.shmaddr;
-
- // get the X server to attach to it
- if (!XShmAttach(X_display, &X_shminfo))
- I_Error("XShmAttach() failed in InitGraphics()");
-
- shmctl (X_shminfo.shmid, IPC_RMID, 0);
- }
- else
- {
- image = XCreateImage( X_display,
- X_visual,
- bpp,
- ZPixmap,
- 0,
- (char*)malloc(X_width * X_height * pixel_size),
- X_width, X_height,
- bpp,
- X_width *pixel_size);
-
- }
- }
-