/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "Engine/StdH.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // !!! 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. // control for partial usage of compiled vertex arrays BOOL CVA_b2D = FALSE; BOOL CVA_bWorld = FALSE; BOOL CVA_bModels = FALSE; // common element arrays CStaticStackArray _avtxCommon; CStaticStackArray _atexCommon; CStaticStackArray _acolCommon; CStaticStackArray _aiCommonElements; CStaticStackArray _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; #ifdef PLATFORM_WIN32 // DG: not used on other platforms static UWORD _auwGammaTable[256*3]; #endif // 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; INDEX sys_bUsingDirect3D = 0; /* * Low level hook flags */ #define WH_KEYBOARD_LL 13 #ifdef PLATFORM_WIN32 void EnableWindowsKeys(void); #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 /* * 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<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) ); // 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; } // 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) STUBBED("Swap interval shouldn't just be for fullscreen"); // !!! FIXME --ryan. if( _pGfx->gl_ulFlags&GLF_FULLSCREEN) { // report current swap interval STUBBED("I don't think the non-D3D path sets GLF_VSYNC anywhere. Mismerge?"); // !!! FIXME --ryan. CPrintF( "- Swap interval: "); if( _pGfx->gl_ulFlags&GLF_VSYNC) { #if PLATFORM_WIN32 const int gliWaits = (int) pwglGetSwapIntervalEXT(); if( gliWaits>=0) { ASSERT( gliWaits==_pGfx->gl_iSwapInterval); CPrintF( "%d frame(s)\n", gliWaits); } else CPrintF( "not readable\n"); #else const int gliWaits = SDL_GL_GetSwapInterval(); if( gliWaits>=0) { ASSERT( gliWaits==_pGfx->gl_iSwapInterval); CPrintF( "%d frame(s)\n", gliWaits); } else CPrintF( "adaptive vsync\n"); #endif } 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, 0, 2); 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 SE1_D3D // Direct3D only stuff if( eAPI==GAT_D3D) { // HW T&L CPrintF( "- Hardware T&L: "); if( _pGfx->gl_ulFlags&GLF_D3D_HASHWTNL) { if( _pGfx->gl_ctMaxStreamsgl_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->GetLowPrecisionTimer(); 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 if(_pSound != NULL) _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, 0, 359); shd_iHueShift = Clamp( shd_iHueShift, 0, 359); _slShdSaturation = (SLONG)( gfx_fSaturation*shd_fSaturation*256.0f); _slShdHueShift = Clamp( (gfx_iHueShift+shd_iHueShift)*255/359, 0, 255); 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, 0, 359); tex_iHueShift = Clamp( tex_iHueShift, 0, 359); _slTexSaturation = (SLONG)( gfx_fSaturation*tex_fSaturation*256.0f); _slTexHueShift = Clamp( (gfx_iHueShift+tex_iHueShift)*255/359, 0, 255); // 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, 0, 1); 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, 0, 255); // prepare fast sqrt tables for( i=0; itd_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() { 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); #ifdef PLATFORM_WIN32 // we will never allow glide splash screen putenv( "FX_GLIDE_NO_SPLASH=1"); // report desktop settings CPrintF(TRANSV("Desktop settings...\n")); HDC hdc = GetDC(NULL); SLONG slBPP = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL); ReleaseDC(NULL, hdc); gfx_ctMonitors = GetSystemMetrics(SM_CMONITORS); CPrintF(TRANSV(" Color Depth: %dbit\n"), slBPP); CPrintF(TRANSV(" Screen: %dx%d\n"), GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); CPrintF(TRANSV(" Virtual screen: %dx%d\n"), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)); CPrintF(TRANSV(" Monitors directly reported: %d\n"), gfx_ctMonitors); #else // we will never allow glide splash screen setenv("FX_GLIDE_NO_SPLASH", "1", 1); 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. // FXME: DG: so why are they commented out? // _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 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 SE1_D3D 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) { // get the dimensions from the window // !!! FIXME : rcg11052001 Abstract this. #ifdef PLATFORM_WIN32 RECT rectWindow; // rectangle for the client area of the window GetClientRect( (HWND)hWnd, &rectWindow); const PIX pixWidth = rectWindow.right - rectWindow.left; const PIX pixHeight = rectWindow.bottom - rectWindow.top; #else int w, h; SDL_GL_GetDrawableSize((SDL_Window *) hWnd, &w, &h); const PIX pixWidth = (PIX) w; const PIX pixHeight = (PIX) 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->GetLowPrecisionTimer(); // 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=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; #ifdef PLATFORM_WIN32 // only used there static BOOL GenerateGammaTable(void); #endif /* * 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, 0, 2); gap_iSwapInterval = Clamp( gap_iSwapInterval, 0, 4); gap_iOptimizeClipping = Clamp( gap_iOptimizeClipping, 0, 2); gap_iTruformLevel = Clamp( gap_iTruformLevel, 0, _pGfx->gl_iMaxTessellationLevel); ogl_iFinish = Clamp( ogl_iFinish, 0, 3); d3d_iFinish = Clamp( d3d_iFinish, 0, 3); // 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; #ifdef PLATFORM_WIN32 pwglSwapIntervalEXT( gl_iSwapInterval); #else SDL_GL_SetSwapInterval( gl_iSwapInterval); #endif } } // swap buffers // !!! FIXME: Move this to platform-specific directories. #ifdef PLATFORM_WIN32 CTempDC tdc(pvp->vp_hWnd); pwglSwapBuffers(tdc.hdc); #else SDL_GL_SwapWindow((SDL_Window *) pvp->vp_hWnd); #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, 1, 16384); 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, 1, _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 #elif defined(PLATFORM_PANDORA) if( gl_ulFlags & GLF_ADJUSTABLEGAMMA) { //hacky Gamma only (no Contrast/Brightness) support. static float old_pandora_gamma = 0.0f; if (old_pandora_gamma!=gfx_fGamma) { char buf[50]; sprintf(buf,"sudo /usr/pandora/scripts/op_gamma.sh %.2f", gfx_fGamma); system(buf); old_pandora_gamma = gfx_fGamma; } } 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); } #ifdef PLATFORM_WIN32 // DG: only used on windows // 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, 2, 256); 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, 0, 65280); } // 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, 0xFF00); } } // 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; } #endif // PLATFORM_WIN32 #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