home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / vid_sunxil.c < prev    next >
C/C++ Source or Header  |  2000-06-17  |  32KB  |  1,289 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // vid_sunxil.c -- uses X to setup windows and XIL to copy images (scaled as needed) 
  21. //       to screen
  22.  
  23. #define _BSD
  24. #define BYTE_DEFINED 1
  25.  
  26. #include <sys/time.h>
  27. #include <sys/types.h>
  28. #include <errno.h>
  29. #include <thread.h>
  30. #include <unistd.h>
  31. #include <signal.h>
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <sys/ipc.h>
  36. #include <sys/shm.h>
  37. #include <X11/Xlib.h>
  38. #include <X11/Xutil.h>
  39. #include <X11/Xatom.h>
  40. #include <X11/keysym.h>
  41. #include <xil/xil.h>
  42.  
  43. #include "quakedef.h"
  44. #include "d_local.h"
  45.  
  46. #define MIN_WIDTH 320
  47. #define MIN_HEIGHT 200
  48.  
  49. cvar_t    _windowed_mouse = {"_windowed_mouse","0", true};
  50. cvar_t    m_filter = {"m_filter","0", true};
  51. float old_windowed_mouse;
  52.  
  53. // The following X property format is defined in Motif 1.1's
  54. // Xm/MwmUtils.h, but QUAKE should not depend on that header
  55. // file. Note: Motif 1.2 expanded this structure with
  56. // uninteresting fields (to QUAKE) so just stick with the
  57. // smaller Motif 1.1 structure.
  58.  
  59. #define MWM_HINTS_DECORATIONS   2
  60. typedef struct
  61. {
  62.   long flags;
  63.   long functions;
  64.   long decorations;
  65.   long input_mode;
  66. } MotifWmHints;
  67.  
  68. #define MAX_COLUMN_SIZE 11
  69.  
  70. #define MAX_MODEDESCS (MAX_COLUMN_SIZE*3)
  71.  
  72. typedef struct
  73. {
  74.     int   modenum;
  75.     int   iscur;
  76.     char  desc[256];
  77. } modedesc_t;
  78.  
  79. extern void M_Menu_Options_f (void);
  80. extern void M_Print (int cx, int cy, char *str);
  81. extern void M_PrintWhite (int cx, int cy, char *str);
  82. extern void M_DrawCharacter (int cx, int line, int num);
  83. extern void M_DrawTransPic (int x, int y, qpic_t *pic);
  84. extern void M_DrawPic (int x, int y, qpic_t *pic);
  85.  
  86. extern int sb_updates;
  87.  
  88. qboolean        mouse_avail;
  89. int             mouse_buttons=3;
  90. int             mouse_oldbuttonstate;
  91. int             mouse_buttonstate;
  92. float   mouse_x, mouse_y;
  93. float   old_mouse_x, old_mouse_y;
  94. int p_mouse_x;
  95. int p_mouse_y;
  96.  
  97. typedef struct
  98. {
  99.   int input;
  100.   int output;
  101. } keymap_t;
  102.  
  103. viddef_t vid; // global video state
  104. unsigned short       d_8to16table[256];
  105.  
  106. int   num_shades=32;
  107.  
  108. int d_con_indirect = 0;
  109.  
  110. int   vid_buffersize;
  111.  
  112. #define STD_EVENT_MASK \
  113. ( \
  114.   StructureNotifyMask | \
  115.   KeyPressMask | \
  116.   KeyReleaseMask | \
  117.   ButtonPressMask | \
  118.   ButtonReleaseMask | \
  119.   ExposureMask | \
  120.   PointerMotionMask | \
  121.   FocusChangeMask \
  122. )
  123.  
  124. int   VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
  125. byte  *VGA_pagebase;
  126.  
  127. qboolean      x_fullscreen = true;
  128. Display       *x_disp = NULL;
  129. int       x_screen, x_screen_width, x_screen_height;
  130. int       x_center_width, x_center_height;
  131. int       x_std_event_mask = STD_EVENT_MASK;
  132. Window        x_win, x_root_win;
  133. qboolean      x_focus = true;
  134. int       global_dx, global_dy;
  135.  
  136.  
  137. static Colormap     x_cmap;
  138. static GC     x_gc;
  139. static Visual     *x_vis;
  140. static XVisualInfo    *x_visinfo;
  141. static Atom     aHints = NULL;
  142. static Atom     aWMDelete = NULL;
  143.  
  144. static qboolean     oktodraw = false;
  145. static qboolean     X11_active = false;
  146.  
  147.  
  148. static int verbose=1;
  149.  
  150. static byte current_palette[768];
  151.  
  152. cvar_t pixel_multiply = {"pixel_multiply", "2", true};
  153. int current_pixel_multiply = 2;
  154.  
  155. #define PM(a) (int)((current_pixel_multiply)?((a)*current_pixel_multiply):(a))
  156. #define MP(a) (int)((current_pixel_multiply)?((a)/current_pixel_multiply):(a))
  157.  
  158. static int        render_pipeline[2];
  159. static XilSystemState       state;
  160. static XilImage       display_image  = NULL;
  161. static XilImage       quake_image  = NULL;
  162. static int        use_mt = 0;
  163. static int        count_frames = 0;
  164.  
  165. /*
  166. ================
  167. D_BeginDirectRect
  168. ================
  169. */
  170. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  171. {
  172. // direct drawing of the "accessing disk" icon isn't supported under Nextstep
  173. }
  174.  
  175.  
  176. /*
  177. ================
  178. D_EndDirectRect
  179. ================
  180. */
  181. void D_EndDirectRect (int x, int y, int width, int height)
  182. {
  183. // direct drawing of the "accessing disk" icon isnt supported under Nextstep
  184. }
  185.  
  186.  
  187. /*
  188. =================
  189. VID_Gamma_f
  190.  
  191. Keybinding command
  192. =================
  193. */
  194.  
  195. byte vid_gamma[256];
  196.  
  197. void VID_Gamma_f (void)
  198. {
  199.  
  200.   float g, f, inf;
  201.   int   i;
  202.  
  203.   if (Cmd_Argc () == 2) {
  204.     g = Q_atof (Cmd_Argv(1));
  205.  
  206.     for (i=0 ; i<255 ; i++) {
  207.       f = pow ((i+1)/256.0, g);
  208.       inf = f*255 + 0.5;
  209.       if (inf < 0)
  210.         inf = 0;
  211.       if (inf > 255)
  212.         inf = 255;
  213.       vid_gamma[i] = inf;
  214.     }
  215.  
  216.     VID_SetPalette (current_palette);
  217.  
  218.     vid.recalc_refdef = 1;        // force a surface cache flush
  219.   }
  220.  
  221. }
  222.  
  223. qboolean CheckPixelMultiply (void)
  224. {
  225.   int m;
  226.   int w, h;
  227.   XWindowAttributes wattr;   
  228.   XWindowChanges chg;
  229.   unsigned int value_mask;
  230.   int old_pixel;
  231.  
  232.   if ((m = (int)pixel_multiply.value) != current_pixel_multiply) {
  233.     if (m < 1)
  234.       m = 1;
  235.     if (m > 4)
  236.       m = 4;
  237.  
  238.     old_pixel = current_pixel_multiply;
  239.     current_pixel_multiply = m;
  240.     Cvar_SetValue("pixel_multiply", m);
  241.     
  242.     if(XGetWindowAttributes(x_disp, x_win, & wattr) == 0)
  243.       return true; // ???
  244.  
  245.     memset(&chg, 0, sizeof(chg));
  246.     chg.width = wattr.width/old_pixel * current_pixel_multiply;
  247.     chg.height = wattr.height/old_pixel * current_pixel_multiply;
  248.  
  249.     if (chg.width < MIN_WIDTH*current_pixel_multiply)
  250.       chg.width = MIN_WIDTH*current_pixel_multiply;
  251.     if (chg.height < MIN_HEIGHT*current_pixel_multiply)
  252.       chg.height = MIN_HEIGHT*current_pixel_multiply;
  253.  
  254.     XConfigureWindow(x_disp, x_win, CWWidth | CWHeight, &chg);
  255.  
  256.     vid.width = MP(wattr.width) & ~3;
  257.     vid.height = MP(wattr.height);
  258.  
  259.     if (vid.width < 320) 
  260.       vid.width = 320;
  261.     if (vid.height < 200)
  262.       vid.height = 200;
  263.     VID_ResetFramebuffer();
  264.  
  265.     return true;
  266.   }
  267.   return false;
  268. }
  269.  
  270. // ========================================================================
  271. // Tragic death handler
  272. // ========================================================================
  273.  
  274. void TragicDeath(int signal_num)
  275. {
  276.   //XAutoRepeatOn(x_disp);
  277.   XCloseDisplay(x_disp);
  278.   Sys_Error("This death brought to you by the number %d\n", signal_num);
  279. }
  280.  
  281. // ========================================================================
  282. // makes a null cursor
  283. // ========================================================================
  284.  
  285. static Cursor CreateNullCursor(Display *display, Window root)
  286. {
  287.   Pixmap cursormask; 
  288.   XGCValues xgc;
  289.   GC gc;
  290.   XColor dummycolour;
  291.   Cursor cursor;
  292.  
  293.   cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
  294.   xgc.function = GXclear;
  295.   gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
  296.   XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
  297.   dummycolour.pixel = 0;
  298.   dummycolour.red = 0;
  299.   dummycolour.flags = 04;
  300.   cursor = XCreatePixmapCursor(display, cursormask, cursormask,
  301.              &dummycolour,&dummycolour, 0,0);
  302.   XFreePixmap(display,cursormask);
  303.   XFreeGC(display,gc);
  304.   return cursor;
  305. }
  306.  
  307.  
  308. void VID_MenuDraw( void )
  309. {
  310.   qpic_t    *p;
  311.     char    *ptr;
  312.     int     i, j, column, row, dup;
  313.     char    temp[100];
  314.  
  315.     p = Draw_CachePic ("gfx/vidmodes.lmp");
  316.     M_DrawPic ( (320-p->width)/2, 4, p);
  317.   M_Print (4*8, 36 + MAX_COLUMN_SIZE * 8 + 8, "Video mode switching unavailable");
  318.   M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, "Press any key...");
  319. }
  320.  
  321. void VID_MenuKey( int key ) { M_Menu_Options_f (); }
  322.  
  323. // Called at startup to set up translation tables, takes 256 8 bit RGB values
  324. // the palette data will go away after the call, so it must be copied off if
  325. // the video driver will need it again
  326.  
  327. byte  surfcache[1024*1024];
  328.  
  329. //
  330. // VID_SetWindowTitle - set the window and icon titles
  331. //
  332.  
  333. void VID_SetWindowTitle( Window win, char *pszName )
  334. {
  335.   XTextProperty textprop;
  336.   XWMHints    *wmHints;
  337.  
  338.     // Setup ICCCM properties
  339.     textprop.value = (unsigned char *)pszName;
  340.     textprop.encoding = XA_STRING;
  341.     textprop.format = 8;
  342.     textprop.nitems = strlen(pszName);
  343.     wmHints = XAllocWMHints();
  344.     wmHints->initial_state = NormalState;
  345.     wmHints->flags = StateHint;
  346.     XSetWMProperties( x_disp, win, &textprop, &textprop,
  347.             // Only put WM_COMMAND property on first window.
  348.             com_argv, com_argc, NULL, NULL, NULL );
  349.     XFree( wmHints );
  350.  
  351.     aWMDelete = XInternAtom( x_disp, "WM_DELETE_WINDOW", False );
  352.     XSetWMProtocols( x_disp, win, &aWMDelete, 1 );
  353. }
  354.  
  355. //
  356. // VID_FullScreen - open the window in full screen mode
  357. //
  358.  
  359. qboolean VID_FullScreen( Window win )
  360. {
  361.   MotifWmHints    hints;
  362.   XWindowChanges  changes;
  363.  
  364.   aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 );
  365.   if (aHints == None) {
  366.     Con_Printf( "Could not intern X atom for _MOTIF_WM_HINTS." );
  367.     return( false );
  368.     }
  369.  
  370.   hints.flags = MWM_HINTS_DECORATIONS;
  371.   hints.decorations = 0; // Absolutely no decorations.
  372.   XChangeProperty( x_disp, win, aHints, aHints, 32, PropModeReplace, (unsigned char *)&hints, 4 );
  373.  
  374.   changes.x = 0;
  375.   changes.y = 0;
  376.   changes.width = x_screen_width;
  377.   changes.height = x_screen_height;
  378.   changes.stack_mode = TopIf;
  379.   XConfigureWindow( x_disp, win, CWX | CWY | CWWidth | CWHeight | CWStackMode, &changes);
  380.   return( true );
  381. }
  382.  
  383. void  VID_Init (unsigned char *palette)
  384. {
  385.  
  386.   int pnum, i;
  387.   XVisualInfo template;
  388.   int num_visuals;
  389.   int template_mask;
  390.   int w, h;
  391.  
  392.   int desired_width=320, desired_height=200;
  393.   
  394.   Cmd_AddCommand ("gamma", VID_Gamma_f);
  395.  
  396.   Cvar_RegisterVariable (&pixel_multiply);
  397.  
  398.   if (pipe(render_pipeline) < 0) 
  399.     Sys_Error("VID_Init: pipe");
  400.   
  401.   for (i=0 ; i<256 ; i++)
  402.     vid_gamma[i] = i;
  403.  
  404.   vid.width = 320;
  405.   vid.height = 200;
  406.   vid.aspect = 1.0;
  407.   vid.numpages = 2;
  408.   vid.colormap = host_colormap;
  409.   vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  410.   //vid.cbits = VID_CBITS;
  411.   //vid.grades = VID_GRADES;
  412.  
  413.   srandom(getpid());
  414.  
  415.   verbose = COM_CheckParm("-verbose");
  416.   count_frames = COM_CheckParm("-count_frames");
  417.  
  418. //
  419. // open the display
  420. //
  421.   x_disp = XOpenDisplay(0);
  422.  
  423.   if (!x_disp) {
  424.     if (getenv("DISPLAY"))
  425.       Sys_Error("VID: Could not open display [%s]\n",
  426.         getenv("DISPLAY"));
  427.     else
  428.       Sys_Error("VID: Could not open local display\n");
  429.   }
  430.  
  431.   x_screen = DefaultScreen( x_disp );
  432.   x_screen_width = WidthOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
  433.   x_screen_height = HeightOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
  434.  
  435.   x_center_width  = x_screen_width/2;
  436.  
  437.   x_center_height = x_screen_height/2;
  438.  
  439.   Con_Printf( "Using screen %d: %dx%d\n", x_screen, x_screen_width, x_screen_height );
  440.  
  441.   x_root_win = DefaultRootWindow( x_disp);
  442.  
  443.   //XAutoRepeatOff(x_disp);
  444.  
  445. // for debugging only
  446.   if (verbose)
  447.     XSynchronize(x_disp, True);
  448.  
  449. //
  450. // check for command-line window size
  451. //
  452.   if ((pnum=COM_CheckParm("-winsize"))) {
  453.     if (pnum >= com_argc-2)
  454.       Sys_Error("VID: -winsize <width> <height>\n");
  455.     desired_width = Q_atoi(com_argv[pnum+1]);
  456.     desired_height = Q_atoi(com_argv[pnum+2]);
  457.     if (desired_width < 1 || desired_height < 1)
  458.       Sys_Error("VID: Bad window width/height\n");    
  459.   }
  460.  
  461.   template_mask = VisualScreenMask; // make sure we get the right one 
  462.   template.screen = x_screen;
  463. //
  464. // specify a visual id
  465. //
  466.   if ((pnum=COM_CheckParm("-visualid"))) {
  467.     if (pnum >= com_argc-1)
  468.       Sys_Error("VID: -visualid <id#>\n");
  469.     template.visualid = Q_atoi(com_argv[pnum+1]);
  470.     template_mask |= VisualIDMask;
  471.   } else  {
  472.     // If not specified, find an 8 bit visual since others don't work
  473. //    template.depth = 8;
  474. //    template_mask |= VisualDepthMask;
  475.     int screen;
  476.     screen = XDefaultScreen(x_disp);
  477.     template.visualid =
  478.       XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
  479.     template_mask = VisualIDMask;
  480.   }
  481. //
  482. // pick a visual- warn if more than one was available
  483. //
  484.   x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
  485.   if (num_visuals > 1) {
  486.     printf("Found more than one visual id at depth %d:\n", template.depth);
  487.     for (i=0 ; i<num_visuals ; i++)
  488.       printf("  -visualid %d\n", (int)(x_visinfo[i].visualid));
  489.   }
  490.   else if (num_visuals == 0) {
  491.     if (template_mask == VisualIDMask)
  492.       Sys_Error("VID: Bad visual id %d\n", template.visualid);
  493.     else
  494.       Sys_Error("VID: No visuals at depth %d\n", template.depth);
  495.   }
  496.  
  497.   if (verbose) {
  498.     printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
  499.     printf("  screen %d\n", x_visinfo->screen);
  500.     printf("  red_mask 0x%x\n", (int)(x_visinfo->red_mask));
  501.     printf("  green_mask 0x%x\n", (int)(x_visinfo->green_mask));
  502.     printf("  blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
  503.     printf("  colormap_size %d\n", x_visinfo->colormap_size);
  504.     printf("  bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
  505.   }
  506.  
  507.   x_vis = x_visinfo->visual;
  508. //
  509. // See if we're going to do pixel multiply
  510. //
  511.   if (pixel_multiply.value < 1 || pixel_multiply.value > 4)
  512.     Cvar_SetValue("pixel_multiply", 2);
  513.   current_pixel_multiply = pixel_multiply.value;
  514.  
  515.   w = 320*current_pixel_multiply; // minimum width
  516.   h = 200*current_pixel_multiply; // minimum height
  517.   if (desired_width < w)
  518.     desired_width = w;
  519.   if (desired_height < h)
  520.     desired_height = h;
  521.  
  522.   vid.width = MP(desired_width);
  523.   vid.height = MP(desired_height);
  524.  
  525.   //
  526.   // patch things up so game doesn't fail if window is too small
  527.   //
  528.  
  529.   if (vid.width < 320) 
  530.     vid.width = 320;
  531.   if (vid.height < 200)
  532.     vid.height = 200;
  533.  
  534. //
  535. // see if we're going to use threads
  536. //
  537.   if(((sysconf(_SC_NPROCESSORS_ONLN) > 1) || COM_CheckParm("-mt")) &&  
  538.     (COM_CheckParm("-no_mt") == 0)) {
  539.     use_mt = 1;
  540.     printf("VID: Using multiple threads!\n");
  541.   }
  542.  
  543. // setup attributes for main window
  544.   {
  545.     int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
  546.     XSetWindowAttributes attribs;
  547.     Colormap tmpcmap;
  548.  
  549.     tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
  550.       x_visinfo->screen), x_vis, AllocNone);
  551.  
  552.     attribs.event_mask = x_std_event_mask;
  553.     attribs.border_pixel = 0;
  554.     attribs.colormap = tmpcmap;
  555.  
  556. // create the main window
  557.     x_win = XCreateWindow(  x_disp,
  558.       XRootWindow(x_disp, x_visinfo->screen),
  559.       0, 0, // x, y
  560.       desired_width, desired_height,
  561.       0, // borderwidth
  562.       x_visinfo->depth,
  563.       InputOutput,
  564.       x_vis,
  565.       attribmask,
  566.       &attribs );
  567.  
  568.     if (x_visinfo->class != TrueColor)
  569.       XFreeColormap(x_disp, tmpcmap);
  570.  
  571.   }
  572.  
  573.   if (x_visinfo->depth == 8) {
  574.  
  575.   // create and upload the palette
  576.     if (x_visinfo->class == PseudoColor) {
  577.       x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
  578.       VID_SetPalette(palette);
  579.       XSetWindowColormap(x_disp, x_win, x_cmap);
  580.     }
  581.  
  582.   }
  583.  
  584.   VID_SetWindowTitle( x_win, "Quake" );
  585.  
  586. // inviso cursor
  587.   XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
  588.  
  589. // create the GC
  590.   {
  591.     XGCValues xgcvalues;
  592.     int valuemask = GCGraphicsExposures;
  593.     xgcvalues.graphics_exposures = False;
  594.     x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
  595.   }
  596.  
  597. // map the window
  598.   XMapWindow(x_disp, x_win);
  599.   XSync(x_disp, True) ;        /* wait for map */
  600. //
  601. // wait for first exposure event
  602. //
  603.   {
  604.     XEvent event;
  605.     do{
  606.       XNextEvent(x_disp, &event);
  607.       if (event.type == Expose && !event.xexpose.count)
  608.         oktodraw = true;
  609.     } while (!oktodraw);
  610.   }
  611. //
  612. // initialize XIL
  613. //
  614.   
  615.   state = xil_open();
  616.   
  617.   if(state == NULL) {
  618.     //
  619.     //  XIL's default error handler will print an error msg on stderr
  620.     //
  621.     Sys_Error("xil_open failed\n");
  622.   }
  623.   
  624.   X11_active = true;
  625.  
  626.   VID_ResetFramebuffer();
  627.  
  628.   D_InitCaches (surfcache, sizeof(surfcache));
  629.   
  630.   vid_menudrawfn = VID_MenuDraw;
  631.   vid_menukeyfn = VID_MenuKey;
  632. }
  633.  
  634. VID_ResetFramebuffer()
  635. {
  636.   XilMemoryStorage storage;
  637.  
  638.   if (use_mt) {
  639.     VID_ResetFramebuffer_MT();
  640.     return;
  641.   }
  642.  
  643. //printf("VID_ResetFramebuffer: vid.width %d, vid.height %d\n", vid.width, vid.height);
  644.  
  645.   xil_destroy(display_image);
  646.  
  647.   xil_destroy(quake_image);
  648.  
  649.   display_image = xil_create_from_window(state, x_disp, x_win);
  650.   quake_image = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
  651.  
  652.   xil_export(quake_image);
  653.   
  654.   if (xil_get_memory_storage(quake_image, &storage) == FALSE)
  655.     Sys_Error("xil_get_memory_storage");
  656.   
  657.   xil_import(quake_image, TRUE);
  658.   xil_export(quake_image);
  659.  
  660.   if (xil_get_memory_storage(quake_image, &storage) == FALSE)
  661.     Sys_Error("xil_get_memory_storage");
  662.  
  663.   vid.rowbytes = storage.byte.scanline_stride;
  664.   vid.buffer =   storage.byte.data;
  665.   vid.conbuffer = vid.buffer;
  666.   vid.conrowbytes = vid.rowbytes;
  667.   vid.conwidth = vid.width;
  668.   vid.conheight = vid.height;
  669.   
  670.   vid.maxwarpwidth = WARP_WIDTH;
  671.   vid.maxwarpheight = WARP_HEIGHT;
  672.   vid.recalc_refdef = 1;        // force a surface cache flush
  673.  
  674.   free(d_pzbuffer);
  675.  
  676.   d_pzbuffer = malloc(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer));
  677.         //Hunk_HighAllocName(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer),"zbuff");
  678. }
  679.  
  680. VID_ResetFramebuffer_MT()
  681. {
  682.   XilMemoryStorage storage;
  683.   XilImage drain_renderpipeline();
  684.   XilImage old_display_image;
  685.  
  686.   void * update_thread();
  687.  
  688.   printf("VID_ResetFramebuffer: vid.width %d, vid.height %d\n", vid.width, vid.height);
  689.  
  690.   old_display_image = display_image;
  691.  
  692.   display_image = xil_create_from_window(state, x_disp, x_win);
  693.   
  694.   if (quake_image == NULL) 
  695.     if (thr_create(NULL, NULL, update_thread, NULL, THR_NEW_LWP, NULL) != 0)
  696.       Sys_Error("VID: thr_create"); 
  697.   
  698.   quake_image = drain_renderpipeline(quake_image);
  699.  
  700.   xil_destroy(old_display_image);
  701.  
  702.   free(d_pzbuffer);
  703.  
  704.   d_pzbuffer = malloc(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer));
  705. }
  706.  
  707. void VID_ShiftPalette(unsigned char *p)
  708. {
  709.   VID_SetPalette(p);
  710. }
  711.  
  712. void VID_SetPalette(unsigned char *palette)
  713. {
  714.  
  715.   int i;
  716.   XColor colors[256];
  717.  
  718.   if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) {
  719.       if (palette != current_palette)
  720.         memcpy(current_palette, palette, 768);
  721.       for (i=0 ; i<256 ; i++)
  722.         {
  723.           colors[i].pixel = i;
  724.           colors[i].flags = DoRed|DoGreen|DoBlue;
  725.           colors[i].red = vid_gamma[palette[i*3]] * 257;
  726.           colors[i].green = vid_gamma[palette[i*3+1]] * 257;
  727.           colors[i].blue = vid_gamma[palette[i*3+2]] * 257;
  728.         }
  729.       XStoreColors(x_disp, x_cmap, colors, 256);
  730.     }
  731.  
  732. }
  733.  
  734. // Called at shutdown
  735.  
  736. void  VID_Shutdown (void)
  737. {
  738.   X11_active = false;
  739.   Con_Printf("VID_Shutdown\n");
  740.   //XAutoRepeatOn(x_disp);
  741.   xil_destroy(display_image);
  742.   xil_destroy(quake_image);
  743.   display_image = NULL;
  744.   quake_image = NULL;
  745.   XCloseDisplay(x_disp);
  746. }
  747.  
  748. int XLateKey(XKeyEvent *ev)
  749. {
  750.  
  751.   int key;
  752.   char buf[64];
  753.   KeySym keysym;
  754.  
  755.   XLookupString(ev, buf, sizeof buf, &keysym, 0);
  756.  
  757.   switch(keysym) {
  758.     case XK_Page_Up:   key = K_PGUP; break;
  759.     case XK_Page_Down:   key = K_PGDN; break;
  760.     case XK_Home:  key = K_HOME; break;
  761.     case XK_End:   key = K_END; break;
  762.     case XK_Left:  key = K_LEFTARROW; break;
  763.     case XK_Right:  key = K_RIGHTARROW;   break;
  764.     case XK_Down:  key = K_DOWNARROW; break;
  765.     case XK_Up:    key = K_UPARROW;  break;
  766.     case XK_Escape: key = K_ESCAPE;   break;
  767.     case XK_Return: key = K_ENTER;     break;
  768.     case XK_Tab:    key = K_TAB;       break;
  769.     case XK_Help:
  770.     case XK_F1:    key = K_F1;        break;
  771.     case XK_F2:    key = K_F2;        break;
  772.     case XK_F3:    key = K_F3;        break;
  773.     case XK_F4:    key = K_F4;        break;
  774.     case XK_F5:    key = K_F5;        break;
  775.     case XK_F6:    key = K_F6;        break;
  776.     case XK_F7:    key = K_F7;        break;
  777.     case XK_F8:    key = K_F8;        break;
  778.     case XK_F9:    key = K_F9;        break;
  779.     case XK_F10:    key = K_F10;       break;
  780.     case XK_F11:    key = K_F11;       break;
  781.     case XK_F12:    key = K_F12;       break;
  782.     case XK_BackSpace:
  783.     case XK_Delete: key = K_BACKSPACE; break;
  784.     case XK_Pause:  key = K_PAUSE;     break;
  785.     case XK_Shift_L:
  786.     case XK_Shift_R:    key = K_SHIFT;    break;
  787.     case XK_Control_L: 
  788.     case XK_Control_R:  key = K_CTRL;    break;
  789.     case XK_Alt_L:  
  790.     case XK_Meta_L: 
  791.     case XK_Alt_R:  
  792.     case XK_Meta_R: key = K_ALT;      break;
  793.       // various other keys on the keyboard
  794.            case XK_F27: key = K_HOME; break;
  795.     case XK_F29: key = K_PGUP; break;
  796.     case XK_F33: key = K_END; break;
  797.     case XK_F35: key = K_PGDN; break;
  798.     case XK_Insert:
  799.     case XK_KP_Insert: key = K_INS; break;
  800.     case XK_F24: key = '-'; break;
  801.     case XK_KP_Add: key = '+'; break;
  802.     case XK_KP_Subtract: key = '-'; break;
  803.     case XK_F25: key = '/'; break;
  804.     case XK_F26: key = '*'; break;
  805.  
  806.     default:
  807.       key = (unsigned char)*buf;
  808.       break;
  809.     } 
  810.  
  811.   return key;
  812.  
  813. }
  814.  
  815. struct {
  816.   int key;
  817.   int down;
  818. } keyq[64];
  819.  
  820. int keyq_head=0;
  821. int keyq_tail=0;
  822.  
  823. int config_notify=0;
  824. int config_notify_width;
  825. int config_notify_height;
  826.  
  827. void GetEvent(void)
  828. {
  829.   XEvent x_event;
  830.   int b;
  831.  
  832.   XNextEvent(x_disp, &x_event);
  833.   switch(x_event.type) {
  834.     case KeyPress:
  835.       Key_Event(XLateKey(&x_event.xkey), true);
  836.       break;
  837.     case KeyRelease:
  838.       Key_Event(XLateKey(&x_event.xkey), false);
  839.       break;
  840.  
  841.     case MotionNotify:
  842.  
  843.       if (_windowed_mouse.value) {
  844.         mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2));
  845.         mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2));
  846.   //printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n", 
  847.   //  x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y);
  848.  
  849.         /* move the mouse to the window center again */
  850.         XSelectInput( x_disp, x_win, x_std_event_mask & ~PointerMotionMask );
  851.         XWarpPointer(x_disp,None,x_win,0,0,0,0, 
  852.           (vid.width/2),(vid.height/2));
  853.         XSelectInput( x_disp, x_win, x_std_event_mask );
  854.       } else {
  855.         mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
  856.         mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
  857.         p_mouse_x=x_event.xmotion.x;
  858.         p_mouse_y=x_event.xmotion.y;
  859.       }
  860.       break;
  861.  
  862.     case ButtonPress:
  863.       b=-1;
  864.       if (x_event.xbutton.button == 1)
  865.         b = 0;
  866.       else if (x_event.xbutton.button == 2)
  867.         b = 2;
  868.       else if (x_event.xbutton.button == 3)
  869.         b = 1;
  870.       if (b>=0)
  871.         mouse_buttonstate |= 1<<b;
  872.       break;
  873.  
  874.     case ButtonRelease:
  875.       b=-1;
  876.       if (x_event.xbutton.button == 1)
  877.         b = 0;
  878.       else if (x_event.xbutton.button == 2)
  879.         b = 2;
  880.       else if (x_event.xbutton.button == 3)
  881.         b = 1;
  882.       if (b>=0)
  883.         mouse_buttonstate &= ~(1<<b);
  884.       break;
  885.     
  886.     case ConfigureNotify:
  887.       //      printf("config notify\n");
  888.       config_notify_width = x_event.xconfigure.width;
  889.       config_notify_height = x_event.xconfigure.height;
  890.       config_notify = 1;
  891.       sb_updates = 0;
  892.       break;
  893.     case Expose:  
  894.       sb_updates = 0;
  895.       break;
  896.     case ClientMessage:
  897.       if (x_event.xclient.data.l[0] == aWMDelete) Host_Quit_f();
  898.       break;
  899. #if 0
  900.     case FocusIn:
  901.       printf("FocusIn...\n");
  902.       x_focus = true;
  903.       break;
  904.     case FocusOut:
  905.       printf("FocusOut...\n");
  906.       x_focus = false;
  907.       break;
  908. #endif
  909.   }
  910.  
  911.   if (old_windowed_mouse != _windowed_mouse.value) {
  912.     old_windowed_mouse = _windowed_mouse.value;
  913.  
  914.     if (!_windowed_mouse.value) {
  915.       /* ungrab the pointer */
  916.       XUngrabPointer(x_disp,CurrentTime);
  917.     } else {
  918.       /* grab the pointer */
  919.       XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
  920.         GrabModeAsync,x_win,None,CurrentTime);
  921.     }
  922.   }
  923. }
  924.  
  925. // flushes the given rectangles from the view buffer to the screen
  926.  
  927. void
  928. VID_Update (vrect_t *rects)
  929. {
  930.   void VID_Update_MT(vrect_t *);
  931.  
  932.  
  933.   if (count_frames) {
  934.     static int count;
  935.     static long long s;
  936.     long long gethrtime();
  937.  
  938.     if (count == 0)
  939.       s = gethrtime();
  940.  
  941.     if (count++ == 200) {
  942.       long long n = gethrtime();
  943.       count = 1;
  944.       printf("%lf frames/secs\n", 200.0/((double)(n-s) / 1e9));
  945.       s = n;
  946.     }
  947.   }
  948.  
  949.   if (use_mt) {
  950.     VID_Update_MT(rects);
  951.     return;
  952.   }
  953.  
  954.   // if the window changes dimension, skip this frame
  955.  
  956.   if (config_notify) {
  957.     int w, h;
  958.     XWindowChanges chg;
  959.     unsigned int value_mask;
  960.  
  961.     w = 320*current_pixel_multiply; // minimum width
  962.     h = 200*current_pixel_multiply; // minimum height
  963.       
  964.     if (config_notify_width < w || config_notify_height < h) {
  965.       // We must resize the window
  966.       memset(&chg, 0, sizeof(chg));
  967.       value_mask = 0;
  968.       if (config_notify_width < w) {
  969.         config_notify_width = chg.width = w;
  970.         value_mask |= CWWidth;
  971.       }
  972.       if (config_notify_height < h) {
  973.         config_notify_height = chg.height = h;
  974.         value_mask |= CWHeight;
  975.       }
  976.       if (value_mask)
  977.         XConfigureWindow(x_disp, x_win, value_mask, &chg);
  978.     }
  979.  
  980.     config_notify = 0;
  981.  
  982.     vid.width = MP(config_notify_width) & ~3;
  983.     vid.height = MP(config_notify_height);
  984.  
  985.     if (vid.width < 320) 
  986.       vid.width = 320;
  987.     if (vid.height < 200)
  988.       vid.height = 200;
  989.     
  990.     VID_ResetFramebuffer();
  991.  
  992.     return;
  993.   }
  994.   // if pixel multiply changed, skip this frame
  995.   if (CheckPixelMultiply())
  996.     return;
  997.  
  998.   while (rects) { // I've never seen more than one rect?
  999.     XilMemoryStorage storage;
  1000.  
  1001.     xil_import(quake_image, TRUE); // let xil control the image
  1002.  
  1003.     if (current_pixel_multiply < 2)
  1004.       xil_copy(quake_image, display_image);
  1005.     else
  1006.       xil_scale(quake_image, display_image, "nearest",
  1007.           (float)current_pixel_multiply, (float)current_pixel_multiply);
  1008.  
  1009.     xil_export(quake_image);  // back to quake
  1010.  
  1011.     if (xil_get_memory_storage(quake_image, &storage) == FALSE)
  1012.       Sys_Error("xil_get_memory_storage");
  1013.  
  1014.     vid.buffer =   storage.byte.data;
  1015.     vid.conbuffer = vid.buffer;
  1016.  
  1017.     rects = rects->pnext;
  1018.   }
  1019. }
  1020.  
  1021. void
  1022. VID_Update_MT (vrect_t *rects)
  1023. {
  1024.   XilImage sched_update();
  1025.  
  1026.   // if the window changes dimension, skip this frame
  1027.  
  1028.   if (config_notify) {
  1029.     int w, h;
  1030.     XWindowChanges chg;
  1031.     unsigned int value_mask;
  1032.  
  1033.     w = 320*current_pixel_multiply; // minimum width
  1034.     h = 200*current_pixel_multiply; // minimum height
  1035.       
  1036.     if (config_notify_width < w || config_notify_height < h) {
  1037.       // We must resize the window
  1038.       memset(&chg, 0, sizeof(chg));
  1039.       value_mask = 0;
  1040.       if (config_notify_width < w) {
  1041.         config_notify_width = chg.width = w;
  1042.         value_mask |= CWWidth;
  1043.       }
  1044.       if (config_notify_height < h) {
  1045.         config_notify_height = chg.height = h;
  1046.         value_mask |= CWHeight;
  1047.       }
  1048.       if (value_mask)
  1049.         XConfigureWindow(x_disp, x_win, value_mask, &chg);
  1050.     }
  1051.  
  1052.     config_notify = 0;
  1053.  
  1054.     vid.width = MP(config_notify_width) & ~3;
  1055.     vid.height = MP(config_notify_height);
  1056.  
  1057.     if (vid.width < 320) 
  1058.       vid.width = 320;
  1059.     if (vid.height < 200)
  1060.       vid.height = 200;
  1061.     
  1062.     VID_ResetFramebuffer_MT();
  1063.  
  1064.     return;
  1065.   }
  1066.   // if pixel multiply changed, skip this frame
  1067.   if (CheckPixelMultiply())
  1068.     return;
  1069.  
  1070.   quake_image = sched_update(quake_image);
  1071. }
  1072.  
  1073. XilImage
  1074. drain_renderpipeline(XilImage old)
  1075. {
  1076.   XilImage new;
  1077.  
  1078.   XilMemoryStorage storage;
  1079.   
  1080.   if (old) 
  1081.     if (read(render_pipeline[1], &new, sizeof(new)) != sizeof (new)) {
  1082.       Sys_Error("drain_renderpipeline: read");
  1083.       xil_destroy(new);
  1084.     }
  1085.  
  1086.   xil_destroy(old);
  1087.  
  1088.  
  1089.   new = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
  1090.   
  1091.   if (write(render_pipeline[0], &new, sizeof (new)) != sizeof(new)) 
  1092.     Sys_Error("drain_renderpipeline: write");
  1093.  
  1094.   new = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
  1095.  
  1096.   xil_export(new);
  1097.  
  1098.   if (xil_get_memory_storage(new, &storage) == FALSE)
  1099.     Sys_Error("xil_get_memory_storage");
  1100.  
  1101.   vid.rowbytes = storage.byte.scanline_stride;
  1102.   vid.buffer =   storage.byte.data;
  1103.   vid.conbuffer = vid.buffer;
  1104.   vid.conrowbytes = vid.rowbytes;
  1105.   vid.conwidth = vid.width;
  1106.   vid.conheight = vid.height;
  1107.   
  1108.   vid.maxwarpwidth = WARP_WIDTH;
  1109.   vid.maxwarpheight = WARP_HEIGHT;
  1110.   vid.recalc_refdef = 1;        // force a surface cache flush
  1111.  
  1112.   return(new);
  1113.  
  1114. }
  1115.  
  1116. XilImage
  1117. sched_update(XilImage image)
  1118. {
  1119.   XilImage new;
  1120.   XilMemoryStorage storage;
  1121.  
  1122.   if (write(render_pipeline[1], &image, sizeof(image)) != sizeof (image)) 
  1123.     Sys_Error("sched_update:write");
  1124.  
  1125.   if (read(render_pipeline[1], &new, sizeof(new)) != sizeof (new))
  1126.     Sys_Error("sched_update:read");
  1127.  
  1128.   xil_export(new);
  1129.  
  1130.   if (xil_get_memory_storage(new, &storage) == FALSE)
  1131.     Sys_Error("xil_get_memory_storage");
  1132.  
  1133.   vid.buffer =   storage.byte.data;
  1134.   vid.conbuffer = vid.buffer;
  1135.  
  1136.   return (new);
  1137. }
  1138.  
  1139. void *update_thread()
  1140. {
  1141.   XilImage image;
  1142.  
  1143.   if (!X11_active)
  1144.     return;
  1145.  
  1146.   while (read(render_pipeline[0], &image, sizeof (image)) == sizeof(image)) {
  1147.  
  1148.     xil_import(image, TRUE); // let xil control the image
  1149.  
  1150.     if (!display_image)
  1151.       return;
  1152.  
  1153.     if (current_pixel_multiply < 2)
  1154.       xil_copy(image, display_image);
  1155.     else
  1156.       xil_scale(image, display_image, "nearest",
  1157.           (float)current_pixel_multiply, (float)current_pixel_multiply);
  1158.  
  1159.     if (write(render_pipeline[0], &image, sizeof (image)) != sizeof(image)) 
  1160.       Sys_Error("update_thread: write");
  1161.   }
  1162. }
  1163.  
  1164.  
  1165. static int dither;
  1166.  
  1167. void VID_DitherOn(void)
  1168. {
  1169.   if (dither == 0) {
  1170.     vid.recalc_refdef = 1;
  1171.     dither = 1;
  1172.   }
  1173. }
  1174.  
  1175. void VID_DitherOff(void)
  1176. {
  1177.   if (dither) {
  1178.     vid.recalc_refdef = 1;
  1179.     dither = 0;
  1180.   }
  1181. }
  1182.  
  1183. void VID_SetDefaultMode( void )
  1184. {
  1185. }
  1186.  
  1187. int I_OpenWindow(void)
  1188. {
  1189.   return 0;
  1190. }
  1191.  
  1192. void I_EraseWindow(int window)
  1193. {
  1194.  
  1195. }
  1196.  
  1197. void I_DrawCircle(int window, int x, int y, int r)
  1198. {
  1199. }
  1200.  
  1201. void I_DisplayWindow(int window)
  1202. {
  1203. }
  1204.  
  1205. void Sys_SendKeyEvents(void)
  1206. {
  1207.   // get events from x server
  1208.        if (x_disp) {
  1209.            while (XPending(x_disp)) GetEvent();
  1210.            while (keyq_head != keyq_tail) {
  1211.                Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
  1212.                keyq_tail = (keyq_tail + 1) & 63;
  1213.              }
  1214.          }
  1215. }
  1216.  
  1217. void IN_Init (void)
  1218. {
  1219.   Cvar_RegisterVariable (&_windowed_mouse);
  1220.   Cvar_RegisterVariable (&m_filter);
  1221.    if ( COM_CheckParm ("-nomouse") )
  1222.      return;
  1223.    mouse_x = mouse_y = 0.0;
  1224.    mouse_avail = 1;
  1225. }
  1226.  
  1227. void IN_Shutdown (void)
  1228. {
  1229.    mouse_avail = 0;
  1230. }
  1231.  
  1232. void IN_Commands (void)
  1233. {
  1234.   int i;
  1235.    
  1236.   if (!mouse_avail) return;
  1237.    
  1238.   for (i=0 ; i<mouse_buttons ; i++) {
  1239.     if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
  1240.       Key_Event (K_MOUSE1 + i, true);
  1241.  
  1242.     if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
  1243.       Key_Event (K_MOUSE1 + i, false);
  1244.   }
  1245.   mouse_oldbuttonstate = mouse_buttonstate;
  1246. }
  1247.  
  1248. void IN_Move (usercmd_t *cmd)
  1249. {
  1250.   if (!mouse_avail)
  1251.     return;
  1252.    
  1253.   if (m_filter.value) {
  1254.     mouse_x = (mouse_x + old_mouse_x) * 0.5;
  1255.     mouse_y = (mouse_y + old_mouse_y) * 0.5;
  1256.   }
  1257.  
  1258.   old_mouse_x = mouse_x;
  1259.   old_mouse_y = mouse_y;
  1260.    
  1261.   mouse_x *= sensitivity.value;
  1262.   mouse_y *= sensitivity.value;
  1263.    
  1264.   if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
  1265.     cmd->sidemove += m_side.value * mouse_x;
  1266.   else
  1267.     cl.viewangles[YAW] -= m_yaw.value * mouse_x;
  1268.   if (in_mlook.state & 1)
  1269.     V_StopPitchDrift ();
  1270.    
  1271.   if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
  1272.     cl.viewangles[PITCH] += m_pitch.value * mouse_y;
  1273.     if (cl.viewangles[PITCH] > 80)
  1274.       cl.viewangles[PITCH] = 80;
  1275.     if (cl.viewangles[PITCH] < -70)
  1276.       cl.viewangles[PITCH] = -70;
  1277.   } else {
  1278.     if ((in_strafe.state & 1) && noclip_anglehack)
  1279.       cmd->upmove -= m_forward.value * mouse_y;
  1280.     else
  1281.       cmd->forwardmove -= m_forward.value * mouse_y;
  1282.   }
  1283.   mouse_x = mouse_y = 0.0;
  1284. }
  1285.  
  1286. //void VID_UnlockBuffer(void) { }
  1287. //void VID_LockBuffer(void) { }
  1288.  
  1289.