tge/engine/platformWin32/winV2Video.cc
2017-04-17 06:17:10 -06:00

664 lines
21 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/winV2Video.h"
#include "platform/3Dfx.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"
static U8 sResCode; // Used for initializing the resolution list only
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;
}
//------------------------------------------------------------------------------
Voodoo2Device::Voodoo2Device()
{
initDevice();
}
//------------------------------------------------------------------------------
void Voodoo2Device::initDevice()
{
// Set the device name:
mDeviceName = "Voodoo2";
// Set some initial conditions:
mResolutionList.clear();
mFullScreenOnly = true;
// Enumerate all available resolutions:
Resolution newRes;
newRes = Resolution( 640, 480, 16 );
mResolutionList.push_back( newRes );
if ( sResCode & 1 )
{
newRes = Resolution( 800, 600, 16 );
mResolutionList.push_back( newRes );
}
if ( sResCode & 2 )
{
Con::printf( "SLI detected." );
newRes = Resolution( 960, 720, 16 );
mResolutionList.push_back( newRes );
newRes = Resolution( 1024, 768, 16 );
mResolutionList.push_back( newRes );
}
}
//------------------------------------------------------------------------------
bool Voodoo2Device::activate( U32 width, U32 height, U32 /*bpp*/, bool /*fullScreen*/ )
{
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, "Voodoo2Device::activate\ndwglMakeCurrent( NULL, NULL ) failed!" );
return false;
}
Con::printf( "Deleting the rendering context..." );
if ( !dwglDeleteContext( winState.hGLRC ) )
{
AssertFatal( false, "Voodoo2Device::activate\ndwglDeleteContext failed!" );
return false;
}
winState.hGLRC = NULL;
}
// If window already exists, kill it so we can start fresh:
if ( winState.appWindow )
{
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 the 3Dfx standalone driver:
if ( winState.hinstOpenGL )
GL_Shutdown();
GL_Init( "3dfxvgl", "glu32" );
// This device only supports full-screen, so force it:
smIsFullScreen = true;
Con::setVariable( "$pref::Video::fullScreen", "true" );
// Create the new window:
Con::printf( "Creating a new full-screen window..." );
winState.appWindow = CreateOpenGLWindow( width, height, true );
if ( !winState.appWindow )
{
AssertFatal( false, "Voodoo2Device::activate\nFailed to create a window!" );
return false;
}
// Get a device context from the new window:
HDC tempDC = GetDC( winState.appWindow );
if ( !tempDC )
{
AssertFatal( false, "Voodoo2Device::activate\nFailed to get a device context!" );
return false;
}
// Set the pixel format of the new window:
PIXELFORMATDESCRIPTOR pfd;
CreatePixelFormat( &pfd, 16, 16, 8, false );
S32 chosenFormat = ChooseBestPixelFormat( tempDC, &pfd );
dwglDescribePixelFormat( tempDC, chosenFormat, sizeof( pfd ), &pfd );
bool test = dwglSetPixelFormat( tempDC, chosenFormat, &pfd );
ReleaseDC( winState.appWindow, tempDC );
if ( !test )
{
AssertFatal( false, "Voodoo2Device::activate\nFailed to set the pixel format of the device context!" );
return false;
}
Con::printf( "Pixel format set:" );
Con::printf( " %d color bits, %d depth bits, %d stencil bits", pfd.cColorBits, pfd.cDepthBits, pfd.cStencilBits );
// Set the resolution:
smCurrentRes.bpp = 16; // Force 16-bit color.
if ( !setScreenMode( width, height, 16, true, true, false ) )
return false;
// 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 );
// Set a few variables:
if ( Con::getIntVariable( "$pref::OpenGL::mipReduction" ) < 1 )
Con::setIntVariable( "$pref::OpenGL::mipReduction", 1 );
if ( Con::getIntVariable( "$pref::OpenGL::interiorMipReduction" ) < 1 )
Con::setIntVariable( "$pref::OpenGL::interiorMipReduction", 1 );
if ( Con::getIntVariable( "$pref::OpenGL::skyMipReduction" ) < 1 )
Con::setIntVariable( "$pref::OpenGL::skyMipReduction", 1 );
if (dStrcmp(vendorString, Con::getVariable("$pref::Video::profiledVendor")) ||
dStrcmp(rendererString, Con::getVariable("$pref::Video::profiledRenderer")))
{
// Voodoo2 defaults
Con::setBoolVariable("$pref::OpenGL::disableEXTCompiledVertexArray", false);
Con::setBoolVariable("$pref::OpenGL::disableSubImage", false);
Con::setBoolVariable("$pref::OpenGL::noEnvColor", true);
Con::setBoolVariable("$pref::OpenGL::disableARBTextureCompression", false);
Con::setBoolVariable("$pref::Interior::lockArrays", true);
Con::setBoolVariable("$pref::TS::skipFirstFog", false);
Con::setBoolVariable("$pref::OpenGL::noDrawArraysAlpha", true);
}
if ( needResurrect )
{
// Reload the textures:
Con::printf( "Resurrecting the texture manager..." );
Game->textureResurrect();
}
// Set the new window to the foreground:
ShowWindow( winState.appWindow, SW_SHOW );
SetForegroundWindow( winState.appWindow );
SetFocus( winState.appWindow );
GL_EXT_Init();
Con::setBoolVariable( "$SwapIntervalSupported", false );
Con::setVariable( "$pref::Video::displayDevice", mDeviceName );
Con::setBoolVariable("$pref::OpenGL::allowTexGen", true);
return true;
}
//------------------------------------------------------------------------------
void Voodoo2Device::shutdown()
{
if ( winState.hGLRC )
{
dwglMakeCurrent( NULL, NULL );
dwglDeleteContext( winState.hGLRC );
winState.hGLRC = NULL;
}
if ( winState.appDC )
{
ReleaseDC( winState.appWindow, winState.appDC );
winState.appDC = NULL;
}
ChangeDisplaySettings( NULL, 0 );
}
//------------------------------------------------------------------------------
bool Voodoo2Device::setScreenMode( U32 width, U32 height, U32 bpp, bool fullScreen, bool forceIt, bool repaint )
{
HWND curtain = NULL;
bool needResurrect = false;
Resolution newRes( width, height, bpp );
if ( !fullScreen )
{
// The 3Dfx Voodoo2 OpenGL driver only runs in full-screen, so ignore:
Con::warnf( ConsoleLogEntry::General, "Sorry, the Voodoo 2 display device only supports full-screen!" );
}
// Force the res to be one of the ones in the supported list:
U32 resIndex = 0;
U32 bestScore = 0, thisScore = 0;
for ( U32 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 ) );
if ( !bestScore || thisScore < bestScore )
{
bestScore = thisScore;
resIndex = i;
}
}
}
newRes = mResolutionList[resIndex];
// Return if we aren't forcing it and we are already in the desired resolution:
if ( !forceIt && newRes == smCurrentRes )
return true;
Con::printf( "Setting screen mode to %dx%dx16 (fs)...", newRes.w, newRes.h );
// Delete the rendering context:
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, "Voodoo2Device::setScreenMode\ndwglMakeCurrent( NULL, NULL ) failed!" );
return false;
}
Con::printf( "Deleting the rendering context..." );
if ( !dwglDeleteContext( winState.hGLRC ) )
{
AssertFatal( false, "Voodoo2Device::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;
}
// Change the display settings (shouldn't really be necessary, but is):
U32 test;
DEVMODE devMode;
dMemset( &devMode, 0, sizeof( devMode ) );
devMode.dmSize = sizeof( devMode );
devMode.dmPelsWidth = newRes.w;
devMode.dmPelsHeight = newRes.h;
devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
Con::printf( "Changing the display settings to %dx%dx16...", newRes.w, newRes.h );
curtain = CreateCurtain( newRes.w, newRes.h );
test = ChangeDisplaySettings( &devMode, CDS_FULLSCREEN );
if ( test != DISP_CHANGE_SUCCESSFUL )
{
ChangeDisplaySettings( NULL, 0 );
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;
};
return false;
}
if( winState.appWindow && !fullScreen )
ShowWindow( winState.appWindow, SW_NORMAL );
else
ShowWindow( winState.appWindow, SW_MAXIMIZE );
// Resize the window:
if ( !SetWindowPos( winState.appWindow, NULL, 0, 0, newRes.w, newRes.h, SWP_NOZORDER | SWP_NOMOVE ) )
{
Con::printf( "Voodoo2Device::setScreenMode - SetWindowPos sizing to %dx%d failed.", newRes.w, newRes.h );
return false;
}
// Get a new device context:
Con::printf( "Acquiring a new device context..." );
winState.appDC = GetDC( winState.appWindow );
if ( !winState.appDC )
{
AssertFatal( false, "Voodoo2Device::setScreenMode\nFailed to get a valid device context!" );
return false;
}
// Create a new rendering context:
Con::printf( "Creating a new rendering context..." );
winState.hGLRC = dwglCreateContext( winState.appDC );
if ( !winState.hGLRC )
{
AssertFatal( false, "Voodoo2Device::setScreenMode\nFailed to create a GL 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, "Voodoo2Device::setScreenMode\nFailed to make the rendering context current!" );
return false;
}
if ( needResurrect )
{
// Reload the textures:
Con::printf( "Resurrecting the texture manager..." );
Game->textureResurrect();
}
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 );
if ( repaint )
Con::evaluate( "resetCanvas();" );
return true;
}
//------------------------------------------------------------------------------
void Voodoo2Device::swapBuffers()
{
dwglSwapBuffers( winState.appDC );
}
//------------------------------------------------------------------------------
const char* Voodoo2Device::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 );
// TODO - move strings out of code and into script...
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 Voodoo2Device::getGammaCorrection(F32 &g)
{
// apparently the qwlGetDeviceGammaRamp3DFX doesn't actually work. So, this
// is a good default. We don't need to worry about restoring the original
// gamma. Anything we do is wiped out once we destroy the Voodoo2 window.
g = 0.8;
return true;
U16 ramp[256*3];
if (!dwglGetDeviceGammaRamp3DFX(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 Voodoo2Device::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 dwglSetDeviceGammaRamp3DFX(winState.appDC, ramp);
}
//------------------------------------------------------------------------------
bool Voodoo2Device::setVerticalSync( bool on )
{
on;
return( false );
}
//------------------------------------------------------------------------------
// Stuff for Voodoo 2 detection:
#ifndef GR_HARDWARE
#define GR_HARDWARE 0xa1
#endif
#define GLIDE_NUM_TMU 2
#define MAX_NUM_SST 4
typedef S32 GrSstType;
#define GR_SSTTYPE_VOODOO 0
#define GR_SSTTYPE_SST96 1
#define GR_SSTTYPE_AT3D 2
typedef struct GrTMUConfig_St
{
S32 tmuRev; /* Rev of Texelfx chip */
S32 tmuRam; /* 1, 2, or 4 MB */
} GrTMUConfig_t;
typedef struct GrVoodooConfig_St
{
S32 fbRam; /* 1, 2, or 4 MB */
S32 fbiRev; /* Rev of Pixelfx chip */
S32 nTexelfx; /* How many texelFX chips are there? */
FxBool sliDetect; /* Is it a scan-line interleaved board? */
GrTMUConfig_t tmuConfig[GLIDE_NUM_TMU]; /* Configuration of the Texelfx chips */
} GrVoodooConfig_t;
typedef struct GrSst96Config_St
{
S32 fbRam; /* How much? */
S32 nTexelfx;
GrTMUConfig_t tmuConfig;
} GrSst96Config_t;
typedef struct GrAT3DConfig_St
{
S32 rev;
} GrAT3DConfig_t;
typedef struct
{
S32 num_sst; /* # of HW units in the system */
struct
{
GrSstType type; /* Which hardware is it? */
union SstBoard_u
{
GrVoodooConfig_t VoodooConfig;
GrSst96Config_t SST96Config;
GrAT3DConfig_t AT3DConfig;
} sstBoard;
} SSTs[MAX_NUM_SST]; /* configuration for each board */
} GrHwConfiguration;
typedef FxBool( FX_CALL *grSstQueryBoards_fpt )( GrHwConfiguration *hwconfig );
typedef FxBool( FX_CALL *grSstQueryHardware_fpt )( GrHwConfiguration *hwconfig );
typedef void ( FX_CALL *grGlideInit_fpt )( void );
typedef const char* ( FX_CALL *grGetString_fpt )( FxU32 pName );
typedef void( FX_CALL *grGlideShutdown_fpt )( void );
//------------------------------------------------------------------------------
DisplayDevice* Voodoo2Device::create()
{
// Detect the Voodoo2 OpenGL driver:
GrHwConfiguration hwConfig;
bool result = true;
// Reset the available resolution specifier code:
sResCode = 0;
grGlideInit_fpt grGlideInit = NULL;
grGlideShutdown_fpt grGlideShutdown = NULL;
grSstQueryBoards_fpt grSstQueryBoards = NULL;
grSstQueryHardware_fpt grSstQueryHardware = NULL;
grGetString_fpt grGetString = NULL;
// Let the Glide 2 stuff go first:
HINSTANCE glide2DLL = LoadLibrary( dT("glide2x") );
if ( !glide2DLL )
return NULL;
grSstQueryBoards = (grSstQueryBoards_fpt) GetProcAddress( glide2DLL, "_grSstQueryBoards@4" );
if ( grSstQueryBoards )
{
grSstQueryBoards( &hwConfig );
if ( hwConfig.num_sst == 0 )
result = false;
else
{
grGlideInit = (grGlideInit_fpt) GetProcAddress( glide2DLL, "_grGlideInit@0" );
grSstQueryHardware = (grSstQueryHardware_fpt) GetProcAddress( glide2DLL, "_grSstQueryHardware@4" );
grGlideShutdown = (grGlideShutdown_fpt) GetProcAddress( glide2DLL, "_grGlideShutdown@0" );
if ( grGlideInit && grSstQueryHardware && grGlideShutdown )
{
grGlideInit();
grSstQueryHardware( &hwConfig );
// Find out what resolutions are available:
if ( hwConfig.SSTs[0].sstBoard.VoodooConfig.sliDetect == 0 ) // SLI not detected.
{
if ( hwConfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4 )
sResCode = 1; // low bit indicates 800x600
}
else // SLI detected.
{
sResCode = 1;
if ( hwConfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4 )
sResCode += 2;
}
grGlideShutdown();
}
grGlideInit = NULL;
grGlideShutdown = NULL;
}
}
else
result = false;
FreeLibrary( glide2DLL );
if ( result )
{
// Glide 3's turn:
HINSTANCE glide3DLL = LoadLibrary( dT("glide3x") );
if ( !glide3DLL )
return NULL;
grGlideInit = (grGlideInit_fpt) GetProcAddress( glide3DLL, "_grGlideInit@0" );
grGetString = (grGetString_fpt) GetProcAddress( glide3DLL, "_grGetString@4" );
grGlideShutdown = (grGlideShutdown_fpt) GetProcAddress( glide3DLL, "_grGlideShutdown@0" );
if ( grGlideInit && grGetString && grGlideShutdown )
{
grGlideInit();
const char* hardware = grGetString( GR_HARDWARE );
if ( dStrcmp( hardware, "Voodoo2" ) != 0 )
result = false;
grGlideShutdown();
}
else
result = false;
FreeLibrary( glide3DLL );
}
if ( result )
return new Voodoo2Device();
else
return NULL;
}