1 /*
2 Copyright (C) 1997-2001 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 /*
21 ** GLW_IMP.C
22 **
23 ** This file contains ALL Linux specific stuff having to do with the
24 ** OpenGL refresh. When a port is being made the following functions
25 ** must be implemented by the port:
26 **
27 ** GLimp_EndFrame
28 ** GLimp_Init
29 ** GLimp_Shutdown
30 ** GLimp_SwitchFullscreen
31 **
32 */
33
34 #include <termios.h>
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #ifdef __linux__
38 #include <sys/vt.h>
39 #endif
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <signal.h>
43
44 #include "../ref_gl/gl_local.h"
45
46 #include "../client/keys.h"
47
48 #include "../unix/rw_unix.h"
49 #include "../unix/glw_unix.h"
50
51 #include <GL/glx.h>
52
53 #include <X11/keysym.h>
54 #include <X11/Xatom.h>
55 #include <X11/cursorfont.h>
56
57 #include <X11/extensions/xf86dga.h>
58 #include <X11/extensions/xf86vmode.h>
59
60 glwstate_t glw_state;
61
62 static Display *dpy = NULL;
63 static int scrnum;
64 static Window win;
65 static GLXContext ctx = NULL;
66 static Atom wmDeleteWindow;
67
68 #define KEY_MASK (KeyPressMask | KeyReleaseMask)
69 #define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
70 PointerMotionMask | ButtonMotionMask )
71 #define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
72
73 /*****************************************************************************/
74 /* MOUSE */
75 /*****************************************************************************/
76
77 // this is inside the renderer shared lib, so these are called from vid_so
78
79 static qboolean mouse_avail;
80 static int mx, my;
81 static int old_mouse_x, old_mouse_y;
82
83 static int win_x, win_y;
84
85 static cvar_t *m_filter;
86 static cvar_t *in_mouse;
87 static cvar_t *in_dgamouse;
88
89 static cvar_t *r_fakeFullscreen;
90
91 static XF86VidModeModeInfo **vidmodes;
92 static XF86VidModeGamma oldgamma;
93 static int default_dotclock_vidmode;
94 static int num_vidmodes;
95 static qboolean vidmode_active = false;
96 static Time myxtime;
97
98 static qboolean mlooking;
99
100 static qboolean mouse_active = false;
101 static qboolean dgamouse = false;
102 static qboolean vidmode_ext = false;
103
104 // state struct passed in Init
105 static in_state_t *in_state;
106
107 static cvar_t *sensitivity;
108 static cvar_t *lookstrafe;
109 static cvar_t *m_side;
110 static cvar_t *m_yaw;
111 static cvar_t *m_pitch;
112 static cvar_t *m_forward;
113 static cvar_t *freelook;
114 static cvar_t *autosensitivity;
115
116 qboolean have_stencil = false;
117
CreateNullCursor(Display * display,Window root)118 static Cursor CreateNullCursor(Display *display, Window root)
119 {
120 Pixmap cursormask;
121 XGCValues xgc;
122 GC gc;
123 XColor dummycolour;
124 Cursor cursor;
125
126 cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
127 xgc.function = GXclear;
128 gc = XCreateGC(display, cursormask, GCFunction, &xgc);
129 XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
130 dummycolour.pixel = 0;
131 dummycolour.red = 0;
132 dummycolour.flags = 04;
133 cursor = XCreatePixmapCursor(display, cursormask, cursormask,
134 &dummycolour,&dummycolour, 0,0);
135 XFreePixmap(display,cursormask);
136 XFreeGC(display,gc);
137 return cursor;
138 }
139
install_grabs(void)140 static void install_grabs(void)
141 {
142
143 // inviso cursor
144 XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
145
146 XGrabPointer(dpy, win,
147 True,
148 0,
149 GrabModeAsync, GrabModeAsync,
150 win,
151 None,
152 CurrentTime);
153
154 if (in_dgamouse->value) {
155 int MajorVersion, MinorVersion;
156
157 if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
158 // unable to query, probalby not supported
159 ri.Con_Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
160 ri.Cvar_Set( "in_dgamouse", "0" );
161 } else {
162 dgamouse = true;
163 XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
164 XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
165 }
166 } else {
167 XWarpPointer(dpy, None, win,
168 0, 0, 0, 0,
169 vid.width / 2, vid.height / 2);
170 }
171
172 XGrabKeyboard(dpy, win,
173 False,
174 GrabModeAsync, GrabModeAsync,
175 CurrentTime);
176
177 mouse_active = true;
178
179 // XSync(dpy, True);
180 }
181
uninstall_grabs(void)182 static void uninstall_grabs(void)
183 {
184 if (!dpy || !win)
185 return;
186
187 if (dgamouse) {
188 dgamouse = false;
189 XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
190 }
191
192 XUngrabPointer(dpy, CurrentTime);
193 XUngrabKeyboard(dpy, CurrentTime);
194
195 // inviso cursor
196 XUndefineCursor(dpy, win);
197
198 mouse_active = false;
199 }
200
Force_CenterView_f(void)201 static void Force_CenterView_f (void)
202 {
203 in_state->viewangles[PITCH] = 0;
204 }
205
RW_IN_MLookDown(void)206 static void RW_IN_MLookDown (void)
207 {
208 mlooking = true;
209 }
210
RW_IN_MLookUp(void)211 static void RW_IN_MLookUp (void)
212 {
213 mlooking = false;
214 in_state->IN_CenterView_fp ();
215 }
216
RW_IN_Init(in_state_t * in_state_p)217 void RW_IN_Init(in_state_t *in_state_p)
218 {
219 int mtype;
220 int i;
221
222 in_state = in_state_p;
223
224 // mouse variables
225 m_filter = ri.Cvar_Get ("m_filter", "0", 0);
226 in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
227 in_dgamouse = ri.Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
228 freelook = ri.Cvar_Get( "freelook", "1", CVAR_ARCHIVE );
229 lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
230 sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
231 m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
232 m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
233 m_forward = ri.Cvar_Get ("m_forward", "1", 0);
234 m_side = ri.Cvar_Get ("m_side", "0.8", 0);
235 autosensitivity = ri.Cvar_Get ("autosensitivity", "1", CVAR_ARCHIVE);
236
237 ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
238 ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
239
240 ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
241
242 mx = my = 0.0;
243 mouse_avail = true;
244 }
245
RW_IN_Shutdown(void)246 void RW_IN_Shutdown(void)
247 {
248 mouse_avail = false;
249 }
250
251 /*
252 ===========
253 IN_Commands
254 ===========
255 */
RW_IN_Commands(void)256 void RW_IN_Commands (void)
257 {
258 }
259
260 /*
261 ===========
262 IN_Move
263 ===========
264 */
RW_IN_Move(usercmd_t * cmd,int * mcoords)265 void RW_IN_Move (usercmd_t *cmd, int *mcoords)
266 {
267
268 if (!mouse_avail)
269 return;
270
271 if (m_filter->value)
272 {
273 mx = (mx + old_mouse_x) * 0.5;
274 my = (my + old_mouse_y) * 0.5;
275 }
276
277 old_mouse_x = mx;
278 old_mouse_y = my;
279
280 // raw coords for menu mouse
281 mcoords[0] = mx;
282 mcoords[1] = my;
283
284 if (autosensitivity->value)
285 {
286 mx *= sensitivity->value * (r_newrefdef.fov_x/90.0);
287 my *= sensitivity->value * (r_newrefdef.fov_y/90.0);
288 }
289 else
290 {
291 mx *= sensitivity->value;
292 my *= sensitivity->value;
293 }
294
295
296 // add mouse X/Y movement to cmd
297 if ( (*in_state->in_strafe_state & 1) ||
298 (lookstrafe->value && mlooking ))
299 cmd->sidemove += m_side->value * mx;
300 else
301 in_state->viewangles[YAW] -= m_yaw->value * mx;
302
303 if ( (mlooking || freelook->value) &&
304 !(*in_state->in_strafe_state & 1))
305 {
306 in_state->viewangles[PITCH] += m_pitch->value * my;
307 }
308 else
309 {
310 cmd->forwardmove -= m_forward->value * my;
311 }
312
313 mx = my = 0;
314 }
IN_DeactivateMouse(void)315 static void IN_DeactivateMouse( void )
316 {
317 if (!mouse_avail || !dpy || !win)
318 return;
319
320 if (mouse_active) {
321 uninstall_grabs();
322 mouse_active = false;
323 }
324 }
325
IN_ActivateMouse(void)326 static void IN_ActivateMouse( void )
327 {
328 if (!mouse_avail || !dpy || !win)
329 return;
330
331 if (!mouse_active) {
332 mx = my = 0; // don't spazz
333 install_grabs();
334 mouse_active = true;
335 }
336 }
337
RW_IN_Frame(void)338 void RW_IN_Frame (void)
339 {
340 }
341
RW_IN_Activate(qboolean active)342 void RW_IN_Activate(qboolean active)
343 {
344 if (active || vidmode_active)
345 IN_ActivateMouse();
346 else
347 IN_DeactivateMouse ();
348 }
349
350 /*****************************************************************************/
351 /* KEYBOARD */
352 /*****************************************************************************/
353
XLateKey(XKeyEvent * ev)354 static int XLateKey(XKeyEvent *ev)
355 {
356
357 int key;
358 char buf[64];
359 KeySym keysym;
360
361 key = 0;
362
363 XLookupString(ev, buf, sizeof buf, &keysym, 0);
364
365 switch(keysym)
366 {
367 case XK_KP_Page_Up: key = K_KP_PGUP; break;
368 case XK_Page_Up: key = K_PGUP; break;
369
370 case XK_KP_Page_Down: key = K_KP_PGDN; break;
371 case XK_Page_Down: key = K_PGDN; break;
372
373 case XK_KP_Home: key = K_KP_HOME; break;
374 case XK_Home: key = K_HOME; break;
375
376 case XK_KP_End: key = K_KP_END; break;
377 case XK_End: key = K_END; break;
378
379 case XK_KP_Left: key = K_KP_LEFTARROW; break;
380 case XK_Left: key = K_LEFTARROW; break;
381
382 case XK_KP_Right: key = K_KP_RIGHTARROW; break;
383 case XK_Right: key = K_RIGHTARROW; break;
384
385 case XK_KP_Down: key = K_KP_DOWNARROW; break;
386 case XK_Down: key = K_DOWNARROW; break;
387
388 case XK_KP_Up: key = K_KP_UPARROW; break;
389 case XK_Up: key = K_UPARROW; break;
390
391 case XK_Escape: key = K_ESCAPE; break;
392
393 case XK_KP_Enter: key = K_KP_ENTER; break;
394 case XK_Return: key = K_ENTER; break;
395
396 case XK_Tab: key = K_TAB; break;
397
398 case XK_F1: key = K_F1; break;
399
400 case XK_F2: key = K_F2; break;
401
402 case XK_F3: key = K_F3; break;
403
404 case XK_F4: key = K_F4; break;
405
406 case XK_F5: key = K_F5; break;
407
408 case XK_F6: key = K_F6; break;
409
410 case XK_F7: key = K_F7; break;
411
412 case XK_F8: key = K_F8; break;
413
414 case XK_F9: key = K_F9; break;
415
416 case XK_F10: key = K_F10; break;
417
418 case XK_F11: key = K_F11; break;
419
420 case XK_F12: key = K_F12; break;
421
422 case XK_BackSpace: key = K_BACKSPACE; break;
423
424 case XK_KP_Delete: key = K_KP_DEL; break;
425 case XK_Delete: key = K_DEL; break;
426
427 case XK_Pause: key = K_PAUSE; break;
428
429 case XK_Shift_L:
430 case XK_Shift_R: key = K_SHIFT; break;
431
432 case XK_Execute:
433 case XK_Control_L:
434 case XK_Control_R: key = K_CTRL; break;
435
436 case XK_Alt_L:
437 case XK_Meta_L:
438 case XK_Alt_R:
439 case XK_Meta_R: key = K_ALT; break;
440
441 case XK_KP_Begin: key = K_KP_5; break;
442
443 case XK_Insert:key = K_INS; break;
444 case XK_KP_Insert: key = K_KP_INS; break;
445
446 case XK_KP_Multiply: key = '*'; break;
447 case XK_KP_Add: key = K_KP_PLUS; break;
448 case XK_KP_Subtract: key = K_KP_MINUS; break;
449 case XK_KP_Divide: key = K_KP_SLASH; break;
450
451 default:
452 key = *(unsigned char*)buf;
453 if (key >= 'A' && key <= 'Z')
454 key = key - 'A' + 'a';
455 if (key >= 1 && key <= 26)
456 key = key + 'a' - 1;
457 break;
458 }
459
460 return key;
461 }
462
HandleEvents(void)463 static void HandleEvents(void)
464 {
465 XEvent event;
466 int b;
467 qboolean dowarp = false;
468 int mwx = vid.width/2;
469 int mwy = vid.height/2;
470 int mouse_buttonstate;
471
472 if (!dpy)
473 return;
474
475 while (XPending(dpy)) {
476
477 XNextEvent(dpy, &event);
478 switch(event.type) {
479 case KeyPress:
480 myxtime = event.xkey.time;
481 if (in_state && in_state->Key_Event_fp)
482 in_state->Key_Event_fp (XLateKey(&event.xkey), true);
483 break;
484 case KeyRelease:
485 if (in_state && in_state->Key_Event_fp)
486 in_state->Key_Event_fp (XLateKey(&event.xkey), event.type == KeyPress);
487 break;
488
489 case MotionNotify:
490 if (mouse_active) {
491 if (dgamouse) {
492 mx += (event.xmotion.x + win_x);
493 my += (event.xmotion.y + win_y);
494 }
495 else
496 {
497 mx += ((int)event.xmotion.x - mwx);
498 my += ((int)event.xmotion.y - mwy);
499
500 if (mx || my)
501 dowarp = true;
502 }
503 }
504 break;
505
506
507 case ButtonPress:
508 myxtime = event.xbutton.time;
509 b=-1;
510 if (event.xbutton.button == 1)
511 b = 0;
512 else if (event.xbutton.button == 2)
513 b = 2;
514 else if (event.xbutton.button == 3)
515 b = 1;
516 else if (event.xbutton.button == 4)
517 in_state->Key_Event_fp (K_MWHEELUP, 1);
518 else if (event.xbutton.button == 5)
519 in_state->Key_Event_fp (K_MWHEELDOWN, 1);
520 else if (event.xbutton.button == 6)
521 in_state->Key_Event_fp (K_MOUSE4, 1);
522 else if (event.xbutton.button == 7)
523 in_state->Key_Event_fp (K_MOUSE5, 1);
524 if (b>=0 && in_state && in_state->Key_Event_fp)
525 in_state->Key_Event_fp (K_MOUSE1 + b, true);
526 if (b>=0)
527 mouse_buttonstate |= 1<<b;
528 break;
529
530 case ButtonRelease:
531 b=-1;
532 if (event.xbutton.button == 1)
533 b = 0;
534 else if (event.xbutton.button == 2)
535 b = 2;
536 else if (event.xbutton.button == 3)
537 b = 1;
538 else if (event.xbutton.button == 4)
539 in_state->Key_Event_fp (K_MWHEELUP, 0);
540 else if (event.xbutton.button == 5)
541 in_state->Key_Event_fp (K_MWHEELDOWN, 0);
542 else if (event.xbutton.button == 6)
543 in_state->Key_Event_fp (K_MOUSE4, 0);
544 else if (event.xbutton.button == 7)
545 in_state->Key_Event_fp (K_MOUSE5, 0);
546 if (b>=0 && in_state && in_state->Key_Event_fp)
547 in_state->Key_Event_fp (K_MOUSE1 + b, false);
548 if (b>=0)
549 mouse_buttonstate &= ~(1<<b);
550 break;
551
552 case CreateNotify :
553 win_x = event.xcreatewindow.x;
554 win_y = event.xcreatewindow.y;
555 break;
556
557 case ConfigureNotify :
558 win_x = event.xconfigure.x;
559 win_y = event.xconfigure.y;
560 break;
561
562 case ClientMessage:
563 if (event.xclient.data.l[0] == wmDeleteWindow)
564 ri.Cmd_ExecuteText(EXEC_NOW, "quit");
565 break;
566 }
567 }
568
569 if (dowarp) {
570 /* move the mouse to the window center again */
571 XWarpPointer(dpy,None,win,0,0,0,0, vid.width/2,vid.height/2);
572 }
573 }
574
575 Key_Event_fp_t Key_Event_fp;
576
KBD_Init(Key_Event_fp_t fp)577 void KBD_Init(Key_Event_fp_t fp)
578 {
579 Key_Event_fp = fp;
580 }
581
KBD_Update(void)582 void KBD_Update(void)
583 {
584 // get events from x server
585 HandleEvents();
586 }
587
KBD_Close(void)588 void KBD_Close(void)
589 {
590 }
591
592 /*****************************************************************************/
593
594 static qboolean GLimp_SwitchFullscreen( int width, int height );
595 qboolean GLimp_InitGL (void);
596
signal_handler(int sig)597 static void signal_handler(int sig)
598 {
599 printf("Received signal %d, exiting...\n", sig);
600 GLimp_Shutdown();
601 _exit(0);
602 }
603
InitSig(void)604 static void InitSig(void)
605 {
606 signal(SIGHUP, signal_handler);
607 signal(SIGQUIT, signal_handler);
608 signal(SIGILL, signal_handler);
609 signal(SIGTRAP, signal_handler);
610 signal(SIGIOT, signal_handler);
611 signal(SIGBUS, signal_handler);
612 signal(SIGFPE, signal_handler);
613 signal(SIGSEGV, signal_handler);
614 signal(SIGTERM, signal_handler);
615 }
616
617 /*
618 ** GLimp_SetMode
619 */
GLimp_SetMode(int * pwidth,int * pheight,int mode,qboolean fullscreen)620 int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
621 {
622 int width, height;
623 int attrib[] = {
624 GLX_RGBA,
625 GLX_RED_SIZE, 1,
626 GLX_GREEN_SIZE, 1,
627 GLX_BLUE_SIZE, 1,
628 GLX_DOUBLEBUFFER,
629 GLX_DEPTH_SIZE, 1,
630 GLX_STENCIL_SIZE, 1,
631 None
632 };
633 Window root;
634 XVisualInfo *visinfo;
635 XSetWindowAttributes attr;
636 unsigned long mask;
637 int MajorVersion, MinorVersion;
638 int actualWidth, actualHeight;
639 XSizeHints *sizehints;
640 XWMHints *wmhints;
641 int i;
642
643 r_fakeFullscreen = ri.Cvar_Get( "r_fakeFullscreen", "0", CVAR_ARCHIVE);
644
645 ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
646
647 if (fullscreen)
648 ri.Con_Printf (PRINT_ALL, "...setting fullscreen mode %d:", mode );
649 else
650 ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
651
652 if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
653 {
654 ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
655 return rserr_invalid_mode;
656 }
657
658 ri.Con_Printf( PRINT_ALL, " %d %d\n", width, height );
659
660 // destroy the existing window
661 GLimp_Shutdown ();
662
663 if (!(dpy = XOpenDisplay(NULL))) {
664 fprintf(stderr, "Error couldn't open the X display\n");
665 return rserr_invalid_mode;
666 }
667
668 scrnum = DefaultScreen(dpy);
669 root = RootWindow(dpy, scrnum);
670
671 // Get video mode list
672 MajorVersion = MinorVersion = 0;
673 if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
674 vidmode_ext = false;
675 } else {
676 ri.Con_Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
677 MajorVersion, MinorVersion);
678 vidmode_ext = true;
679 }
680
681 visinfo = qglXChooseVisual(dpy, scrnum, attrib);
682 if (!visinfo) {
683 fprintf(stderr, "Error couldn't get an RGB, Double-buffered, Depth visual\n");
684 return rserr_invalid_mode;
685 }
686
687 gl_state.hwgamma = false;
688
689 if (vidmode_ext) {
690 int best_fit, best_dist, dist, x, y;
691
692 XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
693
694 // Are we going fullscreen? If so, let's change video mode
695 if (fullscreen && !r_fakeFullscreen->value) {
696 best_dist = 9999999;
697 best_fit = -1;
698
699 for (i = 0; i < num_vidmodes; i++) {
700 if (width > vidmodes[i]->hdisplay ||
701 height > vidmodes[i]->vdisplay)
702 continue;
703
704 x = width - vidmodes[i]->hdisplay;
705 y = height - vidmodes[i]->vdisplay;
706 dist = (x * x) + (y * y);
707 if (dist < best_dist) {
708 best_dist = dist;
709 best_fit = i;
710 }
711 }
712
713 if (best_fit != -1) {
714 actualWidth = vidmodes[best_fit]->hdisplay;
715 actualHeight = vidmodes[best_fit]->vdisplay;
716
717 // change to the mode
718 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
719 vidmode_active = true;
720 if (XF86VidModeGetGamma(dpy, scrnum, &oldgamma)) {
721 gl_state.hwgamma = true;
722 /* We can no reliably detect hardware gamma
723 changes across software gamma calls, which
724 can reset the flag, so change it anyway */
725 vid_gamma->modified = true;
726 ri.Con_Printf( PRINT_ALL, "Using hardware gamma\n");
727 }
728
729 // Move the viewport to top left
730 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
731 } else
732 fullscreen = 0;
733 }
734 }
735
736 /* window attributes */
737 attr.background_pixel = 0;
738 attr.border_pixel = 0;
739 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
740 attr.event_mask = X_MASK;
741 if (vidmode_active) {
742 mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore |
743 CWEventMask | CWOverrideRedirect;
744 attr.override_redirect = True;
745 attr.backing_store = NotUseful;
746 attr.save_under = False;
747 } else
748 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
749
750 win = XCreateWindow(dpy, root, 0, 0, width, height,
751 0, visinfo->depth, InputOutput,
752 visinfo->visual, mask, &attr);
753
754 XStoreName(dpy, win, "Quake2maX");
755
756 sizehints = XAllocSizeHints();
757 if (sizehints) {
758 sizehints->min_width = width;
759 sizehints->min_height = height;
760 sizehints->max_width = width;
761 sizehints->max_height = height;
762 sizehints->base_width = width;
763 sizehints->base_height = vid.height;
764
765 sizehints->flags = PMinSize | PMaxSize | PBaseSize;
766 }
767
768 wmhints = XAllocWMHints();
769 if (wmhints) {
770 #include "q2icon.xbm"
771
772 Pixmap icon_pixmap, icon_mask;
773 unsigned long fg, bg;
774 int i;
775
776 fg = BlackPixel(dpy, visinfo->screen);
777 bg = WhitePixel(dpy, visinfo->screen);
778 icon_pixmap = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, fg, bg, visinfo->depth);
779 for (i = 0; i < sizeof(q2icon_bits); i++)
780 q2icon_bits[i] = ~q2icon_bits[i];
781 icon_mask = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, bg, fg, visinfo->depth);
782
783 wmhints->flags = IconPixmapHint|IconMaskHint;
784 wmhints->icon_pixmap = icon_pixmap;
785 wmhints->icon_mask = icon_mask;
786 }
787
788 XSetWMProperties(dpy, win, NULL, NULL, NULL, 0,
789 sizehints, wmhints, None);
790 if (sizehints)
791 XFree(sizehints);
792 if (wmhints)
793 XFree(wmhints);
794
795 wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
796 XSetWMProtocols(dpy, win, &wmDeleteWindow, 1);
797
798 XMapWindow(dpy, win);
799
800 if (vidmode_active) {
801 XMoveWindow(dpy, win, 0, 0);
802 XRaiseWindow(dpy, win);
803 XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
804 XFlush(dpy);
805 // Move the viewport to top left
806 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
807 }
808
809 XFlush(dpy);
810
811 ctx = qglXCreateContext(dpy, visinfo, NULL, True);
812
813 qglXMakeCurrent(dpy, win, ctx);
814
815 *pwidth = width;
816 *pheight = height;
817
818 // let the sound and input subsystems know about the new window
819 ri.Vid_NewWindow (width, height);
820
821 qglXMakeCurrent(dpy, win, ctx);
822
823 {
824 // Vertex arrays
825 qglEnableClientState (GL_VERTEX_ARRAY);
826 qglEnableClientState (GL_TEXTURE_COORD_ARRAY);
827
828 qglTexCoordPointer (2, GL_FLOAT, sizeof(tex_array[0]), tex_array[0]);
829 qglVertexPointer (3, GL_FLOAT, sizeof(vert_array[0]), vert_array[0]);
830 qglColorPointer (4, GL_FLOAT, sizeof(col_array[0]), col_array[0]);
831 }
832
833 return rserr_ok;
834 }
835
836 /*
837 ** GLimp_Shutdown
838 **
839 ** This routine does all OS specific shutdown procedures for the OpenGL
840 ** subsystem. Under OpenGL this means NULLing out the current DC and
841 ** HGLRC, deleting the rendering context, and releasing the DC acquired
842 ** for the window. The state structure is also nulled out.
843 **
844 */
GLimp_Shutdown(void)845 void GLimp_Shutdown( void )
846 {
847
848 RS_FreeAllScripts(); // unload rscript
849 uninstall_grabs();
850 mouse_active = false;
851 dgamouse = false;
852
853 if (dpy) {
854 if (ctx)
855 qglXDestroyContext(dpy, ctx);
856 if (win)
857 XDestroyWindow(dpy, win);
858 if (gl_state.hwgamma) {
859 XF86VidModeSetGamma(dpy, scrnum, &oldgamma);
860 }
861 if (vidmode_active)
862 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
863 XUngrabKeyboard(dpy, CurrentTime);
864 XCloseDisplay(dpy);
865 }
866 ctx = NULL;
867 dpy = NULL;
868 win = 0;
869 ctx = NULL;
870 }
871
872 /*
873 ** GLimp_Init
874 **
875 ** This routine is responsible for initializing the OS specific portions
876 ** of OpenGL.
877 */
GLimp_Init(void * hinstance,void * wndproc)878 int GLimp_Init( void *hinstance, void *wndproc )
879 {
880 InitSig();
881
882 ri.Con_Printf( PRINT_ALL, "... Using stencil buffer\n" );
883 have_stencil = true; // Stencil shadows - MrG
884
885 RS_ScanPathForScripts(); // load all found scripts
886
887 return true;
888 }
889
890 /*
891 ** GLimp_BeginFrame
892 */
GLimp_BeginFrame(float camera_seperation)893 void GLimp_BeginFrame( float camera_seperation )
894 {
895 //Heffo - CIN Texture Update
896 CIN_ProcessCins();
897 }
898
899 /*
900 ** GLimp_EndFrame
901 **
902 ** Responsible for doing a swapbuffers and possibly for other stuff
903 ** as yet to be determined. Probably better not to make this a GLimp
904 ** function and instead do a call to GLimp_SwapBuffers.
905 */
GLimp_EndFrame(void)906 void GLimp_EndFrame (void)
907 {
908 qglFlush();
909 qglXSwapBuffers(dpy, win);
910
911 // rscript - MrG
912 rs_realtime=Sys_Milliseconds() * 0.001f;
913 }
914
915 /*
916 ** GLimp_AppActivate
917 */
GLimp_AppActivate(qboolean active)918 void GLimp_AppActivate( qboolean active )
919 {
920 }
921
Fake_glColorTableEXT(GLenum target,GLenum internalformat,GLsizei width,GLenum format,GLenum type,const GLvoid * table)922 void Fake_glColorTableEXT( GLenum target, GLenum internalformat,
923 GLsizei width, GLenum format, GLenum type,
924 const GLvoid *table )
925 {
926 byte temptable[256][4];
927 byte *intbl;
928 int i;
929
930 for (intbl = (byte *)table, i = 0; i < 256; i++) {
931 temptable[i][2] = *intbl++;
932 temptable[i][1] = *intbl++;
933 temptable[i][0] = *intbl++;
934 temptable[i][3] = 255;
935 }
936 qgl3DfxSetPaletteEXT((GLuint *)temptable);
937 }
938
939
940 /*------------------------------------------------*/
941 /* X11 Input Stuff
942 /*------------------------------------------------*/
943
944
945 /*
946 ** UpdateHardwareGamma
947 **
948 ** We are using gamma relative to the desktop, so that we can share it
949 ** with software renderer and don't require to change desktop gamma
950 ** to match hardware gamma image brightness. It seems that Quake 3 is
951 ** using the opposite approach, but it has no software renderer after
952 ** all.
953 */
UpdateHardwareGamma()954 void UpdateHardwareGamma()
955 {
956 XF86VidModeGamma gamma;
957 float g;
958
959 g = (1.3 - vid_gamma->value + 1);
960 g = (g>1 ? g : 1);
961 gamma.red = oldgamma.red * g;
962 gamma.green = oldgamma.green * g;
963 gamma.blue = oldgamma.blue * g;
964 XF86VidModeSetGamma(dpy, scrnum, &gamma);
965 }
966
967
968
969 /*------------------------------------------------*/
970 /* X11 Input Stuff
971 /*------------------------------------------------*/
972
973
RW_Sys_GetClipboardData()974 char *RW_Sys_GetClipboardData()
975 {
976 Window sowner;
977 Atom type, property;
978 unsigned long len, bytes_left, tmp;
979 unsigned char *data;
980 int format, result;
981 char *ret = NULL;
982
983 sowner = XGetSelectionOwner(dpy, XA_PRIMARY);
984
985 if (sowner != None) {
986 property = XInternAtom(dpy,
987 "GETCLIPBOARDDATA_PROP",
988 False);
989
990 XConvertSelection(dpy,
991 XA_PRIMARY, XA_STRING,
992 property, win, myxtime); /* myxtime == time of last X event */
993 XFlush(dpy);
994
995 XGetWindowProperty(dpy,
996 win, property,
997 0, 0, False, AnyPropertyType,
998 &type, &format, &len,
999 &bytes_left, &data);
1000 if (bytes_left > 0) {
1001 result =
1002 XGetWindowProperty(dpy,
1003 win, property,
1004 0, bytes_left, True, AnyPropertyType,
1005 &type, &format, &len,
1006 &tmp, &data);
1007 if (result == Success) {
1008 ret = strdup(data);
1009 }
1010 XFree(data);
1011 }
1012 }
1013 return ret;
1014 }
1015
1016
1017