1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20#include <termios.h> 21#include <sys/ioctl.h> 22#include <sys/stat.h> 23#include <sys/vt.h> 24#include <stdarg.h> 25#include <stdio.h> 26#include <signal.h> 27 28#include <dlfcn.h> 29 30#include "quakedef.h" 31 32#include <GL/glx.h> 33 34#include <X11/keysym.h> 35#include <X11/cursorfont.h> 36 37#include <X11/extensions/xf86dga.h> 38#include <X11/extensions/xf86vmode.h> 39 40#define WARP_WIDTH 320 41#define WARP_HEIGHT 200 42 43static Display *dpy = NULL; 44static int scrnum; 45static Window win; 46static GLXContext ctx = NULL; 47 48#define KEY_MASK (KeyPressMask | KeyReleaseMask) 49#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \ 50 PointerMotionMask | ButtonMotionMask ) 51#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask ) 52 53 54unsigned short d_8to16table[256]; 55unsigned d_8to24table[256]; 56unsigned char d_15to8table[65536]; 57 58cvar_t vid_mode = {"vid_mode","0",false}; 59 60static qboolean mouse_avail; 61static qboolean mouse_active; 62static int mx, my; 63static int old_mouse_x, old_mouse_y; 64 65static cvar_t in_mouse = {"in_mouse", "1", false}; 66static cvar_t in_dgamouse = {"in_dgamouse", "1", false}; 67static cvar_t m_filter = {"m_filter", "0"}; 68 69qboolean dgamouse = false; 70qboolean vidmode_ext = false; 71 72static int win_x, win_y; 73 74static int scr_width, scr_height; 75 76static XF86VidModeModeInfo **vidmodes; 77static int default_dotclock_vidmode; 78static int num_vidmodes; 79static qboolean vidmode_active = false; 80 81/*-----------------------------------------------------------------------*/ 82 83//int texture_mode = GL_NEAREST; 84//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; 85//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; 86int texture_mode = GL_LINEAR; 87//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; 88//int texture_mode = GL_LINEAR_MIPMAP_LINEAR; 89 90int texture_extension_number = 1; 91 92float gldepthmin, gldepthmax; 93 94cvar_t gl_ztrick = {"gl_ztrick","1"}; 95 96const char *gl_vendor; 97const char *gl_renderer; 98const char *gl_version; 99const char *gl_extensions; 100 101void (*qglColorTableEXT) (int, int, int, int, int, const void*); 102void (*qgl3DfxSetPaletteEXT) (GLuint *); 103 104static float vid_gamma = 1.0; 105 106qboolean is8bit = false; 107qboolean isPermedia = false; 108qboolean gl_mtexable = false; 109 110/*-----------------------------------------------------------------------*/ 111void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) 112{ 113} 114 115void D_EndDirectRect (int x, int y, int width, int height) 116{ 117} 118 119static int XLateKey(XKeyEvent *ev) 120{ 121 122 int key; 123 char buf[64]; 124 KeySym keysym; 125 126 key = 0; 127 128 XLookupString(ev, buf, sizeof buf, &keysym, 0); 129 130 switch(keysym) 131 { 132 case XK_KP_Page_Up: 133 case XK_Page_Up: key = K_PGUP; break; 134 135 case XK_KP_Page_Down: 136 case XK_Page_Down: key = K_PGDN; break; 137 138 case XK_KP_Home: 139 case XK_Home: key = K_HOME; break; 140 141 case XK_KP_End: 142 case XK_End: key = K_END; break; 143 144 case XK_KP_Left: 145 case XK_Left: key = K_LEFTARROW; break; 146 147 case XK_KP_Right: 148 case XK_Right: key = K_RIGHTARROW; break; 149 150 case XK_KP_Down: 151 case XK_Down: key = K_DOWNARROW; break; 152 153 case XK_KP_Up: 154 case XK_Up: key = K_UPARROW; break; 155 156 case XK_Escape: key = K_ESCAPE; break; 157 158 case XK_KP_Enter: 159 case XK_Return: key = K_ENTER; break; 160 161 case XK_Tab: key = K_TAB; break; 162 163 case XK_F1: key = K_F1; break; 164 165 case XK_F2: key = K_F2; break; 166 167 case XK_F3: key = K_F3; break; 168 169 case XK_F4: key = K_F4; break; 170 171 case XK_F5: key = K_F5; break; 172 173 case XK_F6: key = K_F6; break; 174 175 case XK_F7: key = K_F7; break; 176 177 case XK_F8: key = K_F8; break; 178 179 case XK_F9: key = K_F9; break; 180 181 case XK_F10: key = K_F10; break; 182 183 case XK_F11: key = K_F11; break; 184 185 case XK_F12: key = K_F12; break; 186 187 case XK_BackSpace: key = K_BACKSPACE; break; 188 189 case XK_KP_Delete: 190 case XK_Delete: key = K_DEL; break; 191 192 case XK_Pause: key = K_PAUSE; break; 193 194 case XK_Shift_L: 195 case XK_Shift_R: key = K_SHIFT; break; 196 197 case XK_Execute: 198 case XK_Control_L: 199 case XK_Control_R: key = K_CTRL; break; 200 201 case XK_Alt_L: 202 case XK_Meta_L: 203 case XK_Alt_R: 204 case XK_Meta_R: key = K_ALT; break; 205 206 case XK_KP_Begin: key = '5'; break; 207 208 case XK_KP_Insert: 209 case XK_Insert:key = K_INS; break; 210 211 case XK_KP_Multiply: key = '*'; break; 212 case XK_KP_Add: key = '+'; break; 213 case XK_KP_Subtract: key = '-'; break; 214 case XK_KP_Divide: key = '/'; break; 215 216#if 0 217 case 0x021: key = '1';break;/* [!] */ 218 case 0x040: key = '2';break;/* [@] */ 219 case 0x023: key = '3';break;/* [#] */ 220 case 0x024: key = '4';break;/* [$] */ 221 case 0x025: key = '5';break;/* [%] */ 222 case 0x05e: key = '6';break;/* [^] */ 223 case 0x026: key = '7';break;/* [&] */ 224 case 0x02a: key = '8';break;/* [*] */ 225 case 0x028: key = '9';;break;/* [(] */ 226 case 0x029: key = '0';break;/* [)] */ 227 case 0x05f: key = '-';break;/* [_] */ 228 case 0x02b: key = '=';break;/* [+] */ 229 case 0x07c: key = '\'';break;/* [|] */ 230 case 0x07d: key = '[';break;/* [}] */ 231 case 0x07b: key = ']';break;/* [{] */ 232 case 0x022: key = '\'';break;/* ["] */ 233 case 0x03a: key = ';';break;/* [:] */ 234 case 0x03f: key = '/';break;/* [?] */ 235 case 0x03e: key = '.';break;/* [>] */ 236 case 0x03c: key = ',';break;/* [<] */ 237#endif 238 239 default: 240 key = *(unsigned char*)buf; 241 if (key >= 'A' && key <= 'Z') 242 key = key - 'A' + 'a'; 243 break; 244 } 245 246 return key; 247} 248 249static Cursor CreateNullCursor(Display *display, Window root) 250{ 251 Pixmap cursormask; 252 XGCValues xgc; 253 GC gc; 254 XColor dummycolour; 255 Cursor cursor; 256 257 cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/); 258 xgc.function = GXclear; 259 gc = XCreateGC(display, cursormask, GCFunction, &xgc); 260 XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); 261 dummycolour.pixel = 0; 262 dummycolour.red = 0; 263 dummycolour.flags = 04; 264 cursor = XCreatePixmapCursor(display, cursormask, cursormask, 265 &dummycolour,&dummycolour, 0,0); 266 XFreePixmap(display,cursormask); 267 XFreeGC(display,gc); 268 return cursor; 269} 270 271static void install_grabs(void) 272{ 273 274// inviso cursor 275 XDefineCursor(dpy, win, CreateNullCursor(dpy, win)); 276 277 XGrabPointer(dpy, win, 278 True, 279 0, 280 GrabModeAsync, GrabModeAsync, 281 win, 282 None, 283 CurrentTime); 284 285 if (in_dgamouse.value) { 286 int MajorVersion, MinorVersion; 287 288 if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) { 289 // unable to query, probalby not supported 290 Con_Printf( "Failed to detect XF86DGA Mouse\n" ); 291 in_dgamouse.value = 0; 292 } else { 293 dgamouse = true; 294 XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse); 295 XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0); 296 } 297 } else { 298 XWarpPointer(dpy, None, win, 299 0, 0, 0, 0, 300 vid.width / 2, vid.height / 2); 301 } 302 303 XGrabKeyboard(dpy, win, 304 False, 305 GrabModeAsync, GrabModeAsync, 306 CurrentTime); 307 308 mouse_active = true; 309 310// XSync(dpy, True); 311} 312 313static void uninstall_grabs(void) 314{ 315 if (!dpy || !win) 316 return; 317 318 if (dgamouse) { 319 dgamouse = false; 320 XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0); 321 } 322 323 XUngrabPointer(dpy, CurrentTime); 324 XUngrabKeyboard(dpy, CurrentTime); 325 326// inviso cursor 327 XUndefineCursor(dpy, win); 328 329 mouse_active = false; 330} 331 332static void HandleEvents(void) 333{ 334 XEvent event; 335 KeySym ks; 336 int b; 337 qboolean dowarp = false; 338 int mwx = vid.width/2; 339 int mwy = vid.height/2; 340 341 if (!dpy) 342 return; 343 344 while (XPending(dpy)) { 345 XNextEvent(dpy, &event); 346 347 switch (event.type) { 348 case KeyPress: 349 case KeyRelease: 350 Key_Event(XLateKey(&event.xkey), event.type == KeyPress); 351 break; 352 353 case MotionNotify: 354 if (mouse_active) { 355 if (dgamouse) { 356 mx += (event.xmotion.x + win_x) * 2; 357 my += (event.xmotion.y + win_y) * 2; 358 } 359 else 360 { 361 mx += ((int)event.xmotion.x - mwx) * 2; 362 my += ((int)event.xmotion.y - mwy) * 2; 363 mwx = event.xmotion.x; 364 mwy = event.xmotion.y; 365 366 if (mx || my) 367 dowarp = true; 368 } 369 } 370 break; 371 372 break; 373 374 case ButtonPress: 375 b=-1; 376 if (event.xbutton.button == 1) 377 b = 0; 378 else if (event.xbutton.button == 2) 379 b = 2; 380 else if (event.xbutton.button == 3) 381 b = 1; 382 if (b>=0) 383 Key_Event(K_MOUSE1 + b, true); 384 break; 385 386 case ButtonRelease: 387 b=-1; 388 if (event.xbutton.button == 1) 389 b = 0; 390 else if (event.xbutton.button == 2) 391 b = 2; 392 else if (event.xbutton.button == 3) 393 b = 1; 394 if (b>=0) 395 Key_Event(K_MOUSE1 + b, false); 396 break; 397 398 case CreateNotify : 399 win_x = event.xcreatewindow.x; 400 win_y = event.xcreatewindow.y; 401 break; 402 403 case ConfigureNotify : 404 win_x = event.xconfigure.x; 405 win_y = event.xconfigure.y; 406 break; 407 } 408 } 409 410 if (dowarp) { 411 /* move the mouse to the window center again */ 412 XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2); 413 } 414 415} 416 417static void IN_DeactivateMouse( void ) 418{ 419 if (!mouse_avail || !dpy || !win) 420 return; 421 422 if (mouse_active) { 423 uninstall_grabs(); 424 mouse_active = false; 425 } 426} 427 428static void IN_ActivateMouse( void ) 429{ 430 if (!mouse_avail || !dpy || !win) 431 return; 432 433 if (!mouse_active) { 434 mx = my = 0; // don't spazz 435 install_grabs(); 436 mouse_active = true; 437 } 438} 439 440 441void VID_Shutdown(void) 442{ 443 if (!ctx || !dpy) 444 return; 445 IN_DeactivateMouse(); 446 if (dpy) { 447 if (ctx) 448 glXDestroyContext(dpy, ctx); 449 if (win) 450 XDestroyWindow(dpy, win); 451 if (vidmode_active) 452 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]); 453 XCloseDisplay(dpy); 454 } 455 vidmode_active = false; 456 dpy = NULL; 457 win = 0; 458 ctx = NULL; 459} 460 461void signal_handler(int sig) 462{ 463 printf("Received signal %d, exiting...\n", sig); 464 Sys_Quit(); 465 exit(0); 466} 467 468void InitSig(void) 469{ 470 signal(SIGHUP, signal_handler); 471 signal(SIGINT, signal_handler); 472 signal(SIGQUIT, signal_handler); 473 signal(SIGILL, signal_handler); 474 signal(SIGTRAP, signal_handler); 475 signal(SIGIOT, signal_handler); 476 signal(SIGBUS, signal_handler); 477 signal(SIGFPE, signal_handler); 478 signal(SIGSEGV, signal_handler); 479 signal(SIGTERM, signal_handler); 480} 481 482void VID_ShiftPalette(unsigned char *p) 483{ 484// VID_SetPalette(p); 485} 486 487void VID_SetPalette (unsigned char *palette) 488{ 489 byte *pal; 490 unsigned r,g,b; 491 unsigned v; 492 int r1,g1,b1; 493 int j,k,l,m; 494 unsigned short i; 495 unsigned *table; 496 FILE *f; 497 char s[255]; 498 int dist, bestdist; 499 500// 501// 8 8 8 encoding 502// 503 pal = palette; 504 table = d_8to24table; 505 for (i=0 ; i<256 ; i++) 506 { 507 r = pal[0]; 508 g = pal[1]; 509 b = pal[2]; 510 pal += 3; 511 512 v = (255<<24) + (r<<0) + (g<<8) + (b<<16); 513 *table++ = v; 514 } 515 d_8to24table[255] &= 0xffffff; // 255 is transparent 516 517 for (i=0; i < (1<<15); i++) { 518 /* Maps 519 000000000000000 520 000000000011111 = Red = 0x1F 521 000001111100000 = Blue = 0x03E0 522 111110000000000 = Grn = 0x7C00 523 */ 524 r = ((i & 0x1F) << 3)+4; 525 g = ((i & 0x03E0) >> 2)+4; 526 b = ((i & 0x7C00) >> 7)+4; 527 pal = (unsigned char *)d_8to24table; 528 for (v=0,k=0,bestdist=10000*10000; v<256; v++,pal+=4) { 529 r1 = (int)r - (int)pal[0]; 530 g1 = (int)g - (int)pal[1]; 531 b1 = (int)b - (int)pal[2]; 532 dist = (r1*r1)+(g1*g1)+(b1*b1); 533 if (dist < bestdist) { 534 k=v; 535 bestdist = dist; 536 } 537 } 538 d_15to8table[i]=k; 539 } 540} 541 542void CheckMultiTextureExtensions(void) 543{ 544 void *prjobj; 545 546 if (strstr(gl_extensions, "GL_SGIS_multitexture ") && !COM_CheckParm("-nomtex")) { 547 Con_Printf("Found GL_SGIS_multitexture...\n"); 548 549 if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL) { 550 Con_Printf("Unable to open symbol list for main program.\n"); 551 return; 552 } 553 554 qglMTexCoord2fSGIS = (void *) dlsym(prjobj, "glMTexCoord2fSGIS"); 555 qglSelectTextureSGIS = (void *) dlsym(prjobj, "glSelectTextureSGIS"); 556 557 if (qglMTexCoord2fSGIS && qglSelectTextureSGIS) { 558 Con_Printf("Multitexture extensions found.\n"); 559 gl_mtexable = true; 560 } else 561 Con_Printf("Symbol not found, disabled.\n"); 562 563 dlclose(prjobj); 564 } 565} 566 567/* 568=============== 569GL_Init 570=============== 571*/ 572void GL_Init (void) 573{ 574 gl_vendor = glGetString (GL_VENDOR); 575 Con_Printf ("GL_VENDOR: %s\n", gl_vendor); 576 gl_renderer = glGetString (GL_RENDERER); 577 Con_Printf ("GL_RENDERER: %s\n", gl_renderer); 578 579 gl_version = glGetString (GL_VERSION); 580 Con_Printf ("GL_VERSION: %s\n", gl_version); 581 gl_extensions = glGetString (GL_EXTENSIONS); 582 Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions); 583 584// Con_Printf ("%s %s\n", gl_renderer, gl_version); 585 586 CheckMultiTextureExtensions (); 587 588 glClearColor (1,0,0,0); 589 glCullFace(GL_FRONT); 590 glEnable(GL_TEXTURE_2D); 591 592 glEnable(GL_ALPHA_TEST); 593 glAlphaFunc(GL_GREATER, 0.666); 594 595 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); 596 glShadeModel (GL_FLAT); 597 598 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 599 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 600 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 601 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 602 603 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 604 605// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 606 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 607} 608 609/* 610================= 611GL_BeginRendering 612 613================= 614*/ 615void GL_BeginRendering (int *x, int *y, int *width, int *height) 616{ 617 extern cvar_t gl_clear; 618 619 *x = *y = 0; 620 *width = scr_width; 621 *height = scr_height; 622 623// if (!wglMakeCurrent( maindc, baseRC )) 624// Sys_Error ("wglMakeCurrent failed"); 625 626// glViewport (*x, *y, *width, *height); 627} 628 629 630void GL_EndRendering (void) 631{ 632 glFlush(); 633 glXSwapBuffers(dpy, win); 634} 635 636qboolean VID_Is8bit(void) 637{ 638 return is8bit; 639} 640 641void VID_Init8bitPalette(void) 642{ 643 // Check for 8bit Extensions and initialize them. 644 int i; 645 void *prjobj; 646 647 if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL) { 648 Con_Printf("Unable to open symbol list for main program.\n"); 649 return; 650 } 651 652 if (strstr(gl_extensions, "3DFX_set_global_palette") && 653 (qgl3DfxSetPaletteEXT = dlsym(prjobj, "gl3DfxSetPaletteEXT")) != NULL) { 654 GLubyte table[256][4]; 655 char *oldpal; 656 657 Con_SafePrintf("8-bit GL extensions enabled.\n"); 658 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); 659 oldpal = (char *) d_8to24table; //d_8to24table3dfx; 660 for (i=0;i<256;i++) { 661 table[i][2] = *oldpal++; 662 table[i][1] = *oldpal++; 663 table[i][0] = *oldpal++; 664 table[i][3] = 255; 665 oldpal++; 666 } 667 qgl3DfxSetPaletteEXT((GLuint *)table); 668 is8bit = true; 669 670 } else if (strstr(gl_extensions, "GL_EXT_shared_texture_palette") && 671 (qglColorTableEXT = dlsym(prjobj, "glColorTableEXT")) != NULL) { 672 char thePalette[256*3]; 673 char *oldPalette, *newPalette; 674 675 Con_SafePrintf("8-bit GL extensions enabled.\n"); 676 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); 677 oldPalette = (char *) d_8to24table; //d_8to24table3dfx; 678 newPalette = thePalette; 679 for (i=0;i<256;i++) { 680 *newPalette++ = *oldPalette++; 681 *newPalette++ = *oldPalette++; 682 *newPalette++ = *oldPalette++; 683 oldPalette++; 684 } 685 qglColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette); 686 is8bit = true; 687 } 688 689 dlclose(prjobj); 690} 691 692static void Check_Gamma (unsigned char *pal) 693{ 694 float f, inf; 695 unsigned char palette[768]; 696 int i; 697 698 if ((i = COM_CheckParm("-gamma")) == 0) { 699 if ((gl_renderer && strstr(gl_renderer, "Voodoo")) || 700 (gl_vendor && strstr(gl_vendor, "3Dfx"))) 701 vid_gamma = 1; 702 else 703 vid_gamma = 0.7; // default to 0.7 on non-3dfx hardware 704 } else 705 vid_gamma = Q_atof(com_argv[i+1]); 706 707 for (i=0 ; i<768 ; i++) 708 { 709 f = pow ( (pal[i]+1)/256.0 , vid_gamma ); 710 inf = f*255 + 0.5; 711 if (inf < 0) 712 inf = 0; 713 if (inf > 255) 714 inf = 255; 715 palette[i] = inf; 716 } 717 718 memcpy (pal, palette, sizeof(palette)); 719} 720 721void VID_Init(unsigned char *palette) 722{ 723 int i; 724 int attrib[] = { 725 GLX_RGBA, 726 GLX_RED_SIZE, 1, 727 GLX_GREEN_SIZE, 1, 728 GLX_BLUE_SIZE, 1, 729 GLX_DOUBLEBUFFER, 730 GLX_DEPTH_SIZE, 1, 731 None 732 }; 733 char gldir[MAX_OSPATH]; 734 int width = 640, height = 480; 735 XSetWindowAttributes attr; 736 unsigned long mask; 737 Window root; 738 XVisualInfo *visinfo; 739 qboolean fullscreen = true; 740 int MajorVersion, MinorVersion; 741 int actualWidth, actualHeight; 742 743 Cvar_RegisterVariable (&vid_mode); 744 Cvar_RegisterVariable (&in_mouse); 745 Cvar_RegisterVariable (&in_dgamouse); 746 Cvar_RegisterVariable (&m_filter); 747 Cvar_RegisterVariable (&gl_ztrick); 748 749 vid.maxwarpwidth = WARP_WIDTH; 750 vid.maxwarpheight = WARP_HEIGHT; 751 vid.colormap = host_colormap; 752 vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); 753 754// interpret command-line params 755 756// set vid parameters 757 if ((i = COM_CheckParm("-window")) != 0) 758 fullscreen = false; 759 760 if ((i = COM_CheckParm("-width")) != 0) 761 width = atoi(com_argv[i+1]); 762 763 if ((i = COM_CheckParm("-height")) != 0) 764 height = atoi(com_argv[i+1]); 765 766 if ((i = COM_CheckParm("-conwidth")) != 0) 767 vid.conwidth = Q_atoi(com_argv[i+1]); 768 else 769 vid.conwidth = 640; 770 771 vid.conwidth &= 0xfff8; // make it a multiple of eight 772 773 if (vid.conwidth < 320) 774 vid.conwidth = 320; 775 776 // pick a conheight that matches with correct aspect 777 vid.conheight = vid.conwidth*3 / 4; 778 779 if ((i = COM_CheckParm("-conheight")) != 0) 780 vid.conheight = Q_atoi(com_argv[i+1]); 781 if (vid.conheight < 200) 782 vid.conheight = 200; 783 784 if (!(dpy = XOpenDisplay(NULL))) { 785 fprintf(stderr, "Error couldn't open the X display\n"); 786 exit(1); 787 } 788 789 scrnum = DefaultScreen(dpy); 790 root = RootWindow(dpy, scrnum); 791 792 // Get video mode list 793 MajorVersion = MinorVersion = 0; 794 if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) { 795 vidmode_ext = false; 796 } else { 797 Con_Printf("Using XFree86-VidModeExtension Version %d.%d\n", MajorVersion, MinorVersion); 798 vidmode_ext = true; 799 } 800 801 visinfo = glXChooseVisual(dpy, scrnum, attrib); 802 if (!visinfo) { 803 fprintf(stderr, "qkHack: Error couldn't get an RGB, Double-buffered, Depth visual\n"); 804 exit(1); 805 } 806 807 if (vidmode_ext) { 808 int best_fit, best_dist, dist, x, y; 809 810 XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes); 811 812 // Are we going fullscreen? If so, let's change video mode 813 if (fullscreen) { 814 best_dist = 9999999; 815 best_fit = -1; 816 817 for (i = 0; i < num_vidmodes; i++) { 818 if (width > vidmodes[i]->hdisplay || 819 height > vidmodes[i]->vdisplay) 820 continue; 821 822 x = width - vidmodes[i]->hdisplay; 823 y = height - vidmodes[i]->vdisplay; 824 dist = (x * x) + (y * y); 825 if (dist < best_dist) { 826 best_dist = dist; 827 best_fit = i; 828 } 829 } 830 831 if (best_fit != -1) { 832 actualWidth = vidmodes[best_fit]->hdisplay; 833 actualHeight = vidmodes[best_fit]->vdisplay; 834 835 // change to the mode 836 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]); 837 vidmode_active = true; 838 839 // Move the viewport to top left 840 XF86VidModeSetViewPort(dpy, scrnum, 0, 0); 841 } else 842 fullscreen = 0; 843 } 844 } 845 846 /* window attributes */ 847 attr.background_pixel = 0; 848 attr.border_pixel = 0; 849 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone); 850 attr.event_mask = X_MASK; 851 if (vidmode_active) { 852 mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | 853 CWEventMask | CWOverrideRedirect; 854 attr.override_redirect = True; 855 attr.backing_store = NotUseful; 856 attr.save_under = False; 857 } else 858 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; 859 860 win = XCreateWindow(dpy, root, 0, 0, width, height, 861 0, visinfo->depth, InputOutput, 862 visinfo->visual, mask, &attr); 863 XMapWindow(dpy, win); 864 865 if (vidmode_active) { 866 XMoveWindow(dpy, win, 0, 0); 867 XRaiseWindow(dpy, win); 868 XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0); 869 XFlush(dpy); 870 // Move the viewport to top left 871 XF86VidModeSetViewPort(dpy, scrnum, 0, 0); 872 } 873 874 XFlush(dpy); 875 876 ctx = glXCreateContext(dpy, visinfo, NULL, True); 877 878 glXMakeCurrent(dpy, win, ctx); 879 880 scr_width = width; 881 scr_height = height; 882 883 if (vid.conheight > height) 884 vid.conheight = height; 885 if (vid.conwidth > width) 886 vid.conwidth = width; 887 vid.width = vid.conwidth; 888 vid.height = vid.conheight; 889 890 vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0); 891 vid.numpages = 2; 892 893 InitSig(); // trap evil signals 894 895 GL_Init(); 896 897 sprintf (gldir, "%s/glquake", com_gamedir); 898 Sys_mkdir (gldir); 899 900 VID_SetPalette(palette); 901 902 // Check for 3DFX Extensions and initialize them. 903 VID_Init8bitPalette(); 904 905 Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height); 906 907 vid.recalc_refdef = 1; // force a surface cache flush 908} 909 910void Sys_SendKeyEvents(void) 911{ 912 HandleEvents(); 913} 914 915void Force_CenterView_f (void) 916{ 917 cl.viewangles[PITCH] = 0; 918} 919 920void IN_Init(void) 921{ 922} 923 924void IN_Shutdown(void) 925{ 926} 927 928/* 929=========== 930IN_Commands 931=========== 932*/ 933void IN_Commands (void) 934{ 935 if (!dpy || !win) 936 return; 937 938 if (vidmode_active || key_dest == key_game) 939 IN_ActivateMouse(); 940 else 941 IN_DeactivateMouse (); 942} 943 944/* 945=========== 946IN_Move 947=========== 948*/ 949void IN_MouseMove (usercmd_t *cmd) 950{ 951 if (!mouse_avail) 952 return; 953 954 if (m_filter.value) 955 { 956 mx = (mx + old_mouse_x) * 0.5; 957 my = (my + old_mouse_y) * 0.5; 958 } 959 old_mouse_x = mx; 960 old_mouse_y = my; 961 962 mx *= sensitivity.value; 963 my *= sensitivity.value; 964 965// add mouse X/Y movement to cmd 966 if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) )) 967 cmd->sidemove += m_side.value * mx; 968 else 969 cl.viewangles[YAW] -= m_yaw.value * mx; 970 971 if (in_mlook.state & 1) 972 V_StopPitchDrift (); 973 974 if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) 975 { 976 cl.viewangles[PITCH] += m_pitch.value * my; 977 if (cl.viewangles[PITCH] > 80) 978 cl.viewangles[PITCH] = 80; 979 if (cl.viewangles[PITCH] < -70) 980 cl.viewangles[PITCH] = -70; 981 } 982 else 983 { 984 if ((in_strafe.state & 1) && noclip_anglehack) 985 cmd->upmove -= m_forward.value * my; 986 else 987 cmd->forwardmove -= m_forward.value * my; 988 } 989 mx = my = 0; 990} 991 992void IN_Move (usercmd_t *cmd) 993{ 994 IN_MouseMove(cmd); 995} 996 997 998