Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.