// change texture filtering mode if needed extern void MimicTexParams_D3D( CTexParams &tpLocal) { ASSERT( &tpLocal!=NULL); _pfGfxProfile.StartTimer( CGfxProfile::PTI_TEXTUREPARAMS); // update texture filtering mode if required if( tpLocal.tp_iFilter != _tpGlobal[0].tp_iFilter) tpLocal.tp_iFilter = _tpGlobal[0].tp_iFilter; // eventually adjust filtering for textures w/o mipmaps const INDEX iMipFilter = _tpGlobal[0].tp_iFilter % 10; if( (!tpLocal.tp_bSingleMipmap != !_tpGlobal[GFX_iActiveTexUnit].tp_bSingleMipmap) && iMipFilter!=0) { HRESULT hr; _D3DTEXTUREFILTERTYPE eMipFilter; extern INDEX GFX_iActiveTexUnit; // no mipmaps? if( tpLocal.tp_bSingleMipmap) { #ifndef NDEBUG // paranoid! hr = _pGfx->gl_pd3dDevice->GetTextureStageState( GFX_iActiveTexUnit, D3DTSS_MIPFILTER, (ULONG*)&eMipFilter); D3D_CHECKERROR(hr); ASSERT( eMipFilter==D3DTEXF_POINT || eMipFilter==D3DTEXF_LINEAR); #endif // set it hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_MIPFILTER, D3DTEXF_NONE); } // yes mipmaps? else { switch( iMipFilter) { case 0: eMipFilter = D3DTEXF_NONE; break; case 1: eMipFilter = D3DTEXF_POINT; break; case 2: eMipFilter = D3DTEXF_LINEAR; break; default: ASSERTALWAYS( "Invalid mipmap filtering mode."); } // set it hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_MIPFILTER, eMipFilter); } // check and update mipmap state D3D_CHECKERROR(hr); _tpGlobal[GFX_iActiveTexUnit].tp_bSingleMipmap = tpLocal.tp_bSingleMipmap; } // update texture anisotropy degree if( tpLocal.tp_iAnisotropy != _tpGlobal[0].tp_iAnisotropy) tpLocal.tp_iAnisotropy = _tpGlobal[0].tp_iAnisotropy; // update texture clamping modes if changed if( tpLocal.tp_eWrapU!=_tpGlobal[GFX_iActiveTexUnit].tp_eWrapU || tpLocal.tp_eWrapV!=_tpGlobal[GFX_iActiveTexUnit].tp_eWrapV) { tpLocal.tp_eWrapU = _tpGlobal[GFX_iActiveTexUnit].tp_eWrapU; tpLocal.tp_eWrapV = _tpGlobal[GFX_iActiveTexUnit].tp_eWrapV; } // keep last texture params (for tex upload and stuff) _tpCurrent = &tpLocal; _pfGfxProfile.StopTimer( CGfxProfile::PTI_TEXTUREPARAMS); }
// read depth buffer and update visibility flag of depth points static void UpdateDepthPointsVisibility( const CDrawPort *pdp, const INDEX iMirrorLevel, DepthInfo *pdi, const INDEX ctCount) { const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI; ASSERT(GfxValidApi(eAPI)); ASSERT( pdp!=NULL && ctCount>0); const CRaster *pra = pdp->dp_Raster; // OpenGL if( eAPI==GAT_OGL) { _sfStats.StartTimer(CStatForm::STI_GFXAPI); FLOAT fPointOoK; // for each stored point for( INDEX idi=0; idi<ctCount; idi++) { DepthInfo &di = pdi[idi]; // skip if not in required mirror level or was already checked in this iteration if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest) continue; const PIX pixJ = pra->ra_Height-1 - di.di_pixJ; // OpenGL has Y-inversed buffer! pglReadPixels( di.di_pixI, pixJ, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &fPointOoK); OGL_CHECKERROR; // it is visible if there is nothing nearer in z-buffer already di.di_bVisible = (di.di_fOoK<fPointOoK); } // done _sfStats.StopTimer(CStatForm::STI_GFXAPI); return; } // Direct3D #ifdef SE1_D3D if( eAPI==GAT_D3D) { _sfStats.StartTimer(CStatForm::STI_GFXAPI); // ok, this will get really complicated ... // We'll have to do it thru back buffer because darn DX8 won't let us have values from z-buffer; // Anyway, we'll lock backbuffer, read color from the lens location and try to write little triangle there // with slightly modified color. Then we'll readout that color and see if triangle passes z-test. Voila! :) // P.S. To avoid lock-modify-lock, we need to batch all the locks in one. Uhhhh ... :( COLOR col; INDEX idi; SLONG slColSize; HRESULT hr; D3DLOCKED_RECT rectLocked; D3DSURFACE_DESC surfDesc; LPDIRECT3DSURFACE8 pBackBuffer; // fetch back buffer (different for full screen and windowed mode) const BOOL bFullScreen = _pGfx->gl_ulFlags & GLF_FULLSCREEN; if( bFullScreen) { hr = _pGfx->gl_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); } else { hr = pra->ra_pvpViewPort->vp_pSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); } // what, cannot get a back buffer? if( hr!=D3D_OK) { // to hell with it all _sfStats.StopTimer(CStatForm::STI_GFXAPI); return; } // keep format of back-buffer pBackBuffer->GetDesc(&surfDesc); const D3DFORMAT d3dfBack = surfDesc.Format; // prepare array that'll back-buffer colors from depth point locations _acolDelayed.Push(ctCount); // store all colors for( idi=0; idi<ctCount; idi++) { DepthInfo &di = pdi[idi]; // skip if not in required mirror level or was already checked in this iteration if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest) continue; // fetch pixel _acolDelayed[idi] = 0; const RECT rectToLock = { di.di_pixI, di.di_pixJ, di.di_pixI+1, di.di_pixJ+1 }; hr = pBackBuffer->LockRect( &rectLocked, &rectToLock, D3DLOCK_READONLY); if( hr!=D3D_OK) continue; // skip if lock didn't make it // read, convert and store original color _acolDelayed[idi] = UnpackColor_D3D( (UBYTE*)rectLocked.pBits, d3dfBack, slColSize) | CT_OPAQUE; pBackBuffer->UnlockRect(); } // prepare to draw little triangles there with slightly adjusted colors _sfStats.StopTimer(CStatForm::STI_GFXAPI); gfxEnableDepthTest(); gfxDisableDepthWrite(); gfxDisableBlend(); gfxDisableAlphaTest(); gfxDisableTexture(); _sfStats.StartTimer(CStatForm::STI_GFXAPI); // prepare array and shader _avtxDelayed.Push(ctCount*3); d3dSetVertexShader(D3DFVF_CTVERTEX); // draw one trianle around each depth point INDEX ctVertex = 0; for( idi=0; idi<ctCount; idi++) { DepthInfo &di = pdi[idi]; col = _acolDelayed[idi]; // skip if not in required mirror level or was already checked in this iteration, or wasn't fetched at all if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest || col==0) continue; const ULONG d3dCol = rgba2argb(col^0x20103000); const PIX pixI = di.di_pixI - pdp->dp_MinI; // convert raster loc to drawport loc const PIX pixJ = di.di_pixJ - pdp->dp_MinJ; // batch it and advance to next triangle CTVERTEX &vtx0 = _avtxDelayed[ctVertex++]; CTVERTEX &vtx1 = _avtxDelayed[ctVertex++]; CTVERTEX &vtx2 = _avtxDelayed[ctVertex++]; vtx0.fX=pixI; vtx0.fY=pixJ-2; vtx0.fZ=di.di_fOoK; vtx0.ulColor=d3dCol; vtx0.fU=vtx0.fV=0; vtx1.fX=pixI-2; vtx1.fY=pixJ+2; vtx1.fZ=di.di_fOoK; vtx1.ulColor=d3dCol; vtx1.fU=vtx0.fV=0; vtx2.fX=pixI+2; vtx2.fY=pixJ; vtx2.fZ=di.di_fOoK; vtx2.ulColor=d3dCol; vtx2.fU=vtx0.fV=0; } // draw a bunch hr = _pGfx->gl_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, ctVertex/3, &_avtxDelayed[0], sizeof(CTVERTEX)); D3D_CHECKERROR(hr); // readout colors again and compare to old ones for( idi=0; idi<ctCount; idi++) { DepthInfo &di = pdi[idi]; col = _acolDelayed[idi]; // skip if not in required mirror level or was already checked in this iteration, or wasn't fetched at all if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest || col==0) continue; // fetch pixel const RECT rectToLock = { di.di_pixI, di.di_pixJ, di.di_pixI+1, di.di_pixJ+1 }; hr = pBackBuffer->LockRect( &rectLocked, &rectToLock, D3DLOCK_READONLY); if( hr!=D3D_OK) continue; // skip if lock didn't make it // read new color const COLOR colNew = UnpackColor_D3D( (UBYTE*)rectLocked.pBits, d3dfBack, slColSize) | CT_OPAQUE; pBackBuffer->UnlockRect(); // if we managed to write adjusted color, point is visible! di.di_bVisible = (col!=colNew); } // phew, done! :) D3DRELEASE( pBackBuffer, TRUE); _acolDelayed.PopAll(); _avtxDelayed.PopAll(); _sfStats.StopTimer(CStatForm::STI_GFXAPI); return; } #endif // SE1_D3D }
// upload context for current texture to accelerator's memory // (returns format in which texture was really uploaded) extern void UploadTexture_D3D( LPDIRECT3DTEXTURE8 *ppd3dTexture, ULONG *pulTexture, PIX pixSizeU, PIX pixSizeV, D3DFORMAT eInternalFormat, BOOL bDiscard) { // safeties ASSERT( pulTexture!=NULL); ASSERT( pixSizeU>0 && pixSizeV>0); _sfStats.StartTimer( CStatForm::STI_BINDTEXTURE); _pfGfxProfile.StartTimer( CGfxProfile::PTI_TEXTUREUPLOADING); // recreate texture if needed HRESULT hr; if( bDiscard) { if( (*ppd3dTexture)!=NULL) D3DRELEASE( (*ppd3dTexture), TRUE); hr = _pGfx->gl_pd3dDevice->CreateTexture( pixSizeU, pixSizeV, 0, 0, eInternalFormat, D3DPOOL_MANAGED, ppd3dTexture); D3D_CHECKERROR(hr); } // D3D texture must be valid now LPDIRECT3DTEXTURE8 pd3dTex = (*ppd3dTexture); ASSERT( pd3dTex!=NULL); // prepare routine for conversion SetInternalFormat_D3D(eInternalFormat); // upload each mipmap INDEX iMip=0; PIX pixOffset=0; while( pixSizeU>0 && pixSizeV>0) { // check that memory is readable and upload one mipmap ASSERT( pulTexture[pixOffset +pixSizeU*pixSizeV -1] != 0xDEADBEEF); UploadMipmap_D3D( pulTexture+pixOffset, pd3dTex, pixSizeU, pixSizeV, iMip); // advance to next mip-map pixOffset += pixSizeU*pixSizeV; pixSizeU >>=1; pixSizeV >>=1; iMip++; // end here if there is only one mip-map to upload if( _tpCurrent->tp_bSingleMipmap) break; } // see if we need to generate and upload additional mipmaps (those under 1*N or N*1) if( !_tpCurrent->tp_bSingleMipmap && pixSizeU!=pixSizeV) { // prepare variables PIX pixSize = Max(pixSizeU,pixSizeV); ASSERT( pixSize<=2048); ULONG *pulSrc = pulTexture+pixOffset-pixSize*2; ULONG *pulDst = _aulLastMipmaps; // loop thru mipmaps while( pixSizeU>0 || pixSizeV>0) { // make next mipmap if( pixSizeU==0) pixSizeU=1; if( pixSizeV==0) pixSizeV=1; pixSize = pixSizeU*pixSizeV; __asm { pxor mm0,mm0 mov esi,D [pulSrc] mov edi,D [pulDst] mov ecx,D [pixSize] pixLoop: movd mm1,D [esi+0] movd mm2,D [esi+4] punpcklbw mm1,mm0 punpcklbw mm2,mm0 paddw mm1,mm2 psrlw mm1,1 packuswb mm1,mm0 movd D [edi],mm1 add esi,4*2 add edi,4 dec ecx jnz pixLoop emms } // upload mipmap and advance UploadMipmap_D3D( pulDst, pd3dTex, pixSizeU, pixSizeV, iMip); pulSrc = pulDst; pulDst += pixSize; pixOffset += pixSize; pixSizeU >>=1; pixSizeV >>=1; iMip++; } }