// Render one tile in wireframe mode static void RenderWireTile(INDEX itt) { ASSERT(_ptrTerrain!=NULL); CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt]; INDEX ctVertices = tt.GetVertices().Count(); GFXVertex4 *pavVertices; if(ter_bLerpVertices) { PrepareSmothVertices(itt); pavVertices = &_avLerpedVerices[0]; } else { pavVertices = &tt.GetVertices()[0]; } INDEX ctIndices = tt.GetIndices().Count(); if(ctIndices>0) { gfxDisableBlend(); gfxDisableTexture(); gfxSetConstantColor(_colTerrainEdges); gfxSetVertexArray(pavVertices,ctVertices); gfxLockArrays(); gfxDrawElements(ctIndices,&tt.GetIndices()[0]); gfxUnlockArrays(); } }
// Prepare scene for terrain rendering void PrepareScene(CAnyProjection3D &apr, CDrawPort *pdp, CTerrain *ptrTerrain) { ASSERT(ptrTerrain!=NULL); ASSERT(ptrTerrain->tr_penEntity!=NULL); // Set current terrain _ptrTerrain = ptrTerrain; // Set drawport _pdp = pdp; // Prepare and set the projection apr->ObjectPlacementL() = CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0)); apr->Prepare(); _aprProjection = apr; _pdp->SetProjection( _aprProjection); CEntity *pen = ptrTerrain->tr_penEntity; // calculate projection of viewer in absolute space const FLOATmatrix3D &mViewer = _aprProjection->pr_ViewerRotationMatrix; _vViewer(1) = -mViewer(3,1); _vViewer(2) = -mViewer(3,2); _vViewer(3) = -mViewer(3,3); // calculate projection of viewer in object space _vViewerObj = _vViewer * !pen->en_mRotation; const CPlacement3D &plTerrain = pen->GetLerpedPlacement(); _mObjectToView = mViewer * pen->en_mRotation; _vObjectToView = (plTerrain.pl_PositionVector - _aprProjection->pr_vViewerPosition) * mViewer; // make transform matrix const FLOATmatrix3D &m = _mObjectToView; const FLOAT3D &v = _vObjectToView; FLOAT glm[16]; glm[0] = m(1,1); glm[4] = m(1,2); glm[ 8] = m(1,3); glm[12] = v(1); glm[1] = m(2,1); glm[5] = m(2,2); glm[ 9] = m(2,3); glm[13] = v(2); glm[2] = m(3,1); glm[6] = m(3,2); glm[10] = m(3,3); glm[14] = v(3); glm[3] = 0; glm[7] = 0; glm[11] = 0; glm[15] = 1; gfxSetViewMatrix(glm); // Get viewer in absolute space _vViewerAbs = (_aprProjection->ViewerPlacementR().pl_PositionVector - pen->en_plPlacement.pl_PositionVector) * !pen->en_mRotation; gfxDisableBlend(); gfxDisableTexture(); gfxDisableAlphaTest(); gfxEnableDepthTest(); gfxEnableDepthWrite(); gfxCullFace(GFX_BACK); }
// Draw terrain quad tree void DrawQuadTree(void) { ASSERT(_ptrTerrain!=NULL); QuadTreeLevel &qtl = _ptrTerrain->tr_aqtlQuadTreeLevels[0]; gfxDisableTexture(); // for each quad tree node for(INDEX iqtn=qtl.qtl_iFirstNode;iqtn<qtl.qtl_iFirstNode+qtl.qtl_ctNodes;iqtn++) { // draw node QuadTreeNode &qtn = _ptrTerrain->tr_aqtnQuadTreeNodes[iqtn]; gfxDrawWireBox(qtn.qtn_aabbox,0x00FF00FF); } }
// Set current texture index void shaSetTexture(INDEX iTextureIndex) { if(_paTextures==NULL || iTextureIndex<0 || iTextureIndex>=_ctTextures || _paTextures[iTextureIndex] == NULL) { gfxDisableTexture(); return; } ASSERT(iTextureIndex<_ctTextures); CTextureObject *pto = _paTextures[iTextureIndex]; ASSERT(pto!=NULL); CTextureData *pTextureData = (CTextureData*)pto->GetData(); const INDEX iFrameNo = pto->GetFrame(); pTextureData->SetAsCurrent(iFrameNo); }
// render bounding box static void RenderWireframeBox( FLOAT3D vMinVtx, FLOAT3D vMaxVtx, COLOR col) { // only for OpenGL (for now) if( _pGfx->gl_eCurrentAPI!=GAT_OGL) return; // prepare wireframe OpenGL settings gfxDisableDepthTest(); gfxDisableDepthWrite(); gfxDisableBlend(); gfxDisableAlphaTest(); gfxDisableTexture(); // fill vertex array so it represents bounding box FLOAT3D vBoxVtxs[8]; vBoxVtxs[0] = FLOAT3D( vMinVtx(1), vMinVtx(2), vMinVtx(3)); vBoxVtxs[1] = FLOAT3D( vMaxVtx(1), vMinVtx(2), vMinVtx(3)); vBoxVtxs[2] = FLOAT3D( vMaxVtx(1), vMinVtx(2), vMaxVtx(3)); vBoxVtxs[3] = FLOAT3D( vMinVtx(1), vMinVtx(2), vMaxVtx(3)); vBoxVtxs[4] = FLOAT3D( vMinVtx(1), vMaxVtx(2), vMinVtx(3)); vBoxVtxs[5] = FLOAT3D( vMaxVtx(1), vMaxVtx(2), vMinVtx(3)); vBoxVtxs[6] = FLOAT3D( vMaxVtx(1), vMaxVtx(2), vMaxVtx(3)); vBoxVtxs[7] = FLOAT3D( vMinVtx(1), vMaxVtx(2), vMaxVtx(3)); // connect vertices into lines of bounding box INDEX iBoxLines[12][2]; iBoxLines[ 0][0] = 0; iBoxLines[ 0][1] = 1; iBoxLines[ 1][0] = 1; iBoxLines[ 1][1] = 2; iBoxLines[ 2][0] = 2; iBoxLines[ 2][1] = 3; iBoxLines[ 3][0] = 3; iBoxLines[ 3][1] = 0; iBoxLines[ 4][0] = 0; iBoxLines[ 4][1] = 4; iBoxLines[ 5][0] = 1; iBoxLines[ 5][1] = 5; iBoxLines[ 6][0] = 2; iBoxLines[ 6][1] = 6; iBoxLines[ 7][0] = 3; iBoxLines[ 7][1] = 7; iBoxLines[ 8][0] = 4; iBoxLines[ 8][1] = 5; iBoxLines[ 9][0] = 5; iBoxLines[ 9][1] = 6; iBoxLines[10][0] = 6; iBoxLines[10][1] = 7; iBoxLines[11][0] = 7; iBoxLines[11][1] = 4; // for all vertices in bounding box glCOLOR(col); pglBegin( GL_LINES); for( INDEX i=0; i<12; i++) { // get starting and ending vertices of one line FLOAT3D &v0 = vBoxVtxs[iBoxLines[i][0]]; FLOAT3D &v1 = vBoxVtxs[iBoxLines[i][1]]; pglVertex3f( v0(1), v0(2), v0(3)); pglVertex3f( v1(1), v1(2), v1(3)); } pglEnd(); OGL_CHECKERROR; }
// fill rate benchmark static DOUBLE FillRatePass(INDEX ct) { if( !_pdp->Lock()) { ASSERT(FALSE); return 0.0; } StartTimer(); _pdp->Fill(C_GRAY|255); _pdp->FillZBuffer(1.0f); GFXVertex avtx[4]; avtx[0].x = 0; avtx[0].y = 0; avtx[0].z = 0.5f; avtx[1].x = 0; avtx[1].y = _pixSizeJ; avtx[1].z = 0.5f; avtx[2].x = _pixSizeI; avtx[2].y = _pixSizeJ; avtx[2].z = 0.5f; avtx[3].x = _pixSizeI; avtx[3].y = 0; avtx[3].z = 0.5f; GFXTexCoord atex[4] = { {0,0}, {0,1}, {1,1}, {1,0} }; GFXColor acol[4] = { 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFF00FF }; INDEX_T aidx[6] = { 0,1,2, 0,2,3}; gfxSetVertexArray( &avtx[0], 4); gfxSetTexCoordArray( &atex[0], FALSE); gfxSetColorArray( &acol[0]); if(_bTexture) { gfxEnableTexture(); if(_bMultiTexture) { gfxSetTextureUnit(1); gfxEnableTexture(); gfxSetTexture( _ulTexObject, _tpLocal); gfxSetTexCoordArray(atex, FALSE); gfxSetTextureUnit(0); } } else { gfxDisableTexture(); } if(_bBlend) { gfxEnableBlend(); if(_bTexture) { gfxBlendFunc( GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA); } else { gfxBlendFunc( GFX_ONE, GFX_ONE); } } else { gfxDisableBlend(); } if(_bDepth) { gfxEnableDepthTest(); gfxEnableDepthWrite(); } else { gfxDisableDepthTest(); gfxDisableDepthWrite(); } gfxDisableAlphaTest(); for( INDEX i=0; i<ct; i++) gfxDrawElements( 6, &aidx[0]); if(_bMultiTexture) { gfxSetTextureUnit(1); gfxDisableTexture(); gfxSetTextureUnit(0); } _pdp->Unlock(); gfxFinish(); _pvp->SwapBuffers(); return StopTimer(); }
static DOUBLE TrisTroughputPass(INDEX ct) { if( !_pdp->Lock()) { ASSERT(FALSE); return 0.0; } StartTimer(); gfxSetFrustum( -0.5f, +0.5f, -0.5f, +0.5f, 0.5f, 2.0f); gfxSetViewMatrix(NULL); gfxCullFace(GFX_NONE); _pdp->Fill(C_GRAY|255); _pdp->FillZBuffer(1.0f); if(_bTexture) { gfxEnableTexture(); } else { gfxDisableTexture(); } if(_bBlend) { gfxEnableBlend(); gfxBlendFunc( GFX_ONE, GFX_ONE); } else { gfxDisableBlend(); } if(_bDepth) { gfxEnableDepthTest(); gfxEnableDepthWrite(); } else { gfxDisableDepthTest(); gfxDisableDepthWrite(); } gfxDisableAlphaTest(); gfxSetVertexArray( &_avtx[0], _avtx.Count()); gfxLockArrays(); gfxSetTexCoordArray( &_atex[0], FALSE); gfxSetColorArray( &_acol[0]); if(_bMultiTexture) { gfxSetTextureUnit(1); gfxEnableTexture(); gfxSetTexture( _ulTexObject, _tpLocal); gfxSetTexCoordArray( &_atex[0], FALSE); gfxSetTextureUnit(0); } for( INDEX i=0; i<ct; i++) gfxDrawElements( _aiElements.Count(), &_aiElements[0]); gfxUnlockArrays(); if(_bMultiTexture) { gfxSetTextureUnit(1); gfxDisableTexture(); gfxSetTextureUnit(0); } _pdp->Unlock(); gfxFinish(); _pvp->SwapBuffers(); return StopTimer(); }
void ShowSelectionInternal(CTerrain *ptrTerrain, Rect &rcExtract, CTextureData *ptdBrush, GFXColor colSelection, FLOAT fStrenght, SelectionFill sfFill) { ASSERT(ptrTerrain!=NULL); ASSERT(ptdBrush!=NULL); Rect rcSelection; FLOATaabbox3D bboxSelection; // Clamp rect used for extraction rcSelection.rc_iLeft = Clamp(rcExtract.rc_iLeft , 0, ptrTerrain->tr_pixHeightMapWidth); rcSelection.rc_iTop = Clamp(rcExtract.rc_iTop , 0, ptrTerrain->tr_pixHeightMapHeight); rcSelection.rc_iRight = Clamp(rcExtract.rc_iRight , 0, ptrTerrain->tr_pixHeightMapWidth); rcSelection.rc_iBottom = Clamp(rcExtract.rc_iBottom , 0, ptrTerrain->tr_pixHeightMapHeight); // Prepare box for vertex selection bboxSelection = FLOAT3D(rcSelection.rc_iLeft, 0, rcSelection.rc_iTop); bboxSelection |= FLOAT3D(rcSelection.rc_iRight, 0, rcSelection.rc_iBottom); // Stretch selection box bboxSelection.minvect(1) *= ptrTerrain->tr_vStretch(1); bboxSelection.minvect(3) *= ptrTerrain->tr_vStretch(3); bboxSelection.maxvect(1) *= ptrTerrain->tr_vStretch(1); bboxSelection.maxvect(3) *= ptrTerrain->tr_vStretch(3); // Set selection box height FLOATaabbox3D bboxAllTerrain; ptrTerrain->GetAllTerrainBBox(bboxAllTerrain); bboxSelection.minvect(2) = bboxAllTerrain.minvect(2); bboxSelection.maxvect(2) = bboxAllTerrain.maxvect(2); GFXVertex *pavVertices; INDEX *paiIndices; INDEX ctVertices; INDEX ctIndices; // Extract vertices in selection rect ExtractVerticesInRect(ptrTerrain, rcSelection, &pavVertices, &paiIndices, ctVertices, ctIndices); if(ctVertices!=rcSelection.Width()*rcSelection.Height()) { ASSERT(FALSE); return; } // if no vertices if(ctVertices==0) { return; } // Prepare vertex colors for selection preview PIX pixWidth = rcSelection.Width(); PIX pixHeight = rcSelection.Height(); INDEX iStepX = ptdBrush->GetWidth() - pixWidth; INDEX iFirst = 0; if(rcExtract.rc_iTop<0) { iFirst += -rcExtract.rc_iTop*ptdBrush->GetWidth(); } if(rcExtract.rc_iLeft<0) { iFirst += -rcExtract.rc_iLeft; } _aiExtColors.Push(ctVertices); GFXColor *pacolColor = (GFXColor*)&_aiExtColors[0]; GFXColor *pacolBrush = (GFXColor*)&ptdBrush->td_pulFrames[iFirst]; // Fill vertex colors for selection preview SLONG slStrength = (SLONG) (Clamp(Abs(fStrenght),0.0f,1.0f) * 256.0f); // for each row for(INDEX iy=0;iy<pixHeight;iy++) { // for each col for(INDEX ix=0;ix<pixWidth;ix++) { pacolColor->ul.abgr = colSelection.ul.abgr; pacolColor->ub.a = (pacolBrush->ub.r*slStrength)>>8; pacolColor++; pacolBrush++; } pacolBrush+=iStepX; } // Render selected polygons for selection preview if(sfFill == SF_WIREFRAME) { gfxPolygonMode(GFX_LINE); gfxEnableDepthBias(); } if(sfFill != SF_POINTS) { // Draw selection gfxDisableTexture(); gfxDisableAlphaTest(); gfxEnableBlend(); gfxBlendFunc(GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA); gfxSetVertexArray(pavVertices,ctVertices); gfxSetColorArray(&_aiExtColors[0]); gfxLockArrays(); gfxDrawElements(ctIndices,paiIndices); gfxUnlockArrays(); gfxDisableBlend(); } if(sfFill == SF_WIREFRAME) { gfxDisableDepthBias(); gfxPolygonMode(GFX_FILL); } if(sfFill == SF_POINTS) { DrawSelectedVertices(pavVertices,&_aiExtColors[0],ctVertices); } }
// 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 }