summaryrefslogtreecommitdiff
path: root/src/i_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/i_video.c')
-rw-r--r--src/i_video.c1053
1 files changed, 1053 insertions, 0 deletions
diff --git a/src/i_video.c b/src/i_video.c
new file mode 100644
index 00000000..867276ab
--- /dev/null
+++ b/src/i_video.c
@@ -0,0 +1,1053 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// $Id: i_video.c 4 2005-07-23 16:19:41Z fraggle $
+//
+// 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$
+// Revision 1.1 2005/07/23 16:19:58 fraggle
+// Initial revision
+//
+//
+// DESCRIPTION:
+// DOOM graphics stuff for X11, UNIX.
+//
+//-----------------------------------------------------------------------------
+
+static const char
+rcsid[] = "$Id: i_video.c 4 2005-07-23 16:19:41Z fraggle $";
+
+#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 <signal.h>
+
+#include "doomstat.h"
+#include "i_system.h"
+#include "v_video.h"
+#include "m_argv.h"
+#include "d_main.h"
+
+#include "doomdef.h"
+
+#define POINTER_WARP_COUNTDOWN 1
+
+Display* X_display=0;
+Window X_mainWindow;
+Colormap X_cmap;
+Visual* X_visual;
+GC X_gc;
+XEvent X_event;
+int 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;
+
+// Blocky mode,
+// replace each 320x200 pixel with multiply*multiply pixels.
+// According to Dave Taylor, it still is a bonehead thing
+// to use ....
+static int multiply=1;
+
+
+//
+// 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;
+
+ 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(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;
+}
+
+
+
+//
+// I_StartFrame
+//
+void I_StartFrame (void)
+{
+ // er?
+
+}
+
+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:
+ 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:
+ 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:
+ 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_StartTic (void)
+{
+
+ if (!X_display)
+ return;
+
+ while (XPending(X_display))
+ I_GetEvent();
+
+ // 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;
+
+}
+
+
+//
+// I_UpdateNoBlit
+//
+void I_UpdateNoBlit (void)
+{
+ // what is this?
+}
+
+//
+// I_FinishUpdate
+//
+void I_FinishUpdate (void)
+{
+
+ static int lasttic;
+ int tics;
+ int i;
+ // UNUSED static unsigned char *bigscreen=0;
+
+ // draws little dots on the bottom of the screen
+ if (devparm)
+ {
+
+ i = I_GetTime();
+ tics = i - lasttic;
+ lasttic = i;
+ if (tics > 20) tics = 20;
+
+ for (i=0 ; i<tics*2 ; i+=2)
+ screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
+ for ( ; i<20*2 ; i+=2)
+ screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
+
+ }
+
+ // scales the screen size before blitting it
+ if (multiply == 2)
+ {
+ unsigned int *olineptrs[2];
+ unsigned int *ilineptr;
+ int x, y, i;
+ unsigned int twoopixels;
+ unsigned int twomoreopixels;
+ unsigned int fouripixels;
+
+ ilineptr = (unsigned int *) (screens[0]);
+ for (i=0 ; i<2 ; i++)
+ olineptrs[i] = (unsigned int *) &image->data[i*X_width];
+
+ y = SCREENHEIGHT;
+ while (y--)
+ {
+ x = SCREENWIDTH;
+ do
+ {
+ fouripixels = *ilineptr++;
+ twoopixels = (fouripixels & 0xff000000)
+ | ((fouripixels>>8) & 0xffff00)
+ | ((fouripixels>>16) & 0xff);
+ twomoreopixels = ((fouripixels<<16) & 0xff000000)
+ | ((fouripixels<<8) & 0xffff00)
+ | (fouripixels & 0xff);
+#ifdef __BIG_ENDIAN__
+ *olineptrs[0]++ = twoopixels;
+ *olineptrs[1]++ = twoopixels;
+ *olineptrs[0]++ = twomoreopixels;
+ *olineptrs[1]++ = twomoreopixels;
+#else
+ *olineptrs[0]++ = twomoreopixels;
+ *olineptrs[1]++ = twomoreopixels;
+ *olineptrs[0]++ = twoopixels;
+ *olineptrs[1]++ = twoopixels;
+#endif
+ } while (x-=4);
+ olineptrs[0] += X_width/4;
+ olineptrs[1] += X_width/4;
+ }
+
+ }
+ else if (multiply == 3)
+ {
+ unsigned int *olineptrs[3];
+ unsigned int *ilineptr;
+ int x, y, i;
+ unsigned int fouropixels[3];
+ unsigned int fouripixels;
+
+ ilineptr = (unsigned int *) (screens[0]);
+ for (i=0 ; i<3 ; i++)
+ olineptrs[i] = (unsigned int *) &image->data[i*X_width];
+
+ y = SCREENHEIGHT;
+ while (y--)
+ {
+ x = SCREENWIDTH;
+ do
+ {
+ fouripixels = *ilineptr++;
+ fouropixels[0] = (fouripixels & 0xff000000)
+ | ((fouripixels>>8) & 0xff0000)
+ | ((fouripixels>>16) & 0xffff);
+ fouropixels[1] = ((fouripixels<<8) & 0xff000000)
+ | (fouripixels & 0xffff00)
+ | ((fouripixels>>8) & 0xff);
+ fouropixels[2] = ((fouripixels<<16) & 0xffff0000)
+ | ((fouripixels<<8) & 0xff00)
+ | (fouripixels & 0xff);
+#ifdef __BIG_ENDIAN__
+ *olineptrs[0]++ = fouropixels[0];
+ *olineptrs[1]++ = fouropixels[0];
+ *olineptrs[2]++ = fouropixels[0];
+ *olineptrs[0]++ = fouropixels[1];
+ *olineptrs[1]++ = fouropixels[1];
+ *olineptrs[2]++ = fouropixels[1];
+ *olineptrs[0]++ = fouropixels[2];
+ *olineptrs[1]++ = fouropixels[2];
+ *olineptrs[2]++ = fouropixels[2];
+#else
+ *olineptrs[0]++ = fouropixels[2];
+ *olineptrs[1]++ = fouropixels[2];
+ *olineptrs[2]++ = fouropixels[2];
+ *olineptrs[0]++ = fouropixels[1];
+ *olineptrs[1]++ = fouropixels[1];
+ *olineptrs[2]++ = fouropixels[1];
+ *olineptrs[0]++ = fouropixels[0];
+ *olineptrs[1]++ = fouropixels[0];
+ *olineptrs[2]++ = fouropixels[0];
+#endif
+ } while (x-=4);
+ olineptrs[0] += 2*X_width/4;
+ olineptrs[1] += 2*X_width/4;
+ olineptrs[2] += 2*X_width/4;
+ }
+
+ }
+ else if (multiply == 4)
+ {
+ // Broken. Gotta fix this some day.
+ void Expand4(unsigned *, double *);
+ Expand4 ((unsigned *)(screens[0]), (double *) (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);
+
+ }
+
+}
+
+
+//
+// I_ReadScreen
+//
+void I_ReadScreen (byte* scr)
+{
+ memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
+}
+
+
+//
+// Palette stuff.
+//
+static XColor colors[256];
+
+void UploadNewPalette(Colormap cmap, byte *palette)
+{
+
+ register int i;
+ register int c;
+ static boolean firstcall = true;
+
+#ifdef __cplusplus
+ if (X_visualinfo.c_class == PseudoColor && X_visualinfo.depth == 8)
+#else
+ if (X_visualinfo.class == PseudoColor && X_visualinfo.depth == 8)
+#endif
+ {
+ // initialize the colormap
+ if (firstcall)
+ {
+ firstcall = false;
+ for (i=0 ; i<256 ; i++)
+ {
+ colors[i].pixel = i;
+ colors[i].flags = DoRed|DoGreen|DoBlue;
+ }
+ }
+
+ // set the X colormap entries
+ 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;
+ }
+
+ // store the colors to the current colormap
+ XStoreColors(X_display, cmap, colors, 256);
+
+ }
+}
+
+//
+// I_SetPalette
+//
+void I_SetPalette (byte* palette)
+{
+ UploadNewPalette(X_cmap, palette);
+}
+
+
+//
+// This function is probably redundant,
+// if XShmDetach works properly.
+// ddt never detached the XShm memory,
+// thus there might have been stale
+// handles accumulating.
+//
+void grabsharedmemory(int size)
+{
+
+ int key = ('d'<<24) | ('o'<<16) | ('o'<<8) | 'm';
+ struct shmid_ds shminfo;
+ int minsize = 320*200;
+ int id;
+ int rc;
+ // UNUSED int done=0;
+ int pollution=5;
+
+ // try to use what was here before
+ do
+ {
+ id = shmget((key_t) key, minsize, 0777); // just get the id
+ if (id != -1)
+ {
+ rc=shmctl(id, IPC_STAT, &shminfo); // get stats on it
+ if (!rc)
+ {
+ if (shminfo.shm_nattch)
+ {
+ fprintf(stderr, "User %d appears to be running "
+ "DOOM. Is that wise?\n", shminfo.shm_cpid);
+ key++;
+ }
+ else
+ {
+ if (getuid() == shminfo.shm_perm.cuid)
+ {
+ rc = shmctl(id, IPC_RMID, 0);
+ if (!rc)
+ fprintf(stderr,
+ "Was able to kill my old shared memory\n");
+ else
+ I_Error("Was NOT able to kill my old shared memory");
+
+ id = shmget((key_t)key, size, IPC_CREAT|0777);
+ if (id==-1)
+ I_Error("Could not get shared memory");
+
+ rc=shmctl(id, IPC_STAT, &shminfo);
+
+ break;
+
+ }
+ if (size >= shminfo.shm_segsz)
+ {
+ fprintf(stderr,
+ "will use %d's stale shared memory\n",
+ shminfo.shm_cpid);
+ break;
+ }
+ else
+ {
+ fprintf(stderr,
+ "warning: can't use stale "
+ "shared memory belonging to id %d, "
+ "key=0x%x\n",
+ shminfo.shm_cpid, key);
+ key++;
+ }
+ }
+ }
+ else
+ {
+ I_Error("could not get stats on key=%d", key);
+ }
+ }
+ else
+ {
+ id = shmget((key_t)key, size, IPC_CREAT|0777);
+ if (id==-1)
+ {
+ extern int errno;
+ fprintf(stderr, "errno=%d\n", errno);
+ I_Error("Could not get any shared memory");
+ }
+ break;
+ }
+ } while (--pollution);
+
+ if (!pollution)
+ {
+ I_Error("Sorry, system too polluted with stale "
+ "shared memory segments.\n");
+ }
+
+ X_shminfo.shmid = id;
+
+ // attach to the shared memory segment
+ image->data = X_shminfo.shmaddr = shmat(id, 0, 0);
+
+ fprintf(stderr, "shared memory id=%d, addr=0x%x\n", id,
+ (int) (image->data));
+}
+
+void I_InitGraphics(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;
+
+ signal(SIGINT, (void (*)(int)) I_Quit);
+
+ if (M_CheckParm("-2"))
+ multiply = 2;
+
+ if (M_CheckParm("-3"))
+ multiply = 3;
+
+ if (M_CheckParm("-4"))
+ multiply = 4;
+
+ X_width = SCREENWIDTH * multiply;
+ X_height = SCREENHEIGHT * multiply;
+
+ // 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 = DefaultScreen(X_display);
+ if (!XMatchVisualInfo(X_display, X_screen, 8, PseudoColor, &X_visualinfo))
+ I_Error("xdoom currently only supports 256-color PseudoColor screens");
+ 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;
+ }
+ }
+
+ fprintf(stderr, "Using MITSHM extension\n");
+
+ // create the colormap
+ X_cmap = XCreateColormap(X_display, RootWindow(X_display,
+ X_screen), X_visual, AllocAll);
+
+ // setup attributes for main window
+ attribmask = CWEventMask | CWColormap | CWBorderPixel;
+ attribs.event_mask =
+ KeyPressMask
+ | KeyReleaseMask
+ // | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
+ | ExposureMask;
+
+ attribs.colormap = X_cmap;
+ attribs.border_pixel = 0;
+
+ // create the main window
+ X_mainWindow = XCreateWindow( X_display,
+ RootWindow(X_display, X_screen),
+ x, y,
+ X_width, X_height,
+ 0, // borderwidth
+ 8, // 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)
+ {
+
+ X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
+
+ // create the image
+ image = XShmCreateImage( X_display,
+ X_visual,
+ 8,
+ ZPixmap,
+ 0,
+ &X_shminfo,
+ X_width,
+ X_height );
+
+ grabsharedmemory(image->bytes_per_line * image->height);
+
+
+ // UNUSED
+ // create the shared memory segment
+ // X_shminfo.shmid = shmget (IPC_PRIVATE,
+ // image->bytes_per_line * image->height, IPC_CREAT | 0777);
+ // if (X_shminfo.shmid < 0)
+ // {
+ // perror("");
+ // I_Error("shmget() failed in InitGraphics()");
+ // }
+ // fprintf(stderr, "shared memory id=%d\n", X_shminfo.shmid);
+ // attach to the shared memory segment
+ // image->data = X_shminfo.shmaddr = shmat(X_shminfo.shmid, 0, 0);
+
+
+ if (!image->data)
+ {
+ perror("");
+ I_Error("shmat() failed in InitGraphics()");
+ }
+
+ // get the X server to attach to it
+ if (!XShmAttach(X_display, &X_shminfo))
+ I_Error("XShmAttach() failed in InitGraphics()");
+
+ }
+ else
+ {
+ image = XCreateImage( X_display,
+ X_visual,
+ 8,
+ ZPixmap,
+ 0,
+ (char*)malloc(X_width * X_height),
+ X_width, X_height,
+ 8,
+ X_width );
+
+ }
+
+ if (multiply == 1)
+ screens[0] = (unsigned char *) (image->data);
+ else
+ screens[0] = (unsigned char *) malloc (SCREENWIDTH * SCREENHEIGHT);
+
+}
+
+
+unsigned exptable[256];
+
+void InitExpand (void)
+{
+ int i;
+
+ for (i=0 ; i<256 ; i++)
+ exptable[i] = i | (i<<8) | (i<<16) | (i<<24);
+}
+
+double exptable2[256*256];
+
+void InitExpand2 (void)
+{
+ int i;
+ int j;
+ // UNUSED unsigned iexp, jexp;
+ double* exp;
+ union
+ {
+ double d;
+ unsigned u[2];
+ } pixel;
+
+ printf ("building exptable2...\n");
+ exp = exptable2;
+ for (i=0 ; i<256 ; i++)
+ {
+ pixel.u[0] = i | (i<<8) | (i<<16) | (i<<24);
+ for (j=0 ; j<256 ; j++)
+ {
+ pixel.u[1] = j | (j<<8) | (j<<16) | (j<<24);
+ *exp++ = pixel.d;
+ }
+ }
+ printf ("done.\n");
+}
+
+int inited;
+
+void
+Expand4
+( unsigned* lineptr,
+ double* xline )
+{
+ double dpixel;
+ unsigned x;
+ unsigned y;
+ unsigned fourpixels;
+ unsigned step;
+ double* exp;
+
+ exp = exptable2;
+ if (!inited)
+ {
+ inited = 1;
+ InitExpand2 ();
+ }
+
+
+ step = 3*SCREENWIDTH/2;
+
+ y = SCREENHEIGHT-1;
+ do
+ {
+ x = SCREENWIDTH;
+
+ do
+ {
+ fourpixels = lineptr[0];
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
+ xline[0] = dpixel;
+ xline[160] = dpixel;
+ xline[320] = dpixel;
+ xline[480] = dpixel;
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
+ xline[1] = dpixel;
+ xline[161] = dpixel;
+ xline[321] = dpixel;
+ xline[481] = dpixel;
+
+ fourpixels = lineptr[1];
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
+ xline[2] = dpixel;
+ xline[162] = dpixel;
+ xline[322] = dpixel;
+ xline[482] = dpixel;
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
+ xline[3] = dpixel;
+ xline[163] = dpixel;
+ xline[323] = dpixel;
+ xline[483] = dpixel;
+
+ fourpixels = lineptr[2];
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
+ xline[4] = dpixel;
+ xline[164] = dpixel;
+ xline[324] = dpixel;
+ xline[484] = dpixel;
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
+ xline[5] = dpixel;
+ xline[165] = dpixel;
+ xline[325] = dpixel;
+ xline[485] = dpixel;
+
+ fourpixels = lineptr[3];
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
+ xline[6] = dpixel;
+ xline[166] = dpixel;
+ xline[326] = dpixel;
+ xline[486] = dpixel;
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
+ xline[7] = dpixel;
+ xline[167] = dpixel;
+ xline[327] = dpixel;
+ xline[487] = dpixel;
+
+ lineptr+=4;
+ xline+=8;
+ } while (x-=16);
+ xline += step;
+ } while (y--);
+}
+
+