/* =========================================================================== Copyright (C) 1997-2001 Id Software, Inc. This file is part of Quake 2 source code. Quake 2 source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Quake 2 source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Quake 2 source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ /* ** GLW_IMP.C ** ** This file contains ALL Win32 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 #include #include "../renderer/r_local.h" #include "resource.h" #include "glw_win.h" #include "winquake.h" static qboolean GLimp_SwitchFullscreen( int width, int height ); qboolean GLimp_InitGL (void); glwstate_t glw_state; extern cvar_t *vid_fullscreen; extern cvar_t *vid_ref; // Knightmare- added Vic's hardware gammaramp WORD original_ramp[3][256]; WORD gamma_ramp[3][256]; void InitGammaRamp (void) { if (!r_ignorehwgamma->value) { if (qwglGetDeviceGammaRamp3DFX) /* { WORD newramp[3*256]; int j; glState.gammaRamp = qwglGetDeviceGammaRamp3DFX ( glw_state.hDC, newramp ); for (j = 0; j < 256; j++) { original_ramp[0][j] = newramp[j+0]; original_ramp[1][j] = newramp[j+256]; original_ramp[2][j] = newramp[j+512]; } }*/ glState.gammaRamp = qwglGetDeviceGammaRamp3DFX ( glw_state.hDC, original_ramp ); else glState.gammaRamp = GetDeviceGammaRamp ( glw_state.hDC, original_ramp ); } else glState.gammaRamp = false; if (glState.gammaRamp) vid_gamma->modified = true; } void ShutdownGammaRamp (void) { // if (r_ignorehwgamma->value) if (!glState.gammaRamp) return; if (qwglSetDeviceGammaRamp3DFX) /* { WORD newramp[3*256]; int j; for (j = 0; j < 256; j++) { newramp[j+0] = original_ramp[0][j]; newramp[j+256] = original_ramp[1][j]; newramp[j+512] = original_ramp[2][j]; } qwglSetDeviceGammaRamp3DFX ( glw_state.hDC, newramp ); }*/ qwglSetDeviceGammaRamp3DFX ( glw_state.hDC, original_ramp ); else SetDeviceGammaRamp (glw_state.hDC, original_ramp); } void UpdateGammaRamp (void) { int i, o; if (!glState.gammaRamp) return; memcpy (gamma_ramp, original_ramp, sizeof(original_ramp)); for (o = 0; o < 3; o++) { for (i = 0; i < 256; i++) { signed int v; v = 255 * pow ((i+0.5)/255.5, vid_gamma->value ) + 0.5; if (v > 255) v = 255; if (v < 0) v = 0; gamma_ramp[o][i] = ((WORD)v) << 8; } } if (qwglSetDeviceGammaRamp3DFX) /* { WORD newramp[3*256]; int j; for (j = 0; j < 256; j++) { newramp[j+0] = gamma_ramp[0][j]; newramp[j+256] = gamma_ramp[1][j]; newramp[j+512] = gamma_ramp[2][j]; } qwglSetDeviceGammaRamp3DFX (glw_state.hDC, newramp); }*/ qwglSetDeviceGammaRamp3DFX (glw_state.hDC, gamma_ramp); else SetDeviceGammaRamp (glw_state.hDC, gamma_ramp); } void ToggleGammaRamp (qboolean enable) { // WORD newramp[3*256]; // int j; if (!glState.gammaRamp) return; if (enable) { if (qwglSetDeviceGammaRamp3DFX) /* { for (j = 0; j < 256; j++) { newramp[j+0] = gamma_ramp[0][j]; newramp[j+256] = gamma_ramp[1][j]; newramp[j+512] = gamma_ramp[2][j]; } qwglSetDeviceGammaRamp3DFX (glw_state.hDC, newramp); }*/ qwglSetDeviceGammaRamp3DFX (glw_state.hDC, gamma_ramp); else SetDeviceGammaRamp (glw_state.hDC, gamma_ramp); } else { if (qwglSetDeviceGammaRamp3DFX) /* { for (j = 0; j < 256; j++) { newramp[j+0] = original_ramp[0][j]; newramp[j+256] = original_ramp[1][j]; newramp[j+512] = original_ramp[2][j]; } qwglSetDeviceGammaRamp3DFX ( glw_state.hDC, newramp ); }*/ qwglSetDeviceGammaRamp3DFX ( glw_state.hDC, original_ramp ); else SetDeviceGammaRamp (glw_state.hDC, original_ramp); } } // end Vic's hardware gammaramp static qboolean VerifyDriver( void ) { char buffer[1024]; // strncpy( buffer, qglGetString( GL_RENDERER ) ); Q_strncpyz( buffer, qglGetString( GL_RENDERER ), sizeof(buffer) ); strlwr( buffer ); if ( strcmp( buffer, "gdi generic" ) == 0 ) if ( !glw_state.mcd_accelerated ) return false; return true; } /* ** VID_CreateWindow */ #define WINDOW_CLASS_NAME "KMQuake2" // changed #define WINDOW_CLASS_NAME2 "KMQuake2 - The Reckoning" // changed #define WINDOW_CLASS_NAME3 "KMQuake2 - Ground Zero" // changed qboolean VID_CreateWindow( int width, int height, qboolean fullscreen ) { WNDCLASS wc; RECT r; cvar_t *vid_xpos, *vid_ypos; int stylebits; int x, y, w, h; int exstyle; /* Register the frame class */ wc.style = 0; wc.lpfnWndProc = (WNDPROC)glw_state.wndproc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = glw_state.hInstance; if (FS_ModType("xatrix")) { // q2mp1 wc.hIcon = LoadIcon(glw_state.hInstance, MAKEINTRESOURCE(IDI_ICON2)); //wc.lpszClassName = WINDOW_CLASS_NAME2; } else if (FS_ModType("rogue")) { // q2mp2 wc.hIcon = LoadIcon(glw_state.hInstance, MAKEINTRESOURCE(IDI_ICON3)); //wc.lpszClassName = WINDOW_CLASS_NAME3; } else { wc.hIcon = LoadIcon(glw_state.hInstance, MAKEINTRESOURCE(IDI_ICON1)); } wc.hCursor = LoadCursor (NULL,IDC_ARROW); wc.hbrBackground = (void *)COLOR_GRAYTEXT; wc.lpszMenuName = 0; wc.lpszClassName = WINDOW_CLASS_NAME; if (!RegisterClass (&wc) ) VID_Error (ERR_FATAL, "Couldn't register window class"); if (fullscreen) { exstyle = WS_EX_TOPMOST; //stylebits = WS_POPUP|WS_VISIBLE; stylebits = WS_POPUP|WS_SYSMENU|WS_VISIBLE; } else { exstyle = 0; //stylebits = WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE; stylebits = WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_VISIBLE; } r.left = 0; r.top = 0; r.right = width; r.bottom = height; AdjustWindowRect (&r, stylebits, FALSE); w = r.right - r.left; h = r.bottom - r.top; if (fullscreen) { x = 0; y = 0; } else { vid_xpos = Cvar_Get ("vid_xpos", "0", 0); vid_ypos = Cvar_Get ("vid_ypos", "0", 0); x = vid_xpos->value; y = vid_ypos->value; } glw_state.hWnd = CreateWindowEx ( exstyle, WINDOW_CLASS_NAME, "KMQuake2", //Knightmare changed stylebits, x, y, w, h, NULL, NULL, glw_state.hInstance, NULL); if (!glw_state.hWnd) VID_Error (ERR_FATAL, "Couldn't create window"); ShowWindow( glw_state.hWnd, SW_SHOW ); UpdateWindow( glw_state.hWnd ); // init all the gl stuff for the window if (!GLimp_InitGL ()) { VID_Printf( PRINT_ALL, "VID_CreateWindow() - GLimp_InitGL failed\n"); return false; } SetForegroundWindow( glw_state.hWnd ); SetFocus( glw_state.hWnd ); // let the sound and input subsystems know about the new window VID_NewWindow (width, height); return true; } /* ** GLimp_SetMode */ rserr_t GLimp_SetMode ( int *pwidth, int *pheight, int mode, qboolean fullscreen ) { int width, height; const char *win_fs[] = { "W", "FS" }; VID_Printf( PRINT_ALL, "Initializing OpenGL display\n"); VID_Printf (PRINT_ALL, "...setting mode %d:", mode ); if ( !VID_GetModeInfo( &width, &height, mode ) ) { VID_Printf( PRINT_ALL, " invalid mode\n" ); return rserr_invalid_mode; } VID_Printf( PRINT_ALL, " %dx%d %s\n", width, height, win_fs[fullscreen] ); // destroy the existing window if (glw_state.hWnd) { GLimp_Shutdown (); } // do a CDS if needed if ( fullscreen ) { DEVMODE dm; VID_Printf( PRINT_ALL, "...attempting fullscreen\n" ); memset( &dm, 0, sizeof( dm ) ); dm.dmSize = sizeof( dm ); dm.dmPelsWidth = width; dm.dmPelsHeight = height; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; // Added refresh rate control if ( r_displayrefresh->value != 0 ) { dm.dmDisplayFrequency = r_displayrefresh->integer; dm.dmFields |= DM_DISPLAYFREQUENCY; VID_Printf( PRINT_ALL, "...using r_displayrefresh of %d\n", (int)r_displayrefresh->value ); } if ( r_bitdepth->value != 0 ) { dm.dmBitsPerPel = r_bitdepth->value; dm.dmFields |= DM_BITSPERPEL; VID_Printf( PRINT_ALL, "...using r_bitdepth of %d\n", ( int ) r_bitdepth->value ); } else { HDC hdc = GetDC( NULL ); int bitspixel = GetDeviceCaps( hdc, BITSPIXEL ); VID_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel ); ReleaseDC( 0, hdc ); } VID_Printf( PRINT_ALL, "...calling CDS: " ); if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL ) { *pwidth = width; *pheight = height; glState.fullscreen = true; VID_Printf( PRINT_ALL, "ok\n" ); if ( !VID_CreateWindow (width, height, true) ) return rserr_invalid_mode; return rserr_ok; } else { *pwidth = width; *pheight = height; VID_Printf( PRINT_ALL, "failed\n" ); VID_Printf( PRINT_ALL, "...calling CDS assuming dual monitors:" ); dm.dmPelsWidth = width * 2; dm.dmPelsHeight = height; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; if ( r_bitdepth->value != 0 ) { dm.dmBitsPerPel = r_bitdepth->value; dm.dmFields |= DM_BITSPERPEL; } /* ** our first CDS failed, so maybe we're running on some weird dual monitor ** system */ if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL ) { VID_Printf( PRINT_ALL, " failed\n" ); VID_Printf( PRINT_ALL, "...setting windowed mode\n" ); ChangeDisplaySettings( 0, 0 ); *pwidth = width; *pheight = height; glState.fullscreen = false; if ( !VID_CreateWindow (width, height, false) ) return rserr_invalid_mode; return rserr_invalid_fullscreen; } else { VID_Printf( PRINT_ALL, " ok\n" ); if ( !VID_CreateWindow (width, height, true) ) return rserr_invalid_mode; glState.fullscreen = true; return rserr_ok; } } } else { VID_Printf( PRINT_ALL, "...setting windowed mode\n" ); ChangeDisplaySettings( 0, 0 ); *pwidth = width; *pheight = height; glState.fullscreen = false; if ( !VID_CreateWindow (width, height, false) ) return rserr_invalid_mode; } return rserr_ok; } /* ** 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 ) { // Knightmare- added Vic's hardware gamma ramp ShutdownGammaRamp (); if ( qwglMakeCurrent && !qwglMakeCurrent( NULL, NULL ) ) VID_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglMakeCurrent failed\n"); if ( glw_state.hGLRC ) { if ( qwglDeleteContext && !qwglDeleteContext( glw_state.hGLRC ) ) VID_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglDeleteContext failed\n"); glw_state.hGLRC = NULL; } if (glw_state.hDC) { if ( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) ) VID_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - ReleaseDC failed\n" ); glw_state.hDC = NULL; } if (glw_state.hWnd) { //Knightmare- remove leftover button on taskbar ShowWindow (glw_state.hWnd, SW_HIDE); //end Knightmare DestroyWindow ( glw_state.hWnd ); glw_state.hWnd = NULL; } if ( glw_state.log_fp ) { fclose( glw_state.log_fp ); glw_state.log_fp = 0; } UnregisterClass (WINDOW_CLASS_NAME, glw_state.hInstance); if ( glState.fullscreen ) { ChangeDisplaySettings( 0, 0 ); glState.fullscreen = false; } } /* ** GLimp_Init ** ** This routine is responsible for initializing the OS specific portions ** of OpenGL. Under Win32 this means dealing with the pixelformats and ** doing the wgl interface stuff. */ qboolean GLimp_Init( void *hinstance, void *wndproc ) { #define OSR2_BUILD_NUMBER 1111 OSVERSIONINFO vinfo; vinfo.dwOSVersionInfoSize = sizeof(vinfo); glw_state.allowdisplaydepthchange = false; if ( GetVersionEx( &vinfo) ) { if ( vinfo.dwMajorVersion > 4 ) { glw_state.allowdisplaydepthchange = true; } else if ( vinfo.dwMajorVersion == 4 ) { if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) { glw_state.allowdisplaydepthchange = true; } else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) { if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER ) { glw_state.allowdisplaydepthchange = true; } } } } else { VID_Printf( PRINT_ALL, "GLimp_Init() - GetVersionEx failed\n" ); return false; } glw_state.hInstance = ( HINSTANCE ) hinstance; glw_state.wndproc = wndproc; return true; } qboolean GLimp_InitGL (void) { PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, // version number PFD_DRAW_TO_WINDOW | // support window PFD_SUPPORT_OPENGL | // support OpenGL PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 32, // 32-bit color depth // was 24 0, 0, 0, 0, 0, 0, // color bits ignored 0, // no alpha buffer 0, // shift bit ignored 0, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored //Knightmare 12/24/2001- stencil buffer 24, // 24-bit z-buffer, was 32 8, // 8-bit stencil buffer //end Knightmare 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored }; int pixelformat; cvar_t *stereo; stereo = Cvar_Get( "cl_stereo", "0", 0 ); /* ** set PFD_STEREO if necessary */ if ( stereo->value != 0 ) { VID_Printf( PRINT_ALL, "...attempting to use stereo\n" ); pfd.dwFlags |= PFD_STEREO; glState.stereo_enabled = true; } else { glState.stereo_enabled = false; } /* ** figure out if we're running on a minidriver or not */ if ( strstr( gl_driver->string, "opengl32" ) != 0 ) glw_state.minidriver = false; else glw_state.minidriver = true; /* ** Get a DC for the specified window */ if ( glw_state.hDC != NULL ) VID_Printf( PRINT_ALL, "GLimp_Init() - non-NULL DC exists\n" ); if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL ) { VID_Printf( PRINT_ALL, "GLimp_Init() - GetDC failed\n" ); return false; } if ( glw_state.minidriver ) { if ( (pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd)) == 0 ) { VID_Printf (PRINT_ALL, "GLimp_Init() - qwglChoosePixelFormat failed\n"); return false; } if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE ) { VID_Printf (PRINT_ALL, "GLimp_Init() - qwglSetPixelFormat failed\n"); return false; } qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd ); } else { if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 ) { VID_Printf (PRINT_ALL, "GLimp_Init() - ChoosePixelFormat failed\n"); return false; } if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE ) { VID_Printf (PRINT_ALL, "GLimp_Init() - SetPixelFormat failed\n"); return false; } DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd ); if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) ) { extern cvar_t *gl_allow_software; if ( gl_allow_software->value ) glw_state.mcd_accelerated = true; else glw_state.mcd_accelerated = false; } else { glw_state.mcd_accelerated = true; } } /* ** report if stereo is desired but unavailable */ if ( !( pfd.dwFlags & PFD_STEREO ) && ( stereo->value != 0 ) ) { VID_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" ); Cvar_SetValue( "cl_stereo", 0 ); glState.stereo_enabled = false; } /* ** startup the OpenGL subsystem by creating a context and making ** it current */ if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 ) { VID_Printf (PRINT_ALL, "GLimp_Init() - qwglCreateContext failed\n"); goto fail; } if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) { VID_Printf (PRINT_ALL, "GLimp_Init() - qwglMakeCurrent failed\n"); goto fail; } if ( !VerifyDriver() ) { VID_Printf( PRINT_ALL, "GLimp_Init() - no hardware acceleration detected.\nPlease install drivers provided by your video card/GPU vendor.\n" ); goto fail; } /* ** print out PFD specifics */ VID_Printf( PRINT_ALL, "PIXELFORMAT: color(%d-bits) Z(%d-bit)\n", ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits ); // Knightmare- Vic's hardware gamma stuff InitGammaRamp (); // moved these to GL_SetDefaultState //glState.blend = false; //glState.alphaTest = false; //end Knightmare //Knightmare- 12/24/2001- stecil buffer { char buffer[1024]; // strncpy( buffer, qglGetString( GL_RENDERER ) ); Q_strncpyz( buffer, qglGetString( GL_RENDERER ), sizeof(buffer) ); strlwr( buffer ); if (strstr(buffer, "Voodoo3")) { VID_Printf( PRINT_ALL, "... Voodoo3 has no stencil buffer\n" ); glConfig.have_stencil = false; } else { if (pfd.cStencilBits) { VID_Printf( PRINT_ALL, "... Using stencil buffer\n" ); glConfig.have_stencil = true; // Stencil shadows - MrG } } } //if (pfd.cStencilBits) // glConfig.have_stencil = true; //end Knightmare /* Moved to GL_SetDefaultState in r_glstate.c // Vertex arrays qglEnableClientState (GL_TEXTURE_COORD_ARRAY); qglEnableClientState (GL_VERTEX_ARRAY); qglEnableClientState (GL_COLOR_ARRAY); qglTexCoordPointer (2, GL_FLOAT, sizeof(texCoordArray[0][0]), texCoordArray[0][0]); qglVertexPointer (3, GL_FLOAT, sizeof(vertexArray[0]), vertexArray[0]); qglColorPointer (4, GL_FLOAT, sizeof(colorArray[0]), colorArray[0]); //glState.activetmu[0] = true; // end vertex arrays */ return true; fail: if ( glw_state.hGLRC ) { qwglDeleteContext( glw_state.hGLRC ); glw_state.hGLRC = NULL; } if ( glw_state.hDC ) { ReleaseDC( glw_state.hWnd, glw_state.hDC ); glw_state.hDC = NULL; } return false; } /* ** GLimp_BeginFrame */ void GLimp_BeginFrame( float camera_separation ) { if ( r_bitdepth->modified ) { if ( r_bitdepth->value != 0 && !glw_state.allowdisplaydepthchange ) { Cvar_SetValue( "r_bitdepth", 0 ); VID_Printf( PRINT_ALL, "r_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" ); } r_bitdepth->modified = false; } if ( camera_separation < 0 && glState.stereo_enabled ) { qglDrawBuffer( GL_BACK_LEFT ); } else if ( camera_separation > 0 && glState.stereo_enabled ) { qglDrawBuffer( GL_BACK_RIGHT ); } else { qglDrawBuffer( GL_BACK ); } } /* ** 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) { int err; err = qglGetError(); // assert( err == GL_NO_ERROR ); if (err != GL_NO_ERROR) // Output error code instead VID_Printf (PRINT_DEVELOPER, "OpenGL Error %i\n", err); if ( stricmp( r_drawbuffer->string, "GL_BACK" ) == 0 ) { if ( !qwglSwapBuffers( glw_state.hDC ) ) VID_Error (ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n"); } } /* ** GLimp_AppActivate */ void GLimp_AppActivate( qboolean active ) { static qboolean desktop_restored; cvar_t *restore_desktop = Cvar_Get( "win_alttab_restore_desktop", "1", CVAR_ARCHIVE ); if ( active ) { ToggleGammaRamp (true); SetForegroundWindow( glw_state.hWnd ); ShowWindow( glw_state.hWnd, SW_RESTORE ); // Knightmare- restore desktop settings on alt-tabbing from fullscreen if ( vid_fullscreen->value && desktop_restored && glw_state.hGLRC != NULL ) { int width, height; DEVMODE dm; if ( !VID_GetModeInfo (&width, &height, (int)(r_mode->value)) ) { VID_Printf( PRINT_ALL, "invalid mode\n" ); return; } memset( &dm, 0, sizeof( dm ) ); dm.dmSize = sizeof( dm ); dm.dmPelsWidth = width; dm.dmPelsHeight = height; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; if ( r_displayrefresh->value != 0 ) { dm.dmDisplayFrequency = r_displayrefresh->integer; dm.dmFields |= DM_DISPLAYFREQUENCY; // VID_Printf( PRINT_ALL, "...using r_displayrefresh of %d\n", (int)r_displayrefresh->value ); } if ( r_bitdepth->value != 0 ) { dm.dmBitsPerPel = r_bitdepth->value; dm.dmFields |= DM_BITSPERPEL; // VID_Printf( PRINT_ALL, "...using r_bitdepth of %d\n", (int)r_bitdepth->value ); } else { HDC hdc = GetDC( NULL ); int bitspixel = GetDeviceCaps( hdc, BITSPIXEL ); // VID_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel ); ReleaseDC( 0, hdc ); } VID_Printf( PRINT_ALL, "...calling CDS: " ); if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL ) { VID_Printf( PRINT_ALL, "ok\n" ); } else { // our first CDS failed, so maybe we're running on some weird dual monitor system VID_Printf( PRINT_ALL, "failed\n" ); VID_Printf( PRINT_ALL, "...calling CDS assuming dual monitors: " ); dm.dmPelsWidth = width * 2; dm.dmPelsHeight = height; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; if ( r_bitdepth->value != 0 ) { dm.dmBitsPerPel = r_bitdepth->value; dm.dmFields |= DM_BITSPERPEL; } if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL ) { VID_Printf( PRINT_ALL, "ok\n" ); } } desktop_restored = false; } } else { ToggleGammaRamp (false); if ( vid_fullscreen->value ) { ShowWindow( glw_state.hWnd, SW_MINIMIZE ); // Knightmare- restore desktop settings on alt-tabbing from fullscreen if (restore_desktop->value) { ChangeDisplaySettings (0, 0); desktop_restored = true; } else desktop_restored = false; } } }