You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/Cry3DEngine/VisAreaMan.cpp

2172 lines
69 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "Cry3DEngine_precompiled.h"
#include "StatObj.h"
#include "ObjMan.h"
#include "VisAreas.h"
#include "3dEngine.h"
#include "TimeOfDay.h"
#include "AABBSV.h"
#define DEFAULT_INITIAL_PORTALS 1
#define DEFAULT_INITIAL_VISAREAS 1
#define DEFAULT_INITIAL_OCCLAREAS 1
CVisAreaManager::CVisAreaManager()
{
m_pCurPortal = m_pCurArea = 0;
m_bOutdoorVisible = false;
m_bSkyVisible = false;
m_bSunIsNeeded = false;
m_bOceanVisible = false;
m_pAABBTree = NULL;
m_visAreas.PreAllocate(DEFAULT_INITIAL_VISAREAS);
m_visAreaColdData.PreAllocate(DEFAULT_INITIAL_VISAREAS);
m_portals.PreAllocate(DEFAULT_INITIAL_PORTALS);
m_portalColdData.PreAllocate(DEFAULT_INITIAL_PORTALS);
m_occlAreas.PreAllocate(DEFAULT_INITIAL_OCCLAREAS);
m_occlAreaColdData.PreAllocate(DEFAULT_INITIAL_OCCLAREAS);
m_segVisAreas.Clear();
m_segPortals.Clear();
m_segOcclAreas.Clear();
}
void CVisAreaManager::DeleteAllVisAreas()
{
for (int i = 0; i < m_lstVisAreas.Count(); i++)
{
if (m_visAreas.Find(m_lstVisAreas[i]) >= 0)
{
delete m_lstVisAreas[i];
}
else
{
delete m_lstVisAreas[i]->GetColdData();
delete m_lstVisAreas[i];
}
}
m_visAreas.Clear();
m_visAreaColdData.Clear();
m_lstVisAreas.Clear();
for (int i = 0; i < m_lstPortals.Count(); i++)
{
if (m_portals.Find(m_lstPortals[i]) >= 0)
{
delete m_lstPortals[i];
}
else
{
delete m_lstPortals[i]->GetColdData();
delete m_lstPortals[i];
}
}
m_portals.Clear();
m_portalColdData.Clear();
m_lstPortals.Clear();
for (int i = 0; i < m_lstOcclAreas.Count(); i++)
{
if (m_occlAreas.Find(m_lstOcclAreas[i]) >= 0)
{
delete m_lstOcclAreas[i];
}
else
{
delete m_lstOcclAreas[i]->GetColdData();
delete m_lstOcclAreas[i];
}
}
m_occlAreas.Clear();
m_occlAreaColdData.Clear();
m_lstOcclAreas.Clear();
stl::free_container(CVisArea::m_lUnavailableAreas);
}
void SAABBTreeNode::OffsetPosition(const Vec3& delta)
{
nodeBox.Move(delta);
if (!nodeAreas.Count())
{
for (int i = 0; i < 2; i++)
{
if (arrChilds[i])
{
arrChilds[i]->OffsetPosition(delta);
}
}
}
}
CVisAreaManager::~CVisAreaManager()
{
if (GetRenderer())
{
GetRenderer()->EF_ClearDeferredClipVolumesList();
}
DeleteAllVisAreas();
delete m_pAABBTree;
m_pAABBTree = NULL;
}
SAABBTreeNode::SAABBTreeNode(PodArray<CVisArea*>& lstAreas, AABB box, int nRecursion)
{
memset(this, 0, sizeof(*this));
nodeBox = box;
nRecursion++;
if (nRecursion > 8 || lstAreas.Count() < 8)
{
nodeAreas.AddList(lstAreas);
return;
}
PodArray<CVisArea*> lstAreas0, lstAreas1;
Vec3 vSize = nodeBox.GetSize();
Vec3 vCenter = nodeBox.GetCenter();
AABB nodeBox0 = nodeBox;
AABB nodeBox1 = nodeBox;
if (vSize.x >= vSize.y && vSize.x >= vSize.z)
{
nodeBox0.min.x = vCenter.x;
nodeBox1.max.x = vCenter.x;
}
else if (vSize.y >= vSize.x && vSize.y >= vSize.z)
{
nodeBox0.min.y = vCenter.y;
nodeBox1.max.y = vCenter.y;
}
else
{
nodeBox0.min.z = vCenter.z;
nodeBox1.max.z = vCenter.z;
}
for (int i = 0; i < lstAreas.Count(); i++)
{
if (Overlap::AABB_AABB(nodeBox0, *lstAreas[i]->GetAABBox()))
{
lstAreas0.Add(lstAreas[i]);
}
if (Overlap::AABB_AABB(nodeBox1, *lstAreas[i]->GetAABBox()))
{
lstAreas1.Add(lstAreas[i]);
}
}
if (lstAreas0.Count())
{
arrChilds[0] = new SAABBTreeNode(lstAreas0, nodeBox0, nRecursion);
}
if (lstAreas1.Count())
{
arrChilds[1] = new SAABBTreeNode(lstAreas1, nodeBox1, nRecursion);
}
}
SAABBTreeNode::~SAABBTreeNode()
{
delete arrChilds[0];
delete arrChilds[1];
}
SAABBTreeNode* SAABBTreeNode::GetTopNode(const AABB& box, void** pNodeCache)
{
AABB boxClip = box;
boxClip.ClipToBox(nodeBox);
SAABBTreeNode* pNode = this;
if (pNodeCache)
{
pNode = (SAABBTreeNode*)*pNodeCache;
if (!pNode || !pNode->nodeBox.ContainsBox(boxClip))
{
pNode = this;
}
}
// Find top node containing box.
for (;; )
{
int i;
for (i = 0; i < 2; i++)
{
if (pNode->arrChilds[i] && pNode->arrChilds[i]->nodeBox.ContainsBox(boxClip))
{
pNode = pNode->arrChilds[i];
break;
}
}
if (i == 2)
{
break;
}
}
if (pNodeCache)
{
*(SAABBTreeNode**)pNodeCache = pNode;
}
return pNode;
}
bool SAABBTreeNode::IntersectsVisAreas(const AABB& box)
{
if (nodeBox.IsIntersectBox(box))
{
if (nodeAreas.Count())
{ // leaf
for (int i = 0; i < nodeAreas.Count(); i++)
{
if (nodeAreas[i]->m_bActive && nodeAreas[i]->m_boxArea.IsIntersectBox(box))
{
return true;
}
}
}
else
{ // node
for (int i = 0; i < 2; i++)
{
if (arrChilds[i])
{
if (arrChilds[i]->IntersectsVisAreas(box))
{
return true;
}
}
}
}
}
return false;
}
int SAABBTreeNode::ClipOutsideVisAreas(Sphere& sphere, Vec3 const& vNormal)
{
int nClipped = 0;
if (sphere.radius > FLT_MAX * 0.01f || Overlap::Sphere_AABB(sphere, nodeBox))
{
if (nodeAreas.Count())
{ // leaf
for (int i = 0; i < nodeAreas.Count(); i++)
{
if (nodeAreas[i]->m_bActive && Overlap::Sphere_AABB(sphere, nodeAreas[i]->m_boxArea))
{
nClipped += nodeAreas[i]->ClipToVisArea(false, sphere, vNormal);
}
}
}
else
{ // node
for (int i = 0; i < 2; i++)
{
if (arrChilds[i])
{
nClipped += arrChilds[i]->ClipOutsideVisAreas(sphere, vNormal);
}
}
}
}
return nClipped;
}
void CVisAreaManager::UpdateAABBTree()
{
delete m_pAABBTree;
PodArray<CVisArea*> lstAreas;
lstAreas.AddList(m_lstPortals);
lstAreas.AddList(m_lstVisAreas);
AABB nodeBox;
nodeBox.min = Vec3(1000000, 1000000, 1000000);
nodeBox.max = -nodeBox.min;
for (int i = 0; i < lstAreas.Count(); i++)
{
nodeBox.Add(*lstAreas[i]->GetAABBox());
}
m_pAABBTree = new SAABBTreeNode(lstAreas, nodeBox);
}
bool CVisAreaManager::IsEntityVisible(IRenderNode* pEnt)
{
if (GetCVars()->e_Portals == 3)
{
return true;
}
if (!pEnt->GetEntityVisArea())
{
return IsOutdoorAreasVisible();
}
return true;
}
void CVisAreaManager::SetCurAreas(const SRenderingPassInfo& passInfo)
{
m_pCurArea = 0;
m_pCurPortal = 0;
if (!GetCVars()->e_Portals)
{
return;
}
if (!m_pAABBTree)
{
UpdateAABBTree();
}
CVisArea* pFound = m_pAABBTree->FindVisarea(passInfo.GetCamera().GetOccPos());
#ifdef _DEBUG
// find camera portal id
for (int v = 0; v < m_lstPortals.Count(); v++)
{
if (m_lstPortals[v]->m_bActive && m_lstPortals[v]->IsPointInsideVisArea(passInfo.GetCamera().GetOccPos()))
{
m_pCurPortal = m_lstPortals[v];
break;
}
}
// if not inside any portal - try to find area
if (!m_pCurPortal)
{
// int nFoundAreasNum = 0;
// find camera area
for (int nVolumeId = 0; nVolumeId < m_lstVisAreas.Count(); nVolumeId++)
{
if (m_lstVisAreas[nVolumeId]->IsPointInsideVisArea(passInfo.GetCamera().GetOccPos()))
{
// nFoundAreasNum++;
m_pCurArea = m_lstVisAreas[nVolumeId];
break;
}
}
// if(nFoundAreasNum>1) // if more than one area found - set cur area to undefined
{ // todo: try to set joining portal as current
// m_pCurArea = 0;
}
}
assert(pFound == m_pCurArea || pFound == m_pCurPortal);
#endif // _DEBUG
if (pFound)
{
if (pFound->IsPortal())
{
m_pCurPortal = pFound;
}
else
{
m_pCurArea = pFound;
}
}
// camera is in outdoors
m_lstActiveEntransePortals.Clear();
if (!m_pCurArea && !m_pCurPortal)
{
MakeActiveEntransePortalsList(&passInfo.GetCamera(), m_lstActiveEntransePortals, 0, passInfo);
}
/*
if(m_pCurArea)
{
IVisArea * arrAreas[8];
int nres = m_pCurArea->GetVisAreaConnections(arrAreas, 8);
nres=nres;
}
DefineTrees();*/
/* if(GetCVars()->e_Portals == 4)
{
if(m_pCurPortal)
{
IVisArea * arrAreas[64];
int nConnections = m_pCurPortal->GetVisAreaConnections(arrAreas,64);
PrintMessage("CurPortal = %s, nConnections = %d", m_pCurPortal->m_sName, nConnections);
}
if(m_pCurArea)
{
IVisArea * arrAreas[64];
int nConnections = m_pCurArea->GetVisAreaConnections(arrAreas,64);
PrintMessage("CurArea = %s, nRes = %d", m_pCurArea->m_sName, nConnections);
}
}*/
}
bool CVisAreaManager::IsSkyVisible()
{
return m_bSkyVisible;
}
bool CVisAreaManager::IsOceanVisible()
{
return m_bOceanVisible;
}
bool CVisAreaManager::IsOutdoorAreasVisible()
{
if (!m_pCurArea && !m_pCurPortal)
{
m_bOutdoorVisible = true;
return m_bOutdoorVisible; // camera not in the areas
}
if (m_pCurPortal && m_pCurPortal->m_lstConnections.Count() == 1)
{
m_bOutdoorVisible = true;
return m_bOutdoorVisible; // camera is in exit portal
}
if (m_bOutdoorVisible)
{
return true; // exit is visible
}
// note: outdoor camera is no modified in this case
return false;
}
/*void CVisAreaManager::SetAreaFogVolume(CTerrain * pTerrain, CVisArea * pVisArea)
{
pVisArea->m_pFogVolume=0;
for(int f=0; f<Get3DEngine()->GetFogVolumes().Count(); f++)
{
const Vec3 & v1Min = Get3DEngine()->GetFogVolumes()[f].box.min;
const Vec3 & v1Max = Get3DEngine()->GetFogVolumes()[f].box.max;
const Vec3 & v2Min = pVisArea->m_boxArea.min;
const Vec3 & v2Max = pVisArea->m_boxArea.max;
if(v1Max.x>v2Min.x && v2Max.x>v1Min.x)
if(v1Max.y>v2Min.y && v2Max.y>v1Min.y)
if(v1Max.z>v2Min.z && v2Max.z>v1Min.z)
if(!Get3DEngine()->GetFogVolumes()[f].bOcean)
{
Vec3 arrVerts3d[8] =
{
Vec3(v1Min.x,v1Min.y,v1Min.z),
Vec3(v1Min.x,v1Max.y,v1Min.z),
Vec3(v1Max.x,v1Min.y,v1Min.z),
Vec3(v1Max.x,v1Max.y,v1Min.z),
Vec3(v1Min.x,v1Min.y,v1Max.z),
Vec3(v1Min.x,v1Max.y,v1Max.z),
Vec3(v1Max.x,v1Min.y,v1Max.z),
Vec3(v1Max.x,v1Max.y,v1Max.z)
};
bool bIntersect = false;
for(int i=0; i<8; i++)
if(pVisArea->IsPointInsideVisArea(arrVerts3d[i]))
{
bIntersect = true;
break;
}
if(!bIntersect)
if(pVisArea->IsPointInsideVisArea((v1Min+v1Max)*0.5f))
bIntersect = true;
if(!bIntersect)
{
for(int i=0; i<pVisArea->m_lstShapePoints.Count(); i++)
if(Get3DEngine()->GetFogVolumes()[f].IsInsideBBox(pVisArea->m_lstShapePoints[i]))
{
bIntersect = true;
break;
}
}
if(!bIntersect)
{
Vec3 vCenter = (pVisArea->m_boxArea.min+pVisArea->m_boxArea.max)*0.5f;
if(Get3DEngine()->GetFogVolumes()[f].IsInsideBBox(vCenter))
bIntersect = true;
}
if(bIntersect)
{
pVisArea->m_pFogVolume = &Get3DEngine()->GetFogVolumes()[f];
Get3DEngine()->GetFogVolumes()[f].bIndoorOnly = true;
pTerrain->UnregisterFogVolumeFromOutdoor(&Get3DEngine()->GetFogVolumes()[f]);
break;
}
}
}
}*/
void CVisAreaManager::PortalsDrawDebug()
{
UpdateConnections();
/*
if(m_pCurArea)
{
for(int p=0; p<m_pCurArea->m_lstConnections.Count(); p++)
{
CVisArea * pPortal = m_pCurArea->m_lstConnections[p];
float fBlink = gEnv->pTimer->GetFrameStartTime().GetPeriodicFraction(1.0f)>0.5f ? 1.0f : 0.0f;
float fError = pPortal->IsPortalValid() ? 1.0f : fBlink;
GetRenderer()->SetMaterialColor(fError,fError*(pPortal->m_lstConnections.Count()<2),0,0.25f);
DrawBBox(pPortal->m_boxArea.min, pPortal->m_boxArea.max, DPRIM_SOLID_BOX);
GetRenderer()->DrawLabel((pPortal->m_boxArea.min+ pPortal->m_boxArea.max)*0.5f,
2,pPortal->m_sName);
}
}
else*/
{
// debug draw areas
GetRenderer()->SetMaterialColor(0, 1, 0, 0.25f);
Vec3 oneVec(1, 1, 1);
for (int v = 0; v < m_lstVisAreas.Count(); v++)
{
DrawBBox(m_lstVisAreas[v]->m_boxArea.min, m_lstVisAreas[v]->m_boxArea.max);//, DPRIM_SOLID_BOX);
GetRenderer()->DrawLabelEx((m_lstVisAreas[v]->m_boxArea.min + m_lstVisAreas[v]->m_boxArea.max) * 0.5f,
1, (float*)&oneVec, 0, 1, m_lstVisAreas[v]->GetName());
GetRenderer()->SetMaterialColor(0, 1, 0, 0.25f);
DrawBBox(m_lstVisAreas[v]->m_boxStatics, Col_LightGray);
}
// debug draw portals
for (int v = 0; v < m_lstPortals.Count(); v++)
{
CVisArea* pPortal = m_lstPortals[v];
float fBlink = gEnv->pTimer->GetFrameStartTime().GetPeriodicFraction(1.0f) > 0.5f ? 1.0f : 0.0f;
float fError = pPortal->IsPortalValid() ? 1.f : fBlink;
ColorB col(
(int)clamp_tpl(fError * 255.0f, 0.0f, 255.0f),
(int)clamp_tpl(fError * (pPortal->m_lstConnections.Count() < 2) * 255.0f, 0.0f, 255.0f),
0,
64);
DrawBBox(pPortal->m_boxArea.min, pPortal->m_boxArea.max, col);
GetRenderer()->DrawLabelEx((pPortal->m_boxArea.min + pPortal->m_boxArea.max) * 0.5f,
1, (float*)&oneVec, 0, 1, pPortal->GetName());
Vec3 vCenter = (pPortal->m_boxArea.min + pPortal->m_boxArea.max) * 0.5f;
DrawBBox(vCenter - Vec3(0.1f, 0.1f, 0.1f), vCenter + Vec3(0.1f, 0.1f, 0.1f));
int nConnections = pPortal->m_lstConnections.Count();
if (nConnections == 1)
{
col = ColorB(0, 255, 0, 64);
}
else
{
col = ColorB(0, 0, 255, 64);
}
for (int i = 0; i < nConnections && i < 2; i++)
{
DrawLine(vCenter, vCenter + pPortal->m_vConnNormals[i], col);
}
DrawBBox(pPortal->m_boxStatics.min, pPortal->m_boxStatics.max, col);
}
/*
// debug draw area shape
GetRenderer()->SetMaterialColor(0,0,1,0.25f);
for(int v=0; v<m_lstVisAreas.Count(); v++)
for(int p=0; p<m_lstVisAreas[v]->m_lstShapePoints.Count(); p++)
GetRenderer()->DrawLabel(m_lstVisAreas[v]->m_lstShapePoints[p], 2,"%d", p);
for(int v=0; v<m_lstPortals.Count(); v++)
for(int p=0; p<m_lstPortals[v]->m_lstShapePoints.Count(); p++)
GetRenderer()->DrawLabel(m_lstPortals[v]->m_lstShapePoints[p], 2,"%d", p);*/
}
}
void CVisAreaManager::DrawVisibleSectors(const SRenderingPassInfo& passInfo, SRendItemSorter& rendItemSorter)
{
FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
AZ_TRACE_METHOD();
for (int i = 0; i < m_lstVisibleAreas.Count(); i++)
{
CVisArea* pArea = m_lstVisibleAreas[i];
if (pArea->m_pObjectsTree)
{
for (int c = 0; c < pArea->m_lstCurCamerasLen; c++)
{
rendItemSorter.IncreaseOctreeCounter();
// create a new RenderingPassInfo object, which a camera matching the visarea
pArea->m_pObjectsTree->Render_Object_Nodes(false, OCTREENODE_RENDER_FLAG_OBJECTS, SRenderingPassInfo::CreateTempRenderingInfo(CVisArea::s_tmpCameras[pArea->m_lstCurCamerasIdx + c], passInfo), rendItemSorter);
}
}
}
rendItemSorter.IncreaseGroupCounter();
}
void CVisAreaManager::CheckVis(const SRenderingPassInfo& passInfo)
{
FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
AZ_TRACE_METHOD();
if (passInfo.IsGeneralPass())
{
m_bOutdoorVisible = false;
m_bSkyVisible = false;
m_bOceanVisible = false;
CVisArea::s_tmpCameras.Clear();
}
m_lstOutdoorPortalCameras.Clear();
m_lstVisibleAreas.Clear();
m_bSunIsNeeded = false;
GetRenderer()->EF_ClearDeferredClipVolumesList();
SetCurAreas(passInfo);
CCamera camRoot = passInfo.GetCamera();
camRoot.m_ScissorInfo.x1 = 0;
camRoot.m_ScissorInfo.y1 = 0;
camRoot.m_ScissorInfo.x2 = GetRenderer()->GetWidth(); // todo: use values from camera
camRoot.m_ScissorInfo.y2 = GetRenderer()->GetHeight();
if (GetCVars()->e_Portals == 3)
{ // draw everything for debug
for (int i = 0; i < m_lstVisAreas.Count(); i++)
{
if (camRoot.IsAABBVisible_F(AABB(m_lstVisAreas[i]->m_boxArea.min, m_lstVisAreas[i]->m_boxArea.max)))
{
m_lstVisAreas[i]->PreRender(0, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
}
}
for (int i = 0; i < m_lstPortals.Count(); i++)
{
if (camRoot.IsAABBVisible_F(AABB(m_lstPortals[i]->m_boxArea.min, m_lstPortals[i]->m_boxArea.max)))
{
m_lstPortals[i]->PreRender(0, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
}
}
}
else
{
if (passInfo.IsRecursivePass())
{ // use another starting point for reflections
CVisArea* pVisArea = (CVisArea*)GetVisAreaFromPos(camRoot.GetOccPos());
if (pVisArea)
{
pVisArea->PreRender(3, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
}
}
else if (m_pCurArea)
{ // camera inside some sector
m_pCurArea->PreRender(GetCVars()->e_PortalsMaxRecursion, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
for (int ii = 0; ii < m_lstOutdoorPortalCameras.Count(); ii++) // process all exit portals
{ // for each portal build list of potentially visible entrances into other areas
MakeActiveEntransePortalsList(&m_lstOutdoorPortalCameras[ii], m_lstActiveEntransePortals, (CVisArea*)m_lstOutdoorPortalCameras[ii].m_pPortal, passInfo);
for (int i = 0; i < m_lstActiveEntransePortals.Count(); i++) // entrance into another building is visible
{
m_lstActiveEntransePortals[i]->PreRender(i == 0 ? 5 : 1,
m_lstOutdoorPortalCameras[ii], 0, m_pCurPortal, 0, 0, 0, 0, m_lstVisibleAreas, passInfo);
}
}
// reset scissor if skybox is visible also thru skyboxonly portal
if (m_bSkyVisible && m_lstOutdoorPortalCameras.Count() == 1)
{
m_lstOutdoorPortalCameras[0].m_ScissorInfo.x1 =
m_lstOutdoorPortalCameras[0].m_ScissorInfo.x2 =
m_lstOutdoorPortalCameras[0].m_ScissorInfo.y1 =
m_lstOutdoorPortalCameras[0].m_ScissorInfo.y2 = 0;
}
}
else if (m_pCurPortal)
{ // camera inside some portal
m_pCurPortal->PreRender(GetCVars()->e_PortalsMaxRecursion - 1, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
if (m_pCurPortal->m_lstConnections.Count() == 1)
{
m_lstOutdoorPortalCameras.Clear(); // camera in outdoor
}
if (m_pCurPortal->m_lstConnections.Count() == 1 || m_lstOutdoorPortalCameras.Count())
{ // if camera is in exit portal or exit is visible
MakeActiveEntransePortalsList(m_lstOutdoorPortalCameras.Count() ? &m_lstOutdoorPortalCameras[0] : &camRoot,
m_lstActiveEntransePortals,
m_lstOutdoorPortalCameras.Count() ? (CVisArea*)m_lstOutdoorPortalCameras[0].m_pPortal : m_pCurPortal, passInfo);
for (int i = 0; i < m_lstActiveEntransePortals.Count(); i++) // entrance into another building is visible
{
m_lstActiveEntransePortals[i]->PreRender(i == 0 ? 5 : 1,
m_lstOutdoorPortalCameras.Count() ? m_lstOutdoorPortalCameras[0] : camRoot, 0, m_pCurPortal, 0, 0, 0, 0, m_lstVisibleAreas, passInfo);
}
// m_lstOutdoorPortalCameras.Clear(); // otherwise ocean in fleet was not scissored
}
}
else if (m_lstActiveEntransePortals.Count())
{ // camera in outdoors - process visible entrance portals
for (int i = 0; i < m_lstActiveEntransePortals.Count(); i++)
{
m_lstActiveEntransePortals[i]->PreRender(5, camRoot, 0, m_lstActiveEntransePortals[i], &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
}
m_lstActiveEntransePortals.Clear();
// do not recurse to another building since we already processed all potential entrances
m_lstOutdoorPortalCameras.Clear(); // use default camera
m_bOutdoorVisible = true;
}
}
if (GetCVars()->e_Portals == 2)
{
PortalsDrawDebug();
}
}
void CVisAreaManager::ActivatePortal(const Vec3& vPos, bool bActivate, const char* szEntityName)
{
// bool bFound = false;
for (int v = 0; v < m_lstPortals.Count(); v++)
{
AABB aabb;
aabb.min = m_lstPortals[v]->m_boxArea.min - Vec3(0.5f, 0.5f, 0.1f);
aabb.max = m_lstPortals[v]->m_boxArea.max + Vec3(0.5f, 0.5f, 0.0f);
if (Overlap::Point_AABB(vPos, aabb))
{
m_lstPortals[v]->m_bActive = bActivate;
// switch to PrintComment once portals activation is working stable
PrintMessage("I3DEngine::ActivatePortal(): Portal %s is %s by entity %s at position(%.1f,%.1f,%.1f)",
m_lstPortals[v]->GetName(), bActivate ? "Enabled" : "Disabled", szEntityName, vPos.x, vPos.y, vPos.z);
// bFound = true;
}
}
/*
if(!bFound)
{
PrintComment("I3DEngine::ActivatePortal(): Portal not found for entity %s at position(%.1f,%.1f,%.1f)",
szEntityName, vPos.x, vPos.y, vPos.z);
}
*/
}
/*
bool CVisAreaManager::IsEntityInVisibleArea(IRenderNodeState * pRS)
{
if( pRS && pRS->plstVisAreaId && pRS->plstVisAreaId->Count() )
{
PodArray<int> * pVisAreas = pRS->plstVisAreaId;
for(int n=0; n<pVisAreas->Count(); n++)
if( m_lstVisAreas[pVisAreas->GetAt(n)].m_nVisFrameId==passInfo.GetFrameID() )
break;
if(n==pVisAreas->Count())
return false; // no visible areas
}
else
return false; // entity is not inside
return true;
} */
bool CVisAreaManager::IsValidVisAreaPointer(CVisArea* pVisArea)
{
if (m_lstVisAreas.Find(pVisArea) < 0 &&
m_lstPortals.Find(pVisArea) < 0 &&
m_lstOcclAreas.Find(pVisArea) < 0)
{
return false;
}
return true;
}
//This is only called from the editor, so pVisArea will not be pool allocated by type
bool CVisAreaManager::DeleteVisArea(CVisArea* pVisArea)
{
bool bFound = false;
if (m_lstVisAreas.Delete(pVisArea) || m_lstPortals.Delete(pVisArea) || m_lstOcclAreas.Delete(pVisArea))
{
delete pVisArea;
bFound = true;
}
m_lstActiveOcclVolumes.Delete(pVisArea);
m_lstIndoorActiveOcclVolumes.Delete(pVisArea);
m_lstActiveEntransePortals.Delete(pVisArea);
m_pCurArea = 0;
m_pCurPortal = 0;
UpdateConnections();
delete m_pAABBTree;
m_pAABBTree = NULL;
return bFound;
}
/*void CVisAreaManager::LoadVisAreaShapeFromXML(XmlNodeRef pDoc)
{
for(int i=0; i<m_lstVisAreas.Count(); i++)
{
delete m_lstVisAreas[i];
m_lstVisAreas.Delete(i);
i--;
}
for(int i=0; i<m_lstPortals.Count(); i++)
{
delete m_lstPortals[i];
m_lstPortals.Delete(i);
i--;
}
// fill list of volumes of shape points
XmlNodeRef pObjectsNode = pDoc->findChild("Objects");
if (pObjectsNode)
{
for (int i = 0; i < pObjectsNode->getChildCount(); i++)
{
XmlNodeRef pNode = pObjectsNode->getChild(i);
if (pNode->isTag("Object"))
{
const char * pType = pNode->getAttr("Type");
if (strstr(pType,"OccluderArea") || strstr(pType,"VisArea") || strstr(pType,"Portal"))
{
CVisArea * pArea = new CVisArea();
pArea->m_boxArea.max=SetMinBB();
pArea->m_boxArea.min=SetMaxBB();
// set name
strcpy(pArea->m_sName, pNode->getAttr("Name"));
strlwr(pArea->m_sName);
// set height
pNode->getAttr("Height",pArea->m_fHeight);
// set ambient color
pNode->getAttr("AmbientColor", pArea->m_vAmbColor);
// set dynamic ambient color
// pNode->getAttr("DynAmbientColor", pArea->m_vDynAmbColor);
// set SkyOnly flag
pNode->getAttr("SkyOnly", pArea->m_bSkyOnly);
// set AfectedByOutLights flag
pNode->getAttr("AffectedBySun", pArea->m_bAfectedByOutLights);
// set ViewDistRatio
pNode->getAttr("ViewDistRatio", pArea->m_fViewDistRatio);
// set DoubleSide flag
pNode->getAttr("DoubleSide", pArea->m_bDoubleSide);
// set UseInIndoors flag
pNode->getAttr("UseInIndoors", pArea->m_bUseInIndoors);
if(strstr(pType, "OccluderArea"))
m_lstOcclAreas.Add(pArea);
else if(strstr(pArea->m_sName,"portal") || strstr(pType,"Portal"))
m_lstPortals.Add(pArea);
else
m_lstVisAreas.Add(pArea);
// load vertices
XmlNodeRef pPointsNode = pNode->findChild("Points");
if (pPointsNode)
for (int i = 0; i < pPointsNode->getChildCount(); i++)
{
XmlNodeRef pPointNode = pPointsNode->getChild(i);
Vec3 vPos;
if (pPointNode->isTag("Point") && pPointNode->getAttr("Pos", vPos))
{
pArea->m_lstShapePoints.Add(vPos);
pArea->m_boxArea.max.CheckMax(vPos);
pArea->m_boxArea.min.CheckMin(vPos);
pArea->m_boxArea.max.CheckMax(vPos+Vec3(0,0,pArea->m_fHeight));
pArea->m_boxArea.min.CheckMin(vPos+Vec3(0,0,pArea->m_fHeight));
}
}
pArea->UpdateGeometryBBox();
}
}
}
}
// load area boxes to support old way
// LoadVisAreaBoxFromXML(pDoc);
}*/
//THIS SHOULD ONLY BE CALLED BY THE EDITOR
void CVisAreaManager::UpdateVisArea(CVisArea* pArea, const Vec3* pPoints, int nCount, const char* szName, const SVisAreaInfo& info)
{ // on first update there will be nothing to delete, area will be added into list only in this function
// If pArea is in these lists, then remove it.
const VisAreaGUID& areaGUID = pArea->GetGUID();
for (int i = 0; i < m_lstVisAreas.Count(); ++i)
{
CVisArea* pAreaInList = m_lstVisAreas[i];
if (areaGUID == pAreaInList->GetGUID())
{
m_lstVisAreas.Delete(i);
--i;
}
}
for (int i = 0; i < m_lstPortals.Count(); ++i)
{
CVisArea* pPortalInList = m_lstPortals[i];
if (areaGUID == pPortalInList->GetGUID())
{
m_lstPortals.Delete(i);
--i;
}
}
for (int i = 0; i < m_lstOcclAreas.Count(); ++i)
{
CVisArea* pOccAreaInList = m_lstOcclAreas[i];
if (areaGUID == pOccAreaInList->GetGUID())
{
m_lstOcclAreas.Delete(i);
--i;
}
}
SGenericColdData* pColdData = pArea->GetColdData();
if (pColdData != NULL)
{
if (pColdData->m_dataType == eCDT_Portal)
{
SPortalColdData* pPortalColdData = static_cast<SPortalColdData*>(pColdData);
if (pPortalColdData->m_pRNTmpData)
{
Get3DEngine()->FreeRNTmpData(&pPortalColdData->m_pRNTmpData);
pPortalColdData->m_pRNTmpData = NULL;
}
}
delete pArea->GetColdData();
pArea->SetColdDataPtr(NULL);
}
SGenericColdData* pColdDataPtr = NULL;
char sTemp[64];
cry_strcpy(sTemp, szName);
_strlwr_s(sTemp, sizeof(sTemp));
bool bPortal = false;
bool bVisArea = false;
bool bOcclArea = false;
//TODO: Refactor with code below so it's not horrible
if (strstr(sTemp, "portal"))
{
pColdDataPtr = new SPortalColdData();
bPortal = true;
}
else if (strstr(sTemp, "visarea"))
{
pColdDataPtr = new SGenericColdData();
bVisArea = true;
}
else if (strstr(sTemp, "occlarea"))
{
pColdDataPtr = new SGenericColdData();
bOcclArea = true;
}
else
{
pColdDataPtr = new SGenericColdData();
}
assert(pColdDataPtr);
pArea->SetColdDataPtr(pColdDataPtr);
pArea->Update(pPoints, nCount, sTemp, info);
if (bPortal)
{
if (pArea->m_lstConnections.Count() == 1)
{
pArea->UpdateGeometryBBox();
}
m_lstPortals.Add(pArea);
}
else if (bVisArea)
{
m_lstVisAreas.Add(pArea);
}
else if (bOcclArea)
{
m_lstOcclAreas.Add(pArea);
}
UpdateConnections();
delete m_pAABBTree;
m_pAABBTree = NULL;
}
void CVisAreaManager::UpdateConnections()
{
// Reset connectivity
for (int p = 0; p < m_lstPortals.Count(); p++)
{
m_lstPortals[p]->m_lstConnections.Clear();
}
for (int v = 0; v < m_lstVisAreas.Count(); v++)
{
m_lstVisAreas[v]->m_lstConnections.Clear();
}
// Init connectivity - check intersection of all areas and portals
for (int p = 0; p < m_lstPortals.Count(); p++)
{
for (int v = 0; v < m_lstVisAreas.Count(); v++)
{
if (m_lstVisAreas[v]->IsPortalIntersectAreaInValidWay(m_lstPortals[p]))
{ // if bboxes intersect
m_lstVisAreas[v]->m_lstConnections.Add(m_lstPortals[p]);
m_lstPortals[p]->m_lstConnections.Add(m_lstVisAreas[v]);
// set portal direction
Vec3 vNormal = m_lstVisAreas[v]->GetConnectionNormal(m_lstPortals[p]);
if (m_lstPortals[p]->m_lstConnections.Count() <= 2)
{
m_lstPortals[p]->m_vConnNormals[m_lstPortals[p]->m_lstConnections.Count() - 1] = vNormal;
}
}
}
}
}
void CVisAreaManager::MoveObjectsIntoList(PodArray<SRNInfo>* plstVisAreasEntities, const AABB& boxArea, bool bRemoveObjects)
{
for (int p = 0; p < m_lstPortals.Count(); p++)
{
if (m_lstPortals[p]->m_pObjectsTree && Overlap::AABB_AABB(m_lstPortals[p]->m_boxArea, boxArea))
{
m_lstPortals[p]->m_pObjectsTree->MoveObjectsIntoList(plstVisAreasEntities, bRemoveObjects ? NULL : &boxArea, bRemoveObjects);
}
}
for (int v = 0; v < m_lstVisAreas.Count(); v++)
{
if (m_lstVisAreas[v]->m_pObjectsTree && Overlap::AABB_AABB(m_lstVisAreas[v]->m_boxArea, boxArea))
{
m_lstVisAreas[v]->m_pObjectsTree->MoveObjectsIntoList(plstVisAreasEntities, bRemoveObjects ? NULL : &boxArea, bRemoveObjects);
}
}
}
bool CVisAreaManager::IntersectsVisAreas(const AABB& box, void** pNodeCache)
{
FUNCTION_PROFILER_3DENGINE;
if (!m_pAABBTree)
{
UpdateAABBTree();
}
SAABBTreeNode* pTopNode = m_pAABBTree->GetTopNode(box, pNodeCache);
return pTopNode->IntersectsVisAreas(box);
}
bool CVisAreaManager::ClipOutsideVisAreas(Sphere& sphere, Vec3 const& vNormal, void* pNodeCache)
{
FUNCTION_PROFILER_3DENGINE;
if (!m_pAABBTree)
{
UpdateAABBTree();
}
AABB box(sphere.center - Vec3(sphere.radius), sphere.center + Vec3(sphere.radius));
SAABBTreeNode* pTopNode = m_pAABBTree->GetTopNode(box, &pNodeCache);
return pTopNode->ClipOutsideVisAreas(sphere, vNormal) > 0;
}
//This is used by the editor. Use the visareas pool for all areas, so prefetching
// is still safe.
CVisArea* CVisAreaManager::CreateVisArea(VisAreaGUID visGUID)
{
return new CVisArea(visGUID);
}
bool CVisAreaManager::IsEntityVisAreaVisibleReqursive(CVisArea* pVisArea, int nMaxReqursion, PodArray<CVisArea*>* pUnavailableAreas, const CDLight* pLight, const SRenderingPassInfo& passInfo)
{
int nAreaId = pUnavailableAreas->Count();
pUnavailableAreas->Add(pVisArea);
bool bFound = false;
if (pVisArea)
{ // check is lsource area was rendered in prev frame
if (abs(pVisArea->m_nRndFrameId - passInfo.GetFrameID()) > 2)
{
if (nMaxReqursion > 1)
{
for (int n = 0; n < pVisArea->m_lstConnections.Count(); n++)
{ // loop other sectors
CVisArea* pNeibArea = (CVisArea*)pVisArea->m_lstConnections[n];
if (-1 == pUnavailableAreas->Find(pNeibArea) &&
(!pLight || Overlap::Sphere_AABB(Sphere(pLight->m_Origin, pLight->m_fRadius), *pNeibArea->GetAABBox())))
{
if (IsEntityVisAreaVisibleReqursive(pNeibArea, nMaxReqursion - 1, pUnavailableAreas, pLight, passInfo))
{
bFound = true;
break;
}//if visible
}
}// for
}
}
else
{
bFound = true;
}
}
else if (IsOutdoorAreasVisible()) //Indirect - outdoor can be a problem!
{
bFound = true;
}
pUnavailableAreas->Delete(nAreaId);
return bFound;
}
bool CVisAreaManager::IsEntityVisAreaVisible(IRenderNode* pEnt, int nMaxReqursion, const CDLight* pLight, const SRenderingPassInfo& passInfo)
{
if (!pEnt)
{
return false;
}
PodArray<CVisArea*>& lUnavailableAreas = m_tmpLstUnavailableAreas;
lUnavailableAreas.Clear();
lUnavailableAreas.PreAllocate(nMaxReqursion, 0);
return IsEntityVisAreaVisibleReqursive((CVisArea*)pEnt->GetEntityVisArea(), nMaxReqursion, &lUnavailableAreas, pLight, passInfo);
/*
if(pEnt->GetEntityVisArea())
{
if(pEnt->GetEntityVisArea())//->IsPortal())
{ // check is lsource area was rendered in prev frame
CVisArea * pVisArea = pEnt->GetEntityVisArea();
int nRndFrameId = passInfo.GetFrameID();
if(abs(pVisArea->m_nRndFrameId - nRndFrameId)>2)
{
if(!nCheckNeighbors)
return false; // this area is not visible
// try neibhour areas
bool bFound = false;
if(pEnt->GetEntityVisArea()->IsPortal())
{
CVisArea * pPort = pEnt->GetEntityVisArea();
for(int n=0; n<pPort->m_lstConnections.Count(); n++)
{ // loop other sectors
CVisArea * pNeibArea = (CVisArea*)pPort->m_lstConnections[n];
if(abs(pNeibArea->m_nRndFrameId - passInfo.GetFrameID())<=2)
{
bFound=true;
break;
}
}
}
else
{
for(int t=0; !bFound && t<pVisArea->m_lstConnections.Count(); t++)
{ // loop portals
CVisArea * pPort = (CVisArea*)pVisArea->m_lstConnections[t];
if(abs(pPort->m_nRndFrameId - passInfo.GetFrameID())<=2)
{
bFound=true;
break;
}
for(int n=0; n<pPort->m_lstConnections.Count(); n++)
{ // loop other sectors
CVisArea * pNeibArea = (CVisArea*)pPort->m_lstConnections[n];
if(abs(pNeibArea->m_nRndFrameId - passInfo.GetFrameID())<=2)
{
bFound=true;
break;
}
}
}
}
if(!bFound)
return false;
return true;
}
}
else
return false; // not visible
}
else if(!IsOutdoorAreasVisible())
return false;
return true;
*/
}
int __cdecl CVisAreaManager__CmpDistToPortal(const void* v1, const void* v2)
{
CVisArea* p1 = *((CVisArea**)v1);
CVisArea* p2 = *((CVisArea**)v2);
if (!p1 || !p2)
{
return 0;
}
if (p1->m_fDistance > p2->m_fDistance)
{
return 1;
}
else if (p1->m_fDistance < p2->m_fDistance)
{
return -1;
}
return 0;
}
void CVisAreaManager::MakeActiveEntransePortalsList(const CCamera* pCamera, PodArray<CVisArea*>& lstActiveEntransePortals, CVisArea* pThisPortal, const SRenderingPassInfo& passInfo)
{
lstActiveEntransePortals.Clear();
float fZoomFactor = pCamera ? (0.2f + 0.8f * (RAD2DEG(pCamera->GetFov()) / 90.f)) : 1.f;
for (int nPortalId = 0; nPortalId < m_lstPortals.Count(); nPortalId++)
{
CVisArea* pPortal = m_lstPortals[nPortalId];
if (pPortal->m_lstConnections.Count() == 1 && pPortal != pThisPortal && pPortal->IsActive() && !pPortal->m_bSkyOnly)
{
if (!pCamera || pCamera->IsAABBVisible_F(pPortal->m_boxStatics))
{
Vec3 vNormal = pPortal->m_lstConnections[0]->GetConnectionNormal(pPortal);
Vec3 vCenter = (pPortal->m_boxArea.min + pPortal->m_boxArea.max) * 0.5f;
if (vNormal.Dot(vCenter - (pCamera ? pCamera->GetPosition() : passInfo.GetCamera().GetPosition())) < 0)
{
continue;
}
/*
if(pCurPortal)
{
vNormal = pCurPortal->m_vConnNormals[0];
if(vNormal.Dot(vCenter - curCamera.GetPosition())<0)
continue;
}
*/
pPortal->m_fDistance = pPortal->m_boxArea.GetDistance(pCamera ? pCamera->GetPosition() : passInfo.GetCamera().GetPosition());
float fRadius = (pPortal->m_boxArea.max - pPortal->m_boxArea.min).GetLength() * 0.5f;
if (pPortal->m_fDistance * fZoomFactor > fRadius * pPortal->m_fViewDistRatio * GetFloatCVar(e_ViewDistRatioPortals) / 60.f)
{
continue;
}
SPortalColdData* pColdData = static_cast<SPortalColdData*>(pPortal->GetColdData());
Get3DEngine()->CheckCreateRNTmpData(&pColdData->m_pRNTmpData, NULL, passInfo);
// test occlusion
if (GetObjManager()->IsBoxOccluded(pPortal->m_boxStatics, pPortal->m_fDistance, &pColdData->m_pRNTmpData->userData.m_OcclState, false, eoot_PORTAL, passInfo))
{
continue;
}
lstActiveEntransePortals.Add(pPortal);
// if(GetCVars()->e_Portals==3)
// DrawBBox(pPortal->m_boxStatics.min, pPortal->m_boxStatics.max);
}
}
}
// sort by distance
if (lstActiveEntransePortals.Count())
{
qsort(&lstActiveEntransePortals[0], lstActiveEntransePortals.Count(),
sizeof(lstActiveEntransePortals[0]), CVisAreaManager__CmpDistToPortal);
// m_pCurPortal = lstActiveEntransePortals[0];
}
}
void CVisAreaManager::DrawOcclusionAreasIntoCBuffer([[maybe_unused]] CCullBuffer* pCBuffer, const SRenderingPassInfo& passInfo)
{
FUNCTION_PROFILER_3DENGINE;
m_lstActiveOcclVolumes.Clear();
m_lstIndoorActiveOcclVolumes.Clear();
#if defined(OCCLUSIONCULLER_W)
m_allActiveVerts.resize(0);
m_allActiveVerts.reserve(m_lstOcclAreas.Count());
#endif
float fZoomFactor = 0.2f + 0.8f * (RAD2DEG(passInfo.GetCamera().GetFov()) / 90.f);
float fDistRatio = GetFloatCVar(e_OcclusionVolumesViewDistRatio) / fZoomFactor;
if (GetCVars()->e_OcclusionVolumes)
{
for (int i = 0; i < m_lstOcclAreas.Count(); i++)
{
CVisArea* pArea = m_lstOcclAreas[i];
if (passInfo.GetCamera().IsAABBVisible_E(pArea->m_boxArea))
{
float fRadius = (pArea->m_boxArea.min - pArea->m_boxArea.max).GetLength();
Vec3 vPos = (pArea->m_boxArea.min + pArea->m_boxArea.max) * 0.5f;
float fDist = passInfo.GetCamera().GetPosition().GetDistance(vPos);
if (fDist < fRadius * pArea->m_fViewDistRatio * fDistRatio && pArea->m_lstShapePoints.Count() >= 2)
{
int nRecursiveLevel = passInfo.GetRecursiveLevel();
if (!pArea->m_arrOcclCamera[nRecursiveLevel])
{
pArea->m_arrOcclCamera[nRecursiveLevel] = new CCamera;
}
*pArea->m_arrOcclCamera[nRecursiveLevel] = passInfo.GetCamera();
SActiveVerts activeVerts;
if (pArea->m_lstShapePoints.Count() == 4)
{
activeVerts.arrvActiveVerts[0] = pArea->m_lstShapePoints[0];
activeVerts.arrvActiveVerts[1] = pArea->m_lstShapePoints[1];
activeVerts.arrvActiveVerts[2] = pArea->m_lstShapePoints[2];
activeVerts.arrvActiveVerts[3] = pArea->m_lstShapePoints[3];
}
else
{
activeVerts.arrvActiveVerts[0] = pArea->m_lstShapePoints[0];
activeVerts.arrvActiveVerts[1] = pArea->m_lstShapePoints[0] + Vec3(0, 0, pArea->m_fHeight);
activeVerts.arrvActiveVerts[2] = pArea->m_lstShapePoints[1] + Vec3(0, 0, pArea->m_fHeight);
activeVerts.arrvActiveVerts[3] = pArea->m_lstShapePoints[1];
}
Plane plane;
plane.SetPlane(activeVerts.arrvActiveVerts[0], activeVerts.arrvActiveVerts[2], activeVerts.arrvActiveVerts[1]);
if (plane.DistFromPlane(passInfo.GetCamera().GetPosition()) < 0)
{
std::swap(activeVerts.arrvActiveVerts[0], activeVerts.arrvActiveVerts[3]);
std::swap(activeVerts.arrvActiveVerts[1], activeVerts.arrvActiveVerts[2]);
}
else if (!pArea->m_bDoubleSide)
{
continue;
}
// GetRenderer()->SetMaterialColor(1,0,0,1);
pArea->UpdatePortalCameraPlanes(*pArea->m_arrOcclCamera[passInfo.GetRecursiveLevel()], activeVerts.arrvActiveVerts, false, passInfo);
// make far plane never clip anything
#if defined(OCCLUSIONCULLER_W)
m_allActiveVerts.push_back(activeVerts);
#endif
Plane newNearPlane;
newNearPlane.SetPlane(activeVerts.arrvActiveVerts[0], activeVerts.arrvActiveVerts[2], activeVerts.arrvActiveVerts[1]);
pArea->m_arrOcclCamera[passInfo.GetRecursiveLevel()]->SetFrustumPlane(FR_PLANE_NEAR, newNearPlane);
Plane newFarPlane;
newFarPlane.SetPlane(Vec3(0, 1, -1024), Vec3(1, 0, -1024), Vec3(0, 0, -1024));
pArea->m_arrOcclCamera[passInfo.GetRecursiveLevel()]->SetFrustumPlane(FR_PLANE_FAR, newFarPlane);
//pArea->m_arrOcclCamera[m_nRenderStackLevel]->UpdateFrustum();
m_lstActiveOcclVolumes.Add(pArea);
pArea->m_fDistance = fDist;
}
}
}
}
if (m_lstActiveOcclVolumes.Count())
{ // sort occluders by distance to the camera
qsort(&m_lstActiveOcclVolumes[0], m_lstActiveOcclVolumes.Count(),
sizeof(m_lstActiveOcclVolumes[0]), CVisAreaManager__CmpDistToPortal);
// remove occluded occluders
for (int i = m_lstActiveOcclVolumes.Count() - 1; i >= 0; i--)
{
CVisArea* pArea = m_lstActiveOcclVolumes[i];
AABB extrudedBox = pArea->m_boxStatics;
extrudedBox.min -= Vec3(VEC_EPSILON, VEC_EPSILON, VEC_EPSILON);
extrudedBox.max += Vec3(VEC_EPSILON, VEC_EPSILON, VEC_EPSILON);
if (IsOccludedByOcclVolumes(extrudedBox, passInfo))
{
m_lstActiveOcclVolumes.Delete(i);
}
}
#ifdef OCCLUSIONCULLER_W
// draw them into the CBuffer
for (size_t i = 0, size = m_allActiveVerts.size(); i < size; i++)
{
pCBuffer->AddOccluderPlane(m_allActiveVerts[i].arrvActiveVerts);
}
#endif
// put indoor occluders into separate list
for (int i = m_lstActiveOcclVolumes.Count() - 1; i >= 0; i--)
{
CVisArea* pArea = m_lstActiveOcclVolumes[i];
if (pArea->m_bUseInIndoors)
{
m_lstIndoorActiveOcclVolumes.Add(pArea);
}
}
if (GetCVars()->e_Portals == 4)
{ // show really active occluders
for (int i = 0; i < m_lstActiveOcclVolumes.Count(); i++)
{
CVisArea* pArea = m_lstActiveOcclVolumes[i];
GetRenderer()->SetMaterialColor(0, 1, 0, 1);
DrawBBox(pArea->m_boxStatics.min, pArea->m_boxStatics.max);
}
}
}
}
void CVisAreaManager::GetStreamingStatus(int& nLoadedSectors, int& nTotalSectors)
{
nLoadedSectors = 0;
nTotalSectors = m_lstPortals.Count() + m_lstVisAreas.Count();
}
void CVisAreaManager::GetMemoryUsage(ICrySizer* pSizer) const
{
// areas
for (int v = 0; v < m_lstVisAreas.Count(); v++)
{
m_lstVisAreas[v]->GetMemoryUsage(pSizer);
}
// portals
for (int v = 0; v < m_lstPortals.Count(); v++)
{
m_lstPortals[v]->GetMemoryUsage(pSizer);
}
// occl areas
for (int v = 0; v < m_lstOcclAreas.Count(); v++)
{
m_lstOcclAreas[v]->GetMemoryUsage(pSizer);
}
pSizer->AddObject(this, sizeof(*this));
}
void CVisAreaManager::PrecacheLevel(bool bPrecacheAllVisAreas, Vec3* pPrecachePoints, int nPrecachePointsNum)
{
CryLog("Precaching the level ...");
// gEnv->pLog->UpdateLoadingScreen(0);
float fPrecacheTimeStart = GetTimer()->GetAsyncCurTime();
GetRenderer()->EnableSwapBuffers((GetCVars()->e_PrecacheLevel >= 2) ? true : false);
uint32 dwPrecacheLocations = 0;
Vec3 arrCamDir[6] =
{
Vec3(1, 0, 0),
Vec3(-1, 0, 0),
Vec3(0, 1, 0),
Vec3(0, -1, 0),
Vec3(0, 0, 1),
Vec3(0, 0, -1)
};
//loop over all sectors and place a light in the middle of the sector
for (int v = 0; v < m_lstVisAreas.Count() && bPrecacheAllVisAreas; v++)
{
GetRenderer()->EF_Query(EFQ_IncrementFrameID);
++dwPrecacheLocations;
// find real geometry bbox
/* bool bGeomFound = false;
Vec3 vBoxMin(100000.f,100000.f,100000.f);
Vec3 vBoxMax(-100000.f,-100000.f,-100000.f);
for(int s=0; s<ENTITY_LISTS_NUM; s++)
for(int e=0; e<m_lstVisAreas[v]->m_lstEntities[s].Count(); e++)
{
AABB aabbBox = m_lstVisAreas[v]->m_lstEntities[s][e].aabbBox;
vBoxMin.CheckMin(aabbBox.min);
vBoxMax.CheckMax(aabbBox.max);
bGeomFound = true;
}*/
Vec3 vAreaCenter = m_lstVisAreas[v]->m_boxArea.GetCenter();
CryLog(" Precaching VisArea %s", m_lstVisAreas[v]->GetName());
//place camera in the middle of a sector and render sector from different directions
for (int i = 0; i < 6 /*&& bGeomFound*/; i++)
{
GetRenderer()->BeginFrame();
// setup camera
CCamera cam = gEnv->pSystem->GetViewCamera();
Matrix33 mat = Matrix33::CreateRotationVDir(arrCamDir[i], 0);
cam.SetMatrix(mat);
cam.SetPosition(vAreaCenter);
cam.SetFrustum(GetRenderer()->GetWidth(), GetRenderer()->GetHeight(), gf_PI / 2, cam.GetNearPlane(), cam.GetFarPlane());
// Get3DEngine()->SetupCamera(cam);
Get3DEngine()->RenderWorld(SHDF_ZPASS | SHDF_ALLOWHDR | SHDF_ALLOWPOSTPROCESS | SHDF_ALLOW_WATER | SHDF_ALLOW_AO, SRenderingPassInfo::CreateGeneralPassRenderingInfo(cam), "PrecacheVisAreas");
GetRenderer()->RenderDebug();
GetRenderer()->EndFrame();
if (GetCVars()->e_PrecacheLevel >= 2)
{
CrySleep(200);
}
}
}
CryLog("Precached %d visarea sectors", dwPrecacheLocations);
//--------------------------------------------------------------------------------------
//---- PRE-FETCHING OF RENDER-DATA IN OUTDOORS ----
//--------------------------------------------------------------------------------------
// loop over all cam-position in the level and render this part of the level from 6 different directions
for (int p = 0; pPrecachePoints && p < nPrecachePointsNum; p++) //loop over outdoor-camera position
{
CryLog(" Precaching PrecacheCamera point %d of %d", p, nPrecachePointsNum);
for (int i = 0; i < 6; i++) //loop over 6 camera orientations
{
GetRenderer()->BeginFrame();
// setup camera
CCamera cam = gEnv->pSystem->GetViewCamera();
Matrix33 mat = Matrix33::CreateRotationVDir(arrCamDir[i], 0);
cam.SetMatrix(mat);
cam.SetPosition(pPrecachePoints[p]);
cam.SetFrustum(GetRenderer()->GetWidth(), GetRenderer()->GetHeight(), gf_PI / 2, cam.GetNearPlane(), cam.GetFarPlane());
Get3DEngine()->RenderWorld(SHDF_ZPASS | SHDF_ALLOWHDR | SHDF_ALLOWPOSTPROCESS | SHDF_ALLOW_WATER | SHDF_ALLOW_AO, SRenderingPassInfo::CreateGeneralPassRenderingInfo(cam), "PrecacheOutdoor");
GetRenderer()->RenderDebug();
GetRenderer()->EndFrame();
if (GetCVars()->e_PrecacheLevel >= 2)
{
CrySleep(1000);
}
}
}
CryLog("Precached %d PrecacheCameraXX points", nPrecachePointsNum);
GetRenderer()->EnableSwapBuffers(true);
float fPrecacheTime = GetTimer()->GetAsyncCurTime() - fPrecacheTimeStart;
CryLog("Level Precache finished in %.2f seconds", fPrecacheTime);
}
void CVisAreaManager::GetObjectsAround(Vec3 vExploPos, float fExploRadius, PodArray<SRNInfo>* pEntList, bool bSkip_ERF_NO_DECALNODE_DECALS, bool bSkipDynamicObjects)
{
AABB aabbBox(vExploPos - Vec3(fExploRadius, fExploRadius, fExploRadius), vExploPos + Vec3(fExploRadius, fExploRadius, fExploRadius));
CVisArea* pVisArea = (CVisArea*)GetVisAreaFromPos(vExploPos);
if (pVisArea && pVisArea->m_pObjectsTree)
{
pVisArea->m_pObjectsTree->MoveObjectsIntoList(pEntList, &aabbBox, false, true, bSkip_ERF_NO_DECALNODE_DECALS, bSkipDynamicObjects);
}
/*
// find static objects around
for(int i=0; pVisArea && i<pVisArea->m_lstEntities[STATIC_OBJECTS].Count(); i++)
{
IRenderNode * pRenderNode = pVisArea->m_lstEntities[STATIC_OBJECTS][i].pNode;
if(bSkip_ERF_NO_DECALNODE_DECALS && pRenderNode->GetRndFlags()&ERF_NO_DECALNODE_DECALS)
continue;
if(pRenderNode->GetRenderNodeType() == eERType_Decal)
continue;
if(Overlap::Sphere_AABB(Sphere(vExploPos,fExploRadius), pRenderNode->GetBBox()))
if(pEntList->Find(pRenderNode)<0)
pEntList->Add(pRenderNode);
}
}*/
}
void CVisAreaManager::IntersectWithBox(const AABB& aabbBox, PodArray<CVisArea*>* plstResult, [[maybe_unused]] bool bOnlyIfVisible)
{
for (int p = 0; p < m_lstPortals.Count(); p++)
{
if (m_lstPortals[p]->m_boxArea.min.x < aabbBox.max.x&& m_lstPortals[p]->m_boxArea.max.x > aabbBox.min.x &&
m_lstPortals[p]->m_boxArea.min.y < aabbBox.max.y&& m_lstPortals[p]->m_boxArea.max.y > aabbBox.min.y)
{
plstResult->Add(m_lstPortals[p]);
}
}
for (int v = 0; v < m_lstVisAreas.Count(); v++)
{
if (m_lstVisAreas[v]->m_boxArea.min.x < aabbBox.max.x&& m_lstVisAreas[v]->m_boxArea.max.x > aabbBox.min.x &&
m_lstVisAreas[v]->m_boxArea.min.y < aabbBox.max.y&& m_lstVisAreas[v]->m_boxArea.max.y > aabbBox.min.y)
{
plstResult->Add(m_lstVisAreas[v]);
}
}
}
int CVisAreaManager::GetNumberOfVisArea() const
{
return m_lstPortals.size() + m_lstVisAreas.size();
}
IVisArea* CVisAreaManager::GetVisAreaById(int nID) const
{
if (nID < 0)
{
return NULL;
}
if (nID < (int)m_lstPortals.size())
{
return m_lstPortals[ nID ];
}
nID -= m_lstPortals.size();
if (nID < (int)m_lstVisAreas.size())
{
return m_lstVisAreas[ nID ];
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////
void CVisAreaManager::AddListener(IVisAreaCallback* pListener)
{
if (m_lstCallbacks.Find(pListener) < 0)
{
m_lstCallbacks.Add(pListener);
}
}
//////////////////////////////////////////////////////////////////////////
void CVisAreaManager::RemoveListener(IVisAreaCallback* pListener)
{
m_lstCallbacks.Delete(pListener);
}
void CVisAreaManager::CloneRegion(const AABB& region, const Vec3& offset, float zRotation)
{
PodArray<Vec3> points;
PodArray<CVisArea*> visAreas;
IntersectWithBox(region, &visAreas, false);
Vec3 localOrigin = region.GetCenter();
Matrix34 l2w(Matrix33::CreateRotationZ(zRotation));
l2w.SetTranslation(offset);
int numAreas = visAreas.size();
for (int i = 0; i < numAreas; ++i)
{
CVisArea* pSrcArea = visAreas[i];
CVisArea* pCloneArea = CreateVisArea(0);
SVisAreaInfo info;
info.fHeight = pSrcArea->m_fHeight;
info.vAmbientColor = pSrcArea->m_vAmbientColor;
info.bAffectedByOutLights = pSrcArea->m_bAffectedByOutLights;
info.bIgnoreSkyColor = pSrcArea->m_bIgnoreSky;
info.bSkyOnly = pSrcArea->m_bSkyOnly;
info.fViewDistRatio = pSrcArea->m_fViewDistRatio;
info.bDoubleSide = pSrcArea->m_bDoubleSide;
info.bUseDeepness = pSrcArea->m_bUseDeepness;
info.bUseInIndoors = pSrcArea->m_bUseInIndoors;
info.bOceanIsVisible = pSrcArea->m_bOceanVisible;
info.bIgnoreGI = pSrcArea->m_bIgnoreGI;
info.bIgnoreOutdoorAO = pSrcArea->m_bIgnoreOutdoorAO;
points = pSrcArea->m_lstShapePoints;
int numPoints = points.size();
for (int p = 0; p < numPoints; ++p)
{
Vec3& point = points[p];
point -= localOrigin;
point = l2w * point;
}
const char* pName = pSrcArea->m_pVisAreaColdData->m_sName;
UpdateVisArea(pCloneArea, &points[0], numPoints, pName, info);
}
}
void CVisAreaManager::ClearRegion(const AABB& region)
{
PodArray<CVisArea*> visAreas;
IntersectWithBox(region, &visAreas, false);
bool updated = false;
// What we're doing here is basically just what's done in DeleteVisArea, but this
// should be a pooled vis area, so we don't want to actually delete it. Instead we
// just unregister them and let the pool cleanup actually destruct them.
int numAreas = visAreas.size();
for (int i = 0; i < numAreas; ++i)
{
CVisArea* pVisArea = visAreas[i];
// IntersectWithBox only checks x and y, but we want to also make sure it's in the z
if (pVisArea->m_boxArea.min.z < region.max.z && pVisArea->m_boxArea.max.z > region.min.z)
{
bool deletedVis = m_lstVisAreas.Delete(pVisArea);
bool deletedPortal = m_lstPortals.Delete(pVisArea);
bool deletedOccluder = m_lstOcclAreas.Delete(pVisArea);
CRY_ASSERT_MESSAGE(!deletedVis || (m_visAreas.Find(pVisArea) >= 0), "Should only clear pooled vis areas, going to leak");
CRY_ASSERT_MESSAGE(!deletedPortal || (m_portals.Find(pVisArea) >= 0), "Should only clear pooled portals, going to leak");
CRY_ASSERT_MESSAGE(!deletedOccluder || (m_occlAreas.Find(pVisArea) >= 0), "Should only clear pooled occluders, going to leak");
if (deletedVis || deletedPortal || deletedOccluder)
{
updated = true;
}
m_lstActiveOcclVolumes.Delete(pVisArea);
m_lstIndoorActiveOcclVolumes.Delete(pVisArea);
m_lstActiveEntransePortals.Delete(pVisArea);
}
}
if (updated)
{
m_pCurArea = NULL;
m_pCurPortal = NULL;
UpdateConnections();
delete m_pAABBTree;
m_pAABBTree = NULL;
}
}
void CVisAreaManager::ActivateObjectsLayer(uint16 nLayerId, bool bActivate, bool bPhys, IGeneralMemoryHeap* pHeap)
{
{
uint32 dwSize = m_lstVisAreas.Count();
for (uint32 dwI = 0; dwI < dwSize; ++dwI)
{
if (m_lstVisAreas[dwI]->m_pObjectsTree)
{
m_lstVisAreas[dwI]->m_pObjectsTree->ActivateObjectsLayer(nLayerId, bActivate, bPhys, pHeap);
}
}
}
{
uint32 dwSize = m_lstPortals.Count();
for (uint32 dwI = 0; dwI < dwSize; ++dwI)
{
if (m_lstPortals[dwI]->m_pObjectsTree)
{
m_lstPortals[dwI]->m_pObjectsTree->ActivateObjectsLayer(nLayerId, bActivate, bPhys, pHeap);
}
}
}
}
void CVisAreaManager::GetObjects(PodArray<IRenderNode*>& lstObjects, const AABB* pBBox)
{
{
uint32 dwSize = m_lstVisAreas.Count();
for (uint32 dwI = 0; dwI < dwSize; ++dwI)
{
if (m_lstVisAreas[dwI]->m_pObjectsTree)
{
m_lstVisAreas[dwI]->m_pObjectsTree->GetObjects(lstObjects, pBBox);
}
}
}
{
uint32 dwSize = m_lstPortals.Count();
for (uint32 dwI = 0; dwI < dwSize; ++dwI)
{
if (m_lstPortals[dwI]->m_pObjectsTree)
{
m_lstPortals[dwI]->m_pObjectsTree->GetObjects(lstObjects, pBBox);
}
}
}
}
void CVisAreaManager::GetObjectsByFlags(uint dwFlags, PodArray<IRenderNode*>& lstObjects)
{
{
uint32 dwSize = m_lstVisAreas.Count();
for (uint32 dwI = 0; dwI < dwSize; ++dwI)
{
if (m_lstVisAreas[dwI]->m_pObjectsTree)
{
m_lstVisAreas[dwI]->m_pObjectsTree->GetObjectsByFlags(dwFlags, lstObjects);
}
}
}
{
uint32 dwSize = m_lstPortals.Count();
for (uint32 dwI = 0; dwI < dwSize; ++dwI)
{
if (m_lstPortals[dwI]->m_pObjectsTree)
{
m_lstPortals[dwI]->m_pObjectsTree->GetObjectsByFlags(dwFlags, lstObjects);
}
}
}
}
void CVisAreaManager::GenerateStatObjAndMatTables(std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, SHotUpdateInfo* pExportInfo)
{
{
uint32 dwSize = m_lstVisAreas.Count();
for (uint32 dwI = 0; dwI < dwSize; ++dwI)
{
if (m_lstVisAreas[dwI]->m_pObjectsTree)
{
m_lstVisAreas[dwI]->m_pObjectsTree->GenerateStatObjAndMatTables(pStatObjTable, pMatTable, pStatInstGroupTable, pExportInfo);
}
}
}
{
uint32 dwSize = m_lstPortals.Count();
for (uint32 dwI = 0; dwI < dwSize; ++dwI)
{
if (m_lstPortals[dwI]->m_pObjectsTree)
{
m_lstPortals[dwI]->m_pObjectsTree->GenerateStatObjAndMatTables(pStatObjTable, pMatTable, pStatInstGroupTable, pExportInfo);
}
}
}
}
bool CVisAreaManager::IsAABBVisibleFromPoint(AABB& box, Vec3 pos)
{
CVisArea* pAreaBox = (CVisArea*)GetVisAreaFromPos(box.GetCenter());
CVisArea* pAreaPos = (CVisArea*)GetVisAreaFromPos(pos);
if (!pAreaBox && !pAreaPos)
{
return true; // no indoors involved
}
PodArray<CVisArea*> arrPortals;
int nRecursion = 0;
Shadowvolume sv;
NAABB_SV::AABB_ReceiverShadowVolume(pos, box, sv);
bool bRes = false;
bRes = FindShortestPathToVisArea(pAreaPos, pAreaBox, arrPortals, nRecursion, sv);
GetRenderer()->DrawLabel(box.GetCenter(), 2, "-%s-", bRes ? "Y" : "N");
GetRenderer()->DrawLabel(pos, 2, "-X-");
DrawLine(pos, box.GetCenter());
DrawBBox(box, bRes ? Col_White : Col_NavyBlue);
return bRes;
}
bool CVisAreaManager::FindShortestPathToVisArea(CVisArea* pThisArea, CVisArea* pTargetArea, PodArray<CVisArea*>& arrVisitedAreas, int& nRecursion, const Shadowvolume& sv)
{
// skip double processing
if (arrVisitedAreas.Find(pThisArea) >= 0)
{
return false;
}
// check if point to box frustum intersects pThisArea visarea
if (pThisArea && !NAABB_SV::Is_AABB_In_ShadowVolume(sv, *pThisArea->GetAABBox()))
{
return false;
}
// check if box visarea reached
if (pThisArea == pTargetArea)
{
return true;
}
// register as already processed
arrVisitedAreas.Add(pThisArea);
// recurse to connections
if (pThisArea)
{
for (int p = 0; p < pThisArea->m_lstConnections.Count(); p++)
{
if (FindShortestPathToVisArea(pThisArea->m_lstConnections[p], pTargetArea, arrVisitedAreas, nRecursion, sv))
{
return true;
}
}
if (pThisArea->IsPortal() && pThisArea->m_lstConnections.Count() == 1 && !pThisArea->m_bSkyOnly)
{
if (FindShortestPathToVisArea(NULL, pTargetArea, arrVisitedAreas, nRecursion, sv))
{
return true;
}
}
}
else
{
for (int p = 0; p < m_lstPortals.Count(); p++)
{
if (m_lstPortals[p]->IsPortal() && m_lstPortals[p]->m_lstConnections.Count() == 1 && !m_lstPortals[p]->m_bSkyOnly)
{
if (FindShortestPathToVisArea(m_lstPortals[p], pTargetArea, arrVisitedAreas, nRecursion, sv))
{
return true;
}
}
}
}
return false;
}
CVisArea* CVisAreaManager::CreateTypeVisArea()
{
CVisArea* pNewVisArea = new CVisArea();
SGenericColdData* pColdData = &m_visAreaColdData.AddNew();
m_visAreas.Add(pNewVisArea);
pColdData->ResetGenericData();
pNewVisArea->SetColdDataPtr(pColdData);
return pNewVisArea;
}
CVisArea* CVisAreaManager::CreateTypePortal()
{
CVisArea* pNewPortal = new CVisArea();
SPortalColdData* pColdData = &m_portalColdData.AddNew();
m_portals.Add(pNewPortal);
pColdData->ResetPortalData();
pNewPortal->SetColdDataPtr(pColdData);
return pNewPortal;
}
CVisArea* CVisAreaManager::CreateTypeOcclArea()
{
CVisArea* pNewOcclArea = new CVisArea();
SGenericColdData* pColdData = &m_occlAreaColdData.AddNew();
m_occlAreas.Add(pNewOcclArea);
pColdData->ResetGenericData();
pNewOcclArea->SetColdDataPtr(pColdData);
return pNewOcclArea;
}
void CVisAreaManager::InitAABBTree()
{
IF (!m_pAABBTree, 0)
{
UpdateAABBTree();
}
}
//////////////////////////////////////////////////////////////////////
// Segmented World
void CVisAreaManager::ReleaseInactiveSegments()
{
for (int i = 0; i < m_arrDeletedVisArea.Count(); i++)
{
int nSlotID = m_arrDeletedVisArea[i];
SAFE_DELETE(m_visAreas[nSlotID]->m_pObjectsTree);
}
m_arrDeletedVisArea.Clear();
for (int i = 0; i < m_arrDeletedPortal.Count(); i++)
{
int nSlotID = m_arrDeletedPortal[i];
SAFE_DELETE(m_portals[nSlotID]->m_pObjectsTree);
}
m_arrDeletedPortal.Clear();
for (int i = 0; i < m_arrDeletedOcclArea.Count(); i++)
{
int nSlotID = m_arrDeletedOcclArea[i];
SAFE_DELETE(m_occlAreas[nSlotID]->m_pObjectsTree);
}
m_arrDeletedOcclArea.Clear();
}
bool CVisAreaManager::CreateSegment(int nSID)
{
if (nSID >= m_visAreaSegmentData.Count())
{
m_visAreaSegmentData.PreAllocate(nSID + 1, nSID + 1);
m_portalSegmentData.PreAllocate(nSID + 1, nSID + 1);
if (GetCVars()->e_OcclusionVolumes)
{
m_occlAreaSegmentData.PreAllocate(nSID + 1, nSID + 1);
}
}
return true;
}
bool CVisAreaManager::DeleteSegment(int nSID, bool bDeleteNow)
{
if (nSID < 0 || (size_t)nSID >= m_visAreaSegmentData.size())
{
return false;
}
DeleteVisAreaSegment(nSID, m_visAreaSegmentData, m_lstVisAreas, m_visAreas, m_arrDeletedVisArea);
DeleteVisAreaSegment(nSID, m_portalSegmentData, m_lstPortals, m_portals, m_arrDeletedPortal);
if (GetCVars()->e_OcclusionVolumes)
{
DeleteVisAreaSegment(nSID, m_occlAreaSegmentData, m_lstOcclAreas, m_occlAreas, m_arrDeletedOcclArea);
}
if (bDeleteNow)
{
ReleaseInactiveSegments();
}
return true;
}
void CVisAreaManager::DeleteVisAreaSegment(int nSID,
PodArray<CVisAreaSegmentData>& visAreaSegmentData,
PodArray<CVisArea*>& lstVisAreas,
PodArray<CVisArea*, ReservedVisAreaBytes>& visAreas,
PodArray<int>& deletedVisAreas)
{
std::vector<int>& visAreasInSegment = visAreaSegmentData[nSID].m_visAreaIndices;
for (size_t i = 0; i < visAreasInSegment.size(); i++)
{
int index = visAreasInSegment[i];
assert(index >= 0 && index < visAreas.Count());
CSWVisArea* pVisArea = (CSWVisArea*)visAreas[index];
pVisArea->Release();
// delete the visarea if it's ref count reaches zero
if (!pVisArea->NumRefs())
{
deletedVisAreas.push_back(index);
}
}
visAreasInSegment.clear();
for (int i = 0; i < lstVisAreas.Count(); i++)
{
CSWVisArea* pVisArea = (CSWVisArea*)lstVisAreas[i];
if (!pVisArea->NumRefs())
{
lstVisAreas.Delete(i);
}
}
}
CVisArea* CVisAreaManager::FindVisAreaByGuid(VisAreaGUID guid, PodArray<CVisArea*>& lstVisAreas)
{
if (!guid)
{
for (int i = 0; i < lstVisAreas.Count(); i++)
{
if (lstVisAreas[i] && guid == lstVisAreas[i]->m_nVisGUID)
{
return lstVisAreas[i];
}
}
}
return NULL;
}
void CVisAreaManager::OffsetPosition(const Vec3& delta)
{
for (int i = 0; i < m_lstVisAreas.Count(); i++)
{
m_lstVisAreas[i]->OffsetPosition(delta);
}
for (int i = 0; i < m_lstPortals.Count(); i++)
{
m_lstPortals[i]->OffsetPosition(delta);
}
for (int i = 0; i < m_lstOcclAreas.Count(); i++)
{
m_lstOcclAreas[i]->OffsetPosition(delta);
}
if (m_pAABBTree)
{
m_pAABBTree->OffsetPosition(delta);
}
}