rserr_t GLimp_SetMode( int mode, int colorbits, bool fullscreen ) { if ( !XInitThreads() ) { common->Printf( "...XInitThreads() failed, disabling r_smp\n" ); Cvar_Set( "r_smp", "0" ); } // set up our custom error handler for X failures XSetErrorHandler( &qXErrorHandler ); if ( fullscreen && in_nograb->value ) { common->Printf( "Fullscreen not allowed with in_nograb 1\n" ); Cvar_Set( "r_fullscreen", "0" ); r_fullscreen->modified = false; fullscreen = false; } common->Printf( "...setting mode %d:", mode ); if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) { common->Printf( " invalid mode\n" ); return RSERR_INVALID_MODE; } common->Printf( " %d %d\n", glConfig.vidWidth, glConfig.vidHeight ); // open the display if ( !( dpy = XOpenDisplay( NULL ) ) ) { fprintf( stderr, "Error couldn't open the X display\n" ); return RSERR_INVALID_MODE; } scrnum = DefaultScreen( dpy ); Window root = RootWindow( dpy, scrnum ); // Get video mode list if ( !XF86VidModeQueryVersion( dpy, &vidmode_MajorVersion, &vidmode_MinorVersion ) ) { vidmode_ext = false; } else { common->Printf( "Using XFree86-VidModeExtension Version %d.%d\n", vidmode_MajorVersion, vidmode_MinorVersion ); vidmode_ext = true; } // Check for DGA int dga_MajorVersion = 0; int dga_MinorVersion = 0; if ( in_dgamouse->value ) { if ( !XF86DGAQueryVersion( dpy, &dga_MajorVersion, &dga_MinorVersion ) ) { // unable to query, probalby not supported common->Printf( "Failed to detect XF86DGA Mouse\n" ); Cvar_Set( "in_dgamouse", "0" ); } else { common->Printf( "XF86DGA Mouse (Version %d.%d) initialized\n", dga_MajorVersion, dga_MinorVersion ); } } int actualWidth = glConfig.vidWidth; int actualHeight = glConfig.vidHeight; 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 ) { best_dist = 9999999; best_fit = -1; for ( int 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 = true; // Move the viewport to top left XF86VidModeSetViewPort( dpy, scrnum, 0, 0 ); common->Printf( "XFree86-VidModeExtension Activated at %dx%d\n", actualWidth, actualHeight ); } else { fullscreen = 0; common->Printf( "XFree86-VidModeExtension: No acceptable modes found\n" ); } } else { common->Printf( "XFree86-VidModeExtension: Ignored on non-fullscreen\n" ); } } if ( !colorbits ) { colorbits = !r_colorbits->value ? 24 : r_colorbits->value; } int depthbits = !r_depthbits->value ? 24 : r_depthbits->value; int stencilbits = r_stencilbits->value; XVisualInfo* visinfo = NULL; for ( int 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; } break; case 3: if ( stencilbits == 24 ) { stencilbits = 16; } else if ( stencilbits == 16 ) { stencilbits = 8; } break; } } int tcolorbits = colorbits; int tdepthbits = depthbits; int 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; } } 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 //GLX_SAMPLES_SGIS, 4, /* for better AA */ None }; // these match in the array enum { ATTR_RED_IDX = 2, ATTR_GREEN_IDX = 4, ATTR_BLUE_IDX = 6, ATTR_DEPTH_IDX = 9, ATTR_STENCIL_IDX = 11 }; 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; visinfo = glXChooseVisual( dpy, scrnum, attrib ); if ( !visinfo ) { continue; } common->Printf( "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 ) { common->Printf( "Couldn't get a visual\n" ); return RSERR_INVALID_MODE; } // Window attributes XSetWindowAttributes attr; unsigned long mask; 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 ); XStoreName( dpy, win, R_GetTitleForWindow() ); /* GH: Don't let the window be resized */ XSizeHints sizehints; sizehints.flags = PMinSize | PMaxSize; sizehints.min_width = sizehints.max_width = actualWidth; sizehints.min_height = sizehints.max_height = actualHeight; XSetWMNormalHints( dpy, win, &sizehints ); XMapWindow( dpy, win ); if ( vidmode_active ) { XMoveWindow( dpy, win, 0, 0 ); //XRaiseWindow(dpy, win); //XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0); //XFlush(dpy); // Move the viewport to top left //XF86VidModeSetViewPort(dpy, scrnum, 0, 0); } // hook to window close wm_protocols = XInternAtom( dpy, "WM_PROTOCOLS", False ); wm_delete_window = XInternAtom( dpy, "WM_DELETE_WINDOW", False ); XSetWMProtocols( dpy, win, &wm_delete_window, 1 ); XFlush( dpy ); XSync( dpy, False ); // bk001130 - from cvs1.17 (mkv) ctx = glXCreateContext( dpy, visinfo, NULL, True ); XSync( dpy, False ); // bk001130 - from cvs1.17 (mkv) /* GH: Free the visinfo after we're done with it */ XFree( visinfo ); glXMakeCurrent( dpy, win, ctx ); glConfig.deviceSupportsGamma = false; if ( vidmode_ext ) { if ( vidmode_MajorVersion < GAMMA_MINMAJOR || ( vidmode_MajorVersion == GAMMA_MINMAJOR && vidmode_MinorVersion < GAMMA_MINMINOR ) ) { common->Printf( "XF86 Gamma extension not supported in this version\n" ); } else { XF86VidModeGetGamma( dpy, scrnum, &vidmode_InitialGamma ); common->Printf( "XF86 Gamma extension initialized\n" ); glConfig.deviceSupportsGamma = true; } } // Check for software GL implementation. const char* glstring = ( char* )glGetString( GL_RENDERER ); if ( !String::ICmp( glstring, "Mesa X11" ) || !String::ICmp( glstring, "Mesa GLX Indirect" ) ) { if ( !r_allowSoftwareGL->integer ) { common->Printf( "\n\n***********************************************************\n" ); common->Printf( " You are using software Mesa (no hardware acceleration)!\n" ); common->Printf( " If this is intentional, add\n" ); common->Printf( " \"+set r_allowSoftwareGL 1\"\n" ); common->Printf( " to the command line when starting the game.\n" ); common->Printf( "***********************************************************\n" ); GLimp_Shutdown(); return RSERR_INVALID_MODE; } else { common->Printf( "...using software Mesa (r_allowSoftwareGL==1).\n" ); } } GLW_GenDefaultLists(); return RSERR_OK; }
// Responsible for creating the Win32 window and initializing the OpenGL driver. static bool GLW_CreateWindow( int width, int height, int colorbits, bool fullscreen ) { // // register the window class if necessary // if ( !s_classRegistered ) { vid_xpos = Cvar_Get( "vid_xpos", "3", CVAR_ARCHIVE ); vid_ypos = Cvar_Get( "vid_ypos", "22", CVAR_ARCHIVE ); WNDCLASS wc; Com_Memset( &wc, 0, sizeof ( wc ) ); wc.style = 0; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = global_hInstance; wc.hIcon = LoadIcon( global_hInstance, MAKEINTRESOURCE( IDI_ICON1 ) ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = ( HBRUSH )COLOR_GRAYTEXT; wc.lpszMenuName = 0; wc.lpszClassName = WINDOW_CLASS_NAME; if ( !RegisterClass( &wc ) ) { common->FatalError( "GLW_CreateWindow: could not register window class" ); } s_classRegistered = true; common->Printf( "...registered window class\n" ); } // // create the HWND if one does not already exist // if ( !GMainWindow ) { // // compute width and height // RECT r; r.left = 0; r.top = 0; r.right = width; r.bottom = height; int exstyle; int stylebits; if ( fullscreen ) { exstyle = WS_EX_TOPMOST; stylebits = WS_POPUP | WS_VISIBLE | WS_SYSMENU; } else { exstyle = 0; stylebits = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_VISIBLE | WS_SYSMENU; // | WS_MINIMIZEBOX AdjustWindowRect( &r, stylebits, FALSE ); } int w = r.right - r.left; int h = r.bottom - r.top; int x, y; if ( fullscreen ) { x = 0; y = 0; } else { x = vid_xpos->integer; y = vid_ypos->integer; // adjust window coordinates if necessary // so that the window is completely on screen if ( x < 0 ) { x = 0; } if ( y < 0 ) { y = 0; } if ( w < desktopWidth && h < desktopHeight ) { if ( x + w > desktopWidth ) { x = ( desktopWidth - w ); } if ( y + h > desktopHeight ) { y = ( desktopHeight - h ); } } } GMainWindow = CreateWindowEx( exstyle, WINDOW_CLASS_NAME, R_GetTitleForWindow(), stylebits, x, y, w, h, NULL, NULL, global_hInstance, NULL ); if ( !GMainWindow ) { common->FatalError( "GLW_CreateWindow() - Couldn't create window" ); } ShowWindow( GMainWindow, SW_SHOW ); UpdateWindow( GMainWindow ); common->Printf( "...created window@%d,%d (%dx%d)\n", x, y, w, h ); } else { common->Printf( "...window already present, CreateWindowEx skipped\n" ); } if ( !GLW_InitDriver( colorbits ) ) { ShowWindow( GMainWindow, SW_HIDE ); DestroyWindow( GMainWindow ); GMainWindow = NULL; return false; } SetForegroundWindow( GMainWindow ); SetFocus( GMainWindow ); WG_CheckHardwareGamma(); // initialise default lists GLW_GenDefaultLists(); return true; }
/* ** GLimp_Init ** ** This is the platform specific OpenGL initialization function. It ** is responsible for loading OpenGL, initializing it, setting ** extensions, creating a window of the appropriate size, doing ** fullscreen manipulations, etc. Its overall responsibility is ** to make sure that a functional OpenGL subsystem is operating ** when it returns to the ref. */ void GLimp_Init( void ) { char buf[1024]; cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE ); cvar_t *cv; ri.Printf( PRINT_ALL, "Initializing OpenGL subsystem\n" ); // // check OS version to see if we can do fullscreen display changes // if ( !GLW_CheckOSVersion() ) { ri.Error( ERR_VID_FATAL, "GLimp_Init() - incorrect operating system\n" ); } // save off hInstance and wndproc cv = ri.Cvar_Get( "win_hinstance", "", 0 ); sscanf( cv->string, "%i", (int *)&g_wv.hInstance ); cv = ri.Cvar_Get( "win_wndproc", "", 0 ); sscanf( cv->string, "%i", (int *)&glw_state.wndproc ); r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); r_maskMinidriver = ri.Cvar_Get( "r_maskMinidriver", "0", CVAR_LATCH ); // load appropriate DLL and initialize subsystem GLW_StartOpenGL(); // 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 ) ); Q_strncpyz( glConfig.version_string, qglGetString( GL_VERSION ), sizeof( glConfig.version_string ) ); Q_strncpyz( glConfig.extensions_string, qglGetString( GL_EXTENSIONS ), sizeof( glConfig.extensions_string ) ); // TTimo - safe check if ( strlen( qglGetString( GL_EXTENSIONS ) ) >= sizeof( glConfig.extensions_string ) ) { Com_Printf( S_COLOR_YELLOW "WARNNING: GL extensions string too long (%d), truncated to %d\n", strlen( qglGetString( GL_EXTENSIONS ) ), sizeof( glConfig.extensions_string ) ); } // // chipset specific configuration // Q_strncpyz( buf, glConfig.renderer_string, sizeof( buf ) ); Q_strlwr( buf ); // // NOTE: if changing cvars, do it within this block. This allows them // to be overridden when testing driver fixes, etc. but only sets // them to their default state when the hardware is first installed/run. // if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) { glConfig.hardwareType = GLHW_GENERIC; ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); // VOODOO GRAPHICS w/ 2MB if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) ) { ri.Cvar_Set( "r_picmip", "2" ); ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); } else { //----(SA) FIXME: RETURN TO DEFAULT Another id build change for DK/DM ri.Cvar_Set( "r_picmip", "1" ); //----(SA) was "1" // JPW NERVE back to 1 //----(SA) if ( strstr( buf, "rage 128" ) || strstr( buf, "rage128" ) ) { ri.Cvar_Set( "r_finish", "0" ); } // Savage3D and Savage4 should always have trilinear enabled else if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) ) { ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); } } } // // this is where hardware specific workarounds that should be // detected/initialized every startup should go. // if ( strstr( buf, "banshee" ) || strstr( buf, "voodoo3" ) ) { glConfig.hardwareType = GLHW_3DFX_2D3D; } // VOODOO GRAPHICS w/ 2MB else if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) ) { } else if ( strstr( buf, "glzicd" ) ) { } else if ( strstr( buf, "rage pro" ) /*|| strstr( buf, "Rage Pro")*/ || strstr( buf, "ragepro" ) ) { glConfig.hardwareType = GLHW_RAGEPRO; ri.Printf( PRINT_WARNING, "WARNING: Rage Pro hardware is unsupported. Rendering errors may occur.\n" ); } else if ( strstr( buf, "rage 128" ) ) { } else if ( strstr( buf, "permedia2" ) ) { glConfig.hardwareType = GLHW_PERMEDIA2; ri.Printf( PRINT_WARNING, "WARNING: Permedia hardware is unsupported. Rendering errors may occur.\n" ); } else if ( strstr( buf, "riva 128" ) ) { glConfig.hardwareType = GLHW_RIVA128; ri.Printf( PRINT_WARNING, "WARNING: Riva 128 hardware is unsupported. Rendering errors may occur.\n" ); } else if ( strstr( buf, "matrox" ) ) { } else if ( strstr( buf, "riva tnt " ) ) { } if ( strstr( buf, "geforce3" ) || strstr( buf, "geforce4 ti" ) || strstr( buf, "geforce fx 5600" ) || strstr( buf, "geforce fx 5800" ) || strstr( buf, "radeon 8500" ) || strstr( buf, "radeon 9000" ) || strstr( buf, "radeon 9500" ) || strstr( buf, "radeon 9600" ) || strstr( buf, "radeon 9700" ) || strstr( buf, "radeon 9800" ) || strstr( buf, "nv20" ) || strstr( buf, "nv30" ) ) { ri.Cvar_Set( "r_highQualityVideo", "1" ); } else { ri.Cvar_Set( "r_highQualityVideo", "0" ); } ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string ); GLW_InitExtensions(); WG_CheckHardwareGamma(); // initialise default lists GLW_GenDefaultLists(); }