// Draw all tiles that are in lowest lod static void RenderBatchedTiles(void) { // Set texture wrapping gfxSetTextureWrapping(GFX_CLAMP,GFX_CLAMP); // Use terrains global top map as texture _ptrTerrain->tr_tdTopMap.SetAsCurrent(); GFXVertex4 *pavVertices = &_avDelayedVertices[0]; GFXTexCoord *pauvTexCoords = &_auvDelayedTexCoords[0]; GFXTexCoord *pauvShadowMapTC = &_auvDelayedShadowMapTC[0]; INDEX *paiIndices = &_aiDelayedIndices[0]; INDEX ctVertices = _avDelayedVertices.Count(); INDEX ctIndices = _aiDelayedIndices.Count(); // Prepare white color array FillConstColorArray(ctVertices); GFXColor *pacolColors = &_acolVtxConstColors[0]; gfxEnableAlphaTest(); gfxDisableBlend(); gfxSetVertexArray(pavVertices,ctVertices); gfxSetTexCoordArray(pauvTexCoords, FALSE); gfxSetColorArray(pacolColors); gfxLockArrays(); gfxDrawElements(ctIndices,paiIndices); gfxDisableAlphaTest(); _ctTris +=ctIndices/2; // if shadows are visible if(_wrpWorldRenderPrefs.wrp_shtShadows!=CWorldRenderPrefs::SHT_NONE) { gfxDepthFunc(GFX_EQUAL); gfxBlendFunc(GFX_DST_COLOR,GFX_SRC_COLOR); gfxEnableBlend(); gfxSetTexCoordArray(pauvShadowMapTC, FALSE); _ptrTerrain->tr_tdShadowMap.SetAsCurrent(); gfxDrawElements(ctIndices,paiIndices); gfxDepthFunc(GFX_LESS_EQUAL); } if(_ptrTerrain->GetFlags()&TR_HAS_FOG) { RenderFogLayer(-1); } if(_ptrTerrain->GetFlags()&TR_HAS_HAZE) { RenderHazeLayer(-1); } gfxUnlockArrays(); // Popall delayed arrays _avDelayedVertices.PopAll(); _auvDelayedTexCoords.PopAll(); _auvDelayedShadowMapTC.PopAll(); _aiDelayedIndices.PopAll(); }
static void RenderHazeLayer(INDEX itt) { FLOAT3D vObjPosition = _ptrTerrain->tr_penEntity->en_plPlacement.pl_PositionVector; _fHazeAdd = -_haze_hp.hp_fNear; _fHazeAdd += _vViewer(1) * (vObjPosition(1) - _aprProjection->pr_vViewerPosition(1)); _fHazeAdd += _vViewer(2) * (vObjPosition(2) - _aprProjection->pr_vViewerPosition(2)); _fHazeAdd += _vViewer(3) * (vObjPosition(3) - _aprProjection->pr_vViewerPosition(3)); GFXVertex *pvVtx; INDEX *piIndices; INDEX ctVertices; INDEX ctIndices; // if this is tile if(itt>=0) { CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt]; pvVtx = &tt.GetVertices()[0]; piIndices = &tt.GetIndices()[0]; ctVertices = tt.GetVertices().Count(); ctIndices = tt.GetIndices().Count(); // else this are batched tiles } else { pvVtx = &_avDelayedVertices[0]; piIndices = &_aiDelayedIndices[0]; ctVertices = _avDelayedVertices.Count(); ctIndices = _aiDelayedIndices.Count(); } GFXTexCoord *pfHazeTC = _atcHaze.Push(ctVertices); GFXColor *pcolHaze = _acolHaze.Push(ctVertices); const COLOR colH = AdjustColor( _haze_hp.hp_colColor, _slTexHueShift, _slTexSaturation); GFXColor colHaze(colH); // for each vertex in tile for(INDEX ivx=0;ivx<ctVertices;ivx++) { GetHazeMapInVertex(pvVtx[ivx],pfHazeTC[ivx]); pcolHaze[ivx] = colHaze; } // render haze layer gfxDepthFunc(GFX_EQUAL); gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP); gfxSetTexture( _haze_ulTexture, _haze_tpLocal); gfxSetTexCoordArray(pfHazeTC, FALSE); gfxSetColorArray(pcolHaze); gfxBlendFunc( GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA); gfxEnableBlend(); gfxDrawElements(ctIndices,piIndices); gfxDepthFunc(GFX_LESS_EQUAL); _atcHaze.PopAll(); _acolHaze.PopAll(); }
// Get empty color array for modifying GFXColor *shaGetNewColorArray(void) { ASSERT(_ctVertices!=0); _acolVtxModifyColors.PopAll(); _acolVtxModifyColors.Push(_ctVertices); return &_acolVtxModifyColors[0]; }
// Get empty texcoords array for modifying GFXTexCoord *shaGetNewTexCoordArray(void) { ASSERT(_ctVertices!=0); _uvUVMapForModify.PopAll(); _uvUVMapForModify.Push(_ctVertices); return &_uvUVMapForModify[0]; }
// Get empty vertex array for modifying GFXVertex *shaGetNewVertexArray(void) { ASSERT(_ctVertices!=0); _vModifyVertices.PopAll(); _vModifyVertices.Push(_ctVertices); return &_vModifyVertices[0]; }
// make array of entity offsets in a block void MakeInfos(CStaticStackArray<EntityBlockInfo> &aebi, UBYTE *pubBlock, SLONG slSize, UBYTE *pubFirst, UBYTE *&pubEnd) { // clear all offsets aebi.PopAll(); // until end of block UBYTE *pub = pubFirst; while (pub<pubBlock+slSize) { // if no more entities if (*(ULONG*)pub != ENT4) { pubEnd = pub; // stop return; } // remember it EntityBlockInfo &ebi = aebi.Push(); ebi.ebi_slOffset = pub-pubBlock; pub+=sizeof(ULONG); // get id and size ULONG ulID = *(ULONG*)pub; ebi.ebi_ulID = ulID; pub+=sizeof(ULONG); SLONG slSizeChunk = *(SLONG*)pub; pub+=sizeof(ULONG); ebi.ebi_slSize = slSizeChunk+sizeof(SLONG)*3; pub+=slSizeChunk; } }
// turn credits on void Credits_On(INDEX iType) { if (_bCreditsOn) { Credits_Off(); } _astrCredits.PopAll(); if (iType==1) { _fSpeed = 1.0f; LoadOneFile(CTFILENAME("Data\\Intro.txt")); } else if (iType==2) { _fSpeed = 2.0f; LoadOneFile(CTFILENAME("Data\\Credits.txt")); LoadOneFile(CTFILENAME("Data\\Credits_End.txt")); } else { _fSpeed = 2.0f; #if _SE_DEMO || TECHTESTONLY LoadOneFile(CTFILENAME("Data\\Credits_Demo.txt")); #else LoadOneFile(CTFILENAME("Data\\Credits.txt")); #endif } // if some file was loaded if (_bCreditsOn) { // remember start time if (iType==1 || iType==2) { _bUseRealTime = FALSE; _tmStart = _pTimer->GetLerpedCurrentTick(); } else { _bUseRealTime = TRUE; _tvStart = _pTimer->GetHighPrecisionTimer(); } } }
void CCastRay::ClearSectorList(void) { // for each active sector for(INDEX ias=0; ias<_aas.Count(); ias++) { // mark it as inactive _aas[ias].as_pbsc->bsc_ulFlags&=~BSCF_RAYTESTED; } _aas.PopAll(); }
static void FillConstColorArray(INDEX ctVertices) { INDEX ctColors=_acolVtxConstColors.Count(); _acolVtxConstColors.PopAll(); _acolVtxConstColors.Push(ctVertices); // if requested array is larger then existing one if(ctVertices>ctColors) { memset(&_acolVtxConstColors[ctColors],255,(ctVertices-ctColors)*sizeof(GFXColor)); } }
// Clean all values void shaClean(void) { _ctVertices = -1; _ctIndices = -1; _ctColors = -1; _ctTextures = -1; _ctUVMaps = -1; _ctLights = -1; _colConstant = 0; _ulFlags = 0; _pShader = NULL; _paVertices = NULL; _paNormals = NULL; _paIndices = NULL; _paUVMaps = NULL; _paTextures = NULL; _paColors = NULL; _paFloats = NULL; _pCurrentUVMap = NULL; _pcolVtxColors = NULL; _paFogUVMap = NULL; _paHazeUVMap = NULL; _pacolVtxHaze = NULL; _pmObjToView = NULL; _pmObjToAbs = NULL; _paprProjection = NULL; _acolVtxColors.PopAll(); _acolVtxModifyColors.PopAll(); _vModifyVertices.PopAll(); _uvUVMapForModify.PopAll(); shaCullFace(GFX_BACK); }
// check all delayed depth points extern void CheckDelayedDepthPoints( const CDrawPort *pdp, INDEX iMirrorLevel/*=0*/) { // skip if not delayed or mirror level is to high gap_iOptimizeDepthReads = Clamp( gap_iOptimizeDepthReads, 0L, 2L); if( gap_iOptimizeDepthReads==0 || iMirrorLevel>7) return; ASSERT( pdp!=NULL && iMirrorLevel>=0); // check only if time lapse allows const CTimerValue tvNow = _pTimer->GetHighPrecisionTimer(); const TIME tmDelta = (tvNow-_tvLast[iMirrorLevel]).GetSeconds(); ASSERT( tmDelta>=0); if( gap_iOptimizeDepthReads==2 && tmDelta<0.1f) return; // prepare _tvLast[iMirrorLevel] = tvNow; INDEX ctPoints = _adiDelayed.Count(); if( ctPoints==0) return; // done if no points in queue // for each point INDEX iPoint = 0; while( iPoint<ctPoints) { DepthInfo &di = _adiDelayed[iPoint]; // if the point is not active any more if( iMirrorLevel==di.di_iMirrorLevel && di.di_iSwapLastRequest<_iCheckIteration-KEEP_BEHIND) { // delete it by moving the last one on its place di = _adiDelayed[ctPoints-1]; ctPoints--; // if the point is still active } else { // go to next point iPoint++; } } // remove unused points at the end if( ctPoints==0) _adiDelayed.PopAll(); else _adiDelayed.PopUntil(ctPoints-1); // ignore stalls if( tmDelta>1.0f) return; // check and update visibility of what has left ASSERT( ctPoints == _adiDelayed.Count()); if( ctPoints>0) UpdateDepthPointsVisibility( pdp, iMirrorLevel, &_adiDelayed[0], ctPoints); // mark checking _iCheckIteration++; }
// Calculate lightning for given model void shaCalculateLightForSpecular(void) { ASSERT(_paNormals!=NULL); _acolVtxColors.PopAll(); _acolVtxColors.Push(_ctVertices); GFXColor colModel = (GFXColor)_colModel; // Model color GFXColor &colAmbient = (GFXColor)_colAmbient; // Ambient color GFXColor &colLight = (GFXColor)_colLight; // Light color GFXColor &colSurface = (GFXColor)_colConstant; // shader color // colModel = MulColors(colModel.r,colSurface.abgr); colModel.MultiplyRGBA(colModel,colSurface); UBYTE ubColShift = 8; SLONG slar = colAmbient.r; SLONG slag = colAmbient.g; SLONG slab = colAmbient.b; if(shaOverBrightningEnabled()) { slar = ClampUp(slar,127L); slag = ClampUp(slag,127L); slab = ClampUp(slab,127L); ubColShift = 8; } else { slar*=2; slag*=2; slab*=2; ubColShift = 7; } // for each vertex color for(INDEX ivx=0;ivx<_ctVertices;ivx++) { // calculate vertex light FLOAT3D &vNorm = FLOAT3D(_paNormals[ivx].nx,_paNormals[ivx].ny,_paNormals[ivx].nz); FLOAT fDot = vNorm % _vLightDir; fDot = Clamp(fDot,0.0f,1.0f); SLONG slDot = NormFloatToByte(fDot); _acolVtxColors[ivx].r = ClampUp(colModel.r * (slar + ((colLight.r * slDot)>>ubColShift))>>8,255L); _acolVtxColors[ivx].g = ClampUp(colModel.g * (slag + ((colLight.g * slDot)>>ubColShift))>>8,255L); _acolVtxColors[ivx].b = ClampUp(colModel.b * (slab + ((colLight.b * slDot)>>ubColShift))>>8,255L); _acolVtxColors[ivx].a = slDot;//colModel.a;//slDot; } // Set current wertex array _pcolVtxColors = &_acolVtxColors[0]; }
CRenderModel::~CRenderModel(void) { if( !(rm_ulFlags&RMF_ATTACHMENT)) _armRenderModels.PopAll(); }
void PrepareSmothVertices(INDEX itt) { CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt]; const INDEX ctVertices = tt.GetVertices().Count(); const FLOAT &fLerpFactor = tt.tt_fLodLerpFactor; // Allocate memory for all vertices _avLerpedVerices.PopAll(); _avLerpedVerices.Push(ctVertices); // Get pointers to src and dst vertex arrays GFXVertex *pavSrcFirst = &tt.GetVertices()[0]; GFXVertex *pavDstFirst = &_avLerpedVerices[0]; GFXVertex *pavSrc = &pavSrcFirst[0]; GFXVertex *pavDst = &pavDstFirst[0]; INDEX iFacing=0; // for each vertex column for(INDEX iy=0;iy<tt.tt_ctLodVtxY;iy++) { // for each vertex in row in even column step by 2 for(INDEX ix=0;ix<tt.tt_ctLodVtxX-2;ix+=2) { // Copy first vertex pavDst[0] = pavSrc[0]; // Second vertex is lerped between left and right vertices Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor); // Increment vertex pointers pavDst+=2; pavSrc+=2; } // Copy last vertex in row pavDst[0] = pavSrc[0]; // Increment vertex pointers and go to odd column pavDst++; pavSrc++; iy++; // if this is not last row if(iy<tt.tt_ctLodVtxY) { // for each vertex in row in odd column step by 2 for(INDEX ix=0;ix<tt.tt_ctLodVtxX-2;ix+=2) { // First vertex is lerped between top and bottom vertices Lerp(pavDst[0],pavSrc[0],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX],fLerpFactor); // is this odd vertex in row #pragma message(">> Fix this") if(((ix+iy)/2)%2) { // if(iFacing&1) // Second vertex (diagonal one) is lerped between topright and bottom left vertices Lerp(pavDst[1],pavSrc[1],pavSrc[-tt.tt_ctLodVtxX+2],pavSrc[tt.tt_ctLodVtxX],fLerpFactor); } else { // Second vertex (diagonal one) is lerped between topleft and bottom right vertices Lerp(pavDst[1],pavSrc[1],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX+2],fLerpFactor); } iFacing++; // Increment vertex pointers pavDst+=2; pavSrc+=2; } // Last vertex in row is lerped between top and bottom vertices (same as first in row) Lerp(pavDst[0],pavSrc[0],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX],fLerpFactor); } // Increment vertex pointers pavDst++; pavSrc++; } pavDst--; pavSrc--; /* // Copy border vertices GFXVertex *pvBorderDst = pavDst; GFXVertex *pvBorderSrc = pavSrc; for(INDEX ivx=tt.tt_ctNonBorderVertices;ivx<ctVertices;ivx++) { //*pavDst++ = *pavSrc++; pvBorderDst[0] = pvBorderSrc[0]; pvBorderDst++; pvBorderSrc++; } */ // Lerp top border vertices const INDEX &iTopNeigbour = tt.tt_aiNeighbours[NB_TOP]; // if top neighbour exists if(iTopNeigbour>=0) { CTerrainTile &ttTop = _ptrTerrain->tr_attTiles[iTopNeigbour]; const FLOAT &fLerpFactor = ttTop.tt_fLodLerpFactor; // Get source vertex pointer in top neighbour (vertex in bottom left corner of top neighbour) const INDEX iSrcVtx = ttTop.tt_ctLodVtxX * (ttTop.tt_ctLodVtxY-1); GFXVertex *pavSrc = &ttTop.GetVertices()[iSrcVtx]; // Calculate num of vertices that needs to be lerped const INDEX ctLerps = (ttTop.tt_ctLodVtxX-1)/2; // is top tile in same lod as this tile and has smaller or equal lerp factor if(tt.tt_iLod==ttTop.tt_iLod && fLerpFactor<=tt.tt_fLodLerpFactor) { // Get destination vertex pointer in this tile (first vertex in top left corner of this tile - first vertex in array) const INDEX iDstVtx = 0; GFXVertex *pavDst = &pavDstFirst[iDstVtx]; // for each vertex in bottom row of top tile that needs to be lerped for(INDEX ivx=0;ivx<ctLerps;ivx++) { // First vertex is same as in top tile pavDst[0] = pavSrc[0]; // Second vertex is lerped between left and right vertices Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor); pavDst+=2; pavSrc+=2; } // is top tile in higher lod } else if(tt.tt_iLod>ttTop.tt_iLod) { const INDEX iVtxDiff = (ttTop.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1); // Get destination vertex pointer to copy vertices from top neighbour (first vertex in top left corner of this tile - first vertex in array) // Get destination vertex pointer to lerp vertices from top neighbour (first vertex added as additional top border vertex) const INDEX iDstCopyVtx = 0; const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_TOP]; GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx]; GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx]; // if diference is in one lod if(iVtxDiff==2) { // for each vertex in bottom row of top tile that needs to be lerped for(INDEX ivx=0;ivx<ctLerps;ivx++) { // Copy src vertex in normal dst vertex array pavDstCopy[0] = pavSrc[0]; // Lerp left and right src vertices in border dst vertex Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor); pavDstLerp++; pavDstCopy++; pavSrc+=2; } // diference is more than one lod } else { INDEX ctbv = tt.tt_ctBorderVertices[NB_TOP]; INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex // for each border vertex for(INDEX ivx=0;ivx<ctbv;ivx+=2) { // Lerp left and right src vertices in border dst vertex Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor); // if this border vertex is not last in quad if(ivxInQuad!=iVtxDiff) { // Copy second border vertex pavDstLerp[1] = pavSrc[2]; pavDstLerp+=2; ivxInQuad+=2; // this is last border vertex } else { // Copy second non border vertex pavDstCopy[1] = pavSrc[2]; pavDstCopy++; // since this wasn't border vertex, fix border vertex loop counter ctbv++; pavDstLerp++; ivxInQuad=2; } pavSrc+=2; } } } } // Lerp bottom border vertices const INDEX &iBottomNeigbour = tt.tt_aiNeighbours[NB_BOTTOM]; // if bottom neighbour exists if(iBottomNeigbour>=0) { CTerrainTile &ttBottom = _ptrTerrain->tr_attTiles[iBottomNeigbour]; const FLOAT &fLerpFactor = ttBottom.tt_fLodLerpFactor; // Get source vertex pointer in bottom neighbour (vertex in top left corner of bottom neighbour - first vertex in array) const INDEX iSrcVtx = 0; GFXVertex *pavSrc = &ttBottom.GetVertices()[iSrcVtx]; // Calculate num of vertices that needs to be lerped const INDEX ctLerps = (ttBottom.tt_ctLodVtxX-1)/2; // is bottom tile in same lod as this tile and has smaller lerp factor if(tt.tt_iLod==ttBottom.tt_iLod && fLerpFactor<tt.tt_fLodLerpFactor) { // Get destination vertex pointer in this tile (first vertex in bottom left corner of this tile) const INDEX iDstVtx = tt.tt_ctLodVtxX * (tt.tt_ctLodVtxY-1); GFXVertex *pavDst = &pavDstFirst[iDstVtx]; // for each vertex in top row of bottom tile that needs to be lerped for(INDEX ivx=0;ivx<ctLerps;ivx++) { // First vertex is same as in bottom tile pavDst[0] = pavSrc[0]; // Second vertex is lerped between left and right vertices Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor); pavDst+=2; pavSrc+=2; } // is bottom tile in higher lod } else if(tt.tt_iLod>ttBottom.tt_iLod) { const INDEX iVtxDiff = (ttBottom.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1); // Get destination vertex pointer to copy vertices from bottom neighbour (first vertex in bottom left corner of this tile) // Get destination vertex pointer to lerp vertices from bottom neighbour (first vertex added as additional bottom border vertex) const INDEX iDstCopyVtx = tt.tt_ctLodVtxX * (tt.tt_ctLodVtxY-1); const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_BOTTOM]; GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx]; GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx]; // if diference is in one lod if(iVtxDiff==2) { // for each vertex in top row of bottom tile that needs to be lerped for(INDEX ivx=0;ivx<ctLerps;ivx++) { // Copy src vertex in normal dst vertex array pavDstCopy[0] = pavSrc[0]; // Lerp left and right src vertices in border dst vertex Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor); pavDstLerp++; pavDstCopy++; pavSrc+=2; } // diference is more than one lod } else { INDEX ctbv = tt.tt_ctBorderVertices[NB_BOTTOM]; INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex // for each border vertex for(INDEX ivx=0;ivx<ctbv;ivx+=2) { // Lerp left and right src vertices in border dst vertex Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor); // if this border vertex is not last in quad if(ivxInQuad!=iVtxDiff) { // Copy second border vertex pavDstLerp[1] = pavSrc[2]; pavDstLerp+=2; ivxInQuad+=2; // this is last border vertex } else { // Copy second non border vertex pavDstCopy[1] = pavSrc[2]; pavDstCopy++; // since this wasn't border vertex, fix border vertex loop counter ctbv++; pavDstLerp++; ivxInQuad=2; } pavSrc+=2; } } } } // Lerp left border vertices const INDEX &iLeftNeigbour = tt.tt_aiNeighbours[NB_LEFT]; // if left neighbour exists if(iLeftNeigbour>=0) { CTerrainTile &ttLeft = _ptrTerrain->tr_attTiles[iLeftNeigbour]; const FLOAT &fLerpFactor = ttLeft.tt_fLodLerpFactor; // Get source vertex pointer in left neighbour (vertex in top right corner of left neighbour) const INDEX iSrcVtx = ttLeft.tt_ctLodVtxX-1; const INDEX iSrcStep = ttLeft.tt_ctLodVtxX; GFXVertex *pavSrc = &ttLeft.GetVertices()[iSrcVtx]; // Calculate num of vertices that needs to be lerped const INDEX ctLerps = (ttLeft.tt_ctLodVtxX-1)/2; // is left tile in same lod as this tile and has smaller or equal lerp factor if(tt.tt_iLod==ttLeft.tt_iLod && fLerpFactor<=tt.tt_fLodLerpFactor) { // Get destination vertex pointer in this tile (first vertex in top left corner of this tile - first vertex in array) const INDEX iDstVtx = 0; const INDEX iDstStep = tt.tt_ctLodVtxX; GFXVertex *pavDst = &pavDstFirst[iDstVtx]; // for each vertex in last column of left tile that needs to be lerped for(INDEX ivx=0;ivx<ctLerps;ivx++) { // First vertex is same as in left tile pavDst[0] = pavSrc[0]; // Second vertex is lerped between top and bottom vertices Lerp(pavDst[iDstStep],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor); pavDst+=iDstStep*2; pavSrc+=iSrcStep*2; } // is left tile in higher lod } else if(tt.tt_iLod>ttLeft.tt_iLod) { const INDEX iVtxDiff = (ttLeft.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1); // Get destination vertex pointer to copy vertices from left neighbour (first vertex in top left corner of this tile - first vertex in array) // Get destination vertex pointer to lerp vertices from left neighbour (first vertex added as additional left border vertex) const INDEX iDstCopyVtx = 0; const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_LEFT]; const INDEX iDstStep = tt.tt_ctLodVtxX; GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx]; GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx]; // if diference is in one lod if(iVtxDiff==2) { // for each vertex in last column of left tile that needs to be lerped for(INDEX ivx=0;ivx<ctLerps;ivx++) { // Copy src vertex in normal dst vertex array pavDstCopy[0] = pavSrc[0]; // Lerp left and right src vertices in border dst vertex Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor); pavDstLerp++; pavDstCopy+=iDstStep; pavSrc+=iSrcStep*2; } // diference is more than one lod } else { INDEX ctbv = tt.tt_ctBorderVertices[NB_LEFT]; INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex // for each border vertex for(INDEX ivx=0;ivx<ctbv;ivx+=2) { // Lerp left and right src vertices in border dst vertex Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor); // if this border vertex is not last in quad if(ivxInQuad!=iVtxDiff) { // Copy second border vertex pavDstLerp[1] = pavSrc[iSrcStep*2]; pavDstLerp+=2; ivxInQuad+=2; // this is last border vertex } else { // Copy second non border vertex pavDstCopy[iDstStep] = pavSrc[iSrcStep*2]; pavDstCopy+=iDstStep; // since this wasn't border vertex, fix border vertex loop counter ctbv++; pavDstLerp++; ivxInQuad=2; } pavSrc+=iSrcStep*2; } } } } // Lerp right border vertices const INDEX &iRightNeigbour = tt.tt_aiNeighbours[NB_RIGHT]; // if right neighbour exists if(iRightNeigbour>=0) { CTerrainTile &ttRight = _ptrTerrain->tr_attTiles[iRightNeigbour]; const FLOAT &fLerpFactor = ttRight.tt_fLodLerpFactor; // Get source vertex pointer in right neighbour (vertex in top left corner of left neighbour - first vertex in array) const INDEX iSrcVtx = 0; const INDEX iSrcStep = ttRight.tt_ctLodVtxX; GFXVertex *pavSrc = &ttRight.GetVertices()[iSrcVtx]; // Calculate num of vertices that needs to be lerped const INDEX ctLerps = (ttRight.tt_ctLodVtxX-1)/2; // is right tile in same lod as this tile and has smaller lerp factor if(tt.tt_iLod==ttRight.tt_iLod && fLerpFactor<tt.tt_fLodLerpFactor) { // Get destination vertex pointer in this tile (first vertex in top right corner of this tile) INDEX iDstVtx = tt.tt_ctLodVtxX-1; INDEX iDstStep = tt.tt_ctLodVtxX; GFXVertex *pavDst = &pavDstFirst[iDstVtx]; // for each vertex in first column of right tile that needs to be lerped for(INDEX ivx=0;ivx<ctLerps;ivx++) { // First vertex is same as in right tile pavDst[0] = pavSrc[0]; // Second vertex is lerped between top and bottom vertices Lerp(pavDst[iDstStep],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor); pavDst+=iDstStep*2; pavSrc+=iSrcStep*2; } // is right tile in higher lod } else if(tt.tt_iLod>ttRight.tt_iLod) { const INDEX iVtxDiff = (ttRight.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1); // Get destination vertex pointer to copy vertices from right neighbour (first vertex in top right corner of this tile) // Get destination vertex pointer to lerp vertices from right neighbour (first vertex added as additional right border vertex) const INDEX iDstCopyVtx = tt.tt_ctLodVtxX-1; const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_RIGHT]; const INDEX iDstStep = tt.tt_ctLodVtxX; GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx]; GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx]; // if diference is in one lod if(iVtxDiff==2) { // for each vertex in first column of right tile that needs to be lerped for(INDEX ivx=0;ivx<ctLerps;ivx++) { // Copy src vertex in normal dst vertex array pavDstCopy[0] = pavSrc[0]; // Lerp left and right src vertices in border dst vertex Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor); pavDstLerp++; pavDstCopy+=iDstStep; pavSrc+=iSrcStep*2; } // diference is more than one lod } else { INDEX ctbv = tt.tt_ctBorderVertices[NB_RIGHT]; INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex // for each border vertex for(INDEX ivx=0;ivx<ctbv;ivx+=2) { // Lerp left and right src vertices in border dst vertex Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor); // if this border vertex is not last in quad if(ivxInQuad!=iVtxDiff) { // Copy second border vertex pavDstLerp[1] = pavSrc[iSrcStep*2]; pavDstLerp+=2; ivxInQuad+=2; // this is last border vertex } else { // Copy second non border vertex pavDstCopy[iDstStep] = pavSrc[iSrcStep*2]; pavDstCopy+=iDstStep; // since this wasn't border vertex, fix border vertex loop counter ctbv++; pavDstLerp++; ivxInQuad=2; } pavSrc+=iSrcStep*2; } } } } }
void PrepareSmothVerticesOnTileLayer(INDEX iTerrainTile, INDEX iTileLayer) { CTerrainTile &tt = _ptrTerrain->tr_attTiles[iTerrainTile]; CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[iTileLayer]; TileLayer &ttl = tt.GetTileLayers()[iTileLayer]; ASSERT(tt.tt_iLod==0); const INDEX ctVertices = ttl.tl_avVertices.Count(); const FLOAT &fLerpFactor = tt.tt_fLodLerpFactor; // Allocate memory for all vertices _avLerpedTileLayerVertices.PopAll(); _avLerpedTileLayerVertices.Push(ctVertices); // Get pointers to src and dst vertex arrays GFXVertex *pavSrcFirst = &ttl.tl_avVertices[0]; GFXVertex *pavDstFirst = &_avLerpedTileLayerVertices[0]; GFXVertex *pavSrc = &pavSrcFirst[0]; GFXVertex *pavDst = &pavDstFirst[0]; INDEX ctQuadsPerRow = _ptrTerrain->tr_ctQuadsInTileRow; INDEX ctVerticesInRow = _ptrTerrain->tr_ctQuadsInTileRow*2; INDEX iFacing = 1; // Minimize popping on vertices using 4 quads, 2 from current row and 2 from next row in same tile for(INDEX iz=0;iz<ctQuadsPerRow;iz+=2) { for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) { // Get pointer for quads in next row GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2]; GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2]; pavDst[0] = pavSrc[0]; Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[5],fLerpFactor); Lerp(pavDst[2],pavSrc[2],pavSrc[0],pavNRSrc[2],fLerpFactor); if(iFacing&1) { Lerp(pavDst[3],pavSrc[3],pavSrc[0],pavNRSrc[7],fLerpFactor); } else { Lerp(pavDst[3],pavSrc[3],pavSrc[5],pavNRSrc[2],fLerpFactor); } pavDst[4] = pavDst[1]; pavDst[5] = pavSrc[5]; pavDst[6] = pavDst[3]; Lerp(pavDst[7],pavSrc[7],pavSrc[5],pavNRSrc[7],fLerpFactor); pavNRDst[0] = pavDst[2]; pavNRDst[1] = pavDst[3]; pavNRDst[2] = pavNRSrc[2]; Lerp(pavNRDst[3],pavNRSrc[3],pavNRSrc[2],pavNRSrc[7],fLerpFactor); pavNRDst[4] = pavDst[3]; pavNRDst[5] = pavDst[7]; pavNRDst[6] = pavNRDst[3]; pavNRDst[7] = pavNRSrc[7]; // Increment vertex pointers pavSrc+=8; pavDst+=8; iFacing++; } iFacing++; pavSrc+=ctVerticesInRow*2; pavDst+=ctVerticesInRow*2; } // Lerp top border INDEX iTopNeighbour = tt.tt_aiNeighbours[NB_TOP]; // if top border exists if(iTopNeighbour>=0) { CTerrainTile &ttTop = _ptrTerrain->tr_attTiles[iTopNeighbour]; const FLOAT fTopLerpFactor = ttTop.tt_fLodLerpFactor; // is top tile in highest lod and has smaller or equal lerp factor if(ttTop.tt_iLod==0 && fTopLerpFactor<=fLerpFactor) { TileLayer &ttl = ttTop.GetTileLayers()[iTileLayer]; INDEX iFirstVertex = ctVerticesInRow*(ctVerticesInRow-2); GFXVertex *pavSrc = &ttl.tl_avVertices[iFirstVertex]; GFXVertex *pavDst = &_avLerpedTileLayerVertices[0]; // for each quad for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) { Lerp(pavDst[1],pavSrc[6],pavSrc[2],pavSrc[7],fTopLerpFactor); pavDst[4] = pavDst[1]; pavSrc+=8; pavDst+=8; } } } // Lerp bottom border INDEX iBottomNeighbour = tt.tt_aiNeighbours[NB_BOTTOM]; // if bottom border exists if(iBottomNeighbour>=0) { CTerrainTile &ttBottom = _ptrTerrain->tr_attTiles[iBottomNeighbour]; const FLOAT fBottomLerpFactor = ttBottom.tt_fLodLerpFactor; // is bottom tile in highest lod and has smaller lerp factor if(ttBottom.tt_iLod==0 && fBottomLerpFactor<fLerpFactor) { TileLayer &ttl = ttBottom.GetTileLayers()[iTileLayer]; INDEX iFirstVertex = ctVerticesInRow*(ctVerticesInRow-2); GFXVertex *pavSrc = &ttl.tl_avVertices[0]; GFXVertex *pavDst = &_avLerpedTileLayerVertices[iFirstVertex]; // for each quad for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) { Lerp(pavDst[3],pavSrc[1],pavSrc[0],pavSrc[5],fBottomLerpFactor); pavDst[6] = pavDst[3]; pavSrc+=8; pavDst+=8; } } } // Lerp left border INDEX iLeftNeighbour = tt.tt_aiNeighbours[NB_LEFT]; // if left neightbour exits if(iLeftNeighbour>=0) { CTerrainTile &ttLeft = _ptrTerrain->tr_attTiles[iLeftNeighbour]; const FLOAT fLeftLerpFactor = ttLeft.tt_fLodLerpFactor; // is left tile in highest lod and has smaller or equal left factor if(ttLeft.tt_iLod==0 && fLeftLerpFactor<=fLerpFactor) { TileLayer &ttl = ttLeft.GetTileLayers()[iTileLayer]; INDEX iFirstVertex = ctVerticesInRow*2-8; GFXVertex *pavSrc = &ttl.tl_avVertices[iFirstVertex]; GFXVertex *pavDst = &_avLerpedTileLayerVertices[0]; // for each quad for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) { GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2]; GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2]; Lerp(pavDst[2],pavSrc[7],pavSrc[5],pavNRSrc[7],fLeftLerpFactor); pavNRDst[0] = pavDst[2]; pavSrc+=ctVerticesInRow*4; pavDst+=ctVerticesInRow*4; } } } // Lerp right border INDEX iRightNeighbour = tt.tt_aiNeighbours[NB_RIGHT]; // if right neightbour exits if(iRightNeighbour>=0) { CTerrainTile &ttRight = _ptrTerrain->tr_attTiles[iRightNeighbour]; const FLOAT fRightLerpFactor = ttRight.tt_fLodLerpFactor; // is right tile in highest lod and has smaller left factor if(ttRight.tt_iLod==0 && fRightLerpFactor<fLerpFactor) { TileLayer &ttl = ttRight.GetTileLayers()[iTileLayer]; INDEX iFirstVertex = ctVerticesInRow*2-8; GFXVertex *pavSrc = &ttl.tl_avVertices[0]; GFXVertex *pavDst = &_avLerpedTileLayerVertices[iFirstVertex]; // for each quad for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) { GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2]; GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2]; Lerp(pavDst[7],pavSrc[2],pavSrc[0],pavNRSrc[2],fRightLerpFactor); pavNRDst[5] = pavDst[7]; pavSrc+=ctVerticesInRow*4; pavDst+=ctVerticesInRow*4; } } } }
// Calculate lightning for given model void shaCalculateLight(void) { // if full bright if(shaGetFlags()&BASE_FULL_BRIGHT) { GFXColor colLight = _colConstant; GFXColor colAmbient; GFXColor colConstant; // is over brightning enabled if(shaOverBrightningEnabled()) { colAmbient = 0x7F7F7FFF; } else { colAmbient = 0xFFFFFFFF; } colConstant.MultiplyRGBA(colLight,colAmbient); shaSetConstantColor(ByteSwap(colConstant.abgr)); // no vertex colors return; } ASSERT(_paNormals!=NULL); _acolVtxColors.PopAll(); _acolVtxColors.Push(_ctVertices); GFXColor colModel = (GFXColor)_colModel; // Model color GFXColor &colAmbient = (GFXColor)_colAmbient; // Ambient color GFXColor &colLight = (GFXColor)_colLight; // Light color GFXColor &colSurface = (GFXColor)_colConstant; // shader color colModel.MultiplyRGBA(colModel,colSurface); UBYTE ubColShift = 8; SLONG slar = colAmbient.r; SLONG slag = colAmbient.g; SLONG slab = colAmbient.b; if(shaOverBrightningEnabled()) { slar = ClampUp(slar,127L); slag = ClampUp(slag,127L); slab = ClampUp(slab,127L); ubColShift = 8; } else { slar*=2; slag*=2; slab*=2; ubColShift = 7; } // for each vertex color for(INDEX ivx=0;ivx<_ctVertices;ivx++) { // calculate vertex light FLOAT3D &vNorm = FLOAT3D(_paNormals[ivx].nx,_paNormals[ivx].ny,_paNormals[ivx].nz); FLOAT fDot = vNorm % _vLightDir; fDot = Clamp(fDot,0.0f,1.0f); SLONG slDot = NormFloatToByte(fDot); _acolVtxColors[ivx].r = ClampUp(colModel.r * (slar + ((colLight.r * slDot)>>ubColShift))>>8,255L); _acolVtxColors[ivx].g = ClampUp(colModel.g * (slag + ((colLight.g * slDot)>>ubColShift))>>8,255L); _acolVtxColors[ivx].b = ClampUp(colModel.b * (slab + ((colLight.b * slDot)>>ubColShift))>>8,255L); _acolVtxColors[ivx].a = colModel.a;//slDot; } // Set current vertex color array _pcolVtxColors = &_acolVtxColors[0]; }
// 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 }
static void RenderFogLayer(INDEX itt) { FLOATmatrix3D &mViewer = _aprProjection->pr_ViewerRotationMatrix; FLOAT3D vObjPosition = _ptrTerrain->tr_penEntity->en_plPlacement.pl_PositionVector; // get viewer -z in object space _vFViewerObj = FLOAT3D(0,0,-1) * !_mObjectToView; // get fog direction in object space _vHDirObj = _fog_vHDirAbs * !(!mViewer*_mObjectToView); // get viewer offset _fFogAddZ = _vViewer(1) * (vObjPosition(1) - _aprProjection->pr_vViewerPosition(1)); _fFogAddZ += _vViewer(2) * (vObjPosition(2) - _aprProjection->pr_vViewerPosition(2)); _fFogAddZ += _vViewer(3) * (vObjPosition(3) - _aprProjection->pr_vViewerPosition(3)); // get fog offset _fFogAddH = (_fog_vHDirAbs % vObjPosition) + _fog_fp.fp_fH3; GFXVertex *pvVtx; INDEX *piIndices; INDEX ctVertices; INDEX ctIndices; // if this is tile if(itt>=0) { CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt]; pvVtx = &tt.GetVertices()[0]; piIndices = &tt.GetIndices()[0]; ctVertices = tt.GetVertices().Count(); ctIndices = tt.GetIndices().Count(); // else this are batched tiles } else { pvVtx = &_avDelayedVertices[0]; piIndices = &_aiDelayedIndices[0]; ctVertices = _avDelayedVertices.Count(); ctIndices = _aiDelayedIndices.Count(); } GFXTexCoord *pfFogTC = _atcHaze.Push(ctVertices); GFXColor *pcolFog = _acolHaze.Push(ctVertices); const COLOR colF = AdjustColor( _fog_fp.fp_colColor, _slTexHueShift, _slTexSaturation); GFXColor colFog(colF); // for each vertex in tile for(INDEX ivx=0;ivx<ctVertices;ivx++) { GetFogMapInVertex(pvVtx[ivx],pfFogTC[ivx]); pcolFog[ivx] = colFog; } // render fog layer gfxDepthFunc(GFX_EQUAL); gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP); gfxSetTexture( _fog_ulTexture, _fog_tpLocal); gfxSetTexCoordArray(pfFogTC, FALSE); gfxSetColorArray(pcolFog); gfxBlendFunc( GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA); gfxEnableBlend(); gfxDisableAlphaTest(); gfxDrawElements(ctIndices,piIndices); gfxDepthFunc(GFX_LESS_EQUAL); _atcHaze.PopAll(); _acolHaze.PopAll(); }