/* 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 #ifdef SE1_D3D // asm shortcuts #define O offset #define Q qword ptr #define D dword ptr #define W word ptr #define B byte ptr #define ASMOPT 1 extern INDEX gap_iTruformLevel; extern ULONG _fog_ulTexture; extern ULONG _haze_ulTexture; // state variables extern BOOL GFX_bDepthTest; extern BOOL GFX_bDepthWrite; extern BOOL GFX_bAlphaTest; extern BOOL GFX_bBlending; extern BOOL GFX_bDithering; extern BOOL GFX_bClipping; extern BOOL GFX_bClipPlane; extern BOOL GFX_bColorArray; extern BOOL GFX_bFrontFace; extern BOOL GFX_bTruform; extern INDEX GFX_iActiveTexUnit; extern FLOAT GFX_fMinDepthRange; extern FLOAT GFX_fMaxDepthRange; extern GfxBlend GFX_eBlendSrc; extern GfxBlend GFX_eBlendDst; extern GfxComp GFX_eDepthFunc; extern GfxFace GFX_eCullFace; extern INDEX GFX_iTexModulation[GFX_MAXTEXUNITS]; extern INDEX GFX_ctVertices; extern BOOL D3D_bUseColorArray = FALSE; // internal vars static INDEX _iVtxOffset = 0; static INDEX _iIdxOffset = 0; static INDEX _iVtxPos = 0; static INDEX _iTexPass = 0; static INDEX _iColPass = 0; static DWORD _dwCurrentVS = NONE; static ULONG _ulStreamsMask = NONE; static ULONG _ulLastStreamsMask = NONE; static BOOL _bProjectiveMapping = FALSE; static BOOL _bLastProjectiveMapping = FALSE; static DWORD _dwVtxLockFlags; // for vertex and normal static DWORD _dwColLockFlags[GFX_MAXLAYERS]; // for colors static DWORD _dwTexLockFlags[GFX_MAXLAYERS]; // for texture coords // shaders created so far struct VertexShader { ULONG vs_ulMask; DWORD vs_dwHandle; }; static CStaticStackArray _avsShaders; // device type (HAL is default, REF is only for debuging) extern const D3DDEVTYPE d3dDevType = D3DDEVTYPE_HAL; // identity matrix extern const D3DMATRIX GFX_d3dIdentityMatrix = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; // sizes of vertex components #define POSSIZE (4*sizeof(FLOAT)) #define NORSIZE (4*sizeof(FLOAT)) #define TEXSIZE (2*sizeof(FLOAT)) #define TX4SIZE (4*sizeof(FLOAT)) #define COLSIZE (4*sizeof(UBYTE)) #define IDXSIZE (1*sizeof(UWORD)) #define POSIDX (0) #define COLIDX (1) #define TEXIDX (2) #define NORIDX (6) // SHADER SETUP PARAMS #define DECLTEXOFS (2*TEXIDX) #define MAXSTREAMS (7L) // template shader DWORD _adwDeclTemplate[] = { D3DVSD_STREAM(0), D3DVSD_REG( D3DVSDE_POSITION, D3DVSDT_FLOAT3), D3DVSD_STREAM(1), D3DVSD_REG( D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR), D3DVSD_STREAM(2), D3DVSD_REG( D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2), D3DVSD_STREAM(3), D3DVSD_REG( D3DVSDE_TEXCOORD1, D3DVSDT_FLOAT2), D3DVSD_STREAM(4), D3DVSD_REG( D3DVSDE_TEXCOORD2, D3DVSDT_FLOAT2), D3DVSD_STREAM(5), D3DVSD_REG( D3DVSDE_TEXCOORD3, D3DVSDT_FLOAT2), D3DVSD_STREAM(6), D3DVSD_REG( D3DVSDE_NORMAL, D3DVSDT_FLOAT3), D3DVSD_END() }; // current shader DWORD _adwCurrentDecl[2*MAXSTREAMS+1]; // check whether texture format is supported in D3D static BOOL HasTextureFormat_D3D( D3DFORMAT d3dTextureFormat) { // quickie? const D3DFORMAT d3dScreenFormat = _pGfx->gl_d3dColorFormat; if( d3dTextureFormat==D3DFMT_UNKNOWN || d3dScreenFormat==NONE) return TRUE; // check extern const D3DDEVTYPE d3dDevType; HRESULT hr = _pGfx->gl_pD3D->CheckDeviceFormat( _pGfx->gl_iCurrentAdapter, d3dDevType, d3dScreenFormat, 0, D3DRTYPE_TEXTURE, d3dTextureFormat); return( hr==D3D_OK); } #define VTXSIZE (POSSIZE + (_pGfx->gl_iMaxTessellationLevel>0 ? NORSIZE : 0) + TX4SIZE \ + COLSIZE * _pGfx->gl_ctColBuffers \ + TEXSIZE * (_pGfx->gl_ctTexBuffers-1)) // returns number of vertices based on vertex size and required size in memory (KB) extern INDEX VerticesFromSize_D3D( SLONG &slSize) { slSize = Clamp( slSize, 64L, 4096L); return (slSize*1024 / VTXSIZE); } // returns size in memory based on number of vertices extern SLONG SizeFromVertices_D3D( INDEX ctVertices) { return (ctVertices * VTXSIZE); } // construct vertex shader out of streams' bit-mask extern DWORD SetupShader_D3D( ULONG ulStreamsMask) { HRESULT hr; const LPDIRECT3DDEVICE8 pd3dDev = _pGfx->gl_pd3dDevice; const INDEX ctShaders = _avsShaders.Count(); INDEX iVS; // delete all shaders? if( ulStreamsMask==NONE) { for( iVS=0; iVSDeleteVertexShader(_avsShaders[iVS].vs_dwHandle); D3D_CHECKERROR(hr); } // free array _avsShaders.PopAll(); _dwCurrentVS = NONE; return NONE; } // see if required shader has already been created for( iVS=0; iVS>= 1; } // mark end _adwCurrentDecl[iDstDecl*2] = D3DVSD_END(); ASSERT( iDstDecl < MAXSTREAMS); ASSERT( _iTexPass>=0 && _iColPass>=0); ASSERT( _iVtxPos >=0 && _iVtxPos<65536); // create new vertex shader const DWORD dwFlags = (_pGfx->gl_ulFlags&GLF_D3D_USINGHWTNL) ? NONE : D3DUSAGE_SOFTWAREPROCESSING; hr = pd3dDev->CreateVertexShader( &_adwCurrentDecl[0], NULL, &vs.vs_dwHandle, dwFlags); D3D_CHECKERROR(hr); // store and reset shader _pGfx->gl_dwVertexShader = 0; return vs.vs_dwHandle; } // prepare vertex arrays for drawing extern void SetupVertexArrays_D3D( INDEX ctVertices) { INDEX i; HRESULT hr; ASSERT( ctVertices>=0); // do nothing if buffer is sufficient ctVertices = ClampUp( ctVertices, 65535L); // need to clamp max vertices first if( ctVertices!=0 && ctVertices<=_pGfx->gl_ctVertices) return; // determine SW or HW VP and NPatches usage (Truform) DWORD dwFlags = D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY; const BOOL bNPatches = (_pGfx->gl_iMaxTessellationLevel>0 && gap_iTruformLevel>0); if( !(_pGfx->gl_ulFlags&GLF_D3D_USINGHWTNL)) dwFlags |= D3DUSAGE_SOFTWAREPROCESSING; if( bNPatches) dwFlags |= D3DUSAGE_NPATCHES; const LPDIRECT3DDEVICE8 pd3dDev = _pGfx->gl_pd3dDevice; // deallocate if needed if( _pGfx->gl_pd3dVtx!=NULL) { // vertex and eventual normal array D3DRELEASE( _pGfx->gl_pd3dVtx, TRUE); if( _pGfx->gl_pd3dNor!=NULL) D3DRELEASE( _pGfx->gl_pd3dNor, TRUE); // color arrays for( i=0; i<_pGfx->gl_ctColBuffers; i++) { ASSERT( _pGfx->gl_pd3dCol[i]!=NULL); D3DRELEASE( _pGfx->gl_pd3dCol[i], TRUE); } // texcoord arrays for( i=0; i<_pGfx->gl_ctTexBuffers; i++) { ASSERT( _pGfx->gl_pd3dTex[i]!=NULL); D3DRELEASE( _pGfx->gl_pd3dTex[i], TRUE); } // reset all streams, too for( i=0; i<_pGfx->gl_ctMaxStreams; i++) { hr = pd3dDev->SetStreamSource( i, NULL,0); D3D_CHECKERROR(hr); } } // allocate if needed if( ctVertices>0) { // update max vertex count if( _pGfx->gl_ctVertices < ctVertices) _pGfx->gl_ctVertices = ctVertices; else ctVertices = _pGfx->gl_ctVertices; // create buffers hr = pd3dDev->CreateVertexBuffer( ctVertices*POSSIZE, dwFlags, 0, D3DPOOL_DEFAULT, &_pGfx->gl_pd3dVtx); D3D_CHECKERROR(hr); // normals buffer only if required if( bNPatches) { hr = pd3dDev->CreateVertexBuffer( ctVertices*NORSIZE, dwFlags, 0, D3DPOOL_DEFAULT, &_pGfx->gl_pd3dNor); D3D_CHECKERROR(hr); } // all color buffers for( i=0; i<_pGfx->gl_ctColBuffers; i++) { hr = pd3dDev->CreateVertexBuffer( ctVertices*COLSIZE, dwFlags, 0, D3DPOOL_DEFAULT, &_pGfx->gl_pd3dCol[i]); D3D_CHECKERROR(hr); } // 1st texture buffer might have projective mapping hr = pd3dDev->CreateVertexBuffer( ctVertices*TX4SIZE, dwFlags, 0, D3DPOOL_DEFAULT, &_pGfx->gl_pd3dTex[0]); D3D_CHECKERROR(hr); for( i=1; i<_pGfx->gl_ctTexBuffers; i++) { hr = pd3dDev->CreateVertexBuffer( ctVertices*TEXSIZE, dwFlags, 0, D3DPOOL_DEFAULT, &_pGfx->gl_pd3dTex[i]); D3D_CHECKERROR(hr); } } // just switch it off if not needed any more (i.e. D3D is shutting down) else _pGfx->gl_ctVertices = 0; // reset and check _iVtxOffset = 0; _pGfx->gl_dwVertexShader = NONE; _ulStreamsMask = NONE; _ulLastStreamsMask = NONE; _bProjectiveMapping = FALSE; _bLastProjectiveMapping = FALSE; // reset locking flags _dwVtxLockFlags = D3DLOCK_DISCARD; for( i=0; igl_ctVertices<65536); } // prepare index arrays for drawing extern void SetupIndexArray_D3D( INDEX ctIndices) { HRESULT hr; ASSERT( ctIndices>=0); // clamp max indices ctIndices = ClampUp( ctIndices, 65535L); // do nothing if buffer is sufficient if( ctIndices!=0 && ctIndices<=_pGfx->gl_ctIndices) return; // determine SW or HW VP DWORD dwFlags = D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY; if( !(_pGfx->gl_ulFlags&GLF_D3D_USINGHWTNL)) dwFlags |= D3DUSAGE_SOFTWAREPROCESSING; if( _pGfx->gl_iMaxTessellationLevel>0 && gap_iTruformLevel>0) dwFlags |= D3DUSAGE_NPATCHES; const LPDIRECT3DDEVICE8 pd3dDev = _pGfx->gl_pd3dDevice; // dealocate if needed if( _pGfx->gl_ctIndices>0) D3DRELEASE( _pGfx->gl_pd3dIdx, TRUE); // allocate if needed if( ctIndices>0) { // eventually update max index count if( _pGfx->gl_ctIndices < ctIndices) _pGfx->gl_ctIndices = ctIndices; else ctIndices = _pGfx->gl_ctIndices; // create buffer hr = pd3dDev->CreateIndexBuffer( ctIndices*IDXSIZE, dwFlags, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &_pGfx->gl_pd3dIdx); D3D_CHECKERROR(hr); // set it hr = _pGfx->gl_pd3dDevice->SetIndices( _pGfx->gl_pd3dIdx, 0); D3D_CHECKERROR(hr); } // just switch it off if not needed any more (i.e. D3D is shutting down) else _pGfx->gl_ctIndices = 0; // reset and check _iIdxOffset = 0; ASSERT(_pGfx->gl_ctIndices<65536); } // initialize Direct3D driver BOOL CGfxLibrary::InitDriver_D3D(void) { // check for presence of DirectX 8 gl_hiDriver = LoadLibraryA( "D3D8.DLL"); if( gl_hiDriver==NONE) { // not present - BUAHHAHAHAHAR :) CPrintF( "DX8 error: API not installed.\n"); gl_gaAPI[GAT_D3D].ga_ctAdapters = 0; return FALSE; } // query DX8 interface IDirect3D8* (WINAPI *pDirect3DCreate8)(UINT SDKVersion); pDirect3DCreate8 = (IDirect3D8* (WINAPI *)(UINT SDKVersion))GetProcAddress( gl_hiDriver, "Direct3DCreate8"); if( pDirect3DCreate8==NULL) { // cannot init CPrintF( "DX8 error: Cannot get entry procedure address.\n"); FreeLibrary(gl_hiDriver); gl_hiDriver = NONE; return FALSE; } // init DX8 gl_pD3D = pDirect3DCreate8(D3D_SDK_VERSION); if( gl_pD3D==NULL) { // cannot start CPrintF( "DX8 error: Cannot be initialized.\n"); FreeLibrary(gl_hiDriver); gl_hiDriver = NONE; return FALSE; } // made it! return TRUE; } // initialize Direct3D driver void CGfxLibrary::EndDriver_D3D(void) { // unbind textures if( _pTextureStock!=NULL) { {FOREACHINDYNAMICCONTAINER( _pTextureStock->st_ctObjects, CTextureData, ittd) { CTextureData &td = *ittd; td.td_tpLocal.Clear(); td.Unbind(); }} } // unbind fog, haze and flat texture gfxDeleteTexture( _fog_ulTexture); gfxDeleteTexture( _haze_ulTexture); ASSERT( _ptdFlat!=NULL); _ptdFlat->td_tpLocal.Clear(); _ptdFlat->Unbind(); // reset shader and vertices SetupShader_D3D(NONE); SetupVertexArrays_D3D(0); SetupIndexArray_D3D(0); gl_d3dColorFormat = (D3DFORMAT)NONE; gl_d3dDepthFormat = (D3DFORMAT)NONE; // shutdown device and d3d INDEX iRef; iRef = gl_pd3dDevice->Release(); iRef = gl_pD3D->Release(); } // prepare current viewport for rendering thru Direct3D BOOL CGfxLibrary::SetCurrentViewport_D3D(CViewPort *pvp) { // determine full screen mode CDisplayMode dm; RECT rectWindow; _pGfx->GetCurrentDisplayMode(dm); ASSERT( (dm.dm_pixSizeI==0 && dm.dm_pixSizeJ==0) || (dm.dm_pixSizeI!=0 && dm.dm_pixSizeJ!=0)); GetClientRect( pvp->vp_hWnd, &rectWindow); const PIX pixWinSizeI = rectWindow.right - rectWindow.left; const PIX pixWinSizeJ = rectWindow.bottom - rectWindow.top; // full screen allows only one window (main one, which has already been initialized) if( dm.dm_pixSizeI==pixWinSizeI && dm.dm_pixSizeJ==pixWinSizeJ) { gl_pvpActive = pvp; // remember as current viewport (must do that BEFORE InitContext) if( gl_ulFlags & GLF_INITONNEXTWINDOW) InitContext_D3D(); gl_ulFlags &= ~GLF_INITONNEXTWINDOW; return TRUE; } // if must init entire D3D if( gl_ulFlags & GLF_INITONNEXTWINDOW) { gl_ulFlags &= ~GLF_INITONNEXTWINDOW; // reopen window pvp->CloseCanvas(); pvp->OpenCanvas(); gl_pvpActive = pvp; InitContext_D3D(); pvp->vp_ctDisplayChanges = gl_ctDriverChanges; return TRUE; } // if window was not set for this driver if( pvp->vp_ctDisplayChangesCloseCanvas(); pvp->OpenCanvas(); pvp->vp_ctDisplayChanges = gl_ctDriverChanges; gl_pvpActive = pvp; return TRUE; } // no need to set context if it is the same window as last time if( gl_pvpActive!=NULL && gl_pvpActive->vp_hWnd==pvp->vp_hWnd) return TRUE; // set rendering target HRESULT hr; LPDIRECT3DSURFACE8 pColorSurface; hr = pvp->vp_pSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pColorSurface); if( hr!=D3D_OK) return FALSE; hr = gl_pd3dDevice->SetRenderTarget( pColorSurface, pvp->vp_pSurfDepth); D3DRELEASE( pColorSurface, TRUE); if( hr!=D3D_OK) return FALSE; // remember as current window gl_pvpActive = pvp; return TRUE; } // prepares Direct3D drawing context void CGfxLibrary::InitContext_D3D() { // must have context ASSERT( gl_pvpActive!=NULL); // report header CPrintF( TRANS("\n* Direct3D context created: *----------------------------------\n")); CDisplayAdapter &da = gl_gaAPI[GAT_D3D].ga_adaAdapter[gl_iCurrentAdapter]; CPrintF( " (%s, %s, %s)\n\n", da.da_strVendor, da.da_strRenderer, da.da_strVersion); HRESULT hr; // reset engine's internal Direct3D state variables GFX_bTruform = FALSE; GFX_bClipping = TRUE; GFX_bFrontFace = TRUE; hr = gl_pd3dDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE); D3D_CHECKERROR(hr); GFX_bDepthTest = FALSE; hr = gl_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE); D3D_CHECKERROR(hr); GFX_bDepthWrite = FALSE; hr = gl_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE); D3D_CHECKERROR(hr); GFX_bAlphaTest = FALSE; hr = gl_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE); D3D_CHECKERROR(hr); GFX_bBlending = FALSE; hr = gl_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE); D3D_CHECKERROR(hr); GFX_bDithering = TRUE; hr = gl_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, FALSE); D3D_CHECKERROR(hr); GFX_bClipPlane = FALSE; hr = gl_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE); D3D_CHECKERROR(hr); GFX_eCullFace = GFX_NONE; hr = gl_pd3dDevice->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL); D3D_CHECKERROR(hr); GFX_eDepthFunc = GFX_LESS_EQUAL; hr = gl_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE); D3D_CHECKERROR(hr); GFX_eBlendSrc = GFX_ONE; hr = gl_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE); D3D_CHECKERROR(hr); GFX_eBlendDst = GFX_ONE; // (re)set some D3D defaults hr = gl_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); D3D_CHECKERROR(hr); hr = gl_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 128); D3D_CHECKERROR(hr); // constant color default setup hr = gl_pd3dDevice->SetRenderState( D3DRS_COLORVERTEX, FALSE); D3D_CHECKERROR(hr); hr = gl_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE); D3D_CHECKERROR(hr); hr = gl_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xFFFFFFFF); D3D_CHECKERROR(hr); D3DMATERIAL8 d3dMaterial; memset( &d3dMaterial, 0, sizeof(d3dMaterial)); d3dMaterial.Diffuse.r = d3dMaterial.Ambient.r = 1.0f; d3dMaterial.Diffuse.g = d3dMaterial.Ambient.g = 1.0f; d3dMaterial.Diffuse.b = d3dMaterial.Ambient.b = 1.0f; d3dMaterial.Diffuse.a = d3dMaterial.Ambient.a = 1.0f; hr = gl_pd3dDevice->SetMaterial(&d3dMaterial); D3D_CHECKERROR(hr); GFX_bColorArray = FALSE; // disable texturing extern BOOL GFX_abTexture[GFX_MAXTEXUNITS]; for( INDEX iUnit=0; iUnitSetTexture( iUnit, NULL); D3D_CHECKERROR(hr); hr = gl_pd3dDevice->SetTextureStageState( iUnit, D3DTSS_COLOROP, D3DTOP_DISABLE); D3D_CHECKERROR(hr); hr = gl_pd3dDevice->SetTextureStageState( iUnit, D3DTSS_ALPHAOP, D3DTOP_MODULATE); D3D_CHECKERROR(hr); } // set default texture unit and modulation mode GFX_iActiveTexUnit = 0; // reset frustum/ortho matrix 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; // reset depth range D3DVIEWPORT8 d3dViewPort = { 0,0, 8,8, 0,1 }; hr = gl_pd3dDevice->SetViewport( &d3dViewPort); D3D_CHECKERROR(hr); hr = gl_pd3dDevice->GetViewport( &d3dViewPort); D3D_CHECKERROR(hr); ASSERT( d3dViewPort.MinZ==0 && d3dViewPort.MaxZ==1); GFX_fMinDepthRange = 0.0f; GFX_fMaxDepthRange = 1.0f; // get capabilites D3DCAPS8 d3dCaps; hr = gl_pd3dDevice->GetDeviceCaps( &d3dCaps); D3D_CHECKERROR(hr); // determine rasterizer acceleration gl_ulFlags &= ~GLF_HASACCELERATION; if( (d3dCaps.DevCaps & D3DDEVCAPS_HWRASTERIZATION) || d3dDevType==D3DDEVTYPE_REF) gl_ulFlags |= GLF_HASACCELERATION; // determine support for 32-bit textures gl_ulFlags &= ~GLF_32BITTEXTURES; if( HasTextureFormat_D3D(D3DFMT_X8R8G8B8) || HasTextureFormat_D3D(D3DFMT_A8R8G8B8)) gl_ulFlags |= GLF_32BITTEXTURES; // determine support for compressed textures gl_ulFlags &= ~GLF_TEXTURECOMPRESSION; if( HasTextureFormat_D3D(D3DFMT_DXT1)) gl_ulFlags |= GLF_TEXTURECOMPRESSION; // determine max supported dimension of texture gl_pixMaxTextureDimension = d3dCaps.MaxTextureWidth; ASSERT( gl_pixMaxTextureDimension == d3dCaps.MaxTextureHeight); // perhaps not ? // determine support for disabling of color buffer writes gl_ulFlags &= ~GLF_D3D_COLORWRITES; if( d3dCaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) gl_ulFlags |= GLF_D3D_COLORWRITES; // determine support for custom clip planes gl_ulFlags &= ~GLF_D3D_CLIPPLANE; if( d3dCaps.MaxUserClipPlanes>0) gl_ulFlags |= GLF_D3D_CLIPPLANE; else CPrintF( TRANS("User clip plane not supported - mirrors will not work well.\n")); // determine support for texture LOD biasing gl_fMaxTextureLODBias = 0.0f; if( d3dCaps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) { gl_fMaxTextureLODBias = 4.0f; } // determine support for anisotropic filtering gl_iMaxTextureAnisotropy = 1; if( d3dCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) { gl_iMaxTextureAnisotropy = d3dCaps.MaxAnisotropy; ASSERT( gl_iMaxTextureAnisotropy>1); } // determine support for z-biasing gl_ulFlags &= ~GLF_D3D_ZBIAS; if( d3dCaps.RasterCaps & D3DPRASTERCAPS_ZBIAS) gl_ulFlags |= GLF_D3D_ZBIAS; // check support for vsync swapping gl_ulFlags &= ~GLF_VSYNC; if( d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) { if( d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) gl_ulFlags |= GLF_VSYNC; } else CPrintF( TRANS(" Vertical syncronization cannot be disabled.\n")); // determine support for N-Patches extern INDEX truform_iLevel; extern BOOL truform_bLinear; truform_iLevel = -1; truform_bLinear = FALSE; gl_iTessellationLevel = 0; gl_iMaxTessellationLevel = 0; INDEX ctMinStreams = GFX_MINSTREAMS; // set minimum number of required streams if( d3dCaps.DevCaps & D3DDEVCAPS_NPATCHES) { if( gl_ctMaxStreams>GFX_MINSTREAMS) { gl_iMaxTessellationLevel = 7; hr = gl_pd3dDevice->SetRenderState( D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE); D3D_CHECKERROR(hr); ctMinStreams++; // need an extra stream for normals now } else CPrintF( TRANS("Not enough streams - N-Patches cannot be used.\n")); } // determine support for multi-texturing (only if Modulate2X mode is supported!) gl_ctTextureUnits = 1; gl_ctRealTextureUnits = d3dCaps.MaxSimultaneousTextures; if( gl_ctRealTextureUnits>1) { // check everything that is required for multi-texturing if( !(d3dCaps.TextureOpCaps&D3DTOP_MODULATE2X)) CPrintF( TRANS("Texture operation MODULATE2X missing - multi-texturing cannot be used.\n")); else if( gl_ctMaxStreams<=ctMinStreams) CPrintF( TRANS("Not enough streams - multi-texturing cannot be used.\n")); else gl_ctTextureUnits = Min( GFX_MAXTEXUNITS, Min( gl_ctRealTextureUnits, 1+gl_ctMaxStreams-ctMinStreams)); } // setup fog and haze textures extern PIX _fog_pixSizeH; extern PIX _fog_pixSizeL; extern PIX _haze_pixSize; _fog_ulTexture = NONE; _haze_ulTexture = NONE; _fog_pixSizeH = 0; _fog_pixSizeL = 0; _haze_pixSize = 0; // prepare pattern texture extern CTexParams _tpPattern; extern ULONG _ulPatternTexture; extern ULONG _ulLastUploadedPattern; _ulPatternTexture = NONE; _ulLastUploadedPattern = 0; _tpPattern.Clear(); // determine number of color/texcoord buffers gl_ctTexBuffers = gl_ctTextureUnits; gl_ctColBuffers = 1; INDEX ctStreamsRemain = gl_ctMaxStreams - (ctMinStreams-1+gl_ctTextureUnits); // -1 because of 1 texture unit inside MinStreams FOREVER { // done if no more or enough streams if( ctStreamsRemain==0 || (gl_ctTexBuffers==GFX_MAXLAYERS && gl_ctColBuffers==GFX_MAXLAYERS)) break; // increase number of tex or color buffers if( gl_ctColBuffers0 && gl_ctTexBuffers<=GFX_MAXLAYERS); ASSERT( gl_ctColBuffers>0 && gl_ctColBuffers<=GFX_MAXLAYERS); gl_ctVertices = 0; gl_ctIndices = 0; extern INDEX d3d_iVertexBuffersSize; extern INDEX _iLastVertexBufferSize; const INDEX ctVertices = VerticesFromSize_D3D(d3d_iVertexBuffersSize); _iLastVertexBufferSize = d3d_iVertexBuffersSize; SetupVertexArrays_D3D(ctVertices); SetupIndexArray_D3D(2*ctVertices); // reset texture filtering and some static vars _tpGlobal[0].Clear(); _tpGlobal[1].Clear(); _tpGlobal[2].Clear(); _tpGlobal[3].Clear(); _avsShaders.Clear(); _iVtxOffset = 0; _iIdxOffset = 0; _dwCurrentVS = NONE; _ulStreamsMask = NONE; _ulLastStreamsMask = NONE; _bProjectiveMapping = FALSE; _bLastProjectiveMapping = FALSE; gl_dwVertexShader = NONE; GFX_ctVertices = 0; // reset locking flags _dwVtxLockFlags = D3DLOCK_DISCARD; for( i=0; igl_pD3D->CheckDepthStencilMatch( iAdapter, d3dDevType, d3dfColor, d3dfColor, ad3dFormats[i]); if( hr==D3D_OK) break; } // not found? if( i==ctFormats) { // do additional check for whole format list for( i=0; igl_pD3D->CheckDepthStencilMatch( iAdapter, d3dDevType, d3dfColor, d3dfColor, ad3dFormats[i]); if( hr==D3D_OK) break; } // what, z-buffer still not supported? if( i==iStart) { ASSERT( "FindDepthFormat_D3D: Z-buffer format not found?!" ); iDepthBits = 0; return D3DFMT_UNKNOWN; } } // aaaah, found! :) ASSERT( i>=0 && i3) iDepthBits = 16; else if( i>0) iDepthBits = 24; else iDepthBits = 32; return ad3dFormats[i]; } // prepare display mode BOOL CGfxLibrary::InitDisplay_D3D( INDEX iAdapter, PIX pixSizeI, PIX pixSizeJ, enum DisplayDepth eColorDepth) { // reset HRESULT hr; D3DDISPLAYMODE d3dDisplayMode; D3DPRESENT_PARAMETERS d3dPresentParams; gl_pD3D->GetAdapterDisplayMode( iAdapter, &d3dDisplayMode); memset( &d3dPresentParams, 0, sizeof(d3dPresentParams)); // readout device capabilites D3DCAPS8 d3dCaps; hr = gl_pD3D->GetDeviceCaps( iAdapter, d3dDevType, &d3dCaps); D3D_CHECKERROR(hr); // clamp depth/stencil values extern INDEX gap_iDepthBits; extern INDEX gap_iStencilBits; if( gap_iDepthBits <12) gap_iDepthBits = 0; else if( gap_iDepthBits <22) gap_iDepthBits = 16; else if( gap_iDepthBits <28) gap_iDepthBits = 24; else gap_iDepthBits = 32; if( gap_iStencilBits<3) gap_iStencilBits = 0; else if( gap_iStencilBits<7) gap_iStencilBits = 4; else gap_iStencilBits = 8; // prepare INDEX iZDepth = gap_iDepthBits; D3DFORMAT d3dDepthFormat = D3DFMT_UNKNOWN; D3DFORMAT d3dColorFormat = d3dDisplayMode.Format; d3dPresentParams.BackBufferCount = 1; d3dPresentParams.MultiSampleType = D3DMULTISAMPLE_NONE; // !!!! TODO d3dPresentParams.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; d3dPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD; const BOOL bFullScreen = (pixSizeI>0 && pixSizeJ>0); // setup for full screen if( bFullScreen) { // determine color and depth format if( eColorDepth==DD_16BIT) d3dColorFormat = D3DFMT_R5G6B5; if( eColorDepth==DD_32BIT) d3dColorFormat = D3DFMT_X8R8G8B8; d3dDepthFormat = FindDepthFormat_D3D( iAdapter, d3dColorFormat, iZDepth); // determine refresh rate and presentation interval extern INDEX gap_iRefreshRate; const UINT uiRefresh = gap_iRefreshRate>0 ? gap_iRefreshRate : D3DPRESENT_RATE_DEFAULT; const SLONG slIntervals = d3dCaps.PresentationIntervals; UINT uiInterval = (slIntervals&D3DPRESENT_INTERVAL_IMMEDIATE) ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE; extern INDEX gap_iSwapInterval; switch(gap_iSwapInterval) { case 1: if( slIntervals&D3DPRESENT_INTERVAL_ONE) uiInterval=D3DPRESENT_INTERVAL_ONE; break; case 2: if( slIntervals&D3DPRESENT_INTERVAL_TWO) uiInterval=D3DPRESENT_INTERVAL_TWO; break; case 3: if( slIntervals&D3DPRESENT_INTERVAL_THREE) uiInterval=D3DPRESENT_INTERVAL_THREE; break; case 4: if( slIntervals&D3DPRESENT_INTERVAL_FOUR) uiInterval=D3DPRESENT_INTERVAL_FOUR; break; default: break; } // construct back cvar switch(uiInterval) { case 1: gap_iSwapInterval=1; break; case 2: gap_iSwapInterval=2; break; case 3: gap_iSwapInterval=3; break; case 4: gap_iSwapInterval=4; break; default: gap_iSwapInterval=0; break; } gl_iSwapInterval = gap_iSwapInterval; // copy to gfx lib // set context directly to main window d3dPresentParams.Windowed = FALSE; d3dPresentParams.BackBufferWidth = pixSizeI; d3dPresentParams.BackBufferHeight = pixSizeJ; d3dPresentParams.BackBufferFormat = d3dColorFormat; d3dPresentParams.EnableAutoDepthStencil = TRUE; d3dPresentParams.AutoDepthStencilFormat = d3dDepthFormat; d3dPresentParams.FullScreen_RefreshRateInHz = uiRefresh; d3dPresentParams.FullScreen_PresentationInterval = uiInterval; } // setup for windowed mode else { // create dummy Direct3D context d3dPresentParams.Windowed = TRUE; d3dPresentParams.BackBufferWidth = 8; d3dPresentParams.BackBufferHeight = 8; d3dPresentParams.BackBufferFormat = d3dColorFormat; d3dPresentParams.EnableAutoDepthStencil = FALSE; d3dDepthFormat = FindDepthFormat_D3D( iAdapter, d3dColorFormat, iZDepth); gl_iSwapInterval = -1; } // determine HW or SW vertex processing DWORD dwVP = D3DCREATE_SOFTWARE_VERTEXPROCESSING; gl_ulFlags &= ~(GLF_D3D_HASHWTNL|GLF_D3D_USINGHWTNL); gl_ctMaxStreams = 16; // software T&L has enough streams extern INDEX d3d_bUseHardwareTnL; // cannot have HW VP if not supported by HW, right? if( d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { gl_ulFlags |= GLF_D3D_HASHWTNL; gl_ctMaxStreams = d3dCaps.MaxStreams; if( gl_ctMaxStreamsCreateDevice( iAdapter, d3dDevType, _hwndMain, dwVP, &d3dPresentParams, &gl_pd3dDevice); if( hr!=D3D_OK) return FALSE; gl_d3dColorFormat = d3dColorFormat; gl_d3dDepthFormat = d3dDepthFormat; gl_iCurrentDepth = iZDepth; return TRUE; } // fallback D3D internal format // (reverts to next format that closely matches requied one) static D3DFORMAT FallbackFormat_D3D( D3DFORMAT eFormat, BOOL b2ndTry) { switch( eFormat) { case D3DFMT_X8R8G8B8: return !b2ndTry ? D3DFMT_A8R8G8B8 : D3DFMT_R5G6B5; case D3DFMT_X1R5G5B5: return !b2ndTry ? D3DFMT_R5G6B5 : D3DFMT_A1R5G5B5; case D3DFMT_X4R4G4B4: return !b2ndTry ? D3DFMT_R5G6B5 : D3DFMT_A1R5G5B5; case D3DFMT_R5G6B5: return !b2ndTry ? D3DFMT_X1R5G5B5 : D3DFMT_A1R5G5B5; case D3DFMT_L8: return !b2ndTry ? D3DFMT_A8L8 : D3DFMT_X8R8G8B8; case D3DFMT_A8L8: return D3DFMT_A8R8G8B8; case D3DFMT_A1R5G5B5: return D3DFMT_A4R4G4B4; case D3DFMT_A8R8G8B8: return D3DFMT_A4R4G4B4; case D3DFMT_DXT1: return D3DFMT_A1R5G5B5; case D3DFMT_DXT3: return D3DFMT_A4R4G4B4; case D3DFMT_DXT5: return D3DFMT_A4R4G4B4; case D3DFMT_A4R4G4B4: // must have this one! default: ASSERTALWAYS( "Can't fallback texture format."); } // missed! return D3DFMT_UNKNOWN; } // find closest extern D3DFORMAT FindClosestFormat_D3D( D3DFORMAT d3df) { FOREVER { if( HasTextureFormat_D3D(d3df)) return d3df; D3DFORMAT d3df2 = FallbackFormat_D3D( d3df, FALSE); if( HasTextureFormat_D3D(d3df2)) return d3df2; d3df = FallbackFormat_D3D( d3df, TRUE); } } // VERTEX/INDEX BUFFERS SUPPORT THRU STREAMS // DEBUG helper static void CheckStreams(void) { UINT uiRet, ui; INDEX iRef, iPass; DWORD dwVS; HRESULT hr; LPDIRECT3DVERTEXBUFFER8 pVBRet, pVB; LPDIRECT3DINDEXBUFFER8 pIBRet; const LPDIRECT3DDEVICE8 pd3dDev = _pGfx->gl_pd3dDevice; // check passes and buffer position ASSERT( _iTexPass>=0 && _iColPass>=0); ASSERT( _iVtxPos >=0 && _iVtxPos<65536); // check vertex positions ASSERT( _ulStreamsMask & (1<GetStreamSource( POSIDX, &pVBRet, &uiRet); D3D_CHECKERROR(hr); ASSERT( pVBRet!=NULL); iRef = pVBRet->Release(); ASSERT( iRef==1 && pVBRet==_pGfx->gl_pd3dVtx && uiRet==POSSIZE); // check normals pVB = NULL; ui = NORSIZE; hr = pd3dDev->GetStreamSource( NORIDX, &pVBRet, &uiRet); D3D_CHECKERROR(hr); if( pVBRet!=NULL) iRef = pVBRet->Release(); if( _ulStreamsMask & (1<gl_pd3dNor; ASSERT( iRef==1 && pVBRet==pVB && (uiRet==ui || uiRet==0)); // check colors pVB = NULL; ui = COLSIZE; hr = pd3dDev->GetStreamSource( COLIDX, &pVBRet, &uiRet); D3D_CHECKERROR(hr); if( pVBRet!=NULL) iRef = pVBRet->Release(); if( _ulStreamsMask & (1<gl_ctColBuffers; pVB = _pGfx->gl_pd3dCol[iPass]; } ASSERT( iRef==1 && pVBRet==pVB && (uiRet==ui || uiRet==0)); // check 1st texture coords pVB = NULL; ui = _bProjectiveMapping ? TX4SIZE : TEXSIZE; hr = pd3dDev->GetStreamSource( TEXIDX, &pVBRet, &uiRet); D3D_CHECKERROR(hr); if( pVBRet!=NULL) iRef = pVBRet->Release(); if( _ulStreamsMask & (1<<(TEXIDX))) { iPass = (_iTexPass-1) % _pGfx->gl_ctTexBuffers; pVB = _pGfx->gl_pd3dTex[iPass]; } ASSERT( iRef==1 && pVBRet==pVB && (uiRet==ui || uiRet==0)); // check indices hr = pd3dDev->GetIndices( &pIBRet, &uiRet); D3D_CHECKERROR(hr); ASSERT( pIBRet!=NULL); iRef = pIBRet->Release(); ASSERT( iRef==1 && pIBRet==_pGfx->gl_pd3dIdx && uiRet==0); // check shader hr = pd3dDev->GetVertexShader( &dwVS); D3D_CHECKERROR(hr); ASSERT( dwVS!=NONE && dwVS==_pGfx->gl_dwVertexShader); /* check shader declaration (SEEMS LIKE THIS SHIT DOESN'T WORK!) const INDEX ctMaxDecls = 2*MAXSTREAMS+1; INDEX ctDecls = ctMaxDecls; DWORD adwDeclRet[ctMaxDecls]; hr = pd3dDev->GetVertexShaderDeclaration( _pGfx->gl_dwVertexShader, (void*)&adwDeclRet[0], (DWORD*)&ctDecls); D3D_CHECKERROR(hr); ASSERT( ctDecls>0 && ctDecls=0 && _iColPass>=0); ASSERT( _iVtxPos >=0 && _iVtxPos<65536); const BOOL bHWTnL = _pGfx->gl_ulFlags & GLF_D3D_USINGHWTNL; // determine which buffer we work on switch(iType) { // VERTICES case 0: // make sure that we have enough space in vertex buffers ASSERT(GFX_ctVertices>0); SetupVertexArrays_D3D( GFX_ctVertices * (bHWTnL?2:1)); // determine lock type pd3dVB = _pGfx->gl_pd3dVtx; if( !bHWTnL || (_iVtxOffset+GFX_ctVertices)>=_pGfx->gl_ctVertices) { // reset pos and flags _iVtxOffset = 0; _dwVtxLockFlags = D3DLOCK_DISCARD; for( INDEX i=0; igl_iMaxTessellationLevel>0 && gap_iTruformLevel>0); // only if enabled pd3dVB = _pGfx->gl_pd3dNor; ASSERT( _iTexPass<2 && _iColPass<2); // normals must be set in 1st pass (completed or not) // determine lock type, pos and size dwLockFlag = _dwVtxLockFlags; ctLockSize = GFX_ctVertices*4; iLockOffset = _iVtxPos*4; // set stream params iStream = NORIDX; slStride = NORSIZE; break; // COLORS case 2: iThisPass = _iColPass; // restart in case of too many passes if( iThisPass>=_pGfx->gl_ctColBuffers) { dwLockFlag = D3DLOCK_DISCARD; iThisPass %= _pGfx->gl_ctColBuffers; } else { // continue in case of enough buffers dwLockFlag = _dwColLockFlags[iThisPass]; } // mark _dwColLockFlags[iThisPass] = D3DLOCK_NOOVERWRITE; ASSERT( iThisPass>=0 && iThisPass<_pGfx->gl_ctColBuffers); pd3dVB = _pGfx->gl_pd3dCol[iThisPass]; // determine lock pos and size ctLockSize = GFX_ctVertices*1; iLockOffset = _iVtxPos*1; // set stream params iStream = COLIDX; slStride = COLSIZE; _iColPass++; // advance to next color pass break; // PROJECTIVE TEXTURE COORDINATES case 4: _bProjectiveMapping = TRUE; // fall thru ... // TEXTURE COORDINATES case 3: iThisPass = _iTexPass; // restart in case of too many passes if( iThisPass>=_pGfx->gl_ctTexBuffers) { dwLockFlag = D3DLOCK_DISCARD; iThisPass %= _pGfx->gl_ctTexBuffers; } else { // continue in case of enough buffers dwLockFlag = _dwTexLockFlags[iThisPass]; } // mark _dwTexLockFlags[iThisPass] = D3DLOCK_NOOVERWRITE; ASSERT( iThisPass>=0 && iThisPass<_pGfx->gl_ctTexBuffers); pd3dVB = _pGfx->gl_pd3dTex[iThisPass]; // set stream number (must take into account tex-unit, because of multi-texturing!) iStream = TEXIDX +GFX_iActiveTexUnit; // determine stride, lock pos and size if( _bProjectiveMapping) { ctLockSize = GFX_ctVertices*4; iLockOffset = _iVtxPos*4; slStride = TX4SIZE; } else { ctLockSize = GFX_ctVertices*2; iLockOffset = _iVtxPos*2; slStride = TEXSIZE; } // advance to next texture pass _iTexPass++; break; // BUF! WRONG. default: ASSERTALWAYS( "SetVertexArray_D3D: wrong stream number!"); } ASSERT( _iTexPass>=0 && _iColPass>=0); ASSERT( _iVtxPos >=0 && _iVtxPos<65536); // fetch D3D buffer ULONG *pulLockedBuffer; hr = pd3dVB->Lock( iLockOffset*sizeof(ULONG), ctLockSize*sizeof(ULONG), (UBYTE**)&pulLockedBuffer, dwLockFlag); D3D_CHECKERROR(hr); // copy (or convert) vertices there and unlock ASSERT(pulVtx!=NULL); if( iType!=2) CopyLongs( pulVtx, pulLockedBuffer, ctLockSize); // vertex array else abgr2argb( pulVtx, pulLockedBuffer, ctLockSize); // color array (needs conversion) // done hr = pd3dVB->Unlock(); D3D_CHECKERROR(hr); // update streams mask and assign _ulStreamsMask |= 1<gl_pd3dDevice->SetStreamSource( iStream, pd3dVB, slStride); D3D_CHECKERROR(hr); } // prepare and draw arrays extern void DrawElements_D3D( INDEX ctIndices, INDEX *pidx) { // paranoid & sunburnt (by Skunk Anansie:) ASSERT( _iTexPass>=0 && _iColPass>=0); ASSERT( _iVtxPos >=0 && _iVtxPos<65536); const LPDIRECT3DDEVICE8 pd3dDev = _pGfx->gl_pd3dDevice; // at least one triangle must be sent ASSERT( ctIndices>=3 && ((ctIndices/3)*3)==ctIndices); if( ctIndices<3) return; extern INDEX d3d_iVertexRangeTreshold; d3d_iVertexRangeTreshold = Clamp( d3d_iVertexRangeTreshold, 0L, 9999L); // eventually adjust size of index buffer const BOOL bHWTnL = _pGfx->gl_ulFlags & GLF_D3D_USINGHWTNL; SetupIndexArray_D3D( ctIndices * (bHWTnL?2:1)); // determine lock position and type if( (_iIdxOffset+ctIndices) >= _pGfx->gl_ctIndices) _iIdxOffset = 0; const DWORD dwLockFlag = (_iIdxOffset>0) ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD; const SLONG slLockSize = ctIndices *IDXSIZE; const SLONG slLockOffset = _iIdxOffset*IDXSIZE; // copy indices to index buffer HRESULT hr; UWORD *puwLockedBuffer; hr = _pGfx->gl_pd3dIdx->Lock( slLockOffset, slLockSize, (UBYTE**)&puwLockedBuffer, dwLockFlag); D3D_CHECKERROR(hr); INDEX iMinIndex = 65536; INDEX iMaxIndex = 0; const BOOL bSetRange = !(_pGfx->gl_ulFlags&GLF_D3D_USINGHWTNL) && (GFX_ctVertices>d3d_iVertexRangeTreshold); ASSERT( _iVtxPos>=0 && _iVtxPos<65536); #if ASMOPT == 1 const __int64 mmSignD = 0x0000800000008000; const __int64 mmSignW = 0x8000800080008000; __asm { // adjust 32-bit and copy to 16-bit array mov esi,D [pidx] mov edi,D [puwLockedBuffer] mov ecx,D [ctIndices] shr ecx,2 // 4 by 4 jz elemL2 movd mm7,D [_iVtxPos] punpcklwd mm7,mm7 punpckldq mm7,mm7 // MM7 = vtxPos | vtxPos || vtxPos | vtxPos paddw mm7,Q [mmSignW] elemCLoop: movq mm1,Q [esi+0] movq mm2,Q [esi+8] psubd mm1,Q [mmSignD] psubd mm2,Q [mmSignD] packssdw mm1,mm2 paddw mm1,mm7 movq Q [edi],mm1 add esi,4*4 add edi,2*4 dec ecx jnz elemCLoop emms elemL2: test D [ctIndices],2 jz elemL1 mov eax,D [esi+0] mov edx,D [esi+4] add eax,D [_iVtxPos] add edx,D [_iVtxPos] shl edx,16 or eax,edx mov D [edi],eax add esi,4*2 add edi,2*2 elemL1: test D [ctIndices],1 jz elemRange mov eax,D [esi] add eax,D [_iVtxPos] mov W [edi],ax elemRange: // find min/max index (if needed) cmp D [bSetRange],0 jz elemEnd mov edi,D [iMinIndex] mov edx,D [iMaxIndex] mov esi,D [pidx] mov ecx,D [ctIndices] elemTLoop: mov eax,D [esi] add eax,D [_iVtxPos] cmp eax,edi cmovl edi,eax cmp eax,edx cmovg edx,eax add esi,4 dec ecx jnz elemTLoop mov D [iMinIndex],edi mov D [iMaxIndex],edx elemEnd: } #else for( INDEX idx=0; idxiAdj) iMinIndex = iAdj; else if( iMaxIndexgl_pd3dIdx->Unlock(); D3D_CHECKERROR(hr); // check whether to use color array or not if( GFX_bColorArray) _ulStreamsMask |= (1<SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, ttf); D3D_CHECKERROR(hr); } // eventually (re)construct vertex shader out of streams' bit-mask if( _ulLastStreamsMask != _ulStreamsMask) { // reset streams that were used before ULONG ulThisMask = _ulStreamsMask; ULONG ulLastMask = _ulLastStreamsMask; for( INDEX iStream=0; iStreamSetStreamSource( iStream,NULL,0); D3D_CHECKERROR(hr); } // next stream ulThisMask >>= 1; ulLastMask >>= 1; } // setup new vertex shader _dwCurrentVS = SetupShader_D3D(_ulStreamsMask); _ulLastStreamsMask = _ulStreamsMask; } // (re)set vertex shader ASSERT(_dwCurrentVS!=NONE); if( _pGfx->gl_dwVertexShader!=_dwCurrentVS) { hr = _pGfx->gl_pd3dDevice->SetVertexShader(_dwCurrentVS); D3D_CHECKERROR(hr); _pGfx->gl_dwVertexShader = _dwCurrentVS; } #ifndef NDEBUG // Paranoid Android (by Radiohead:) CheckStreams(); #endif // determine vertex range INDEX iVtxStart, ctVtxUsed; // if not too much vertices in buffer if( !bSetRange) { // set whole vertex buffer iVtxStart = _iVtxPos; ctVtxUsed = GFX_ctVertices; // if lotta vertices in buffer } else { // set only part of vertex buffer iVtxStart = iMinIndex; ctVtxUsed = iMaxIndex-iMinIndex+1; ASSERT( iMinIndexDrawIndexedPrimitive( D3DPT_TRIANGLELIST, iVtxStart, ctVtxUsed, _iIdxOffset, ctIndices/3); D3D_CHECKERROR(hr); // move to next available lock position _iIdxOffset += ctIndices; } #endif // SE1_D3D