Files
FC1/Cry3DEngine/terrain_load.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

576 lines
20 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: terrain_load.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: terrain loading
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "terrain_sector.h"
#include "objman.h"
#include "detail_grass.h"
#include "terrain_water.h"
#include "3dengine.h"
#ifdef PS2
#include "File.h"
#endif
CTerrain::CTerrain( )
{
memset(this,0,sizeof(CTerrain)); // there is no virtual functions here
m_fLodLFactor=1;
m_nOldSectorsX = 0;
m_nOldSectorsY =-1;
m_pSHShore = GetRenderer()->EF_LoadShader("TerrainWaterBeach", eSH_World, EF_SYSTEM);
m_pLowResTerrainShader = GetRenderer()->EF_LoadShader("TerrainLowLOD", eSH_World, EF_SYSTEM);
m_matSecondPass.shaderItem.m_pShader = GetRenderer()->EF_LoadShader("TerrainDetailLayers", eSH_World, EF_SYSTEM);
m_fShoreSize=2;
m_pTexturePool = new CTexturePool( );
m_vPrevCameraPos=SetMinBB();
m_pViewCamera = &GetViewCamera();
m_fTextureLodRatio=1.f;
m_bOceanIsVisibe = true;
m_nDefZoomTexId = 0;
}
void CTerrain::CloseTerrainTextureFile()
{
if(m_fpTerrainTextureFile)
GetSystem()->GetIPak()->FClose(m_fpTerrainTextureFile);
m_fpTerrainTextureFile=0;
}
CTerrain::~CTerrain()
{
// UnReg isterInAllSectors(0);
if(m_arrSecInfoTable.m_nSize)
for( int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++)
{
// m_arrSecInfoTable[x][y]->ReleaseSector();
delete (m_arrSecInfoTable[x][y]);
m_arrSecInfoTable[x][y]=0;
}
if(m_fpTerrainTextureFile)
GetSystem()->GetIPak()->FClose(m_fpTerrainTextureFile);
m_fpTerrainTextureFile=0;
for(int i=0; i<MAX_SURFACE_TYPES_COUNT; i++)
{
GetRenderer()->DeleteLeafBuffer(m_DetailTexInfo[i].pVertBuff);
m_DetailTexInfo[i].pVertBuff=0;
// GetRenderer()->ReleaseIndexBuffer(&m_DetailTexInfo[i].m_Indices);
// m_DetailTexInfo[i].m_Indices.Reset();
}
if(m_pLowLodCoverMapTex)
GetRenderer()->RemoveTexture(m_pLowLodCoverMapTex);
m_pLowLodCoverMapTex=0;
if(m_ucpTmpTexBuffer)
delete [] m_ucpTmpTexBuffer;
GetRenderer()->DeleteLeafBuffer(m_pLowResTerrainLeafBuffer);
GetRenderer()->DeleteLeafBuffer(m_pReflectedTerrainLeafBuffer);
if(m_pRETerrainDetailTextureLayers)
m_pRETerrainDetailTextureLayers->Release();
m_pRETerrainDetailTextureLayers=0;
// free detail textures
for(int i=0; i<MAX_SURFACE_TYPES_COUNT; i++)
if(m_DetailTexInfo[i].nTexID>=0)
GetRenderer()->RemoveTexture(m_DetailTexInfo[i].nTexID);
delete m_pDetailObjects;
delete m_pWater;
// delete m_pBugsManager;
delete m_pTexturePool;
GetPhysicalWorld()->SetHeightfieldData(0);
}
void CTerrain::SetDetailTextures(int nId, const char * szFileName, float fScaleX, float fScaleY,
uchar ucProjAxis, const char * szSurfName)
{
if(nId>=0 && nId<MAX_SURFACE_TYPES_COUNT)
{
GetLog()->Log(" Layer %d: %s", nId, szFileName);
ITexPic * pPic = GetRenderer()->EF_LoadTexture(szFileName,FT_NORESIZE,0,eTT_Base);
m_DetailTexInfo[nId].nTexID = pPic->GetTextureID();
m_DetailTexInfo[nId].fScaleX = fScaleX;
m_DetailTexInfo[nId].fScaleY = fScaleY;
m_DetailTexInfo[nId].ucProjAxis = ucProjAxis;
m_DetailTexInfo[nId].ucThisSurfaceTypeId = nId;
CMatMan * pMatMan = Get3DEngine()->GetMatMan();
char szMatName[256]="";
sprintf(szMatName,"terrain.TerrainLayer%d", nId);
m_DetailTexInfo[nId].pMatInfo = pMatMan->FindMatInfo(szMatName);
}
else
Warning(0,0,"CTerrain::SetDetailTextures: LayerId is out fo range: %d: %s", nId, szFileName);
}
bool CTerrain::LoadTerrain(bool bEditorMode)
{
float fStartTime = GetCurAsyncTimeSec();
GetLog()->UpdateLoadingScreen("Loading terrain ... ");
if(!LoadTerrainSettingsFromXML())
{
Warning(0,0,"CTerrain::LoadTerrain: Error loading heightmap settings from XML, default values used");
m_nUnitSize = 2;
m_fInvUnitSize = 1.0f / m_nUnitSize;
m_nTerrainSize = 2048;
}
m_nSectorSize = 64;
m_nSectorsTableSize = m_nTerrainSize/m_nSectorSize;
while((128>>HMAP_BIT_SHIFT) != 128/CTerrain::GetHeightMapUnitSize())
HMAP_BIT_SHIFT++;
if(!LoadHighMap(GetLevelFilePath(HEIGHT_MAP_FILE_NAME), GetSystem()->GetIPak() ))
{
GetLog()->Log("CTerrain::LoadTerrain: Error loading %s", GetLevelFilePath(HEIGHT_MAP_FILE_NAME));
return 0;
}
InitSectors(bEditorMode);
// for phys engine
primitives::heightfield hf;
hf.Basis.SetIdentity33();
hf.origin.zero();
hf.step.x = hf.step.y = (float)CTerrain::GetHeightMapUnitSize();
hf.size.x = hf.size.y = CTerrain::GetTerrainSize()/CTerrain::GetHeightMapUnitSize();
hf.stride.set(hf.size.y+1,1);
hf.pflags = hf.pdata = &GetHMValue(0,0);
hf.heightscale = TERRAIN_Z_RATIO;
hf.typemask = hf.typehole = STYPE_BIT_MASK;
GetPhysicalWorld()->SetHeightfieldData(&hf);
// m_pMapPreviewTex = GetRenderer()->EF_LoadTexture((char*)GetLevelFilePath("terrain\\map_preview.jpg"),FT_CLAMP|FT_NOMIPS|FT_DXT1,0,eTT_Base);
m_pLowLodCoverMapTex = GetRenderer()->EF_LoadTexture((char*)GetLevelFilePath("terrain\\cover_low.dds"), FT_CLAMP,0,eTT_Base);
m_pTerrainEf = GetRenderer()->EF_LoadShader("Terrain", eSH_World, EF_SYSTEM);
// m_pTerrainZPassEf = GetRenderer()->EF_LoadShader("ZBuffPassVP", eSH_World, 0);
// m_pTerrainVPEf = GetRenderer()->EF_LoadShader("TerrainVP", eSH_World, 0);
m_pTerrainLightPassEf = GetRenderer()->EF_LoadShader("TerrainLightPass", eSH_World, EF_SYSTEM);
m_pTerrainShadowPassEf = GetRenderer()->EF_LoadShader("TerrainShadowPass", eSH_World, EF_SYSTEM);
m_pTerrainEf_WithDefaultDetailTexture = GetRenderer()->EF_LoadShader("TerrainWithDefaultDetailTexture", eSH_World, EF_SYSTEM);
m_pTerrainWithFog = GetRenderer()->EF_LoadShader("TerrainWithFog", eSH_World, EF_SYSTEM);
m_pTerrainLayerEf = GetRenderer()->EF_LoadShader("TerrainLayer",eSH_World,EF_SYSTEM);
// m_pTerrainCausticsEf = GetRenderer()->EF_LoadShader("TerrainCaustics", eSH_World, 0);
// if(m_pTerrainCausticsEf->GetFlags() & EF_NOTFOUND)
// m_pTerrainCausticsEf=0;
m_pRETerrainDetailTextureLayers = (CRETerrainDetailTextureLayers*)GetRenderer()->EF_CreateRE(eDATA_TerrainDetailTextureLayers);
m_pTerrainDetailTextureLayersEff = GetRenderer()->EF_LoadShader("TerrainDetailTextureLayers", eSH_World, EF_SYSTEM);
GetLog()->Log("Terrain was loaded in %.2f sec", GetCurAsyncTimeSec()-fStartTime );
return true;
}
int __cdecl CTerrain__Cmp_CStatObjInstForLoading_Size(const void* v1, const void* v2)
{
CStatObjInstForLoading * p1 = ((CStatObjInstForLoading*)v1);
CStatObjInstForLoading * p2 = ((CStatObjInstForLoading*)v2);
list2<StatInstGroup> & lstStaticTypes = ((C3DEngine*)Cry3DEngineBase::Get3DEngine())->GetObjManager()->m_lstStaticTypes;
CStatObj * pStatObj1 = (p1->GetID()<lstStaticTypes.Count()) ? lstStaticTypes[p1->GetID()].GetStatObj() : 0;
CStatObj * pStatObj2 = (p2->GetID()<lstStaticTypes.Count()) ? lstStaticTypes[p2->GetID()].GetStatObj() : 0;
if(!pStatObj1)
return 1;
if(!pStatObj2)
return -1;
int nSecId1 = 0;
{ // get pos
Vec3d vCenter = Vec3d(p1->GetX(),p1->GetY(),p1->GetZ()) + (pStatObj1->GetBoxMin()+pStatObj1->GetBoxMax())*0.5f*p1->GetScale();
// get sector ids
int x = (int)(((vCenter.x)/CTerrain::GetSectorSize()));
int y = (int)(((vCenter.y)/CTerrain::GetSectorSize()));
// get obj bbox
Vec3d vBMin = pStatObj1->GetBoxMin()*p1->GetScale();
Vec3d vBMax = pStatObj1->GetBoxMax()*p1->GetScale();
// if outside of the map, or too big - register in sector (0,0)
if( x<0 || x>=CTerrain::GetSectorsTableSize() || y<0 || y>=CTerrain::GetSectorsTableSize() ||
(vBMax.x - vBMin.x)>TERRAIN_SECTORS_MAX_OVERLAPPING*2 || (vBMax.y - vBMin.y)>TERRAIN_SECTORS_MAX_OVERLAPPING*2)
x = y = 0;
// get sector id
nSecId1 = (x)*CTerrain::GetSectorsTableSize() + (y);
}
int nSecId2 = 0;
{ // get pos
Vec3d vCenter = Vec3d(p2->GetX(),p2->GetY(),p2->GetZ()) + (pStatObj2->GetBoxMin()+pStatObj2->GetBoxMax())*0.5f*p2->GetScale();
// get sector ids
int x = (int)(((vCenter.x)/CTerrain::GetSectorSize()));
int y = (int)(((vCenter.y)/CTerrain::GetSectorSize()));
// get obj bbox
Vec3d vBMin = pStatObj2->GetBoxMin()*p2->GetScale();
Vec3d vBMax = pStatObj2->GetBoxMax()*p2->GetScale();
// if outside of the map, or too big - register in sector (0,0)
if( x<0 || x>=CTerrain::GetSectorsTableSize() || y<0 || y>=CTerrain::GetSectorsTableSize() ||
(vBMax.x - vBMin.x)>TERRAIN_SECTORS_MAX_OVERLAPPING*2 || (vBMax.y - vBMin.y)>TERRAIN_SECTORS_MAX_OVERLAPPING*2)
x = y = 0;
// get sector id
nSecId2 = (x)*CTerrain::GetSectorsTableSize() + (y);
}
if(nSecId1 > nSecId2)
return -1;
if(nSecId1 < nSecId2)
return 1;
if(p1->GetScale()*pStatObj1->GetRadius() > p2->GetScale()*pStatObj2->GetRadius())
return 1;
if(p1->GetScale()*pStatObj1->GetRadius() < p2->GetScale()*pStatObj2->GetRadius())
return -1;
return 0;
}
int __cdecl CTerrain__Cmp_Int(const void* v1, const void* v2)
{
if(*(uint*)v1 > *(uint*)v2)
return 1;
if(*(uint*)v1 < *(uint*)v2)
return -1;
return 0;
}
void CTerrain::LoadStatObjInstances()
{
assert(this); if(!this) return;
GetLog()->Log("Loading static object positions ...");
// RemoveAllStaticObjects();
for( int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++)
m_arrSecInfoTable[x][y]->Unload(true);
// load static object positions list
list2<CStatObjInstForLoading> static_objects;
static_objects.Load(GetLevelFilePath("objects.lst"), GetSystem()->GetIPak());
qsort(static_objects.GetElements(), static_objects.Count(),
sizeof(static_objects[0]), CTerrain__Cmp_CStatObjInstForLoading_Size);
// put objects into sectors depending on object position and fill lstUsedCGFs
list2<CStatObj*> lstUsedCGFs;
for(int i=0; i<static_objects.Count(); i++)
{
float x = static_objects[i].GetX();
float y = static_objects[i].GetY();
float z = static_objects[i].GetZ()>0 ? static_objects[i].GetZ() : GetZApr(x,y);
int nId = static_objects[i].GetID();
uchar ucBr = static_objects[i].GetBrightness();
float fScale = static_objects[i].GetScale();
if( nId>=0 && nId<m_pObjManager->m_lstStaticTypes.Count() &&
fScale>0 &&
x>=0 && x<CTerrain::GetTerrainSize() && y>=0 && y<CTerrain::GetTerrainSize() &&
m_pObjManager->m_lstStaticTypes[nId].GetStatObj() )
{
if(m_pObjManager->m_lstStaticTypes[nId].GetStatObj()->GetRadius()*fScale < GetCVars()->e_vegetation_min_size)
continue; // skip creation of very small objects
if(lstUsedCGFs.Find(m_pObjManager->m_lstStaticTypes[nId].GetStatObj())<0)
lstUsedCGFs.Add(m_pObjManager->m_lstStaticTypes[nId].GetStatObj());
CStatObjInst * pEnt = (CStatObjInst*)((C3DEngine*)Get3DEngine())->CreateVegetation();
pEnt->m_fScale = fScale;
pEnt->m_vPos = Vec3d(x,y,z);
if(!pEnt->m_pEntityRenderState)
pEnt->m_pEntityRenderState = Get3DEngine()->MakeEntityRenderState();
pEnt->SetStatObjGroupId(nId);
pEnt->m_ucBright = ucBr;
pEnt->m_vWSBoxMin = pEnt->m_vPos + m_pObjManager->m_lstStaticTypes[nId].GetStatObj()->GetBoxMin()*fScale;
pEnt->m_vWSBoxMax = pEnt->m_vPos + m_pObjManager->m_lstStaticTypes[nId].GetStatObj()->GetBoxMax()*fScale;
pEnt->Physicalize( );
}
}
// release not used CGF's
int nGroupsReleased=0;
for(int i=0; i<m_pObjManager->m_lstStaticTypes.Count(); i++)
{
CStatObj * pStatObj = m_pObjManager->m_lstStaticTypes[i].GetStatObj();
if(pStatObj && lstUsedCGFs.Find(pStatObj)<0)
{
Get3DEngine()->ReleaseObject(pStatObj);
m_pObjManager->m_lstStaticTypes[i].pStatObj = NULL;
nGroupsReleased++;
}
}
GetLog()->LogPlus(" %d objects created, %d groups released", static_objects.Count(), nGroupsReleased);
}
// returns file path for current level
const char * CTerrain::GetLevelFilePath(const char * szFileName)
{
return Get3DEngine()->GetLevelFilePath(szFileName);
}
void CTerrain::SortStaticInstancesBySize()
{
// set max view distance and sort by size
for( int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++)
m_arrSecInfoTable[x][y]->SortStaticInstancesBySize(m_arrSecInfoTable[x][y]->m_pFogVolume);
}
void CTerrain::CheckUnload()
{
m_nLoadedSectors=0;
for( int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++)
m_nLoadedSectors += m_arrSecInfoTable[x][y]->CheckUnload();
}
void CTerrain::GetStreamingStatus(int & nLoadedSectors, int & nTotalSectors)
{
nLoadedSectors = m_nLoadedSectors;
nTotalSectors = CTerrain::GetSectorsTableSize()*CTerrain::GetSectorsTableSize();
}
void CTerrain::InitFogVolumes()
{
// reset fog volume pointer in all affected terrain sectors
for(int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for(int y=0; y<CTerrain::GetSectorsTableSize(); y++)
{
CSectorInfo * pSecInfo = m_arrSecInfoTable[x][y];
// if(pSecInfo)
// pSecInfo->m_pFogVolume = 0;
SetSectorFogVolume(pSecInfo);
}
for(int v=0; v<m_lstFogVolumes.Count(); v++)
{
// register volume in renderer
int nVolumeID = m_lstFogVolumes[v].nRendererVolumeID = GetRenderer()->EF_RegisterFogVolume(
m_lstFogVolumes[v].fMaxViewDist, m_lstFogVolumes[v].vBoxMax.z, m_lstFogVolumes[v].vColor, -1, m_lstFogVolumes[v].m_bCaustics);
m_lstFogVolumes[v].nRendererVolumeID = nVolumeID;
if(m_lstFogVolumes[v].bOcean)
m_pWater->SetFogVolumrId(nVolumeID);
/*
// get 2d bounds in sectors array
int min_x = (int)(((m_lstFogVolumes[v].vBoxMin.x - 1.f)/CTerrain::GetSectorSize()));
int min_y = (int)(((m_lstFogVolumes[v].vBoxMin.y - 1.f)/CTerrain::GetSectorSize()));
int max_x = (int)(((m_lstFogVolumes[v].vBoxMax.x + 1.f)/CTerrain::GetSectorSize()));
int max_y = (int)(((m_lstFogVolumes[v].vBoxMax.y + 1.f)/CTerrain::GetSectorSize()));
if( min_x<0 ) min_x = 0; else if( min_x>=CTerrain::GetSectorsTableSize() ) min_x = CTerrain::GetSectorsTableSize()-1;
if( min_y<0 ) min_y = 0; else if( min_y>=CTerrain::GetSectorsTableSize() ) min_y = CTerrain::GetSectorsTableSize()-1;
if( max_x<0 ) max_x = 0; else if( max_x>=CTerrain::GetSectorsTableSize() ) max_x = CTerrain::GetSectorsTableSize()-1;
if( max_y<0 ) max_y = 0; else if( max_y>=CTerrain::GetSectorsTableSize() ) max_y = CTerrain::GetSectorsTableSize()-1;
// set fog volume pointer in all affected sectors
for(int x=min_x; x<=max_x; x++)
for(int y=min_y; y<=max_y; y++)
{
CSectorInfo * pSecInfo = m_arrSecInfoTable[x][y];
if(pSecInfo && pSecInfo->m_fMinZ < m_lstFogVolumes[v].vBoxMax.z )
pSecInfo->m_pFogVolume = &m_lstFogVolumes[v];
}*/
}
}
void CTerrain::SetSectorFogVolume(CSectorInfo * pSecInfo)
{
pSecInfo->m_pFogVolume = 0;
for(int v=0; v<m_lstFogVolumes.Count(); v++)
{
if(pSecInfo &&
pSecInfo->m_fMinZ < m_lstFogVolumes[v].vBoxMax.z &&
m_lstFogVolumes[v].IntersectBBox(pSecInfo->m_vBoxMin,pSecInfo->m_vBoxMax) &&
!m_lstFogVolumes[v].bIndoorOnly)
if(!m_lstFogVolumes[v].bOcean || !GetCVars()->e_use_global_fog_in_fog_volumes)
{
pSecInfo->m_pFogVolume = &m_lstFogVolumes[v];
break;
}
}
}
/*
void CTerrain::InitShadowHightTable(CObjManager * pObjManager)
{
memset(m_arrShadowHight,0,sizeof(m_arrShadowHight));
// calculate shadow high map
for( int x=0; x<CTerrain::GetSectorsTableSize(); x++ )
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++ )
{
CSectorInfo * pSecInfo = m_arrSecInfoTable[x][y];
if(!pSecInfo)
GetConsole()->Exit("CTerrain::LoadStaticMap: !pSecInfo2");
for( int i=0; i<pSecInfo->m_lstStatObjects.Count(); i++)
{
CStatObjInst * o = &pSecInfo->m_lstStatObjects[i];
Vec3d vBoxMin, vBoxMax;
pObjManager->GetStaticObjectBBox(o->m_nObjectTypeID, vBoxMin, vBoxMax);
int nSizeX = int(o->m_fScale*(vBoxMax.x-vBoxMin.x)*0.5f*0.33f);
float fSizeZ = o->m_fScale*(vBoxMax.z-vBoxMin.z);
for(int m=-nSizeX; m<=nSizeX; m++)
{
Vec3d vShadowPos = Vec3d(o->m_vPos.x+m, o->m_vPos.y, GetZApr(o->m_vPos.x, o->m_vPos.y) + fSizeZ);
for(int n=0; n<=fSizeZ*4; n++)
{
vShadowPos+=Vec3d(0,1,-0.9f);
if(vShadowPos.z < GetZApr(vShadowPos.x, vShadowPos.y))
break;
if( vShadowPos.x>=0 && vShadowPos.y>=0 && vShadowPos.x<CTerrain::GetTerrainSize() && vShadowPos.y<CTerrain::GetTerrainSize() )
if(vShadowPos.z>m_arrShadowHight[int(vShadowPos.x)][int(vShadowPos.y)])
m_arrShadowHight[int(vShadowPos.x)][int(vShadowPos.y)]=vShadowPos.z;
}
}
}
}
// set brightness of objects
for( x=0; x<CTerrain::GetSectorsTableSize(); x++ )
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++ )
{
CSectorInfo * pSecInfo = m_arrSecInfoTable[x][y];
if(!pSecInfo)
GetConsole()->Exit("CTerrain::LoadStaticMap: !pSecInfo2");
for( int i=0; i<pSecInfo->m_lstStatObjects.Count(); i++ )
{
CStatObjInst * o = &pSecInfo->m_lstStatObjects[i];
o->m_bBright = true;
int fSize = int(o->m_fMaxDist/OBJ_MAX_VIEW_DISTANCE_RATIO);
if(m_arrShadowHight[int(o->m_vPos.x)][int(o->m_vPos.y)])
if(m_arrShadowHight[int(o->m_vPos.x)][int(o->m_vPos.y)] > fSize/2 + o->m_vPos.z)
o->m_bBright = 0;
}
}
}
*/
bool CTerrain::LoadTerrainSettingsFromXML()
{
XDOM::IXMLDOMNodeListPtr pLevelInfoList;
XDOM::IXMLDOMNodePtr pLevelInfoTag;
XDOM::IXMLDOMDocumentPtr pDoc = GetSystem()->CreateXMLDocument();
if(!pDoc->load(Get3DEngine()->GetLevelFilePath("LevelData.xml")))
return 0;
pLevelInfoList = pDoc->getElementsByTagName("LevelInfo");
pLevelInfoList->reset();
XDOM::IXMLDOMNodePtr pNode = pLevelInfoList->nextNode();
{ // GlobalWaterLevel
XDOM::IXMLDOMNodePtr pGlobalWaterLevel = pNode->getAttribute("WaterLevel");
if(!pGlobalWaterLevel)
return 0;
char buff[32];
strcpy(buff, pGlobalWaterLevel->getText());
m_fGlobalWaterLevel = (float)atof(buff);
if (m_fGlobalWaterLevel == 0)
m_fGlobalWaterLevel = WATER_LEVEL_UNKNOWN;
}
{ // HeightmapUnitSize
XDOM::IXMLDOMNodePtr pHeightmapUnitSize = pNode->getAttribute("HeightmapUnitSize");
if(!pHeightmapUnitSize)
return 0;
char buff[32];
strcpy(buff, pHeightmapUnitSize->getText());
m_nUnitSize = atol(buff);
m_fInvUnitSize = 1.0f / m_nUnitSize;
if( m_nUnitSize != 1 && m_nUnitSize != 2 && m_nUnitSize != 4 &&
m_nUnitSize != 8 && m_nUnitSize != 16 && m_nUnitSize != 32 )
return 0;
}
{ // HeightmapSize
XDOM::IXMLDOMNodePtr pHeightmapSize = pNode->getAttribute("HeightmapSize");
if(!pHeightmapSize)
return 0;
char buff[32];
strcpy(buff, pHeightmapSize->getText());
m_nTerrainSize = atol(buff);
if( m_nTerrainSize != 64 &&
m_nTerrainSize != 128 &&
m_nTerrainSize != 256 &&
m_nTerrainSize != 512 &&
m_nTerrainSize != 1024 &&
m_nTerrainSize != 2048 &&
m_nTerrainSize != 4096 )
return 0;
m_nTerrainSize *= m_nUnitSize;
}
/*
{ // SectorsTableSize
XDOM::IXMLDOMNodePtr pSectorsTableSize = pNode->getAttribute("SectorsTableSize");
if(!pSectorsTableSize)
return true; // use default if not found
char buff[32];
strcpy(buff, pSectorsTableSize->getText());
m_nSectorsTableSize = atol(buff);
if( m_nSectorsTableSize != 16 && m_nSectorsTableSize != 32 && m_nSectorsTableSize != 64 )
return 0;
}
*/
return true;
}