Serious-Engine/Sources/Engine/Graphics/Gfx_wrapper.cpp
2016-03-30 11:00:01 -04:00

838 lines
29 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#include "Engine/StdH.h"
#include <Engine/Graphics/GfxLibrary.h>
#include <Engine/Graphics/ViewPort.h>
#include <Engine/Graphics/GfxProfile.h>
#include <Engine/Base/Statistics_internal.h>
//#include <d3dx8math.h>
//#pragma comment(lib, "d3dx8.lib")
//#include <d3dx8tex.h>
//#pragma comment(lib, "d3dx8.lib")
//extern "C" HRESULT WINAPI D3DXGetErrorStringA( HRESULT hr, LPSTR pBuffer, UINT BufferLen);
//char acErrorString[256];
//D3DXGetErrorString( hr, acErrorString, 255);
//ASSERTALWAYS( acErrorString);
extern INDEX gap_bOptimizeStateChanges;
extern INDEX gap_iOptimizeClipping;
extern INDEX gap_iDithering;
// cached states
BOOL GFX_bDepthTest = FALSE;
BOOL GFX_bDepthWrite = FALSE;
BOOL GFX_bAlphaTest = FALSE;
BOOL GFX_bDithering = TRUE;
BOOL GFX_bBlending = TRUE;
BOOL GFX_bClipping = TRUE;
BOOL GFX_bClipPlane = FALSE;
BOOL GFX_bColorArray = FALSE;
BOOL GFX_bTruform = FALSE;
BOOL GFX_bFrontFace = TRUE;
BOOL GFX_bViewMatrix = TRUE;
INDEX GFX_iActiveTexUnit = 0;
FLOAT GFX_fMinDepthRange = 0.0f;
FLOAT GFX_fMaxDepthRange = 0.0f;
GfxBlend GFX_eBlendSrc = GFX_ONE;
GfxBlend GFX_eBlendDst = GFX_ZERO;
GfxComp GFX_eDepthFunc = GFX_LESS_EQUAL;
GfxFace GFX_eCullFace = GFX_NONE;
BOOL GFX_abTexture[GFX_MAXTEXUNITS] = { FALSE, FALSE, FALSE, FALSE };
INDEX GFX_iTexModulation[GFX_MAXTEXUNITS] = { 0, 0, 0, 0 };
// last ortho/frustum values (frustum has negative sign, because of orgho-frustum switching!)
FLOAT GFX_fLastL = 0;
FLOAT GFX_fLastR = 0;
FLOAT GFX_fLastT = 0;
FLOAT GFX_fLastB = 0;
FLOAT GFX_fLastN = 0;
FLOAT GFX_fLastF = 0;
// number of vertices currently in buffer
INDEX GFX_ctVertices = 0;
// for D3D: mark need for clipping (when wants to be disable but cannot be because of user clip plane)
static BOOL _bWantsClipping = TRUE;
// current color mask (for Get... function)
static ULONG _ulCurrentColorMask = (CT_RMASK|CT_GMASK|CT_BMASK|CT_AMASK);
// locking state for OGL
static BOOL _bCVAReallyLocked = FALSE;
// clip plane and last view matrix for D3D
FLOAT D3D_afClipPlane[4] = {0,0,0,0};
FLOAT D3D_afViewMatrix[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
static FLOAT _afActiveClipPlane[4] = {0,0,0,0};
// Truform/N-Patches
INDEX truform_iLevel = -1;
BOOL truform_bLinear = FALSE;
// functions' pointers
void (*gfxEnableDepthWrite)(void) = NULL;
void (*gfxEnableDepthBias)(void) = NULL;
void (*gfxEnableDepthTest)(void) = NULL;
void (*gfxEnableAlphaTest)(void) = NULL;
void (*gfxEnableBlend)(void) = NULL;
void (*gfxEnableDither)(void) = NULL;
void (*gfxEnableTexture)(void) = NULL;
void (*gfxEnableClipping)(void) = NULL;
void (*gfxEnableClipPlane)(void) = NULL;
void (*gfxDisableDepthWrite)(void) = NULL;
void (*gfxDisableDepthBias)(void) = NULL;
void (*gfxDisableDepthTest)(void) = NULL;
void (*gfxDisableAlphaTest)(void) = NULL;
void (*gfxDisableBlend)(void) = NULL;
void (*gfxDisableDither)(void) = NULL;
void (*gfxDisableTexture)(void) = NULL;
void (*gfxDisableClipping)(void) = NULL;
void (*gfxDisableClipPlane)(void) = NULL;
void (*gfxBlendFunc)( GfxBlend eSrc, GfxBlend eDst) = NULL;
void (*gfxDepthFunc)( GfxComp eFunc) = NULL;
void (*gfxDepthRange)( FLOAT fMin, FLOAT fMax) = NULL;
void (*gfxCullFace)( GfxFace eFace) = NULL;
void (*gfxFrontFace)( GfxFace eFace) = NULL;
void (*gfxClipPlane)( const DOUBLE *pdPlane) = NULL;
void (*gfxSetOrtho)( const FLOAT fLeft, const FLOAT fRight, const FLOAT fTop, const FLOAT fBottom, const FLOAT fNear, const FLOAT fFar, const BOOL bSubPixelAdjust) = NULL;
void (*gfxSetFrustum)( const FLOAT fLeft, const FLOAT fRight, const FLOAT fTop, const FLOAT fBottom, const FLOAT fNear, const FLOAT fFar) = NULL;
void (*gfxSetTextureMatrix)( const FLOAT *pfMatrix) = NULL;
void (*gfxSetViewMatrix)( const FLOAT *pfMatrix) = NULL;
void (*gfxPolygonMode)( GfxPolyMode ePolyMode) = NULL;
void (*gfxSetTextureWrapping)( enum GfxWrap eWrapU, enum GfxWrap eWrapV) = NULL;
void (*gfxSetTextureModulation)( INDEX iScale) = NULL;
void (*gfxGenerateTexture)( ULONG &ulTexObject) = NULL;
void (*gfxDeleteTexture)( ULONG &ulTexObject) = NULL;
void (*gfxSetVertexArray)( GFXVertex4 *pvtx, INDEX ctVtx) = NULL;
void (*gfxSetNormalArray)( GFXNormal *pnor) = NULL;
void (*gfxSetTexCoordArray)( GFXTexCoord *ptex, BOOL b4) = NULL;
void (*gfxSetColorArray)( GFXColor *pcol) = NULL;
void (*gfxDrawElements)( INDEX ctElem, INDEX *pidx) = NULL;
void (*gfxSetConstantColor)(COLOR col) = NULL;
void (*gfxEnableColorArray)(void) = NULL;
void (*gfxDisableColorArray)(void) = NULL;
void (*gfxFinish)(void) = NULL;
void (*gfxLockArrays)(void) = NULL;
void (*gfxEnableTruform)( void) = NULL;
void (*gfxDisableTruform)(void) = NULL;
void (*gfxSetColorMask)( ULONG ulColorMask) = NULL;
// dummy function (one size fits all:)
static void none_void(void)
{
ASSERT( _pGfx->gl_eCurrentAPI==GAT_NONE);
}
// error checkers (this is for debug version only)
void OGL_CheckError(void)
{
#ifndef NDEBUG
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
if( eAPI==GAT_OGL) ASSERT( pglGetError()==GL_NO_ERROR);
else ASSERT( eAPI==GAT_NONE);
#endif
}
#ifdef SE1_D3D
void D3D_CheckError(HRESULT hr)
{
#ifndef NDEBUG
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
if( eAPI==GAT_D3D) ASSERT( hr==D3D_OK);
else ASSERT( eAPI==GAT_NONE);
#endif
}
#endif // SE1_D3D
// TEXTURE MANAGEMENT
#ifdef SE1_D3D
static LPDIRECT3DTEXTURE8 *_ppd3dCurrentTexture;
#endif // SE1_D3D
INDEX GetTexturePixRatio_OGL( GLuint uiBindNo);
INDEX GetFormatPixRatio_OGL( GLenum eFormat);
void MimicTexParams_OGL( CTexParams &tpLocal);
void UploadTexture_OGL( ULONG *pulTexture, PIX pixSizeU, PIX pixSizeV,
GLenum eInternalFormat, BOOL bUseSubImage);
#ifdef SE1_D3D
extern INDEX GetTexturePixRatio_D3D( LPDIRECT3DTEXTURE8 pd3dTexture);
extern INDEX GetFormatPixRatio_D3D( D3DFORMAT d3dFormat);
extern void MimicTexParams_D3D( CTexParams &tpLocal);
extern void UploadTexture_D3D( LPDIRECT3DTEXTURE8 *ppd3dTexture, ULONG *pulTexture,
PIX pixSizeU, PIX pixSizeV, D3DFORMAT eInternalFormat, BOOL bDiscard);
#endif // SE1_D3D
// update texture LOD bias
FLOAT _fCurrentLODBias = 0; // LOD bias adjuster
void UpdateLODBias( const FLOAT fLODBias)
{
// check API
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
ASSERT( GfxValidApi(eAPI) );
// only if supported and needed
if( _fCurrentLODBias==fLODBias && _pGfx->gl_fMaxTextureLODBias==0) return;
_fCurrentLODBias = fLODBias;
_sfStats.StartTimer(CStatForm::STI_GFXAPI);
// OpenGL
if( eAPI==GAT_OGL)
{ // if no multitexturing
if( _pGfx->gl_ctTextureUnits<2) {
pglTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, fLODBias);
OGL_CHECKERROR;
}
// if multitexturing is active
else {
for( INDEX iUnit=0; iUnit<_pGfx->gl_ctTextureUnits; iUnit++) { // loop thru units
pglActiveTexture(iUnit); // select the unit
pglTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, fLODBias);
OGL_CHECKERROR;
} // reselect the original unit
pglActiveTexture(GFX_iActiveTexUnit);
OGL_CHECKERROR;
}
}
// Direct3D
#ifdef SE1_D3D
else if( eAPI==GAT_D3D)
{ // just set it
HRESULT hr;
for( INDEX iUnit=0; iUnit<_pGfx->gl_ctTextureUnits; iUnit++) { // loop thru tex units
hr = _pGfx->gl_pd3dDevice->SetTextureStageState( iUnit, D3DTSS_MIPMAPLODBIAS, *((DWORD*)&fLODBias));
D3D_CHECKERROR(hr);
}
}
#endif
_sfStats.StopTimer(CStatForm::STI_GFXAPI);
}
// get current texture filtering mode
void gfxGetTextureFiltering( INDEX &iFilterType, INDEX &iAnisotropyDegree)
{
iFilterType = _tpGlobal[0].tp_iFilter;
iAnisotropyDegree = _tpGlobal[0].tp_iAnisotropy;
}
// set texture filtering mode
void gfxSetTextureFiltering( INDEX &iFilterType, INDEX &iAnisotropyDegree)
{
// clamp vars
INDEX iMagTex = iFilterType /100; iMagTex = Clamp( iMagTex, 0L, 2L); // 0=same as iMinTex, 1=nearest, 2=linear
INDEX iMinTex = iFilterType /10 %10; iMinTex = Clamp( iMinTex, 1L, 2L); // 1=nearest, 2=linear
INDEX iMinMip = iFilterType %10; iMinMip = Clamp( iMinMip, 0L, 2L); // 0=no mipmapping, 1=nearest, 2=linear
iFilterType = iMagTex*100 + iMinTex*10 + iMinMip;
iAnisotropyDegree = Clamp( iAnisotropyDegree, 1L, _pGfx->gl_iMaxTextureAnisotropy);
// skip if not changed
if( _tpGlobal[0].tp_iFilter==iFilterType && _tpGlobal[0].tp_iAnisotropy==iAnisotropyDegree) return;
_tpGlobal[0].tp_iFilter = iFilterType;
_tpGlobal[0].tp_iAnisotropy = iAnisotropyDegree;
// for OpenGL, that's about it
#ifdef SE1_D3D
if( _pGfx->gl_eCurrentAPI!=GAT_D3D) return;
_sfStats.StartTimer(CStatForm::STI_GFXAPI);
// for D3D, it's a stage state (not texture state), so change it!
HRESULT hr;
_D3DTEXTUREFILTERTYPE eMagFilter, eMinFilter, eMipFilter;
const LPDIRECT3DDEVICE8 pd3dDev = _pGfx->gl_pd3dDevice;
extern void UnpackFilter_D3D( INDEX iFilter, _D3DTEXTUREFILTERTYPE &eMagFilter,
_D3DTEXTUREFILTERTYPE &eMinFilter, _D3DTEXTUREFILTERTYPE &eMipFilter);
UnpackFilter_D3D( iFilterType, eMagFilter, eMinFilter, eMipFilter);
if( iAnisotropyDegree>1) { // adjust filter for anisotropy
eMagFilter = D3DTEXF_ANISOTROPIC;
eMinFilter = D3DTEXF_ANISOTROPIC;
}
// set filtering and anisotropy degree
for( INDEX iUnit=0; iUnit<_pGfx->gl_ctTextureUnits; iUnit++) { // must loop thru all usable texture units
hr = pd3dDev->SetTextureStageState( iUnit, D3DTSS_MAXANISOTROPY, iAnisotropyDegree); D3D_CHECKERROR(hr);
hr = pd3dDev->SetTextureStageState( iUnit, D3DTSS_MAGFILTER, eMagFilter); D3D_CHECKERROR(hr);
hr = pd3dDev->SetTextureStageState( iUnit, D3DTSS_MINFILTER, eMinFilter); D3D_CHECKERROR(hr);
hr = pd3dDev->SetTextureStageState( iUnit, D3DTSS_MIPFILTER, eMipFilter); D3D_CHECKERROR(hr);
}
// done
_sfStats.StopTimer(CStatForm::STI_GFXAPI);
#endif
}
// set new texture LOD biasing
void gfxSetTextureBiasing( FLOAT &fLODBias)
{
// adjust LOD biasing if needed
fLODBias = Clamp( fLODBias, -_pGfx->gl_fMaxTextureLODBias, +_pGfx->gl_fMaxTextureLODBias);
if( _pGfx->gl_fTextureLODBias != fLODBias) {
_pGfx->gl_fTextureLODBias = fLODBias;
UpdateLODBias( fLODBias);
}
}
// set texture unit as active
void gfxSetTextureUnit( INDEX iUnit)
{
// check API
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
ASSERT( GfxValidApi(eAPI) );
ASSERT( iUnit>=0 && iUnit<4); // supports 4 layers (for now)
// check consistency
#ifndef NDEBUG
if( eAPI==GAT_OGL) {
GLint gliRet;
pglGetIntegerv( GL_ACTIVE_TEXTURE_ARB, &gliRet);
ASSERT( GFX_iActiveTexUnit==(gliRet-GL_TEXTURE0_ARB));
pglGetIntegerv( GL_CLIENT_ACTIVE_TEXTURE_ARB, &gliRet);
ASSERT( GFX_iActiveTexUnit==(gliRet-GL_TEXTURE0_ARB));
}
#endif
// cached?
if( GFX_iActiveTexUnit==iUnit) return;
GFX_iActiveTexUnit = iUnit;
// really set only for OpenGL
if( eAPI!=GAT_OGL) return;
_sfStats.StartTimer(CStatForm::STI_GFXAPI);
pglActiveTexture(iUnit);
_sfStats.StopTimer(CStatForm::STI_GFXAPI);
}
// set texture as current
void gfxSetTexture( ULONG &ulTexObject, CTexParams &tpLocal)
{
// clamp texture filtering if needed
static INDEX _iLastTextureFiltering = 0;
if( _iLastTextureFiltering != _tpGlobal[0].tp_iFilter) {
INDEX iMagTex = _tpGlobal[0].tp_iFilter /100; iMagTex = Clamp( iMagTex, 0L, 2L); // 0=same as iMinTex, 1=nearest, 2=linear
INDEX iMinTex = _tpGlobal[0].tp_iFilter /10 %10; iMinTex = Clamp( iMinTex, 1L, 2L); // 1=nearest, 2=linear
INDEX iMinMip = _tpGlobal[0].tp_iFilter %10; iMinMip = Clamp( iMinMip, 0L, 2L); // 0=no mipmapping, 1=nearest, 2=linear
_tpGlobal[0].tp_iFilter = iMagTex*100 + iMinTex*10 + iMinMip;
_iLastTextureFiltering = _tpGlobal[0].tp_iFilter;
}
// determine API and enable texturing
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
ASSERT(GfxValidApi(eAPI));
gfxEnableTexture();
_sfStats.StartTimer(CStatForm::STI_BINDTEXTURE);
_sfStats.StartTimer(CStatForm::STI_GFXAPI);
_pfGfxProfile.StartTimer(CGfxProfile::PTI_SETCURRENTTEXTURE);
_pfGfxProfile.IncrementTimerAveragingCounter(CGfxProfile::PTI_SETCURRENTTEXTURE);
if( eAPI==GAT_OGL) { // OpenGL
pglBindTexture( GL_TEXTURE_2D, ulTexObject);
MimicTexParams_OGL(tpLocal);
}
#ifdef SE1_D3D
else if( eAPI==GAT_D3D) { // Direct3D
_ppd3dCurrentTexture = (LPDIRECT3DTEXTURE8*)&ulTexObject;
HRESULT hr = _pGfx->gl_pd3dDevice->SetTexture( GFX_iActiveTexUnit, *_ppd3dCurrentTexture);
D3D_CHECKERROR(hr);
MimicTexParams_D3D(tpLocal);
}
#endif // SE1_D3D
// done
_pfGfxProfile.StopTimer(CGfxProfile::PTI_SETCURRENTTEXTURE);
_sfStats.StopTimer(CStatForm::STI_BINDTEXTURE);
_sfStats.StopTimer(CStatForm::STI_GFXAPI);
}
// upload texture
void gfxUploadTexture( ULONG *pulTexture, PIX pixWidth, PIX pixHeight, ULONG ulFormat, BOOL bNoDiscard)
{
// determine API
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
ASSERT( GfxValidApi(eAPI) );
_sfStats.StartTimer(CStatForm::STI_GFXAPI);
if( eAPI==GAT_OGL) { // OpenGL
UploadTexture_OGL( pulTexture, pixWidth, pixHeight, (GLenum)ulFormat, bNoDiscard);
}
#ifdef SE1_D3D
else if( eAPI==GAT_D3D) { // Direct3D
const LPDIRECT3DTEXTURE8 _pd3dLastTexture = *_ppd3dCurrentTexture;
UploadTexture_D3D( _ppd3dCurrentTexture, pulTexture, pixWidth, pixHeight, (D3DFORMAT)ulFormat, !bNoDiscard);
// in case that texture has been changed, must re-set it as current
if( _pd3dLastTexture != *_ppd3dCurrentTexture) {
HRESULT hr = _pGfx->gl_pd3dDevice->SetTexture( GFX_iActiveTexUnit, *_ppd3dCurrentTexture);
D3D_CHECKERROR(hr);
}
}
#endif // SE1_D3D
_sfStats.StopTimer(CStatForm::STI_GFXAPI);
}
// returns size of uploaded texture
SLONG gfxGetTextureSize( ULONG ulTexObject, BOOL bHasMipmaps/*=TRUE*/)
{
// nothing used if nothing uploaded
if( ulTexObject==0) return 0;
// determine API
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
ASSERT( GfxValidApi(eAPI) );
SLONG slMipSize;
_sfStats.StartTimer(CStatForm::STI_GFXAPI);
// OpenGL
if( eAPI==GAT_OGL)
{
// was texture compressed?
pglBindTexture( GL_TEXTURE_2D, ulTexObject);
BOOL bCompressed = FALSE;
if( _pGfx->gl_ulFlags & GLF_EXTC_ARB) {
pglGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, (BOOL*)&bCompressed);
OGL_CHECKERROR;
}
// for compressed textures, determine size directly
if( bCompressed) {
pglGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, (GLint*)&slMipSize);
OGL_CHECKERROR;
}
// non-compressed textures goes thru determination of internal format
else {
PIX pixWidth, pixHeight;
pglGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, (GLint*)&pixWidth);
pglGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, (GLint*)&pixHeight);
OGL_CHECKERROR;
slMipSize = pixWidth*pixHeight * gfxGetTexturePixRatio(ulTexObject);
}
}
// Direct3D
#ifdef SE1_D3D
else if( eAPI==GAT_D3D)
{
// we can determine exact size from texture surface (i.e. mipmap)
D3DSURFACE_DESC d3dSurfDesc;
HRESULT hr = ((LPDIRECT3DTEXTURE8)ulTexObject)->GetLevelDesc( 0, &d3dSurfDesc);
D3D_CHECKERROR(hr);
slMipSize = d3dSurfDesc.Size;
}
#endif // SE1_D3D
// eventually count in all the mipmaps (takes extra 33% of texture size)
extern INDEX gap_bAllowSingleMipmap;
const SLONG slUploadSize = (bHasMipmaps || !gap_bAllowSingleMipmap) ? slMipSize*4/3 : slMipSize;
_sfStats.StopTimer(CStatForm::STI_GFXAPI);
return slUploadSize;
}
// returns bytes/pixels ratio for uploaded texture
INDEX gfxGetTexturePixRatio( ULONG ulTextureObject)
{
// determine API
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
ASSERT( GfxValidApi(eAPI) );
if( eAPI==GAT_OGL) return GetTexturePixRatio_OGL( (GLuint)ulTextureObject);
#ifdef SE1_D3D
else if( eAPI==GAT_D3D) return GetTexturePixRatio_D3D( (LPDIRECT3DTEXTURE8)ulTextureObject);
#endif // SE1_D3D
else return 0;
}
// returns bytes/pixels ratio for uploaded texture
INDEX gfxGetFormatPixRatio( ULONG ulTextureFormat)
{
// determine API
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
ASSERT( GfxValidApi(eAPI) );
if( eAPI==GAT_OGL) return GetFormatPixRatio_OGL( (GLenum)ulTextureFormat);
#ifdef SE1_D3D
else if( eAPI==GAT_D3D) return GetFormatPixRatio_D3D( (D3DFORMAT)ulTextureFormat);
#endif // SE1_D3D
else return 0;
}
// PATTERN TEXTURE FOR LINES
CTexParams _tpPattern;
ULONG _ulPatternTexture = NONE;
ULONG _ulLastUploadedPattern = 0;
// upload pattern to accelerator memory
void gfxSetPattern( ULONG ulPattern)
{
// set pattern to be current texture
_tpPattern.tp_bSingleMipmap = TRUE;
gfxSetTextureWrapping( GFX_REPEAT, GFX_REPEAT);
gfxSetTexture( _ulPatternTexture, _tpPattern);
// if this pattern is currently uploaded, do nothing
if( _ulLastUploadedPattern==ulPattern) return;
// convert bits to ULONGs
ULONG aulPattern[32];
for( INDEX iBit=0; iBit<32; iBit++) {
if( (0x80000000>>iBit) & ulPattern) aulPattern[iBit] = 0xFFFFFFFF;
else aulPattern[iBit] = 0x00000000;
}
// remember new pattern and upload
_ulLastUploadedPattern = ulPattern;
gfxUploadTexture( &aulPattern[0], 32, 1, TS.ts_tfRGBA8, FALSE);
}
// VERTEX ARRAYS
// for D3D - (type 0=vtx, 1=nor, 2=col, 3=tex)
void SetVertexArray_D3D( INDEX iType, ULONG *pulVtx);
extern void gfxUnlockArrays(void)
{
// only if locked (OpenGL can lock 'em)
if( !_bCVAReallyLocked) return;
ASSERT( _pGfx->gl_eCurrentAPI==GAT_OGL);
#ifndef NDEBUG
INDEX glctRet;
pglGetIntegerv( GL_ARRAY_ELEMENT_LOCK_COUNT_EXT, (GLint*)&glctRet);
ASSERT( glctRet==GFX_ctVertices);
#endif
pglUnlockArraysEXT();
OGL_CHECKERROR;
_bCVAReallyLocked = FALSE;
}
// OpenGL workarounds
// initialization of common quad elements array
void AddQuadElements( const INDEX ctQuads)
{
const INDEX iStart = _aiCommonQuads.Count() /6*4;
INDEX *piQuads = _aiCommonQuads.Push(ctQuads*6);
for( INDEX i=0; i<ctQuads; i++) {
piQuads[i*6 +0] = iStart+ i*4 +0;
piQuads[i*6 +1] = iStart+ i*4 +1;
piQuads[i*6 +2] = iStart+ i*4 +2;
piQuads[i*6 +3] = iStart+ i*4 +2;
piQuads[i*6 +4] = iStart+ i*4 +3;
piQuads[i*6 +5] = iStart+ i*4 +0;
}
}
// helper function for flushers
static void FlushArrays( INDEX *piElements, INDEX ctElements)
{
// check
const INDEX ctVertices = _avtxCommon.Count();
ASSERT( _atexCommon.Count()==ctVertices);
ASSERT( _acolCommon.Count()==ctVertices);
extern BOOL CVA_b2D;
gfxSetVertexArray( &_avtxCommon[0], ctVertices);
if(CVA_b2D) gfxLockArrays();
gfxSetTexCoordArray( &_atexCommon[0], FALSE);
gfxSetColorArray( &_acolCommon[0]);
gfxDrawElements( ctElements, piElements);
gfxUnlockArrays();
}
// render quad elements to screen buffer
void gfxFlushQuads(void)
{
// if there is something to draw
const INDEX ctElements = _avtxCommon.Count()*6/4;
if( ctElements<=0) return;
// draw thru arrays (for OGL only) or elements?
extern INDEX ogl_bAllowQuadArrays;
if( _pGfx->gl_eCurrentAPI==GAT_OGL && ogl_bAllowQuadArrays) FlushArrays( NULL, _avtxCommon.Count());
else {
// make sure that enough quad elements has been initialized
const INDEX ctQuads = _aiCommonQuads.Count();
if( ctElements>ctQuads) AddQuadElements( ctElements-ctQuads); // yes, 4 times more!
FlushArrays( &_aiCommonQuads[0], ctElements);
}
}
// render elements to screen buffer
void gfxFlushElements(void)
{
const INDEX ctElements = _aiCommonElements.Count();
if( ctElements>0) FlushArrays( &_aiCommonElements[0], ctElements);
}
// set truform parameters
void gfxSetTruform( INDEX iLevel, BOOL bLinearNormals)
{
// skip if Truform isn't supported
if( _pGfx->gl_iMaxTessellationLevel<1) {
truform_iLevel = 0;
truform_bLinear = FALSE;
return;
}
// skip if same as last time
iLevel = Clamp( iLevel, 0L, _pGfx->gl_iMaxTessellationLevel);
if( truform_iLevel==iLevel && !truform_bLinear==!bLinearNormals) return;
// determine API
const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
ASSERT( GfxValidApi(eAPI) );
_sfStats.StartTimer(CStatForm::STI_GFXAPI);
// OpenGL needs truform set here
if( eAPI==GAT_OGL) {
GLenum eTriMode = bLinearNormals ? GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI : GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI;
pglPNTrianglesiATI( GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, iLevel);
pglPNTrianglesiATI( GL_PN_TRIANGLES_NORMAL_MODE_ATI, eTriMode);
OGL_CHECKERROR;
}
// if disabled, Direct3D will set tessellation level at "enable" call
#ifdef SE1_D3D
else if( eAPI==GAT_D3D && GFX_bTruform) {
FLOAT fSegments = iLevel+1;
HRESULT hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_PATCHSEGMENTS, *((DWORD*)&fSegments));
D3D_CHECKERROR(hr);
}
#endif // SE1_D3D
// keep current truform params
truform_iLevel = iLevel;
truform_bLinear = bLinearNormals;
_sfStats.StopTimer(CStatForm::STI_GFXAPI);
}
// readout current colormask
extern ULONG gfxGetColorMask(void)
{
return _ulCurrentColorMask;
}
#include "GFX_wrapper_OpenGL.cpp"
#include "GFX_wrapper_Direct3D.cpp"
// DUMMY FUNCTIONS FOR NONE API
static void none_BlendFunc( GfxBlend eSrc, GfxBlend eDst) { NOTHING; }
static void none_DepthFunc( GfxComp eFunc) { NOTHING; };
static void none_DepthRange( FLOAT fMin, FLOAT fMax) { NOTHING; };
static void none_CullFace( GfxFace eFace) { NOTHING; };
static void none_ClipPlane( const DOUBLE *pdViewPlane) { NOTHING; };
static void none_SetOrtho( const FLOAT fLeft, const FLOAT fRight, const FLOAT fTop, const FLOAT fBottom, const FLOAT fNear, const FLOAT fFar, const BOOL bSubPixelAdjust) { NOTHING; };
static void none_SetFrustum( const FLOAT fLeft, const FLOAT fRight, const FLOAT fTop, const FLOAT fBottom, const FLOAT fNear, const FLOAT fFar) { NOTHING; };
static void none_SetMatrix( const FLOAT *pfMatrix) { NOTHING; };
static void none_PolygonMode( GfxPolyMode ePolyMode) { NOTHING; };
static void none_SetTextureWrapping( enum GfxWrap eWrapU, enum GfxWrap eWrapV) { NOTHING; };
static void none_SetTextureModulation( INDEX iScale) { NOTHING; };
static void none_GenDelTexture( ULONG &ulTexObject) { NOTHING; };
static void none_SetVertexArray( GFXVertex4 *pvtx, INDEX ctVtx) { NOTHING; };
static void none_SetNormalArray( GFXNormal *pnor) { NOTHING; };
static void none_SetTexCoordArray( GFXTexCoord *ptex, BOOL b4) { NOTHING; };
static void none_SetColorArray( GFXColor *pcol) { NOTHING; };
static void none_DrawElements( INDEX ctElem, INDEX *pidx) { NOTHING; };
static void none_SetConstantColor( COLOR col) { NOTHING; };
static void none_SetColorMask( ULONG ulColorMask) { NOTHING; };
// functions initialization for OGL, D3D or NONE (dummy)
void GFX_SetFunctionPointers( INDEX iAPI)
{
// OpenGL?
if( iAPI==(INDEX)GAT_OGL)
{
gfxEnableDepthWrite = &ogl_EnableDepthWrite;
gfxEnableDepthBias = &ogl_EnableDepthBias;
gfxEnableDepthTest = &ogl_EnableDepthTest;
gfxEnableAlphaTest = &ogl_EnableAlphaTest;
gfxEnableBlend = &ogl_EnableBlend;
gfxEnableDither = &ogl_EnableDither;
gfxEnableTexture = &ogl_EnableTexture;
gfxEnableClipping = &ogl_EnableClipping;
gfxEnableClipPlane = &ogl_EnableClipPlane;
gfxEnableTruform = &ogl_EnableTruform;
gfxDisableDepthWrite = &ogl_DisableDepthWrite;
gfxDisableDepthBias = &ogl_DisableDepthBias;
gfxDisableDepthTest = &ogl_DisableDepthTest;
gfxDisableAlphaTest = &ogl_DisableAlphaTest;
gfxDisableBlend = &ogl_DisableBlend;
gfxDisableDither = &ogl_DisableDither;
gfxDisableTexture = &ogl_DisableTexture;
gfxDisableClipping = &ogl_DisableClipping;
gfxDisableClipPlane = &ogl_DisableClipPlane;
gfxDisableTruform = &ogl_DisableTruform;
gfxBlendFunc = &ogl_BlendFunc;
gfxDepthFunc = &ogl_DepthFunc;
gfxDepthRange = &ogl_DepthRange;
gfxCullFace = &ogl_CullFace;
gfxFrontFace = &ogl_FrontFace;
gfxClipPlane = &ogl_ClipPlane;
gfxSetOrtho = &ogl_SetOrtho;
gfxSetFrustum = &ogl_SetFrustum;
gfxSetTextureMatrix = &ogl_SetTextureMatrix;
gfxSetViewMatrix = &ogl_SetViewMatrix;
gfxPolygonMode = &ogl_PolygonMode;
gfxSetTextureWrapping = &ogl_SetTextureWrapping;
gfxSetTextureModulation = &ogl_SetTextureModulation;
gfxGenerateTexture = &ogl_GenerateTexture;
gfxDeleteTexture = &ogl_DeleteTexture;
gfxSetVertexArray = &ogl_SetVertexArray;
gfxSetNormalArray = &ogl_SetNormalArray;
gfxSetTexCoordArray = &ogl_SetTexCoordArray;
gfxSetColorArray = &ogl_SetColorArray;
gfxDrawElements = &ogl_DrawElements;
gfxSetConstantColor = &ogl_SetConstantColor;
gfxEnableColorArray = &ogl_EnableColorArray;
gfxDisableColorArray = &ogl_DisableColorArray;
gfxFinish = &ogl_Finish;
gfxLockArrays = &ogl_LockArrays;
gfxSetColorMask = &ogl_SetColorMask;
}
// Direct3D?
#ifdef SE1_D3D
else if( iAPI==(INDEX)GAT_D3D)
{
gfxEnableDepthWrite = &d3d_EnableDepthWrite;
gfxEnableDepthBias = &d3d_EnableDepthBias;
gfxEnableDepthTest = &d3d_EnableDepthTest;
gfxEnableAlphaTest = &d3d_EnableAlphaTest;
gfxEnableBlend = &d3d_EnableBlend;
gfxEnableDither = &d3d_EnableDither;
gfxEnableTexture = &d3d_EnableTexture;
gfxEnableClipping = &d3d_EnableClipping;
gfxEnableClipPlane = &d3d_EnableClipPlane;
gfxEnableTruform = &d3d_EnableTruform;
gfxDisableDepthWrite = &d3d_DisableDepthWrite;
gfxDisableDepthBias = &d3d_DisableDepthBias;
gfxDisableDepthTest = &d3d_DisableDepthTest;
gfxDisableAlphaTest = &d3d_DisableAlphaTest;
gfxDisableBlend = &d3d_DisableBlend;
gfxDisableDither = &d3d_DisableDither;
gfxDisableTexture = &d3d_DisableTexture;
gfxDisableClipping = &d3d_DisableClipping;
gfxDisableClipPlane = &d3d_DisableClipPlane;
gfxDisableTruform = &d3d_DisableTruform;
gfxBlendFunc = &d3d_BlendFunc;
gfxDepthFunc = &d3d_DepthFunc;
gfxDepthRange = &d3d_DepthRange;
gfxCullFace = &d3d_CullFace;
gfxFrontFace = &d3d_FrontFace;
gfxClipPlane = &d3d_ClipPlane;
gfxSetOrtho = &d3d_SetOrtho;
gfxSetFrustum = &d3d_SetFrustum;
gfxSetTextureMatrix = &d3d_SetTextureMatrix;
gfxSetViewMatrix = &d3d_SetViewMatrix;
gfxPolygonMode = &d3d_PolygonMode;
gfxSetTextureWrapping = &d3d_SetTextureWrapping;
gfxSetTextureModulation = &d3d_SetTextureModulation;
gfxGenerateTexture = &d3d_GenerateTexture;
gfxDeleteTexture = &d3d_DeleteTexture;
gfxSetVertexArray = &d3d_SetVertexArray;
gfxSetNormalArray = &d3d_SetNormalArray;
gfxSetTexCoordArray = &d3d_SetTexCoordArray;
gfxSetColorArray = &d3d_SetColorArray;
gfxDrawElements = &d3d_DrawElements;
gfxSetConstantColor = &d3d_SetConstantColor;
gfxEnableColorArray = &d3d_EnableColorArray;
gfxDisableColorArray = &d3d_DisableColorArray;
gfxFinish = &d3d_Finish;
gfxLockArrays = &d3d_LockArrays;
gfxSetColorMask = &d3d_SetColorMask;
}
#endif // SE1_D3D
// NONE!
else
{
gfxEnableDepthWrite = &none_void;
gfxEnableDepthBias = &none_void;
gfxEnableDepthTest = &none_void;
gfxEnableAlphaTest = &none_void;
gfxEnableBlend = &none_void;
gfxEnableDither = &none_void;
gfxEnableTexture = &none_void;
gfxEnableClipping = &none_void;
gfxEnableClipPlane = &none_void;
gfxEnableTruform = &none_void;
gfxDisableDepthWrite = &none_void;
gfxDisableDepthBias = &none_void;
gfxDisableDepthTest = &none_void;
gfxDisableAlphaTest = &none_void;
gfxDisableBlend = &none_void;
gfxDisableDither = &none_void;
gfxDisableTexture = &none_void;
gfxDisableClipping = &none_void;
gfxDisableClipPlane = &none_void;
gfxDisableTruform = &none_void;
gfxBlendFunc = &none_BlendFunc;
gfxDepthFunc = &none_DepthFunc;
gfxDepthRange = &none_DepthRange;
gfxCullFace = &none_CullFace;
gfxFrontFace = &none_CullFace;
gfxClipPlane = &none_ClipPlane;
gfxSetOrtho = &none_SetOrtho;
gfxSetFrustum = &none_SetFrustum;
gfxSetTextureMatrix = &none_SetMatrix;
gfxSetViewMatrix = &none_SetMatrix;
gfxPolygonMode = &none_PolygonMode;
gfxSetTextureWrapping = &none_SetTextureWrapping;
gfxSetTextureModulation = &none_SetTextureModulation;
gfxGenerateTexture = &none_GenDelTexture;
gfxDeleteTexture = &none_GenDelTexture;
gfxSetVertexArray = &none_SetVertexArray;
gfxSetNormalArray = &none_SetNormalArray;
gfxSetTexCoordArray = &none_SetTexCoordArray;
gfxSetColorArray = &none_SetColorArray;
gfxDrawElements = &none_DrawElements;
gfxSetConstantColor = &none_SetConstantColor;
gfxEnableColorArray = &none_void;
gfxDisableColorArray = &none_void;
gfxFinish = &none_void;
gfxLockArrays = &none_void;
gfxSetColorMask = &none_SetColorMask;
}
}