!B (CE-20767) Enabled opaque rendering and shadows for GPU particles. Added ZPassGPU...
[CRYENGINE.git] / Code / CryEngine / Cry3DEngine / VisAreaMan.cpp
blobb704ba177681acc28bf25cf729a887d4998530d8
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 // -------------------------------------------------------------------------
4 // File name: statobjmandraw.cpp
5 // Version: v1.00
6 // Created: 18/12/2002 by Vladimir Kajalin
7 // Compilers: Visual Studio.NET
8 // Description: Visibility areas
9 // -------------------------------------------------------------------------
10 // History:
12 ////////////////////////////////////////////////////////////////////////////
14 #include "StdAfx.h"
15 #include <CryAnimation/ICryAnimation.h>
17 #include "StatObj.h"
18 #include "ObjMan.h"
19 #include "VisAreas.h"
20 #include "terrain_sector.h"
21 #include "terrain.h"
22 #include <CryMath/AABBSV.h>
23 #include "3dEngine.h"
25 #define DEFAULT_INITIAL_PORTALS 1
26 #define DEFAULT_INITIAL_VISAREAS 1
27 #define DEFAULT_INITIAL_OCCLAREAS 1
29 CVisAreaManager::CVisAreaManager()
31 m_pCurPortal = m_pCurArea = 0;
32 m_bOutdoorVisible = false;
33 m_bSkyVisible = false;
34 m_bSunIsNeeded = false;
35 m_bOceanVisible = false;
36 m_pAABBTree = NULL;
38 m_visAreas.PreAllocate(DEFAULT_INITIAL_VISAREAS);
39 m_visAreaColdData.PreAllocate(DEFAULT_INITIAL_VISAREAS);
41 m_portals.PreAllocate(DEFAULT_INITIAL_PORTALS);
42 m_portalColdData.PreAllocate(DEFAULT_INITIAL_PORTALS);
44 m_occlAreas.PreAllocate(DEFAULT_INITIAL_OCCLAREAS);
45 m_occlAreaColdData.PreAllocate(DEFAULT_INITIAL_OCCLAREAS);
47 m_segVisAreas.Clear();
48 m_segPortals.Clear();
49 m_segOcclAreas.Clear();
52 void CVisAreaManager::DeleteAllVisAreas()
54 for (int i = 0; i < m_lstVisAreas.Count(); i++)
56 if (m_visAreas.Find(m_lstVisAreas[i]) >= 0)
58 delete m_lstVisAreas[i];
60 else
62 delete m_lstVisAreas[i]->GetColdData();
63 delete m_lstVisAreas[i];
67 m_visAreas.Clear();
68 m_visAreaColdData.Clear();
69 m_lstVisAreas.Clear();
71 for (int i = 0; i < m_lstPortals.Count(); i++)
73 if (m_portals.Find(m_lstPortals[i]) >= 0)
75 delete m_lstPortals[i];
77 else
79 delete m_lstPortals[i]->GetColdData();
80 delete m_lstPortals[i];
84 m_portals.Clear();
85 m_portalColdData.Clear();
86 m_lstPortals.Clear();
88 for (int i = 0; i < m_lstOcclAreas.Count(); i++)
90 if (m_occlAreas.Find(m_lstOcclAreas[i]) >= 0)
92 delete m_lstOcclAreas[i];
94 else
96 delete m_lstOcclAreas[i]->GetColdData();
97 delete m_lstOcclAreas[i];
101 m_occlAreas.Clear();
102 m_occlAreaColdData.Clear();
103 m_lstOcclAreas.Clear();
105 stl::free_container(CVisArea::m_lUnavailableAreas);
108 void SAABBTreeNode::OffsetPosition(const Vec3& delta)
110 nodeBox.Move(delta);
111 if (!nodeAreas.Count())
113 for (int i = 0; i < 2; i++)
115 if (arrChilds[i])
116 arrChilds[i]->OffsetPosition(delta);
121 CVisAreaManager::~CVisAreaManager()
123 DeleteAllVisAreas();
125 delete m_pAABBTree;
126 m_pAABBTree = NULL;
129 SAABBTreeNode::SAABBTreeNode(PodArray<CVisArea*>& lstAreas, AABB box, int nRecursion)
131 memset(this, 0, sizeof(*this));
133 nodeBox = box;
135 nRecursion++;
136 if (nRecursion > 8 || lstAreas.Count() < 8)
138 nodeAreas.AddList(lstAreas);
139 return;
142 PodArray<CVisArea*> lstAreas0, lstAreas1;
143 Vec3 vSize = nodeBox.GetSize();
144 Vec3 vCenter = nodeBox.GetCenter();
146 AABB nodeBox0 = nodeBox;
147 AABB nodeBox1 = nodeBox;
149 if (vSize.x >= vSize.y && vSize.x >= vSize.z)
151 nodeBox0.min.x = vCenter.x;
152 nodeBox1.max.x = vCenter.x;
154 else if (vSize.y >= vSize.x && vSize.y >= vSize.z)
156 nodeBox0.min.y = vCenter.y;
157 nodeBox1.max.y = vCenter.y;
159 else
161 nodeBox0.min.z = vCenter.z;
162 nodeBox1.max.z = vCenter.z;
165 for (int i = 0; i < lstAreas.Count(); i++)
167 if (Overlap::AABB_AABB(nodeBox0, *lstAreas[i]->GetAABBox()))
168 lstAreas0.Add(lstAreas[i]);
170 if (Overlap::AABB_AABB(nodeBox1, *lstAreas[i]->GetAABBox()))
171 lstAreas1.Add(lstAreas[i]);
174 if (lstAreas0.Count())
175 arrChilds[0] = new SAABBTreeNode(lstAreas0, nodeBox0, nRecursion);
177 if (lstAreas1.Count())
178 arrChilds[1] = new SAABBTreeNode(lstAreas1, nodeBox1, nRecursion);
181 SAABBTreeNode::~SAABBTreeNode()
183 delete arrChilds[0];
184 delete arrChilds[1];
187 SAABBTreeNode* SAABBTreeNode::GetTopNode(const AABB& box, void** pNodeCache)
189 AABB boxClip = box;
190 boxClip.ClipToBox(nodeBox);
192 SAABBTreeNode* pNode = this;
193 if (pNodeCache)
195 pNode = (SAABBTreeNode*)*pNodeCache;
196 if (!pNode || !pNode->nodeBox.ContainsBox(boxClip))
197 pNode = this;
200 // Find top node containing box.
201 for (;;)
203 int i;
204 for (i = 0; i < 2; i++)
206 if (pNode->arrChilds[i] && pNode->arrChilds[i]->nodeBox.ContainsBox(boxClip))
208 pNode = pNode->arrChilds[i];
209 break;
212 if (i == 2)
213 break;
216 if (pNodeCache)
217 *(SAABBTreeNode**)pNodeCache = pNode;
218 return pNode;
221 bool SAABBTreeNode::IntersectsVisAreas(const AABB& box)
223 if (nodeBox.IsIntersectBox(box))
225 if (nodeAreas.Count())
227 // leaf
228 for (int i = 0; i < nodeAreas.Count(); i++)
230 if (nodeAreas[i]->m_bActive && nodeAreas[i]->m_boxArea.IsIntersectBox(box))
231 return true;
234 else
236 // node
237 for (int i = 0; i < 2; i++)
238 if (arrChilds[i])
239 if (arrChilds[i]->IntersectsVisAreas(box))
240 return true;
243 return false;
246 int SAABBTreeNode::ClipOutsideVisAreas(Sphere& sphere, Vec3 const& vNormal)
248 int nClipped = 0;
250 if (sphere.radius > FLT_MAX * 0.01f || Overlap::Sphere_AABB(sphere, nodeBox))
252 if (nodeAreas.Count())
254 // leaf
255 for (int i = 0; i < nodeAreas.Count(); i++)
257 if (nodeAreas[i]->m_bActive && Overlap::Sphere_AABB(sphere, nodeAreas[i]->m_boxArea))
258 nClipped += nodeAreas[i]->ClipToVisArea(false, sphere, vNormal);
261 else
263 // node
264 for (int i = 0; i < 2; i++)
265 if (arrChilds[i])
266 nClipped += arrChilds[i]->ClipOutsideVisAreas(sphere, vNormal);
270 return nClipped;
273 void CVisAreaManager::UpdateAABBTree()
275 delete m_pAABBTree;
276 PodArray<CVisArea*> lstAreas;
277 lstAreas.AddList(m_lstPortals);
278 lstAreas.AddList(m_lstVisAreas);
280 AABB nodeBox;
281 nodeBox.min = Vec3(1000000, 1000000, 1000000);
282 nodeBox.max = -nodeBox.min;
283 for (int i = 0; i < lstAreas.Count(); i++)
284 nodeBox.Add(*lstAreas[i]->GetAABBox());
286 m_pAABBTree = new SAABBTreeNode(lstAreas, nodeBox);
289 bool CVisAreaManager::IsEntityVisible(IRenderNode* pEnt) const
291 if (GetCVars()->e_Portals == 3)
292 return true;
294 if (!pEnt->GetEntityVisArea())
295 return IsOutdoorAreasVisible();
297 return true;
300 void CVisAreaManager::SetCurAreas(const SRenderingPassInfo& passInfo)
302 m_pCurArea = 0;
303 m_pCurPortal = 0;
305 if (!GetCVars()->e_Portals)
306 return;
308 if (!m_pAABBTree)
309 UpdateAABBTree();
311 CVisArea* pFound = m_pAABBTree->FindVisarea(passInfo.GetCamera().GetOccPos());
313 #ifdef _DEBUG
315 // find camera portal id
316 for (int v = 0; v < m_lstPortals.Count(); v++)
317 if (m_lstPortals[v]->m_bActive && m_lstPortals[v]->IsPointInsideVisArea(passInfo.GetCamera().GetOccPos()))
319 m_pCurPortal = m_lstPortals[v];
320 break;
323 // if not inside any portal - try to find area
324 if (!m_pCurPortal)
326 // int nFoundAreasNum = 0;
328 // find camera area
329 for (int nVolumeId = 0; nVolumeId < m_lstVisAreas.Count(); nVolumeId++)
331 if (m_lstVisAreas[nVolumeId]->IsPointInsideVisArea(passInfo.GetCamera().GetOccPos()))
333 // nFoundAreasNum++;
334 m_pCurArea = m_lstVisAreas[nVolumeId];
335 break;
339 // if(nFoundAreasNum>1) // if more than one area found - set cur area to undefined
341 // todo: try to set joining portal as current
342 // m_pCurArea = 0;
346 assert(pFound == m_pCurArea || pFound == m_pCurPortal);
348 #endif // _DEBUG
350 if (pFound)
352 if (pFound->IsPortal())
353 m_pCurPortal = pFound;
354 else
355 m_pCurArea = pFound;
358 // camera is in outdoors
359 m_lstActiveEntransePortals.Clear();
360 if (!m_pCurArea && !m_pCurPortal)
361 MakeActiveEntransePortalsList(&passInfo.GetCamera(), m_lstActiveEntransePortals, 0, passInfo);
364 if(m_pCurArea)
366 IVisArea * arrAreas[8];
367 int nres = m_pCurArea->GetVisAreaConnections(arrAreas, 8);
368 nres=nres;
370 DefineTrees();*/
372 /* if(GetCVars()->e_Portals == 4)
374 if(m_pCurPortal)
376 IVisArea * arrAreas[64];
377 int nConnections = m_pCurPortal->GetVisAreaConnections(arrAreas,64);
378 PrintMessage("CurPortal = %s, nConnections = %d", m_pCurPortal->m_sName, nConnections);
381 if(m_pCurArea)
383 IVisArea * arrAreas[64];
384 int nConnections = m_pCurArea->GetVisAreaConnections(arrAreas,64);
385 PrintMessage("CurArea = %s, nRes = %d", m_pCurArea->m_sName, nConnections);
390 /*void CVisAreaManager::SetAreaFogVolume(CTerrain * pTerrain, CVisArea * pVisArea)
392 pVisArea->m_pFogVolume=0;
393 for(int f=0; f<Get3DEngine()->GetFogVolumes().Count(); f++)
395 const Vec3 & v1Min = Get3DEngine()->GetFogVolumes()[f].box.min;
396 const Vec3 & v1Max = Get3DEngine()->GetFogVolumes()[f].box.max;
397 const Vec3 & v2Min = pVisArea->m_boxArea.min;
398 const Vec3 & v2Max = pVisArea->m_boxArea.max;
400 if(v1Max.x>v2Min.x && v2Max.x>v1Min.x)
401 if(v1Max.y>v2Min.y && v2Max.y>v1Min.y)
402 if(v1Max.z>v2Min.z && v2Max.z>v1Min.z)
403 if(!Get3DEngine()->GetFogVolumes()[f].bOcean)
405 Vec3 arrVerts3d[8] =
407 Vec3(v1Min.x,v1Min.y,v1Min.z),
408 Vec3(v1Min.x,v1Max.y,v1Min.z),
409 Vec3(v1Max.x,v1Min.y,v1Min.z),
410 Vec3(v1Max.x,v1Max.y,v1Min.z),
411 Vec3(v1Min.x,v1Min.y,v1Max.z),
412 Vec3(v1Min.x,v1Max.y,v1Max.z),
413 Vec3(v1Max.x,v1Min.y,v1Max.z),
414 Vec3(v1Max.x,v1Max.y,v1Max.z)
417 bool bIntersect = false;
418 for(int i=0; i<8; i++)
419 if(pVisArea->IsPointInsideVisArea(arrVerts3d[i]))
421 bIntersect = true;
422 break;
425 if(!bIntersect)
426 if(pVisArea->IsPointInsideVisArea((v1Min+v1Max)*0.5f))
427 bIntersect = true;
429 if(!bIntersect)
431 for(int i=0; i<pVisArea->m_lstShapePoints.Count(); i++)
432 if(Get3DEngine()->GetFogVolumes()[f].IsInsideBBox(pVisArea->m_lstShapePoints[i]))
434 bIntersect = true;
435 break;
439 if(!bIntersect)
441 Vec3 vCenter = (pVisArea->m_boxArea.min+pVisArea->m_boxArea.max)*0.5f;
442 if(Get3DEngine()->GetFogVolumes()[f].IsInsideBBox(vCenter))
443 bIntersect = true;
446 if(bIntersect)
448 pVisArea->m_pFogVolume = &Get3DEngine()->GetFogVolumes()[f];
449 Get3DEngine()->GetFogVolumes()[f].bIndoorOnly = true;
450 pTerrain->UnregisterFogVolumeFromOutdoor(&Get3DEngine()->GetFogVolumes()[f]);
451 break;
457 void CVisAreaManager::PortalsDrawDebug()
459 UpdateConnections();
461 if(m_pCurArea)
463 for(int p=0; p<m_pCurArea->m_lstConnections.Count(); p++)
465 CVisArea * pPortal = m_pCurArea->m_lstConnections[p];
466 float fBlink = gEnv->pTimer->GetFrameStartTime().GetPeriodicFraction(1.0f)>0.5f ? 1.0f : 0.0f;
467 float fError = pPortal->IsPortalValid() ? 1.0f : fBlink;
468 GetRenderer()->SetMaterialColor(fError,fError*(pPortal->m_lstConnections.Count()<2),0,0.25f);
469 DrawBBox(pPortal->m_boxArea.min, pPortal->m_boxArea.max, DPRIM_SOLID_BOX);
470 GetRenderer()->DrawLabel((pPortal->m_boxArea.min+ pPortal->m_boxArea.max)*0.5f,
471 2,pPortal->m_sName);
474 else*/
476 // debug draw areas
477 Vec3 oneVec(1, 1, 1);
478 for (int v = 0; v < m_lstVisAreas.Count(); v++)
480 DrawBBox(m_lstVisAreas[v]->m_boxArea.min, m_lstVisAreas[v]->m_boxArea.max, ColorB(0, 255, 0, 64)); //, DPRIM_SOLID_BOX);
481 IRenderAuxText::DrawLabelEx((m_lstVisAreas[v]->m_boxArea.min + m_lstVisAreas[v]->m_boxArea.max) * 0.5f, 1, (float*)&oneVec, 0, 1, m_lstVisAreas[v]->GetName());
482 DrawBBox(m_lstVisAreas[v]->m_boxStatics, Col_LightGray);
485 // debug draw portals
486 for (int v = 0; v < m_lstPortals.Count(); v++)
488 CVisArea* pPortal = m_lstPortals[v];
490 float fBlink = gEnv->pTimer->GetFrameStartTime().GetPeriodicFraction(1.0f) > 0.5f ? 1.0f : 0.0f;
491 float fError = pPortal->IsPortalValid() ? 1.f : fBlink;
493 ColorB col(
494 (int)clamp_tpl(fError * 255.0f, 0.0f, 255.0f),
495 (int)clamp_tpl(fError * (pPortal->m_lstConnections.Count() < 2) * 255.0f, 0.0f, 255.0f),
497 64);
498 DrawBBox(pPortal->m_boxArea.min, pPortal->m_boxArea.max, col);
500 IRenderAuxText::DrawLabelEx((pPortal->m_boxArea.min + pPortal->m_boxArea.max) * 0.5f, 1, (float*)&oneVec, 0, 1, pPortal->GetName());
502 Vec3 vCenter = (pPortal->m_boxArea.min + pPortal->m_boxArea.max) * 0.5f;
503 DrawBBox(vCenter - Vec3(0.1f, 0.1f, 0.1f), vCenter + Vec3(0.1f, 0.1f, 0.1f));
505 int nConnections = pPortal->m_lstConnections.Count();
506 if (nConnections == 1)
507 col = ColorB(0, 255, 0, 64);
508 else
509 col = ColorB(0, 0, 255, 64);
511 for (int i = 0; i < nConnections && i < 2; i++)
512 DrawLine(vCenter, vCenter + pPortal->m_vConnNormals[i], col);
514 DrawBBox(pPortal->m_boxStatics.min, pPortal->m_boxStatics.max, col);
518 // debug draw area shape
519 GetRenderer()->SetMaterialColor(0,0,1,0.25f);
520 for(int v=0; v<m_lstVisAreas.Count(); v++)
521 for(int p=0; p<m_lstVisAreas[v]->m_lstShapePoints.Count(); p++)
522 GetRenderer()->DrawLabel(m_lstVisAreas[v]->m_lstShapePoints[p], 2,"%d", p);
523 for(int v=0; v<m_lstPortals.Count(); v++)
524 for(int p=0; p<m_lstPortals[v]->m_lstShapePoints.Count(); p++)
525 GetRenderer()->DrawLabel(m_lstPortals[v]->m_lstShapePoints[p], 2,"%d", p);*/
529 void CVisAreaManager::DrawVisibleSectors(const SRenderingPassInfo& passInfo, FrustumMaskType passCullMask)
531 FUNCTION_PROFILER_3DENGINE;
533 for (int i = 0; i < m_lstVisibleAreas.Count(); i++)
535 CVisArea* pArea = m_lstVisibleAreas[i];
536 Vec3 vAmbColor = pArea->GetFinalAmbientColor();
537 if (pArea->IsObjectsTreeValid())
539 for (int c = 0; c < pArea->m_lstCurCamerasLen; c++)
541 passInfo.GetRendItemSorter().IncreaseOctreeCounter();
542 // create a new RenderingPassInfo object, which a camera matching the visarea
543 pArea->GetObjectsTree()->Render_Object_Nodes(false, OCTREENODE_RENDER_FLAG_OBJECTS, vAmbColor, passCullMask,
544 SRenderingPassInfo::CreateTempRenderingInfo(CVisArea::s_tmpCameras[pArea->m_lstCurCamerasIdx + c], passInfo));
549 passInfo.GetRendItemSorter().IncreaseGroupCounter();
552 void CVisAreaManager::PhysicalizeInBox(const AABB& bbox)
554 for (int i = 0; i < m_lstVisAreas.Count(); i++)
556 CVisArea* pArea = m_lstVisAreas[i];
557 if (pArea && pArea->IsObjectsTreeValid() && Overlap::AABB_AABB(*pArea->GetAABBox(), bbox))
559 pArea->GetObjectsTree()->PhysicalizeInBox(bbox);
562 for (int i = 0; i < m_lstPortals.Count(); i++)
564 CVisArea* pArea = m_lstPortals[i];
565 if (pArea && pArea->IsObjectsTreeValid() && Overlap::AABB_AABB(*pArea->GetAABBox(), bbox))
567 pArea->GetObjectsTree()->PhysicalizeInBox(bbox);
571 void CVisAreaManager::DephysicalizeInBox(const AABB& bbox)
573 for (int i = 0; i < m_lstVisAreas.Count(); i++)
575 CVisArea* pArea = m_lstVisAreas[i];
576 if (pArea && pArea->IsObjectsTreeValid() && Overlap::AABB_AABB(*pArea->GetAABBox(), bbox))
578 pArea->GetObjectsTree()->DephysicalizeInBox(bbox);
581 for (int i = 0; i < m_lstPortals.Count(); i++)
583 CVisArea* pArea = m_lstPortals[i];
584 if (pArea && pArea->IsObjectsTreeValid() && Overlap::AABB_AABB(*pArea->GetAABBox(), bbox))
586 pArea->GetObjectsTree()->DephysicalizeInBox(bbox);
591 void CVisAreaManager::CheckVis(const SRenderingPassInfo& passInfo)
593 FUNCTION_PROFILER_3DENGINE;
594 MEMSTAT_CONTEXT(EMemStatContextType::Other, "CVisAreaManager::CheckVis");
596 if (passInfo.IsGeneralPass())
598 m_bOutdoorVisible = false;
599 m_bSkyVisible = false;
600 m_bOceanVisible = false;
601 CVisArea::s_tmpCameras.Clear();
604 m_lstOutdoorPortalCameras.Clear();
605 m_lstVisibleAreas.Clear();
606 m_bSunIsNeeded = false;
608 SetCurAreas(passInfo);
610 CCamera camRoot = passInfo.GetCamera();
612 camRoot.m_ScissorInfo.x1 = 0;
613 camRoot.m_ScissorInfo.y1 = 0;
614 camRoot.m_ScissorInfo.x2 = camRoot.GetViewSurfaceX();
615 camRoot.m_ScissorInfo.y2 = camRoot.GetViewSurfaceZ();
617 if (GetCVars()->e_Portals == 3)
619 // draw everything for debug
620 for (int i = 0; i < m_lstVisAreas.Count(); i++)
621 if (camRoot.IsAABBVisible_F(AABB(m_lstVisAreas[i]->m_boxArea.min, m_lstVisAreas[i]->m_boxArea.max)))
622 m_lstVisAreas[i]->PreRender(0, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
624 for (int i = 0; i < m_lstPortals.Count(); i++)
625 if (camRoot.IsAABBVisible_F(AABB(m_lstPortals[i]->m_boxArea.min, m_lstPortals[i]->m_boxArea.max)))
626 m_lstPortals[i]->PreRender(0, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
628 else
630 if (passInfo.IsRecursivePass())
632 // use another starting point for reflections
633 CVisArea* pVisArea = (CVisArea*)GetVisAreaFromPos(camRoot.GetOccPos());
634 if (pVisArea)
635 pVisArea->PreRender(3, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
637 else if (m_pCurArea)
639 // camera inside some sector
640 m_pCurArea->PreRender(GetCVars()->e_PortalsMaxRecursion, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
642 for (int ii = 0; ii < m_lstOutdoorPortalCameras.Count(); ii++) // process all exit portals
644 // for each portal build list of potentially visible entrances into other areas
645 MakeActiveEntransePortalsList(&m_lstOutdoorPortalCameras[ii], m_lstActiveEntransePortals, (CVisArea*)m_lstOutdoorPortalCameras[ii].m_pPortal, passInfo);
646 for (int i = 0; i < m_lstActiveEntransePortals.Count(); i++) // entrance into another building is visible
647 m_lstActiveEntransePortals[i]->PreRender(i == 0 ? 5 : 1,
648 m_lstOutdoorPortalCameras[ii], 0, m_pCurPortal, 0, 0, 0, 0, m_lstVisibleAreas, passInfo);
651 // reset scissor if skybox is visible also thru skyboxonly portal
652 if (m_bSkyVisible && m_lstOutdoorPortalCameras.Count() == 1)
653 m_lstOutdoorPortalCameras[0].m_ScissorInfo.x1 =
654 m_lstOutdoorPortalCameras[0].m_ScissorInfo.x2 =
655 m_lstOutdoorPortalCameras[0].m_ScissorInfo.y1 =
656 m_lstOutdoorPortalCameras[0].m_ScissorInfo.y2 = 0;
658 else if (m_pCurPortal)
660 // camera inside some portal
661 m_pCurPortal->PreRender(GetCVars()->e_PortalsMaxRecursion - 1, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
663 if (m_pCurPortal->m_lstConnections.Count() == 1)
664 m_lstOutdoorPortalCameras.Clear(); // camera in outdoor
666 if (m_pCurPortal->m_lstConnections.Count() == 1 || m_lstOutdoorPortalCameras.Count())
668 // if camera is in exit portal or exit is visible
669 MakeActiveEntransePortalsList(m_lstOutdoorPortalCameras.Count() ? &m_lstOutdoorPortalCameras[0] : &camRoot,
670 m_lstActiveEntransePortals,
671 m_lstOutdoorPortalCameras.Count() ? (CVisArea*)m_lstOutdoorPortalCameras[0].m_pPortal : m_pCurPortal, passInfo);
672 for (int i = 0; i < m_lstActiveEntransePortals.Count(); i++) // entrance into another building is visible
673 m_lstActiveEntransePortals[i]->PreRender(i == 0 ? 5 : 1,
674 m_lstOutdoorPortalCameras.Count() ? m_lstOutdoorPortalCameras[0] : camRoot, 0, m_pCurPortal, 0, 0, 0, 0, m_lstVisibleAreas, passInfo);
675 // m_lstOutdoorPortalCameras.Clear(); // otherwise ocean in fleet was not scissored
678 else if (m_lstActiveEntransePortals.Count())
680 // camera in outdoors - process visible entrance portals
681 for (int i = 0; i < m_lstActiveEntransePortals.Count(); i++)
682 m_lstActiveEntransePortals[i]->PreRender(5, camRoot, 0, m_lstActiveEntransePortals[i], &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible, &m_bOceanVisible, m_lstVisibleAreas, passInfo);
683 m_lstActiveEntransePortals.Clear();
685 // do not recurse to another building since we already processed all potential entrances
686 m_lstOutdoorPortalCameras.Clear(); // use default camera
687 m_bOutdoorVisible = true;
691 if (GetCVars()->e_Portals == 2)
692 PortalsDrawDebug();
694 if (!m_bOutdoorVisible)
696 if (!m_pCurArea && !m_pCurPortal)
697 m_bOutdoorVisible = true; // camera not in the areas
698 else if (m_pCurPortal && m_pCurPortal->m_lstConnections.Count() == 1)
699 m_bOutdoorVisible = true; // camera is in exit portal
701 // exit is visible
702 // note: outdoor camera is no modified in this case
706 void CVisAreaManager::ActivatePortal(const Vec3& vPos, bool bActivate, const char* szEntityName)
708 // bool bFound = false;
710 for (int v = 0; v < m_lstPortals.Count(); v++)
712 AABB aabb;
713 aabb.min = m_lstPortals[v]->m_boxArea.min - Vec3(0.5f, 0.5f, 0.1f);
714 aabb.max = m_lstPortals[v]->m_boxArea.max + Vec3(0.5f, 0.5f, 0.0f);
716 if (Overlap::Point_AABB(vPos, aabb))
718 m_lstPortals[v]->m_bActive = bActivate;
720 // switch to PrintComment once portals activation is working stable
721 PrintMessage("I3DEngine::ActivatePortal(): Portal %s is %s by entity %s at position(%.1f,%.1f,%.1f)",
722 m_lstPortals[v]->GetName(), bActivate ? "Enabled" : "Disabled", szEntityName, vPos.x, vPos.y, vPos.z);
724 // bFound = true;
729 if(!bFound)
731 PrintComment("I3DEngine::ActivatePortal(): Portal not found for entity %s at position(%.1f,%.1f,%.1f)",
732 szEntityName, vPos.x, vPos.y, vPos.z);
737 void CVisAreaManager::ActivateOcclusionAreas(IVisAreaTestCallback* pTest, bool bActivate)
739 for (int v = 0; v < m_lstOcclAreas.Count(); v++)
741 if (pTest->TestVisArea(m_lstOcclAreas[v]))
743 m_lstOcclAreas[v]->m_bActive = bActivate;
748 bool CVisAreaManager::IsValidVisAreaPointer(CVisArea* pVisArea)
750 if (m_lstVisAreas.Find(pVisArea) < 0 &&
751 m_lstPortals.Find(pVisArea) < 0 &&
752 m_lstOcclAreas.Find(pVisArea) < 0)
753 return false;
755 return true;
758 //This is only called from the editor, so pVisArea will not be pool allocated by type
759 bool CVisAreaManager::DeleteVisArea(CVisArea* pVisArea)
761 bool bFound = false;
762 if (m_lstVisAreas.Delete(pVisArea) || m_lstPortals.Delete(pVisArea) || m_lstOcclAreas.Delete(pVisArea))
764 delete pVisArea;
765 bFound = true;
768 m_lstActiveOcclVolumes.Delete(pVisArea);
769 m_lstIndoorActiveOcclVolumes.Delete(pVisArea);
770 m_lstActiveEntransePortals.Delete(pVisArea);
772 m_pCurArea = 0;
773 m_pCurPortal = 0;
774 UpdateConnections();
776 delete m_pAABBTree;
777 m_pAABBTree = NULL;
779 return bFound;
782 /*void CVisAreaManager::LoadVisAreaShapeFromXML(XmlNodeRef pDoc)
784 for(int i=0; i<m_lstVisAreas.Count(); i++)
786 delete m_lstVisAreas[i];
787 m_lstVisAreas.Delete(i);
788 i--;
791 for(int i=0; i<m_lstPortals.Count(); i++)
793 delete m_lstPortals[i];
794 m_lstPortals.Delete(i);
795 i--;
798 // fill list of volumes of shape points
799 XmlNodeRef pObjectsNode = pDoc->findChild("Objects");
800 if (pObjectsNode)
802 for (int i = 0; i < pObjectsNode->getChildCount(); i++)
804 XmlNodeRef pNode = pObjectsNode->getChild(i);
805 if (pNode->isTag("Object"))
807 const char * pType = pNode->getAttr("Type");
808 if (strstr(pType,"OccluderArea") || strstr(pType,"VisArea") || strstr(pType,"Portal"))
810 CVisArea * pArea = new CVisArea();
812 pArea->m_boxArea.max=SetMinBB();
813 pArea->m_boxArea.min=SetMaxBB();
815 // set name
816 strcpy(pArea->m_sName, pNode->getAttr("Name"));
817 strlwr(pArea->m_sName);
819 // set height
820 pNode->getAttr("Height",pArea->m_fHeight);
822 // set ambient color
823 pNode->getAttr("AmbientColor", pArea->m_vAmbColor);
825 // set dynamic ambient color
826 // pNode->getAttr("DynAmbientColor", pArea->m_vDynAmbColor);
828 // set SkyOnly flag
829 pNode->getAttr("SkyOnly", pArea->m_bSkyOnly);
831 // set AfectedByOutLights flag
832 pNode->getAttr("AffectedBySun", pArea->m_bAfectedByOutLights);
834 // set ViewDistRatio
835 pNode->getAttr("ViewDistRatio", pArea->m_fViewDistRatio);
837 // set DoubleSide flag
838 pNode->getAttr("DoubleSide", pArea->m_bDoubleSide);
840 // set UseInIndoors flag
841 pNode->getAttr("UseInIndoors", pArea->m_bUseInIndoors);
843 if(strstr(pType, "OccluderArea"))
844 m_lstOcclAreas.Add(pArea);
845 else if(strstr(pArea->m_sName,"portal") || strstr(pType,"Portal"))
846 m_lstPortals.Add(pArea);
847 else
848 m_lstVisAreas.Add(pArea);
850 // load vertices
851 XmlNodeRef pPointsNode = pNode->findChild("Points");
852 if (pPointsNode)
853 for (int i = 0; i < pPointsNode->getChildCount(); i++)
855 XmlNodeRef pPointNode = pPointsNode->getChild(i);
857 Vec3 vPos;
858 if (pPointNode->isTag("Point") && pPointNode->getAttr("Pos", vPos))
860 pArea->m_lstShapePoints.Add(vPos);
861 pArea->m_boxArea.max.CheckMax(vPos);
862 pArea->m_boxArea.min.CheckMin(vPos);
863 pArea->m_boxArea.max.CheckMax(vPos+Vec3(0,0,pArea->m_fHeight));
864 pArea->m_boxArea.min.CheckMin(vPos+Vec3(0,0,pArea->m_fHeight));
867 pArea->UpdateGeometryBBox();
873 // load area boxes to support old way
874 // LoadVisAreaBoxFromXML(pDoc);
877 //THIS SHOULD ONLY BE CALLED BY THE EDITOR
878 void CVisAreaManager::UpdateVisArea(CVisArea* pArea, const Vec3* pPoints, int nCount, const char* szName, const SVisAreaInfo& info)
880 // on first update there will be nothing to delete, area will be added into list only in this function
881 m_lstPortals.Delete(pArea);
882 m_lstVisAreas.Delete(pArea);
883 m_lstOcclAreas.Delete(pArea);
885 SGenericColdData* pColdData = pArea->GetColdData();
886 if (pColdData != NULL)
888 delete pArea->GetColdData();
889 pArea->SetColdDataPtr(NULL);
892 SGenericColdData* pColdDataPtr = NULL;
894 char sTemp[64];
895 cry_strcpy(sTemp, szName);
896 _strlwr_s(sTemp, sizeof(sTemp));
897 strlwr(sTemp);
899 bool bPortal = false;
900 bool bVisArea = false;
901 bool bOcclArea = false;
903 //TODO: Refactor with code below so it's not horrible
904 if (strstr(sTemp, "portal"))
906 pColdDataPtr = new SPortalColdData();
907 bPortal = true;
909 else if (strstr(sTemp, "visarea"))
911 pColdDataPtr = new SGenericColdData();
912 bVisArea = true;
914 else if (strstr(sTemp, "occlarea"))
916 pColdDataPtr = new SGenericColdData();
917 bOcclArea = true;
919 else
921 pColdDataPtr = new SGenericColdData();
924 assert(pColdDataPtr);
925 pArea->SetColdDataPtr(pColdDataPtr);
927 pArea->Update(pPoints, nCount, sTemp, info);
929 if (bPortal)
931 if (pArea->m_lstConnections.Count() == 1)
932 pArea->UpdateGeometryBBox();
934 m_lstPortals.Add(pArea);
936 else if (bVisArea)
938 m_lstVisAreas.Add(pArea);
940 else if (bOcclArea)
942 m_lstOcclAreas.Add(pArea);
945 UpdateConnections();
947 // disable terrain culling for tunnels
948 pArea->UpdateOcclusionFlagInTerrain();
950 delete m_pAABBTree;
951 m_pAABBTree = NULL;
954 void CVisAreaManager::UpdateConnections()
956 // Reset connectivity
957 for (int p = 0; p < m_lstPortals.Count(); p++)
958 m_lstPortals[p]->m_lstConnections.Clear();
960 for (int v = 0; v < m_lstVisAreas.Count(); v++)
961 m_lstVisAreas[v]->m_lstConnections.Clear();
963 // Init connectivity - check intersection of all areas and portals
964 for (int p = 0; p < m_lstPortals.Count(); p++)
966 for (int v = 0; v < m_lstVisAreas.Count(); v++)
968 if (m_lstVisAreas[v]->IsPortalIntersectAreaInValidWay(m_lstPortals[p]))
970 // if bboxes intersect
971 m_lstVisAreas[v]->m_lstConnections.Add(m_lstPortals[p]);
972 m_lstPortals[p]->m_lstConnections.Add(m_lstVisAreas[v]);
974 // set portal direction
975 Vec3 vNormal = m_lstVisAreas[v]->GetConnectionNormal(m_lstPortals[p]);
976 if (m_lstPortals[p]->m_lstConnections.Count() <= 2)
977 m_lstPortals[p]->m_vConnNormals[m_lstPortals[p]->m_lstConnections.Count() - 1] = vNormal;
983 void CVisAreaManager::MoveObjectsIntoList(PodArray<SRNInfo>* plstVisAreasEntities, const AABB* boxArea, bool bRemoveObjects)
985 for (int p = 0; p < m_lstPortals.Count(); p++)
987 if (m_lstPortals[p]->IsObjectsTreeValid() && (!boxArea || Overlap::AABB_AABB(m_lstPortals[p]->m_boxArea, *boxArea)))
989 m_lstPortals[p]->GetObjectsTree()->MoveObjectsIntoList(plstVisAreasEntities, boxArea, bRemoveObjects);
993 for (int v = 0; v < m_lstVisAreas.Count(); v++)
995 if (m_lstVisAreas[v]->IsObjectsTreeValid() && (!boxArea || Overlap::AABB_AABB(m_lstVisAreas[v]->m_boxArea, *boxArea)))
997 m_lstVisAreas[v]->GetObjectsTree()->MoveObjectsIntoList(plstVisAreasEntities, boxArea, bRemoveObjects);
1002 void CVisAreaManager::CleanUpTrees()
1004 for (int p = 0; p < m_lstPortals.Count(); p++)
1006 if (m_lstPortals[p]->IsObjectsTreeValid())
1008 m_lstPortals[p]->GetObjectsTree()->CleanUpTree();
1012 for (int v = 0; v < m_lstVisAreas.Count(); v++)
1014 if (m_lstVisAreas[v]->IsObjectsTreeValid())
1016 m_lstVisAreas[v]->GetObjectsTree()->CleanUpTree();
1021 bool CVisAreaManager::IntersectsVisAreas(const AABB& box, void** pNodeCache)
1023 FUNCTION_PROFILER_3DENGINE;
1025 if (!m_pAABBTree)
1026 UpdateAABBTree();
1027 SAABBTreeNode* pTopNode = m_pAABBTree->GetTopNode(box, pNodeCache);
1028 return pTopNode->IntersectsVisAreas(box);
1031 bool CVisAreaManager::ClipOutsideVisAreas(Sphere& sphere, Vec3 const& vNormal, void* pNodeCache)
1033 FUNCTION_PROFILER_3DENGINE;
1035 if (!m_pAABBTree)
1036 UpdateAABBTree();
1037 AABB box(sphere.center - Vec3(sphere.radius), sphere.center + Vec3(sphere.radius));
1038 SAABBTreeNode* pTopNode = m_pAABBTree->GetTopNode(box, &pNodeCache);
1039 return pTopNode->ClipOutsideVisAreas(sphere, vNormal) > 0;
1042 //This is used by the editor. Use the visareas pool for all areas, so prefetching
1043 // is still safe.
1044 CVisArea* CVisAreaManager::CreateVisArea(VisAreaGUID visGUID)
1046 return new CVisArea(visGUID);
1049 bool CVisAreaManager::IsEntityVisAreaVisibleRecursive(const CVisArea* pVisArea, int nMaxRecursion, PodArray<const CVisArea*>* pUnavailableAreas, const SRenderLight* pLight, const SRenderingPassInfo& passInfo) const
1051 int nAreaId = pUnavailableAreas->Count();
1052 pUnavailableAreas->Add(pVisArea);
1054 bool bFound = false;
1055 if (pVisArea)
1057 // check is lsource area was rendered in prev frame
1058 if (abs(pVisArea->m_nRndFrameId - passInfo.GetFrameID()) > 2)
1060 if (nMaxRecursion > 1)
1062 for (int n = 0; n < pVisArea->m_lstConnections.Count(); n++)
1064 // loop other sectors
1065 CVisArea* pNeibArea = (CVisArea*)pVisArea->m_lstConnections[n];
1066 if (-1 == pUnavailableAreas->Find(pNeibArea) &&
1067 (!pLight || Overlap::Sphere_AABB(Sphere(pLight->m_Origin, pLight->m_fRadius), *pNeibArea->GetAABBox())))
1069 if (IsEntityVisAreaVisibleRecursive(pNeibArea, nMaxRecursion - 1, pUnavailableAreas, pLight, passInfo))
1071 bFound = true;
1072 break;
1073 } //if visible
1075 } // for
1078 else
1079 bFound = true;
1081 else if (IsOutdoorAreasVisible()) //Indirect - outdoor can be a problem!
1082 bFound = true;
1084 pUnavailableAreas->Delete(nAreaId);
1085 return bFound;
1088 bool CVisAreaManager::IsEntityVisAreaVisible(const IRenderNode* pEnt, int nMaxReqursion, const SRenderLight* pLight, const SRenderingPassInfo& passInfo) const
1090 if (!pEnt)
1091 return false;
1093 PodArray<const CVisArea*> lUnavailableAreas;
1095 lUnavailableAreas.Clear();
1096 lUnavailableAreas.PreAllocate(nMaxReqursion, 0);
1098 return IsEntityVisAreaVisibleRecursive((CVisArea*)pEnt->GetEntityVisArea(), nMaxReqursion, &lUnavailableAreas, pLight, passInfo);
1101 int __cdecl CVisAreaManager__CmpDistToPortal(const void* v1, const void* v2)
1103 CVisArea* p1 = *((CVisArea**)v1);
1104 CVisArea* p2 = *((CVisArea**)v2);
1106 if (!p1 || !p2)
1107 return 0;
1109 if (p1->m_fDistance > p2->m_fDistance)
1110 return 1;
1111 else if (p1->m_fDistance < p2->m_fDistance)
1112 return -1;
1114 return 0;
1117 void CVisAreaManager::MakeActiveEntransePortalsList(const CCamera* pCamera, PodArray<CVisArea*>& lstActiveEntransePortals, CVisArea* pThisPortal, const SRenderingPassInfo& passInfo)
1119 lstActiveEntransePortals.Clear();
1120 float fZoomFactor = passInfo.GetZoomFactor();
1122 for (int nPortalId = 0; nPortalId < m_lstPortals.Count(); nPortalId++)
1124 CVisArea* pPortal = m_lstPortals[nPortalId];
1126 if (pPortal->m_lstConnections.Count() == 1 && pPortal != pThisPortal && pPortal->IsActive() && !pPortal->m_bSkyOnly)
1128 if (!pCamera || pCamera->IsAABBVisible_F(pPortal->m_boxStatics))
1130 Vec3 vNormal = pPortal->m_lstConnections[0]->GetConnectionNormal(pPortal);
1131 Vec3 vCenter = (pPortal->m_boxArea.min + pPortal->m_boxArea.max) * 0.5f;
1132 if (vNormal.Dot(vCenter - (pCamera ? pCamera->GetPosition() : passInfo.GetCamera().GetPosition())) < 0)
1133 continue;
1135 if(pCurPortal)
1137 vNormal = pCurPortal->m_vConnNormals[0];
1138 if(vNormal.Dot(vCenter - curCamera.GetPosition())<0)
1139 continue;
1142 pPortal->m_fDistance = pPortal->m_boxArea.GetDistance(pCamera ? pCamera->GetPosition() : passInfo.GetCamera().GetPosition());
1144 float fRadius = (pPortal->m_boxArea.max - pPortal->m_boxArea.min).GetLength() * 0.5f;
1145 if (pPortal->m_fDistance * fZoomFactor > fRadius * pPortal->m_fViewDistRatio * GetFloatCVar(e_ViewDistRatioPortals) / 60.f)
1146 continue;
1148 SPortalColdData* pColdData = static_cast<SPortalColdData*>(pPortal->GetColdData());
1150 // test occlusion
1151 if (GetObjManager()->IsBoxOccluded(pPortal->m_boxStatics, pPortal->m_fDistance, &pColdData->m_occlusionTestClient, false, eoot_PORTAL, passInfo))
1152 continue;
1154 lstActiveEntransePortals.Add(pPortal);
1156 // if(GetCVars()->e_Portals==3)
1157 // DrawBBox(pPortal->m_boxStatics.min, pPortal->m_boxStatics.max);
1162 // sort by distance
1163 if (lstActiveEntransePortals.Count())
1165 qsort(&lstActiveEntransePortals[0], lstActiveEntransePortals.Count(),
1166 sizeof(lstActiveEntransePortals[0]), CVisAreaManager__CmpDistToPortal);
1167 // m_pCurPortal = lstActiveEntransePortals[0];
1171 void CVisAreaManager::MergeCameras(CCamera& cam1, const CCamera& cam2, const SRenderingPassInfo& passInfo)
1173 assert(0); // under development
1174 /* {
1175 float fDotLR1 = cam1.GetFrustumPlane(FR_PLANE_LEFT )->n.Dot(cam1.GetFrustumPlane(FR_PLANE_RIGHT)->n);
1176 float fDotRL2 = cam2.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_LEFT)->n);
1177 int y=0;
1180 // left-right
1181 float fDotLR = cam1.GetFrustumPlane(FR_PLANE_LEFT)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_RIGHT)->n);
1182 float fDotRL = cam1.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_LEFT)->n);
1183 if (fabs(fDotLR) < fabs(fDotRL))
1185 cam1.SetFrustumPlane(FR_PLANE_RIGHT, *cam2.GetFrustumPlane(FR_PLANE_RIGHT));
1186 cam1.SetPPVertex(2, cam2.GetPPVertex(2));
1187 cam1.SetPPVertex(3, cam2.GetPPVertex(3));
1189 else
1191 cam1.SetFrustumPlane(FR_PLANE_LEFT, *cam2.GetFrustumPlane(FR_PLANE_LEFT));
1192 cam1.SetPPVertex(0, cam2.GetPPVertex(0));
1193 cam1.SetPPVertex(1, cam2.GetPPVertex(1));
1198 float fDotLR1 = cam1.GetFrustumPlane(FR_PLANE_LEFT )->n.Dot(cam1.GetFrustumPlane(FR_PLANE_RIGHT)->n);
1199 float fDotRL2 = cam2.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_LEFT)->n);
1200 int y=0;
1203 // top-bottom
1204 float fDotTB = cam1.GetFrustumPlane(FR_PLANE_TOP )->n.Dot(cam2.GetFrustumPlane(FR_PLANE_BOTTOM)->n);
1205 float fDotBT = cam1.GetFrustumPlane(FR_PLANE_BOTTOM)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_TOP )->n);
1207 if(fDotTB>fDotBT)
1208 cam1.SetFrustumPlane(FR_PLANE_BOTTOM, *cam2.GetFrustumPlane(FR_PLANE_BOTTOM));
1209 else
1210 cam1.SetFrustumPlane(FR_PLANE_TOP, *cam2.GetFrustumPlane(FR_PLANE_TOP));
1212 cam1.SetFrustumPlane(FR_PLANE_NEAR, *passInfo.GetCamera().GetFrustumPlane(FR_PLANE_NEAR));
1213 cam1.SetFrustumPlane(FR_PLANE_FAR, *passInfo.GetCamera().GetFrustumPlane(FR_PLANE_FAR));
1215 cam1.SetFrustumPlane(FR_PLANE_TOP, *passInfo.GetCamera().GetFrustumPlane(FR_PLANE_TOP));
1216 cam1.SetFrustumPlane(FR_PLANE_BOTTOM, *passInfo.GetCamera().GetFrustumPlane(FR_PLANE_BOTTOM));
1218 //cam1.UpdateFrustum();
1220 if(GetCVars()->e_Portals==4)
1222 GetRenderer()->SetMaterialColor(1,1,1,1);
1223 DrawBBox(pVerts[0],pVerts[1],DPRIM_LINE);
1224 GetRenderer()->DrawLabel(pVerts[0],2,"0");
1225 DrawBBox(pVerts[1],pVerts[2],DPRIM_LINE);
1226 GetRenderer()->DrawLabel(pVerts[1],2,"1");
1227 DrawBBox(pVerts[2],pVerts[3],DPRIM_LINE);
1228 GetRenderer()->DrawLabel(pVerts[2],2,"2");
1229 DrawBBox(pVerts[3],pVerts[0],DPRIM_LINE);
1230 GetRenderer()->DrawLabel(pVerts[3],2,"3");
1234 void CVisAreaManager::DrawOcclusionAreasIntoCBuffer(const SRenderingPassInfo& passInfo)
1236 FUNCTION_PROFILER_3DENGINE;
1238 m_lstActiveOcclVolumes.Clear();
1239 m_lstIndoorActiveOcclVolumes.Clear();
1241 float fDistRatio = GetFloatCVar(e_OcclusionVolumesViewDistRatio) * passInfo.GetInverseZoomFactor();
1243 if (GetCVars()->e_OcclusionVolumes)
1244 for (int i = 0; i < m_lstOcclAreas.Count(); i++)
1246 CVisArea* pArea = m_lstOcclAreas[i];
1247 if (pArea->m_bActive && passInfo.GetCamera().IsAABBVisible_E(pArea->m_boxArea))
1249 float fRadius = (pArea->m_boxArea.min - pArea->m_boxArea.max).GetLength();
1250 Vec3 vPos = (pArea->m_boxArea.min + pArea->m_boxArea.max) * 0.5f;
1251 float fDist = passInfo.GetCamera().GetPosition().GetDistance(vPos);
1252 if (fDist < fRadius * pArea->m_fViewDistRatio * fDistRatio && pArea->m_lstShapePoints.Count() >= 2)
1254 int nRecursiveLevel = passInfo.GetRecursiveLevel();
1255 if (!pArea->m_arrOcclCamera[nRecursiveLevel])
1256 pArea->m_arrOcclCamera[nRecursiveLevel] = new CCamera;
1257 *pArea->m_arrOcclCamera[nRecursiveLevel] = passInfo.GetCamera();
1259 SActiveVerts activeVerts;
1261 if (pArea->m_lstShapePoints.Count() == 4)
1263 activeVerts.arrvActiveVerts[0] = pArea->m_lstShapePoints[0];
1264 activeVerts.arrvActiveVerts[1] = pArea->m_lstShapePoints[1];
1265 activeVerts.arrvActiveVerts[2] = pArea->m_lstShapePoints[2];
1266 activeVerts.arrvActiveVerts[3] = pArea->m_lstShapePoints[3];
1268 else
1270 CRY_ASSERT(pArea->m_lstShapePoints.Count() == 2, "Occlusion area only supports planes or quads");
1272 activeVerts.arrvActiveVerts[0] = pArea->m_lstShapePoints[0];
1273 activeVerts.arrvActiveVerts[1] = pArea->m_lstShapePoints[0] + Vec3(0, 0, pArea->m_fHeight);
1274 activeVerts.arrvActiveVerts[2] = pArea->m_lstShapePoints[1] + Vec3(0, 0, pArea->m_fHeight);
1275 activeVerts.arrvActiveVerts[3] = pArea->m_lstShapePoints[1];
1278 Plane plane;
1279 plane.SetPlane(activeVerts.arrvActiveVerts[0], activeVerts.arrvActiveVerts[2], activeVerts.arrvActiveVerts[1]);
1281 if (plane.DistFromPlane(passInfo.GetCamera().GetPosition()) < 0)
1283 std::swap(activeVerts.arrvActiveVerts[0], activeVerts.arrvActiveVerts[3]);
1284 std::swap(activeVerts.arrvActiveVerts[1], activeVerts.arrvActiveVerts[2]);
1286 else if (!pArea->m_bDoubleSide)
1287 continue;
1289 // GetRenderer()->SetMaterialColor(1,0,0,1);
1290 pArea->UpdatePortalCameraPlanes(*pArea->m_arrOcclCamera[passInfo.GetRecursiveLevel()], activeVerts.arrvActiveVerts, false, passInfo);
1292 // make far plane never clip anything
1294 Plane newNearPlane;
1295 newNearPlane.SetPlane(activeVerts.arrvActiveVerts[0], activeVerts.arrvActiveVerts[2], activeVerts.arrvActiveVerts[1]);
1296 pArea->m_arrOcclCamera[passInfo.GetRecursiveLevel()]->SetFrustumPlane(FR_PLANE_NEAR, newNearPlane);
1298 Plane newFarPlane;
1299 newFarPlane.SetPlane(Vec3(0, 1, -1024), Vec3(1, 0, -1024), Vec3(0, 0, -1024));
1300 pArea->m_arrOcclCamera[passInfo.GetRecursiveLevel()]->SetFrustumPlane(FR_PLANE_FAR, newFarPlane);
1301 //pArea->m_arrOcclCamera[m_nRenderStackLevel]->UpdateFrustum();
1303 m_lstActiveOcclVolumes.Add(pArea);
1304 pArea->m_fDistance = fDist;
1309 if (m_lstActiveOcclVolumes.Count())
1311 // sort occluders by distance to the camera
1312 qsort(&m_lstActiveOcclVolumes[0], m_lstActiveOcclVolumes.Count(),
1313 sizeof(m_lstActiveOcclVolumes[0]), CVisAreaManager__CmpDistToPortal);
1315 // remove occluded occluders
1316 for (int i = m_lstActiveOcclVolumes.Count() - 1; i >= 0; i--)
1318 CVisArea* pArea = m_lstActiveOcclVolumes[i];
1319 AABB extrudedBox = pArea->m_boxStatics;
1320 extrudedBox.min -= Vec3(VEC_EPSILON, VEC_EPSILON, VEC_EPSILON);
1321 extrudedBox.max += Vec3(VEC_EPSILON, VEC_EPSILON, VEC_EPSILON);
1322 if (IsOccludedByOcclVolumes(extrudedBox, passInfo))
1323 m_lstActiveOcclVolumes.Delete(i);
1326 // put indoor occluders into separate list
1327 for (int i = m_lstActiveOcclVolumes.Count() - 1; i >= 0; i--)
1329 CVisArea* pArea = m_lstActiveOcclVolumes[i];
1330 if (pArea->m_bUseInIndoors)
1331 m_lstIndoorActiveOcclVolumes.Add(pArea);
1334 if (GetCVars()->e_Portals == 4)
1336 // show really active occluders
1337 for (int i = 0; i < m_lstActiveOcclVolumes.Count(); i++)
1339 CVisArea* pArea = m_lstActiveOcclVolumes[i];
1340 DrawBBox(pArea->m_boxStatics.min, pArea->m_boxStatics.max, ColorB(0, 255, 0));
1347 void CVisAreaManager::CompileObjects()
1349 // areas
1350 for(int v=0; v<m_lstVisAreas.Count(); v++)
1351 m_lstVisAreas[v]->CompileObjects(STATIC_OBJECTS);
1353 // portals
1354 for(int v=0; v<m_lstPortals.Count(); v++)
1355 m_lstPortals[v]->CompileObjects(STATIC_OBJECTS);
1359 void CVisAreaManager::CheckUnload()
1361 m_nLoadedSectors=0;
1363 // areas
1364 for(int v=0; v<m_lstVisAreas.Count(); v++)
1365 m_nLoadedSectors += m_lstVisAreas[v]->CheckUnload();
1367 // portals
1368 for(int v=0; v<m_lstPortals.Count(); v++)
1369 m_nLoadedSectors += m_lstPortals[v]->CheckUnload();
1372 void CVisAreaManager::GetStreamingStatus(int& nLoadedSectors, int& nTotalSectors)
1374 nLoadedSectors = 0;//m_nLoadedSectors;
1375 nTotalSectors = m_lstPortals.Count() + m_lstVisAreas.Count();
1378 void CVisAreaManager::GetMemoryUsage(ICrySizer* pSizer) const
1380 // areas
1381 for (int v = 0; v < m_lstVisAreas.Count(); v++)
1382 m_lstVisAreas[v]->GetMemoryUsage(pSizer);
1384 // portals
1385 for (int v = 0; v < m_lstPortals.Count(); v++)
1386 m_lstPortals[v]->GetMemoryUsage(pSizer);
1388 // occl areas
1389 for (int v = 0; v < m_lstOcclAreas.Count(); v++)
1390 m_lstOcclAreas[v]->GetMemoryUsage(pSizer);
1392 pSizer->AddObject(this, sizeof(*this));
1395 void CVisAreaManager::PrecacheLevel(bool bPrecacheAllVisAreas, Vec3* pPrecachePoints, int nPrecachePointsNum)
1397 CryLog("Precaching the level ...");
1398 // gEnv->pLog->UpdateLoadingScreen(0);
1400 #if !defined(EXCLUDE_NORMAL_LOG)
1401 float fPrecacheTimeStart = GetTimer()->GetAsyncCurTime();
1402 #endif
1404 int nRenderingFlags = SHDF_ZPASS | SHDF_ALLOWHDR | SHDF_ALLOWPOSTPROCESS | SHDF_ALLOW_WATER | SHDF_ALLOW_AO | SHDF_ALLOW_SKY;
1406 GetRenderer()->EnableSwapBuffers((GetCVars()->e_PrecacheLevel >= 2) ? true : false);
1408 uint32 dwPrecacheLocations = 0;
1410 Vec3 arrCamDir[6] =
1412 Vec3(1, 0, 0),
1413 Vec3(-1, 0, 0),
1414 Vec3(0, 1, 0),
1415 Vec3(0, -1, 0),
1416 Vec3(0, 0, 1),
1417 Vec3(0, 0, -1)
1420 //loop over all sectors and place a light in the middle of the sector
1421 for (int v = 0; v < m_lstVisAreas.Count() && bPrecacheAllVisAreas; v++)
1423 GetRenderer()->EF_Query(EFQ_IncrementFrameID);
1425 ++dwPrecacheLocations;
1427 // find real geometry bbox
1428 /* bool bGeomFound = false;
1429 Vec3 vBoxMin(100000.f,100000.f,100000.f);
1430 Vec3 vBoxMax(-100000.f,-100000.f,-100000.f);
1431 for(int s=0; s<ENTITY_LISTS_NUM; s++)
1432 for(int e=0; e<m_lstVisAreas[v]->m_lstEntities[s].Count(); e++)
1434 AABB aabbBox = m_lstVisAreas[v]->m_lstEntities[s][e].aabbBox;
1435 vBoxMin.CheckMin(aabbBox.min);
1436 vBoxMax.CheckMax(aabbBox.max);
1437 bGeomFound = true;
1440 Vec3 vAreaCenter = m_lstVisAreas[v]->m_boxArea.GetCenter();
1441 CryLog(" Precaching VisArea %s", m_lstVisAreas[v]->GetName());
1443 //place camera in the middle of a sector and render sector from different directions
1444 for (int i = 0; i < 6 /*&& bGeomFound*/; i++)
1446 // setup camera
1447 CCamera cam = gEnv->pSystem->GetViewCamera();
1448 Matrix33 mat = Matrix33::CreateRotationVDir(arrCamDir[i], 0);
1449 cam.SetMatrix(mat);
1450 cam.SetPosition(vAreaCenter);
1451 cam.SetFrustum(GetRenderer()->GetOverlayWidth(), GetRenderer()->GetOverlayHeight(), gf_PI / 2, cam.GetNearPlane(), cam.GetFarPlane());
1452 // Get3DEngine()->SetupCamera(cam);
1454 GetRenderer()->BeginFrame({}, SGraphicsPipelineKey::BaseGraphicsPipelineKey);
1455 Get3DEngine()->RenderWorld(nRenderingFlags, SRenderingPassInfo::CreateGeneralPassRenderingInfo(SGraphicsPipelineKey::BaseGraphicsPipelineKey, cam), "PrecacheVisAreas");
1456 GetRenderer()->RenderDebug();
1457 GetRenderer()->EndFrame();
1459 if (GetCVars()->e_PrecacheLevel >= 2)
1460 CrySleep(200);
1464 CryLog("Precached %u visarea sectors", dwPrecacheLocations);
1466 //--------------------------------------------------------------------------------------
1467 //---- PRE-FETCHING OF RENDER-DATA IN OUTDOORS ----
1468 //--------------------------------------------------------------------------------------
1470 // loop over all cam-position in the level and render this part of the level from 6 different directions
1471 for (int p = 0; pPrecachePoints && p < nPrecachePointsNum; p++) //loop over outdoor-camera position
1473 CryLog(" Precaching PrecacheCamera point %d of %d", p, nPrecachePointsNum);
1474 for (int i = 0; i < 6; i++) //loop over 6 camera orientations
1476 // setup camera
1477 CCamera cam = gEnv->pSystem->GetViewCamera();
1478 Matrix33 mat = Matrix33::CreateRotationVDir(arrCamDir[i], 0);
1479 cam.SetMatrix(mat);
1480 cam.SetPosition(pPrecachePoints[p]);
1481 cam.SetFrustum(GetRenderer()->GetOverlayWidth(), GetRenderer()->GetOverlayHeight(), gf_PI / 2, cam.GetNearPlane(), cam.GetFarPlane());
1483 GetRenderer()->BeginFrame({}, SGraphicsPipelineKey::BaseGraphicsPipelineKey);
1484 Get3DEngine()->RenderWorld(nRenderingFlags, SRenderingPassInfo::CreateGeneralPassRenderingInfo(SGraphicsPipelineKey::BaseGraphicsPipelineKey, cam), "PrecacheOutdoor");
1485 GetRenderer()->RenderDebug();
1486 GetRenderer()->EndFrame();
1488 if (GetCVars()->e_PrecacheLevel >= 2)
1489 CrySleep(1000);
1493 CryLog("Precached %d PrecacheCameraXX points", nPrecachePointsNum);
1495 GetRenderer()->EnableSwapBuffers(true);
1497 #if !defined(EXCLUDE_NORMAL_LOG)
1498 float fPrecacheTime = GetTimer()->GetAsyncCurTime() - fPrecacheTimeStart;
1499 CryLog("Level Precache finished in %.2f seconds", fPrecacheTime);
1500 #endif
1503 void CVisAreaManager::GetObjectsAround(Vec3 vExploPos, float fExploRadius, PodArray<SRNInfo>* pEntList, bool bSkip_ERF_NO_DECALNODE_DECALS, bool bSkipDynamicObjects)
1505 AABB aabbBox(vExploPos - Vec3(fExploRadius, fExploRadius, fExploRadius), vExploPos + Vec3(fExploRadius, fExploRadius, fExploRadius));
1507 CVisArea* pVisArea = (CVisArea*)GetVisAreaFromPos(vExploPos);
1509 if (pVisArea && pVisArea->IsObjectsTreeValid())
1511 pVisArea->GetObjectsTree()->MoveObjectsIntoList(pEntList, &aabbBox, false, true, bSkip_ERF_NO_DECALNODE_DECALS, bSkipDynamicObjects);
1515 // find static objects around
1516 for(int i=0; pVisArea && i<pVisArea->m_lstEntities[STATIC_OBJECTS].Count(); i++)
1518 IRenderNode * pRenderNode = pVisArea->m_lstEntities[STATIC_OBJECTS][i].pNode;
1519 if(bSkip_ERF_NO_DECALNODE_DECALS && pRenderNode->GetRndFlags()&ERF_NO_DECALNODE_DECALS)
1520 continue;
1522 if(pRenderNode->GetRenderNodeType() == eERType_Decal)
1523 continue;
1525 if(Overlap::Sphere_AABB(Sphere(vExploPos,fExploRadius), pRenderNode->GetBBox()))
1526 if(pEntList->Find(pRenderNode)<0)
1527 pEntList->Add(pRenderNode);
1531 void CVisAreaManager::IntersectWithBox(const AABB& aabbBox, PodArray<CVisArea*>* plstResult, bool bOnlyIfVisible)
1533 for (int p = 0; p < m_lstPortals.Count(); p++)
1535 if (m_lstPortals[p]->m_boxArea.min.x<aabbBox.max.x && m_lstPortals[p]->m_boxArea.max.x> aabbBox.min.x &&
1536 m_lstPortals[p]->m_boxArea.min.y<aabbBox.max.y && m_lstPortals[p]->m_boxArea.max.y> aabbBox.min.y)
1538 plstResult->Add(m_lstPortals[p]);
1542 for (int v = 0; v < m_lstVisAreas.Count(); v++)
1544 if (m_lstVisAreas[v]->m_boxArea.min.x<aabbBox.max.x && m_lstVisAreas[v]->m_boxArea.max.x> aabbBox.min.x &&
1545 m_lstVisAreas[v]->m_boxArea.min.y<aabbBox.max.y && m_lstVisAreas[v]->m_boxArea.max.y> aabbBox.min.y)
1547 plstResult->Add(m_lstVisAreas[v]);
1552 int CVisAreaManager::GetNumberOfVisArea() const
1554 return m_lstPortals.size() + m_lstVisAreas.size();
1557 IVisArea* CVisAreaManager::GetVisAreaById(int nID) const
1559 if (nID < 0)
1560 return NULL;
1562 if (nID < (int)m_lstPortals.size())
1564 return m_lstPortals[nID];
1566 nID -= m_lstPortals.size();
1567 if (nID < (int)m_lstVisAreas.size())
1569 return m_lstVisAreas[nID];
1572 return NULL;
1575 //////////////////////////////////////////////////////////////////////////
1576 void CVisAreaManager::AddListener(IVisAreaCallback* pListener)
1578 if (m_lstCallbacks.Find(pListener) < 0)
1579 m_lstCallbacks.Add(pListener);
1582 //////////////////////////////////////////////////////////////////////////
1583 void CVisAreaManager::RemoveListener(IVisAreaCallback* pListener)
1585 m_lstCallbacks.Delete(pListener);
1588 void CVisAreaManager::CloneRegion(const AABB& region, const Vec3& offset, float zRotation)
1590 PodArray<Vec3> points;
1592 PodArray<CVisArea*> visAreas;
1593 IntersectWithBox(region, &visAreas, false);
1595 Vec3 localOrigin = region.GetCenter();
1596 Matrix34 l2w(Matrix33::CreateRotationZ(zRotation));
1597 l2w.SetTranslation(offset);
1599 int numAreas = visAreas.size();
1600 for (int i = 0; i < numAreas; ++i)
1602 CVisArea* pSrcArea = visAreas[i];
1603 CVisArea* pCloneArea = CreateVisArea(0);
1605 SVisAreaInfo info;
1606 info.fHeight = pSrcArea->m_fHeight;
1607 info.vAmbientColor = pSrcArea->m_vAmbientColor;
1608 info.bAffectedByOutLights = pSrcArea->m_bAffectedByOutLights;
1609 info.bIgnoreSkyColor = pSrcArea->m_bIgnoreSky;
1610 info.bSkyOnly = pSrcArea->m_bSkyOnly;
1611 info.fViewDistRatio = pSrcArea->m_fViewDistRatio;
1612 info.bDoubleSide = pSrcArea->m_bDoubleSide;
1613 info.bUseDeepness = pSrcArea->m_bUseDeepness;
1614 info.bUseInIndoors = pSrcArea->m_bUseInIndoors;
1615 info.bOceanIsVisible = pSrcArea->m_bOceanVisible;
1616 info.bIgnoreGI = pSrcArea->m_bIgnoreGI;
1617 info.bIgnoreOutdoorAO = pSrcArea->m_bIgnoreOutdoorAO;
1619 points = pSrcArea->m_lstShapePoints;
1620 int numPoints = points.size();
1621 for (int p = 0; p < numPoints; ++p)
1623 Vec3& point = points[p];
1625 point -= localOrigin;
1626 point = l2w * point;
1629 const char* pName = pSrcArea->m_pVisAreaColdData->m_sName;
1631 UpdateVisArea(pCloneArea, &points[0], numPoints, pName, info);
1635 void CVisAreaManager::ClearRegion(const AABB& region)
1637 PodArray<CVisArea*> visAreas;
1638 IntersectWithBox(region, &visAreas, false);
1640 bool updated = false;
1642 // What we're doing here is basically just what's done in DeleteVisArea, but this
1643 // should be a pooled vis area, so we don't want to actually delete it. Instead we
1644 // just unregister them and let the pool cleanup actually destruct them.
1645 int numAreas = visAreas.size();
1646 for (int i = 0; i < numAreas; ++i)
1648 CVisArea* pVisArea = visAreas[i];
1650 // IntersectWithBox only checks x and y, but we want to also make sure it's in the z
1651 if (pVisArea->m_boxArea.min.z < region.max.z && pVisArea->m_boxArea.max.z > region.min.z)
1653 bool deletedVis = m_lstVisAreas.Delete(pVisArea);
1654 bool deletedPortal = m_lstPortals.Delete(pVisArea);
1655 bool deletedOccluder = m_lstOcclAreas.Delete(pVisArea);
1657 CRY_ASSERT(!deletedVis || (m_visAreas.Find(pVisArea) >= 0), "Should only clear pooled vis areas, going to leak");
1658 CRY_ASSERT(!deletedPortal || (m_portals.Find(pVisArea) >= 0), "Should only clear pooled portals, going to leak");
1659 CRY_ASSERT(!deletedOccluder || (m_occlAreas.Find(pVisArea) >= 0), "Should only clear pooled occluders, going to leak");
1661 if (deletedVis || deletedPortal || deletedOccluder)
1663 updated = true;
1666 m_lstActiveOcclVolumes.Delete(pVisArea);
1667 m_lstIndoorActiveOcclVolumes.Delete(pVisArea);
1668 m_lstActiveEntransePortals.Delete(pVisArea);
1672 if (updated)
1674 m_pCurArea = NULL;
1675 m_pCurPortal = NULL;
1676 UpdateConnections();
1678 delete m_pAABBTree;
1679 m_pAABBTree = NULL;
1683 namespace
1685 inline void HelperMarkAllSectorsAsUncompiled(PodArray<CVisArea*>& arrayVisArea)
1687 int s = arrayVisArea.Count();
1688 for (int i = 0; i < s; ++i)
1690 if (arrayVisArea[i]->IsObjectsTreeValid())
1692 arrayVisArea[i]->GetObjectsTree()->MarkAsUncompiled();
1697 inline void HelperActivateObjectsLayer(PodArray<CVisArea*>& arrayVisArea, uint16 nLayerId, bool bActivate, bool bPhys, IGeneralMemoryHeap* pHeap, const AABB& layerBox)
1699 int s = arrayVisArea.Count();
1700 for (int i = 0; i < s; ++i)
1702 if (arrayVisArea[i]->IsObjectsTreeValid())
1704 arrayVisArea[i]->GetObjectsTree()->ActivateObjectsLayer(nLayerId, bActivate, bPhys, pHeap, layerBox);
1709 inline void HelperGetObjects(PodArray<CVisArea*>& arrayVisArea, PodArray<IRenderNode*>& lstObjects, const AABB* pBBox)
1711 int s = arrayVisArea.Count();
1712 for (int i = 0; i < s; ++i)
1714 if (arrayVisArea[i]->IsObjectsTreeValid())
1716 arrayVisArea[i]->GetObjectsTree()->GetObjects(lstObjects, pBBox);
1721 inline void HelperGetObjectsByFlags(PodArray<CVisArea*>& arrayVisArea, uint dwFlags, PodArray<IRenderNode*>& lstObjects)
1723 int s = arrayVisArea.Count();
1724 for (int i = 0; i < s; ++i)
1726 if (arrayVisArea[i]->IsObjectsTreeValid())
1728 arrayVisArea[i]->GetObjectsTree()->GetObjectsByFlags(dwFlags, lstObjects);
1733 inline void HelperGenerateStatObjAndMatTables(PodArray<CVisArea*>& arrayVisArea, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, SHotUpdateInfo* pExportInfo)
1735 int s = arrayVisArea.Count();
1736 for (int i = 0; i < s; ++i)
1738 if (arrayVisArea[i]->IsObjectsTreeValid())
1740 arrayVisArea[i]->GetObjectsTree()->GenerateStatObjAndMatTables(pStatObjTable, pMatTable, pStatInstGroupTable, pExportInfo);
1746 void CVisAreaManager::MarkAllSectorsAsUncompiled()
1748 HelperMarkAllSectorsAsUncompiled(m_lstPortals);
1749 HelperMarkAllSectorsAsUncompiled(m_lstVisAreas);
1752 void CVisAreaManager::ActivateObjectsLayer(uint16 nLayerId, bool bActivate, bool bPhys, IGeneralMemoryHeap* pHeap, const AABB& layerBox)
1754 HelperActivateObjectsLayer(m_lstVisAreas, nLayerId, bActivate, bPhys, pHeap, layerBox);
1755 HelperActivateObjectsLayer(m_lstPortals, nLayerId, bActivate, bPhys, pHeap, layerBox);
1758 void CVisAreaManager::GetObjects(PodArray<IRenderNode*>& lstObjects, const AABB* pBBox)
1760 HelperGetObjects(m_lstVisAreas, lstObjects, pBBox);
1761 HelperGetObjects(m_lstPortals, lstObjects, pBBox);
1764 void CVisAreaManager::GetObjectsByFlags(uint dwFlags, PodArray<IRenderNode*>& lstObjects)
1766 HelperGetObjectsByFlags(m_lstVisAreas, dwFlags, lstObjects);
1767 HelperGetObjectsByFlags(m_lstPortals, dwFlags, lstObjects);
1770 void CVisAreaManager::GenerateStatObjAndMatTables(std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, SHotUpdateInfo* pExportInfo)
1772 HelperGenerateStatObjAndMatTables(m_lstVisAreas, pStatObjTable, pMatTable, pStatInstGroupTable, pExportInfo);
1773 HelperGenerateStatObjAndMatTables(m_lstPortals, pStatObjTable, pMatTable, pStatInstGroupTable, pExportInfo);
1776 bool CVisAreaManager::IsAABBVisibleFromPoint(AABB& box, Vec3 pos) const
1778 CVisArea* pAreaBox = (CVisArea*)GetVisAreaFromPos(box.GetCenter());
1779 CVisArea* pAreaPos = (CVisArea*)GetVisAreaFromPos(pos);
1781 if (!pAreaBox && !pAreaPos)
1782 return true; // no indoors involved
1784 PodArray<CVisArea*> arrPortals;
1785 int nRecursion = 0;
1786 Shadowvolume sv;
1787 NAABB_SV::AABB_ReceiverShadowVolume(pos, box, sv);
1789 bool bRes = FindShortestPathToVisArea(pAreaPos, pAreaBox, arrPortals, nRecursion, sv);
1791 IRenderAuxText::DrawLabelF(box.GetCenter(), 2, "-%s-", bRes ? "Y" : "N");
1792 IRenderAuxText::DrawLabel(pos, 2, "-X-");
1793 DrawLine(pos, box.GetCenter());
1794 DrawBBox(box, bRes ? Col_White : Col_NavyBlue);
1796 return bRes;
1799 bool CVisAreaManager::FindShortestPathToVisArea(CVisArea* pThisArea, CVisArea* pTargetArea, PodArray<CVisArea*>& arrVisitedAreas, int& nRecursion, const Shadowvolume& sv) const
1801 // skip double processing
1802 if (arrVisitedAreas.Find(pThisArea) >= 0)
1803 return false;
1805 // check if point to box frustum intersects pThisArea visarea
1806 if (pThisArea && !NAABB_SV::Is_AABB_In_ShadowVolume(sv, *pThisArea->GetAABBox()))
1807 return false;
1809 // check if box visarea reached
1810 if (pThisArea == pTargetArea)
1811 return true;
1813 // register as already processed
1814 arrVisitedAreas.Add(pThisArea);
1816 // recurse to connections
1817 if (pThisArea)
1819 for (int p = 0; p < pThisArea->m_lstConnections.Count(); p++)
1820 if (FindShortestPathToVisArea(pThisArea->m_lstConnections[p], pTargetArea, arrVisitedAreas, nRecursion, sv))
1821 return true;
1823 if (pThisArea->IsPortal() && pThisArea->m_lstConnections.Count() == 1 && !pThisArea->m_bSkyOnly)
1824 if (FindShortestPathToVisArea(NULL, pTargetArea, arrVisitedAreas, nRecursion, sv))
1825 return true;
1827 else
1829 for (int p = 0; p < m_lstPortals.Count(); p++)
1830 if (m_lstPortals[p]->IsPortal() && m_lstPortals[p]->m_lstConnections.Count() == 1 && !m_lstPortals[p]->m_bSkyOnly)
1831 if (FindShortestPathToVisArea(m_lstPortals[p], pTargetArea, arrVisitedAreas, nRecursion, sv))
1832 return true;
1835 return false;
1838 CVisArea* CVisAreaManager::CreateTypeVisArea()
1840 CVisArea* pNewVisArea = new CVisArea();
1841 SGenericColdData* pColdData = &m_visAreaColdData.AddNew();
1843 m_visAreas.Add(pNewVisArea);
1844 pColdData->ResetGenericData();
1845 pNewVisArea->SetColdDataPtr(pColdData);
1847 return pNewVisArea;
1850 CVisArea* CVisAreaManager::CreateTypePortal()
1852 CVisArea* pNewPortal = new CVisArea();
1853 SPortalColdData* pColdData = &m_portalColdData.AddNew();
1855 m_portals.Add(pNewPortal);
1856 pColdData->ResetPortalData();
1857 pNewPortal->SetColdDataPtr(pColdData);
1859 return pNewPortal;
1862 CVisArea* CVisAreaManager::CreateTypeOcclArea()
1864 CVisArea* pNewOcclArea = new CVisArea();
1865 SGenericColdData* pColdData = &m_occlAreaColdData.AddNew();
1867 m_occlAreas.Add(pNewOcclArea);
1868 pColdData->ResetGenericData();
1869 pNewOcclArea->SetColdDataPtr(pColdData);
1871 return pNewOcclArea;
1874 void CVisAreaManager::InitAABBTree()
1876 IF (!m_pAABBTree, 0)
1878 UpdateAABBTree();
1882 CVisArea* CVisAreaManager::FindVisAreaByGuid(VisAreaGUID guid, PodArray<CVisArea*>& lstVisAreas)
1884 if (!guid)
1886 for (int i = 0; i < lstVisAreas.Count(); i++)
1888 if (lstVisAreas[i] && guid == lstVisAreas[i]->m_nVisGUID)
1889 return lstVisAreas[i];
1893 return NULL;
1896 void CVisAreaManager::OffsetPosition(const Vec3& delta)
1898 for (int i = 0; i < m_lstVisAreas.Count(); i++)
1899 m_lstVisAreas[i]->OffsetPosition(delta);
1901 for (int i = 0; i < m_lstPortals.Count(); i++)
1902 m_lstPortals[i]->OffsetPosition(delta);
1904 for (int i = 0; i < m_lstOcclAreas.Count(); i++)
1905 m_lstOcclAreas[i]->OffsetPosition(delta);
1907 if (m_pAABBTree)
1908 m_pAABBTree->OffsetPosition(delta);