12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388 |
- /*
- ** GLW_IMP.C
- **
- ** This file contains ALL Linux specific stuff having to do with the
- ** OpenGL refresh. When a port is being made the following functions
- ** must be implemented by the port:
- **
- ** GLimp_EndFrame
- ** GLimp_Init
- ** GLimp_Shutdown
- ** GLimp_SwitchFullscreen
- **
- */
- #include <termios.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #include <sys/vt.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <signal.h>
- #include <pthread.h>
- #include <semaphore.h>
- //#include "../qcommon/qcommon.h"
- //#include "../client/keys.h"
- #include "../renderer/tr_local.h"
- #include "../client/client.h"
- #include "unix_glw.h"
- #include <GL/glx.h>
- #include <X11/keysym.h>
- #include <X11/cursorfont.h>
- #include <X11/extensions/xf86dga.h>
- #include <X11/extensions/xf86vmode.h>
- typedef enum {
- RSERR_OK,
- RSERR_INVALID_FULLSCREEN,
- RSERR_INVALID_MODE,
- RSERR_UNKNOWN
- } rserr_t;
- glwstate_t glw_state;
- static Display *dpy = NULL;
- static int scrnum;
- static Window win = 0;
- static GLXContext ctx = NULL;
- static qboolean autorepeaton = qtrue;
- #define KEY_MASK (KeyPressMask | KeyReleaseMask)
- #define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
- PointerMotionMask | ButtonMotionMask )
- #define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
- static qboolean mouse_avail;
- static qboolean mouse_active;
- static int mx, my;
- static cvar_t *in_mouse;
- static cvar_t *in_dgamouse;
- static cvar_t *r_fakeFullscreen;
- qboolean dgamouse = qfalse;
- qboolean vidmode_ext = qfalse;
- static int win_x, win_y;
- static XF86VidModeModeInfo **vidmodes;
- static int default_dotclock_vidmode;
- static int num_vidmodes;
- static qboolean vidmode_active = qfalse;
- static int mouse_accel_numerator;
- static int mouse_accel_denominator;
- static int mouse_threshold;
- /*****************************************************************************/
- /* KEYBOARD */
- /*****************************************************************************/
- static unsigned int keyshift[256]; // key to map to if shift held down in console
- static qboolean shift_down=qfalse;
- static char *XLateKey(XKeyEvent *ev, int *key)
- {
- static char buf[64];
- KeySym keysym;
- static qboolean setup = qfalse;
- int i;
- *key = 0;
- XLookupString(ev, buf, sizeof buf, &keysym, 0);
- // ri.Printf( PRINT_ALL, "keysym=%04X\n", (int)keysym);
- switch(keysym)
- {
- case XK_KP_Page_Up:
- case XK_KP_9: *key = K_KP_PGUP; break;
- case XK_Page_Up: *key = K_PGUP; break;
- case XK_KP_Page_Down:
- case XK_KP_3: *key = K_KP_PGDN; break;
- case XK_Page_Down: *key = K_PGDN; break;
- case XK_KP_Home: *key = K_KP_HOME; break;
- case XK_KP_7: *key = K_KP_HOME; break;
- case XK_Home: *key = K_HOME; break;
- case XK_KP_End:
- case XK_KP_1: *key = K_KP_END; break;
- case XK_End: *key = K_END; break;
- case XK_KP_Left: *key = K_KP_LEFTARROW; break;
- case XK_KP_4: *key = K_KP_LEFTARROW; break;
- case XK_Left: *key = K_LEFTARROW; break;
- case XK_KP_Right: *key = K_KP_RIGHTARROW; break;
- case XK_KP_6: *key = K_KP_RIGHTARROW; break;
- case XK_Right: *key = K_RIGHTARROW; break;
- case XK_KP_Down:
- case XK_KP_2: *key = K_KP_DOWNARROW; break;
- case XK_Down: *key = K_DOWNARROW; break;
- case XK_KP_Up:
- case XK_KP_8: *key = K_KP_UPARROW; break;
- case XK_Up: *key = K_UPARROW; break;
- case XK_Escape: *key = K_ESCAPE; break;
- case XK_KP_Enter: *key = K_KP_ENTER; break;
- case XK_Return: *key = K_ENTER; break;
- case XK_Tab: *key = K_TAB; break;
- case XK_F1: *key = K_F1; break;
- case XK_F2: *key = K_F2; break;
- case XK_F3: *key = K_F3; break;
- case XK_F4: *key = K_F4; break;
- case XK_F5: *key = K_F5; break;
- case XK_F6: *key = K_F6; break;
- case XK_F7: *key = K_F7; break;
- case XK_F8: *key = K_F8; break;
- case XK_F9: *key = K_F9; break;
- case XK_F10: *key = K_F10; break;
- case XK_F11: *key = K_F11; break;
- case XK_F12: *key = K_F12; break;
- // case XK_BackSpace: *key = K_BACKSPACE; break;
- case XK_BackSpace: *key = 8; break; // ctrl-h
- case XK_KP_Delete:
- case XK_KP_Decimal: *key = K_KP_DEL; break;
- case XK_Delete: *key = K_DEL; break;
- case XK_Pause: *key = K_PAUSE; break;
- case XK_Shift_L:
- case XK_Shift_R: *key = K_SHIFT; break;
- case XK_Execute:
- case XK_Control_L:
- case XK_Control_R: *key = K_CTRL; break;
- case XK_Alt_L:
- case XK_Meta_L:
- case XK_Alt_R:
- case XK_Meta_R: *key = K_ALT; break;
- case XK_KP_Begin: *key = K_KP_5; break;
- case XK_Insert: *key = K_INS; break;
- case XK_KP_Insert:
- case XK_KP_0: *key = K_KP_INS; break;
- case XK_KP_Multiply: *key = '*'; break;
- case XK_KP_Add: *key = K_KP_PLUS; break;
- case XK_KP_Subtract: *key = K_KP_MINUS; break;
- case XK_KP_Divide: *key = K_KP_SLASH; break;
- default:
- *key = *(unsigned char *)buf;
- if (*key >= 'A' && *key <= 'Z')
- *key = *key - 'A' + 'a';
- break;
- }
- return buf;
- }
- // ========================================================================
- // makes a null cursor
- // ========================================================================
- static Cursor CreateNullCursor(Display *display, Window root)
- {
- Pixmap cursormask;
- XGCValues xgc;
- GC gc;
- XColor dummycolour;
- Cursor cursor;
- cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
- xgc.function = GXclear;
- gc = XCreateGC(display, cursormask, GCFunction, &xgc);
- XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
- dummycolour.pixel = 0;
- dummycolour.red = 0;
- dummycolour.flags = 04;
- cursor = XCreatePixmapCursor(display, cursormask, cursormask,
- &dummycolour,&dummycolour, 0,0);
- XFreePixmap(display,cursormask);
- XFreeGC(display,gc);
- return cursor;
- }
- static void install_grabs(void)
- {
- // inviso cursor
- XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
- XGrabPointer(dpy, win,
- False,
- MOUSE_MASK,
- GrabModeAsync, GrabModeAsync,
- win,
- None,
- CurrentTime);
- XGetPointerControl(dpy, &mouse_accel_numerator, &mouse_accel_denominator,
- &mouse_threshold);
- XChangePointerControl(dpy, qtrue, qtrue, 2, 1, 0);
- if (in_dgamouse->value) {
- int MajorVersion, MinorVersion;
- if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
- // unable to query, probalby not supported
- ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
- ri.Cvar_Set( "in_dgamouse", "0" );
- } else {
- dgamouse = qtrue;
- XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
- XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
- }
- } else {
- XWarpPointer(dpy, None, win,
- 0, 0, 0, 0,
- glConfig.vidWidth / 2, glConfig.vidHeight / 2);
- }
- XGrabKeyboard(dpy, win,
- False,
- GrabModeAsync, GrabModeAsync,
- CurrentTime);
- // XSync(dpy, True);
- }
- static void uninstall_grabs(void)
- {
- if (dgamouse) {
- dgamouse = qfalse;
- XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
- }
- XChangePointerControl(dpy, qtrue, qtrue, mouse_accel_numerator,
- mouse_accel_denominator, mouse_threshold);
- XUngrabPointer(dpy, CurrentTime);
- XUngrabKeyboard(dpy, CurrentTime);
- // inviso cursor
- XUndefineCursor(dpy, win);
- // XAutoRepeatOn(dpy);
- // XSync(dpy, True);
- }
- static void HandleEvents(void)
- {
- int b;
- int key;
- XEvent event;
- qboolean dowarp = qfalse;
- int mwx = glConfig.vidWidth/2;
- int mwy = glConfig.vidHeight/2;
- char *p;
-
- if (!dpy)
- return;
- while (XPending(dpy)) {
- XNextEvent(dpy, &event);
- switch(event.type) {
- case KeyPress:
- p = XLateKey(&event.xkey, &key);
- if (key)
- Sys_QueEvent( 0, SE_KEY, key, qtrue, 0, NULL );
- while (*p)
- Sys_QueEvent( 0, SE_CHAR, *p++, 0, 0, NULL );
- break;
- case KeyRelease:
- XLateKey(&event.xkey, &key);
-
- Sys_QueEvent( 0, SE_KEY, key, qfalse, 0, NULL );
- break;
- #if 0
- case KeyPress:
- case KeyRelease:
- key = XLateKey(&event.xkey);
-
- Sys_QueEvent( 0, SE_KEY, key, event.type == KeyPress, 0, NULL );
- if (key == K_SHIFT)
- shift_down = (event.type == KeyPress);
- if (key < 128 && (event.type == KeyPress)) {
- if (shift_down)
- key = keyshift[key];
- Sys_QueEvent( 0, SE_CHAR, key, 0, 0, NULL );
- }
- #endif
- break;
- case MotionNotify:
- if (mouse_active) {
- if (dgamouse) {
- if (abs(event.xmotion.x_root) > 1)
- mx += event.xmotion.x_root * 2;
- else
- mx += event.xmotion.x_root;
- if (abs(event.xmotion.y_root) > 1)
- my += event.xmotion.y_root * 2;
- else
- my += event.xmotion.y_root;
- // ri.Printf(PRINT_ALL, "mouse (%d,%d) (root=%d,%d)\n", event.xmotion.x + win_x, event.xmotion.y + win_y, event.xmotion.x_root, event.xmotion.y_root);
- }
- else
- {
- // ri.Printf(PRINT_ALL, "mouse x=%d,y=%d\n", (int)event.xmotion.x - mwx, (int)event.xmotion.y - mwy);
- mx += ((int)event.xmotion.x - mwx);
- my += ((int)event.xmotion.y - mwy);
- mwx = event.xmotion.x;
- mwy = event.xmotion.y;
- if (mx || my)
- dowarp = qtrue;
- }
- }
- break;
- case ButtonPress:
- b=-1;
- if (event.xbutton.button == 1)
- b = 0;
- else if (event.xbutton.button == 2)
- b = 2;
- else if (event.xbutton.button == 3)
- b = 1;
- Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + b, qtrue, 0, NULL );
- break;
- case ButtonRelease:
- b=-1;
- if (event.xbutton.button == 1)
- b = 0;
- else if (event.xbutton.button == 2)
- b = 2;
- else if (event.xbutton.button == 3)
- b = 1;
- Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + b, qfalse, 0, NULL );
- break;
- case CreateNotify :
- win_x = event.xcreatewindow.x;
- win_y = event.xcreatewindow.y;
- break;
- case ConfigureNotify :
- win_x = event.xconfigure.x;
- win_y = event.xconfigure.y;
- break;
- }
- }
- if (dowarp) {
- /* move the mouse to the window center again */
- XWarpPointer(dpy,None,win,0,0,0,0,
- (glConfig.vidWidth/2),(glConfig.vidHeight/2));
- }
- }
- void KBD_Init(void)
- {
- }
- void KBD_Close(void)
- {
- }
- void IN_ActivateMouse( void )
- {
- if (!mouse_avail || !dpy || !win)
- return;
- if (!mouse_active) {
- mx = my = 0; // don't spazz
- install_grabs();
- mouse_active = qtrue;
- }
- }
- void IN_DeactivateMouse( void )
- {
- if (!mouse_avail || !dpy || !win)
- return;
- if (mouse_active) {
- uninstall_grabs();
- mouse_active = qfalse;
- }
- }
- /*****************************************************************************/
- static qboolean signalcaught = qfalse;;
- static void signal_handler(int sig)
- {
- if (signalcaught) {
- printf("DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n", sig);
- _exit(1);
- }
- signalcaught = qtrue;
- printf("Received signal %d, exiting...\n", sig);
- GLimp_Shutdown();
- _exit(1);
- }
- static void InitSig(void)
- {
- signal(SIGHUP, signal_handler);
- signal(SIGQUIT, signal_handler);
- signal(SIGILL, signal_handler);
- signal(SIGTRAP, signal_handler);
- signal(SIGIOT, signal_handler);
- signal(SIGBUS, signal_handler);
- signal(SIGFPE, signal_handler);
- signal(SIGSEGV, signal_handler);
- signal(SIGTERM, signal_handler);
- }
- /*
- ** GLimp_SetGamma
- **
- ** This routine should only be called if glConfig.deviceSupportsGamma is TRUE
- */
- void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] )
- {
- }
- /*
- ** GLimp_Shutdown
- **
- ** This routine does all OS specific shutdown procedures for the OpenGL
- ** subsystem. Under OpenGL this means NULLing out the current DC and
- ** HGLRC, deleting the rendering context, and releasing the DC acquired
- ** for the window. The state structure is also nulled out.
- **
- */
- void GLimp_Shutdown( void )
- {
- if (!ctx || !dpy)
- return;
- IN_DeactivateMouse();
- XAutoRepeatOn(dpy);
- if (dpy) {
- if (ctx)
- qglXDestroyContext(dpy, ctx);
- if (win)
- XDestroyWindow(dpy, win);
- if (vidmode_active)
- XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
- XCloseDisplay(dpy);
- }
- vidmode_active = qfalse;
- dpy = NULL;
- win = 0;
- ctx = NULL;
- memset( &glConfig, 0, sizeof( glConfig ) );
- memset( &glState, 0, sizeof( glState ) );
- QGL_Shutdown();
- }
- /*
- ** GLimp_LogComment
- */
- void GLimp_LogComment( char *comment )
- {
- if ( glw_state.log_fp ) {
- fprintf( glw_state.log_fp, "%s", comment );
- }
- }
- /*
- ** GLW_StartDriverAndSetMode
- */
- static qboolean GLW_StartDriverAndSetMode( const char *drivername,
- int mode,
- qboolean fullscreen )
- {
- rserr_t err;
- // don't ever bother going into fullscreen with a voodoo card
- #if 1 // JDC: I reenabled this
- if ( strstr( drivername, "Voodoo" ) ) {
- ri.Cvar_Set( "r_fullscreen", "0" );
- r_fullscreen->modified = qfalse;
- fullscreen = qfalse;
- }
- #endif
- err = GLW_SetMode( drivername, mode, fullscreen );
- switch ( err )
- {
- case RSERR_INVALID_FULLSCREEN:
- ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
- return qfalse;
- case RSERR_INVALID_MODE:
- ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode );
- return qfalse;
- default:
- break;
- }
- return qtrue;
- }
- /*
- ** GLW_SetMode
- */
- int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
- {
- int attrib[] = {
- GLX_RGBA, // 0
- GLX_RED_SIZE, 4, // 1, 2
- GLX_GREEN_SIZE, 4, // 3, 4
- GLX_BLUE_SIZE, 4, // 5, 6
- GLX_DOUBLEBUFFER, // 7
- GLX_DEPTH_SIZE, 1, // 8, 9
- GLX_STENCIL_SIZE, 1, // 10, 11
- None
- };
- // these match in the array
- #define ATTR_RED_IDX 2
- #define ATTR_GREEN_IDX 4
- #define ATTR_BLUE_IDX 6
- #define ATTR_DEPTH_IDX 9
- #define ATTR_STENCIL_IDX 11
- Window root;
- XVisualInfo *visinfo;
- XSetWindowAttributes attr;
- unsigned long mask;
- int colorbits, depthbits, stencilbits;
- int tcolorbits, tdepthbits, tstencilbits;
- int MajorVersion, MinorVersion;
- int actualWidth, actualHeight;
- int i;
- r_fakeFullscreen = ri.Cvar_Get( "r_fakeFullscreen", "0", CVAR_ARCHIVE);
- ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
- ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
- if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
- {
- ri.Printf( PRINT_ALL, " invalid mode\n" );
- return RSERR_INVALID_MODE;
- }
- ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
- if (!(dpy = XOpenDisplay(NULL))) {
- fprintf(stderr, "Error couldn't open the X display\n");
- return RSERR_INVALID_MODE;
- }
- scrnum = DefaultScreen(dpy);
- root = RootWindow(dpy, scrnum);
- actualWidth = glConfig.vidWidth;
- actualHeight = glConfig.vidHeight;
- // Get video mode list
- MajorVersion = MinorVersion = 0;
- if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
- vidmode_ext = qfalse;
- } else {
- ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
- MajorVersion, MinorVersion);
- vidmode_ext = qtrue;
- }
- if (vidmode_ext) {
- int best_fit, best_dist, dist, x, y;
-
- XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
- // Are we going fullscreen? If so, let's change video mode
- if (fullscreen && !r_fakeFullscreen->integer) {
- best_dist = 9999999;
- best_fit = -1;
- for (i = 0; i < num_vidmodes; i++) {
- if (glConfig.vidWidth > vidmodes[i]->hdisplay ||
- glConfig.vidHeight > vidmodes[i]->vdisplay)
- continue;
- x = glConfig.vidWidth - vidmodes[i]->hdisplay;
- y = glConfig.vidHeight - vidmodes[i]->vdisplay;
- dist = (x * x) + (y * y);
- if (dist < best_dist) {
- best_dist = dist;
- best_fit = i;
- }
- }
- if (best_fit != -1) {
- actualWidth = vidmodes[best_fit]->hdisplay;
- actualHeight = vidmodes[best_fit]->vdisplay;
- // change to the mode
- XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
- vidmode_active = qtrue;
- // Move the viewport to top left
- XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
- } else
- fullscreen = 0;
- }
- }
- if (!r_colorbits->value)
- colorbits = 24;
- else
- colorbits = r_colorbits->value;
- if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
- colorbits = 16;
- if (!r_depthbits->value)
- depthbits = 24;
- else
- depthbits = r_depthbits->value;
- stencilbits = r_stencilbits->value;
- for (i = 0; i < 16; i++) {
- // 0 - default
- // 1 - minus colorbits
- // 2 - minus depthbits
- // 3 - minus stencil
- if ((i % 4) == 0 && i) {
- // one pass, reduce
- switch (i / 4) {
- case 2 :
- if (colorbits == 24)
- colorbits = 16;
- break;
- case 1 :
- if (depthbits == 24)
- depthbits = 16;
- else if (depthbits == 16)
- depthbits = 8;
- case 3 :
- if (stencilbits == 24)
- stencilbits = 16;
- else if (stencilbits == 16)
- stencilbits = 8;
- }
- }
- tcolorbits = colorbits;
- tdepthbits = depthbits;
- tstencilbits = stencilbits;
- if ((i % 4) == 3) { // reduce colorbits
- if (tcolorbits == 24)
- tcolorbits = 16;
- }
- if ((i % 4) == 2) { // reduce depthbits
- if (tdepthbits == 24)
- tdepthbits = 16;
- else if (tdepthbits == 16)
- tdepthbits = 8;
- }
- if ((i % 4) == 1) { // reduce stencilbits
- if (tstencilbits == 24)
- tstencilbits = 16;
- else if (tstencilbits == 16)
- tstencilbits = 8;
- else
- tstencilbits = 0;
- }
- if (tcolorbits == 24) {
- attrib[ATTR_RED_IDX] = 8;
- attrib[ATTR_GREEN_IDX] = 8;
- attrib[ATTR_BLUE_IDX] = 8;
- } else {
- // must be 16 bit
- attrib[ATTR_RED_IDX] = 4;
- attrib[ATTR_GREEN_IDX] = 4;
- attrib[ATTR_BLUE_IDX] = 4;
- }
- attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth
- attrib[ATTR_STENCIL_IDX] = tstencilbits;
- #if 0
- ri.Printf( PRINT_DEVELOPER, "Attempting %d/%d/%d Color bits, %d depth, %d stencil display...",
- attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX],
- attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]);
- #endif
- visinfo = qglXChooseVisual(dpy, scrnum, attrib);
- if (!visinfo) {
- #if 0
- ri.Printf( PRINT_DEVELOPER, "failed\n");
- #endif
- continue;
- }
- #if 0
- ri.Printf( PRINT_DEVELOPER, "Successful\n");
- #endif
- ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n",
- attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX],
- attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]);
- glConfig.colorBits = tcolorbits;
- glConfig.depthBits = tdepthbits;
- glConfig.stencilBits = tstencilbits;
- break;
- }
- if (!visinfo) {
- ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
- return RSERR_INVALID_MODE;
- }
- /* window attributes */
- attr.background_pixel = BlackPixel(dpy, scrnum);
- attr.border_pixel = 0;
- attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
- attr.event_mask = X_MASK;
- if (vidmode_active) {
- mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore |
- CWEventMask | CWOverrideRedirect;
- attr.override_redirect = True;
- attr.backing_store = NotUseful;
- attr.save_under = False;
- } else
- mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
- win = XCreateWindow(dpy, root, 0, 0,
- actualWidth, actualHeight,
- 0, visinfo->depth, InputOutput,
- visinfo->visual, mask, &attr);
- XMapWindow(dpy, win);
- if (vidmode_active)
- XMoveWindow(dpy, win, 0, 0);
- // Check for DGA
- if (in_dgamouse->value) {
- if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
- // unable to query, probalby not supported
- ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
- ri.Cvar_Set( "in_dgamouse", "0" );
- } else
- ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n",
- MajorVersion, MinorVersion);
- }
- XFlush(dpy);
- ctx = qglXCreateContext(dpy, visinfo, NULL, True);
- qglXMakeCurrent(dpy, win, ctx);
- return RSERR_OK;
- }
- /*
- ** GLW_InitExtensions
- */
- static void GLW_InitExtensions( void )
- {
- // Use modern texture compression extensions
- if ( strstr( glConfig.extensions_string, "ARB_texture_compression" ) && strstr( glConfig.extensions_string, "EXT_texture_compression_s3tc" ) )
- {
- if ( r_ext_compressed_textures->value )
- {
- glConfig.textureCompression = TC_S3TC_DXT;
- ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" );
- }
- else
- {
- glConfig.textureCompression = TC_NONE;
- ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_compression_s3tc\n" );
- }
- }
- // Or check for old ones
- else if ( strstr( glConfig.extensions_string, "GL_S3_s3tc" ) )
- {
- if ( r_ext_compressed_textures->value )
- {
- glConfig.textureCompression = TC_S3TC;
- ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
- }
- else
- {
- glConfig.textureCompression = TC_NONE;
- ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
- }
- }
- else
- {
- glConfig.textureCompression = TC_NONE;
- ri.Printf( PRINT_ALL, "...no texture compression found\n" );
- }
- #if 0
- // WGL_EXT_swap_control
- if ( strstr( glConfig.extensions_string, "WGL_EXT_swap_control" ) )
- {
- qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" );
- ri.Printf( PRINT_ALL, "...using WGL_EXT_swap_control\n" );
- }
- else
- {
- ri.Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" );
- }
- #endif
- // GL_ARB_multitexture
- qglMultiTexCoord2fARB = NULL;
- qglActiveTextureARB = NULL;
- qglClientActiveTextureARB = NULL;
- if ( strstr( glConfig.extensions_string, "GL_ARB_multitexture" ) )
- {
- if ( r_ext_multitexture->value )
- {
- qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) dlsym( glw_state.OpenGLLib, "glMultiTexCoord2fARB" );
- qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glActiveTextureARB" );
- qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glClientActiveTextureARB" );
- if ( qglActiveTextureARB )
- {
- ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
- }
- else
- {
- ri.Printf( PRINT_ALL, "...blind search for ARB_multitexture failed\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
- }
- // GL_EXT_texture_filter_anisotropic
- glConfig.textureFilterAnisotropicAvailable = qfalse;
- if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) )
- {
- glConfig.textureFilterAnisotropicAvailable = qtrue;
- ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic available\n" );
- if ( r_ext_texture_filter_anisotropic->integer )
- {
- ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n" );
- }
- else
- {
- ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" );
- }
- ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "1" );
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" );
- ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" );
- }
- // GL_EXT_compiled_vertex_array
- if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) )
- {
- if ( r_ext_compiled_vertex_array->value )
- {
- ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" );
- qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) dlsym( glw_state.OpenGLLib, "glLockArraysEXT" );
- qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) dlsym( glw_state.OpenGLLib, "glUnlockArraysEXT" );
- if (!qglLockArraysEXT || !qglUnlockArraysEXT) {
- ri.Error (ERR_FATAL, "bad getprocaddress");
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
- }
- }
- /*
- ** GLW_LoadOpenGL
- **
- ** GLimp_win.c internal function that that attempts to load and use
- ** a specific OpenGL DLL.
- */
- static qboolean GLW_LoadOpenGL( const char *name )
- {
- qboolean fullscreen;
- ri.Printf( PRINT_ALL, "...loading %s: ", name );
- // disable the 3Dfx splash screen and set gamma
- // we do this all the time, but it shouldn't hurt anything
- // on non-3Dfx stuff
- putenv("FX_GLIDE_NO_SPLASH=0");
- // Mesa VooDoo hacks
- putenv("MESA_GLX_FX=fullscreen\n");
- // load the QGL layer
- if ( QGL_Init( name ) )
- {
- fullscreen = r_fullscreen->integer;
- // create the window and set up the context
- if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) )
- {
- if (r_mode->integer != 3) {
- if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) ) {
- goto fail;
- }
- } else
- goto fail;
- }
- return qtrue;
- }
- else
- {
- ri.Printf( PRINT_ALL, "failed\n" );
- }
- fail:
- QGL_Shutdown();
- return qfalse;
- }
- /*
- ** GLimp_Init
- **
- ** This routine is responsible for initializing the OS specific portions
- ** of OpenGL.
- */
- void GLimp_Init( void )
- {
- qboolean attemptedlibGL = qfalse;
- qboolean attempted3Dfx = qfalse;
- qboolean success = qfalse;
- char buf[1024];
- cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
- cvar_t *cv;
- glConfig.deviceSupportsGamma = qfalse;
- InitSig();
- //
- // load and initialize the specific OpenGL driver
- //
- if ( !GLW_LoadOpenGL( r_glDriver->string ) )
- {
- if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) )
- {
- attemptedlibGL = qtrue;
- }
- else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
- {
- attempted3Dfx = qtrue;
- }
- if ( !attempted3Dfx && !success )
- {
- attempted3Dfx = qtrue;
- if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) )
- {
- ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME );
- r_glDriver->modified = qfalse;
- success = qtrue;
- }
- }
- // try ICD before trying 3Dfx standalone driver
- if ( !attemptedlibGL && !success )
- {
- attemptedlibGL = qtrue;
- if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) )
- {
- ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME );
- r_glDriver->modified = qfalse;
- success = qtrue;
- }
- }
-
- if (!success)
- ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
- }
- // get our config strings
- Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
- Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
- if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
- glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
- Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
- Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
- //
- // chipset specific configuration
- //
- strcpy( buf, glConfig.renderer_string );
- strlwr( buf );
- if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
- {
- ri.Cvar_Set( "r_picmip", "1" );
- ri.Cvar_Set( "r_twopartfog", "0" );
- ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
- //
- // voodoo issues
- //
- if ( strstr( buf, "voodoo" ) && !strstr( buf, "banshee" ) )
- {
- ri.Cvar_Set( "r_fakeFullscreen", "1");
- }
- //
- // Riva128 issues
- //
- if ( strstr( buf, "riva 128" ) )
- {
- ri.Cvar_Set( "r_twopartfog", "1" );
- }
- //
- // Rage Pro issues
- //
- if ( strstr( buf, "rage pro" ) )
- {
- ri.Cvar_Set( "r_mode", "2" );
- ri.Cvar_Set( "r_twopartfog", "1" );
- }
- //
- // Permedia2 issues
- //
- if ( strstr( buf, "permedia2" ) )
- {
- ri.Cvar_Set( "r_vertexLight", "1" );
- }
- //
- // Riva TNT issues
- //
- if ( strstr( buf, "riva tnt " ) )
- {
- if ( r_texturebits->integer == 32 ||
- ( ( r_texturebits->integer == 0 ) && glConfig.colorBits > 16 ) )
- {
- ri.Cvar_Set( "r_picmip", "1" );
- }
- }
- ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
- }
- // initialize extensions
- GLW_InitExtensions();
- InitSig();
- return;
- }
- /*
- ** GLimp_EndFrame
- **
- ** Responsible for doing a swapbuffers and possibly for other stuff
- ** as yet to be determined. Probably better not to make this a GLimp
- ** function and instead do a call to GLimp_SwapBuffers.
- */
- void GLimp_EndFrame (void)
- {
- #if 0
- int err;
- if ( !glState.finishCalled )
- qglFinish();
- // check for errors
- if ( !gl_ignore_errors->value ) {
- if ( ( err = qglGetError() ) != GL_NO_ERROR )
- {
- ri.Error( ERR_FATAL, "GLimp_EndFrame() - glGetError() failed (0x%x)!\n", err );
- }
- }
- #endif
- // don't flip if drawing to front buffer
- if ( stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
- {
- qglXSwapBuffers(dpy, win);
- }
- // check logging
- QGL_EnableLogging( r_logFile->value );
- #if 0
- GLimp_LogComment( "*** RE_EndFrame ***\n" );
- // decrement log
- if ( gl_log->value )
- {
- ri.Cvar_Set( "gl_log", va("%i",gl_log->value - 1 ) );
- }
- #endif
- }
- /*
- ===========================================================
- SMP acceleration
- ===========================================================
- */
- sem_t renderCommandsEvent;
- sem_t renderCompletedEvent;
- sem_t renderActiveEvent;
- void (*glimpRenderThread)( void );
- void GLimp_RenderThreadWrapper( void *stub ) {
- glimpRenderThread();
- #if 0
- // unbind the context before we die
- qglXMakeCurrent(dpy, None, NULL);
- #endif
- }
- /*
- =======================
- GLimp_SpawnRenderThread
- =======================
- */
- pthread_t renderThreadHandle;
- qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) {
- sem_init( &renderCommandsEvent, 0, 0 );
- sem_init( &renderCompletedEvent, 0, 0 );
- sem_init( &renderActiveEvent, 0, 0 );
- glimpRenderThread = function;
- if (pthread_create( &renderThreadHandle, NULL,
- GLimp_RenderThreadWrapper, NULL)) {
- return qfalse;
- }
- return qtrue;
- }
- static void *smpData;
- static int glXErrors;
- void *GLimp_RendererSleep( void ) {
- void *data;
- #if 0
- if ( !qglXMakeCurrent(dpy, None, NULL) ) {
- glXErrors++;
- }
- #endif
- // ResetEvent( renderActiveEvent );
- // after this, the front end can exit GLimp_FrontEndSleep
- sem_post ( &renderCompletedEvent );
- sem_wait ( &renderCommandsEvent );
- #if 0
- if ( !qglXMakeCurrent(dpy, win, ctx) ) {
- glXErrors++;
- }
- #endif
- // ResetEvent( renderCompletedEvent );
- // ResetEvent( renderCommandsEvent );
- data = smpData;
- // after this, the main thread can exit GLimp_WakeRenderer
- sem_post ( &renderActiveEvent );
- return data;
- }
- void GLimp_FrontEndSleep( void ) {
- sem_wait ( &renderCompletedEvent );
- #if 0
- if ( !qglXMakeCurrent(dpy, win, ctx) ) {
- glXErrors++;
- }
- #endif
- }
- void GLimp_WakeRenderer( void *data ) {
- smpData = data;
- #if 0
- if ( !qglXMakeCurrent(dpy, None, NULL) ) {
- glXErrors++;
- }
- #endif
- // after this, the renderer can continue through GLimp_RendererSleep
- sem_post( &renderCommandsEvent );
- sem_wait( &renderActiveEvent );
- }
- /*===========================================================*/
- /*****************************************************************************/
- /* MOUSE */
- /*****************************************************************************/
- void IN_Init(void)
- {
- // mouse variables
- in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
- in_dgamouse = Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
- if (in_mouse->value)
- mouse_avail = qtrue;
- else
- mouse_avail = qfalse;
- }
- void IN_Shutdown(void)
- {
- mouse_avail = qfalse;
- }
- void IN_MouseMove(void)
- {
- if (!mouse_avail || !dpy || !win)
- return;
- #if 0
- if (!dgamouse) {
- Window root, child;
- int root_x, root_y;
- int win_x, win_y;
- unsigned int mask_return;
- int mwx = glConfig.vidWidth/2;
- int mwy = glConfig.vidHeight/2;
- XQueryPointer(dpy, win, &root, &child,
- &root_x, &root_y, &win_x, &win_y, &mask_return);
- mx = win_x - mwx;
- my = win_y - mwy;
- XWarpPointer(dpy,None,win,0,0,0,0, mwx, mwy);
- }
- #endif
- if (mx || my)
- Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL );
- mx = my = 0;
- }
- void IN_Frame (void)
- {
- if ( cls.keyCatchers || cls.state != CA_ACTIVE ) {
- // temporarily deactivate if not in the game and
- // running on the desktop
- // voodoo always counts as full screen
- if (Cvar_VariableValue ("r_fullscreen") == 0
- && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME ) ) {
- IN_DeactivateMouse ();
- return;
- }
- if (dpy && !autorepeaton) {
- XAutoRepeatOn(dpy);
- autorepeaton = qtrue;
- }
- } else if (dpy && autorepeaton) {
- XAutoRepeatOff(dpy);
- autorepeaton = qfalse;
- }
- IN_ActivateMouse();
- // post events to the system que
- IN_MouseMove();
- }
- void IN_Activate(void)
- {
- }
- void Sys_SendKeyEvents (void)
- {
- XEvent event;
- if (!dpy)
- return;
- HandleEvents();
- // while (XCheckMaskEvent(dpy,KEY_MASK|MOUSE_MASK,&event))
- // HandleEvent(&event);
- }
|