glw_imp.c (21153B)
1 /* 2 ** GLW_IMP.C 3 ** 4 ** This file contains ALL Linux specific stuff having to do with the 5 ** OpenGL refresh. When a port is being made the following functions 6 ** must be implemented by the port: 7 ** 8 ** GLimp_EndFrame 9 ** GLimp_Init 10 ** GLimp_Shutdown 11 ** GLimp_SwitchFullscreen 12 ** 13 */ 14 15 #include <signal.h> 16 17 #include <X11/Xlib.h> 18 #include <X11/Xutil.h> 19 #include <X11/Xatom.h> 20 #include <X11/keysym.h> 21 #include <X11/extensions/XShm.h> 22 #include <Xm/MwmUtil.h> 23 24 #include <GL/glx.h> 25 26 #include "../ref_gl/gl_local.h" 27 #include "../client/keys.h" 28 #include "../linux/rw_linux.h" 29 30 GLXContext gl_cx; 31 32 static qboolean doShm; 33 static Display *x_disp; 34 static Colormap x_cmap; 35 static Window x_win; 36 static GC x_gc; 37 static Visual *x_vis; 38 static XVisualInfo *x_visinfo; 39 40 static int StudlyRGBattributes[] = 41 { 42 GLX_DOUBLEBUFFER, 43 GLX_RGBA, 44 GLX_RED_SIZE, 4, 45 GLX_GREEN_SIZE, 4, 46 GLX_BLUE_SIZE, 4, 47 GLX_DEPTH_SIZE, 1, 48 GLX_SAMPLES_SGIS, 4, /* for better AA */ 49 None, 50 }; 51 52 static int RGBattributes[] = 53 { 54 GLX_DOUBLEBUFFER, 55 GLX_RGBA, 56 GLX_RED_SIZE, 4, 57 GLX_GREEN_SIZE, 4, 58 GLX_BLUE_SIZE, 4, 59 GLX_DEPTH_SIZE, 1, 60 None, 61 }; 62 63 #define STD_EVENT_MASK (StructureNotifyMask | KeyPressMask \ 64 | KeyReleaseMask | ExposureMask | PointerMotionMask | \ 65 ButtonPressMask | ButtonReleaseMask) 66 67 int current_framebuffer; 68 static int x_shmeventtype; 69 //static XShmSegmentInfo x_shminfo; 70 71 static qboolean oktodraw = false; 72 static qboolean X11_active = false; 73 74 struct 75 { 76 int key; 77 int down; 78 } keyq[64]; 79 int keyq_head=0; 80 int keyq_tail=0; 81 82 static int mx, my; 83 static int p_mouse_x, p_mouse_y; 84 static cvar_t *_windowed_mouse; 85 86 static cvar_t *sensitivity; 87 static cvar_t *lookstrafe; 88 static cvar_t *m_side; 89 static cvar_t *m_yaw; 90 static cvar_t *m_pitch; 91 static cvar_t *m_forward; 92 static cvar_t *freelook; 93 94 int config_notify=0; 95 int config_notify_width; 96 int config_notify_height; 97 98 typedef unsigned short PIXEL; 99 100 // Console variables that we need to access from this module 101 102 /*****************************************************************************/ 103 /* MOUSE */ 104 /*****************************************************************************/ 105 106 // this is inside the renderer shared lib, so these are called from vid_so 107 108 static qboolean mouse_avail; 109 static int mouse_buttonstate; 110 static int mouse_oldbuttonstate; 111 static int mouse_x, mouse_y; 112 static int old_mouse_x, old_mouse_y; 113 static float old_windowed_mouse; 114 static int p_mouse_x, p_mouse_y; 115 116 static cvar_t *_windowed_mouse; 117 static cvar_t *m_filter; 118 static cvar_t *in_mouse; 119 120 static qboolean mlooking; 121 122 // state struct passed in Init 123 static in_state_t *in_state; 124 125 int XShmQueryExtension(Display *); 126 int XShmGetEventBase(Display *); 127 128 static void signal_handler(int sig) 129 { 130 fprintf(stderr, "Received signal %d, exiting...\n", sig); 131 GLimp_Shutdown(); 132 _exit(0); 133 } 134 135 static void InitSig(void) 136 { 137 struct sigaction sa; 138 sigaction(SIGINT, 0, &sa); 139 sa.sa_handler = signal_handler; 140 sigaction(SIGINT, &sa, 0); 141 sigaction(SIGTERM, &sa, 0); 142 } 143 144 /* 145 ** GLimp_SetMode 146 */ 147 int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ) 148 { 149 int width, height; 150 GLint attribs[32]; 151 152 fprintf(stderr, "GLimp_SetMode\n"); 153 154 ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n"); 155 156 ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode ); 157 158 if ( !ri.Vid_GetModeInfo( &width, &height, mode ) ) 159 { 160 ri.Con_Printf( PRINT_ALL, " invalid mode\n" ); 161 return rserr_invalid_mode; 162 } 163 164 ri.Con_Printf( PRINT_ALL, " %d %d\n", width, height ); 165 166 // destroy the existing window 167 GLimp_Shutdown (); 168 169 *pwidth = width; 170 *pheight = height; 171 172 if ( !GLimp_InitGraphics( fullscreen ) ) { 173 // failed to set a valid mode in windowed mode 174 return rserr_invalid_mode; 175 } 176 /* gl_cx = glXCreateContext( x_disp, x_visinfo, 0, True ); */ 177 178 // let the sound and input subsystems know about the new window 179 ri.Vid_NewWindow (width, height); 180 181 return rserr_ok; 182 } 183 184 /* 185 ** GLimp_Shutdown 186 ** 187 ** This routine does all OS specific shutdown procedures for the OpenGL 188 ** subsystem. Under OpenGL this means NULLing out the current DC and 189 ** HGLRC, deleting the rendering context, and releasing the DC acquired 190 ** for the window. The state structure is also nulled out. 191 ** 192 */ 193 void GLimp_Shutdown( void ) 194 { 195 fprintf(stderr, "GLimp_Shutdown\n"); 196 197 if (!x_disp) 198 return; 199 200 XSynchronize( x_disp, True ); 201 XAutoRepeatOn(x_disp); 202 XCloseDisplay(x_disp); 203 x_disp = NULL; 204 } 205 206 /* 207 ** GLimp_Init 208 ** 209 ** This routine is responsible for initializing the OS specific portions 210 ** of OpenGL. 211 */ 212 int GLimp_Init( void *hinstance, void *wndproc ) 213 { 214 // catch signals so i can turn on auto-repeat and stuff 215 InitSig(); 216 217 return true; 218 } 219 220 /* 221 ** GLimp_BeginFrame 222 */ 223 void GLimp_BeginFrame( float camera_seperation ) 224 { 225 } 226 227 /* 228 ** GLimp_EndFrame 229 ** 230 ** Responsible for doing a swapbuffers and possibly for other stuff 231 ** as yet to be determined. Probably better not to make this a GLimp 232 ** function and instead do a call to GLimp_SwapBuffers. 233 */ 234 void GLimp_EndFrame (void) 235 { 236 glFlush(); 237 glXSwapBuffers( x_disp, x_win ); 238 } 239 240 /* 241 ** GLimp_AppActivate 242 */ 243 void GLimp_AppActivate( qboolean active ) 244 { 245 } 246 247 // ======================================================================== 248 // makes a null cursor 249 // ======================================================================== 250 251 static Cursor CreateNullCursor(Display *display, Window root) 252 { 253 Pixmap cursormask; 254 XGCValues xgc; 255 GC gc; 256 XColor dummycolour; 257 Cursor cursor; 258 259 cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/); 260 xgc.function = GXclear; 261 gc = XCreateGC(display, cursormask, GCFunction, &xgc); 262 XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); 263 dummycolour.pixel = 0; 264 dummycolour.red = 0; 265 dummycolour.flags = 04; 266 cursor = XCreatePixmapCursor(display, cursormask, cursormask, 267 &dummycolour,&dummycolour, 0,0); 268 XFreePixmap(display,cursormask); 269 XFreeGC(display,gc); 270 return cursor; 271 } 272 273 /* 274 ** GLimp_InitGraphics 275 ** 276 ** This initializes the GL implementation specific 277 ** graphics subsystem. 278 ** 279 ** The necessary width and height parameters are grabbed from 280 ** vid.width and vid.height. 281 */ 282 qboolean GLimp_InitGraphics( qboolean fullscreen ) 283 { 284 int pnum, i; 285 XVisualInfo template; 286 int num_visuals; 287 int template_mask; 288 289 fprintf(stderr, "GLimp_InitGraphics\n"); 290 291 srandom(getpid()); 292 293 // let the sound and input subsystems know about the new window 294 ri.Vid_NewWindow (vid.width, vid.height); 295 296 // open the display 297 x_disp = XOpenDisplay(NULL); 298 if (!x_disp) 299 { 300 if (getenv("DISPLAY")) 301 Sys_Error("VID: Could not open display [%s]\n", 302 getenv("DISPLAY")); 303 else 304 Sys_Error("VID: Could not open local display\n"); 305 } 306 else 307 fprintf(stderr, "VID: Opened display %s\n", getenv("DISPLAY")); 308 309 XAutoRepeatOff(x_disp); 310 311 // for debugging only 312 XSynchronize(x_disp, True); 313 314 // check for command-line window size 315 template_mask = 0; 316 317 #if 0 318 // specify a visual id 319 if ((pnum=COM_CheckParm("-visualid"))) 320 { 321 if (pnum >= com_argc-1) 322 Sys_Error("VID: -visualid <id#>\n"); 323 template.visualid = Q_atoi(com_argv[pnum+1]); 324 template_mask = VisualIDMask; 325 } 326 327 // If not specified, use default visual 328 else 329 #endif 330 { 331 int screen; 332 screen = XDefaultScreen(x_disp); 333 template.visualid = 334 XVisualIDFromVisual(XDefaultVisual(x_disp, screen)); 335 template_mask = VisualIDMask; 336 } 337 338 // pick a visual- warn if more than one was available 339 340 x_visinfo = glXChooseVisual( x_disp, DefaultScreen( x_disp ), 341 StudlyRGBattributes ); 342 if (!x_visinfo) 343 { 344 fprintf(stderr, "Using non studly RGB attributes\n"); 345 x_visinfo = glXChooseVisual( x_disp, DefaultScreen( x_disp ), 346 RGBattributes ); 347 if (!x_visinfo) Sys_Error( "No matching visual available!\n" ); 348 } 349 350 ri.Con_Printf(PRINT_ALL, "Using visualid 0x%x:\n", 351 (int)(x_visinfo->visualid)); 352 #if 0 353 if (verbose) 354 { 355 printf("Using visualid %d:\n", (int)(x_visinfo->visualid)); 356 printf(" screen %d\n", x_visinfo->screen); 357 printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask)); 358 printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask)); 359 printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask)); 360 printf(" colormap_size %d\n", x_visinfo->colormap_size); 361 printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb); 362 } 363 #endif 364 365 x_vis = x_visinfo->visual; 366 367 // setup attributes for main window 368 { 369 int attribmask = CWEventMask | CWColormap | CWBorderPixel; 370 XSetWindowAttributes attribs; 371 Colormap tmpcmap; 372 373 Window root_win = XRootWindow(x_disp, x_visinfo->screen); 374 375 tmpcmap = XCreateColormap(x_disp, root_win, x_vis, AllocNone); 376 377 378 attribs.event_mask = STD_EVENT_MASK; 379 attribs.border_pixel = 0; 380 attribs.colormap = tmpcmap; 381 382 // create the main window 383 x_win = XCreateWindow( x_disp, 384 root_win, 385 0, 0, // x, y 386 vid.width, vid.height, 387 0, // borderwidth 388 x_visinfo->depth, 389 InputOutput, 390 x_vis, 391 attribmask, 392 &attribs ); 393 XStoreName(x_disp, x_win, "Quake II"); 394 395 if (x_visinfo->class != TrueColor) 396 XFreeColormap(x_disp, tmpcmap); 397 } 398 399 if (x_visinfo->depth == 8) 400 { 401 // create and upload the palette 402 if (x_visinfo->class == PseudoColor) 403 { 404 x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll); 405 XSetWindowColormap(x_disp, x_win, x_cmap); 406 } 407 408 } 409 410 // inviso cursor 411 XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win)); 412 413 // create the GC 414 { 415 XGCValues xgcvalues; 416 int valuemask = GCGraphicsExposures; 417 xgcvalues.graphics_exposures = False; 418 x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues ); 419 } 420 421 // set window properties for full screen 422 if (fullscreen) { 423 MotifWmHints wmhints; 424 Atom aHints; 425 XSizeHints sizehints; 426 XWindowChanges changes; 427 428 aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 ); 429 if (aHints == None) 430 { 431 ri.Con_Printf( PRINT_ALL, "Could not intern X atom for _MOTIF_WM_HINTS." ); 432 /* return( false ); */ 433 } 434 else { 435 wmhints.flags = MWM_HINTS_DECORATIONS; 436 wmhints.decorations = 0; // Absolutely no decorations. 437 XChangeProperty(x_disp, x_win, aHints, aHints, 32, 438 PropModeReplace, (unsigned char *)&wmhints, 439 4 ); 440 441 sizehints.flags = USPosition | USSize; 442 sizehints.x = 0; 443 sizehints.y = 0; 444 sizehints.width = vid.width; 445 sizehints.height = vid.height; 446 XSetWMNormalHints( x_disp, x_win, &sizehints ); 447 448 changes.x = 0; 449 changes.y = 0; 450 changes.width = vid.width; 451 changes.height = vid.height; 452 changes.stack_mode = TopIf; 453 XConfigureWindow(x_disp, x_win, 454 CWX | CWY | CWWidth | CWHeight | CWStackMode, 455 &changes); 456 } 457 } 458 459 // map the window 460 XMapWindow(x_disp, x_win); 461 462 // wait for first exposure event 463 { 464 XEvent event; 465 do 466 { 467 XNextEvent(x_disp, &event); 468 if (event.type == Expose && !event.xexpose.count) 469 oktodraw = true; 470 } while (!oktodraw); 471 } 472 // now safe to draw 473 474 gl_cx = glXCreateContext( x_disp, x_visinfo, 0, True ); 475 if (!glXMakeCurrent( x_disp, x_win, gl_cx )) 476 Sys_Error( "Can't make window current to context\n" ); 477 478 // even if MITSHM is available, make sure it's a local connection 479 #if 0 480 // This is messing up the DISPLAY environment variable so can't close and 481 // reopen the window (it lops off the :0.0)... 482 if (XShmQueryExtension(x_disp)) 483 { 484 char *displayname; 485 doShm = true; 486 displayname = (char *) getenv("DISPLAY"); 487 if (displayname) 488 { 489 char *d = displayname; 490 while (*d && (*d != ':')) d++; 491 if (*d) *d = 0; 492 if (!(!strcasecmp(displayname, "unix") || !*displayname)) 493 doShm = false; 494 } 495 } 496 #endif 497 498 #if 0 499 if (doShm) 500 { 501 x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion; 502 ResetSharedFrameBuffers(); 503 } 504 else 505 ResetFrameBuffer(); 506 #endif 507 508 current_framebuffer = 0; 509 /* vid.rowbytes = x_framebuffer[0]->bytes_per_line; */ 510 /* vid.buffer = x_framebuffer[0]->data; */ 511 512 // XSynchronize(x_disp, False); 513 514 X11_active = true; 515 516 return true; 517 } 518 519 /*****************************************************************************/ 520 521 int XLateKey(XKeyEvent *ev) 522 { 523 524 int key; 525 char buf[64]; 526 KeySym keysym; 527 528 key = 0; 529 530 XLookupString(ev, buf, sizeof buf, &keysym, 0); 531 532 switch(keysym) 533 { 534 case XK_KP_Page_Up: key = K_KP_PGUP; break; 535 case XK_Page_Up: key = K_PGUP; break; 536 537 case XK_KP_Page_Down: key = K_KP_PGDN; break; 538 case XK_Page_Down: key = K_PGDN; break; 539 540 case XK_KP_Home: key = K_KP_HOME; break; 541 case XK_Home: key = K_HOME; break; 542 543 case XK_KP_End: key = K_KP_END; break; 544 case XK_End: key = K_END; break; 545 546 case XK_KP_Left: key = K_KP_LEFTARROW; break; 547 case XK_Left: key = K_LEFTARROW; break; 548 549 case XK_KP_Right: key = K_KP_RIGHTARROW; break; 550 case XK_Right: key = K_RIGHTARROW; break; 551 552 case XK_KP_Down: key = K_KP_DOWNARROW; break; 553 case XK_Down: key = K_DOWNARROW; break; 554 555 case XK_KP_Up: key = K_KP_UPARROW; break; 556 case XK_Up: key = K_UPARROW; break; 557 558 case XK_Escape: key = K_ESCAPE; break; 559 560 case XK_KP_Enter: key = K_KP_ENTER; break; 561 case XK_Return: key = K_ENTER; break; 562 563 case XK_Tab: key = K_TAB; break; 564 565 case XK_F1: key = K_F1; break; 566 567 case XK_F2: key = K_F2; break; 568 569 case XK_F3: key = K_F3; break; 570 571 case XK_F4: key = K_F4; break; 572 573 case XK_F5: key = K_F5; break; 574 575 case XK_F6: key = K_F6; break; 576 577 case XK_F7: key = K_F7; break; 578 579 case XK_F8: key = K_F8; break; 580 581 case XK_F9: key = K_F9; break; 582 583 case XK_F10: key = K_F10; break; 584 585 case XK_F11: key = K_F11; break; 586 587 case XK_F12: key = K_F12; break; 588 589 case XK_BackSpace: key = K_BACKSPACE; break; 590 591 case XK_KP_Delete: key = K_KP_DEL; break; 592 case XK_Delete: key = K_DEL; break; 593 594 case XK_Pause: key = K_PAUSE; break; 595 596 case XK_Shift_L: 597 case XK_Shift_R: key = K_SHIFT; break; 598 599 case XK_Execute: 600 case XK_Control_L: 601 case XK_Control_R: key = K_CTRL; break; 602 603 case XK_Alt_L: 604 case XK_Meta_L: 605 case XK_Alt_R: 606 case XK_Meta_R: key = K_ALT; break; 607 608 case XK_KP_Begin: key = K_KP_5; break; 609 610 case XK_Insert:key = K_INS; break; 611 case XK_KP_Insert: key = K_KP_INS; break; 612 613 case XK_KP_Multiply: key = '*'; break; 614 case XK_KP_Add: key = K_KP_PLUS; break; 615 case XK_KP_Subtract: key = K_KP_MINUS; break; 616 case XK_KP_Divide: key = K_KP_SLASH; break; 617 618 #if 0 619 case 0x021: key = '1';break;/* [!] */ 620 case 0x040: key = '2';break;/* [@] */ 621 case 0x023: key = '3';break;/* [#] */ 622 case 0x024: key = '4';break;/* [$] */ 623 case 0x025: key = '5';break;/* [%] */ 624 case 0x05e: key = '6';break;/* [^] */ 625 case 0x026: key = '7';break;/* [&] */ 626 case 0x02a: key = '8';break;/* [*] */ 627 case 0x028: key = '9';;break;/* [(] */ 628 case 0x029: key = '0';break;/* [)] */ 629 case 0x05f: key = '-';break;/* [_] */ 630 case 0x02b: key = '=';break;/* [+] */ 631 case 0x07c: key = '\'';break;/* [|] */ 632 case 0x07d: key = '[';break;/* [}] */ 633 case 0x07b: key = ']';break;/* [{] */ 634 case 0x022: key = '\'';break;/* ["] */ 635 case 0x03a: key = ';';break;/* [:] */ 636 case 0x03f: key = '/';break;/* [?] */ 637 case 0x03e: key = '.';break;/* [>] */ 638 case 0x03c: key = ',';break;/* [<] */ 639 #endif 640 641 default: 642 key = *(unsigned char*)buf; 643 if (key >= 'A' && key <= 'Z') 644 key = key - 'A' + 'a'; 645 break; 646 } 647 648 return key; 649 } 650 651 void GetEvent(void) 652 { 653 XEvent x_event; 654 int b; 655 656 XNextEvent(x_disp, &x_event); 657 switch(x_event.type) { 658 case KeyPress: 659 keyq[keyq_head].key = XLateKey(&x_event.xkey); 660 keyq[keyq_head].down = true; 661 keyq_head = (keyq_head + 1) & 63; 662 break; 663 case KeyRelease: 664 keyq[keyq_head].key = XLateKey(&x_event.xkey); 665 keyq[keyq_head].down = false; 666 keyq_head = (keyq_head + 1) & 63; 667 break; 668 669 case MotionNotify: 670 if (_windowed_mouse->value) { 671 mx += ((int)x_event.xmotion.x - (int)(vid.width/2)); 672 my += ((int)x_event.xmotion.y - (int)(vid.height/2)); 673 674 /* move the mouse to the window center again */ 675 XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask); 676 XWarpPointer(x_disp,None,x_win,0,0,0,0, 677 (vid.width/2),(vid.height/2)); 678 XSelectInput(x_disp,x_win, STD_EVENT_MASK); 679 } else { 680 mx = ((int)x_event.xmotion.x - (int)p_mouse_x); 681 my = ((int)x_event.xmotion.y - (int)p_mouse_y); 682 p_mouse_x=x_event.xmotion.x; 683 p_mouse_y=x_event.xmotion.y; 684 } 685 break; 686 687 case ButtonPress: 688 b=-1; 689 if (x_event.xbutton.button == 1) 690 b = 0; 691 else if (x_event.xbutton.button == 2) 692 b = 2; 693 else if (x_event.xbutton.button == 3) 694 b = 1; 695 if (b>=0) 696 mouse_buttonstate |= 1<<b; 697 break; 698 699 case ButtonRelease: 700 b=-1; 701 if (x_event.xbutton.button == 1) 702 b = 0; 703 else if (x_event.xbutton.button == 2) 704 b = 2; 705 else if (x_event.xbutton.button == 3) 706 b = 1; 707 if (b>=0) 708 mouse_buttonstate &= ~(1<<b); 709 break; 710 711 case ConfigureNotify: 712 config_notify_width = x_event.xconfigure.width; 713 config_notify_height = x_event.xconfigure.height; 714 config_notify = 1; 715 break; 716 717 default: 718 if (doShm && x_event.type == x_shmeventtype) 719 oktodraw = true; 720 } 721 722 if (old_windowed_mouse != _windowed_mouse->value) { 723 old_windowed_mouse = _windowed_mouse->value; 724 725 if (!_windowed_mouse->value) { 726 /* ungrab the pointer */ 727 XUngrabPointer(x_disp,CurrentTime); 728 } else { 729 /* grab the pointer */ 730 XGrabPointer(x_disp,x_win,True,0,GrabModeAsync, 731 GrabModeAsync,x_win,None,CurrentTime); 732 } 733 } 734 } 735 736 /*****************************************************************************/ 737 738 /*****************************************************************************/ 739 /* KEYBOARD */ 740 /*****************************************************************************/ 741 742 Key_Event_fp_t Key_Event_fp; 743 744 void KBD_Init(Key_Event_fp_t fp) 745 { 746 _windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE); 747 Key_Event_fp = fp; 748 } 749 750 void KBD_Update(void) 751 { 752 // get events from x server 753 if (x_disp) 754 { 755 while (XPending(x_disp)) 756 GetEvent(); 757 while (keyq_head != keyq_tail) 758 { 759 Key_Event_fp(keyq[keyq_tail].key, keyq[keyq_tail].down); 760 keyq_tail = (keyq_tail + 1) & 63; 761 } 762 } 763 } 764 765 void KBD_Close(void) 766 { 767 } 768 769 770 static void Force_CenterView_f (void) 771 { 772 in_state->viewangles[PITCH] = 0; 773 } 774 775 static void RW_IN_MLookDown (void) 776 { 777 mlooking = true; 778 } 779 780 static void RW_IN_MLookUp (void) 781 { 782 mlooking = false; 783 in_state->IN_CenterView_fp (); 784 } 785 786 void RW_IN_Init(in_state_t *in_state_p) 787 { 788 int mtype; 789 int i; 790 791 fprintf(stderr, "GL RW_IN_Init\n"); 792 793 in_state = in_state_p; 794 795 // mouse variables 796 _windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE); 797 m_filter = ri.Cvar_Get ("m_filter", "0", 0); 798 in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE); 799 freelook = ri.Cvar_Get( "freelook", "0", 0 ); 800 lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0); 801 sensitivity = ri.Cvar_Get ("sensitivity", "3", 0); 802 m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0); 803 m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0); 804 m_forward = ri.Cvar_Get ("m_forward", "1", 0); 805 m_side = ri.Cvar_Get ("m_side", "0.8", 0); 806 807 ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown); 808 ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp); 809 810 ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f); 811 812 mouse_x = mouse_y = 0.0; 813 mouse_avail = true; 814 } 815 816 void RW_IN_Shutdown(void) 817 { 818 mouse_avail = false; 819 820 ri.Cmd_RemoveCommand ("force_centerview"); 821 ri.Cmd_RemoveCommand ("+mlook"); 822 ri.Cmd_RemoveCommand ("-mlook"); 823 } 824 825 /* 826 =========== 827 IN_Commands 828 =========== 829 */ 830 void RW_IN_Commands (void) 831 { 832 int i; 833 834 if (!mouse_avail) 835 return; 836 837 for (i=0 ; i<3 ; i++) { 838 if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) ) 839 in_state->Key_Event_fp (K_MOUSE1 + i, true); 840 841 if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) ) 842 in_state->Key_Event_fp (K_MOUSE1 + i, false); 843 } 844 mouse_oldbuttonstate = mouse_buttonstate; 845 } 846 847 /* 848 =========== 849 IN_Move 850 =========== 851 */ 852 void RW_IN_Move (usercmd_t *cmd) 853 { 854 if (!mouse_avail) 855 return; 856 857 if (m_filter->value) 858 { 859 mouse_x = (mx + old_mouse_x) * 0.5; 860 mouse_y = (my + old_mouse_y) * 0.5; 861 } else { 862 mouse_x = mx; 863 mouse_y = my; 864 } 865 866 old_mouse_x = mx; 867 old_mouse_y = my; 868 869 if (!mouse_x && !mouse_y) 870 return; 871 872 mouse_x *= sensitivity->value; 873 mouse_y *= sensitivity->value; 874 875 // add mouse X/Y movement to cmd 876 if ( (*in_state->in_strafe_state & 1) || 877 (lookstrafe->value && mlooking )) 878 cmd->sidemove += m_side->value * mouse_x; 879 else 880 in_state->viewangles[YAW] -= m_yaw->value * mouse_x; 881 882 if ( (mlooking || freelook->value) && 883 !(*in_state->in_strafe_state & 1)) 884 { 885 in_state->viewangles[PITCH] += m_pitch->value * mouse_y; 886 } 887 else 888 { 889 cmd->forwardmove -= m_forward->value * mouse_y; 890 } 891 mx = my = 0; 892 } 893 894 void RW_IN_Frame (void) 895 { 896 } 897 898 void RW_IN_Activate(void) 899 { 900 } 901 902 903 //=============================================================================== 904 905 /* 906 ================ 907 Sys_MakeCodeWriteable 908 ================ 909 */ 910 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) 911 { 912 913 int r; 914 unsigned long addr; 915 int psize = getpagesize(); 916 917 addr = (startaddr & ~(psize-1)) - psize; 918 919 // fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr, 920 // addr, startaddr+length, length); 921 922 r = mprotect((char*)addr, length + startaddr - addr + psize, 7); 923 924 if (r < 0) 925 Sys_Error("Protection change failed\n"); 926 927 }