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 */
D_BeginDirectRect(int x,int y,byte * pbitmap,int width,int height)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 */
D_EndDirectRect(int x,int y,int width,int height)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
VID_Gamma_f(void)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
CheckPixelMultiply(void)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
TragicDeath(int signal_num)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
CreateNullCursor(Display * display,Window root)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
VID_MenuDraw(void)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
VID_MenuKey(int key)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
VID_SetWindowTitle(Window win,char * pszName)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
VID_FullScreen(Window win)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
VID_Init(unsigned char * palette)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
VID_ResetFramebuffer()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
VID_ResetFramebuffer_MT()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
VID_ShiftPalette(unsigned char * p)707 void VID_ShiftPalette(unsigned char *p)
708 {
709 VID_SetPalette(p);
710 }
711
VID_SetPalette(unsigned char * palette)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
VID_Shutdown(void)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
XLateKey(XKeyEvent * ev)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
GetEvent(void)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
VID_Update(vrect_t * rects)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
VID_Update_MT(vrect_t * rects)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
drain_renderpipeline(XilImage old)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
sched_update(XilImage image)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
update_thread()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
VID_DitherOn(void)1167 void VID_DitherOn(void)
1168 {
1169 if (dither == 0) {
1170 vid.recalc_refdef = 1;
1171 dither = 1;
1172 }
1173 }
1174
VID_DitherOff(void)1175 void VID_DitherOff(void)
1176 {
1177 if (dither) {
1178 vid.recalc_refdef = 1;
1179 dither = 0;
1180 }
1181 }
1182
VID_SetDefaultMode(void)1183 void VID_SetDefaultMode( void )
1184 {
1185 }
1186
I_OpenWindow(void)1187 int I_OpenWindow(void)
1188 {
1189 return 0;
1190 }
1191
I_EraseWindow(int window)1192 void I_EraseWindow(int window)
1193 {
1194
1195 }
1196
I_DrawCircle(int window,int x,int y,int r)1197 void I_DrawCircle(int window, int x, int y, int r)
1198 {
1199 }
1200
I_DisplayWindow(int window)1201 void I_DisplayWindow(int window)
1202 {
1203 }
1204
Sys_SendKeyEvents(void)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
IN_Init(void)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
IN_Shutdown(void)1227 void IN_Shutdown (void)
1228 {
1229 mouse_avail = 0;
1230 }
1231
IN_Commands(void)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
IN_Move(usercmd_t * cmd)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