mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-11-22 18:30:27 +01:00
1008 lines
33 KiB
C++
Executable File
1008 lines
33 KiB
C++
Executable File
/* Copyright (c) 2002-2012 Croteam Ltd.
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of version 2 of the GNU General Public License as published by
|
|
the Free Software Foundation
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
|
|
|
|
#include "Engine/StdH.h"
|
|
|
|
#include <Engine/Terrain/Terrain.h>
|
|
#include <Engine/Terrain/TerrainRender.h>
|
|
#include <Engine/Terrain/TerrainMisc.h>
|
|
|
|
// !!! FIXME: This is messing up name mangling. Need to look at this. --ryan.
|
|
#if ((defined PLATFORM_UNIX) && (defined __forceinline))
|
|
# undef __forceinline
|
|
# define __forceinline
|
|
#endif
|
|
|
|
#include <Engine/Terrain/TerrainTile.h>
|
|
|
|
extern CTerrain *_ptrTerrain;
|
|
extern FLOAT3D _vViewerAbs;
|
|
|
|
#define BORDERTEST 0
|
|
|
|
extern CStaticStackArray<GFXVertex4> _avLerpedVerices;
|
|
|
|
CTerrainTile::CTerrainTile()
|
|
{
|
|
tt_iIndex = -1;
|
|
tt_iArrayIndex = -1;
|
|
tt_iLod = -1;
|
|
tt_iRequestedLod = 0;
|
|
tt_ulTileFlags = 0;
|
|
}
|
|
|
|
// Render tile
|
|
void CTerrainTile::Render(void)
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
CTerrainTile::~CTerrainTile()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
// Release tile
|
|
void CTerrainTile::Clear()
|
|
{
|
|
}
|
|
|
|
// TEMP!!!!!
|
|
__forceinline void CTerrainTile::LerpVertexPos(GFXVertex4 &vtx, INDEX iVxTarget, INDEX iVxFirst,INDEX iVxLast)
|
|
{
|
|
GFXVertex4 &vxFirst = GetVertices()[iVxFirst];
|
|
GFXVertex4 &vxLast = GetVertices()[iVxLast];
|
|
GFXVertex4 &vxTarget = GetVertices()[iVxTarget];
|
|
|
|
FLOAT fLerpMaxPosY = Lerp(vxFirst.y,vxLast.y,0.5f);
|
|
FLOAT fLerpResultY = Lerp(vxTarget.y,fLerpMaxPosY,tt_fLodLerpFactor);
|
|
vtx.x = vxTarget.x;
|
|
vtx.y = fLerpResultY;
|
|
vtx.z = vxTarget.z;
|
|
}
|
|
|
|
/*
|
|
* Tile memory alloc
|
|
*/
|
|
|
|
INDEX CTerrainTile::ChangeTileArrays(INDEX iRequestedArrayLod)
|
|
{
|
|
// if requested lod is same as current lod
|
|
if(iRequestedArrayLod==tt_iLod) {
|
|
// Just pop all arrays
|
|
GetVertices().PopAll();
|
|
GetTexCoords().PopAll();
|
|
GetShadowMapTC().PopAll();
|
|
GetIndices().PopAll();
|
|
// if tile is in highest lod
|
|
if(tt_iLod==0) {
|
|
// pop detail uvmap
|
|
GetDetailTC().PopAll();
|
|
// for each tile layer
|
|
INDEX cttl=GetTileLayers().Count();
|
|
for(INDEX itl=0;itl<cttl;itl++) {
|
|
// pop all arrays for this layer
|
|
TileLayer &tl = GetTileLayers()[itl];
|
|
tl.tl_acColors.PopAll();
|
|
tl.tl_atcTexCoords.PopAll();
|
|
tl.tl_auiIndices.PopAll();
|
|
tl.tl_avVertices.PopAll();
|
|
}
|
|
}
|
|
return tt_iLod;
|
|
}
|
|
|
|
// release current tile arrays
|
|
ReleaseTileArrays();
|
|
// Allocate new arrays for new lod
|
|
CArrayHolder &ah = _ptrTerrain->tr_aArrayHolders[iRequestedArrayLod];
|
|
|
|
ASSERT(tt_iArrayIndex==-1);
|
|
tt_iArrayIndex = ah.GetNewArrays();
|
|
|
|
// if this is first lod
|
|
if(iRequestedArrayLod==0) {
|
|
// Add tile layers
|
|
INDEX ctLayers = _ptrTerrain->tr_atlLayers.Count();
|
|
if(ctLayers>0) {
|
|
GetTileLayers().Push(ctLayers);
|
|
}
|
|
}
|
|
return iRequestedArrayLod;
|
|
}
|
|
|
|
void CTerrainTile::ReleaseTileArrays()
|
|
{
|
|
// if tile had some arrays
|
|
if(tt_iArrayIndex != -1) {
|
|
// Free them
|
|
CArrayHolder &ahOld = _ptrTerrain->tr_aArrayHolders[tt_iLod];
|
|
ahOld.FreeArrays(tt_iArrayIndex);
|
|
tt_iArrayIndex = -1;
|
|
}
|
|
}
|
|
|
|
void CTerrainTile::EmptyTileArrays()
|
|
{
|
|
ASSERT(tt_iArrayIndex != -1);
|
|
|
|
CArrayHolder &ahCurrent = _ptrTerrain->tr_aArrayHolders[tt_iLod];
|
|
ahCurrent.EmptyArrays(tt_iArrayIndex);
|
|
}
|
|
|
|
/*
|
|
* Tile generation (TEMP)
|
|
*/
|
|
|
|
inline void CTerrainTile::AddTriangle(INDEX iind1,INDEX iind2,INDEX iind3)
|
|
{
|
|
// is this tile in highest lod
|
|
if(tt_iLod==0) {
|
|
|
|
// Is this triangle visible
|
|
GFXVertex *pvx[3];
|
|
pvx[0] = &GetVertices()[iind1];
|
|
pvx[1] = &GetVertices()[iind2];
|
|
pvx[2] = &GetVertices()[iind3];
|
|
|
|
// check if all vertices all visible
|
|
SLONG slTriangleMask = pvx[0]->shade + pvx[1]->shade + pvx[2]->shade;
|
|
if(slTriangleMask!=255*3) {
|
|
return;
|
|
}
|
|
|
|
// Add one triangle
|
|
INDEX_T *pIndices = GetIndices().Push(3);
|
|
pIndices[0] = iind1;
|
|
pIndices[1] = iind2;
|
|
pIndices[2] = iind3;
|
|
|
|
// for each layer
|
|
INDEX cttl = GetTileLayers().Count();
|
|
for(INDEX itl=0;itl<cttl;itl++) {
|
|
TileLayer &ttl = GetTileLayers()[itl];
|
|
CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[itl];
|
|
// if this is tile layer
|
|
if(tl.tl_ltType==LT_TILE) {
|
|
continue; // skip it
|
|
}
|
|
|
|
COLOR ul = ttl.tl_acColors[iind1].ub.a + ttl.tl_acColors[iind2].ub.a + ttl.tl_acColors[iind3].ub.a;
|
|
if(ul>0) {
|
|
INDEX_T *pIndices = ttl.tl_auiIndices.Push(3);
|
|
pIndices[0] = iind1;
|
|
pIndices[1] = iind2;
|
|
pIndices[2] = iind3;
|
|
}
|
|
}
|
|
} else {
|
|
INDEX_T *pIndices = GetIndices().Push(3);
|
|
pIndices[0] = iind1;
|
|
pIndices[1] = iind2;
|
|
pIndices[2] = iind3;
|
|
}
|
|
}
|
|
|
|
// Returns a height in heightmap
|
|
inline FLOAT GetHeight(INDEX ic,INDEX ir,INDEX iTileIndex)
|
|
{
|
|
CTerrainTile &tt = _ptrTerrain->tr_attTiles[iTileIndex];
|
|
// Get Y position of vertex from heightmap
|
|
INDEX icHMap = ic + tt.tt_iOffsetX*_ptrTerrain->GetQuadsPerTileRow();
|
|
INDEX irHMap = ir + tt.tt_iOffsetZ*_ptrTerrain->GetQuadsPerTileRow();
|
|
INDEX ivx = icHMap+irHMap*_ptrTerrain->tr_pixHeightMapWidth;
|
|
return (FLOAT)_ptrTerrain->tr_auwHeightMap[ivx];
|
|
}
|
|
|
|
BYTE GetVertexAlpha(INDEX ic,INDEX ir,INDEX iTileIndex,INDEX iLayer)
|
|
{
|
|
CTerrainTile &tt = _ptrTerrain->tr_attTiles[iTileIndex];
|
|
INDEX icHMap = ic + tt.tt_iOffsetX*_ptrTerrain->GetQuadsPerTileRow();
|
|
INDEX irHMap = ir + tt.tt_iOffsetZ*_ptrTerrain->GetQuadsPerTileRow();
|
|
INDEX ivx = icHMap+irHMap*_ptrTerrain->tr_pixHeightMapWidth;
|
|
CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[iLayer];
|
|
return tl.tl_aubColors[ivx];
|
|
}
|
|
|
|
// Returns vertex at specified position inside one tile
|
|
GFXVertex4 GetVertex(INDEX ic,INDEX ir,INDEX iTileIndex)
|
|
{
|
|
CTerrainTile &tt = _ptrTerrain->tr_attTiles[iTileIndex];
|
|
FLOAT fPosY = GetHeight(ic,ir,iTileIndex);
|
|
|
|
GFXVertex4 vx;
|
|
INDEX ix = ic + tt.tt_iOffsetX*_ptrTerrain->GetQuadsPerTileRow();
|
|
INDEX iz = ir + tt.tt_iOffsetZ*_ptrTerrain->GetQuadsPerTileRow();
|
|
vx.x = (FLOAT)(ix);
|
|
vx.z = (FLOAT)(iz);
|
|
vx.y = fPosY;
|
|
// Fill 'shade' with edge map value
|
|
INDEX iMask = ix + iz*_ptrTerrain->tr_pixHeightMapWidth;
|
|
vx.shade = _ptrTerrain->tr_aubEdgeMap[iMask];
|
|
|
|
return vx;
|
|
}
|
|
|
|
// Add vertex to array of vertices
|
|
void CTerrainTile::AddVertex(INDEX ic, INDEX ir)
|
|
{
|
|
GFXVertex4 &vxFinal = GetVertices().Push();
|
|
GFXTexCoord &tcShadow = GetShadowMapTC().Push();
|
|
|
|
const GFXVertex4 &vx = GetVertex(ic,ir,tt_iIndex);
|
|
vxFinal.x = vx.x * _ptrTerrain->tr_vStretch(1);
|
|
vxFinal.y = vx.y * _ptrTerrain->tr_vStretch(2);
|
|
vxFinal.z = vx.z * _ptrTerrain->tr_vStretch(3);
|
|
vxFinal.shade = vx.shade;
|
|
|
|
// if this tile is in highest lod
|
|
if(tt_iLod==0) {
|
|
// for each layer
|
|
INDEX cttl = GetTileLayers().Count();
|
|
for(INDEX itl=0;itl<cttl;itl++) {
|
|
TileLayer &ttl = GetTileLayers()[itl];
|
|
CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[itl];
|
|
// Set vertex color
|
|
GFXColor &col = ttl.tl_acColors.Push();
|
|
BYTE bAlpha = GetVertexAlpha(ic,ir,tt_iIndex,itl);
|
|
col.ul.abgr = 0x00FFFFFF;
|
|
col.ub.a = bAlpha;
|
|
// if this is normal layer
|
|
if(tl.tl_ltType == LT_NORMAL) {
|
|
// Set its texcoords
|
|
GFXTexCoord &tc = ttl.tl_atcTexCoords.Push();
|
|
tc.uv.u = (FLOAT)ic;
|
|
tc.uv.v = (FLOAT)ir;
|
|
}
|
|
}
|
|
|
|
GFXTexCoord &tcDetail = GetDetailTC().Push();
|
|
tcDetail.uv.u = ic * 2;
|
|
tcDetail.uv.v = ir * 2;
|
|
// if tile is in lowest lod
|
|
} else if(tt_iLod==_ptrTerrain->tr_iMaxTileLod) {
|
|
GFXTexCoord &tc = GetTexCoords().Push();
|
|
FLOAT fWidth = (_ptrTerrain->tr_pixHeightMapWidth-1);
|
|
FLOAT fHeight = (_ptrTerrain->tr_pixHeightMapHeight-1);
|
|
tc.uv.u = vx.x / fWidth;
|
|
tc.uv.v = vx.z / fHeight;
|
|
// tile is not in highest lod nor in lowest lod
|
|
} else {
|
|
GFXTexCoord &tc = GetTexCoords().Push();
|
|
tc.uv.u = ((vx.x - tt_iOffsetX * _ptrTerrain->GetQuadsPerTileRow()) / (_ptrTerrain->GetQuadsPerTileRow()));
|
|
tc.uv.v = ((vx.z - tt_iOffsetZ * _ptrTerrain->GetQuadsPerTileRow()) / (_ptrTerrain->GetQuadsPerTileRow()));
|
|
}
|
|
|
|
tcShadow.uv.u = vx.x / (_ptrTerrain->tr_pixHeightMapWidth-1);
|
|
tcShadow.uv.v = vx.z / (_ptrTerrain->tr_pixHeightMapHeight-1);
|
|
}
|
|
|
|
void CTerrainTile::ReGenerateTileLayer(INDEX iTileLayer)
|
|
{
|
|
FLOAT fStrX = _ptrTerrain->tr_vStretch(1);
|
|
FLOAT fStrY = _ptrTerrain->tr_vStretch(2);
|
|
FLOAT fStrZ = _ptrTerrain->tr_vStretch(3);
|
|
PIX pixHMWidth = _ptrTerrain->tr_pixHeightMapWidth;
|
|
|
|
PIX iOffsetX = tt_iOffsetX * _ptrTerrain->tr_ctQuadsInTileRow;
|
|
PIX iOffsetZ = tt_iOffsetZ * _ptrTerrain->tr_ctQuadsInTileRow;
|
|
|
|
INDEX ctQuadsPerRow = _ptrTerrain->tr_ctQuadsInTileRow;
|
|
|
|
CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[iTileLayer];
|
|
TileLayer &ttl = GetTileLayers()[iTileLayer];
|
|
INDEX ctVertices = ctQuadsPerRow*ctQuadsPerRow*4; // four vertices per one quad
|
|
INDEX ctIndices = ctQuadsPerRow*ctQuadsPerRow*6; // six indices per one quad
|
|
|
|
ASSERT(ttl.tl_avVertices.Count()==0 && ttl.tl_atcTexCoords.Count()==0 && ttl.tl_auiIndices.Count()==0);
|
|
GFXVertex *pvtx = ttl.tl_avVertices.Push(ctVertices);
|
|
GFXTexCoord *ptc = ttl.tl_atcTexCoords.Push(ctVertices);
|
|
INDEX_T *pind = ttl.tl_auiIndices.Push(ctIndices);
|
|
UBYTE *pubMask = tl.tl_aubColors;
|
|
|
|
INDEX ivx = 0;
|
|
INDEX iind = 0;
|
|
BOOL bFacing = FALSE;
|
|
INDEX iTilesInRowLog2 = FastLog2(tl.tl_ctTilesInRow);
|
|
// for each quad in tile
|
|
for(INDEX iz=0;iz<ctQuadsPerRow;iz++) {
|
|
for(INDEX ix=0;ix<ctQuadsPerRow;ix++) {
|
|
PIX pix = ix+iOffsetX + (iz+iOffsetZ)*pixHMWidth;
|
|
|
|
// Add four vertices for this quad
|
|
pvtx[ivx ].x = (FLOAT)(iOffsetX+ix+0)*fStrX;
|
|
pvtx[ivx ].y = (FLOAT)_ptrTerrain->tr_auwHeightMap[pix] * fStrY;
|
|
pvtx[ivx ].z = (FLOAT)(iOffsetZ+iz+0)*fStrZ;
|
|
pvtx[ivx+1].x = (FLOAT)(iOffsetX+ix+1)*fStrX;
|
|
pvtx[ivx+1].y = (FLOAT)_ptrTerrain->tr_auwHeightMap[pix+1] * fStrY;
|
|
pvtx[ivx+1].z = (FLOAT)(iOffsetZ+iz+0)*fStrZ;
|
|
pvtx[ivx+2].x = (FLOAT)(iOffsetX+ix+0)*fStrX;
|
|
pvtx[ivx+2].y = (FLOAT)_ptrTerrain->tr_auwHeightMap[pix+pixHMWidth] * fStrY;
|
|
pvtx[ivx+2].z = (FLOAT)(iOffsetZ+iz+1)*fStrZ;
|
|
pvtx[ivx+3].x = (FLOAT)(iOffsetX+ix+1)*fStrX;
|
|
pvtx[ivx+3].y = (FLOAT)_ptrTerrain->tr_auwHeightMap[pix+pixHMWidth+1] * fStrY;
|
|
pvtx[ivx+3].z = (FLOAT)(iOffsetZ+iz+1)*fStrZ;
|
|
|
|
UBYTE ubMask = pubMask[pix];
|
|
INDEX iTile = ubMask&TL_TILE_INDEX; // First 4 bits
|
|
BOOL bFlipX = (ubMask&TL_FLIPX)>>TL_FLIPX_SHIFT;
|
|
BOOL bFlipY = (ubMask&TL_FLIPY)>>TL_FLIPY_SHIFT;
|
|
BOOL bSwapXY = (ubMask&TL_SWAPXY)>>TL_SWAPXY_SHIFT;
|
|
BOOL bVisible = (ubMask&TL_VISIBLE)>>TL_VISIBLE_SHIFT;
|
|
INDEX iTileX = iTile&(tl.tl_ctTilesInRow-1);
|
|
INDEX iTileY = iTile>>iTilesInRowLog2;
|
|
|
|
ASSERT(iTileX<tl.tl_ctTilesInRow);
|
|
ASSERT(iTileY<tl.tl_ctTilesInCol);
|
|
|
|
// Add four texcoords
|
|
ptc[ivx ].uv.u = tl.tl_fTileU * (iTileX + bFlipX);
|
|
ptc[ivx ].uv.v = tl.tl_fTileV * (iTileY + bFlipY);
|
|
ptc[ivx+1].uv.u = tl.tl_fTileU * (iTileX + 1-bFlipX);
|
|
ptc[ivx+1].uv.v = tl.tl_fTileV * (iTileY + bFlipY);
|
|
ptc[ivx+2].uv.u = tl.tl_fTileU * (iTileX + bFlipX);
|
|
ptc[ivx+2].uv.v = tl.tl_fTileV * (iTileY + 1-bFlipY);
|
|
ptc[ivx+3].uv.u = tl.tl_fTileU * (iTileX + 1-bFlipX);
|
|
ptc[ivx+3].uv.v = tl.tl_fTileV * (iTileY + 1-bFlipY);
|
|
|
|
if(bSwapXY) {
|
|
Swap(ptc[ivx+1].uv.u,ptc[ivx+2].uv.u);
|
|
Swap(ptc[ivx+1].uv.v,ptc[ivx+2].uv.v);
|
|
}
|
|
|
|
// if tile is visible
|
|
if(bVisible) {
|
|
// Add six indices
|
|
if(bFacing) {
|
|
pind[iind ] = ivx;
|
|
pind[iind+1] = ivx+2;
|
|
pind[iind+2] = ivx+1;
|
|
pind[iind+3] = ivx+1;
|
|
pind[iind+4] = ivx+2;
|
|
pind[iind+5] = ivx+3;
|
|
} else {
|
|
pind[iind ] = ivx+2;
|
|
pind[iind+1] = ivx+3;
|
|
pind[iind+2] = ivx;
|
|
pind[iind+3] = ivx;
|
|
pind[iind+4] = ivx+3;
|
|
pind[iind+5] = ivx+1;
|
|
}
|
|
iind+=6;
|
|
} else {
|
|
ctIndices-=6;
|
|
}
|
|
|
|
ivx+=4;
|
|
bFacing=!bFacing;
|
|
}
|
|
bFacing=!bFacing;
|
|
}
|
|
|
|
// discard triangles that arn't visible
|
|
if(ctIndices<ctQuadsPerRow*ctQuadsPerRow*6) {
|
|
ttl.tl_auiIndices.PopUntil(ctIndices);
|
|
}
|
|
// discart vertices that arn't visible
|
|
if(ctVertices<ctQuadsPerRow*ctQuadsPerRow*4) {
|
|
ttl.tl_avVertices.PopUntil(ctVertices);
|
|
ttl.tl_atcTexCoords.PopUntil(ctVertices);
|
|
}
|
|
|
|
ASSERT(ivx==ctVertices);
|
|
ASSERT(iind==ctIndices);
|
|
}
|
|
|
|
// Regenerate tile
|
|
void CTerrainTile::ReGenerate()
|
|
{
|
|
// remember lod before regen
|
|
INDEX iOldLod = tt_iLod;
|
|
// Allocate arrays for requested lod
|
|
tt_iLod = ChangeTileArrays(tt_iRequestedLod);
|
|
|
|
// for each vertex in row
|
|
INDEX iStep = 1<<tt_iLod;
|
|
INDEX ir;
|
|
for(ir=0;ir<tt_ctVtxY;ir+=iStep) {
|
|
// for each vertex in col
|
|
for(INDEX ic=0;ic<tt_ctVtxX;ic+=iStep) {
|
|
// add vertex in this row and col
|
|
AddVertex(ic,ir);
|
|
}
|
|
}
|
|
|
|
// Calculate number of quads for this lod
|
|
INDEX ctQuads = _ptrTerrain->GetQuadsPerTileRow()>>tt_iLod;
|
|
|
|
// Fill middle of tile with triangles
|
|
for(ir=1;ir<ctQuads-1;ir++) {
|
|
for(INDEX ic=1;ic<ctQuads-1;ic++) {
|
|
INDEX ivx = ic+ir*(ctQuads+1);
|
|
if(ivx%2) {
|
|
AddTriangle(ivx,ivx+ctQuads+1,ivx+1);
|
|
AddTriangle(ivx+1,ivx+ctQuads+1,ivx+ctQuads+2);
|
|
} else {
|
|
AddTriangle(ivx+ctQuads+1,ivx+ctQuads+2,ivx);
|
|
AddTriangle(ivx,ivx+ctQuads+2,ivx+1);
|
|
}
|
|
}
|
|
}
|
|
|
|
//INDEX ctVtxBefore = GetVertices().Count();
|
|
//INDEX ctTrisBefore = GetIndices().Count()/3;
|
|
|
|
// tt_ctNormalVertices = GetVertexCount();
|
|
// Generate borders for tile
|
|
ReGenerateTopBorder();
|
|
ReGenerateLeftBorder();
|
|
ReGenerateBottomBorder();
|
|
ReGenerateRightBorder();
|
|
|
|
// if this tile is in first lod
|
|
if(tt_iLod==0) {
|
|
// for each layer
|
|
INDEX cttl = _ptrTerrain->tr_atlLayers.Count();
|
|
for(INDEX itl=0;itl<cttl;itl++) {
|
|
CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[itl];
|
|
// if this is tile layer
|
|
if(tl.tl_ltType == LT_TILE) {
|
|
// Regenerate it
|
|
ReGenerateTileLayer(itl);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL bAllowTopMapRegen = !(GetFlags()&TT_NO_TOPMAP_REGEN);
|
|
// if top map is allowed to be regenerated
|
|
if(bAllowTopMapRegen) {
|
|
// if tile is not in highest nor in lowest lod
|
|
if(tt_iLod>0 && tt_iLod<_ptrTerrain->tr_iMaxTileLod) {
|
|
// if top map regen is forced or tile has changed lod
|
|
BOOL bForceTopMapRegen = (GetFlags()&TT_FORCE_TOPMAP_REGEN);
|
|
if(bForceTopMapRegen || iOldLod!=tt_iLod) {
|
|
// Update tile top map
|
|
_ptrTerrain->UpdateTopMap(tt_iIndex);
|
|
// remove flag that forced top map regen
|
|
RemoveFlag(TT_FORCE_TOPMAP_REGEN);
|
|
// allow terrain to regenerete top map
|
|
_ptrTerrain->AddFlag(TR_ALLOW_TOP_MAP_REGEN);
|
|
}
|
|
}
|
|
// if not
|
|
} else {
|
|
// regenerate it next time
|
|
RemoveFlag(TT_NO_TOPMAP_REGEN);
|
|
}
|
|
|
|
// if flag to resize quad tree node has been set
|
|
if(GetFlags()&TT_QUADTREENODE_REGEN) {
|
|
// update quad tree node
|
|
UpdateQuadTreeNode();
|
|
// node has been updated
|
|
RemoveFlag(TT_QUADTREENODE_REGEN);
|
|
}
|
|
|
|
INDEX ctBorderVertices = tt_ctBorderVertices[0] + tt_ctBorderVertices[1] +
|
|
tt_ctBorderVertices[2] + tt_ctBorderVertices[3];
|
|
// if tile is in lowest lod, has not lerp factor and no border vertices
|
|
if(tt_iLod==_ptrTerrain->tr_iMaxTileLod && tt_fLodLerpFactor==0.0f && ctBorderVertices == 0) {
|
|
// mark it as available for batch rendering
|
|
AddFlag(TT_IN_LOWEST_LOD);
|
|
} else {
|
|
RemoveFlag(TT_IN_LOWEST_LOD);
|
|
}
|
|
|
|
}
|
|
|
|
INDEX CTerrainTile::CalculateLOD(void)
|
|
{
|
|
QuadTreeNode &qtn = _ptrTerrain->tr_aqtnQuadTreeNodes[tt_iIndex];
|
|
FLOAT fDistance = (qtn.qtn_aabbox.Center() - _vViewerAbs).Length() - qtn.qtn_aabbox.Size().Length() / 2;
|
|
|
|
// if flag has been set for tile to regenerate without lod
|
|
if(GetFlags()&TT_NO_LODING) {
|
|
// set new lod at 0
|
|
fDistance = 0;
|
|
// if tile is in highest lod, no need to regenerate texture
|
|
// AddFlag(TT_NO_TOPMAP_REGEN);
|
|
|
|
// remove flag for no loding
|
|
RemoveFlag(TT_NO_LODING);
|
|
}
|
|
|
|
// Calculate new lod
|
|
INDEX iNewLod = Clamp((INDEX)(fDistance/_ptrTerrain->tr_fDistFactor),(INDEX)0,_ptrTerrain->tr_iMaxTileLod);
|
|
|
|
// if lod has changed
|
|
if(iNewLod!=tt_iLod) {
|
|
// add to regeneration queue
|
|
_ptrTerrain->AddTileToRegenQueue(tt_iIndex);
|
|
// for each neighbour
|
|
for(INDEX in=0;in<4;in++) {
|
|
INDEX ini = tt_aiNeighbours[in];
|
|
// if neighbour is valid
|
|
if(ini>=0) {
|
|
//CTerrainTile &ttNeigbour = _ptrTerrain->tr_attTiles[ini];
|
|
// if neighbour is in higher lod
|
|
if(TRUE) { /*ttNeigbour.tt_iLod > tt.tt_iNewLod*/
|
|
// add neighbour to regen queue
|
|
_ptrTerrain->AddTileToRegenQueue(ini);
|
|
}
|
|
}
|
|
}
|
|
// Calculate num of vertices for row and col in current lod
|
|
tt_ctLodVtxX = (_ptrTerrain->GetQuadsPerTileRow() >> iNewLod) + 1;
|
|
tt_ctLodVtxY = (_ptrTerrain->GetQuadsPerTileRow() >> iNewLod) + 1;
|
|
}
|
|
|
|
// Calculate lerp factor
|
|
tt_fLodLerpFactor = Clamp(fDistance/_ptrTerrain->tr_fDistFactor - iNewLod,0.0f,1.0f);
|
|
// if tile is in lowest lod
|
|
if(iNewLod == _ptrTerrain->tr_iMaxTileLod) {
|
|
// no lerping for this tile
|
|
tt_fLodLerpFactor = 0.0f;
|
|
}
|
|
// return new lod
|
|
return iNewLod;
|
|
}
|
|
|
|
// Update quad tree node
|
|
void CTerrainTile::UpdateQuadTreeNode()
|
|
{
|
|
// resize aabox for this node
|
|
FLOATaabbox3D bboxNewBox;
|
|
GFXVertex4 *pavVertices;
|
|
INDEX_T *paiIndices;
|
|
INDEX ctVertices;
|
|
INDEX ctIndices;
|
|
QuadTreeNode &qtn = _ptrTerrain->tr_aqtnQuadTreeNodes[tt_iIndex];
|
|
|
|
// prepare box that will extract vertices (x and z of old box are allready valid)
|
|
bboxNewBox = qtn.qtn_aabbox;
|
|
bboxNewBox.minvect(2) = 0;
|
|
bboxNewBox.maxvect(2) = 65536 * _ptrTerrain->tr_vStretch(2);
|
|
|
|
// extract vertices in box
|
|
ExtractPolygonsInBox(_ptrTerrain,bboxNewBox,&pavVertices,&paiIndices,ctVertices,ctIndices);
|
|
|
|
// if some vertices exists
|
|
if(ctVertices>0) {
|
|
qtn.qtn_aabbox = FLOAT3D(pavVertices->x,pavVertices->y,pavVertices->z);
|
|
pavVertices++;
|
|
} else {
|
|
ASSERTALWAYS("Some vertices must exisits for tile bbox");
|
|
}
|
|
|
|
// for each vertex in box after first
|
|
for(INDEX ivx=1;ivx<ctVertices;ivx++) {
|
|
// add vertex to box
|
|
qtn.qtn_aabbox |= FLOAT3D(pavVertices->x,pavVertices->y,pavVertices->z);
|
|
pavVertices++;
|
|
}
|
|
|
|
// notify terrain that it needs to update higher levels of quad tree
|
|
_ptrTerrain->AddFlag(TR_REBUILD_QUADTREE);
|
|
}
|
|
|
|
// Regenerate top border
|
|
void CTerrainTile::ReGenerateTopBorder()
|
|
{
|
|
INDEX iTopTileIndex = tt_aiNeighbours[NB_TOP];
|
|
INDEX iTopBorderLod = tt_iLod;
|
|
// If top neighbour exists
|
|
if(iTopTileIndex!=(-1)) {
|
|
CTerrainTile &ttTop = _ptrTerrain->tr_attTiles[iTopTileIndex];
|
|
iTopBorderLod = ttTop.tt_iRequestedLod; // !!!! iLod 2 iRequested
|
|
}
|
|
#if BORDERTEST
|
|
iTopBorderLod = 0;
|
|
#endif
|
|
|
|
|
|
INDEX iStep = 1<<tt_iLod; // Tile step in vertices for this lod
|
|
INDEX iBorderStep = 1<<iTopBorderLod; // Border tile step for border lod
|
|
INDEX ctQuads = tt_ctVtxX-iStep; // Number of quads in this tile
|
|
INDEX ctVtxInsert = iStep-iBorderStep; // Number of vertices to insert in each quad
|
|
INDEX iLastVx = 0; // Last vertex inserted in quads
|
|
INDEX icVtx = 1; // Existing tile vertex index in column, using step one
|
|
INDEX iVtxRow = 0; // Row to add vertices in
|
|
INDEX iBaseFanVtx = (tt_ctVtxX-1) / iStep + 3; // Index of fan triangle to connect to
|
|
|
|
tt_iFirstBorderVertex[NB_TOP] = GetVertices().Count();
|
|
|
|
// Add half of topleft corner
|
|
INDEX icb;
|
|
for(icb=0;icb<ctVtxInsert;icb+=iBorderStep) {
|
|
AddVertex(icb+iBorderStep,0);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx-1,ivxAdded,iLastVx);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close top left fan
|
|
AddTriangle(iBaseFanVtx-1,icVtx,iLastVx);
|
|
|
|
// Insert aditional vertices into each quad in top row after first
|
|
for(INDEX ic=iStep;ic<ctQuads-iStep;ic+=iStep) {
|
|
iLastVx = icVtx;
|
|
if(icVtx%2) {
|
|
// for each vertex nedeed to be inserted in this quad
|
|
for(INDEX icb=0;icb<ctVtxInsert;icb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(ic+icb+iBorderStep,iVtxRow);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx-1,ivxAdded,iLastVx);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close fan
|
|
AddTriangle(iBaseFanVtx-1,icVtx+1,iLastVx);
|
|
// Add last fan triangle
|
|
AddTriangle(iBaseFanVtx,icVtx+1,iBaseFanVtx-1);
|
|
} else {
|
|
// Add first fan triangle
|
|
AddTriangle(iBaseFanVtx,icVtx,iBaseFanVtx-1);
|
|
// for each vertex nedeed to be inserted in this quad
|
|
for(INDEX icb=0;icb<ctVtxInsert;icb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(ic+icb+iBorderStep,iVtxRow);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx,ivxAdded,iLastVx);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close fan
|
|
AddTriangle(iBaseFanVtx,icVtx+1,iLastVx);
|
|
}
|
|
iBaseFanVtx++;
|
|
icVtx++;
|
|
}
|
|
|
|
iLastVx = icVtx;
|
|
// Add half of topright corner
|
|
for(icb=0;icb<ctVtxInsert;icb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(icb+iBorderStep+ctQuads-1,0);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx-1,ivxAdded,iLastVx);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close top right fan
|
|
AddTriangle(iBaseFanVtx-1,icVtx+1,iLastVx);
|
|
|
|
tt_ctBorderVertices[NB_TOP] = GetVertices().Count() - tt_iFirstBorderVertex[NB_TOP];
|
|
}
|
|
// Regenerate left border
|
|
void CTerrainTile::ReGenerateLeftBorder()
|
|
{
|
|
INDEX iLeftTileIndex = tt_aiNeighbours[NB_LEFT];
|
|
INDEX iLeftBorderLod = tt_iLod;
|
|
// If top neighbour exists
|
|
if(iLeftTileIndex!=(-1)) {
|
|
CTerrainTile &ttLeft = _ptrTerrain->tr_attTiles[iLeftTileIndex];
|
|
iLeftBorderLod = ttLeft.tt_iRequestedLod;
|
|
}
|
|
#if BORDERTEST
|
|
iLeftBorderLod = 0;
|
|
#endif
|
|
|
|
|
|
INDEX iStep = 1<<tt_iLod; // Tile step in vertices for this lod
|
|
INDEX iBorderStep = 1<<iLeftBorderLod; // Border tile step for border lod
|
|
INDEX ctQuads = tt_ctVtxX-iStep;// Number of quads in this tile
|
|
INDEX ctVtxInsert = iStep-iBorderStep; // Number of vertices to insert in each quad
|
|
INDEX iLastVx = 0; // Last vertex inserted in quads
|
|
INDEX iVtxCol = 0; // Col to add vertices in
|
|
INDEX iBaseStep = (tt_ctVtxX-1) / iStep + 1;
|
|
INDEX irVtx = iBaseStep; // Existing tile vertex index in row, using step one
|
|
INDEX iBaseFanVtx = iBaseStep + 1; // Index of fan triangle to connect to
|
|
|
|
tt_iFirstBorderVertex[NB_LEFT] = GetVertices().Count();
|
|
|
|
// Add half of topleft corner
|
|
INDEX irb;
|
|
for(irb=0;irb<ctVtxInsert;irb+=iBorderStep) {
|
|
AddVertex(iVtxCol,irb+iBorderStep);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx,iLastVx,ivxAdded);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close top left fan
|
|
AddTriangle(iBaseFanVtx,iLastVx,irVtx);
|
|
|
|
// Insert aditional vertices into each quad in top row after first
|
|
for(INDEX ir=iStep;ir<ctQuads-iStep;ir+=iStep) {
|
|
iLastVx = irVtx;
|
|
if(irVtx%2) {
|
|
// for each vertex nedeed to be inserted in this quad
|
|
for(INDEX irb=0;irb<ctVtxInsert;irb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(iVtxCol,ir+irb+iBorderStep);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx,iLastVx,ivxAdded);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close fan
|
|
AddTriangle(iBaseFanVtx,iLastVx,irVtx+iBaseStep);
|
|
// Add last fan triangle
|
|
AddTriangle(iBaseFanVtx+iBaseStep,iBaseFanVtx,irVtx+iBaseStep);
|
|
} else {
|
|
// Add first fan triangle
|
|
AddTriangle(iBaseFanVtx,iLastVx,iBaseFanVtx+iBaseStep);
|
|
// for each vertex nedeed to be inserted in this quad
|
|
for(INDEX irb=0;irb<ctVtxInsert;irb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(iVtxCol,ir+irb+iBorderStep);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx+iBaseStep,iLastVx,ivxAdded);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close fan
|
|
AddTriangle(iBaseFanVtx+iBaseStep,iLastVx,irVtx+iBaseStep);
|
|
}
|
|
iBaseFanVtx+=iBaseStep;
|
|
irVtx+=iBaseStep;
|
|
}
|
|
|
|
iLastVx = irVtx;
|
|
// Add half of bottomleft corner
|
|
for(irb=0;irb<ctVtxInsert;irb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(iVtxCol,irb+iBorderStep+ctQuads-1);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx,iLastVx,ivxAdded);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close top right fan
|
|
AddTriangle(iBaseFanVtx,iLastVx,irVtx+iBaseStep);
|
|
|
|
tt_ctBorderVertices[NB_LEFT] = GetVertices().Count() - tt_iFirstBorderVertex[NB_LEFT];
|
|
}
|
|
// Regenerate right border
|
|
void CTerrainTile::ReGenerateRightBorder()
|
|
{
|
|
INDEX iRightTileIndex = tt_aiNeighbours[NB_RIGHT];
|
|
INDEX iRightBorderLod = tt_iLod;
|
|
// If top neighbour exists
|
|
if(iRightTileIndex!=(-1)) {
|
|
CTerrainTile &ttRight = _ptrTerrain->tr_attTiles[iRightTileIndex];
|
|
iRightBorderLod = ttRight.tt_iRequestedLod;
|
|
}
|
|
#if BORDERTEST
|
|
iRightBorderLod = 0;
|
|
#endif
|
|
|
|
|
|
INDEX iStep = 1<<tt_iLod; // Tile step in vertices for this lod
|
|
INDEX iBorderStep = 1<<iRightBorderLod; // Border tile step for border lod
|
|
INDEX ctQuads = tt_ctVtxX-iStep;// Number of quads in this tile
|
|
INDEX ctVtxInsert = iStep-iBorderStep; // Number of vertices to insert in each quad
|
|
INDEX iLastVx = 0; // Last vertex inserted in quads
|
|
INDEX iVtxCol = tt_ctVtxX-1; // Col to add vertices in
|
|
INDEX iBaseStep = (tt_ctVtxX-1) / iStep + 1;
|
|
INDEX irVtx = iBaseStep-1; // Existing tile vertex index in row, using step one
|
|
INDEX iBaseFanVtx = iBaseStep - 2 +iBaseStep; // Index of fan triangle to connect to
|
|
|
|
tt_iFirstBorderVertex[NB_RIGHT] = GetVertices().Count();
|
|
|
|
iLastVx = irVtx;
|
|
// Add half of topleft corner
|
|
INDEX irb;
|
|
for(irb=0;irb<ctVtxInsert;irb+=iBorderStep) {
|
|
AddVertex(iVtxCol,irb+iBorderStep);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx,ivxAdded,iLastVx);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
|
|
// Close top left fan
|
|
AddTriangle(iBaseFanVtx,irVtx+iBaseStep,iLastVx);
|
|
irVtx+=iBaseStep;
|
|
// Insert aditional vertices into each quad in top row after first
|
|
for(INDEX ir=iStep;ir<ctQuads-iStep;ir+=iStep) {
|
|
iLastVx = irVtx;
|
|
if(irVtx%2) {
|
|
// Add first fan triangle
|
|
AddTriangle(iBaseFanVtx,iBaseFanVtx+iBaseStep,iLastVx+iBaseStep);
|
|
// for each vertex nedeed to be inserted in this quad
|
|
for(INDEX irb=0;irb<ctVtxInsert;irb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(iVtxCol,ir+irb+iBorderStep);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx,ivxAdded,iLastVx);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close fan
|
|
AddTriangle(iBaseFanVtx,irVtx+iBaseStep,iLastVx);
|
|
} else {
|
|
// Add first fan triangle
|
|
AddTriangle(iBaseFanVtx,iBaseFanVtx+iBaseStep,iLastVx);
|
|
// for each vertex nedeed to be inserted in this quad
|
|
for(INDEX irb=0;irb<ctVtxInsert;irb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(iVtxCol,ir+irb+iBorderStep);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx+iBaseStep,ivxAdded,iLastVx);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close fan
|
|
AddTriangle(iBaseFanVtx+iBaseStep,irVtx+iBaseStep,iLastVx);
|
|
|
|
}
|
|
iBaseFanVtx+=iBaseStep;
|
|
irVtx+=iBaseStep;
|
|
}
|
|
|
|
iLastVx = irVtx;
|
|
// Add half of bottomleft corner
|
|
for(irb=0;irb<ctVtxInsert;irb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(iVtxCol,irb+iBorderStep+ctQuads-1);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx,ivxAdded,iLastVx);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close top right fan
|
|
AddTriangle(iBaseFanVtx,irVtx+iBaseStep,iLastVx);
|
|
|
|
tt_ctBorderVertices[NB_RIGHT] = GetVertices().Count() - tt_iFirstBorderVertex[NB_RIGHT];
|
|
}
|
|
// Regenerate bottom border
|
|
void CTerrainTile::ReGenerateBottomBorder()
|
|
{
|
|
INDEX iBottomTileIndex = tt_aiNeighbours[NB_BOTTOM];
|
|
INDEX iBottomBorderLod = tt_iRequestedLod;
|
|
// If bottom neighbour exists
|
|
if(iBottomTileIndex!=(-1)) {
|
|
CTerrainTile &ttBottom = _ptrTerrain->tr_attTiles[iBottomTileIndex];
|
|
iBottomBorderLod = ttBottom.tt_iRequestedLod;
|
|
}
|
|
#if BORDERTEST
|
|
iBottomBorderLod = 0;
|
|
#endif
|
|
|
|
|
|
INDEX iStep = 1<<tt_iLod; // Tile step in vertices for this lod
|
|
INDEX iBorderStep = 1<<iBottomBorderLod;// Border tile step for border lod
|
|
INDEX ctQuads = tt_ctVtxX-iStep;// Number of quads in this tile
|
|
INDEX ctVtxInsert = iStep-iBorderStep; // Number of vertices to insert in each quad
|
|
INDEX iLastVx = 0; // Last vertex inserted in quads
|
|
INDEX iBaseFanVtx = (((tt_ctVtxX-1) / iStep)*((tt_ctVtxX-1) / iStep)) + 1; // Index of fan triangle to connect to
|
|
INDEX iVtxRow = tt_ctVtxX-1; // Row to add vertices in
|
|
INDEX icVtx = iBaseFanVtx + (tt_ctVtxX-1)/ iStep; // Existing tile vertex index in column, using step one
|
|
|
|
tt_iFirstBorderVertex[NB_BOTTOM] = GetVertices().Count();
|
|
|
|
iLastVx = icVtx-1;
|
|
// Add half of bottom left corner
|
|
INDEX icb;
|
|
for(icb=0;icb<ctVtxInsert;icb+=iBorderStep) {
|
|
AddVertex(icb+iBorderStep,iVtxRow);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx-1,iLastVx,ivxAdded);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close bottom left fan
|
|
AddTriangle(iBaseFanVtx-1,iLastVx,icVtx);
|
|
|
|
// Insert aditional vertices into each quad in top row after first
|
|
for(INDEX ic=iStep;ic<ctQuads-iStep;ic+=iStep) {
|
|
iLastVx = icVtx;
|
|
if(icVtx%2) {
|
|
// Add first fan triangle
|
|
AddTriangle(iBaseFanVtx-1,icVtx+1,iBaseFanVtx);
|
|
// for each vertex nedeed to be inserted in this quad
|
|
for(INDEX icb=0;icb<ctVtxInsert;icb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(ic+icb+iBorderStep,iVtxRow);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx-1,iLastVx,ivxAdded);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close fan
|
|
AddTriangle(iBaseFanVtx-1,iLastVx,icVtx+1);
|
|
} else {
|
|
// Add first fan triangle
|
|
AddTriangle(iBaseFanVtx-1,icVtx,iBaseFanVtx);
|
|
// for each vertex nedeed to be inserted in this quad
|
|
for(INDEX icb=0;icb<ctVtxInsert;icb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(ic+icb+iBorderStep,iVtxRow);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx,iLastVx,ivxAdded);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close fan
|
|
AddTriangle(iBaseFanVtx,iLastVx,icVtx+1);
|
|
}
|
|
iBaseFanVtx++;
|
|
icVtx++;
|
|
}
|
|
|
|
iLastVx = icVtx;
|
|
// Add half of bottomright corner
|
|
for(icb=0;icb<ctVtxInsert;icb+=iBorderStep) {
|
|
// Insert vertex into quad and add one triangle
|
|
AddVertex(icb+iBorderStep+ctQuads-1,iVtxRow);
|
|
INDEX ivxAdded = GetVertices().Count()-1;
|
|
AddTriangle(iBaseFanVtx-1,iLastVx,ivxAdded);
|
|
iLastVx = ivxAdded;
|
|
}
|
|
// Close bottom right fan
|
|
AddTriangle(iBaseFanVtx-1,iLastVx,icVtx+1);
|
|
|
|
tt_ctBorderVertices[NB_BOTTOM] = GetVertices().Count() - tt_iFirstBorderVertex[NB_BOTTOM];
|
|
}
|
|
|
|
|
|
__forceinline CStaticStackArray<GFXVertex4> &CTerrainTile::GetVertices() {
|
|
ASSERT(tt_iArrayIndex!=-1);
|
|
ASSERT(tt_iLod!=-1);
|
|
CArrayHolder &ah = _ptrTerrain->tr_aArrayHolders[tt_iLod];
|
|
TileArrays &ta = ah.ah_ataTileArrays[tt_iArrayIndex];
|
|
return ta.ta_avVertices;
|
|
}
|
|
__forceinline CStaticStackArray<GFXTexCoord> &CTerrainTile::GetTexCoords() {
|
|
ASSERT(tt_iArrayIndex!=-1);
|
|
ASSERT(tt_iLod!=-1);
|
|
CArrayHolder &ah = _ptrTerrain->tr_aArrayHolders[tt_iLod];
|
|
TileArrays &ta = ah.ah_ataTileArrays[tt_iArrayIndex];
|
|
return ta.ta_auvTexCoords;
|
|
}
|
|
__forceinline CStaticStackArray<GFXTexCoord> &CTerrainTile::GetShadowMapTC() {
|
|
ASSERT(tt_iArrayIndex!=-1);
|
|
ASSERT(tt_iLod!=-1);
|
|
CArrayHolder &ah = _ptrTerrain->tr_aArrayHolders[tt_iLod];
|
|
TileArrays &ta = ah.ah_ataTileArrays[tt_iArrayIndex];
|
|
return ta.ta_auvShadowMap;
|
|
}
|
|
__forceinline CStaticStackArray<GFXTexCoord> &CTerrainTile::GetDetailTC() {
|
|
ASSERT(tt_iArrayIndex!=-1);
|
|
ASSERT(tt_iRequestedLod==0 || tt_iLod==0);
|
|
CArrayHolder &ah = _ptrTerrain->tr_aArrayHolders[tt_iRequestedLod];
|
|
TileArrays &ta = ah.ah_ataTileArrays[tt_iArrayIndex];
|
|
return ta.ta_auvDetailMap;
|
|
}
|
|
__forceinline CStaticStackArray<INDEX_T> &CTerrainTile::GetIndices() {
|
|
ASSERT(tt_iArrayIndex!=-1);
|
|
ASSERT(tt_iLod!=-1);
|
|
CArrayHolder &ah = _ptrTerrain->tr_aArrayHolders[tt_iLod];
|
|
TileArrays &ta = ah.ah_ataTileArrays[tt_iArrayIndex];
|
|
return ta.ta_auiIndices;
|
|
}
|
|
__forceinline CStaticStackArray<TileLayer> &CTerrainTile::GetTileLayers() {
|
|
ASSERT(tt_iArrayIndex!=-1);
|
|
ASSERT(tt_iRequestedLod==0 || tt_iLod==0);
|
|
CArrayHolder &ah = _ptrTerrain->tr_aArrayHolders[tt_iRequestedLod];
|
|
TileArrays &ta = ah.ah_ataTileArrays[tt_iArrayIndex];
|
|
return ta.ta_atlLayers;
|
|
}
|
|
__forceinline CTextureData *CTerrainTile::GetTopMap()
|
|
{
|
|
ASSERT(tt_iArrayIndex!=-1);
|
|
ASSERT(tt_iLod!=-1);
|
|
ASSERT(tt_iLod!=0);
|
|
ASSERT(tt_iLod!=_ptrTerrain->tr_iMaxTileLod);
|
|
CArrayHolder &ah = _ptrTerrain->tr_aArrayHolders[tt_iRequestedLod];
|
|
TileArrays &ta = ah.ah_ataTileArrays[tt_iArrayIndex];
|
|
return ta.ta_ptdTopMap;
|
|
}
|
|
|
|
// Count used memory
|
|
SLONG CTerrainTile::GetUsedMemory(void)
|
|
{
|
|
SLONG slUsedMemory=0;
|
|
slUsedMemory += sizeof(CTerrainTile);
|
|
return slUsedMemory;
|
|
}
|