//----------------------------------------------------------------------------- // Copyright (c) 2013 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "platformWin32/platformGL.h" #include "platformWin32/platformWin32.h" #include "platformWin32/winOGLVideo.h" #include "console/console.h" #include "math/mPoint.h" #include "platform/event.h" #include "game/gameInterface.h" #include "console/consoleInternal.h" #include "console/ast.h" #include "io/fileStream.h" //------------------------------------------------------------------------------ struct CardProfile { const char *vendor; // manufacturer const char *renderer; // driver name bool safeMode; // destroy rendering context for resolution change bool lockArray; // allow compiled vertex arrays bool subImage; // allow glTexSubImage* bool fogTexture; // require bound texture for combine extension bool noEnvColor; // no texture environment color bool clipHigh; // clip high resolutions bool deleteContext; // delete rendering context bool texCompress; // allow texture compression bool interiorLock; // lock arrays for Interior render bool skipFirstFog; // skip first two-pass fogging (dumb 3Dfx hack) bool only16; // inhibit 32-bit resolutions bool noArraysAlpha; // don't use glDrawArrays with a GL_ALPHA texture const char *proFile; // explicit profile of graphic settings }; struct OSCardProfile { const char *vendor; // manufacturer const char *renderer; // driver name bool allowOpenGL; // allow OpenGL driver bool preferOpenGL; // prefer OpenGL driver }; static Vector sCardProfiles(__FILE__, __LINE__); static Vector sOSCardProfiles(__FILE__, __LINE__); //------------------------------------------------------------------------------ #include "winOGLVideo_ScriptBinding.h" //------------------------------------------------------------------------------ struct ProcessorProfile { U16 clock; // clock range max U16 adjust; // CPU adjust }; static U8 sNumProcessors = 4; static ProcessorProfile sProcessorProfiles[] = { { 400, 0 }, { 600, 5 }, { 800, 10 }, { 1000, 15 }, }; struct SettingProfile { U16 performance; // metric range max const char *settings; // default file }; static U8 sNumSettings = 3; static SettingProfile sSettingProfiles[] = { { 33, "LowProfile.cs" }, { 66, "MediumProfile.cs" }, { 100, "HighProfile.cs" }, }; //------------------------------------------------------------------------------ static void clearCardProfiles() { while (sCardProfiles.size()) { dFree((char *) sCardProfiles.last().vendor); dFree((char *) sCardProfiles.last().renderer); dFree((char *) sCardProfiles.last().proFile); sCardProfiles.decrement(); } } static void clearOSCardProfiles() { while (sOSCardProfiles.size()) { dFree((char *) sOSCardProfiles.last().vendor); dFree((char *) sOSCardProfiles.last().renderer); sOSCardProfiles.decrement(); } } static void execScript(const char *scriptFile) { // execute the script FileStream str; if (!str.open(scriptFile, FileStream::Read)) return; U32 size = str.getStreamSize(); char *script = new char[size + 1]; str.read(size, script); str.close(); script[size] = 0; Con::executef(2, "eval", script); delete[] script; } static void profileSystem(const char *vendor, const char *renderer) { //Con::executef(2, "exec", "scripts/CardProfiles.cs"); execScript("CardProfiles.cs"); const char *arch; OSVERSIONINFO OSVersionInfo; const char *os = NULL; char osProfiles[64]; if (dStrstr(PlatformSystemInfo.processor.name,"AMD") != NULL) arch = "AMD"; else arch = "Intel"; dMemset( &OSVersionInfo, 0, sizeof( OSVERSIONINFO ) ); OSVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); if ( GetVersionEx( &OSVersionInfo ) ) { if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) if ( OSVersionInfo.dwMinorVersion == 0 ) { if (dStrcmp(arch,"Intel") == 0) os = "W95"; } else if ( OSVersionInfo.dwMinorVersion == 10 ) if ( OSVersionInfo.szCSDVersion[1] != 'A' ) os = "W98"; else os = "W98SE"; else os = "WME"; else if ( OSVersionInfo.dwMajorVersion >= 5 ) os = "W2K"; if ( os != NULL ) { dSprintf(osProfiles,64,"%s%sCardProfiles.cs",arch,os); //Con::executef(2, "exec", osProfiles); execScript(osProfiles); } } const char *proFile = NULL; U32 i; for (i = 0; i < (U32)sCardProfiles.size(); ++i) if (dStrstr(vendor, sCardProfiles[i].vendor) && (!dStrcmp(sCardProfiles[i].renderer, "*") || dStrstr(renderer, sCardProfiles[i].renderer))) { Con::setBoolVariable("$pref::Video::safeModeOn", sCardProfiles[i].safeMode); Con::setBoolVariable("$pref::OpenGL::disableEXTCompiledVertexArray", !sCardProfiles[i].lockArray); Con::setBoolVariable("$pref::OpenGL::disableSubImage", !sCardProfiles[i].subImage); Con::setBoolVariable("$pref::TS::fogTexture", sCardProfiles[i].fogTexture); Con::setBoolVariable("$pref::OpenGL::noEnvColor", sCardProfiles[i].noEnvColor); Con::setBoolVariable("$pref::Video::clipHigh", sCardProfiles[i].clipHigh); if (!sCardProfiles[i].deleteContext) { OSVERSIONINFO OSVersionInfo; // HACK: The Voodoo3/5 on W2K crash when deleting a rendering context // So we're not deleting it. // Oh, and the Voodoo3 returns a Banshee renderer string under W2K dMemset( &OSVersionInfo, 0, sizeof( OSVERSIONINFO ) ); OSVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); if ( GetVersionEx( &OSVersionInfo ) && OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && OSVersionInfo.dwMajorVersion == 5) Con::setBoolVariable("$pref::Video::deleteContext", false); else Con::setBoolVariable("$pref::Video::deleteContext", true); } else Con::setBoolVariable("$pref::Video::deleteContext", true); Con::setBoolVariable("$pref::OpenGL::disableARBTextureCompression", !sCardProfiles[i].texCompress); Con::setBoolVariable("$pref::Interior::lockArrays", sCardProfiles[i].interiorLock); Con::setBoolVariable("$pref::TS::skipFirstFog", sCardProfiles[i].skipFirstFog); Con::setBoolVariable("$pref::Video::only16", sCardProfiles[i].only16); Con::setBoolVariable("$pref::OpenGL::noDrawArraysAlpha", sCardProfiles[i].noArraysAlpha); proFile = sCardProfiles[i].proFile; break; } // defaults U16 glProfile; if (!proFile) { // no driver GL profile -- make one via weighting GL extensions glProfile = 25; glProfile += gGLState.suppARBMultitexture * 25; glProfile += gGLState.suppLockedArrays * 15; glProfile += gGLState.suppVertexArrayRange * 10; glProfile += gGLState.suppTextureEnvCombine * 5; glProfile += gGLState.suppPackedPixels * 5; glProfile += gGLState.suppTextureCompression * 5; glProfile += gGLState.suppS3TC * 5; glProfile += gGLState.suppFXT1 * 5; Con::setBoolVariable("$pref::Video::safeModeOn", true); Con::setBoolVariable("$pref::OpenGL::disableEXTCompiledVertexArray", false); Con::setBoolVariable("$pref::OpenGL::disableSubImage", false); Con::setBoolVariable("$pref::TS::fogTexture", false); Con::setBoolVariable("$pref::OpenGL::noEnvColor", false); Con::setBoolVariable("$pref::Video::clipHigh", false); Con::setBoolVariable("$pref::Video::deleteContext", true); Con::setBoolVariable("$pref::OpenGL::disableARBTextureCompression", false); Con::setBoolVariable("$pref::Interior::lockArrays", true); Con::setBoolVariable("$pref::TS::skipFirstFog", false); Con::setBoolVariable("$pref::Video::only16", false); Con::setBoolVariable("$pref::OpenGL::noDrawArraysAlpha", false); } Con::setVariable("$pref::Video::profiledVendor", vendor); Con::setVariable("$pref::Video::profiledRenderer", renderer); if (!Con::getBoolVariable("$DisableSystemProfiling") && ( dStrcmp(vendor, Con::getVariable("$pref::Video::defaultsVendor")) || dStrcmp(renderer, Con::getVariable("$pref::Video::defaultsRenderer")) )) { if (proFile) { char settings[64]; dSprintf(settings,64,"%s.cs",proFile); //Con::executef(2, "exec", settings); execScript(settings); } else { U16 adjust; // match clock with profile for (i = 0; i < sNumProcessors; ++i) { adjust = sProcessorProfiles[i].adjust; if (PlatformSystemInfo.processor.mhz < sProcessorProfiles[i].clock) break; } const char *settings; // match performance metric with profile for (i = 0; i < sNumSettings; ++i) { settings = sSettingProfiles[i].settings; if (glProfile+adjust <= sSettingProfiles[i].performance) break; } //Con::executef(2, "exec", settings); execScript(settings); } bool match = false; for (i = 0; i < (U32)sOSCardProfiles.size(); ++i) if (dStrstr(vendor, sOSCardProfiles[i].vendor) && (!dStrcmp(sOSCardProfiles[i].renderer, "*") || dStrstr(renderer, sOSCardProfiles[i].renderer))) { Con::setBoolVariable("$pref::Video::allowOpenGL", sOSCardProfiles[i].allowOpenGL); Con::setBoolVariable("$pref::Video::preferOpenGL", sOSCardProfiles[i].preferOpenGL); match = true; break; } if (!match) { Con::setBoolVariable("$pref::Video::allowOpenGL", true); Con::setBoolVariable("$pref::Video::preferOpenGL", true); } Con::setVariable("$pref::Video::defaultsVendor", vendor); Con::setVariable("$pref::Video::defaultsRenderer", renderer); } clearCardProfiles(); clearOSCardProfiles(); } //------------------------------------------------------------------------------ OpenGLDevice::OpenGLDevice() { initDevice(); } //------------------------------------------------------------------------------ void OpenGLDevice::initDevice() { // Set the device name: mDeviceName = "OpenGL"; // Let Parent enumerate valid resolutions. Parent::initDevice(); } //------------------------------------------------------------------------------ bool OpenGLDevice::activate( U32 width, U32 height, U32 bpp, bool fullScreen ) { Con::printf( "Activating the OpenGL display device..." ); bool needResurrect = false; // If the rendering context exists, delete it: if ( winState.hGLRC ) { Con::printf( "Killing the texture manager..." ); Game->textureKill(); needResurrect = true; Con::printf( "Making the rendering context not current..." ); if ( !dwglMakeCurrent( NULL, NULL ) ) { AssertFatal( false, "OpenGLDevice::activate\ndwglMakeCurrent( NULL, NULL ) failed!" ); return false; } Con::printf( "Deleting the rendering context ..." ); if ( !dwglDeleteContext( winState.hGLRC ) ) { AssertFatal( false, "OpenGLDevice::activate\ndwglDeleteContext failed!" ); return false; } winState.hGLRC = NULL; } // [neo, 5/31/2007 - #3174] if( winState.appMenu ) { DestroyMenu( winState.appMenu ); winState.appMenu = NULL; } // If the window already exists, kill it so we can start fresh: if ( winState.appWindow ) { if ( winState.appDC ) { Con::printf( "Releasing the device context..." ); ReleaseDC( winState.appWindow, winState.appDC ); winState.appDC = NULL; } Con::printf( "Destroying the window..." ); DestroyWindow( winState.appWindow ); winState.appWindow = NULL; } // If OpenGL library already loaded, shut it down and reload it: if ( winState.hinstOpenGL ) GL_Shutdown(); GL_Init( "opengl32", "glu32" ); static bool onceAlready = false; bool profiled = false; if ( !mFullScreenOnly && fullScreen && !onceAlready ) { OSVERSIONINFO OSVersionInfo; // HACK: The Voodoo5 on W2K will only work if the initial rendering // context is windowed. Can you believe this crap? dMemset( &OSVersionInfo, 0, sizeof( OSVERSIONINFO ) ); OSVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); if ( GetVersionEx( &OSVersionInfo ) && OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && OSVersionInfo.dwMajorVersion == 5 ) //MIN_RESOLUTION defined in platformWin32/platformGL.h if ( !setScreenMode( MIN_RESOLUTION_X, MIN_RESOLUTION_Y, bpp, false, true, false ) ) return false; else { const char* vendorString = (const char*) glGetString( GL_VENDOR ); const char* rendererString = (const char*) glGetString( GL_RENDERER ); // only do this for the first session if (!Con::getBoolVariable("$DisableSystemProfiling") && ( dStrcmp(vendorString, Con::getVariable("$pref::Video::profiledVendor")) || dStrcmp(rendererString, Con::getVariable("$pref::Video::profiledRenderer")) )) { profileSystem(vendorString, rendererString); profiled = true; } } onceAlready = true; } // Set the resolution: if ( !setScreenMode( width, height, bpp, ( fullScreen || mFullScreenOnly ), true, false ) ) return false; // Get original gamma ramp mRestoreGamma = GetDeviceGammaRamp(winState.appDC, mOriginalRamp); // Output some driver info to the console: const char* vendorString = (const char*) glGetString( GL_VENDOR ); const char* rendererString = (const char*) glGetString( GL_RENDERER ); const char* versionString = (const char*) glGetString( GL_VERSION ); Con::printf( "OpenGL driver information:" ); if ( vendorString ) Con::printf( " Vendor: %s", vendorString ); if ( rendererString ) Con::printf( " Renderer: %s", rendererString ); if ( versionString ) Con::printf( " Version: %s", versionString ); if ( needResurrect ) { // Reload the textures: Con::printf( "Resurrecting the texture manager..." ); Game->textureResurrect(); } GL_EXT_Init(); Con::setVariable( "$pref::Video::displayDevice", mDeviceName ); // only do this for the first session if (!profiled && !Con::getBoolVariable("$DisableSystemProfiling") && ( dStrcmp(vendorString, Con::getVariable("$pref::Video::profiledVendor")) || dStrcmp(rendererString, Con::getVariable("$pref::Video::profiledRenderer")) )) { profileSystem(vendorString, rendererString); profiled = true; } if (profiled) { U32 width, height, bpp; if (Con::getBoolVariable("$pref::Video::clipHigh", false)) for (S32 i = mResolutionList.size()-1; i >= 0; --i) if (mResolutionList[i].w > 1152 || mResolutionList[i].h > 864) mResolutionList.erase(i); if (Con::getBoolVariable("$pref::Video::only16", false)) for (S32 i = mResolutionList.size()-1; i >= 0; --i) if (mResolutionList[i].bpp == 32) mResolutionList.erase(i); bool bPrefFullScreen = Con::getBoolVariable("$pref::Video::fullScreen", true); if( bPrefFullScreen || fullScreen ) dSscanf(Con::getVariable("$pref::Video::resolution"), "%d %d %d", &width, &height, &bpp); else dSscanf(Con::getVariable("$pref::Video::windowedRes"), "%d %d %d", &width, &height, &bpp); setScreenMode(width, height, bpp, bPrefFullScreen || fullScreen, false, false); } // Do this here because we now know about the extensions: if ( gGLState.suppSwapInterval ) setVerticalSync( !Con::getBoolVariable( "$pref::Video::disableVerticalSync" ) ); Con::setBoolVariable("$pref::OpenGL::allowTexGen", true); return true; } //------------------------------------------------------------------------------ void OpenGLDevice::shutdown() { Con::printf( "Shutting down the OpenGL display device..." ); if ( winState.hGLRC ) { if (mRestoreGamma) SetDeviceGammaRamp(winState.appDC, mOriginalRamp); Con::printf( "Making the GL rendering context not current..." ); dwglMakeCurrent( NULL, NULL ); if ( Con::getBoolVariable("$pref::Video::deleteContext", true) ) { Con::printf( "Deleting the GL rendering context..." ); dwglDeleteContext( winState.hGLRC ); } winState.hGLRC = NULL; } if ( winState.appDC ) { Con::printf( "Releasing the device context..." ); ReleaseDC( winState.appWindow, winState.appDC ); winState.appDC = NULL; } if ( smIsFullScreen ) { Con::printf( "Restoring the desktop display settings (%dx%dx%d)...", winState.desktopWidth, winState.desktopHeight, winState.desktopBitsPixel ); ChangeDisplaySettings( NULL, 0 ); } } //------------------------------------------------------------------------------ // This is the real workhorse function of the DisplayDevice... // bool OpenGLDevice::setScreenMode( U32 width, U32 height, U32 bpp, bool fullScreen, bool forceIt, bool repaint ) { HWND curtain = NULL; char errorMessage[256]; Resolution newRes( width, height, bpp ); bool newFullScreen = fullScreen; bool safeModeOn = Con::getBoolVariable( "$pref::Video::safeModeOn" ); if ( !newFullScreen && mFullScreenOnly ) { Con::warnf( ConsoleLogEntry::General, "OpenGLDevice::setScreenMode - device or desktop color depth does not allow windowed mode!" ); newFullScreen = true; } if ( !newFullScreen && ( (S32)newRes.w >= winState.desktopClientWidth || (S32)newRes.h >= winState.desktopClientHeight ) ) { Con::warnf( ConsoleLogEntry::General, "OpenGLDevice::setScreenMode -- can't switch to resolution larger than desktop in windowed mode!" ); S32 resIndex = 0; S32 bestScore = 0, thisScore = 0; for ( S32 i = 0; i < mResolutionList.size(); i++ ) { if ( newRes == mResolutionList[i] ) { resIndex = i; break; } else if( (S32)newRes.h <= winState.desktopClientHeight && (S32)newRes.w <= winState.desktopClientWidth ) { thisScore = abs( S32( newRes.w ) - S32( mResolutionList[i].w ) ) + abs( S32( newRes.h ) - S32( mResolutionList[i].h ) ) + ( newRes.bpp == mResolutionList[i].bpp ? 0 : 1 ); if ( !bestScore || ( thisScore < bestScore ) ) { bestScore = thisScore; resIndex = i; } } } } //MIN_RESOLUTION defined in platformWin32/platformGL.h if ( newRes.w < MIN_RESOLUTION_X || newRes.h < MIN_RESOLUTION_Y ) { Con::warnf( ConsoleLogEntry::General, "OpenGLDevice::setScreenMode -- can't go smaller than 640x480!" ); return false; } if ( newFullScreen ) { if (newRes.bpp != 16 && mFullScreenOnly) newRes.bpp = 16; // Match the new resolution to one in the list: U32 resIndex = 0; U32 bestScore = 0, thisScore = 0; for ( int i = 0; i < mResolutionList.size(); i++ ) { if ( newRes == mResolutionList[i] ) { resIndex = i; break; } else { thisScore = abs( S32( newRes.w ) - S32( mResolutionList[i].w ) ) + abs( S32( newRes.h ) - S32( mResolutionList[i].h ) ) + ( newRes.bpp == mResolutionList[i].bpp ? 0 : 1 ); if ( !bestScore || ( thisScore < bestScore ) ) { bestScore = thisScore; resIndex = i; } } } newRes = mResolutionList[resIndex]; } else { // Basically ignore the bit depth parameter: newRes.bpp = winState.desktopBitsPixel; } // Return if already at this resolution: if ( !forceIt && newRes == smCurrentRes && newFullScreen == smIsFullScreen ) return true; Con::printf( "Setting screen mode to %dx%dx%d (%s)...", newRes.w, newRes.h, newRes.bpp, ( newFullScreen ? "fs" : "w" ) ); bool needResurrect = false; if ( ( newRes.bpp != smCurrentRes.bpp ) || ( safeModeOn && ( ( smIsFullScreen != newFullScreen ) || newFullScreen ) ) ) { // Delete the rendering context: if ( winState.hGLRC ) { if (!Video::smNeedResurrect) { Con::printf( "Killing the texture manager..." ); Game->textureKill(); needResurrect = true; } Con::printf( "Making the rendering context not current..." ); if ( !dwglMakeCurrent( NULL, NULL ) ) { AssertFatal( false, "OpenGLDevice::setScreenMode\ndwglMakeCurrent( NULL, NULL ) failed!" ); return false; } Con::printf( "Deleting the rendering context..." ); if ( Con::getBoolVariable("$pref::Video::deleteContext",true) && !dwglDeleteContext( winState.hGLRC ) ) { AssertFatal( false, "OpenGLDevice::setScreenMode\ndwglDeleteContext failed!" ); return false; } winState.hGLRC = NULL; } // Release the device context: if ( winState.appDC ) { Con::printf( "Releasing the device context..." ); ReleaseDC( winState.appWindow, winState.appDC ); winState.appDC = NULL; } // [neo, 5/31/2007 - #3174] if( winState.appMenu ) { DestroyMenu( winState.appMenu ); winState.appMenu = NULL; } // Destroy the window: if ( winState.appWindow ) { Con::printf( "Destroying the window..." ); DestroyWindow( winState.appWindow ); winState.appWindow = NULL; } } else if ( smIsFullScreen != newFullScreen ) { // Change the window style: Con::printf( "Changing the window style..." ); S32 windowStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS; if ( newFullScreen ) windowStyle |= ( WS_MAXIMIZE | WS_VISIBLE); else windowStyle |= ( WS_OVERLAPPEDWINDOW ); if ( winState.appWindow && !SetWindowLong( winState.appWindow, GWL_STYLE, windowStyle ) ) Con::errorf( "SetWindowLong failed to change the window style!" ); } if( winState.appWindow && !newFullScreen ) ShowWindow( winState.appWindow, SW_NORMAL ); else ShowWindow( winState.appWindow, SW_MAXIMIZE ); U32 test; if ( newFullScreen ) { // Change the display settings: DEVMODE devMode; dMemset( &devMode, 0, sizeof( devMode ) ); devMode.dmSize = sizeof( devMode ); devMode.dmPelsWidth = newRes.w; devMode.dmPelsHeight = newRes.h; devMode.dmBitsPerPel = newRes.bpp; devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; Con::printf( "Changing the display settings to %dx%dx%d...", newRes.w, newRes.h, newRes.bpp ); curtain = CreateCurtain( newRes.w, newRes.h ); test = ChangeDisplaySettings( &devMode, CDS_FULLSCREEN ); if ( test != DISP_CHANGE_SUCCESSFUL ) { smIsFullScreen = false; Con::setBoolVariable( "$pref::Video::fullScreen", false ); ChangeDisplaySettings( NULL, 0 ); Con::errorf( ConsoleLogEntry::General, "OpenGLDevice::setScreenMode - ChangeDisplaySettings failed." ); switch( test ) { case DISP_CHANGE_RESTART: Platform::AlertOK( "Display Change Failed", "You must restart your machine to get the specified mode." ); break; case DISP_CHANGE_BADMODE: Platform::AlertOK( "Display Change Failed", "The specified mode is not supported by this device." ); break; default: Platform::AlertOK( "Display Change Failed", "Hardware failed to switch to the specified mode." ); break; }; DestroyWindow( curtain ); return false; } else smIsFullScreen = true; } else if ( smIsFullScreen ) { Con::printf( "Changing to the desktop display settings (%dx%dx%d)...", winState.desktopWidth, winState.desktopHeight, winState.desktopBitsPixel ); ChangeDisplaySettings( NULL, 0 ); smIsFullScreen = false; } Con::setBoolVariable( "$pref::Video::fullScreen", smIsFullScreen ); bool newWindow = false; if ( !winState.appWindow ) { Con::printf( "Creating a new %swindow...", ( fullScreen ? "full-screen " : "" ) ); winState.appWindow = CreateOpenGLWindow( newRes.w, newRes.h, newFullScreen, true ); if ( !winState.appWindow ) { AssertFatal( false, "OpenGLDevice::setScreenMode\nFailed to create a new window!" ); return false; } newWindow = true; } // Move the window: if ( !newFullScreen ) { // Adjust the window rect to compensate for the window style: RECT windowRect; windowRect.left = windowRect.top = 0; windowRect.right = newRes.w; windowRect.bottom = newRes.h; AdjustWindowRect( &windowRect, GetWindowLong( winState.appWindow, GWL_STYLE ), false ); U32 adjWidth = windowRect.right - windowRect.left; U32 adjHeight = windowRect.bottom - windowRect.top; // Center the window on the desktop: U32 xPos = 0, yPos = 0; if(adjWidth < (U32)winState.desktopClientWidth) xPos = ( winState.desktopClientWidth - adjWidth ) / 2; if(adjHeight < (U32)winState.desktopClientHeight) yPos = ( winState.desktopClientHeight - adjHeight ) / 2; test = SetWindowPos( winState.appWindow, 0, xPos, yPos, adjWidth, adjHeight, SWP_NOZORDER ); if ( !test ) { dSprintf( errorMessage, 255, "OpenGLDevice::setScreenMode\nSetWindowPos failed trying to move the window to (%d,%d) and size it to %dx%d.", xPos, yPos, newRes.w, newRes.h ); AssertFatal( false, errorMessage ); return false; } AnimateWindow( winState.appWindow, 90, AW_BLEND ); } else if ( !newWindow ) { // Move and size the window to take up the whole screen: if ( !SetWindowPos( winState.appWindow, HWND_TOPMOST, 0, 0, newRes.w, newRes.h, SWP_NOACTIVATE) || !SetWindowPos( winState.appWindow, HWND_TOPMOST, 0, 0, newRes.w, newRes.h, SWP_NOZORDER) ) { dSprintf( errorMessage, 255, "OpenGLDevice::setScreenMode\nSetWindowPos failed to move the window to (0,0) and size it to %dx%d.", newRes.w, newRes.h ); AssertFatal( false, errorMessage ); return false; } } bool newDeviceContext = false; if ( !winState.appDC ) { // Get a new device context: Con::printf( "Acquiring a new device context..." ); winState.appDC = GetDC( winState.appWindow ); if ( !winState.appDC ) { AssertFatal( false, "OpenGLDevice::setScreenMode\nGetDC failed to get a valid device context!" ); return false; } newDeviceContext = true; } if ( newWindow ) { // Set the pixel format of the new window: PIXELFORMATDESCRIPTOR pfd; CreatePixelFormat( &pfd, newRes.bpp, 24, 8, false ); S32 chosenFormat = ChooseBestPixelFormat( winState.appDC, &pfd ); if ( !chosenFormat ) { AssertFatal( false, "OpenGLDevice::setScreenMode\nNo valid pixel formats found!" ); return false; } dwglDescribePixelFormat( winState.appDC, chosenFormat, sizeof( pfd ), &pfd ); if ( !SetPixelFormat( winState.appDC, chosenFormat, &pfd ) ) { AssertFatal( false, "OpenGLDevice::setScreenMode\nFailed to set the pixel format!" ); return false; } Con::printf( "Pixel format set:" ); Con::printf( " %d color bits, %d depth bits, %d stencil bits", pfd.cColorBits, pfd.cDepthBits, pfd.cStencilBits ); } if ( !winState.hGLRC ) { // Create a new rendering context: Con::printf( "Creating a new rendering context..." ); winState.hGLRC = dwglCreateContext( winState.appDC ); if ( !winState.hGLRC ) { AssertFatal( false, "OpenGLDevice::setScreenMode\ndwglCreateContext failed to create an OpenGL rendering context!" ); return false; } // Make the new rendering context current: Con::printf( "Making the new rendering context current..." ); if ( !dwglMakeCurrent( winState.appDC, winState.hGLRC ) ) { AssertFatal( false, "OpenGLDevice::setScreenMode\ndwglMakeCurrent failed to make the rendering context current!" ); return false; } // Just for kicks. Seems a relatively central place to put this... glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if ( needResurrect ) { // Reload the textures: Con::printf( "Resurrecting the texture manager..." ); Game->textureResurrect(); } } // Just for kicks. Seems a relatively central place to put this... glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if ( newDeviceContext && gGLState.suppSwapInterval ) setVerticalSync( !Con::getBoolVariable( "$pref::Video::disableVerticalSync" ) ); smCurrentRes = newRes; Platform::setWindowSize( newRes.w, newRes.h ); char tempBuf[15]; dSprintf( tempBuf, sizeof( tempBuf ), "%d %d %d", smCurrentRes.w, smCurrentRes.h, smCurrentRes.bpp ); if( fullScreen ) Con::setVariable( "$pref::Video::resolution", tempBuf ); else Con::setVariable( "$pref::Video::windowedRes", tempBuf ); if ( curtain ) DestroyWindow( curtain ); // Doesn't hurt to do this even it isn't necessary: ShowWindow( winState.appWindow, SW_SHOW ); SetForegroundWindow( winState.appWindow ); SetFocus( winState.appWindow ); if (newFullScreen) { // Doesn't hurt to do this an extra time, and seems to help in some cases if ( !SetWindowPos( winState.appWindow, HWND_TOPMOST, 0, 0, newRes.w, newRes.h, SWP_NOACTIVATE) || !SetWindowPos( winState.appWindow, HWND_TOPMOST, 0, 0, newRes.w, newRes.h, SWP_NOZORDER) ) { dSprintf( errorMessage, 255, "OpenGLDevice::setScreenMode\nSetWindowPos failed to move the window to (0,0) and size it to %dx%d.", newRes.w, newRes.h ); AssertFatal( false, errorMessage ); return false; } } //Luma: Clear window at first, as it is showing previous gl color buffer stuff. glClearColor(0.0f,0.0f,0.0f,0.0f); glClear(GL_COLOR_BUFFER_BIT); if ( repaint ) Con::evaluate( "resetCanvas();" ); return true; } //------------------------------------------------------------------------------ void OpenGLDevice::swapBuffers() { dwglSwapBuffers( winState.appDC ); } //------------------------------------------------------------------------------ const char* OpenGLDevice::getDriverInfo() { // Output some driver info to the console: const char* vendorString = (const char*) glGetString( GL_VENDOR ); const char* rendererString = (const char*) glGetString( GL_RENDERER ); const char* versionString = (const char*) glGetString( GL_VERSION ); const char* extensionsString = (const char*) glGetString( GL_EXTENSIONS ); U32 bufferLen = ( vendorString ? dStrlen( vendorString ) : 0 ) + ( rendererString ? dStrlen( rendererString ) : 0 ) + ( versionString ? dStrlen( versionString ) : 0 ) + ( extensionsString ? dStrlen( extensionsString ) : 0 ) + 4; char* returnString = Con::getReturnBuffer( bufferLen ); dSprintf( returnString, bufferLen, "%s\t%s\t%s\t%s", ( vendorString ? vendorString : "" ), ( rendererString ? rendererString : "" ), ( versionString ? versionString : "" ), ( extensionsString ? extensionsString : "" ) ); return( returnString ); } //------------------------------------------------------------------------------ bool OpenGLDevice::getGammaCorrection(F32 &g) { U16 ramp[256*3]; if (!GetDeviceGammaRamp(winState.appDC, ramp)) return false; F32 csum = 0.0; U32 ccount = 0; for (U16 i = 0; i < 256; ++i) { if (i != 0 && ramp[i] != 0 && ramp[i] != 65535) { F64 b = (F64) i/256.0; F64 a = (F64) ramp[i]/65535.0; F32 c = (F32) (mLog(a)/mLog(b)); csum += c; ++ccount; } } g = csum/ccount; return true; } //------------------------------------------------------------------------------ bool OpenGLDevice::setGammaCorrection(F32 g) { U16 ramp[256*3]; for (U16 i = 0; i < 256; ++i) ramp[i] = (U16)((U16)mPow((F32) i/256.0f, g) * 65535.0f); dMemcpy(&ramp[256],ramp,256*sizeof(U16)); dMemcpy(&ramp[512],ramp,256*sizeof(U16)); return SetDeviceGammaRamp(winState.appDC, ramp); } //------------------------------------------------------------------------------ bool OpenGLDevice::setVerticalSync( bool on ) { if ( !gGLState.suppSwapInterval ) return( false ); return( dwglSwapIntervalEXT( on ? 1 : 0 ) ); } //------------------------------------------------------------------------------ DisplayDevice* OpenGLDevice::create() { // Get Bit Depth Switching Info. enumerateBitDepths(); bool result = false; bool fullScreenOnly = false; //------------------------------------------------------------------------------ // This shouldn't happen, but just to be safe... //------------------------------------------------------------------------------ if ( winState.hinstOpenGL ) GL_Shutdown(); //------------------------------------------------------------------------------ // Initialize GL //------------------------------------------------------------------------------ if (!GL_Init( "opengl32", "glu32" )) return NULL; //------------------------------------------------------------------------------ // Create a test window to see if OpenGL hardware acceleration is available: //------------------------------------------------------------------------------ WNDCLASS wc; dMemset(&wc, 0, sizeof(wc)); wc.style = CS_OWNDC; wc.lpfnWndProc = DefWindowProc; wc.hInstance = winState.appInstance; wc.lpszClassName = dT("OGLTest"); RegisterClass( &wc ); //------------------------------------------------------------------------------ // Create the Test Window //------------------------------------------------------------------------------ //MIN_RESOLUTION defined in platformWin32/platformGL.h HWND testWindow = CreateWindow( dT("OGLTest"),dT(""), WS_POPUP, 0, 0, MIN_RESOLUTION_X, MIN_RESOLUTION_Y, NULL, NULL, winState.appInstance, NULL ); if ( !testWindow ) { // Unregister the Window Class UnregisterClass( dT("OGLTest"), winState.appInstance ); // Shutdown GL GL_Shutdown(); // Return Failure return NULL; } //------------------------------------------------------------------------------ // Attempt to Grab a handle to the DeviceContext of our window. //------------------------------------------------------------------------------ HDC testDC = GetDC( testWindow ); if ( !testDC ) { // Destroy the Window DestroyWindow( testWindow ); // Unregister the Window Class UnregisterClass( dT("OGLTest"), winState.appInstance ); // Shutdown GL GL_Shutdown(); // Return Failure. return NULL; } //------------------------------------------------------------------------------ // Create Pixel Format ( Default 16bpp ) //------------------------------------------------------------------------------ PIXELFORMATDESCRIPTOR pfd; CreatePixelFormat( &pfd, 16, 16, 8, false ); U32 chosenFormat = ChooseBestPixelFormat( testDC, &pfd ); if ( chosenFormat != 0 ) { dwglDescribePixelFormat( testDC, chosenFormat, sizeof( pfd ), &pfd ); result = !( pfd.dwFlags & PFD_GENERIC_FORMAT ); if ( result && winState.desktopBitsPixel < 16 && !smCanDo32Bit) { // If Windows 95 cannot switch bit depth, it should only attempt 16-bit cards // with a 16-bit desktop // See if we can get a 32-bit pixel format: PIXELFORMATDESCRIPTOR pfd; CreatePixelFormat( &pfd, 32, 24, 8, false ); S32 chosenFormat = ChooseBestPixelFormat( testDC, &pfd ); if ( chosenFormat != 0 ) { dwglDescribePixelFormat( winState.appDC, chosenFormat, sizeof( pfd ), &pfd ); if (pfd.cColorBits == 16) { Platform::AlertOK("Requires 16-Bit Desktop", "You must run in 16-bit color to run a Torque game.\nPlease quit the game, set your desktop color depth to 16-bit\nand then restart the application."); result = false; } } } } else if ( winState.desktopBitsPixel < 16 && smCanSwitchBitDepth ) { // Try again after changing the display to 16-bit: ReleaseDC( testWindow, testDC ); DestroyWindow( testWindow ); DEVMODE devMode; dMemset( &devMode, 0, sizeof( devMode ) ); devMode.dmSize = sizeof( devMode ); devMode.dmBitsPerPel = 16; devMode.dmFields = DM_BITSPERPEL; U32 test = ChangeDisplaySettings( &devMode, 0 ); if ( test == DISP_CHANGE_SUCCESSFUL ) { //MIN_RESOLUTION defined in platformWin32/platformGL.h testWindow = CreateWindow( dT("OGLTest"), dT(""), WS_OVERLAPPED | WS_CAPTION, 0, 0, MIN_RESOLUTION_X, MIN_RESOLUTION_Y, NULL, NULL, winState.appInstance, NULL ); if ( testWindow ) { testDC = GetDC( testWindow ); if ( testDC ) { CreatePixelFormat( &pfd, 16, 16, 8, false ); chosenFormat = ChooseBestPixelFormat( testDC, &pfd ); if ( chosenFormat != 0 ) { dwglDescribePixelFormat( testDC, chosenFormat, sizeof( pfd ), &pfd ); result = !( pfd.dwFlags & PFD_GENERIC_FORMAT ); if ( result ) fullScreenOnly = true; } } } } ChangeDisplaySettings( NULL, 0 ); } //------------------------------------------------------------------------------ // Can't do even 16 bit, alert user they need to upgrade. //------------------------------------------------------------------------------ else if ( winState.desktopBitsPixel < 16 && !smCanSwitchBitDepth ) { Platform::AlertOK("Requires 16-Bit Desktop", "You must run in 16-bit color to run a Torque game.\nPlease quit the game, set your desktop color depth to 16-bit\nand then restart the application."); } ReleaseDC( testWindow, testDC ); DestroyWindow( testWindow ); UnregisterClass( dT("OGLTest"), winState.appInstance ); GL_Shutdown(); if ( result ) { OpenGLDevice* newOGLDevice = new OpenGLDevice(); if ( newOGLDevice ) { newOGLDevice->mFullScreenOnly = fullScreenOnly; return (DisplayDevice*) newOGLDevice; } else return NULL; } else return NULL; }