//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2002. // ------------------------------------------------------------------------- // File name: terrain.cpp // Version: v1.00 // Created: 28/5/2001 by Vladimir Kajalin // Compilers: Visual Studio.NET // Description: check vis // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "terrain_sector.h" #include "StatObj.h" #include "objman.h" #include "cbuffer.h" #include "terrain_water.h" #include "detail_grass.h" #include "VisAreas.h" void CTerrain::PreCacheArea(const Vec3d & vPos, float fRadius) { // if(!m_pObjManager) return; #ifndef _DEBUG #if !defined(_XBOX) && !defined(LINUX) assert(GetConsole()->Exit("Assert should do nothing in release mode")); // just check #endif // _XBOX #endif // DEBUG m_nUploadsInFrame = -10000; GetLog()->UpdateLoadingScreen("Preloading terrain textures for (%.1f, %.1f, %.1f) ...", vPos.x,vPos.y,vPos.z); int nLoaded=0; for( int x=0; xm_fDistance = GetDist2D( float(m_arrSecInfoTable[x][y]->m_nOriginX+(CTerrain::GetSectorSize()>>1)), float(m_arrSecInfoTable[x][y]->m_nOriginY+(CTerrain::GetSectorSize()>>1)), vPos.x, vPos.y ) - (CTerrain::GetSectorSize()>>1); if(m_arrSecInfoTable[x][y]->m_fDistance < fRadius) { m_arrSecInfoTable[x][y]->SetLOD(); if(IsSectorNonMergable(m_arrSecInfoTable[x][y])) { m_arrSecInfoTable[x][y]->SetTextures(); nLoaded++; } m_arrSecInfoTable[x][y]->m_cLastTimeUsed = fastftol_positive(GetCurTimeSec()) + 20; } } GetLog()->LogPlus(" %d sectors loaded", nLoaded); m_nUploadsInFrame = 0; } int CTerrain::GetSecMML(int x, int y) { assert(x/CTerrain::GetSectorSize()>=0); assert(y/CTerrain::GetSectorSize()>=0); assert(x/CTerrain::GetSectorSize()m_cGeometryMML; } void CTerrain::AddVisSetcor(CSectorInfo * newsec) { m_lstVisSectors.Add(newsec); } void CTerrain::LinkVisSetcors() { for(int i=0; im_nOriginX/CTerrain::GetSectorSize(); int sy1 = info->m_nOriginY/CTerrain::GetSectorSize(); if(sx1+1CheckGeomCompWithLOD(info->m_cGeometryMML); if(sy1+1CheckGeomCompWithLOD(info->m_cGeometryMML); if(sx1>0) m_arrSecInfoTable[sx1-1][sy1]->CheckGeomCompWithLOD(info->m_cGeometryMML); if(sy1>0) m_arrSecInfoTable[sx1][sy1-1]->CheckGeomCompWithLOD(info->m_cGeometryMML); } } void CTerrain::RenderTerrain( CObjManager * pObjManager, const int & DrawFlags ) { FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE ); m_pObjManager = pObjManager; // precache tarrain data if camera was teleported more than 32 meters if(m_nRenderStackLevel==0) { if(GetDistance(m_vPrevCameraPos, GetViewCamera().GetPos()) > 32) PreCacheArea(GetViewCamera().GetPos(), GetViewCamera().GetZMax()*1.5f); m_vPrevCameraPos = GetViewCamera().GetPos(); } if(m_nRenderStackLevel==0) m_fDistanceToSectorWithWater=-1; m_ucTerrainFrame++; m_lstVisSectors.Clear(); if(!m_nRenderStackLevel) m_lstReflectedTerrainIdxArray.Clear(); m_pObjManager->m_lstFarObjects[m_nRenderStackLevel].Clear(); m_vCameraPos = m_pViewCamera->GetPos(); RefineSector(0, CTerrain::GetTerrainSize(), 0, CTerrain::GetTerrainSize(), 0); LinkVisSetcors(); if(m_nRenderStackLevel==0) { m_bOceanIsVisibe = m_fDistanceToSectorWithWater > -1 || !m_lstVisSectors.Count(); m_fDistanceToSectorWithWater-=CTerrain::GetSectorSize()*0.5f; if(m_fDistanceToSectorWithWater<1.0f) m_fDistanceToSectorWithWater=1.0f; if(!m_lstVisSectors.Count()) m_fDistanceToSectorWithWater=0; m_fDistanceToSectorWithWater = max(m_fDistanceToSectorWithWater, (m_pViewCamera->GetPos().z-m_fGlobalWaterLevel)*0.05f); } if(m_pDetailObjects) if(DrawFlags & DLD_DETAIL_OBJECTS) m_pDetailObjects->RenderDetailGrass(this); } void CSectorInfo :: CheckGeomCompWithLOD(int minMML) { if(m_cLastFrameUsed == m_pTerrain->m_ucTerrainFrame) if(m_cGeometryMML < 100) if(m_cGeometryMML>minMML+1) { m_cGeometryMML = minMML+1; int sx1 = m_nOriginX/CTerrain::GetSectorSize(); int sy1 = m_nOriginY/CTerrain::GetSectorSize(); if(sx1+1m_arrSecInfoTable[sx1+1][sy1]->CheckGeomCompWithLOD(m_cGeometryMML); if(sy1+1m_arrSecInfoTable[sx1][sy1+1]->CheckGeomCompWithLOD(m_cGeometryMML); if(sx1>0) m_pTerrain->m_arrSecInfoTable[sx1-1][sy1]->CheckGeomCompWithLOD(m_cGeometryMML); if(sy1>0) m_pTerrain->m_arrSecInfoTable[sx1][sy1-1]->CheckGeomCompWithLOD(m_cGeometryMML); } } // todo: use real quadtree here void CTerrain::RefineSector(int x1, int x2, int y1, int y2, bool bAllIN) { FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled ); int xm = (x1+x2)>>1; int ym = (y1+y2)>>1; if((x2-x1) > CTerrain::GetSectorSize()) { Vec3d bmin((float)x1-TERRAIN_SECTORS_MAX_OVERLAPPING, (float)y1-TERRAIN_SECTORS_MAX_OVERLAPPING,-256.f); Vec3d bmax((float)x2+TERRAIN_SECTORS_MAX_OVERLAPPING, (float)y2+TERRAIN_SECTORS_MAX_OVERLAPPING, 512.f); if( bAllIN || m_pViewCamera->IsAABBVisible_hierarchical(AABB(bmin,bmax),&bAllIN) ) { if(m_vCameraPos.x < xm) { if(m_vCameraPos.y < ym) { RefineSector(x1, xm, y1, ym, bAllIN ); RefineSector(xm, x2, y1, ym, bAllIN ); RefineSector(x1, xm, ym, y2, bAllIN ); RefineSector(xm, x2, ym, y2, bAllIN ); } else { RefineSector(x1, xm, ym, y2, bAllIN ); RefineSector(xm, x2, ym, y2, bAllIN ); RefineSector(x1, xm, y1, ym, bAllIN ); RefineSector(xm, x2, y1, ym, bAllIN ); } } else { if(m_vCameraPos.y < ym) { RefineSector(xm, x2, y1, ym, bAllIN ); RefineSector(xm, x2, ym, y2, bAllIN ); RefineSector(x1, xm, y1, ym, bAllIN ); RefineSector(x1, xm, ym, y2, bAllIN ); } else { RefineSector(xm, x2, ym, y2, bAllIN ); RefineSector(xm, x2, y1, ym, bAllIN ); RefineSector(x1, xm, ym, y2, bAllIN ); RefineSector(x1, xm, y1, ym, bAllIN ); } } } } else { CSectorInfo * info = m_arrSecInfoTable[x1/CTerrain::GetSectorSize()][y1/CTerrain::GetSectorSize()]; // test higher bbox to include all flying dynamic stuff and reflected in water terrain if(!m_pViewCamera->IsAABBVisible_hierarchical( AABB( Vec3d((float)x1-TERRAIN_SECTORS_MAX_OVERLAPPING,(float)y1-TERRAIN_SECTORS_MAX_OVERLAPPING,0), Vec3d((float)x2+TERRAIN_SECTORS_MAX_OVERLAPPING,(float)y2+TERRAIN_SECTORS_MAX_OVERLAPPING,512.f)), &info->m_bAllStaticsInFrustum)) return; // debug: render this sector only if(GetCVars()->e_terrain_draw_this_sector_only) if(GetSecInfo(GetViewCamera().GetPos()) != info) return; // if(info->m_nOriginX != 1344 || info->m_nOriginY!=1344) // return; if(!m_nRenderStackLevel) // for reflections info->MergeSectorIntoLowResTerrain(false); // draw dynamic objects info->RenderEntities(m_pObjManager, !info->m_bAllStaticsInFrustum, "", DYNAMIC_ENTITIES); // test exact bbox of sector, it includes all static geometry if(!m_pViewCamera->IsAABBVisible_hierarchical( AABB(info->m_vBoxMin,info->m_vBoxMax), &info->m_bAllStaticsInFrustum)) return; // test ground visibility if(info->m_bAllStaticsInFrustum) info->m_bGroundVisible = true; else { float fOrgX = float(info->m_nOriginX); float fOrgY = float(info->m_nOriginY); info->m_bGroundVisible = m_pViewCamera->IsAABBVisibleFast( AABB(Vec3d(fOrgX,fOrgY,info->m_fMinZ), Vec3d(fOrgX+CTerrain::GetSectorSize(),fOrgY+CTerrain::GetSectorSize(),max(info->m_fMaxZ,m_fGlobalWaterLevel)))); } // calc distance info->m_fDistance = GetDist2D( (float)xm, (float)ym, m_vCameraPos.x, m_vCameraPos.y ) - (CTerrain::GetSectorSize()>>1)*1.3333f; if(info->m_fDistance > m_pViewCamera->GetZMax()) return; if(info->m_fDistance<1) info->m_fDistance=1; /* if( info->m_fDistance>128 && info->m_vBoxMax.z <= m_fGlobalWaterLevel && m_vCameraPos.z > m_fGlobalWaterLevel+1 && m_bCullUnderwaterTerrain && m_fGlobalWaterLevel) return; */ // occlusion test (affects only static objects) if(GetCVars()->e_terrain_occlusion_culling) if(m_pObjManager->IsBoxOccluded(info->m_vBoxMin,info->m_vBoxMax,info->m_fDistance, &info->m_OcclusionTestClient)) return; // test occl by antiportals if(GetVisAreaManager() && GetVisAreaManager()->IsOccludedByOcclVolumes(info->m_vBoxMin,info->m_vBoxMax)) return; if(m_nRenderStackLevel==0) info->m_cLastFrameUsed = m_ucTerrainFrame; if( info->m_bGroundVisible || info->m_fDistance<4 ) info->SetLOD(); // else // info->m_cGeometryMML = MAX_MML_LEVEL; // update distance to the ocean if(m_nRenderStackLevel==0) { if(info->m_bGroundVisible) if(info->m_fMinZm_fDistance; } AddVisSetcor(info); // render static objects if(info) info->RenderEntities(m_pObjManager, !info->m_bAllStaticsInFrustum, "", STATIC_ENTITIES); } } void CTerrain::UnloadOldSectors(float fMaxViewDist) { FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE ); static int nStaticLoadedTexturesNum[2]={0,0}; int cCurTimeSec = fastftol_positive(GetCurTimeSec()); ///////////////////////////////////////////////////////////////////////////////////// // x/y cycle ///////////////////////////////////////////////////////////////////////////////////// for(int t=0; t<16; t++) { m_nOldSectorsY++; if(m_nOldSectorsY>=CTerrain::GetSectorsTableSize()) { m_nOldSectorsY=0; m_nOldSectorsX++; if(m_nOldSectorsX>=CTerrain::GetSectorsTableSize()) { m_nOldSectorsY=m_nOldSectorsX=0; m_arrLoadedTexturesNum[0] = nStaticLoadedTexturesNum[0]; m_arrLoadedTexturesNum[1] = nStaticLoadedTexturesNum[1]; nStaticLoadedTexturesNum[0] = nStaticLoadedTexturesNum[1]=0; } } ///////////////////////////////////////////////////////////////////////////////////// { CSectorInfo * info = m_arrSecInfoTable[m_nOldSectorsX][m_nOldSectorsY]; if(info->m_bLockTexture) return; // do not unload locked texture if(info->m_nTextureID && info->m_nTextureID != info->m_nLowLodTextureID) nStaticLoadedTexturesNum[0]++; if(info->m_nLowLodTextureID) nStaticLoadedTexturesNum[1]++; float fDistanse = GetDist2D( (float)info->m_nOriginX+(CTerrain::GetSectorSize()>>1), (float)info->m_nOriginY+(CTerrain::GetSectorSize()>>1), m_pViewCamera->GetPos().x, m_pViewCamera->GetPos().y ) - (CTerrain::GetSectorSize()>>1); if((fDistanse > (1.5f*fMaxViewDist)) || (info->m_cLastTimeUsed < (cCurTimeSec - 4))) { // try to release vert buffer if not in use int time info->ReleaseHeightMapVertBuffer(); // release static shadow vertex buffers // info->ReleaseStaticShadowVertexBuffers(); // if(GetCVars()->e_terrain_log) // GetLog()->Log("buffer unloaded %d", info->GetSecIndex()); } if(GetCVars()->e_terrain_debug==3 || !GetCVars()->e_terrain_texture_pool) { if( fDistanse > (1.5f*fMaxViewDist) || (info->m_cLastTimeUsed < (cCurTimeSec - 8))) { info->UnloadHeighFieldTexture(fDistanse, fMaxViewDist); } } } } } int CTerrain::RenderEntitiesOutOfTheMap(CObjManager * pObjManager) { FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE ); if(!GetCVars()->e_objects || GetCVars()->e_terrain_draw_this_sector_only == 2) return 0; // this sector used also for entities outside of the map and for draw near objects m_arrSecInfoTable[0][0]->RenderEntities(pObjManager, true, "", STATIC_ENTITIES); m_arrSecInfoTable[0][0]->RenderEntities(pObjManager, true, "", DYNAMIC_ENTITIES); return 0; } int CTerrain::RenderTerrainWater(bool bRenderShore) { FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE ); if(!GetCVars()->e_water_ocean) return 0; m_pWater->Render(m_nRenderStackLevel); float fCamZ = GetViewCamera().GetPos().z; if(fCamZ>m_fGlobalWaterLevel) if(bRenderShore && m_pSHShore && !m_nRenderStackLevel && GetCVars()->e_beach) { float fZoomFactor = 0.1f+0.9f*(RAD2DEG(GetViewCamera().GetFov())/90.f); for( int i=0; iRenderBeach(m_pSHShore, fZoomFactor, fCamZ); } return 0; } CSectorInfo * CTerrain::GetSectorFromPoint(int _x, int _y) { int x = _x/CTerrain::GetSectorSize(); int y = _y/CTerrain::GetSectorSize(); if( x>=0 && y>=0 && xm_nDynLightMaskNoSun = 0; pSector->m_nDynLightMask = 0; ++p; } } void CTerrain::ApplyForceToEnvironment(Vec3d vPos, float fRadius, float fAmountOfForce) { if(fRadius<=0) return; if(!_finite(vPos.x) || !_finite(vPos.y) || !_finite(vPos.z)) { GetLog()->Log("Error: 3DEngine::ApplyForceToEnvironment: Undefined position passed to the function"); return; } if (fRadius > 50.f) fRadius = 50.f; if(fAmountOfForce>1.f) fAmountOfForce = 1.f; if( (GetDistance(vPos,m_pViewCamera->GetPos()) > 50.f+fRadius*2.f ) || // too far vPos.z < (GetZApr(vPos.x, vPos.y)-1.f)) // under ground return; /* int min_x = (int)(((vPos.x-fRadius)/CTerrain::GetSectorSize()))-1; int min_y = (int)(((vPos.y-fRadius)/CTerrain::GetSectorSize()))-1; int max_x = (int)(((vPos.x+fRadius)/CTerrain::GetSectorSize()))+1; int max_y = (int)(((vPos.y+fRadius)/CTerrain::GetSectorSize()))+1; if(min_x<0) min_x=0; if(min_y<0) min_y=0; if(max_x>=CTerrain::GetSectorsTableSize()) max_x = CTerrain::GetSectorsTableSize()-1; if(max_y>=CTerrain::GetSectorsTableSize()) max_y = CTerrain::GetSectorsTableSize()-1; for(int x=min_x; x<=max_x; x++) for(int y=min_y; y<=max_y; y++) { list2 * pList = &m_arrSecInfoTable[x][y]->m_lstEntities[STATIC_ENTITIES]; for(int s=0; sCount(); s++) if(pList->GetAt(s)->GetEntityRenderType()==eERType_Vegetation) { CStatObjInst * pEnt = (CStatObjInst *)pList->GetAt(s); float fDist = GetDist2D(pEnt->GetPos(true).x,pEnt->GetPos(true).y, vPos.x,vPos.y); if(fDistm_fCurrentBending = (1.f - fDist/fRadius)*fAmountOfForce*0.25; pEnt->m_fCurrentBending=pEnt->m_fCurrentBending; } } }*/ // calc area int x1=int(vPos.x-fRadius-CTerrain::GetHeightMapUnitSize()); int y1=int(vPos.y-fRadius-CTerrain::GetHeightMapUnitSize()); int x2=int(vPos.x+fRadius+CTerrain::GetHeightMapUnitSize()); int y2=int(vPos.y+fRadius+CTerrain::GetHeightMapUnitSize()); int nUnitSize = GetHeightMapUnitSize(); x1=x1/nUnitSize*nUnitSize; x2=x2/nUnitSize*nUnitSize; y1=y1/nUnitSize*nUnitSize; y2=y2/nUnitSize*nUnitSize; // limits if(x1<0) x1=0; if(y1<0) y1=0; if(x2>=CTerrain::GetTerrainSize()) x2=CTerrain::GetTerrainSize()-1; if(y2>=CTerrain::GetTerrainSize()) y2=CTerrain::GetTerrainSize()-1; // get near sectors list2 lstNearSecInfos; for(int x=x1; x<=x2; x++) for(int y=y1; y<=y2; y++) { CSectorInfo * pInfo = GetSecInfo(x,y); if(pInfo && lstNearSecInfos.Find(pInfo)<0) lstNearSecInfos.Add(pInfo); } { CSectorInfo * pInfo = GetSecInfo(0,0); if(pInfo && lstNearSecInfos.Find(pInfo)<0) lstNearSecInfos.Add(pInfo); } // affect objects around for( int s=0; sm_lstEntities[STATIC_ENTITIES].Count(); i++) if(pSecInfo->m_lstEntities[STATIC_ENTITIES][i]->GetEntityRenderType() == eERType_Vegetation) { CStatObjInst * pStatObjInst = (CStatObjInst*)pSecInfo->m_lstEntities[STATIC_ENTITIES][i]; float fDist = GetDist2D(pStatObjInst->GetPos(true).x,pStatObjInst->GetPos(true).y, vPos.x,vPos.y); if(fDist pStatObjInst->m_fCurrentBending) pStatObjInst->m_fCurrentBending = fNewBending; } } } } Vec3d CTerrain::GetTerrainSurfaceNormal(Vec3d vPos) { Vec3d v1 = Vec3d(vPos.x-0.5f, vPos.y-0.5f, GetZApr(vPos.x-0.5f,vPos.y-0.5f)); Vec3d v2 = Vec3d(vPos.x+0.5f, vPos.y, GetZApr(vPos.x+0.5f,vPos.y )); Vec3d v3 = Vec3d(vPos.x, vPos.y+0.5f, GetZApr(vPos.x, vPos.y+0.5f)); return (v2-v1).Cross(v3-v1); } bool CTerrain::UnRegisterInAllSectors(IEntityRender * pEntityRS) { assert(pEntityRS); bool bRes = 0; if(pEntityRS) { int nStatic = (pEntityRS->GetEntityRenderType() != eERType_Unknown); for( int x=0; xm_lstEntities[nStatic].Delete(pEntityRS); pEntityRS->m_pSector = 0; } return bRes; } ushort * CTerrain::GetUnderWaterSmoothHMap(int & nDimensions) { nDimensions = m_arrusUnderWaterSmoothHMap.m_nSize; return m_arrusUnderWaterSmoothHMap.m_pData; } void CTerrain::GetMemoryUsage( class ICrySizer*pSizer) { { SIZER_COMPONENT_NAME(pSizer, "HMap"); GetHighMapMemoryUsage(pSizer); } { SIZER_COMPONENT_NAME(pSizer, "SecInfoTable"); m_arrSecInfoTable.GetMemoryUsage(pSizer); } { SIZER_COMPONENT_NAME(pSizer, "SectorsData"); for( int x=0; xGetMemoryUsage(pSizer); } int nSize = 0; m_arrusUnderWaterSmoothHMap.GetMemoryUsage(pSizer); nSize += m_lstFogVolumes.GetMemoryUsage(); nSize += m_lstLowResTerrainIdxArray.GetMemoryUsage(); nSize += m_lstReflectedTerrainIdxArray.GetMemoryUsage(); nSize += m_lstSectorVertArray.GetMemoryUsage(); nSize += m_lstVisSectors.GetMemoryUsage(); // nSize += m_pBugsManager->GetMemoryUsage(); if(m_pCoverageBuffer) nSize += sizeof(*m_pCoverageBuffer); if(m_pDetailObjects) nSize += sizeof(*m_pDetailObjects) + m_pDetailObjects->GetMemoryUsage(); if(m_pTexturePool) m_pTexturePool->GetMemoryUsage(pSizer); if(m_pWater) nSize += sizeof(*m_pWater) + m_pWater->GetMemoryUsage(); nSize += m_nSectorTextureDataSizeBytes; pSizer->AddObject(this, nSize + sizeof(*this)); } void CTexturePool::TexInfo::GetSize (ICrySizer*pSizer)const { pSizer->Add (*this); pSectorInfo->GetMemoryUsage (pSizer); } void CTexturePool::GetMemoryUsage(class ICrySizer*pSizer) { for (int i = 0; i < sizeof(m_TexturePool)/sizeof(m_TexturePool[0]); ++i) { list2& arrTexInfo = m_TexturePool[i]; for (unsigned j = 0; j < arrTexInfo.size(); ++j) arrTexInfo[j].GetSize (pSizer); } } void CTerrain::UnregisterFogVolumeFromOutdoor(VolumeInfo * pFogVolume) { // reset fog volume pointer in all affected terrain sectors for(int x=0; xm_pFogVolume == pFogVolume) { pSecInfo->m_pFogVolume = 0; SetSectorFogVolume(pSecInfo); } } } void CTerrain::MoveAllEntitiesIntoList(list2 * plstVisAreasEntities, const Vec3d & vBoxMin, const Vec3d & vBoxMax) { // gat 2d bounds int min_x = (int)(((vBoxMin.x - 1.f)/CTerrain::GetSectorSize())); int min_y = (int)(((vBoxMin.y - 1.f)/CTerrain::GetSectorSize())); int max_x = (int)(((vBoxMax.x + 1.f)/CTerrain::GetSectorSize())); int max_y = (int)(((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; // make list of sectors list2 TerrainSectorsList; for(int x=min_x; x<=max_x; x++) for(int y=min_y; y<=max_y; y++) TerrainSectorsList.Add(m_arrSecInfoTable[x][y]); // this sector contains fps weapons and entities from outside of the map TerrainSectorsList.Add(m_arrSecInfoTable[0][0]); // add lists of entities where not added for(int i=0; iAddList(TerrainSectorsList.GetAt(i)->m_lstEntities[DYNAMIC_ENTITIES]); plstVisAreasEntities->AddList(TerrainSectorsList.GetAt(i)->m_lstEntities[STATIC_ENTITIES]); TerrainSectorsList.GetAt(i)->m_lstEntities[STATIC_ENTITIES].Clear(); TerrainSectorsList.GetAt(i)->m_lstEntities[DYNAMIC_ENTITIES].Clear(); } // remove duplicates for(int i=0; iCount(); i++) { IEntityRender * pEnt = plstVisAreasEntities->GetAt(0); plstVisAreasEntities->Delete(pEnt); plstVisAreasEntities->Add(pEnt); } } bool CTerrain::PreloadResources() { FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE ); static int nCurTexPreloadX=0, nCurTexPreloadY=0; nCurTexPreloadX++; if(nCurTexPreloadX>=CTerrain::GetSectorsTableSize()) { nCurTexPreloadX=0; nCurTexPreloadY++; } if(nCurTexPreloadY>=CTerrain::GetSectorsTableSize()) { nCurTexPreloadY = 0; DrawDetailTextures(32, 64, false); if(m_pDetailObjects) m_pDetailObjects->PreloadResources(); } assert(nCurTexPreloadX>=0 && nCurTexPreloadX=0 && nCurTexPreloadYm_fDistance = GetDist2D( float(pSecInfo->m_nOriginX+(CTerrain::GetSectorSize()>>1)), float(pSecInfo->m_nOriginY+(CTerrain::GetSectorSize()>>1)), m_vCameraPos.x, m_vCameraPos.y ) - (CTerrain::GetSectorSize()>>1); pSecInfo->SetLOD(); if(pSecInfo->m_fDistanceSetTextures(); //CCObject * pTerrainCCObject = GetRenderer()->EF_GetObject(true); //pSecInfo->RenderSector(pTerrainCCObject); pSecInfo->PreloadResources(GetViewCamera().GetPos(), 0); pSecInfo->m_cLastTimeUsed = fastftol_positive( GetCurTimeSec() ); } } return !nCurTexPreloadX && !nCurTexPreloadY; } void CTerrain::GetObjects(list2 * pLstObjects) { // reset fog volume pointer in all affected terrain sectors for(int x=0; xAddList(pSecInfo->m_lstEntities[nStatic]); pSecInfo->m_lstEntities[nStatic].Reset(); } } } const void * CTerrain::GetShoreGeometry(int & nPosStride, int & nVertCount, int nSectorX, int nSectorY) { CSectorInfo * pSecInfo = GetSecInfo(nSectorX, nSectorY); if(!pSecInfo) return 0; return pSecInfo->GetShoreGeometry(nPosStride, nVertCount); }