Serious-Engine/Sources/Engine/Graphics/GfxLibrary.cpp
Ryan C. Gordon 24cb244d43 First attempt to hand-merge Ryan's Linux and Mac OS X port.
This was a _ton_ of changes, made 15 years ago, so there are probably some
problems to work out still.

Among others: Engine/Base/Stream.* was mostly abandoned and will need to be
re-ported.

Still, this is a pretty good start, and probably holds a world record for
lines of changes or something.  :)
2016-03-28 23:46:13 -04:00

2164 lines
79 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#include "Engine/StdH.h"
#include <Engine/Graphics/GfxLibrary.h>
#include <Engine/Base/Translation.h>
#include <Engine/Base/ErrorReporting.h>
#include <Engine/Base/Console.h>
#include <Engine/Base/Shell.h>
#include <Engine/Base/Statistics_Internal.h>
#include <Engine/Base/ListIterator.inl>
#include <Engine/Math/Functions.h>
#include <Engine/Math/AABBox.h>
#include <Engine/Models/Normals.h>
#include <Engine/Sound/SoundLibrary.h>
#include <Engine/Templates/Stock_CModelData.h>
#include <Engine/Graphics/OpenGL.h>
#include <Engine/Graphics/Adapter.h>
#include <Engine/Graphics/ShadowMap.h>
#include <Engine/Graphics/Texture.h>
#include <Engine/Graphics/GfxProfile.h>
#include <Engine/Graphics/Raster.h>
#include <Engine/Graphics/ViewPort.h>
#include <Engine/Graphics/DrawPort.h>
#include <Engine/Graphics/Color.h>
#include <Engine/Graphics/Font.h>
#include <Engine/Graphics/MultiMonitor.h>
#include <Engine/Templates/DynamicStackArray.h>
#include <Engine/Templates/DynamicStackArray.cpp>
#include <Engine/Templates/DynamicContainer.cpp>
#include <Engine/Templates/Stock_CTextureData.h>
// !!! FIXME: rcg10112001 This just screams to be broken up into subclasses.
// !!! FIXME: rcg10112001 That would get rid of all the #ifdef'ing and
// !!! FIXME: rcg10112001 the need to continually assert that the current
// !!! FIXME: rcg10112001 driver type is valid.
// !!! FIXME: rcg11052001 ... and I could get rid of this, too...
#ifdef PLATFORM_UNIX
#include <SDL.h>
#endif
// control for partial usage of compiled vertex arrays
extern BOOL CVA_b2D = FALSE;
extern BOOL CVA_bWorld = FALSE;
extern BOOL CVA_bModels = FALSE;
// common element arrays
CStaticStackArray<GFXVertex> _avtxCommon;
CStaticStackArray<GFXTexCoord> _atexCommon;
CStaticStackArray<GFXColor> _acolCommon;
CStaticStackArray<INDEX> _aiCommonElements;
CStaticStackArray<INDEX> _aiCommonQuads; // predefined array for rendering quads thru triangles in glDrawElements()
// global texture parameters
CTexParams _tpGlobal[GFX_MAXTEXUNITS];
// pointer to global graphics library object
CGfxLibrary *_pGfx = NULL;
// forced texture upload quality (0 = default, 16 = force 16-bit, 32 = force 32-bit)
INDEX _iTexForcedQuality = 0;
extern PIX _fog_pixSizeH;
extern PIX _fog_pixSizeL;
extern PIX _haze_pixSize;
// control for partial usage of compiled vertex arrays
extern BOOL CVA_b2D;
extern BOOL CVA_bWorld;
extern BOOL CVA_bModels;
// gamma control
static FLOAT _fLastBrightness, _fLastContrast, _fLastGamma;
static FLOAT _fLastBiasR, _fLastBiasG, _fLastBiasB;
static INDEX _iLastLevels;
static UWORD _auwGammaTable[256*3];
// table for clipping [-512..+1024] to [0..255]
static UBYTE aubClipByte[256*2+ 256 +256*3];
const UBYTE *pubClipByte = &aubClipByte[256*2];
// fast square root and 1/sqrt tables
UBYTE aubSqrt[SQRTTABLESIZE];
UWORD auw1oSqrt[SQRTTABLESIZE];
// table for conversion from compressed 16-bit gouraud normals to 8-bit
UBYTE aubGouraudConv[16384];
// flag for scene rendering in progress (i.e. between 1st lock in frame & swap-buffers)
static BOOL GFX_bRenderingScene = FALSE;
// ID of the last drawport that has been locked
static ULONG GFX_ulLastDrawPortID = 0;
// last size of vertex buffers
INDEX _iLastVertexBufferSize = 0;
// pretouch flag
extern BOOL _bNeedPretouch;
// flat texture
CTextureData *_ptdFlat = NULL;
static ULONG _ulWhite = 0xFFFFFFFF;
// fast sin/cos table
static FLOAT afSinTable[256+256+64];
const FLOAT *pfSinTable = afSinTable +256;
const FLOAT *pfCosTable = afSinTable +256+64;
// texture/shadow control
INDEX tex_iNormalQuality = 00; // 0=optimal, 1=16bit, 2=32bit, 3=compressed (1st num=opaque tex, 2nd=alpha tex)
INDEX tex_iAnimationQuality = 11; // 0=optimal, 1=16bit, 2=32bit, 3=compressed (1st num=opaque tex, 2nd=alpha tex)
INDEX tex_iNormalSize = 9; // log2 of texture area /2 for max texture size allowed
INDEX tex_iAnimationSize = 7;
INDEX tex_iEffectSize = 7;
INDEX tex_bDynamicMipmaps = FALSE; // how many mipmaps will be bilineary filtered (0-15)
INDEX tex_iDithering = 3; // 0=none, 1-3=low, 4-7=medium, 8-10=high
INDEX tex_bCompressAlphaChannel = FALSE; // for compressed textures, compress alpha channel too
INDEX tex_bAlternateCompression = FALSE; // basically, this is fix for GFs (compress opaque texture as translucent)
INDEX tex_bFineEffect = FALSE; // 32bit effect? (works only if base texture hasn't been dithered)
INDEX tex_bFineFog = TRUE; // should fog be 8/32bit? (or just plain 4/16bit)
INDEX tex_iFogSize = 7; // limit fog texture size
INDEX tex_iFiltering = 0; // -6 - +6; negative = sharpen, positive = blur, 0 = none
INDEX tex_iEffectFiltering = +4; // filtering of fire effect textures
INDEX tex_bProgressiveFilter = FALSE; // filter mipmaps in creation time (not afterwards)
INDEX tex_bColorizeMipmaps = FALSE; // DEBUG: colorize texture's mipmap levels in various colors
INDEX shd_iStaticSize = 8;
INDEX shd_iDynamicSize = 8;
INDEX shd_bFineQuality = FALSE;
INDEX shd_iFiltering = 3; // >0 = blurring, 0 = no filtering
INDEX shd_iDithering = 1; // 0=none, 1,2=low, 3,4=medium, 5=high
INDEX shd_iAllowDynamic = 1; // 0=disallow, 1=allow on polys w/o 'NoDynamicLights' flag, 2=allow unconditionally
INDEX shd_bDynamicMipmaps = TRUE;
FLOAT shd_tmFlushDelay = 30.0f; // in seconds
FLOAT shd_fCacheSize = 8.0f; // in megabytes
INDEX shd_bCacheAll = FALSE; // cache all shadowmap at the level loading time (careful - memory eater!)
INDEX shd_bAllowFlats = TRUE; // allow optimization of single-color shadowmaps
INDEX shd_iForceFlats = 0; // force all shadowmaps to be flat (internal!) - 0=don't, 1=w/o overbrighting, 2=w/ overbrighting
INDEX shd_bShowFlats = FALSE; // show shadows that have been optimized as flat
INDEX shd_bColorize = FALSE; // colorize shadows by size (gradieng from red=big to green=little)
// OpenGL control
INDEX ogl_iTextureCompressionType = 1; // 0=none, 1=default (ARB), 2=S3TC, 3=FXT1, 4=old S3TC
INDEX ogl_bUseCompiledVertexArrays = 101; // =XYZ; X=2D, Y=world, Z=models
INDEX ogl_bAllowQuadArrays = FALSE;
INDEX ogl_bExclusive = TRUE;
INDEX ogl_bGrabDepthBuffer = FALSE;
INDEX ogl_iMaxBurstSize = 0; // unlimited
INDEX ogl_bTruformLinearNormals = TRUE;
INDEX ogl_bAlternateClipPlane = FALSE; // signal when user clip plane requires a texture unit
INDEX ogl_iTBufferEffect = 0; // 0=none, 1=partial FSAA, 2=Motion Blur
INDEX ogl_iTBufferSamples = 2; // 2, 4 or 8 (for now)
INDEX ogl_iFinish = 1; // 0=never, 1=before rendering of next frame, 2=at the end of this frame, 3=at projection change
// Direct3D control
INDEX d3d_bUseHardwareTnL = TRUE;
INDEX d3d_bAlternateDepthReads = FALSE; // should check delayed depth reads at the end of current frame (FALSE) or at begining of the next (TRUE)
INDEX d3d_bOptimizeVertexBuffers = TRUE; // enables circular buffers
INDEX d3d_iVertexBuffersSize = 1024; // KBs reserved for vertex buffers
INDEX d3d_iVertexRangeTreshold = 99; // minimum vertices in buffer that triggers range optimization
INDEX d3d_iMaxBurstSize = 0; // 0=unlimited
INDEX d3d_iFinish = 0;
// API common controls
INDEX gap_iUseTextureUnits = 4;
INDEX gap_iTextureFiltering = 21; // bilinear by default
INDEX gap_iTextureAnisotropy = 1; // 1=isotropic, 2=min anisotropy
FLOAT gap_fTextureLODBias = 0.0f;
INDEX gap_bOptimizeStateChanges = TRUE;
INDEX gap_iOptimizeDepthReads = 1; // 0=imediately, 1=after frame, 2=every 0.1 seconds
INDEX gap_iOptimizeClipping = 2; // 0=no, 1=mirror plane only, 2=mirror and frustum
INDEX gap_bAllowGrayTextures = TRUE;
INDEX gap_bAllowSingleMipmap = TRUE;
INDEX gap_iSwapInterval = 0;
INDEX gap_iRefreshRate = 0;
INDEX gap_iDithering = 2; // 16-bit dithering: 0=none, 1=no alpha, 2=all
INDEX gap_bForceTruform = 0; // 0 = only for models that allow truform, 1=for every model
INDEX gap_iTruformLevel = 3; // 0 = no tesselation
INDEX gap_iDepthBits = 0; // 0 (as color depth), 16, 24 or 32
INDEX gap_iStencilBits = 0; // 0 (no stencil buffer), 4 or 8
// models control
INDEX mdl_bShowTriangles = FALSE;
INDEX mdl_bShowStrips = FALSE;
INDEX mdl_bTruformWeapons = FALSE;
INDEX mdl_bCreateStrips = TRUE;
INDEX mdl_bRenderDetail = TRUE;
INDEX mdl_bRenderSpecular = TRUE;
INDEX mdl_bRenderReflection = TRUE;
INDEX mdl_bAllowOverbright = TRUE;
INDEX mdl_bFineQuality = TRUE;
INDEX mdl_iShadowQuality = 1;
FLOAT mdl_fLODMul = 1.0f;
FLOAT mdl_fLODAdd = 0.0f;
INDEX mdl_iLODDisappear = 1; // 0=never, 1=ignore bias, 2=with bias
// ska controls
INDEX ska_bShowSkeleton = FALSE;
INDEX ska_bShowColision = FALSE;
FLOAT ska_fLODMul = 1.0f;
FLOAT ska_fLODAdd = 0.0f;
// terrain controls
INDEX ter_bShowQuadTree = FALSE;
INDEX ter_bShowWireframe = FALSE;
INDEX ter_bLerpVertices = TRUE;
INDEX ter_bShowInfo = FALSE;
INDEX ter_bOptimizeRendering = TRUE;
INDEX ter_bTempFreezeCast = FALSE;
INDEX ter_bNoRegeneration = FALSE;
// !!! FIXME : rcg11232001 Hhmm...I'm failing an assertion in the
// !!! FIXME : rcg11232001 Advanced Rendering Options menu because
// !!! FIXME : rcg11232001 Scripts/CustomOptions/GFX-AdvancedRendering.cfg
// !!! FIXME : rcg11232001 references non-existing cvars, so I'm adding them
// !!! FIXME : rcg11232001 here for now.
static INDEX mdl_bRenderBump = TRUE;
static FLOAT ogl_fTextureAnisotropy = 0.0f;
static FLOAT tex_fNormalSize = 0.0f;
// rendering control
INDEX wld_bAlwaysAddAll = FALSE;
INDEX wld_bRenderMirrors = TRUE;
INDEX wld_bRenderEmptyBrushes = TRUE;
INDEX wld_bRenderShadowMaps = TRUE;
INDEX wld_bRenderTextures = TRUE;
INDEX wld_bRenderDetailPolygons = TRUE;
INDEX wld_bTextureLayers = 111;
INDEX wld_bShowTriangles = FALSE;
INDEX wld_bShowDetailTextures = FALSE;
INDEX wld_iDetailRemovingBias = 3;
FLOAT wld_fEdgeOffsetI = 0.0f; //0.125f;
FLOAT wld_fEdgeAdjustK = 1.0f; //1.0001f;
INDEX gfx_bRenderWorld = TRUE;
INDEX gfx_bRenderParticles = TRUE;
INDEX gfx_bRenderModels = TRUE;
INDEX gfx_bRenderPredicted = FALSE;
INDEX gfx_bRenderFog = TRUE;
INDEX gfx_iLensFlareQuality = 3; // 0=none, 1=corona only, 2=corona and reflections, 3=corona, reflections and glare
INDEX gfx_bDecoratedText = TRUE;
INDEX gfx_bClearScreen = FALSE;
FLOAT gfx_tmProbeDecay = 30.00f; // seconds
INDEX gfx_iProbeSize = 256; // in KBs
INDEX gfx_ctMonitors = 0;
INDEX gfx_bMultiMonDisabled = FALSE;
INDEX gfx_bDisableMultiMonSupport = TRUE;
INDEX gfx_bDisableWindowsKeys = TRUE;
INDEX wed_bIgnoreTJunctions = FALSE;
INDEX wed_bUseBaseForReplacement = FALSE;
// some nifty features
INDEX gfx_iHueShift = 0; // 0-359
FLOAT gfx_fSaturation = 1.0f; // 0.0f = min, 1.0f = default
// the following vars can be influenced by corresponding gfx_ vars
INDEX tex_iHueShift = 0; // added to gfx_
FLOAT tex_fSaturation = 1.0f; // multiplied by gfx_
INDEX shd_iHueShift = 0; // added to gfx_
FLOAT shd_fSaturation = 1.0f; // multiplied by gfx_
// gamma table control
FLOAT gfx_fBrightness = 0.0f; // -0.9 - 0.9
FLOAT gfx_fContrast = 1.0f; // 0.1 - 1.9
FLOAT gfx_fGamma = 1.0f; // 0.1 - 9.0
FLOAT gfx_fBiasR = 1.0f; // 0.0 - 1.0
FLOAT gfx_fBiasG = 1.0f; // 0.0 - 1.0
FLOAT gfx_fBiasB = 1.0f; // 0.0 - 1.0
INDEX gfx_iLevels = 256; // 2 - 256
// stereo rendering control
INDEX gfx_iStereo = 0; // 0=off, 1=red/cyan
INDEX gfx_bStereoInvert = FALSE; // is left eye RED or CYAN
INDEX gfx_iStereoOffset = 10; // view offset (or something:)
FLOAT gfx_fStereoSeparation = 0.25f; // distance between eyes
// cached integers for faster calculation
SLONG _slTexSaturation = 256; // 0 = min, 256 = default
SLONG _slTexHueShift = 0;
SLONG _slShdSaturation = 256;
SLONG _slShdHueShift = 0;
// 'supported' console variable flags
static INDEX sys_bHasTextureCompression = 0;
static INDEX sys_bHasTextureAnisotropy = 0;
static INDEX sys_bHasAdjustableGamma = 0;
static INDEX sys_bHasTextureLODBias = 0;
static INDEX sys_bHasMultitexturing = 0;
static INDEX sys_bHas32bitTextures = 0;
static INDEX sys_bHasSwapInterval = 0;
static INDEX sys_bHasHardwareTnL = 1;
static INDEX sys_bHasTruform = 0;
static INDEX sys_bHasCVAs = 0;
static INDEX sys_bUsingOpenGL = 0;
extern INDEX sys_bUsingDirect3D = 0;
/*
* Low level hook flags
*/
#define WH_KEYBOARD_LL 13
#pragma message(">> doublecheck me!!!")
// these are commented because they are already defined in winuser.h
//#define LLKHF_EXTENDED 0x00000001
//#define LLKHF_INJECTED 0x00000010
//#define LLKHF_ALTDOWN 0x00000020
//#define LLKHF_UP 0x00000080
//#define LLMHF_INJECTED 0x00000001
#ifdef PLATFORM_WIN32
/*
* Structure used by WH_KEYBOARD_LL
*/
// this is commented because there's a variant for this struct in winuser.h
/*typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
DWORD dwExtraInfo;
} KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;*/
static HHOOK _hLLKeyHook = NULL;
LRESULT CALLBACK LowLevelKeyboardProc (INT nCode, WPARAM wParam, LPARAM lParam)
{
// By returning a non-zero value from the hook procedure, the
// message does not get passed to the target window
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;
BOOL bControlKeyDown = 0;
switch (nCode)
{
case HC_ACTION:
{
// Check to see if the CTRL key is pressed
bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);
// Disable CTRL+ESC
if (pkbhs->vkCode == VK_ESCAPE && bControlKeyDown)
return 1;
// Disable ALT+TAB
if (pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN)
return 1;
// Disable ALT+ESC
if (pkbhs->vkCode == VK_ESCAPE && pkbhs->flags & LLKHF_ALTDOWN)
return 1;
break;
}
default:
break;
}
return CallNextHookEx (_hLLKeyHook, nCode, wParam, lParam);
}
void DisableWindowsKeys(void)
{
//if( _hLLKeyHook!=NULL) UnhookWindowsHookEx(_hLLKeyHook);
//_hLLKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, &LowLevelKeyboardProc, NULL, GetCurrentThreadId());
INDEX iDummy;
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &iDummy, 0);
}
void EnableWindowsKeys(void)
{
INDEX iDummy;
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, FALSE, &iDummy, 0);
// if( _hLLKeyHook!=NULL) UnhookWindowsHookEx(_hLLKeyHook);
}
#else
#define DisableWindowsKeys()
#define EnableWindowsKeys()
#endif
// texture size reporting
static CTString ReportQuality( INDEX iQuality)
{
if( iQuality==0) return "optimal";
if( iQuality==1) return "16-bit";
if( iQuality==2) return "32-bit";
if( iQuality==3) return "compressed";
ASSERTALWAYS( "Invalid texture quality.");
return "?";
}
static void TexturesInfo(void)
{
UpdateTextureSettings();
INDEX ctNo04O=0, ctNo64O=0, ctNoMXO=0;
PIX pixK04O=0, pixK64O=0, pixKMXO=0;
SLONG slKB04O=0, slKB64O=0, slKBMXO=0;
INDEX ctNo04A=0, ctNo64A=0, ctNoMXA=0;
PIX pixK04A=0, pixK64A=0, pixKMXA=0;
SLONG slKB04A=0, slKB64A=0, slKBMXA=0;
// walk thru all textures on stock
{FOREACHINDYNAMICCONTAINER( _pTextureStock->st_ctObjects, CTextureData, ittd)
{ // get texture info
CTextureData &td = *ittd;
BOOL bAlpha = td.td_ulFlags&TEX_ALPHACHANNEL;
INDEX ctFrames = td.td_ctFrames;
SLONG slBytes = td.GetUsedMemory();
ASSERT( slBytes>=0);
// get texture size
PIX pixTextureSize = td.GetPixWidth() * td.GetPixHeight();
PIX pixMipmapSize = pixTextureSize;
if( !gap_bAllowSingleMipmap || td.td_ctFineMipLevels>1) pixMipmapSize = pixMipmapSize *4/3;
// increase corresponding counters
if( pixTextureSize<4096) {
if( bAlpha) { pixK04A+=pixMipmapSize; slKB04A+=slBytes; ctNo04A+=ctFrames; }
else { pixK04O+=pixMipmapSize; slKB04O+=slBytes; ctNo04O+=ctFrames; }
} else if( pixTextureSize<=65536) {
if( bAlpha) { pixK64A+=pixMipmapSize; slKB64A+=slBytes; ctNo64A+=ctFrames; }
else { pixK64O+=pixMipmapSize; slKB64O+=slBytes; ctNo64O+=ctFrames; }
} else {
if( bAlpha) { pixKMXA+=pixMipmapSize; slKBMXA+=slBytes; ctNoMXA+=ctFrames; }
else { pixKMXO+=pixMipmapSize; slKBMXO+=slBytes; ctNoMXO+=ctFrames; }
}
}}
// report
const PIX pixNormDim = (PIX) (sqrt(TS.ts_pixNormSize));
const PIX pixAnimDim = (PIX) (sqrt(TS.ts_pixAnimSize));
const PIX pixEffDim = 1L<<tex_iEffectSize;
CTString strTmp;
strTmp = tex_bFineEffect ? "32-bit" : "16-bit";
CPrintF( "\n");
CPrintF( "Normal-opaque textures quality: %s\n", (const char *) ReportQuality(TS.ts_iNormQualityO));
CPrintF( "Normal-translucent textures quality: %s\n", (const char *) ReportQuality(TS.ts_iNormQualityA));
CPrintF( "Animation-opaque textures quality: %s\n", (const char *) ReportQuality(TS.ts_iAnimQualityO));
CPrintF( "Animation-translucent textures quality: %s\n", (const char *) ReportQuality(TS.ts_iAnimQualityA));
CPrintF( "Effect textures quality: %s\n", (const char *) strTmp);
CPrintF( "\n");
CPrintF( "Max allowed normal texture area size: %3dx%d\n", pixNormDim, pixNormDim);
CPrintF( "Max allowed animation texture area size: %3dx%d\n", pixAnimDim, pixAnimDim);
CPrintF( "Max allowed effect texture area size: %3dx%d\n", pixEffDim, pixEffDim);
CPrintF( "\n");
CPrintF( "Opaque textures memory usage:\n");
CPrintF( " <64 pix: %3d frames use %6.1f Kpix in %5d KB\n", ctNo04O, pixK04O/1024.0f, slKB04O/1024);
CPrintF( " 64-256 pix: %3d frames use %6.1f Kpix in %5d KB\n", ctNo64O, pixK64O/1024.0f, slKB64O/1024);
CPrintF( " >256 pix: %3d frames use %6.1f Kpix in %5d KB\n", ctNoMXO, pixKMXO/1024.0f, slKBMXO/1024);
CPrintF( "Translucent textures memory usage:\n");
CPrintF( " <64 pix: %3d frames use %6.1f Kpix in %5d KB\n", ctNo04A, pixK04A/1024.0f, slKB04A/1024);
CPrintF( " 64-256 pix: %3d frames use %6.1f Kpix in %5d KB\n", ctNo64A, pixK64A/1024.0f, slKB64A/1024);
CPrintF( " >256 pix: %3d frames use %6.1f Kpix in %5d KB\n", ctNoMXA, pixKMXA/1024.0f, slKBMXA/1024);
CPrintF("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n");
}
// reformat an extensions string to cross multiple lines
extern CTString ReformatExtensionsString( CTString strUnformatted)
{
CTString strTmp, strDst = "\n";
char *pcSrc = (char*)(const char*)strUnformatted;
FOREVER {
char *pcSpace = strchr( pcSrc, ' ');
if( pcSpace==NULL) break;
*pcSpace = 0;
strTmp.PrintF( " %s\n", pcSrc);
strDst += strTmp;
*pcSpace = ' ';
pcSrc = pcSpace +1;
}
if(strDst=="\n") {
strDst = "none\n";
}
// done
return strDst;
}
// printout extensive OpenGL/Direct3D info to console
static void GAPInfo(void)
{
// check API
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
CPrintF( "\n");
ASSERT( GfxValidApi(eAPI) );
#ifdef PLATFORM_WIN32
// in case of driver hasn't been initialized yet
if( (_pGfx->go_hglRC==NULL
#ifdef SE1_D3D
&& _pGfx->gl_pd3dDevice==NULL
#endif // SE1_D3D
) || eAPI==GAT_NONE) {
// be brief, be quick
CPrintF( TRANS("Display driver hasn't been initialized.\n\n"));
return;
}
#else
// in case of driver hasn't been initialized yet
if (_pGfx->go_hglRC==NULL || eAPI==GAT_NONE) {
// be brief, be quick
CPrintF( TRANS("Display driver hasn't been initialized.\n\n"));
return;
}
#endif
// report API
CPrintF( "- Graphics API: ");
if( eAPI==GAT_OGL) CPrintF( "OpenGL\n");
else CPrintF( "Direct3D\n");
// and number of adapters
CPrintF( "- Adapters found: %d\n", _pGfx->gl_gaAPI[eAPI].ga_ctAdapters);
CPrintF( "\n");
// report renderer
CDisplayAdapter &da = _pGfx->gl_gaAPI[eAPI].ga_adaAdapter[_pGfx->gl_iCurrentAdapter];
if( eAPI==GAT_OGL) CPrintF( "- Vendor: %s\n", (const char *) da.da_strVendor);
CPrintF( "- Renderer: %s\n", (const char *) da.da_strRenderer);
CPrintF( "- Version: %s\n", (const char *) da.da_strVersion);
CPrintF( "\n");
// Z-buffer depth
CPrintF( "- Z-buffer precision: ");
if( _pGfx->gl_iCurrentDepth==0) CPrintF( "default\n");
else CPrintF( "%d bits\n", _pGfx->gl_iCurrentDepth);
// 32-bit textures
CPrintF( "- 32-bit textures: ");
if( _pGfx->gl_ulFlags & GLF_32BITTEXTURES) CPrintF( "supported\n");
else CPrintF( "not supported\n");
// grayscale textures
CPrintF( "- Grayscale textures: ");
if( gap_bAllowGrayTextures) CPrintF( "allowed\n");
else CPrintF( "not allowed\n");
// report maximum texture dimension
CPrintF( "- Max texture dimension: %d pixels\n", _pGfx->gl_pixMaxTextureDimension);
// report multitexturing capabilities
CPrintF( "- Multi-texturing: ");
if( _pGfx->gl_ctRealTextureUnits<2) CPrintF( "not supported\n");
else {
if( gap_iUseTextureUnits>1) CPrintF( "enabled (using %d texture units)\n", gap_iUseTextureUnits);
else CPrintF( "disabled\n");
CPrintF( "- Texture units: %d", _pGfx->gl_ctRealTextureUnits);
if( _pGfx->gl_ctTextureUnits < _pGfx->gl_ctRealTextureUnits) {
CPrintF(" (%d can be used)\n", _pGfx->gl_ctTextureUnits);
} else CPrintF("\n");
}
// report texture anisotropy degree
if( _pGfx->gl_iMaxTextureAnisotropy>=2) {
CPrintF( "- Texture anisotropy: %d of %d\n", _tpGlobal[0].tp_iAnisotropy, _pGfx->gl_iMaxTextureAnisotropy);
} else CPrintF( "- Anisotropic texture filtering: not supported\n");
// report texture LOD bias range
const FLOAT fMaxLODBias = _pGfx->gl_fMaxTextureLODBias;
if( fMaxLODBias>0) {
CPrintF( "- Texture LOD bias: %.1f of +/-%.1f\n", _pGfx->gl_fTextureLODBias, fMaxLODBias);
} else CPrintF( "- Texture LOD biasing: not supported\n");
// OpenGL only stuff ...
if( eAPI==GAT_OGL)
{
// report truform tessellation
CPrintF( "- Truform tessellation: ");
if( _pGfx->gl_iMaxTessellationLevel>0) {
if( _pGfx->gl_iTessellationLevel>0) {
CPrintF( "enabled ");
if( gap_bForceTruform) CPrintF( "(for all models)\n");
else CPrintF( "(only for Truform-ready models)\n");
CTString strNormalMode = ogl_bTruformLinearNormals ? "linear" : "quadratic";
CPrintF( "- Tesselation level: %d of %d (%s normals)\n", _pGfx->gl_iTessellationLevel, _pGfx->gl_iMaxTessellationLevel, (const char *) strNormalMode);
} else CPrintF( "disabled\n");
} else CPrintF( "not supported\n");
// report current swap interval (only if fullscreen)
if( _pGfx->gl_ulFlags&GLF_FULLSCREEN) {
// report current swap interval
CPrintF( "- Swap interval: ");
if( _pGfx->gl_ulFlags&GLF_VSYNC) {
GLint gliWaits = pwglGetSwapIntervalEXT();
if( gliWaits>=0) {
ASSERT( gliWaits==_pGfx->gl_iSwapInterval);
CPrintF( "%d frame(s)\n", gliWaits);
} else CPrintF( "not readable\n");
} else CPrintF( "not adjustable\n");
}
// report T-Buffer support
if( _pGfx->gl_ulFlags & GLF_EXT_TBUFFER) {
CPrintF( "- T-Buffer effect: ");
if( _pGfx->go_ctSampleBuffers==0) CPrintF( "disabled\n");
else {
ogl_iTBufferEffect = Clamp( ogl_iTBufferEffect, 0L, 2L);
CTString strEffect = "Partial anti-aliasing";
if( ogl_iTBufferEffect<1) strEffect = "none";
if( ogl_iTBufferEffect>1) strEffect = "Motion blur";
CPrintF( "%s (%d buffers used)\n", (const char *) strEffect, _pGfx->go_ctSampleBuffers);
}
}
// compiled vertex arrays support
CPrintF( "- Compiled Vertex Arrays: ");
if( _pGfx->gl_ulFlags & GLF_EXT_COMPILEDVERTEXARRAY) {
extern BOOL CVA_b2D;
extern BOOL CVA_bWorld;
extern BOOL CVA_bModels;
if( ogl_bUseCompiledVertexArrays) {
CTString strSep="";
CPrintF( "enabled (for ");
if( CVA_bWorld) { CPrintF( "world"); strSep="/"; }
if( CVA_bModels) { CPrintF( "%smodels", (const char *) strSep); strSep="/"; }
if( CVA_b2D) { CPrintF( "%sparticles", (const char *) strSep); }
CPrintF( ")\n");
} else CPrintF( "disabled\n");
} else CPrintF( "not supported\n");
// report texture compression type
CPrintF( "- Supported texture compression system(s): ");
if( !(_pGfx->gl_ulFlags&GLF_TEXTURECOMPRESSION)) CPrintF( "none\n");
else {
CTString strSep="";
if( _pGfx->gl_ulFlags & GLF_EXTC_ARB) { CPrintF( "ARB"); strSep=", "; }
if( _pGfx->gl_ulFlags & GLF_EXTC_S3TC) { CPrintF( "%sS3TC", (const char *) strSep); strSep=", "; }
if( _pGfx->gl_ulFlags & GLF_EXTC_FXT1) { CPrintF( "%sFTX1", (const char *) strSep); strSep=", "; }
if( _pGfx->gl_ulFlags & GLF_EXTC_LEGACY) { CPrintF( "%sold S3TC", (const char *) strSep); }
CPrintF( "\n- Current texture compression system: ");
switch( ogl_iTextureCompressionType) {
case 0: CPrintF( "none\n"); break;
case 1: CPrintF( "ARB wrapper\n"); break;
case 2: CPrintF( "S3TC\n"); break;
case 3: CPrintF( "FXT1\n"); break;
default: CPrintF( "old S3TC\n"); break;
}
}
/* if exist, report vertex array range extension usage
if( ulExt & GOEXT_VERTEXARRAYRANGE) {
extern BOOL VB_bSetupFailed;
extern SLONG VB_slVertexBufferSize;
extern INDEX VB_iVertexBufferType;
extern INDEX ogl_iVertexBuffers;
if( VB_bSetupFailed) { // didn't manage to setup vertex buffers
CPrintF( "- Enhanced HW T&L: fail\n");
} else if( VB_iVertexBufferType==0) { // not used
CPrintF( "- Enhanced HW T&L: disabled\n");
} else { // works! :)
CTString strBufferType("AGP");
if( VB_iVertexBufferType==2) strBufferType = "video";
const SLONG slMemSize = VB_slVertexBufferSize/1024;
CPrintF( "- Enhanced hardware T&L: %d buffers in %d KB of %s memory",
ogl_iVertexBuffers, slMemSize, strBufferType);
}
} */
// report OpenGL externsions
CPrintF("\n");
CPrintF("- Published extensions: %s", (const char *) ReformatExtensionsString(_pGfx->go_strExtensions));
if( _pGfx->go_strWinExtensions != "") CPrintF("%s", (const char *) ReformatExtensionsString(_pGfx->go_strWinExtensions));
CPrintF("\n- Supported extensions: %s\n", (const char *) ReformatExtensionsString(_pGfx->go_strSupportedExtensions));
}
#ifdef PLATFORM_WIN32
// Direct3D only stuff
if( eAPI==GAT_D3D)
{
// HW T&L
CPrintF( "- Hardware T&L: ");
if( _pGfx->gl_ulFlags&GLF_D3D_HASHWTNL) {
if( _pGfx->gl_ctMaxStreams<GFX_MINSTREAMS) CPrintF( "cannot be used\n");
else if( _pGfx->gl_ulFlags&GLF_D3D_USINGHWTNL) CPrintF( "enabled (%d streams)\n", _pGfx->gl_ctMaxStreams);
else CPrintF( "disabled\n");
} else CPrintF( "not present\n");
// report vtx/idx buffers size
extern SLONG SizeFromVertices_D3D( INDEX ctVertices);
const SLONG slMemoryUsed = SizeFromVertices_D3D(_pGfx->gl_ctVertices);
CPrintF( "- Vertex buffer size: %.1f KB (%d vertices)\n", slMemoryUsed/1024.0f, _pGfx->gl_ctVertices);
// N-Patches tessellation (Truform)
CPrintF( "- N-Patches: ");
if( _pGfx->gl_iMaxTessellationLevel>0) {
if( !(_pGfx->gl_ulFlags&GLF_D3D_USINGHWTNL)) CPrintF( "not possible with SW T&L\n");
else if( _pGfx->gl_iTessellationLevel>0) {
CPrintF( "enabled ");
if( gap_bForceTruform) CPrintF( "(for all models)\n");
else CPrintF( "(only for Truform-ready models)\n");
CPrintF( "- Tesselation level: %d of %d\n", _pGfx->gl_iTessellationLevel, _pGfx->gl_iMaxTessellationLevel);
} else CPrintF( "disabled\n");
} else CPrintF( "not supported\n");
// texture compression
CPrintF( "- Texture compression: ");
if( _pGfx->gl_ulFlags&GLF_TEXTURECOMPRESSION) CPrintF( "supported\n");
else CPrintF( "not supported\n");
// custom clip plane support
CPrintF( "- Custom clip plane: ");
if( _pGfx->gl_ulFlags&GLF_D3D_CLIPPLANE) CPrintF( "supported\n");
else CPrintF( "not supported\n");
// color buffer writes enable/disable support
CPrintF( "- Color masking: ");
if( _pGfx->gl_ulFlags&GLF_D3D_COLORWRITES) CPrintF( "supported\n");
else CPrintF( "not supported\n");
// depth (Z) bias support
CPrintF( "- Depth biasing: ");
if( _pGfx->gl_ulFlags&GLF_D3D_ZBIAS) CPrintF( "supported\n");
else CPrintF( "not supported\n");
// current swap interval (only if fullscreen)
if( _pGfx->gl_ulFlags&GLF_FULLSCREEN) {
CPrintF( "- Swap interval: ");
if( _pGfx->gl_ulFlags&GLF_VSYNC) {
CPrintF( "%d frame(s)\n", _pGfx->gl_iSwapInterval);
} else CPrintF( "not adjustable\n");
}
}
#endif // SE1_D3D
}
// update console system vars
extern void UpdateGfxSysCVars(void)
{
sys_bHasTextureCompression = 0;
sys_bHasTextureAnisotropy = 0;
sys_bHasAdjustableGamma = 0;
sys_bHasTextureLODBias = 0;
sys_bHasMultitexturing = 0;
sys_bHas32bitTextures = 0;
sys_bHasSwapInterval = 0;
sys_bHasHardwareTnL = 1;
sys_bHasTruform = 0;
sys_bHasCVAs = 1;
sys_bUsingOpenGL = 0;
sys_bUsingDirect3D = 0;
if( _pGfx->gl_iMaxTextureAnisotropy>1) sys_bHasTextureAnisotropy = 1;
if( _pGfx->gl_fMaxTextureLODBias>0) sys_bHasTextureLODBias = 1;
if( _pGfx->gl_ctTextureUnits>1) sys_bHasMultitexturing = 1;
if( _pGfx->gl_iMaxTessellationLevel>0) sys_bHasTruform = 1;
if( _pGfx->gl_ulFlags & GLF_TEXTURECOMPRESSION) sys_bHasTextureCompression = 1;
if( _pGfx->gl_ulFlags & GLF_ADJUSTABLEGAMMA) sys_bHasAdjustableGamma = 1;
if( _pGfx->gl_ulFlags & GLF_32BITTEXTURES) sys_bHas32bitTextures = 1;
if( _pGfx->gl_ulFlags & GLF_VSYNC) sys_bHasSwapInterval = 1;
if( _pGfx->gl_eCurrentAPI==GAT_OGL && !(_pGfx->gl_ulFlags&GLF_EXT_COMPILEDVERTEXARRAY)) sys_bHasCVAs = 0;
#ifdef SE1_D3D
if( _pGfx->gl_eCurrentAPI==GAT_D3D && !(_pGfx->gl_ulFlags&GLF_D3D_HASHWTNL)) sys_bHasHardwareTnL = 0;
#endif // SE1_D3D
if( _pGfx->gl_eCurrentAPI==GAT_OGL) sys_bUsingOpenGL = 1;
#ifdef SE1_D3D
if( _pGfx->gl_eCurrentAPI==GAT_D3D) sys_bUsingDirect3D = 1;
#endif // SE1_D3D
}
// determine whether texture or shadowmap needs probing
extern BOOL ProbeMode( CTimerValue tvLast)
{
// probing off ?
if( !_pGfx->gl_bAllowProbing) return FALSE;
if( gfx_tmProbeDecay<1) {
gfx_tmProbeDecay = 0;
return FALSE;
}
// clamp and determine probe mode
if( gfx_tmProbeDecay>999) gfx_tmProbeDecay = 999;
CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
const TIME tmDelta = (tvNow-tvLast).GetSeconds();
if( tmDelta>gfx_tmProbeDecay) return TRUE;
return FALSE;
}
// uncache all cached shadow maps
extern void UncacheShadows(void)
{
// mute all sounds
_pSound->Mute();
// prepare new saturation factors for shadowmaps
gfx_fSaturation = ClampDn( gfx_fSaturation, 0.0f);
shd_fSaturation = ClampDn( shd_fSaturation, 0.0f);
gfx_iHueShift = Clamp( gfx_iHueShift, 0L, 359L);
shd_iHueShift = Clamp( shd_iHueShift, 0L, 359L);
_slShdSaturation = (SLONG)( gfx_fSaturation*shd_fSaturation*256.0f);
_slShdHueShift = Clamp( (gfx_iHueShift+shd_iHueShift)*255L/359L, 0L, 255L);
CListHead &lhOriginal = _pGfx->gl_lhCachedShadows;
// while there is some shadow in main list
while( !lhOriginal.IsEmpty()) {
CShadowMap &sm = *LIST_HEAD( lhOriginal, CShadowMap, sm_lnInGfx);
sm.Uncache();
}
// mark that we need pretouching
_bNeedPretouch = TRUE;
}
// refresh (uncache and eventually cache) all cached shadow maps
extern void CacheShadows(void);
static void RecacheShadows(void)
{
// mute all sounds
_pSound->Mute();
UncacheShadows();
if( shd_bCacheAll) CacheShadows();
else CPrintF( TRANS("All shadows uncached.\n"));
}
// reload all textures that were loaded
extern void ReloadTextures(void)
{
// mute all sounds
_pSound->Mute();
// prepare new saturation factors for textures
gfx_fSaturation = ClampDn( gfx_fSaturation, 0.0f);
tex_fSaturation = ClampDn( tex_fSaturation, 0.0f);
gfx_iHueShift = Clamp( gfx_iHueShift, 0L, 359L);
tex_iHueShift = Clamp( tex_iHueShift, 0L, 359L);
_slTexSaturation = (SLONG)( gfx_fSaturation*tex_fSaturation*256.0f);
_slTexHueShift = Clamp( (gfx_iHueShift+tex_iHueShift)*255L/359L, 0L, 255L);
// update texture settings
UpdateTextureSettings();
// loop thru texture stock
{FOREACHINDYNAMICCONTAINER( _pTextureStock->st_ctObjects, CTextureData, ittd) {
CTextureData &td = *ittd;
td.Reload();
td.td_tpLocal.Clear();
}}
// reset fog/haze texture
_fog_pixSizeH = 0;
_fog_pixSizeL = 0;
_haze_pixSize = 0;
// reinit flat texture
ASSERT( _ptdFlat!=NULL);
_ptdFlat->td_tpLocal.Clear();
_ptdFlat->Unbind();
_ptdFlat->td_ulFlags = TEX_ALPHACHANNEL | TEX_32BIT | TEX_STATIC;
_ptdFlat->td_mexWidth = 1;
_ptdFlat->td_mexHeight = 1;
_ptdFlat->td_iFirstMipLevel = 0;
_ptdFlat->td_ctFineMipLevels = 1;
_ptdFlat->td_slFrameSize = 1*1* BYTES_PER_TEXEL;
_ptdFlat->td_ctFrames = 1;
_ptdFlat->td_ulInternalFormat = TS.ts_tfRGBA8;
_ptdFlat->td_pulFrames = &_ulWhite;
_ptdFlat->SetAsCurrent();
/*
// reset are renderable textures, too
CListHead &lhOriginal = _pGfx->gl_lhRenderTextures;
while( !lhOriginal.IsEmpty()) {
CRenderTexture &rt = *LIST_HEAD( lhOriginal, CRenderTexture, rt_lnInGfx);
rt.Reset();
}
*/
// mark that we need pretouching
_bNeedPretouch = TRUE;
CPrintF( TRANS("All textures reloaded.\n"));
}
// refreshes all textures and shadow maps
static void RefreshTextures(void)
{
// refresh
ReloadTextures();
RecacheShadows();
}
// reload all models that were loaded
static void ReloadModels(void)
{
// mute all sounds
_pSound->Mute();
// loop thru model stock
{FOREACHINDYNAMICCONTAINER( _pModelStock->st_ctObjects, CModelData, itmd) {
CModelData &md = *itmd;
md.Reload();
}}
// mark that we need pretouching
_bNeedPretouch = TRUE;
// all done
CPrintF( TRANS("All models reloaded.\n"));
}
// variable change post functions
static BOOL _bLastModelQuality = -1;
static void MdlPostFunc(void *pvVar)
{
mdl_bFineQuality = Clamp( mdl_bFineQuality, 0L, 1L);
if( _bLastModelQuality!=mdl_bFineQuality) {
_bLastModelQuality = mdl_bFineQuality;
ReloadModels();
}
}
/*
* GfxLibrary functions
*/
static void PrepareTables(void)
{
INDEX i;
// prepare array for fast clamping to 0..255
for( i=-256*2; i<256*4; i++) aubClipByte[i+256*2] = (UBYTE)Clamp( i, 0L, 255L);
// prepare fast sqrt tables
for( i=0; i<SQRTTABLESIZE; i++) aubSqrt[i] = (UBYTE)(sqrt((FLOAT)(i*65536/SQRTTABLESIZE)));
for( i=1; i<SQRTTABLESIZE; i++) auw1oSqrt[i] = (UWORD)(sqrt((FLOAT)(SQRTTABLESIZE-1)/i)*255.0f);
auw1oSqrt[0] = MAX_UWORD;
// prepare fast sin/cos table
for( i=-256; i<256+64; i++) afSinTable[i+256] = Sin((i-128)/256.0f*360.0f);
// prepare gouraud conversion table
for( INDEX h=0; h<128; h++) {
for( INDEX p=0; p<128; p++) {
const FLOAT fSinH = pfSinTable[h*2];
const FLOAT fSinP = pfSinTable[p*2];
const FLOAT fCosH = pfCosTable[h*2];
const FLOAT fCosP = pfCosTable[p*2];
const FLOAT3D v( -fSinH*fCosP, +fSinP, -fCosH*fCosP);
aubGouraudConv[h*128+p] = (UBYTE)GouraudNormal(v);
}
}
// !!! FIXME: rcg01082002
// You can't count on these arrays to be identical on every system, due to
// floating point unit differences. This includes Linux and win32 on the
// x86 platform, and win32 debug builds vs. win32 release builds. Hell, I
// wouldn't be surprised if they gave different values between AMD and Intel
// processors. The tables generate identically between a win32 release and
// Linux release build at this point...except the Gouraud table, which has
// several minor variances. I recommend you get a table you like, use the
// below code to dump it to disk, and then make it a static array that you
// never need to calculate at runtime in the first place. Then you can remove
// this code and this godawful long comment. :)
#if 0
FILE *feh;
feh = fopen("aubClipByte.bin", "wb");
fwrite(aubClipByte, sizeof (aubClipByte), 1, feh);
fclose(feh);
feh = fopen("aubSqrt.bin", "wb");
fwrite(aubSqrt, sizeof (aubSqrt), 1, feh);
fclose(feh);
feh = fopen("auw1oSqrt.bin", "wb");
fwrite(auw1oSqrt, sizeof (auw1oSqrt), 1, feh);
fclose(feh);
feh = fopen("afSinTable.bin", "wb");
fwrite(afSinTable, sizeof (afSinTable), 1, feh);
fclose(feh);
feh = fopen("aubGouraudConv.bin", "wb");
fwrite(aubGouraudConv, sizeof (aubGouraudConv), 1, feh);
fclose(feh);
printf("w00t.\n");
exit(0);
#endif
}
/*
* Construct uninitialized gfx library.
*/
CGfxLibrary::CGfxLibrary(void)
{
// reset some variables to default
gl_iFrameNumber = 0;
gl_slAllowedUploadBurst = 0;
gl_bAllowProbing = FALSE;
gl_iSwapInterval = 1234;
gl_pixMaxTextureDimension = 8192;
gl_ctTextureUnits = 0;
gl_ctRealTextureUnits = 0;
gl_fTextureLODBias = 0;
gl_fMaxTextureLODBias = 0;
gl_iMaxTextureAnisotropy = 0;
gl_iMaxTessellationLevel = 0;
gl_iTessellationLevel = 0;
gl_ulFlags = NONE;
// create some internal tables
PrepareTables();
// no driver loaded
gl_eCurrentAPI = GAT_NONE;
gl_hiDriver = NONE;
go_hglRC = NONE;
gl_ctDriverChanges = 0;
// DX8 not loaded either
#ifdef SE1_D3D
gl_pD3D = NONE;
gl_pd3dDevice = NULL;
gl_d3dColorFormat = (D3DFORMAT)NONE;
gl_d3dDepthFormat = (D3DFORMAT)NONE;
#endif // SE1_D3D
gl_pvpActive = NULL;
gl_ctMaxStreams = 0;
gl_dwVertexShader = 0;
#ifdef SE1_D3D
gl_pd3dIdx = NULL;
gl_pd3dVtx = NULL;
gl_pd3dNor = NULL;
for( INDEX i=0; i<GFX_MAXLAYERS; i++) gl_pd3dCol[i] = gl_pd3dTex[i] = NULL;
#endif // SE1_D3D
gl_ctVertices = 0;
gl_ctIndices = 0;
// reset profiling counters
gl_ctWorldTriangles = 0;
gl_ctModelTriangles = 0;
gl_ctParticleTriangles = 0;
gl_ctTotalTriangles = 0;
// init flat texture
_ptdFlat = new CTextureData;
_ptdFlat->td_ulFlags = TEX_ALPHACHANNEL | TEX_32BIT | TEX_STATIC;
// prepare some quad elements
extern void AddQuadElements( const INDEX ctQuads);
AddQuadElements(1024); // should be enough (at least for a start)
// reset GFX API function pointers
GFX_SetFunctionPointers( (INDEX)GAT_NONE);
}
/*
* Destruct (and clean up).
*/
CGfxLibrary::~CGfxLibrary()
{
extern void EnableWindowsKeys(void);
EnableWindowsKeys();
// free common arrays
_avtxCommon.Clear();
_atexCommon.Clear();
_acolCommon.Clear();
_aiCommonElements.Clear();
_aiCommonQuads.Clear();
// stop current display mode
StopDisplayMode();
// safe release of flat texture
ASSERT( _ptdFlat!=NULL);
_ptdFlat->td_pulFrames = NULL;
delete _ptdFlat;
_ptdFlat = NULL;
}
#define SM_CXVIRTUALSCREEN 78
#define SM_CYVIRTUALSCREEN 79
#define SM_CMONITORS 80
/* Initialize library for application main window. */
void CGfxLibrary::Init(void)
{
ASSERT( this!=NULL);
// we will never allow glide splash screen
putenv( "FX_GLIDE_NO_SPLASH=1");
#ifdef PLATFORM_WIN32
// report desktop settings
CPrintF(TRANS("Desktop settings...\n"));
HDC hdc = GetDC(NULL);
SLONG slBPP = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
ReleaseDC(NULL, hdc);
gfx_ctMonitors = GetSystemMetrics(SM_CMONITORS);
CPrintF(TRANS(" Color Depth: %dbit\n"), slBPP);
CPrintF(TRANS(" Screen: %dx%d\n"), GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
CPrintF(TRANS(" Virtual screen: %dx%d\n"), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
CPrintF(TRANS(" Monitors directly reported: %d\n"), gfx_ctMonitors);
#else
gfx_ctMonitors = 1;
#endif
CPrintF("\n");
gfx_bMultiMonDisabled = FALSE;
_pfGfxProfile.Reset();
// declare some console vars
_pShell->DeclareSymbol("user void MonitorsOn(void);", (void *) &MonitorsOn);
_pShell->DeclareSymbol("user void MonitorsOff(void);", (void *) &MonitorsOff);
_pShell->DeclareSymbol("user void GAPInfo(void);", (void *) &GAPInfo);
_pShell->DeclareSymbol("user void TexturesInfo(void);", (void *) &TexturesInfo);
_pShell->DeclareSymbol("user void UncacheShadows(void);", (void *) &UncacheShadows);
_pShell->DeclareSymbol("user void RecacheShadows(void);", (void *) &RecacheShadows);
_pShell->DeclareSymbol("user void RefreshTextures(void);", (void *) &RefreshTextures);
_pShell->DeclareSymbol("user void ReloadModels(void);", (void *) &ReloadModels);
_pShell->DeclareSymbol("persistent user INDEX ogl_bUseCompiledVertexArrays;", (void *) &ogl_bUseCompiledVertexArrays);
_pShell->DeclareSymbol("persistent user INDEX ogl_bExclusive;", (void *) &ogl_bExclusive);
_pShell->DeclareSymbol("persistent user INDEX ogl_bAllowQuadArrays;", (void *) &ogl_bAllowQuadArrays);
_pShell->DeclareSymbol("persistent user INDEX ogl_iTextureCompressionType;", (void *) &ogl_iTextureCompressionType);
_pShell->DeclareSymbol("persistent user INDEX ogl_iMaxBurstSize;", (void *) &ogl_iMaxBurstSize);
_pShell->DeclareSymbol("persistent user INDEX ogl_bGrabDepthBuffer;", (void *) &ogl_bGrabDepthBuffer);
_pShell->DeclareSymbol("persistent user INDEX ogl_iFinish;", (void *) &ogl_iFinish);
_pShell->DeclareSymbol("persistent user INDEX ogl_iTBufferEffect;", (void *) &ogl_iTBufferEffect);
_pShell->DeclareSymbol("persistent user INDEX ogl_iTBufferSamples;", (void *) &ogl_iTBufferSamples);
_pShell->DeclareSymbol("persistent user INDEX ogl_bTruformLinearNormals;", (void *) &ogl_bTruformLinearNormals);
_pShell->DeclareSymbol("persistent user INDEX ogl_bAlternateClipPlane;", (void *) &ogl_bAlternateClipPlane);
_pShell->DeclareSymbol("persistent user INDEX d3d_bUseHardwareTnL;", (void *) &d3d_bUseHardwareTnL);
_pShell->DeclareSymbol("persistent user INDEX d3d_iMaxBurstSize;", (void *) &d3d_iMaxBurstSize);
_pShell->DeclareSymbol("persistent user INDEX d3d_iVertexBuffersSize;", (void *) &d3d_iVertexBuffersSize);
_pShell->DeclareSymbol("persistent user INDEX d3d_iVertexRangeTreshold;", (void *) &d3d_iVertexRangeTreshold);
_pShell->DeclareSymbol("persistent user INDEX d3d_bAlternateDepthReads;", (void *) &d3d_bAlternateDepthReads);
_pShell->DeclareSymbol("persistent user INDEX d3d_bOptimizeVertexBuffers;", (void *) &d3d_bOptimizeVertexBuffers);
_pShell->DeclareSymbol("persistent user INDEX d3d_iFinish;", (void *) &d3d_iFinish);
_pShell->DeclareSymbol("persistent user INDEX gap_iUseTextureUnits;", (void *) &gap_iUseTextureUnits);
_pShell->DeclareSymbol("persistent user INDEX gap_iTextureFiltering;", (void *) &gap_iTextureFiltering);
_pShell->DeclareSymbol("persistent user INDEX gap_iTextureAnisotropy;", (void *) &gap_iTextureAnisotropy);
_pShell->DeclareSymbol("persistent user FLOAT gap_fTextureLODBias;", (void *) &gap_fTextureLODBias);
_pShell->DeclareSymbol("persistent user INDEX gap_bAllowGrayTextures;", (void *) &gap_bAllowGrayTextures);
_pShell->DeclareSymbol("persistent user INDEX gap_bAllowSingleMipmap;", (void *) &gap_bAllowSingleMipmap);
_pShell->DeclareSymbol("persistent user INDEX gap_bOptimizeStateChanges;", (void *) &gap_bOptimizeStateChanges);
_pShell->DeclareSymbol("persistent user INDEX gap_iOptimizeDepthReads;", (void *) &gap_iOptimizeDepthReads);
_pShell->DeclareSymbol("persistent user INDEX gap_iOptimizeClipping;", (void *) &gap_iOptimizeClipping);
_pShell->DeclareSymbol("persistent user INDEX gap_iSwapInterval;", (void *) &gap_iSwapInterval);
_pShell->DeclareSymbol("persistent user INDEX gap_iRefreshRate;", (void *) &gap_iRefreshRate);
_pShell->DeclareSymbol("persistent user INDEX gap_iDithering;", (void *) &gap_iDithering);
_pShell->DeclareSymbol("persistent user INDEX gap_bForceTruform;", (void *) &gap_bForceTruform);
_pShell->DeclareSymbol("persistent user INDEX gap_iTruformLevel;", (void *) &gap_iTruformLevel);
_pShell->DeclareSymbol("persistent user INDEX gap_iDepthBits;", (void *) &gap_iDepthBits);
_pShell->DeclareSymbol("persistent user INDEX gap_iStencilBits;", (void *) &gap_iStencilBits);
_pShell->DeclareSymbol("void MdlPostFunc(INDEX);", (void *) &MdlPostFunc);
_pShell->DeclareSymbol(" user INDEX gfx_bRenderPredicted;", (void *) &gfx_bRenderPredicted);
_pShell->DeclareSymbol(" user INDEX gfx_bRenderModels;", (void *) &gfx_bRenderModels);
_pShell->DeclareSymbol(" user INDEX mdl_bShowTriangles;", (void *) &mdl_bShowTriangles);
_pShell->DeclareSymbol(" user INDEX mdl_bCreateStrips;", (void *) &mdl_bCreateStrips);
_pShell->DeclareSymbol(" user INDEX mdl_bShowStrips;", (void *) &mdl_bShowStrips);
_pShell->DeclareSymbol("persistent user FLOAT mdl_fLODMul;", (void *) &mdl_fLODMul);
_pShell->DeclareSymbol("persistent user FLOAT mdl_fLODAdd;", (void *) &mdl_fLODAdd);
_pShell->DeclareSymbol("persistent user INDEX mdl_iLODDisappear;", (void *) &mdl_iLODDisappear);
_pShell->DeclareSymbol("persistent user INDEX mdl_bRenderDetail;", (void *) &mdl_bRenderDetail);
_pShell->DeclareSymbol("persistent user INDEX mdl_bRenderSpecular;", (void *) &mdl_bRenderSpecular);
_pShell->DeclareSymbol("persistent user INDEX mdl_bRenderReflection;", (void *) &mdl_bRenderReflection);
_pShell->DeclareSymbol("persistent user INDEX mdl_bAllowOverbright;", (void *) &mdl_bAllowOverbright);
_pShell->DeclareSymbol("persistent user INDEX mdl_bFineQuality post:MdlPostFunc;", (void *) &mdl_bFineQuality);
_pShell->DeclareSymbol("persistent user INDEX mdl_iShadowQuality;", (void *) &mdl_iShadowQuality);
// !!! FIXME : rcg11232001 Hhmm...I'm failing an assertion in the
// !!! FIXME : rcg11232001 Advanced Rendering Options menu because
// !!! FIXME : rcg11232001 Scripts/CustomOptions/GFX-AdvancedRendering.cfg
// !!! FIXME : rcg11232001 references non-existing cvars, so I'm adding
// !!! FIXME : rcg11232001 them here for now.
// _pShell->DeclareSymbol("persistent user INDEX mdl_bRenderBump;", (void *) &mdl_bRenderBump);
// _pShell->DeclareSymbol("persistent user FLOAT ogl_fTextureAnisotropy;", (void *) &ogl_fTextureAnisotropy);
_pShell->DeclareSymbol("persistent user FLOAT tex_fNormalSize;", (void *) &tex_fNormalSize);
_pShell->DeclareSymbol(" INDEX mdl_bTruformWeapons;", (void *) &mdl_bTruformWeapons);
_pShell->DeclareSymbol("persistent user FLOAT gfx_tmProbeDecay;", (void *) &gfx_tmProbeDecay);
_pShell->DeclareSymbol("persistent user INDEX gfx_iProbeSize;", (void *) &gfx_iProbeSize);
_pShell->DeclareSymbol("persistent user INDEX gfx_bClearScreen;", (void *) &gfx_bClearScreen);
_pShell->DeclareSymbol("persistent user INDEX gfx_bDisableMultiMonSupport;", (void *) &gfx_bDisableMultiMonSupport);
_pShell->DeclareSymbol("persistent user INDEX gfx_bDisableWindowsKeys;", (void *) &gfx_bDisableWindowsKeys);
_pShell->DeclareSymbol("persistent user INDEX gfx_bDecoratedText;", (void *) &gfx_bDecoratedText);
_pShell->DeclareSymbol(" const user INDEX gfx_ctMonitors;", (void *) &gfx_ctMonitors);
_pShell->DeclareSymbol(" const user INDEX gfx_bMultiMonDisabled;", (void *) &gfx_bMultiMonDisabled);
_pShell->DeclareSymbol("persistent user INDEX tex_iNormalQuality;", (void *) &tex_iNormalQuality);
_pShell->DeclareSymbol("persistent user INDEX tex_iAnimationQuality;", (void *) &tex_iAnimationQuality);
_pShell->DeclareSymbol("persistent user INDEX tex_iNormalSize;", (void *) &tex_iNormalSize);
_pShell->DeclareSymbol("persistent user INDEX tex_iAnimationSize;", (void *) &tex_iAnimationSize);
_pShell->DeclareSymbol("persistent user INDEX tex_iEffectSize;", (void *) &tex_iEffectSize);
_pShell->DeclareSymbol("persistent user INDEX tex_bFineEffect;", (void *) &tex_bFineEffect);
_pShell->DeclareSymbol("persistent user INDEX tex_bFineFog;", (void *) &tex_bFineFog);
_pShell->DeclareSymbol("persistent user INDEX tex_iFogSize;", (void *) &tex_iFogSize);
_pShell->DeclareSymbol("persistent user INDEX tex_bCompressAlphaChannel;", &tex_bCompressAlphaChannel);
_pShell->DeclareSymbol("persistent user INDEX tex_bAlternateCompression;", &tex_bAlternateCompression);
_pShell->DeclareSymbol("persistent user INDEX tex_bDynamicMipmaps;", &tex_bDynamicMipmaps);
_pShell->DeclareSymbol("persistent user INDEX tex_iDithering;", (void *) &tex_iDithering);
_pShell->DeclareSymbol("persistent user INDEX tex_iFiltering;", (void *) &tex_iFiltering);
_pShell->DeclareSymbol("persistent user INDEX tex_iEffectFiltering;", (void *) &tex_iEffectFiltering);
_pShell->DeclareSymbol("persistent user INDEX tex_bProgressiveFilter;", (void *) &tex_bProgressiveFilter);
_pShell->DeclareSymbol(" user INDEX tex_bColorizeMipmaps;", (void *) &tex_bColorizeMipmaps);
_pShell->DeclareSymbol("persistent user INDEX shd_iStaticSize;", (void *) &shd_iStaticSize);
_pShell->DeclareSymbol("persistent user INDEX shd_iDynamicSize;", (void *) &shd_iDynamicSize);
_pShell->DeclareSymbol("persistent user INDEX shd_bFineQuality;", (void *) &shd_bFineQuality);
_pShell->DeclareSymbol("persistent user INDEX shd_iAllowDynamic;", (void *) &shd_iAllowDynamic);
_pShell->DeclareSymbol("persistent user INDEX shd_bDynamicMipmaps;", (void *) &shd_bDynamicMipmaps);
_pShell->DeclareSymbol("persistent user INDEX shd_iFiltering;", (void *) &shd_iFiltering);
_pShell->DeclareSymbol("persistent user INDEX shd_iDithering;", (void *) &shd_iDithering);
_pShell->DeclareSymbol("persistent user FLOAT shd_tmFlushDelay;", (void *) &shd_tmFlushDelay);
_pShell->DeclareSymbol("persistent user FLOAT shd_fCacheSize;", (void *) &shd_fCacheSize);
_pShell->DeclareSymbol("persistent user INDEX shd_bCacheAll;", (void *) &shd_bCacheAll);
_pShell->DeclareSymbol("persistent user INDEX shd_bAllowFlats;", (void *) &shd_bAllowFlats);
_pShell->DeclareSymbol("persistent INDEX shd_iForceFlats;", (void *) &shd_iForceFlats);
_pShell->DeclareSymbol(" user INDEX shd_bShowFlats;", (void *) &shd_bShowFlats);
_pShell->DeclareSymbol(" user INDEX shd_bColorize;", (void *) &shd_bColorize);
_pShell->DeclareSymbol(" user INDEX gfx_bRenderParticles;", (void *) &gfx_bRenderParticles);
_pShell->DeclareSymbol(" user INDEX gfx_bRenderFog;", (void *) &gfx_bRenderFog);
_pShell->DeclareSymbol(" user INDEX gfx_bRenderWorld;", (void *) &gfx_bRenderWorld);
_pShell->DeclareSymbol("persistent user INDEX gfx_iLensFlareQuality;", (void *) &gfx_iLensFlareQuality);
_pShell->DeclareSymbol("persistent user INDEX wld_bTextureLayers;", (void *) &wld_bTextureLayers);
_pShell->DeclareSymbol("persistent user INDEX wld_bRenderMirrors;", (void *) &wld_bRenderMirrors);
_pShell->DeclareSymbol("persistent user FLOAT wld_fEdgeOffsetI;", (void *) &wld_fEdgeOffsetI);
_pShell->DeclareSymbol("persistent user FLOAT wld_fEdgeAdjustK;", (void *) &wld_fEdgeAdjustK);
_pShell->DeclareSymbol("persistent user INDEX wld_iDetailRemovingBias;", (void *) &wld_iDetailRemovingBias);
_pShell->DeclareSymbol(" user INDEX wld_bRenderEmptyBrushes;", (void *) &wld_bRenderEmptyBrushes);
_pShell->DeclareSymbol(" user INDEX wld_bRenderShadowMaps;", (void *) &wld_bRenderShadowMaps);
_pShell->DeclareSymbol(" user INDEX wld_bRenderTextures;", (void *) &wld_bRenderTextures);
_pShell->DeclareSymbol(" user INDEX wld_bRenderDetailPolygons;", &wld_bRenderDetailPolygons);
_pShell->DeclareSymbol(" user INDEX wld_bShowTriangles;", (void *) &wld_bShowTriangles);
_pShell->DeclareSymbol(" user INDEX wld_bShowDetailTextures;", (void *) &wld_bShowDetailTextures);
_pShell->DeclareSymbol(" user INDEX wed_bIgnoreTJunctions;", (void *) &wed_bIgnoreTJunctions);
_pShell->DeclareSymbol("persistent user INDEX wed_bUseBaseForReplacement;", (void *) &wed_bUseBaseForReplacement);
_pShell->DeclareSymbol("persistent user INDEX tex_iHueShift;", (void *) &tex_iHueShift);
_pShell->DeclareSymbol("persistent user FLOAT tex_fSaturation;", (void *) &tex_fSaturation);
_pShell->DeclareSymbol("persistent user INDEX shd_iHueShift;", (void *) &shd_iHueShift);
_pShell->DeclareSymbol("persistent user FLOAT shd_fSaturation;", (void *) &shd_fSaturation);
_pShell->DeclareSymbol("persistent user INDEX gfx_iHueShift;", (void *) &gfx_iHueShift);
_pShell->DeclareSymbol("persistent user FLOAT gfx_fSaturation;", (void *) &gfx_fSaturation);
_pShell->DeclareSymbol("persistent user FLOAT gfx_fBrightness;", (void *) &gfx_fBrightness);
_pShell->DeclareSymbol("persistent user FLOAT gfx_fContrast;", (void *) &gfx_fContrast);
_pShell->DeclareSymbol("persistent user FLOAT gfx_fGamma;", (void *) &gfx_fGamma);
_pShell->DeclareSymbol("persistent user FLOAT gfx_fBiasR;", (void *) &gfx_fBiasR);
_pShell->DeclareSymbol("persistent user FLOAT gfx_fBiasG;", (void *) &gfx_fBiasG);
_pShell->DeclareSymbol("persistent user FLOAT gfx_fBiasB;", (void *) &gfx_fBiasB);
_pShell->DeclareSymbol("persistent user INDEX gfx_iLevels;", (void *) &gfx_iLevels);
_pShell->DeclareSymbol("persistent user INDEX gfx_iStereo;", (void *) &gfx_iStereo);
_pShell->DeclareSymbol("persistent user INDEX gfx_bStereoInvert;", (void *) &gfx_bStereoInvert);
_pShell->DeclareSymbol("persistent user INDEX gfx_iStereoOffset;", (void *) &gfx_iStereoOffset);
_pShell->DeclareSymbol("persistent user FLOAT gfx_fStereoSeparation;", (void *) &gfx_fStereoSeparation);
_pShell->DeclareSymbol( "INDEX sys_bHasTextureCompression;", (void *) &sys_bHasTextureCompression);
_pShell->DeclareSymbol( "INDEX sys_bHasTextureAnisotropy;", (void *) &sys_bHasTextureAnisotropy);
_pShell->DeclareSymbol( "INDEX sys_bHasAdjustableGamma;", (void *) &sys_bHasAdjustableGamma);
_pShell->DeclareSymbol( "INDEX sys_bHasTextureLODBias;", (void *) &sys_bHasTextureLODBias);
_pShell->DeclareSymbol( "INDEX sys_bHasMultitexturing;", (void *) &sys_bHasMultitexturing);
_pShell->DeclareSymbol( "INDEX sys_bHas32bitTextures;", (void *) &sys_bHas32bitTextures);
_pShell->DeclareSymbol( "INDEX sys_bHasSwapInterval;", (void *) &sys_bHasSwapInterval);
_pShell->DeclareSymbol( "INDEX sys_bHasHardwareTnL;", (void *) &sys_bHasHardwareTnL);
_pShell->DeclareSymbol( "INDEX sys_bHasTruform;", (void *) &sys_bHasTruform);
_pShell->DeclareSymbol( "INDEX sys_bHasCVAs;", (void *) &sys_bHasCVAs);
_pShell->DeclareSymbol( "INDEX sys_bUsingOpenGL;", (void *) &sys_bUsingOpenGL);
_pShell->DeclareSymbol( "INDEX sys_bUsingDirect3D;", (void *) &sys_bUsingDirect3D);
// initialize gfx APIs support
InitAPIs();
}
// set new display mode
BOOL CGfxLibrary::SetDisplayMode( enum GfxAPIType eAPI, INDEX iAdapter, PIX pixSizeI, PIX pixSizeJ,
enum DisplayDepth eColorDepth)
{
// some safeties
ASSERT( pixSizeI>0 && pixSizeJ>0);
// determine new API
GfxAPIType eNewAPI = eAPI;
if( eNewAPI==GAT_CURRENT) eNewAPI = gl_eCurrentAPI;
// shutdown old and startup new API, and mode and ... stuff, you know!
StopDisplayMode();
BOOL bRet = StartDisplayMode( eNewAPI, iAdapter, pixSizeI, pixSizeJ, eColorDepth);
if( !bRet) return FALSE; // didn't make it?
// update some info
gl_iCurrentAdapter = gl_gaAPI[gl_eCurrentAPI].ga_iCurrentAdapter = iAdapter;
gl_dmCurrentDisplayMode.dm_pixSizeI = pixSizeI;
gl_dmCurrentDisplayMode.dm_pixSizeJ = pixSizeJ;
gl_dmCurrentDisplayMode.dm_ddDepth = eColorDepth;
// prepare texture formats for this display mode
extern void DetermineSupportedTextureFormats( GfxAPIType eAPI);
DetermineSupportedTextureFormats(gl_eCurrentAPI);
// made it! (eventually disable windows system keys)
if( gfx_bDisableWindowsKeys) DisableWindowsKeys();
return TRUE;
}
// set display mode to original desktop display mode and default ICD driver
BOOL CGfxLibrary::ResetDisplayMode( enum GfxAPIType eAPI/*=GAT_CURRENT*/)
{
// determine new API
GfxAPIType eNewAPI = eAPI;
if( eNewAPI==GAT_CURRENT) eNewAPI = gl_eCurrentAPI;
// shutdown old and startup new API, and mode and ... stuff, you know!
StopDisplayMode();
BOOL bRet = StartDisplayMode( eNewAPI, 0, 0, 0, DD_DEFAULT);
if( !bRet) return FALSE; // didn't make it?
// update some info
gl_iCurrentAdapter = 0;
gl_dmCurrentDisplayMode.dm_pixSizeI = 0;
gl_dmCurrentDisplayMode.dm_pixSizeJ = 0;
gl_dmCurrentDisplayMode.dm_ddDepth = DD_DEFAULT;
// prepare texture formats for this display mode
extern void DetermineSupportedTextureFormats( GfxAPIType eAPI);
DetermineSupportedTextureFormats(gl_eCurrentAPI);
// made it!
EnableWindowsKeys();
return TRUE;
}
// startup gfx API and set given display mode
BOOL CGfxLibrary::StartDisplayMode( enum GfxAPIType eAPI, INDEX iAdapter, PIX pixSizeI, PIX pixSizeJ,
enum DisplayDepth eColorDepth)
{
// reinit gamma table
_fLastBrightness = 999;
_fLastContrast = 999;
_fLastGamma = 999;
_iLastLevels = 999;
_fLastBiasR = 999;
_fLastBiasG = 999;
_fLastBiasB = 999;
// prepare
BOOL bSuccess;
ASSERT( iAdapter>=0);
const BOOL bFullScreen = (pixSizeI>0 && pixSizeJ>0);
gl_ulFlags &= GLF_ADJUSTABLEGAMMA;
gl_ctDriverChanges++;
GFX_bRenderingScene = FALSE;
GFX_ulLastDrawPortID = 0;
gl_iTessellationLevel = 0;
gl_ctRealTextureUnits = 0;
_iLastVertexBufferSize = 0;
// OpenGL driver ?
if( eAPI==GAT_OGL)
{
// disable multimonitor support if it can interfere with OpenGL
MonitorsOff();
if( bFullScreen) {
// set windows mode to fit same size
bSuccess = CDS_SetMode( pixSizeI, pixSizeJ, eColorDepth);
if( !bSuccess) return FALSE;
} else {
// reset windows mode
CDS_ResetMode();
}
// startup OpenGL
// !!! FIXME : Do something with this.
#ifdef PLATFORM_UNIX
gl_dmCurrentDisplayMode.dm_pixSizeI = pixSizeI;
gl_dmCurrentDisplayMode.dm_pixSizeJ = pixSizeJ;
Uint8 bpp;
switch(eColorDepth) {
case DD_DEFAULT:
gl_iCurrentDepth = 0;
break;
case DD_16BIT:
gl_iCurrentDepth = 16;
break;
case DD_32BIT:
gl_iCurrentDepth = 32;
break;
default:
ASSERT(FALSE);
NOTHING;
}
#endif
bSuccess = InitDriver_OGL(iAdapter!=0);
// try to setup sub-driver
if( !bSuccess) {
// reset windows mode and fail
CDS_ResetMode();
return FALSE;
} // made it
gl_eCurrentAPI = GAT_OGL;
gl_iSwapInterval = 1234; // need to reset
}
// DirectX driver ?
#ifdef SE1_D3D
else if( eAPI==GAT_D3D)
{
// startup D3D
bSuccess = InitDriver_D3D();
if( !bSuccess) return FALSE; // what, didn't make it?
bSuccess = InitDisplay_D3D( iAdapter, pixSizeI, pixSizeJ, eColorDepth);
if( !bSuccess) return FALSE;
// made it
gl_eCurrentAPI = GAT_D3D;
}
#endif // SE1_D3D
// no driver
else
{
ASSERT( eAPI==GAT_NONE);
gl_eCurrentAPI = GAT_NONE;
}
// initialize on first child window
gl_iFrameNumber = 0;
gl_pvpActive = NULL;
gl_ulFlags |= GLF_INITONNEXTWINDOW;
bFullScreen ? gl_ulFlags|=GLF_FULLSCREEN : gl_ulFlags&=~GLF_FULLSCREEN;
// mark that some things needs to be reinitialized
gl_fTextureLODBias = 0.0f;
// set function pointers
GFX_SetFunctionPointers( (INDEX)gl_eCurrentAPI);
// all done
return TRUE;
}
// Stop display mode and shutdown API
void CGfxLibrary::StopDisplayMode(void)
{
// release all cached shadows and models' arrays
extern void Models_ClearVertexArrays(void);
extern void UncacheShadows(void);
Models_ClearVertexArrays();
UncacheShadows();
// shutdown API
if( gl_eCurrentAPI==GAT_OGL)
{ // OpenGL
EndDriver_OGL();
MonitorsOn(); // re-enable multimonitor support if disabled
CDS_ResetMode();
}
#ifdef PLATFORM_WIN32
else if( gl_eCurrentAPI==GAT_D3D)
{ // Direct3D
EndDriver_D3D();
MonitorsOn();
}
#endif
else
{ // none
ASSERT( gl_eCurrentAPI==GAT_NONE);
}
// free driver DLL
if (gl_hiDriver != NULL)
delete gl_hiDriver;
gl_hiDriver = NULL;
// reset some vars
gl_ctRealTextureUnits = 0;
gl_eCurrentAPI = GAT_NONE;
gl_pvpActive = NULL;
gl_ulFlags &= GLF_ADJUSTABLEGAMMA;
// reset function pointers
GFX_SetFunctionPointers( (INDEX)GAT_NONE);
}
// prepare current viewport for rendering
BOOL CGfxLibrary::SetCurrentViewport(CViewPort *pvp)
{
if( gl_eCurrentAPI==GAT_OGL) return SetCurrentViewport_OGL(pvp);
#ifdef SE1_D3D
if( gl_eCurrentAPI==GAT_D3D) return SetCurrentViewport_D3D(pvp);
#endif // SE1_D3D
if( gl_eCurrentAPI==GAT_NONE) return TRUE;
ASSERTALWAYS( "SetCurrenViewport: Wrong API!");
return FALSE;
}
// Lock a drawport for drawing
BOOL CGfxLibrary::LockDrawPort( CDrawPort *pdpToLock)
{
// check API
#ifdef SE1_D3D
ASSERT( gl_eCurrentAPI==GAT_OGL || gl_eCurrentAPI==GAT_D3D || gl_eCurrentAPI==GAT_NONE);
#else // SE1_D3D
ASSERT( gl_eCurrentAPI==GAT_OGL || gl_eCurrentAPI==GAT_NONE);
#endif // SE1_D3D
// don't allow locking if drawport is too small
if( pdpToLock->dp_Width<1 || pdpToLock->dp_Height<1) return FALSE;
// don't set if same as last
const ULONG ulThisDrawPortID = pdpToLock->GetID();
if( GFX_ulLastDrawPortID==ulThisDrawPortID && gap_bOptimizeStateChanges) {
// just set projection
pdpToLock->SetOrtho();
return TRUE;
}
// OpenGL ...
if( gl_eCurrentAPI==GAT_OGL)
{
// pass drawport dimensions to OpenGL
const PIX pixMinSI = pdpToLock->dp_ScissorMinI;
const PIX pixMaxSI = pdpToLock->dp_ScissorMaxI;
const PIX pixMinSJ = pdpToLock->dp_Raster->ra_Height -1 - pdpToLock->dp_ScissorMaxJ;
const PIX pixMaxSJ = pdpToLock->dp_Raster->ra_Height -1 - pdpToLock->dp_ScissorMinJ;
pglViewport( pixMinSI, pixMinSJ, pixMaxSI-pixMinSI+1, pixMaxSJ-pixMinSJ+1);
pglScissor( pixMinSI, pixMinSJ, pixMaxSI-pixMinSI+1, pixMaxSJ-pixMinSJ+1);
OGL_CHECKERROR;
}
// Direct3D ...
#ifdef SE1_D3D
else if( gl_eCurrentAPI==GAT_D3D)
{
// set viewport
const PIX pixMinSI = pdpToLock->dp_ScissorMinI;
const PIX pixMaxSI = pdpToLock->dp_ScissorMaxI;
const PIX pixMinSJ = pdpToLock->dp_ScissorMinJ;
const PIX pixMaxSJ = pdpToLock->dp_ScissorMaxJ;
D3DVIEWPORT8 d3dViewPort = { pixMinSI, pixMinSJ, pixMaxSI-pixMinSI+1, pixMaxSJ-pixMinSJ+1, 0,1 };
HRESULT hr = gl_pd3dDevice->SetViewport( &d3dViewPort);
D3D_CHECKERROR(hr);
}
#endif // SE1_D3D
// mark and set default projection
GFX_ulLastDrawPortID = ulThisDrawPortID;
pdpToLock->SetOrtho();
return TRUE;
}
// Unlock a drawport after drawing
void CGfxLibrary::UnlockDrawPort( CDrawPort *pdpToUnlock)
{
// check API
#ifdef SE1_D3D
ASSERT(gl_eCurrentAPI == GAT_OGL || gl_eCurrentAPI == GAT_D3D || gl_eCurrentAPI == GAT_NONE);
#else // SE1_D3D
ASSERT(gl_eCurrentAPI == GAT_OGL || gl_eCurrentAPI == GAT_NONE);
#endif // SE1_D3D
// eventually signalize that scene rendering has ended
}
/////////////////////////////////////////////////////////////////////
// Window canvas functions
/* Create a new window canvas. */
void CGfxLibrary::CreateWindowCanvas(void *hWnd, CViewPort **ppvpNew, CDrawPort **ppdpNew)
{
RECT rectWindow; // rectangle for the client area of the window
// get the dimensions from the window
// !!! FIXME : rcg11052001 Abstract this.
#ifdef PLATFORM_WIN32
GetClientRect( (HWND)hWnd, &rectWindow);
PIX pixWidth = rectWindow.right - rectWindow.left;
PIX pixHeight = rectWindow.bottom - rectWindow.top;
#else
SDL_Surface *screen = SDL_GetVideoSurface();
PIX pixWidth = screen->w;
PIX pixHeight = screen->h;
#endif
*ppvpNew = NULL;
*ppdpNew = NULL;
// create a new viewport
if (*ppvpNew = new CViewPort( pixWidth, pixHeight, (HWND)hWnd)) {
// and it's drawport
*ppdpNew = &(*ppvpNew)->vp_Raster.ra_MainDrawPort;
} else {
delete *ppvpNew;
*ppvpNew = NULL;
}
}
/* Destroy a window canvas. */
void CGfxLibrary::DestroyWindowCanvas(CViewPort *pvpOld) {
// delete the viewport
delete pvpOld;
}
/////////////////////////////////////////////////////////////////////
// Work canvas functions
#ifdef PLATFORM_WIN32
#define WorkCanvasCLASS "WorkCanvas Window"
static BOOL _bClassRegistered = FALSE;
/* Create a work canvas. */
void CGfxLibrary::CreateWorkCanvas(PIX pixWidth, PIX pixHeight, CDrawPort **ppdpNew)
{
// must have dimensions
ASSERT (pixWidth>0 || pixHeight>0);
if (!_bClassRegistered) {
_bClassRegistered = TRUE;
WNDCLASSA wc;
// must have owndc for opengl and dblclks to give to parent
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = NULL;
wc.hIcon = NULL;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = WorkCanvasCLASS;
RegisterClassA(&wc);
}
// create a window
HWND hWnd = ::CreateWindowExA(
0,
WorkCanvasCLASS,
"", // title
WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_POPUP,
0,0,
pixWidth, pixHeight, // window size
NULL,
NULL,
NULL, //hInstance,
NULL);
ASSERT(hWnd != NULL);
*ppdpNew = NULL;
CViewPort *pvp;
CreateWindowCanvas(hWnd, &pvp, ppdpNew);
}
/* Destroy a work canvas. */
void CGfxLibrary::DestroyWorkCanvas(CDrawPort *pdpOld)
{
CViewPort *pvp = pdpOld->dp_Raster->ra_pvpViewPort;
HWND hwnd = pvp->vp_hWndParent;
DestroyWindowCanvas(pvp);
::DestroyWindow(hwnd);
}
#endif
// optimize memory used by cached shadow maps
#define SHADOWMAXBYTES (256*256*4*4/3)
static SLONG slCachedShadowMemory=0, slDynamicShadowMemory=0;
static INDEX ctCachedShadows=0, ctFlatShadows=0, ctDynamicShadows=0;
BOOL _bShadowsUpdated = TRUE;
void CGfxLibrary::ReduceShadows(void)
{
_sfStats.StartTimer( CStatForm::STI_SHADOWUPDATE);
// clamp shadow caching variables
shd_fCacheSize = Clamp( shd_fCacheSize, 0.1f, 128.0f);
shd_tmFlushDelay = Clamp( shd_tmFlushDelay, 0.1f, 120.0f);
CTimerValue tvNow = _pTimer->GetHighPrecisionTimer(); // readout current time
const TIME tmAcientDelay = Clamp( shd_tmFlushDelay*3, 60.0f, 300.0f);
// determine cached shadowmaps stats (if needed)
if( _bShadowsUpdated)
{
_bShadowsUpdated = FALSE;
slCachedShadowMemory=0; slDynamicShadowMemory=0;
ctCachedShadows=0; ctFlatShadows=0; ctDynamicShadows=0;
{FORDELETELIST( CShadowMap, sm_lnInGfx, _pGfx->gl_lhCachedShadows, itsm) {
CShadowMap &sm = *itsm;
ASSERT( sm.sm_pulCachedShadowMap!=NULL); // must be cached
ASSERT( sm.sm_slMemoryUsed>0 && sm.sm_slMemoryUsed<=SHADOWMAXBYTES); // and have valid size
// remove acient shadowmaps from list (if allowed)
const TIME tmDelta = (tvNow-sm.sm_tvLastDrawn).GetSeconds();
if( tmDelta>tmAcientDelay && !(sm.sm_ulFlags&SMF_PROBED) && !shd_bCacheAll) {
sm.Uncache();
continue;
}
// determine type and occupied space
const BOOL bDynamic = sm.sm_pulDynamicShadowMap!=NULL;
const BOOL bFlat = sm.sm_pulCachedShadowMap==&sm.sm_colFlat;
if( bDynamic) { slDynamicShadowMemory += sm.sm_slMemoryUsed; ctDynamicShadows++; }
if( !bFlat) { slCachedShadowMemory += sm.sm_slMemoryUsed; ctCachedShadows++; }
else { slCachedShadowMemory += sizeof(sm.sm_colFlat); ctFlatShadows++; }
}}
}
// update statistics counters
_pfGfxProfile.IncrementCounter(CGfxProfile::PCI_CACHEDSHADOWBYTES, slCachedShadowMemory);
_pfGfxProfile.IncrementCounter(CGfxProfile::PCI_CACHEDSHADOWS, ctCachedShadows);
_pfGfxProfile.IncrementCounter(CGfxProfile::PCI_FLATSHADOWS, ctFlatShadows);
_pfGfxProfile.IncrementCounter(CGfxProfile::PCI_DYNAMICSHADOWBYTES, slDynamicShadowMemory);
_pfGfxProfile.IncrementCounter(CGfxProfile::PCI_DYNAMICSHADOWS, ctDynamicShadows);
_sfStats.IncrementCounter( CStatForm::SCI_CACHEDSHADOWBYTES, slCachedShadowMemory);
_sfStats.IncrementCounter( CStatForm::SCI_CACHEDSHADOWS, ctCachedShadows);
_sfStats.IncrementCounter( CStatForm::SCI_FLATSHADOWS, ctFlatShadows);
_sfStats.IncrementCounter( CStatForm::SCI_DYNAMICSHADOWBYTES, slDynamicShadowMemory);
_sfStats.IncrementCounter( CStatForm::SCI_DYNAMICSHADOWS, ctDynamicShadows);
// done if reducing is not allowed
if( shd_bCacheAll) {
_sfStats.StopTimer( CStatForm::STI_SHADOWUPDATE);
return;
}
// optimize only if low on memory
ULONG ulShadowCacheSize = (ULONG)(shd_fCacheSize*1024*1024); // in bytes
ULONG ulUsedShadowMemory = slCachedShadowMemory + slDynamicShadowMemory;
if( ulUsedShadowMemory <= ulShadowCacheSize) {
_sfStats.StopTimer( CStatForm::STI_SHADOWUPDATE);
return;
}
// reduce shadow delay if needed
// (lineary from specified value to 2sec for cachedsize>specsize to cachedsize>2*specsize)
TIME tmFlushDelay = shd_tmFlushDelay;
if( tmFlushDelay>2.0f) {
FLOAT fRatio = (FLOAT)ulUsedShadowMemory / ulShadowCacheSize;
ASSERT( fRatio>=1.0f);
fRatio = ClampUp( fRatio/2.0f, 1.0f);
tmFlushDelay = Lerp( tmFlushDelay, 2.0f, fRatio);
}
// loop thru cached shadowmaps list
{FORDELETELIST( CShadowMap, sm_lnInGfx, _pGfx->gl_lhCachedShadows, itsm)
{ // stop iteration if current shadow map it is not too old (list is sorted by time)
// or we have enough memory for cached shadows that remain
CShadowMap &sm = *itsm;
const TIME tmDelta = (tvNow-sm.sm_tvLastDrawn).GetSeconds();
if( tmDelta<tmFlushDelay || ulUsedShadowMemory<ulShadowCacheSize) break;
// uncache shadow (this returns ammount of memory that has been freed)
ulUsedShadowMemory -= sm.Uncache();
ASSERT( ulUsedShadowMemory>=0);
}}
// done
_sfStats.StopTimer( CStatForm::STI_SHADOWUPDATE);
}
// some vars for probing
INDEX _ctProbeTexs = 0;
INDEX _ctProbeShdU = 0;
INDEX _ctProbeShdB = 0;
INDEX _ctFullShdU = 0;
SLONG _slFullShdUBytes = 0;
static BOOL GenerateGammaTable(void);
/*
* Swap buffers in a viewport.
*/
void CGfxLibrary::SwapBuffers(CViewPort *pvp)
{
// check API
#ifdef SE1_D3D
ASSERT(gl_eCurrentAPI == GAT_OGL || gl_eCurrentAPI == GAT_D3D || gl_eCurrentAPI == GAT_NONE);
#else // SE1_D3D
ASSERT(gl_eCurrentAPI == GAT_OGL || gl_eCurrentAPI == GAT_NONE);
#endif // SE1_D3D
// safety check
ASSERT( gl_pvpActive!=NULL);
if( pvp!=gl_pvpActive) {
ASSERTALWAYS( "Swapping viewport that was not last drawn to!");
return;
}
// optimize memory used by cached shadow maps and update shadowmap counters
ReduceShadows();
// check and eventually adjust texture filtering and LOD biasing
gfxSetTextureFiltering( gap_iTextureFiltering, gap_iTextureAnisotropy);
gfxSetTextureBiasing( gap_fTextureLODBias);
// clamp some cvars
gap_iDithering = Clamp( gap_iDithering, 0L, 2L);
gap_iSwapInterval = Clamp( gap_iSwapInterval, 0L, 4L);
gap_iOptimizeClipping = Clamp( gap_iOptimizeClipping, 0L, 2L);
gap_iTruformLevel = Clamp( gap_iTruformLevel, 0L, _pGfx->gl_iMaxTessellationLevel);
ogl_iFinish = Clamp( ogl_iFinish, 0L, 3L);
d3d_iFinish = Clamp( d3d_iFinish, 0L, 3L);
// OpenGL
if( gl_eCurrentAPI==GAT_OGL)
{
// force finishing of all rendering operations (if required)
if( ogl_iFinish==2) gfxFinish();
// check state of swap interval extension usage
if( gl_ulFlags & GLF_VSYNC) {
if( gl_iSwapInterval != gap_iSwapInterval) {
gl_iSwapInterval = gap_iSwapInterval;
pwglSwapIntervalEXT( gl_iSwapInterval);
}
}
// swap buffers
// !!! FIXME: Move this to platform-specific directories.
#ifdef PLATFORM_WIN32
CTempDC tdc(pvp->vp_hWnd);
pwglSwapBuffers(tdc.hdc);
#else
SDL_GL_SwapBuffers();
#endif
// force finishing of all rendering operations (if required)
if( ogl_iFinish==3) gfxFinish();
// reset CVA usage if ext is not present
if( !(gl_ulFlags&GLF_EXT_COMPILEDVERTEXARRAY)) ogl_bUseCompiledVertexArrays = 0;
}
// Direct3D
#ifdef SE1_D3D
else if( gl_eCurrentAPI==GAT_D3D)
{
// force finishing of all rendering operations (if required)
if( d3d_iFinish==2) gfxFinish();
// end scene rendering
HRESULT hr;
if( GFX_bRenderingScene) {
hr = gl_pd3dDevice->EndScene();
D3D_CHECKERROR(hr);
}
CDisplayMode dm;
GetCurrentDisplayMode(dm);
ASSERT( (dm.dm_pixSizeI==0 && dm.dm_pixSizeJ==0) || (dm.dm_pixSizeI!=0 && dm.dm_pixSizeJ!=0));
if( dm.dm_pixSizeI==0 || dm.dm_pixSizeJ==0 ) {
// windowed mode
hr = pvp->vp_pSwapChain->Present( NULL, NULL, NULL, NULL);
} else {
// full screen mode
hr = gl_pd3dDevice->Present( NULL, NULL, NULL, NULL);
} // done swapping
D3D_CHECKERROR(hr);
// force finishing of all rendering operations (if required)
if( d3d_iFinish==3) gfxFinish();
// eventually reset vertex buffer if something got changed
if( _iLastVertexBufferSize!=d3d_iVertexBuffersSize
|| (gl_iTessellationLevel<1 && gap_iTruformLevel>0)
|| (gl_iTessellationLevel>0 && gap_iTruformLevel<1)) {
extern void SetupVertexArrays_D3D( INDEX ctVertices);
extern void SetupIndexArray_D3D( INDEX ctVertices);
extern DWORD SetupShader_D3D( ULONG ulStreamsMask);
SetupShader_D3D(NONE);
SetupVertexArrays_D3D(0);
SetupIndexArray_D3D(0);
extern INDEX VerticesFromSize_D3D( SLONG &slSize);
const INDEX ctVertices = VerticesFromSize_D3D(d3d_iVertexBuffersSize);
SetupVertexArrays_D3D(ctVertices);
SetupIndexArray_D3D(2*ctVertices);
_iLastVertexBufferSize = d3d_iVertexBuffersSize;
}
}
#endif // SE1_D3D
// update tessellation level
gl_iTessellationLevel = gap_iTruformLevel;
// must reset drawport and rendering status for subsequent locks
GFX_ulLastDrawPortID = 0;
GFX_bRenderingScene = FALSE;
// reset frustum/ortho matrix, too
extern BOOL GFX_bViewMatrix;
extern FLOAT GFX_fLastL, GFX_fLastR, GFX_fLastT, GFX_fLastB, GFX_fLastN, GFX_fLastF;
GFX_fLastL = GFX_fLastR = GFX_fLastT = GFX_fLastB = GFX_fLastN = GFX_fLastF = 0;
GFX_bViewMatrix = TRUE;
// set maximum allowed upload ammount
gfx_iProbeSize = Clamp( gfx_iProbeSize, 1L, 16384L);
gl_slAllowedUploadBurst = gfx_iProbeSize *1024;
_ctProbeTexs = 0;
_ctProbeShdU = 0;
_ctProbeShdB = 0;
_ctFullShdU = 0;
_slFullShdUBytes = 0;
// keep time when swap buffer occured and maintain counter of frames for temporal coherence checking
gl_tvFrameTime = _pTimer->GetHighPrecisionTimer();
gl_iFrameNumber++;
// reset profiling counters
gl_ctWorldTriangles = 0;
gl_ctModelTriangles = 0;
gl_ctParticleTriangles = 0;
gl_ctTotalTriangles = 0;
// re-adjust multi-texturing support
gap_iUseTextureUnits = Clamp( gap_iUseTextureUnits, 1L, _pGfx->gl_ctTextureUnits);
ASSERT( gap_iUseTextureUnits>=1 && gap_iUseTextureUnits<=GFX_MAXTEXUNITS);
// re-get usage of compiled vertex arrays
CVA_b2D = ogl_bUseCompiledVertexArrays /100;
CVA_bWorld = ogl_bUseCompiledVertexArrays /10 %10;
CVA_bModels = ogl_bUseCompiledVertexArrays %10;
ogl_bUseCompiledVertexArrays = 0;
if( CVA_b2D) ogl_bUseCompiledVertexArrays += 100;
if( CVA_bWorld) ogl_bUseCompiledVertexArrays += 10;
if( CVA_bModels) ogl_bUseCompiledVertexArrays += 1;
// eventually advance to next sample buffer
if( (gl_ulFlags&GLF_EXT_TBUFFER) && go_ctSampleBuffers>1) {
go_iCurrentWriteBuffer--;
if( go_iCurrentWriteBuffer<0) go_iCurrentWriteBuffer = go_ctSampleBuffers-1;
pglDisable( GL_MULTISAMPLE_3DFX);
}
// clear viewport if needed
if( gfx_bClearScreen) pvp->vp_Raster.ra_MainDrawPort.Fill( C_BLACK|CT_OPAQUE);
//pvp->vp_Raster.ra_MainDrawPort.FillZBuffer(ZBUF_BACK);
// adjust gamma table if supported ...
#ifdef PLATFORM_WIN32
if( gl_ulFlags & GLF_ADJUSTABLEGAMMA) {
// ... and required
const BOOL bTableSet = GenerateGammaTable();
if( bTableSet) {
if( gl_eCurrentAPI==GAT_OGL) {
CTempDC tdc(pvp->vp_hWnd);
SetDeviceGammaRamp( tdc.hdc, &_auwGammaTable[0]);
}
#ifdef SE1_D3D
else if( gl_eCurrentAPI==GAT_D3D) {
gl_pd3dDevice->SetGammaRamp( D3DSGR_NO_CALIBRATION, (D3DGAMMARAMP*)&_auwGammaTable[0]);
}
#endif // SE1_D3D
}
}
else
#endif
// if not supported
{
// just reset settings to default
gfx_fBrightness = 0;
gfx_fContrast = 1;
gfx_fGamma = 1;
gfx_fBiasR = 1;
gfx_fBiasG = 1;
gfx_fBiasB = 1;
gfx_iLevels = 256;
}
}
// get array of all supported display modes
CDisplayMode *CGfxLibrary::EnumDisplayModes( INDEX &ctModes, enum GfxAPIType eAPI/*=GAT_CURRENT*/, INDEX iAdapter/*=0*/)
{
if( eAPI==GAT_CURRENT) eAPI = gl_eCurrentAPI;
if( iAdapter==0) iAdapter = gl_iCurrentAdapter;
CDisplayAdapter *pda = &gl_gaAPI[eAPI].ga_adaAdapter[iAdapter];
ctModes = pda->da_ctDisplayModes;
return &pda->da_admDisplayModes[0];
}
// Lock a raster for drawing.
BOOL CGfxLibrary::LockRaster( CRaster *praToLock)
{
// don't do this! it can break sync consistency in entities!
// SetFPUPrecision(FPT_24BIT);
ASSERT( praToLock->ra_pvpViewPort!=NULL);
BOOL bRes = SetCurrentViewport( praToLock->ra_pvpViewPort);
if( bRes) {
// must signal to picky Direct3D
#ifdef SE1_D3D
if( gl_eCurrentAPI==GAT_D3D && !GFX_bRenderingScene) {
HRESULT hr = gl_pd3dDevice->BeginScene();
D3D_CHECKERROR(hr);
bRes = (hr==D3D_OK);
} // mark it
#endif // SE1_D3D
GFX_bRenderingScene = TRUE;
} // done
return bRes;
}
// Unlock a raster after drawing.
void CGfxLibrary::UnlockRaster( CRaster *praToUnlock)
{
// don't do this! it can break sync consistency in entities!
// SetFPUPrecision(FPT_53BIT);
ASSERT( GFX_bRenderingScene);
}
// generates gamma table and returns true if gamma table has been changed
static BOOL GenerateGammaTable(void)
{
// only if needed
if( _fLastBrightness == gfx_fBrightness
&& _fLastContrast == gfx_fContrast
&& _fLastGamma == gfx_fGamma
&& _iLastLevels == gfx_iLevels
&& _fLastBiasR == gfx_fBiasR
&& _fLastBiasG == gfx_fBiasG
&& _fLastBiasB == gfx_fBiasB) return FALSE;
// guess it's needed
INDEX i;
gfx_fBrightness = Clamp( gfx_fBrightness, -0.8f, 0.8f);
gfx_fContrast = Clamp( gfx_fContrast, 0.2f, 4.0f);
gfx_fGamma = Clamp( gfx_fGamma, 0.2f, 4.0f);
gfx_iLevels = Clamp( gfx_iLevels, 2L, 256L);
gfx_fBiasR = Clamp( gfx_fBiasR, 0.0f, 2.0f);
gfx_fBiasG = Clamp( gfx_fBiasG, 0.0f, 2.0f);
gfx_fBiasB = Clamp( gfx_fBiasB, 0.0f, 2.0f);
_fLastBrightness = gfx_fBrightness;
_fLastContrast = gfx_fContrast;
_fLastGamma = gfx_fGamma;
_iLastLevels = gfx_iLevels;
_fLastBiasR = gfx_fBiasR;
_fLastBiasG = gfx_fBiasG;
_fLastBiasB = gfx_fBiasB;
// fill and adjust gamma
const FLOAT f1oGamma = 1.0f / gfx_fGamma;
for( i=0; i<256; i++) {
FLOAT fVal = i/255.0f;
fVal = Clamp( (FLOAT)pow(fVal,f1oGamma), 0.0f, 1.0f);
_auwGammaTable[i] = (UWORD)(fVal*65280);
}
// adjust contrast
for( i=0; i<256; i++) {
FLOAT fVal = _auwGammaTable[i]/65280.0f;
fVal = Clamp( (fVal-0.5f)*gfx_fContrast +0.5f, 0.0f, 1.0f);
_auwGammaTable[i] = (UWORD)(fVal*65280);
}
// adjust brightness
INDEX iAdd = (INDEX) (256* 256*gfx_fBrightness);
for( i=0; i<256; i++) {
_auwGammaTable[i] = Clamp( _auwGammaTable[i]+iAdd, 0L, 65280L);
}
// adjust levels (posterize)
if( gfx_iLevels<256) {
const FLOAT fLevels = 256 * 256.0f/gfx_iLevels;
for( i=0; i<256; i++) {
INDEX iVal = _auwGammaTable[i];
iVal = (INDEX) (((INDEX)(iVal/fLevels)) *fLevels);
_auwGammaTable[i] = ClampUp( iVal, 0xFF00L);
}
}
// copy R to G and B array
for( i=0; i<256; i++) {
FLOAT fR,fG,fB;
fR=fG=fB = _auwGammaTable[i]/65280.0f;
fR = Clamp( fR*gfx_fBiasR, 0.0f, 1.0f);
fG = Clamp( fG*gfx_fBiasG, 0.0f, 1.0f);
fB = Clamp( fB*gfx_fBiasB, 0.0f, 1.0f);
_auwGammaTable[i+0] = (UWORD)(fR*65280);
_auwGammaTable[i+256] = (UWORD)(fG*65280);
_auwGammaTable[i+512] = (UWORD)(fB*65280);
}
// done
return TRUE;
}
#if 0
DeclareSymbol( "[persistent] [hidden] [const] [type] name [minval] [maxval] [func()]", &shd_iStaticQuality, func()=NULL);
_pShell->DeclareSymbol( "INDEX GfxVarPreFunc(INDEX);", &GfxVarPreFunc);
_pShell->DeclareSymbol( "void GfxVarPostFunc(INDEX);", &GfxVarPostFunc);
static BOOL GfxVarPreFunc(void *pvVar)
{
if (pvVar==&gfx_fSaturation) {
CPrintF("cannot change saturation: just for test\n");
return FALSE;
} else {
CPrintF("gfx var about to be changed\n");
return TRUE;
}
}
static void GfxVarPostFunc(void *pvVar)
{
if (pvVar==&shd_bFineQuality) {
CPrintF("This requires RefreshTextures() to take effect!\n");
}
}
#endif