static void GLW_CreateGLWnd( void ) { int x, y, w, h; HWND hParent; float aspect; DWORD s, es; skinDef_t *skin; int refresh = 0; int colorDepth = 0; WinVars_t *winVars = (WinVars_t*)ri.PlatformGetVars(); if( winVars->hWnd ) return; x = 0; y = 0; if( r_fullscreen->integer ) { int mode_id; char * res = r_fsmode->string; w = atoi( COM_Parse( &res ) ); h = atoi( COM_Parse( &res ) ); aspect = (float)w / (float)h; sql_prepare( &com_db, "SELECT x, y FROM monitors SEARCH dev_name ?" ); sql_bindtext( &com_db, 1, r_fsmonitor->string ); if( sql_step( &com_db ) ) { x = sql_columnasint( &com_db, 0 ); y = sql_columnasint( &com_db, 1 ); } sql_done( &com_db ); //find the settings mode id mode_id = -1; sql_prepare( &com_db, "SELECT id FROM fsmodes SEARCH dev_name ?1 WHERE w=?2 AND h=?3" ); sql_bindtext( &com_db, 1, r_fsmonitor->string ); sql_bindint( &com_db, 2, w ); sql_bindint( &com_db, 3, h ); if( sql_step( &com_db ) ) mode_id = sql_columnasint( &com_db, 0 ); sql_done( &com_db ); //get a matching color mode sql_prepare( &com_db, "SELECT bpp FROM fsmodes_ext SEARCH id ?1" ); sql_bindint( &com_db, 1, mode_id ); while( sql_step( &com_db ) ) { int bpp = sql_columnasint( &com_db, 0 ); if( r_colorbits->integer ) { if( bpp == r_colorbits->integer ) { //take an exact match colorDepth = bpp; break; } if( bpp > r_colorbits->integer ) { if( colorDepth < r_colorbits->integer || bpp < colorDepth ) //if we must go over, take the smallest value that goes over colorDepth = bpp; } else if( bpp > colorDepth ) colorDepth = bpp; } else if( bpp > colorDepth ) colorDepth = bpp; } sql_done( &com_db ); //get a matching refresh rate sql_prepare( &com_db, "SELECT hz FROM fsmodes_ext SEARCH id ?1 WHERE bpp=?2" ); sql_bindint( &com_db, 1, mode_id ); sql_bindint( &com_db, 2, colorDepth ); while( sql_step( &com_db ) ) { int hz = sql_columnasint( &com_db, 0 ); if( r_displayRefresh->integer ) { if( hz == r_displayRefresh->integer ) { //take an exact match refresh = hz; break; } if( hz > r_displayRefresh->integer ) { if( refresh < r_displayRefresh->integer || hz < refresh ) //if we must go over, take the smallest value that goes over refresh = hz; } else if( hz > refresh ) refresh = hz; } else if( hz > refresh ) //take the highest refresh rate refresh = hz; } sql_done( &com_db ); } else { if( !R_GetModeInfo( &w, &h, &aspect, r_mode->integer ) ) { //fall back to special modes w = 0; h = 0; } } /* Clean out old display mode changes. Note that we *don't* skip this when we're going back into fullscreen as it tends to produce some aweful bugs on some Windows installations. */ if( glw_state.cdsFullscreen ) ChangeDisplaySettings( NULL, 0 ); //window style bits es = 0; s = 0; skin = NULL; if( r_fullscreen->integer ) { //go into full screen mode RECT rc; HMONITOR monitor; MONITORINFOEX monitorInfo; hParent = 0; //make sure we're set up for multimon goodness if( winVars->hWndHost ) { GetWindowRect( winVars->hWndHost, &rc ); } else { rc.left = x; rc.top = y; rc.right = x + w; rc.bottom = y + h; } monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONEAREST ); monitorInfo.cbSize = sizeof( monitorInfo ); GetMonitorInfo( monitor, (LPMONITORINFO)&monitorInfo ); //if we got an invalid mode then use desktop resolution if( w == 0 ) w = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left; if( h == 0 ) h = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top; //change that monitor's display size to <w, h> //set the window rect to cover the display //skip the festival of desktop flickering if not changing resolution if( (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left) != w || (monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top) != h ) { DEVMODE dm; memset( &dm, 0, sizeof( dm ) ); dm.dmSize = sizeof( dm ); dm.dmPelsWidth = w; dm.dmPelsHeight = h; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; if( refresh != 0 ) { dm.dmDisplayFrequency = refresh; dm.dmFields |= DM_DISPLAYFREQUENCY; } if( colorDepth != 0 ) { dm.dmBitsPerPel = colorDepth; dm.dmFields |= DM_BITSPERPEL; } if( ChangeDisplaySettingsEx( monitorInfo.szDevice, &dm, NULL, CDS_FULLSCREEN, NULL ) != DISP_CHANGE_SUCCESSFUL ) { //try again without color bits and frequency dm.dmFields &= ~(DM_BITSPERPEL | DM_DISPLAYFREQUENCY); dm.dmBitsPerPel = 0; dm.dmDisplayFrequency = 0; if( ChangeDisplaySettingsEx( monitorInfo.szDevice, &dm, NULL, CDS_FULLSCREEN, NULL ) != DISP_CHANGE_SUCCESSFUL ) //failed... ri.Printf( PRINT_WARNING, "Invalid fullscreen resolution, running at desktop resolution" ); } } //get the new monitor info monitorInfo.cbSize = sizeof( monitorInfo ); GetMonitorInfo( monitor, (LPMONITORINFO)&monitorInfo ); x = monitorInfo.rcMonitor.left; y = monitorInfo.rcMonitor.top; w = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left; h = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top; s = WS_POPUP; es = WS_EX_APPWINDOW | WS_EX_TOPMOST; glw_state.cdsFullscreen = qtrue; } else if( winVars->hWndHost ) { RECT rc; hParent = winVars->hWndHost; GetClientRect( winVars->hWndHost, &rc ); x = rc.left; y = rc.top; w = rc.right - rc.left; h = rc.bottom - rc.top; s = WS_CHILD; es = WS_EX_NOPARENTNOTIFY; } else { RECT rc; HMONITOR monitor; MONITORINFO monitorInfo; qboolean usedefault = qfalse; if( w == 0 ) w = 640; if( h == 0 ) h = 480; vid_xpos = ri.Cvar_Get( "vid_xpos", va("%d",CW_USEDEFAULT), CVAR_ARCHIVE ); vid_ypos = ri.Cvar_Get( "vid_ypos", "0", CVAR_ARCHIVE ); x = vid_xpos->integer; y = vid_ypos->integer; if ( x == CW_USEDEFAULT ) { x = 0; usedefault = qtrue; } rc.left = x; rc.top = y; rc.right = x + w; rc.bottom = y + h; hParent = 0; if( r_skin->string[0] ) skin = Skin_Load( r_skin->string ); //account for the border frame if( skin ) { s = WS_POPUP; es = WS_EX_APPWINDOW; Skin_AdjustWindowRect( &rc, skin ); AdjustWindowRectEx( &rc, s, FALSE, es ); } else { s = WS_OVERLAPPED | WS_SYSMENU | WS_BORDER | WS_CAPTION; es = WS_EX_APPWINDOW; AdjustWindowRectEx( &rc, s, FALSE, es ); } x = rc.left; y = rc.top; w = rc.right - rc.left; h = rc.bottom - rc.top; //constrain to a monitor //this is important as we can't get a //pixel format if we're entirely off screen monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONEAREST ); monitorInfo.cbSize = sizeof( monitorInfo ); GetMonitorInfo( monitor, &monitorInfo ); //if we're not actually intersecting the monitor //(shoved off of the screen I guess) move back onto it if( x > monitorInfo.rcWork.right ) //left window edge past right screen edge x = monitorInfo.rcWork.right - w; if( x + w < monitorInfo.rcWork.left ) //right window edge past left screen edge x = monitorInfo.rcWork.left; if( y > monitorInfo.rcWork.bottom ) //top window edge past bottom screen edge y = monitorInfo.rcWork.bottom - h; if( y + h < monitorInfo.rcWork.top ) //bottom window edge past top screen edge y = monitorInfo.rcWork.top; glw_state.cdsFullscreen = qfalse; if ( usedefault ) { x = monitorInfo.rcMonitor.left + ((monitorInfo.rcMonitor.right-monitorInfo.rcMonitor.left)-w)/2; y = monitorInfo.rcMonitor.top + ((monitorInfo.rcMonitor.bottom-monitorInfo.rcMonitor.top)-h)/2; } } winVars->hWnd = NULL; if( skin ) { Skin_RegisterClass(); winVars->hWnd = Skin_CreateWnd( skin, x, y, w, h ); } if( !winVars->hWnd ) { GLW_RegisterClass(); winVars->hWnd = CreateWindowEx( es, WINDOW_CLASS_NAME, WINDOW_CAPTION, s, x, y, w, h, hParent, NULL, winVars->hInstance, NULL ); } //the window now owns the skin and will free it if( !winVars->hWnd ) ri.Error( ERR_FATAL, "GLW: could not create window" ); SetWindowPos( winVars->hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW ); ShowWindow( winVars->hWnd, SW_SHOWNORMAL ); SetFocus( winVars->hWnd ); //get the window to draw once (get rid of graphical clutter) UpdateWindow( winVars->hWnd ); //fire up the GL glw_state.hDC = GetDC( winVars->hWnd ); if( !glw_state.hDC ) ri.Error( ERR_FATAL, "GLW: could not get window DC" ); //set up the pixel format { int pixelFormat; PIXELFORMATDESCRIPTOR pfd; GLW_CreatePFD( &pfd ); pixelFormat = GLW_ChoosePFDEx( &pfd ); if( !pixelFormat ) { pixelFormat = GLW_ChoosePFD( glw_state.hDC, &pfd ); glConfig.fsaaSamples = 1; } if( !pixelFormat ) ri.Error( ERR_FATAL, "GLW: no valid pixel format" ); pfd.nSize = sizeof( pfd ); DescribePixelFormat( glw_state.hDC, pixelFormat, sizeof( pfd ), &pfd ); if( !SetPixelFormat( glw_state.hDC, pixelFormat, &pfd ) ) ri.Error( ERR_FATAL, "GLW: could not set pixel format" ); glConfig.colorBits = pfd.cColorBits; glConfig.depthBits = pfd.cDepthBits; glConfig.stencilBits = pfd.cStencilBits; glConfig.stereoEnabled = (pfd.dwFlags & PFD_STEREO) ? qtrue : qfalse; ri.Printf( PRINT_ALL, "Using Pixel Format %i\n", pixelFormat ); } glw_state.hGLRC = wglCreateContext( glw_state.hDC ); if( !glw_state.hGLRC || !wglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) ri.Error( ERR_FATAL, "GLW: could not initialize GL" ); GLW_CheckExtensions(); //R_PerfInit(); { //get the actual sizes, in case Windows constrained our window RECT rc; GetClientRect( winVars->hWnd, &rc ); w = rc.right - rc.left; h = rc.bottom - rc.top; //fill in some glConfig stuff which *will* be referenced //by various subsystem init functions (i.e. Cg, bloom) glConfig.vidWidth = w; glConfig.vidHeight = h; glConfig.windowAspect = aspect; } glConfig.deviceSupportsGamma = qfalse; glConfig.isFullscreen = glw_state.cdsFullscreen ? qtrue : qfalse; glConfig.xscale = glConfig.vidWidth / 640.0f; glConfig.yscale = glConfig.vidHeight / 480.0f; if( glConfig.vidWidth * 480 > glConfig.vidHeight * 640 ) { // wide screen glConfig.xscale = glConfig.yscale; glConfig.xbias = ((float)glConfig.vidWidth - (640.0F * glConfig.xscale)) * 0.5F; } else { // no wide screen glConfig.xbias = 0.0f; } }
/* ** - get a DC if one doesn't exist ** - create an HGLRC if one doesn't exist */ static qbool GLW_InitDriver( int colorbits ) { int tpfd; int depthbits, stencilbits; static PIXELFORMATDESCRIPTOR pfd; // save between frames since 'tr' gets cleared ri.Printf( PRINT_DEVELOPER, "Initializing OpenGL driver\n" ); // // get a DC for our window if we don't already have one allocated // if ( glw_state.hDC == NULL ) { if ( ( glw_state.hDC = GetDC( g_wv.hWnd ) ) == NULL ) { ri.Printf( PRINT_ALL, "...Get DC failed\n" ); return qfalse; } ri.Printf( PRINT_DEVELOPER, "...Get DC succeeded\n" ); } if ( colorbits == 0 ) { colorbits = glw_state.desktopBPP; } // // implicitly assume Z-buffer depth == desktop color depth // if ( r_depthbits->integer == 0 ) { if ( colorbits > 16 ) { depthbits = 24; } else { depthbits = 16; } } else { depthbits = r_depthbits->integer; } // // do not allow stencil if Z-buffer depth likely won't contain it // stencilbits = r_stencilbits->integer; if ( depthbits < 24 ) { stencilbits = 0; } // // make two attempts to set the PIXELFORMAT // // // first attempt: r_colorbits, depthbits, and r_stencilbits // if ( !glw_state.pixelFormatSet ) { GLW_CreatePFD( &pfd, colorbits, depthbits, stencilbits, (qbool)r_stereo->integer ); if ( ( tpfd = GLW_MakeContext( &pfd ) ) != TRY_PFD_SUCCESS ) { if ( tpfd == TRY_PFD_FAIL_HARD ) { ri.Printf( PRINT_WARNING, "...failed hard\n" ); return qfalse; } // // punt if we've already tried the desktop bit depth and no stencil bits // if ( ( r_colorbits->integer == glw_state.desktopBPP ) && !stencilbits ) { ReleaseDC( g_wv.hWnd, glw_state.hDC ); glw_state.hDC = NULL; ri.Printf( PRINT_ALL, "...failed to find an appropriate PIXELFORMAT\n" ); return qfalse; } // // second attempt: desktop's color bits and no stencil // if ( colorbits > glw_state.desktopBPP ) colorbits = glw_state.desktopBPP; GLW_CreatePFD( &pfd, colorbits, depthbits, 0, (qbool)r_stereo->integer ); if ( GLW_MakeContext( &pfd ) != TRY_PFD_SUCCESS ) { if ( glw_state.hDC ) { ReleaseDC( g_wv.hWnd, glw_state.hDC ); glw_state.hDC = NULL; } ri.Printf( PRINT_ALL, "...failed to find an appropriate PIXELFORMAT\n" ); return qfalse; } } // report if stereo is desired but unavailable // if ( r_stereo->integer && !( pfd.dwFlags & PFD_STEREO ) ) { ri.Printf( PRINT_ALL, "...failed to select stereo pixel format\n" ); glConfig.stereoEnabled = qfalse; } } // store PFD specifics // glConfig.colorBits = ( int ) pfd.cColorBits; glConfig.depthBits = ( int ) pfd.cDepthBits; glConfig.stencilBits = ( int ) pfd.cStencilBits; return qtrue; }
// - get a DC if one doesn't exist // - create an HGLRC if one doesn't exist static bool GLW_InitDriver( int colorbits ) { static PIXELFORMATDESCRIPTOR pfd; // save between frames since 'tr' gets cleared common->Printf( "Initializing OpenGL driver\n" ); // // get a DC for our window if we don't already have one allocated // if ( maindc == NULL ) { common->Printf( "...getting DC: " ); if ( ( maindc = GetDC( GMainWindow ) ) == NULL ) { common->Printf( "failed\n" ); return false; } common->Printf( "succeeded\n" ); } if ( colorbits == 0 ) { colorbits = desktopBitsPixel; } // // implicitly assume Z-buffer depth == desktop color depth // int depthbits; if ( r_depthbits->integer == 0 ) { if ( colorbits > 16 ) { depthbits = 24; } else { depthbits = 16; } } else { depthbits = r_depthbits->integer; } // // do not allow stencil if Z-buffer depth likely won't contain it // int stencilbits = r_stencilbits->integer; if ( depthbits < 24 ) { stencilbits = 0; } // // make two attempts to set the PIXELFORMAT // // // first attempt: r_colorbits, depthbits, and r_stencilbits // if ( !pixelFormatSet ) { GLW_CreatePFD( &pfd, colorbits, depthbits, stencilbits, !!r_stereo->integer ); int tpfd = GLW_MakeContext( &pfd ); if ( tpfd != TRY_PFD_SUCCESS ) { if ( tpfd == TRY_PFD_FAIL_HARD ) { if ( maindc ) { ReleaseDC( GMainWindow, maindc ); maindc = NULL; } common->Printf( S_COLOR_YELLOW "...failed hard\n" ); return false; } // // punt if we've already tried the desktop bit depth and no stencil bits // if ( ( r_colorbits->integer == desktopBitsPixel ) && ( stencilbits == 0 ) ) { if ( maindc ) { ReleaseDC( GMainWindow, maindc ); maindc = NULL; } common->Printf( "...failed to find an appropriate PIXELFORMAT\n" ); return false; } // // second attempt: desktop's color bits and no stencil // if ( colorbits > desktopBitsPixel ) { colorbits = desktopBitsPixel; } GLW_CreatePFD( &pfd, colorbits, depthbits, 0, !!r_stereo->integer ); if ( GLW_MakeContext( &pfd ) != TRY_PFD_SUCCESS ) { if ( maindc ) { ReleaseDC( GMainWindow, maindc ); maindc = NULL; } common->Printf( "...failed to find an appropriate PIXELFORMAT\n" ); return false; } } // // Report if stereo is desired but unavailable. // if ( !( pfd.dwFlags & PFD_STEREO ) && ( r_stereo->integer != 0 ) ) { common->Printf( "...failed to select stereo pixel format\n" ); glConfig.stereoEnabled = false; } } // // Store PFD specifics. // glConfig.colorBits = ( int )pfd.cColorBits; glConfig.depthBits = ( int )pfd.cDepthBits; glConfig.stencilBits = ( int )pfd.cStencilBits; return true; }