1254 lines
42 KiB
C++
Executable File
1254 lines
42 KiB
C++
Executable File
//-----------------------------------------------------------------------------
|
|
// Torque Game Engine
|
|
// Copyright (C) GarageGames.com, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "platformWin32/platformGL.h"
|
|
#include "platformWin32/platformWin32.h"
|
|
#include "platform/platformAudio.h"
|
|
#include "platformWin32/winOGLVideo.h"
|
|
#include "platformWin32/winD3DVideo.h"
|
|
#include "console/console.h"
|
|
#include "math/mPoint.h"
|
|
#include "platform/event.h"
|
|
#include "platform/gameInterface.h"
|
|
#include "console/consoleInternal.h"
|
|
#include "console/ast.h"
|
|
#include "core/fileStream.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
bool OpenGLDevice::smCanSwitchBitDepth = true;
|
|
|
|
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 allowD3D; // allow D3D driver
|
|
bool preferOpenGL; // prefer OpenGL driver
|
|
};
|
|
|
|
static Vector<CardProfile> sCardProfiles(__FILE__, __LINE__);
|
|
static Vector<OSCardProfile> sOSCardProfiles(__FILE__, __LINE__);
|
|
|
|
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" },
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
ConsoleFunction( addCardProfile, void, 16, 16, "(string vendor, string renderer,"
|
|
"bool safeMode, bool lockArray, bool subImage, bool fogTexture,"
|
|
"bool noEnvColor, bool clipHigh, bool deleteContext, bool texCompress"
|
|
"bool interiorLock, bool skipFirstFog, bool only16,"
|
|
"bool noArraysAlpha, string proFile)"
|
|
""
|
|
"Register a card profile with the card profile manager.\n\n"
|
|
"Most of the parameters are fairly self-explanatory and very internal"
|
|
" to the rendering code; however there are a few of note:\n"
|
|
"@param vendor The vendor string the card claims.\n"
|
|
"@param renderer The renderer string the card claims.\n"
|
|
"@param proFile Name of the file where further configuration information is kept."
|
|
)
|
|
{
|
|
CardProfile profile;
|
|
|
|
profile.vendor = dStrdup(argv[1]);
|
|
profile.renderer = dStrdup(argv[2]);
|
|
|
|
profile.safeMode = dAtob(argv[3]);
|
|
profile.lockArray = dAtob(argv[4]);
|
|
profile.subImage = dAtob(argv[5]);
|
|
profile.fogTexture = dAtob(argv[6]);
|
|
profile.noEnvColor = dAtob(argv[7]);
|
|
profile.clipHigh = dAtob(argv[8]);
|
|
profile.deleteContext = dAtob(argv[9]);
|
|
profile.texCompress = dAtob(argv[10]);
|
|
profile.interiorLock = dAtob(argv[11]);
|
|
profile.skipFirstFog = dAtob(argv[12]);
|
|
profile.only16 = dAtob(argv[13]);
|
|
profile.noArraysAlpha = dAtob(argv[14]);
|
|
|
|
if (strcmp(argv[15],""))
|
|
profile.proFile = dStrdup(argv[15]);
|
|
else
|
|
profile.proFile = NULL;
|
|
|
|
sCardProfiles.push_back(profile);
|
|
}
|
|
|
|
ConsoleFunction( addOSCardProfile, void, 6,6, "(string vendor, string renderer, bool allowOpenGL,"
|
|
" bool allowD3D, bool preferOpenGL) "
|
|
"Register with the profile manager what rendering mode is preferred with the "
|
|
"specified card.")
|
|
{
|
|
OSCardProfile profile;
|
|
|
|
profile.vendor = dStrdup(argv[1]);
|
|
profile.renderer = dStrdup(argv[2]);
|
|
|
|
profile.allowOpenGL = dAtob(argv[3]);
|
|
profile.allowD3D = dAtob(argv[4]);
|
|
profile.preferOpenGL = dAtob(argv[5]);
|
|
|
|
sOSCardProfiles.push_back(profile);
|
|
}
|
|
|
|
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(Platform::SystemInfo.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 < 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 (Platform::SystemInfo.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 < 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::allowD3D", sOSCardProfiles[i].allowD3D);
|
|
Con::setBoolVariable("$pref::Video::preferOpenGL", sOSCardProfiles[i].preferOpenGL);
|
|
|
|
match = true;
|
|
|
|
break;
|
|
}
|
|
|
|
if (!match)
|
|
{
|
|
Con::setBoolVariable("$pref::Video::allowOpenGL", true);
|
|
Con::setBoolVariable("$pref::Video::allowD3D", 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";
|
|
|
|
// Set some initial conditions:
|
|
mResolutionList.clear();
|
|
|
|
// Enumerate all available resolutions:
|
|
DEVMODE devMode;
|
|
U32 modeNum = 0;
|
|
U32 stillGoing = true;
|
|
while ( stillGoing )
|
|
{
|
|
dMemset( &devMode, 0, sizeof( devMode ) );
|
|
devMode.dmSize = sizeof( devMode );
|
|
|
|
stillGoing = EnumDisplaySettings( NULL, modeNum++, &devMode );
|
|
|
|
// if ( devMode.dmPelsWidth >= 640 && devMode.dmPelsHeight >= 480
|
|
if ( devMode.dmPelsWidth >= 480 && devMode.dmPelsHeight >= 360
|
|
&& ( devMode.dmBitsPerPel == 16 || devMode.dmBitsPerPel == 32 ) &&
|
|
( smCanSwitchBitDepth || devMode.dmBitsPerPel == winState.desktopBitsPixel ) )
|
|
{
|
|
// Only add this resolution if it is not already in the list:
|
|
bool alreadyInList = false;
|
|
for ( U32 i = 0; i < mResolutionList.size(); i++ )
|
|
{
|
|
if ( devMode.dmPelsWidth == mResolutionList[i].w
|
|
&& devMode.dmPelsHeight == mResolutionList[i].h
|
|
&& devMode.dmBitsPerPel == mResolutionList[i].bpp )
|
|
{
|
|
alreadyInList = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !alreadyInList )
|
|
{
|
|
Resolution newRes( devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel );
|
|
mResolutionList.push_back( newRes );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
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;
|
|
}
|
|
|
|
// 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 )
|
|
if ( !setScreenMode( 640, 480, 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);
|
|
|
|
dSscanf(Con::getVariable("$pref::Video::resolution"), "%d %d %d", &width, &height, &bpp);
|
|
setScreenMode(width, height, bpp,
|
|
Con::getBoolVariable("$pref::Video::fullScreen", true), 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;
|
|
}
|
|
|
|
// Destroy the window:
|
|
if ( winState.appWindow )
|
|
{
|
|
Con::printf( "Destroying the window..." );
|
|
DestroyWindow( winState.appWindow );
|
|
winState.appWindow = 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 && ( newRes.w >= winState.desktopWidth || newRes.h >= winState.desktopHeight ) )
|
|
{
|
|
Con::warnf( ConsoleLogEntry::General, "OpenGLDevice::setScreenMode -- can't switch to resolution larger than desktop in windowed mode!" );
|
|
// Find the largest standard resolution that will fit on the desktop:
|
|
U32 resIndex;
|
|
for ( resIndex = mResolutionList.size() - 1; resIndex > 0; resIndex-- )
|
|
{
|
|
if ( mResolutionList[resIndex].w < winState.desktopWidth
|
|
&& mResolutionList[resIndex].h < winState.desktopHeight )
|
|
break;
|
|
}
|
|
newRes = mResolutionList[resIndex];
|
|
}
|
|
|
|
if ( newRes.w < 480 || newRes.h < 360 )
|
|
{
|
|
Con::warnf( ConsoleLogEntry::General, "OpenGLDevice::setScreenMode -- can't go smaller than 480x360!" );
|
|
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;
|
|
}
|
|
|
|
// 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_POPUP | WS_MAXIMIZE | WS_VISIBLE);
|
|
else
|
|
windowStyle |= ( WS_OVERLAPPED | WS_CAPTION );
|
|
|
|
if ( winState.appWindow && !SetWindowLong( winState.appWindow, GWL_STYLE, windowStyle ) )
|
|
Con::errorf( "SetWindowLong failed to change the window style!" );
|
|
}
|
|
|
|
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 );
|
|
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 < winState.desktopWidth)
|
|
xPos = ( winState.desktopWidth - adjWidth ) / 2;
|
|
|
|
if(adjHeight < winState.desktopHeight)
|
|
yPos = ( winState.desktopHeight - 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;
|
|
}
|
|
}
|
|
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 );
|
|
Con::setVariable( "$pref::Video::resolution", 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;
|
|
}
|
|
}
|
|
|
|
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] = 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()
|
|
{
|
|
bool result = false;
|
|
bool fullScreenOnly = false;
|
|
|
|
OSVERSIONINFO OSVersionInfo;
|
|
U32 switchedNT = false;
|
|
|
|
dMemset( &OSVersionInfo, 0, sizeof( OSVERSIONINFO ) );
|
|
OSVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
|
|
if ( GetVersionEx( &OSVersionInfo ) &&
|
|
OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
|
|
{
|
|
DEVMODE devMode;
|
|
|
|
dMemset( &devMode, 0, sizeof( devMode ) );
|
|
devMode.dmSize = sizeof( devMode );
|
|
devMode.dmBitsPerPel = winState.desktopBitsPixel == 16 ? 32 : 16;
|
|
devMode.dmFields = DM_BITSPERPEL;
|
|
|
|
// attempt bit-depth change to test Windows 95B
|
|
if ( ChangeDisplaySettings( &devMode, CDS_TEST ) != DISP_CHANGE_SUCCESSFUL )
|
|
smCanSwitchBitDepth = false;
|
|
}
|
|
// switching NT to 32-bit desktop to determine if we have a 16-bit card
|
|
else if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
|
OSVersionInfo.dwMajorVersion == 4 &&
|
|
winState.desktopBitsPixel != 32)
|
|
{
|
|
DEVMODE devMode;
|
|
|
|
dMemset( &devMode, 0, sizeof( devMode ) );
|
|
devMode.dmSize = sizeof( devMode );
|
|
devMode.dmBitsPerPel = 32;
|
|
devMode.dmFields = DM_BITSPERPEL;
|
|
|
|
switchedNT = ChangeDisplaySettings( &devMode, 0 ) == DISP_CHANGE_SUCCESSFUL;
|
|
}
|
|
|
|
// This shouldn't happen, but just to be safe...
|
|
if ( winState.hinstOpenGL )
|
|
GL_Shutdown();
|
|
|
|
if (!GL_Init( "opengl32", "glu32" ))
|
|
{
|
|
if (switchedNT)
|
|
ChangeDisplaySettings( NULL, 0 );
|
|
|
|
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 );
|
|
|
|
HWND testWindow = CreateWindow(
|
|
dT("OGLTest"),
|
|
dT(""),
|
|
WS_POPUP,
|
|
0, 0, 640, 480,
|
|
NULL,
|
|
NULL,
|
|
winState.appInstance,
|
|
NULL );
|
|
|
|
if ( testWindow )
|
|
{
|
|
HDC testDC = GetDC( testWindow );
|
|
if ( testDC )
|
|
{
|
|
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 || pfd.cColorBits == 16) )
|
|
D3DDevice::smStay16 = true;
|
|
|
|
if ( result && winState.desktopBitsPixel != 16 && !smCanSwitchBitDepth)
|
|
{
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
// Don't allow 16-bit cards to do windowed mode on NT
|
|
else if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
|
OSVersionInfo.dwMajorVersion == 4 &&
|
|
result && pfd.cColorBits == 16)
|
|
fullScreenOnly = true;
|
|
}
|
|
else if ( (winState.desktopBitsPixel != 16 || switchedNT) && 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 )
|
|
{
|
|
testWindow = CreateWindow(
|
|
dT("OGLTest"),
|
|
dT(""),
|
|
WS_OVERLAPPED | WS_CAPTION,
|
|
0, 0, 640, 480,
|
|
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 );
|
|
switchedNT = false;
|
|
}
|
|
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();
|
|
|
|
// Return NT to previous desktop bit depth
|
|
if (switchedNT)
|
|
ChangeDisplaySettings( NULL, 0 );
|
|
|
|
if ( result )
|
|
{
|
|
OpenGLDevice* newOGLDevice = new OpenGLDevice();
|
|
if ( newOGLDevice )
|
|
{
|
|
newOGLDevice->mFullScreenOnly = fullScreenOnly;
|
|
return (DisplayDevice*) newOGLDevice;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|