static void InitTris(void) { INDEX iR, iC; INDEX ctVx = _ctR*_ctC; _avtx.Push(ctVx); _atex.Push(ctVx); _acol.Push(ctVx); for( iR=0; iR<_ctR; iR++) { for( iC=0; iC<_ctC; iC++) { INDEX ivx = iR*_ctC+iC; _avtx[ivx].x = FLOAT(iC) / _ctC*4 -2.0f; _avtx[ivx].y = -FLOAT(iR) / _ctR*4 +2.0f; _avtx[ivx].z = -1.0f; _atex[ivx].st.s = (iC+iR) % 2; _atex[ivx].st.t = (iR) % 2; _acol[ivx].ul.abgr = 0xFFFFFFFF; } } INDEX ctTri = (_ctR-1)*(_ctC-1)*2; _aiElements.Push(ctTri*3); for( iR=0; iR<_ctR-1; iR++) { for( iC=0; iC<_ctC-1; iC++) { INDEX iq = iR*(_ctC-1)+iC; _aiElements[iq*6+0] = (iR+1) * _ctC + (iC+0); _aiElements[iq*6+1] = (iR+1) * _ctC + (iC+1); _aiElements[iq*6+2] = (iR+0) * _ctC + (iC+0); _aiElements[iq*6+3] = (iR+0) * _ctC + (iC+0); _aiElements[iq*6+4] = (iR+1) * _ctC + (iC+1); _aiElements[iq*6+5] = (iR+0) * _ctC + (iC+1); } } }
static void BatchTile(INDEX itt) { CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt]; ASSERT(tt.GetVertices().Count()==9); ASSERT(tt.GetIndices().Count()==24); INDEX ctDelayedVertices = _avDelayedVertices.Count(); GFXVertex4 *pavVertices = &tt.GetVertices()[0]; GFXTexCoord *pauvTexCoords = &tt.GetTexCoords()[0]; GFXTexCoord *pauvShadowMapTC = &tt.GetShadowMapTC()[0]; INDEX *paiIndices = &tt.GetIndices()[0]; GFXVertex4 *pavDelVertices = _avDelayedVertices.Push(9); GFXTexCoord *pauvDelTexCoords = _auvDelayedTexCoords.Push(9); GFXTexCoord *pauvDelShadowMapTC = _auvDelayedShadowMapTC.Push(9); INDEX *paiDelIndices = _aiDelayedIndices.Push(24); // for each vertex in tile for(INDEX ivx=0;ivx<9;ivx++) { // copy vertex, texcoord & shadow map texcoord to delayed array pavDelVertices[ivx] = pavVertices[ivx]; pauvDelTexCoords[ivx] = pauvTexCoords[ivx]; pauvDelShadowMapTC[ivx] = pauvShadowMapTC[ivx]; } // for each index in tile for(INDEX iind=0;iind<24;iind++) { // reindex indice for new arrays paiDelIndices[iind] = paiIndices[iind] + ctDelayedVertices; } _ctDelayedNodes++; }
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]; }
static void LoadOneFile(const CTFileName &fnm) { try { // open the file CTFileStream strm; strm.Open_t(fnm); // count number of lines INDEX ctLines = 0; while(!strm.AtEOF()) { CTString strLine; strm.GetLine_t(strLine); ctLines++; } strm.SetPos_t(0); // allocate that much CTString *astr = _astrCredits.Push(ctLines); // load all lines for(INDEX iLine = 0; iLine<ctLines && !strm.AtEOF(); iLine++) { strm.GetLine_t(astr[iLine]); } strm.Close(); _bCreditsOn = TRUE; } catch (char *strError) { CPrintF("%s\n", strError); } }
// 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]; }
// update current active message category static void UpdateType(BOOL bForce=FALSE) { if (_cmtCurrentType==_cmtWantedType && !bForce) { return; } // cleare message cache _acmMessages.Clear(); // for each player's message CDynamicStackArray<CCompMessageID> &acmiMsgs = _ppenPlayer->m_acmiMessages; for(INDEX i=0; i<acmiMsgs.Count(); i++) { CCompMessageID &cmi = acmiMsgs[i]; // if it is of given type if (cmi.cmi_cmtType == _cmtWantedType) { // add it to cache CCompMessage &cm = _acmMessages.Push(); cm.SetMessage(&cmi); } } if (!bForce) { _cmtCurrentType=_cmtWantedType; _iFirstMessageOnScreen = -1; _iWantedFirstMessageOnScreen = 0; _iActiveMessage = 0; _iLastActiveMessage = -2; _iTextLineOnScreen = 0; LastUnreadMessage(); UpdateFirstOnScreen(); } }
// 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; } }
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)); } }
// 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]; }
// check point against depth buffer extern BOOL CheckDepthPoint( const CDrawPort *pdp, PIX pixI, PIX pixJ, FLOAT f**K, INDEX iID, INDEX iMirrorLevel/*=0*/) { // no raster? const CRaster *pra = pdp->dp_Raster; if( pra==NULL) return FALSE; // almoust out of raster? pixI += pdp->dp_MinI; pixJ += pdp->dp_MinJ; if( pixI<1 || pixJ<1 || pixI>pra->ra_Width-2 || pixJ>pra->ra_Height-2) return FALSE; // if shouldn't delay if( gap_iOptimizeDepthReads==0) { // just check immediately DepthInfo di = { iID, pixI, pixJ, f**K, _iCheckIteration, iMirrorLevel, FALSE }; UpdateDepthPointsVisibility( pdp, iMirrorLevel, &di, 1); return di.di_bVisible; } // for each stored point for( INDEX idi=0; idi<_adiDelayed.Count(); idi++) { DepthInfo &di = _adiDelayed[idi]; // if same id if( di.di_iID == iID) { // remember parameters di.di_pixI = pixI; di.di_pixJ = pixJ; di.di_fOoK = f**K; di.di_iSwapLastRequest = _iCheckIteration; // return visibility return di.di_bVisible; } } // if not found... // create new one DepthInfo &di = _adiDelayed.Push(); // remember parameters di.di_iID = iID; di.di_pixI = pixI; di.di_pixJ = pixJ; di.di_fOoK = f**K; di.di_iSwapLastRequest = _iCheckIteration; di.di_iMirrorLevel = iMirrorLevel; di.di_bVisible = FALSE; // not visible by default return FALSE; }
// fill remap array with indices of vertices in order how they appear per polygons FOREACHINDYNAMICCONTAINER(acmMaterials, ConversionMaterial, itcm) { // fill remap array with -1 for( INDEX iRemap=0; iRemap<ctVertices; iRemap++) { aiRemap[iRemap] = -1; } // reset 'vertex in surface' counter INDEX ctvx = 0; // for each polygon in surface {FOREACHINDYNAMICCONTAINER(itcm->ms_Polygons, INDEX, itipol) { INDEX idxPol = *itipol; // for each vertex in polygon for(INDEX iVtx=0; iVtx<3; iVtx++) { // get vertex's index INDEX idxVtx = actTriangles[idxPol].ct_iVtx[iVtx]; if( aiRemap[idxVtx] == -1) { aiRemap[idxVtx] = ctvx; ctvx++; } } }} INDEX ctOld = avDst.Count(); // allocate new block of vertices used in this surface FLOAT3D *pavDst = avDst.Push( ctvx); // for each polygon in surface {FOREACHINDYNAMICCONTAINER(itcm->ms_Polygons, INDEX, itipol) { INDEX iPol=*itipol; // for each vertex in polygon for(INDEX iVtx=0; iVtx<3; iVtx++) { // get vertex's index INDEX idxVtx = actTriangles[iPol].ct_iVtx[iVtx]; // get remapped index INDEX iRemap = aiRemap[idxVtx]; // if cutting object if( bAsOpened) { // copy vertex coordinate pavDst[ iRemap] = avVertices[idxVtx]; } // if creating unwrapped mapping else { // copy texture coordinate FLOAT3D vMap; vMap(1) = avTextureVertices[actTriangles[iPol].ct_iTVtx[iVtx]](1); vMap(2) = -avTextureVertices[actTriangles[iPol].ct_iTVtx[iVtx]](2); vMap(3) = 0; pavDst[ iRemap] = vMap; } // remap index of polygon vertex actTriangles[iPol].ct_iVtx[iVtx] = iRemap+ctOld; } }} }
extern void InternalShader_Mask(void) { // need arrays and texture INDEX ctIdx = shaGetIndexCount(); INDEX ctVtx = shaGetVertexCount(); if( ctIdx==0 || ctVtx==0) return; INDEX *pidx = shaGetIndexArray(); GFXVertex4 *pvtx = shaGetVertexArray(); GFXTexCoord *ptex = shaGetUVMap(0); CTextureObject *pto = shaGetTexture(0); ASSERT( (ctIdx%3) == 0); // must have triangles? // prepare texture ULONG *pulTexFrame = NULL; PIX pixMipWidth=0, pixMipHeight=0; if( pto!=NULL && ptex!=NULL) { CTextureData *ptd = (CTextureData*)pto->GetData(); if( ptd!=NULL && ptd->td_ptegEffect==NULL) { // fetch some texture params pulTexFrame = ptd->td_pulFrames + (pto->GetFrame()*ptd->td_slFrameSize)/BYTES_PER_TEXEL; pixMipWidth = ptd->GetPixWidth(); pixMipHeight = ptd->GetPixHeight(); // reload texture and keep in memory ptd->Force(TEX_STATIC); } } // initialize texture for usage thru render triangle routine SetTriangleTexture( pulTexFrame, pixMipWidth, pixMipHeight); // prepare projection const BOOL bPerspective = _aprProjection.IsPerspective(); CPerspectiveProjection3D &prPerspective = (CPerspectiveProjection3D &)*_aprProjection; CParallelProjection3D &prParallel = (CParallelProjection3D &)*_aprProjection; FLOAT fCenterI, fCenterJ, fRatioI, fRatioJ, fStepI, fStepJ, fZoomI, fZoomJ; FLOAT fFrontClipDistance, fBackClipDistance, f1oFrontClipDistance, f1oBackClipDistance, fDepthBufferFactor; if( bPerspective) { fCenterI = prPerspective.pr_ScreenCenter(1); fCenterJ = prPerspective.pr_ScreenCenter(2); fRatioI = prPerspective.ppr_PerspectiveRatios(1); fRatioJ = prPerspective.ppr_PerspectiveRatios(2); fFrontClipDistance = -prPerspective.pr_NearClipDistance; fBackClipDistance = -prPerspective.pr_FarClipDistance; f1oFrontClipDistance = -1.0f / prPerspective.pr_NearClipDistance; f1oBackClipDistance = -1.0f / prPerspective.pr_FarClipDistance; fDepthBufferFactor = prPerspective.pr_fDepthBufferFactor; } else { fCenterI = prParallel.pr_ScreenCenter(1); fCenterJ = prParallel.pr_ScreenCenter(2); fStepI = prParallel.pr_vStepFactors(1); fStepJ = prParallel.pr_vStepFactors(2); fZoomI = prParallel.pr_vZoomFactors(1); fZoomJ = prParallel.pr_vZoomFactors(2); fFrontClipDistance = -prPerspective.pr_NearClipDistance; fBackClipDistance = -prPerspective.pr_FarClipDistance; f1oFrontClipDistance = 1.0f; f1oBackClipDistance = 1.0f; fDepthBufferFactor = 1.0f; } // copy view space vertices, project 'em to screen space and mark clipping CStaticStackArray<TransformedVertexData> atvd; INDEX iVtx=0; for(; iVtx<ctVtx; iVtx++) { // copy viewspace and texture coords TransformedVertexData &tvd = atvd.Push(); tvd.tvd_fX = pvtx[iVtx].x; tvd.tvd_fY = pvtx[iVtx].y; tvd.tvd_fZ = pvtx[iVtx].z; tvd.tvd_bClipped = FALSE; // initially, vertex is not clipped // prepare screen coordinates if( bPerspective) { const FLOAT f1oZ = 1.0f / tvd.tvd_fZ; tvd.tvd_pv2.pv2_fI = fCenterI + tvd.tvd_fX*fRatioI *f1oZ; tvd.tvd_pv2.pv2_fJ = fCenterJ - tvd.tvd_fY*fRatioJ *f1oZ; tvd.tvd_pv2.pv2_f1oK = fDepthBufferFactor*f1oZ; } else { tvd.tvd_pv2.pv2_fI = fCenterI + tvd.tvd_fX*fZoomI + tvd.tvd_fZ*fStepI; tvd.tvd_pv2.pv2_fJ = fCenterJ - tvd.tvd_fY*fZoomJ - tvd.tvd_fZ*fStepJ; tvd.tvd_pv2.pv2_f1oK = 1; } // adjust texture coords (if any!) if( ptex!=NULL) { tvd.tvd_fU = ptex[iVtx].s; tvd.tvd_fV = ptex[iVtx].t; tvd.tvd_pv2.pv2_fUoK = tvd.tvd_fU * tvd.tvd_pv2.pv2_f1oK *pixMipWidth; tvd.tvd_pv2.pv2_fVoK = tvd.tvd_fV * tvd.tvd_pv2.pv2_f1oK *pixMipHeight; } else tvd.tvd_fU = tvd.tvd_fV = 0; // check clipping against horizontal screen boundaries and near clip plane if( tvd.tvd_pv2.pv2_fI<0 || tvd.tvd_pv2.pv2_fI>=_slMaskWidth || tvd.tvd_fZ>fFrontClipDistance || (fBackClipDistance<0 && tvd.tvd_fZ<fBackClipDistance)) { tvd.tvd_bClipped = TRUE; } } // lets clip and render - triangle by triangle for( INDEX iIdx=0; iIdx<ctIdx; iIdx+=3) { // get transformed triangle TransformedVertexData tvd[3]; iVtx = pidx[iIdx+0]; tvd[0] = atvd[iVtx]; iVtx = pidx[iIdx+1]; tvd[1] = atvd[iVtx]; iVtx = pidx[iIdx+2]; tvd[2] = atvd[iVtx]; // clipped? if( tvd[0].tvd_bClipped || tvd[1].tvd_bClipped || tvd[2].tvd_bClipped) { // create array of vertices for polygon clipped to near clip plane ctvxDst=0; INDEX ivx0=2; INDEX ivx1=0; {for( INDEX ivx=0; ivx<3; ivx++) { TransformedVertexData &tvd0 = tvd[ivx0]; TransformedVertexData &tvd1 = tvd[ivx1]; FLOAT fd0 = fFrontClipDistance-tvd0.tvd_fZ; FLOAT fd1 = fFrontClipDistance-tvd1.tvd_fZ; // if first vertex is in if( fd0>=0) { // add it to clip array ptvdDst[ctvxDst] = tvd0; ctvxDst++; // if second vertex is out if( fd1<0) { // add clipped vertex at exit TransformedVertexData &tvdClipped = ptvdDst[ctvxDst]; ctvxDst++; FLOAT fF = fd1/(fd1-fd0); tvdClipped.tvd_fX = tvd1.tvd_fX - (tvd1.tvd_fX - tvd0.tvd_fX) *fF; tvdClipped.tvd_fY = tvd1.tvd_fY - (tvd1.tvd_fY - tvd0.tvd_fY) *fF; tvdClipped.tvd_fZ = fFrontClipDistance; tvdClipped.tvd_pv2.pv2_f1oK = fDepthBufferFactor * f1oFrontClipDistance; FLOAT fU = tvd1.tvd_fU - (tvd1.tvd_fU - tvd0.tvd_fU) *fF; FLOAT fV = tvd1.tvd_fV - (tvd1.tvd_fV - tvd0.tvd_fV) *fF; tvdClipped.tvd_pv2.pv2_fUoK = fU * tvdClipped.tvd_pv2.pv2_f1oK; tvdClipped.tvd_pv2.pv2_fVoK = fV * tvdClipped.tvd_pv2.pv2_f1oK; } // if first vertex is out (don't add it into clip array) } else { // if second vertex is in if( fd1>=0) { // add clipped vertex at entry TransformedVertexData &tvdClipped = ptvdDst[ctvxDst]; ctvxDst++; FLOAT fF = fd0/(fd0-fd1); tvdClipped.tvd_fX = tvd0.tvd_fX - (tvd0.tvd_fX - tvd1.tvd_fX) *fF; tvdClipped.tvd_fY = tvd0.tvd_fY - (tvd0.tvd_fY - tvd1.tvd_fY) *fF; tvdClipped.tvd_fZ = fFrontClipDistance; tvdClipped.tvd_pv2.pv2_f1oK = fDepthBufferFactor * f1oFrontClipDistance; FLOAT fU = tvd0.tvd_fU - (tvd0.tvd_fU - tvd1.tvd_fU) *fF; FLOAT fV = tvd0.tvd_fV - (tvd0.tvd_fV - tvd1.tvd_fV) *fF; tvdClipped.tvd_pv2.pv2_fUoK = fU * tvdClipped.tvd_pv2.pv2_f1oK; tvdClipped.tvd_pv2.pv2_fVoK = fV * tvdClipped.tvd_pv2.pv2_f1oK; } } // proceed to next vertex in list (i.e. new pair of vertices) ivx0=ivx1; ivx1++; }} // swap buffers Swap( ptvdSrc, ptvdDst); Swap( ctvxSrc, ctvxDst); // if clipping to far clip plane is on if( fBackClipDistance<0) { ctvxDst=0; INDEX ivx0=ctvxSrc-1; INDEX ivx1=0; {for( INDEX ivx=0; ivx<ctvxSrc; ivx++) { TransformedVertexData &tvd0 = ptvdSrc[ivx0]; TransformedVertexData &tvd1 = ptvdSrc[ivx1]; FLOAT fd0 = tvd0.tvd_fZ-fBackClipDistance; FLOAT fd1 = tvd1.tvd_fZ-fBackClipDistance; // if first vertex is in if( fd0>=0) { // add it to clip array ptvdDst[ctvxDst] = tvd0; ctvxDst++; // if second vertex is out if( fd1<0) { // add clipped vertex at exit TransformedVertexData &tvdClipped = ptvdDst[ctvxDst]; ctvxDst++; FLOAT fF = fd1/(fd1-fd0); tvdClipped.tvd_fX = tvd1.tvd_fX - (tvd1.tvd_fX - tvd0.tvd_fX) *fF; tvdClipped.tvd_fY = tvd1.tvd_fY - (tvd1.tvd_fY - tvd0.tvd_fY) *fF; tvdClipped.tvd_fZ = fBackClipDistance; tvdClipped.tvd_pv2.pv2_f1oK = fDepthBufferFactor * f1oBackClipDistance; FLOAT fU = tvd1.tvd_fU - (tvd1.tvd_fU - tvd0.tvd_fU) *fF; FLOAT fV = tvd1.tvd_fV - (tvd1.tvd_fV - tvd0.tvd_fV) *fF; tvdClipped.tvd_pv2.pv2_fUoK = fU * tvdClipped.tvd_pv2.pv2_f1oK; tvdClipped.tvd_pv2.pv2_fVoK = fV * tvdClipped.tvd_pv2.pv2_f1oK; } // if first vertex is out (don't add it into clip array) } else { // if second vertex is in if( fd1>=0) { // add clipped vertex at entry TransformedVertexData &tvdClipped = ptvdDst[ctvxDst]; ctvxDst++; FLOAT fF = fd0/(fd0-fd1); tvdClipped.tvd_fX = tvd0.tvd_fX - (tvd0.tvd_fX - tvd1.tvd_fX) *fF; tvdClipped.tvd_fY = tvd0.tvd_fY - (tvd0.tvd_fY - tvd1.tvd_fY) *fF; tvdClipped.tvd_fZ = fBackClipDistance; tvdClipped.tvd_pv2.pv2_f1oK = fDepthBufferFactor * f1oBackClipDistance; FLOAT fU = tvd0.tvd_fU - (tvd0.tvd_fU - tvd1.tvd_fU) *fF; FLOAT fV = tvd0.tvd_fV - (tvd0.tvd_fV - tvd1.tvd_fV) *fF; tvdClipped.tvd_pv2.pv2_fUoK = fU * tvdClipped.tvd_pv2.pv2_f1oK; tvdClipped.tvd_pv2.pv2_fVoK = fV * tvdClipped.tvd_pv2.pv2_f1oK; } } // proceed to next vertex in list (i.e. new pair of vertices) ivx0=ivx1; ivx1++; }} // swap buffers Swap( ptvdSrc, ptvdDst); Swap( ctvxSrc, ctvxDst); } // for each vertex {for( INDEX ivx=0; ivx<ctvxSrc; ivx++) { // calculate projection TransformedVertexData &tvd = ptvdSrc[ivx]; if( bPerspective) { const FLOAT f1oZ = 1.0f / tvd.tvd_fZ; tvd.tvd_pv2.pv2_fI = fCenterI + tvd.tvd_fX*fRatioI *f1oZ; tvd.tvd_pv2.pv2_fJ = fCenterJ - tvd.tvd_fY*fRatioJ *f1oZ; } else { tvd.tvd_pv2.pv2_fI = fCenterI + tvd.tvd_fX*fZoomI + tvd.tvd_fZ*fStepI; tvd.tvd_pv2.pv2_fJ = fCenterJ - tvd.tvd_fY*fZoomJ - tvd.tvd_fZ*fStepJ; } }} // clip polygon against left edge ctvxDst=0; ivx0=ctvxSrc-1; ivx1=0; {for( INDEX ivx=0; ivx<ctvxSrc; ivx++) { PolyVertex2D &pv20 = ptvdSrc[ivx0].tvd_pv2; PolyVertex2D &pv21 = ptvdSrc[ivx1].tvd_pv2; FLOAT fd0 = pv20.pv2_fI-0; FLOAT fd1 = pv21.pv2_fI-0; // if first vertex is in if( fd0>=0) { // add it to clip array ptvdDst[ctvxDst].tvd_pv2 = pv20; ctvxDst++; // if second vertex is out if( fd1<0) { PolyVertex2D &pv2Clipped = ptvdDst[ctvxDst].tvd_pv2; ctvxDst++; FLOAT fF = fd1/(fd1-fd0); pv2Clipped.pv2_fI = 0; pv2Clipped.pv2_fJ = pv21.pv2_fJ - (pv21.pv2_fJ - pv20.pv2_fJ) *fF; pv2Clipped.pv2_f1oK = pv21.pv2_f1oK - (pv21.pv2_f1oK - pv20.pv2_f1oK) *fF; pv2Clipped.pv2_fUoK = pv21.pv2_fUoK - (pv21.pv2_fUoK - pv20.pv2_fUoK) *fF; pv2Clipped.pv2_fVoK = pv21.pv2_fVoK - (pv21.pv2_fVoK - pv20.pv2_fVoK) *fF; } // if first vertex is out (don't add it into clip array) } else { // if second vertex is in if( fd1>=0) { // add clipped vertex at entry PolyVertex2D &pv2Clipped = ptvdDst[ctvxDst].tvd_pv2; ctvxDst++; FLOAT fF = fd0/(fd0-fd1); pv2Clipped.pv2_fI = 0; pv2Clipped.pv2_fJ = pv20.pv2_fJ - (pv20.pv2_fJ - pv21.pv2_fJ)*fF; pv2Clipped.pv2_f1oK = pv20.pv2_f1oK - (pv20.pv2_f1oK - pv21.pv2_f1oK) *fF; pv2Clipped.pv2_fUoK = pv20.pv2_fUoK - (pv20.pv2_fUoK - pv21.pv2_fUoK) *fF; pv2Clipped.pv2_fVoK = pv20.pv2_fVoK - (pv20.pv2_fVoK - pv21.pv2_fVoK) *fF; } } // proceed to next vertex in list (i.e. new pair of vertices) ivx0=ivx1; ivx1++; }} // swap buffers Swap( ptvdSrc, ptvdDst); Swap( ctvxSrc, ctvxDst); // clip polygon against right edge ctvxDst=0; ivx0=ctvxSrc-1; ivx1=0; {for( INDEX ivx=0; ivx<ctvxSrc; ivx++) { PolyVertex2D &pv20 = ptvdSrc[ivx0].tvd_pv2; PolyVertex2D &pv21 = ptvdSrc[ivx1].tvd_pv2; FLOAT fd0 = _slMaskWidth - pv20.pv2_fI; FLOAT fd1 = _slMaskWidth - pv21.pv2_fI; // if first vertex is in if( fd0>=0) { // add it to clip array ptvdDst[ctvxDst].tvd_pv2 = pv20; ctvxDst++; // if second vertex is out if( fd1<0) { PolyVertex2D &pv2Clipped = ptvdDst[ctvxDst].tvd_pv2; ctvxDst++; FLOAT fF = fd1/(fd1-fd0); pv2Clipped.pv2_fI = _slMaskWidth; pv2Clipped.pv2_fJ = pv21.pv2_fJ - (pv21.pv2_fJ - pv20.pv2_fJ)*fF; pv2Clipped.pv2_f1oK = pv21.pv2_f1oK - (pv21.pv2_f1oK - pv20.pv2_f1oK) *fF; pv2Clipped.pv2_fUoK = pv21.pv2_fUoK - (pv21.pv2_fUoK - pv20.pv2_fUoK) *fF; pv2Clipped.pv2_fVoK = pv21.pv2_fVoK - (pv21.pv2_fVoK - pv20.pv2_fVoK) *fF; } // if first vertex is out (don't add it into clip array) } else { // if second vertex is in if( fd1>=0) { // add clipped vertex at entry PolyVertex2D &pv2Clipped = ptvdDst[ctvxDst].tvd_pv2; ctvxDst++; FLOAT fF = fd0/(fd0-fd1); pv2Clipped.pv2_fI = _slMaskWidth; pv2Clipped.pv2_fJ = pv20.pv2_fJ - (pv20.pv2_fJ - pv21.pv2_fJ)*fF; pv2Clipped.pv2_f1oK = pv20.pv2_f1oK - (pv20.pv2_f1oK - pv21.pv2_f1oK) *fF; pv2Clipped.pv2_fUoK = pv20.pv2_fUoK - (pv20.pv2_fUoK - pv21.pv2_fUoK) *fF; pv2Clipped.pv2_fVoK = pv20.pv2_fVoK - (pv20.pv2_fVoK - pv21.pv2_fVoK) *fF; } } // proceed to next vertex in list (i.e. new pair of vertices) ivx0=ivx1; ivx1++; }} // swap buffers Swap( ptvdSrc, ptvdDst); Swap( ctvxSrc, ctvxDst); // draw all triangles in clipped polygon as a triangle fan, with clipping PolyVertex2D &pvx0 = ptvdSrc[0].tvd_pv2; {for( INDEX ivx=1; ivx<ctvxSrc-1; ivx++) { PolyVertex2D &pvx1 = ptvdSrc[ivx+0].tvd_pv2; PolyVertex2D &pvx2 = ptvdSrc[ivx+1].tvd_pv2; DrawTriangle_Mask( _pubMask, _slMaskWidth, _slMaskHeight, &pvx0, &pvx1, &pvx2, TRUE); }} } // not clipped - just draw! else { DrawTriangle_Mask( _pubMask, _slMaskWidth, _slMaskHeight, &tvd[0].tvd_pv2, &tvd[1].tvd_pv2, &tvd[2].tvd_pv2, TRUE); } } }
// 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 }
// setup CRenderModel class for rendering one model and eventually it's shadow(s) void CModelObject::SetupModelRendering( CRenderModel &rm) { _sfStats.IncrementCounter( CStatForm::SCI_MODELS); _pfModelProfile.StartTimer( CModelProfile::PTI_INITMODELRENDERING); _pfModelProfile.IncrementTimerAveragingCounter( CModelProfile::PTI_INITMODELRENDERING); // get model's data and lerp info rm.rm_pmdModelData = (CModelData*)GetData(); GetFrame( rm.rm_iFrame0, rm.rm_iFrame1, rm.rm_fRatio); const INDEX ctVertices = rm.rm_pmdModelData->md_VerticesCt; if( rm.rm_pmdModelData->md_Flags & MF_COMPRESSED_16BIT) { // set pFrame to point to last and next frames' vertices rm.rm_pFrame16_0 = &rm.rm_pmdModelData->md_FrameVertices16[rm.rm_iFrame0 *ctVertices]; rm.rm_pFrame16_1 = &rm.rm_pmdModelData->md_FrameVertices16[rm.rm_iFrame1 *ctVertices]; } else { // set pFrame to point to last and next frames' vertices rm.rm_pFrame8_0 = &rm.rm_pmdModelData->md_FrameVertices8[rm.rm_iFrame0 *ctVertices]; rm.rm_pFrame8_1 = &rm.rm_pmdModelData->md_FrameVertices8[rm.rm_iFrame1 *ctVertices]; } // obtain current rendering preferences rm.rm_rtRenderType = _mrpModelRenderPrefs.GetRenderType(); // remember blending color rm.rm_colBlend = MulColors( rm.rm_colBlend, mo_colBlendColor); // get decompression/stretch factors FLOAT3D &vDataStretch = rm.rm_pmdModelData->md_Stretch; rm.rm_vStretch(1) = vDataStretch(1) * mo_Stretch(1); rm.rm_vStretch(2) = vDataStretch(2) * mo_Stretch(2); rm.rm_vStretch(3) = vDataStretch(3) * mo_Stretch(3); rm.rm_vOffset = rm.rm_pmdModelData->md_vCompressedCenter; // check if object is inverted (in mirror) BOOL bXInverted = rm.rm_vStretch(1) < 0; BOOL bYInverted = rm.rm_vStretch(2) < 0; BOOL bZInverted = rm.rm_vStretch(3) < 0; rm.rm_ulFlags &= ~RMF_INVERTED; if( bXInverted != bYInverted != bZInverted != _aprProjection->pr_bInverted) rm.rm_ulFlags |= RMF_INVERTED; // prepare projections _pfModelProfile.StartTimer( CModelProfile::PTI_INITPROJECTION); _pfModelProfile.IncrementTimerAveragingCounter( CModelProfile::PTI_INITPROJECTION); PrepareView(rm); _pfModelProfile.StopTimer( CModelProfile::PTI_INITPROJECTION); // get mip factor from projection (if needed) if( (INDEX&)rm.rm_fDistanceFactor==12345678) { FLOAT3D vObjectAbs; _aprProjection->PreClip( rm.rm_vObjectPosition, vObjectAbs); rm.rm_fDistanceFactor = _aprProjection->MipFactor( Min(vObjectAbs(3), 0.0f)); } // adjust mip factor in case of dynamic stretch factor if( mo_Stretch != FLOAT3D(1,1,1)) { rm.rm_fMipFactor = rm.rm_fDistanceFactor - Log2( Max(mo_Stretch(1),Max(mo_Stretch(2),mo_Stretch(3)))); } else { rm.rm_fMipFactor = rm.rm_fDistanceFactor; } // adjust mip factor by custom settings rm.rm_fMipFactor = rm.rm_fMipFactor*mdl_fLODMul +mdl_fLODAdd; // get current mip model using mip factor rm.rm_iMipLevel = GetMipModel( rm.rm_fMipFactor); mo_iLastRenderMipLevel = rm.rm_iMipLevel; // get current vertices mask rm.rm_pmmiMip = &rm.rm_pmdModelData->md_MipInfos[rm.rm_iMipLevel]; // don't allow any shading, if shading is turned off if( rm.rm_rtRenderType & RT_SHADING_NONE) { rm.rm_colAmbient = C_WHITE|CT_OPAQUE; rm.rm_colLight = C_BLACK; } // calculate light vector as seen from model, so that vertex normals // do not need to be transformed for lighting calculations FLOAT fLightDirection=(rm.rm_vLightDirection).Length(); if( fLightDirection>0.001f) { rm.rm_vLightDirection /= fLightDirection; } else { rm.rm_vLightDirection = FLOAT3D(0,0,0); } rm.rm_vLightObj = rm.rm_vLightDirection * !rm.rm_mObjectRotation; // precalculate rendering data if needed extern void PrepareModelForRendering( CModelData &md); PrepareModelForRendering( *rm.rm_pmdModelData); // done with setup if viewing from this model if( rm.rm_ulFlags&RMF_SPECTATOR) { _pfModelProfile.StopTimer( CModelProfile::PTI_INITMODELRENDERING); return; } _pfModelProfile.StartTimer( CModelProfile::PTI_INITATTACHMENTS); // for each attachment on this model object FOREACHINLIST( CAttachmentModelObject, amo_lnInMain, mo_lhAttachments, itamo) { _pfModelProfile.IncrementTimerAveragingCounter( CModelProfile::PTI_INITATTACHMENTS); CAttachmentModelObject *pamo = itamo; // create new render model structure pamo->amo_prm = &_armRenderModels.Push(); const BOOL bVisible = CreateAttachment( rm, *pamo); if( !bVisible) { // skip if not visible pamo->amo_prm = NULL; _armRenderModels.Pop(); continue; } // prepare if visible _pfModelProfile.StopTimer( CModelProfile::PTI_INITMODELRENDERING); _pfModelProfile.StopTimer( CModelProfile::PTI_INITATTACHMENTS); pamo->amo_moModelObject.SetupModelRendering( *pamo->amo_prm); _pfModelProfile.StartTimer( CModelProfile::PTI_INITATTACHMENTS); _pfModelProfile.StartTimer( CModelProfile::PTI_INITMODELRENDERING); }
// 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]; }
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); } }
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(); }
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; } } } }