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

1469 lines
45 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjmandraw.cpp
// Version: v1.00
// Created: 18/12/2002 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Visibility areas
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "visareas.h"
#include "terrain_sector.h"
#include "3dengine.h"
#include "cbuffer.h"
#include "3dengine.h"
#include "IMarkers.h"
CVisAreaManager::CVisAreaManager()
{
m_pCurPortal = m_pCurArea = 0;
m_nLoadedSectors = 0;
}
CVisAreaManager::~CVisAreaManager()
{
for(int i=0; i<m_lstVisAreas.Count(); i++)
delete m_lstVisAreas[i];
for(int i=0; i<m_lstPortals.Count(); i++)
delete m_lstPortals[i];
for(int i=0; i<m_lstOcclAreas.Count(); i++)
delete m_lstOcclAreas[i];
}
bool CVisAreaManager::IsEntityVisible(IEntityRender * pEntityRS)
{
if(!pEntityRS->GetEntityRS() || GetCVars()->e_portals==3)
return true;
if(!pEntityRS->GetEntityVisArea())
return IsOutdoorAreasVisible();
return true;
}
void CVisAreaManager::SetCurAreas(CObjManager * pObjManager)
{
m_pCurArea = 0;
m_pCurPortal = 0;
if(!GetCVars()->e_portals)
return;
// find camera portal id
for(int v=0; v<m_lstPortals.Count(); v++)
if(m_lstPortals[v]->m_bActive && m_lstPortals[v]->IsPointInsideVisArea(GetViewCamera().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(GetViewCamera().GetOccPos()))
{
nFoundAreasNum++;
m_pCurArea = m_lstVisAreas[nVolumeId];
}
}
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;
}
}
// camera is in outdoors
m_lstActiveEntransePortals.Clear();
if(!m_pCurArea && !m_pCurPortal)
MakeActiveEntransePortalsList(GetViewCamera(), m_lstActiveEntransePortals, 0, pObjManager);
/*
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);
GetLog()->Log("CurPortal = %s, nConnections = %d", m_pCurPortal->m_sName, nConnections);
}
if(m_pCurArea)
{
IVisArea * arrAreas[64];
int nConnections = m_pCurArea->GetVisAreaConnections(arrAreas,64);
GetLog()->Log("CurArea = %s, nRes = %d", m_pCurArea->m_sName, nConnections);
}
}
}
bool CVisAreaManager::IsSkyVisible()
{
return m_bSkyVisible;
}
bool CVisAreaManager::IsOutdoorAreasVisible()
{
if(!m_pCurArea && !m_pCurPortal)
return m_bOutdoorVisible=true; // camera not in the areas
if(m_pCurPortal && m_pCurPortal->m_lstConnections.Count()==1)
return m_bOutdoorVisible=true; // 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::LoadVisAreaBoxFromXML(XDOM::IXMLDOMDocumentPtr pDoc)
{
{
{ // reset only non shape volumes
for(int i=0; i<m_lstVisAreas.Count(); i++)
{
if(m_lstVisAreas[i]->m_bLoadedAsAreaBox)
{
delete m_lstVisAreas[i];
m_lstVisAreas.Delete(i);
i--;
}
}
for(int i=0; i<m_lstPortals.Count(); i++)
{
if(m_lstPortals[i]->m_bLoadedAsAreaBox)
{
delete m_lstPortals[i];
m_lstPortals.Delete(i);
i--;
}
}
for(int i=0; i<m_lstOcclAreas.Count(); i++)
{
if(m_lstOcclAreas[i]->m_bLoadedAsAreaBox)
{
delete m_lstOcclAreas[i];
m_lstOcclAreas.Delete(i);
i--;
}
}
}
XDOM::IXMLDOMNodeListPtr pNodeTagList;
XDOM::IXMLDOMNodePtr pNodeTag;
pNodeTagList = pDoc->getElementsByTagName("Objects");
if (pNodeTagList)
{
pNodeTagList->reset();
pNodeTag = pNodeTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pNodeList;
pNodeList = pNodeTag->getElementsByTagName("Object");
if (pNodeList)
{
pNodeList->reset();
XDOM::IXMLDOMNodePtr pNode;
while (pNode = pNodeList->nextNode())
{
XDOM::IXMLDOMNodePtr pName = pNode->getAttribute("Type");
if (pName)
{
if (strstr(pName->getText(),"AreaBox"))
{
XDOM::IXMLDOMNodePtr pAttr0,pAttr1,pAttr2,pAttr3,pAttr4,pAttr5;
pAttr0 = pNode->getAttribute("Pos");
pAttr1 = pNode->getAttribute("Width");
pAttr2 = pNode->getAttribute("Length");
pAttr3 = pNode->getAttribute("Height");
pAttr4 = pNode->getAttribute("Name");
if(pAttr0!=0 && pAttr1!=0 && pAttr2!=0 && pAttr3!=0 && pAttr4!=0)
{
CVisArea * pVolumeInfo = new CVisArea(true);
Vec3d vPos = StringToVector(pAttr0->getText());
Vec3d vSize((float)atof(pAttr1->getText()), (float)atof(pAttr2->getText()), (float)atof(pAttr3->getText()));
pVolumeInfo->m_vBoxMax = vPos + Vec3d(vSize.x*0.5f, vSize.y*0.5f, vSize.z);
pVolumeInfo->m_vBoxMin = vPos - Vec3d(vSize.x*0.5f, vSize.y*0.5f, 0);
const Vec3d & min = pVolumeInfo->m_vBoxMin;
const Vec3d & max = pVolumeInfo->m_vBoxMax;
pVolumeInfo->m_lstShapePoints.Add(Vec3d(min.x,min.y,min.z));
pVolumeInfo->m_lstShapePoints.Add(Vec3d(min.x,max.y,min.z));
pVolumeInfo->m_lstShapePoints.Add(Vec3d(max.x,max.y,min.z));
pVolumeInfo->m_lstShapePoints.Add(Vec3d(max.x,min.y,min.z));
pVolumeInfo->m_fHeight = max.z-min.z;
pVolumeInfo->m_vAmbColor = ((C3DEngine*)Get3DEngine())->GetObjManager()->m_vOutdoorAmbientColor;
pVolumeInfo->m_vDynAmbColor = Vec3d(0,0,0);
strncpy(pVolumeInfo->m_sName, pAttr4->getText(), sizeof(pVolumeInfo->m_sName));
pVolumeInfo->UpdateGeometryBBox();
// add volume to list
strlwr(pVolumeInfo->m_sName);
if(strstr(pVolumeInfo->m_sName, "portal"))
m_lstPortals.Add(pVolumeInfo);
else if(strstr(pVolumeInfo->m_sName, "visarea"))
m_lstVisAreas.Add(pVolumeInfo);
else if(strstr(pVolumeInfo->m_sName, "occlarea"))
m_lstOcclAreas.Add(pVolumeInfo);
else
delete pVolumeInfo;
}
}
}
}
}
}
}
UpdateConnections();
}
void CVisAreaManager::SetAreaFogVolume(CTerrain * pTerrain, CVisArea * pVisArea)
{
pVisArea->m_nFogVolumeId=0;
if(pTerrain)
for(int f=0; f<pTerrain->m_lstFogVolumes.Count(); f++)
{
const Vec3d & v1Min = pTerrain->m_lstFogVolumes[f].vBoxMin;
const Vec3d & v1Max = pTerrain->m_lstFogVolumes[f].vBoxMax;
const Vec3d & v2Min = pVisArea->m_vBoxMin;
const Vec3d & v2Max = pVisArea->m_vBoxMax;
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(!pTerrain->m_lstFogVolumes[f].bOcean)
{
Vec3d arrVerts3d[8] =
{
Vec3d(v1Min.x,v1Min.y,v1Min.z),
Vec3d(v1Min.x,v1Max.y,v1Min.z),
Vec3d(v1Max.x,v1Min.y,v1Min.z),
Vec3d(v1Max.x,v1Max.y,v1Min.z),
Vec3d(v1Min.x,v1Min.y,v1Max.z),
Vec3d(v1Min.x,v1Max.y,v1Max.z),
Vec3d(v1Max.x,v1Min.y,v1Max.z),
Vec3d(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(pTerrain->m_lstFogVolumes[f].InsideBBox(pVisArea->m_lstShapePoints[i]))
{
bIntersect = true;
break;
}
}
if(!bIntersect)
{
Vec3d vCenter = (pVisArea->m_vBoxMin+pVisArea->m_vBoxMax)*0.5f;
if(pTerrain->m_lstFogVolumes[f].InsideBBox(vCenter))
bIntersect = true;
}
if(bIntersect)
{
int nFogId = pVisArea->m_nFogVolumeId = pTerrain->m_lstFogVolumes[f].nRendererVolumeID;
pTerrain->m_lstFogVolumes[f].bIndoorOnly = true;
pTerrain->UnregisterFogVolumeFromOutdoor(&pTerrain->m_lstFogVolumes[f]);
break;
}
}
}
}
void CVisAreaManager::SetupFogVolumes(CTerrain * pTerrain)
{
if(pTerrain)
for(int f=0; f<pTerrain->m_lstFogVolumes.Count(); f++)
pTerrain->m_lstFogVolumes[f].bIndoorOnly = false;
// set fog volumes
for(int p=0; p<m_lstPortals.Count(); p++)
SetAreaFogVolume(pTerrain, m_lstPortals[p]);
for(int v=0; v<m_lstVisAreas.Count(); v++)
SetAreaFogVolume(pTerrain, m_lstVisAreas[v]);
}
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 fError = pPortal->IsPortalValid() ? 1.f : int(GetTimer()->GetCurrTime()*8)&1;
GetRenderer()->SetMaterialColor(fError,fError*(pPortal->m_lstConnections.Count()<2),0,0.25f);
GetRenderer()->Draw3dBBox(pPortal->m_vBoxMin, pPortal->m_vBoxMax, DPRIM_SOLID_BOX);
GetRenderer()->DrawLabel((pPortal->m_vBoxMin+ pPortal->m_vBoxMax)*0.5f,
2,pPortal->m_sName);
}
}
else*/
{
// debug draw areas
GetRenderer()->SetMaterialColor(0,1,0,0.25f);
for(int v=0; v<m_lstVisAreas.Count(); v++)
{
GetRenderer()->Draw3dBBox(m_lstVisAreas[v]->m_vBoxMin, m_lstVisAreas[v]->m_vBoxMax, DPRIM_SOLID_BOX);
GetRenderer()->DrawLabelEx((m_lstVisAreas[v]->m_vBoxMin+ m_lstVisAreas[v]->m_vBoxMax)*0.5f,
1,(float*)&Vec3d(1,1,1),0,1,m_lstVisAreas[v]->m_sName);
GetRenderer()->SetMaterialColor(0,1,0,0.25f);
GetRenderer()->Draw3dBBox(m_lstVisAreas[v]->m_vGeomBoxMin, m_lstVisAreas[v]->m_vGeomBoxMax);
}
// debug draw portals
for(int v=0; v<m_lstPortals.Count(); v++)
{
float fError = m_lstPortals[v]->IsPortalValid() ? 1.f : int(GetTimer()->GetCurrTime()*8)&1;
GetRenderer()->SetMaterialColor(fError,fError*(m_lstPortals[v]->m_lstConnections.Count()<2),0,0.25f);
GetRenderer()->Draw3dBBox(m_lstPortals[v]->m_vBoxMin, m_lstPortals[v]->m_vBoxMax, DPRIM_SOLID_BOX);
GetRenderer()->DrawLabelEx((m_lstPortals[v]->m_vBoxMin+ m_lstPortals[v]->m_vBoxMax)*0.5f,
1,(float*)&Vec3d(1,1,1),0,1,m_lstPortals[v]->m_sName);
CVisArea * pPortal = m_lstPortals[v];
Vec3d vCenter = (pPortal->m_vBoxMin+pPortal->m_vBoxMax)*0.5f;
GetRenderer()->Draw3dBBox(vCenter-Vec3d(0.1f,0.1f,0.1f), vCenter+Vec3d(0.1f,0.1f,0.1f));
for(int i=0; i<pPortal->m_lstConnections.Count() && i<2; i++)
GetRenderer()->Draw3dBBox(vCenter, vCenter+pPortal->m_vConnNormals[i], DPRIM_LINE);
GetRenderer()->SetMaterialColor(0,0,1,0.25f);
GetRenderer()->Draw3dBBox(pPortal->m_vGeomBoxMin, pPortal->m_vGeomBoxMax);
}
/*
// 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);*/
}
}
bool CVisAreaManager::SetEntityArea(IEntityRender* pEntityRS)
{
assert(pEntityRS);
CVisArea ** pVisArea = &pEntityRS->m_pVisArea;
Vec3d vEntBMin, vEntBMax;
pEntityRS->GetBBox(vEntBMin, vEntBMax);
Vec3d vEntCenter = (vEntBMin+vEntBMax)*0.5f;
if(pEntityRS->m_dwRndFlags&ERF_DONOTCHECKVIS)
{ // if CS_FLAG_DRAW_NEAR is set (fps weapon) - use camera position because fps weapon bbox is not correct
// temporary solution until weapon bbox will be fixed
ICryCharInstance * pChar;
if ((pChar = pEntityRS->GetEntityCharacter(1)) && (pChar->GetFlags() & CS_FLAG_DRAW_MODEL) && (pChar->GetFlags() & CS_FLAG_DRAW_NEAR))
vEntCenter = GetViewCamera().GetPos();
else if ((pChar = pEntityRS->GetEntityCharacter(0)) && (pChar->GetFlags() & CS_FLAG_DRAW_MODEL) && (pChar->GetFlags() & CS_FLAG_DRAW_NEAR))
vEntCenter = GetViewCamera().GetPos();
}
if (*pVisArea)
{ // detect if we are still in the same area
if ((*pVisArea)->IsPointInsideVisArea(vEntCenter))
return true;
UnRegisterEntity(pEntityRS);
}
*pVisArea = 0;
int nStatic = (pEntityRS->GetEntityRenderType() != eERType_Unknown);
// find portal containing object center
for(int v=0; v<m_lstPortals.Count(); v++)
{
if(m_lstPortals[v]->IsPointInsideVisArea(vEntCenter))
{
*pVisArea = m_lstPortals[v];
if(m_lstPortals[v]->m_lstEntities[nStatic].Find(pEntityRS)<0)
m_lstPortals[v]->m_lstEntities[nStatic].Add(pEntityRS);
break;
}
}
if(!(*pVisArea)) // if portal not found - find volume
for(int v=0; v<m_lstVisAreas.Count(); v++)
{
if(m_lstVisAreas[v]->IsPointInsideVisArea(vEntCenter))
{
*pVisArea = m_lstVisAreas[v];
if(m_lstVisAreas[v]->m_lstEntities[nStatic].Find(pEntityRS)<0)
m_lstVisAreas[v]->m_lstEntities[nStatic].Add(pEntityRS);
break;
}
}
/*if(0&&!(*pVisArea))
{ // if still not found - reduce requirements and detect box intersection
for(int v=0; v<m_lstPortals.Count(); v++)
{
const Vec3d & v2Min = m_lstPortals[v]->m_vBoxMin;
const Vec3d & v2Max = m_lstPortals[v]->m_vBoxMax;
if(vEntBMax.x>v2Min.x && v2Max.x>vEntBMin.x)
if(vEntBMax.y>v2Min.y && v2Max.y>vEntBMin.y)
if(vEntBMax.z>v2Min.z && v2Max.z>vEntBMin.z)
{
*pVisArea = m_lstPortals[v];
if(m_lstPortals[v]->m_lstEntities[nStatic].Find(pEntityRS)<0)
m_lstPortals[v]->m_lstEntities[nStatic].Add(pEntityRS);
break;
}
}
}*/
if(nStatic && *pVisArea) // update bbox of exit portal // if((*pVisArea)->m_lstConnections.Count()==1)
if((*pVisArea)->IsPortal())
(*pVisArea)->UpdateGeometryBBox();
return (*pVisArea) != 0;
}
bool CVisAreaManager::UnRegisterEntity(IEntityRender* pEntityRS)
{
assert(pEntityRS);
bool bFound = false;
int nStatic = (pEntityRS->GetEntityRenderType() != eERType_Unknown);
// unregister in volumes
if(pEntityRS->m_pVisArea)
bFound |= pEntityRS->m_pVisArea->m_lstEntities[nStatic].Delete(pEntityRS);
pEntityRS->m_pVisArea = 0;
/*
#ifdef _DEBUG
{
// find lost registrations
for(int i=0; i<m_lstVisAreas.Count(); i++)
{
if(m_lstVisAreas[i]->m_lstEntities[nStatic].Find(pEntityRS)>=0)
{
m_lstVisAreas[i]->m_lstEntities[nStatic].Delete(pEntityRS);
assert(0);
}
}
for(int i=0; i<m_lstPortals.Count(); i++)
{
if(m_lstPortals[i]->m_lstEntities[nStatic].Find(pEntityRS)>=0)
{
m_lstPortals[i]->m_lstEntities[nStatic].Delete(pEntityRS);
assert(0);
}
}
}
#endif
*/
return bFound;
}
void CVisAreaManager::Render(CObjManager * pObjManager)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
if(!pObjManager->m_nRenderStackLevel)
{
m_bOutdoorVisible = false;
m_bSkyVisible = false;
}
m_lstOutdoorPortalCameras.Clear();
SetCurAreas(pObjManager);
CCamera camRoot = GetViewCamera();
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.IsAABBVisibleFast( AABB(m_lstVisAreas[i]->m_vBoxMin,m_lstVisAreas[i]->m_vBoxMax) ))
m_lstVisAreas[i]->DrawVolume(pObjManager, 0, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible);
for(int i=0; i<m_lstPortals.Count(); i++)
if(camRoot.IsAABBVisibleFast( AABB(m_lstPortals[i]->m_vBoxMin,m_lstPortals[i]->m_vBoxMax) ))
m_lstPortals[i]->DrawVolume(pObjManager, 0, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible);
}
else
{
if(pObjManager->m_nRenderStackLevel)
{ // use another starting point for reflections
CVisArea * pVisArea = (CVisArea *)GetVisAreaFromPos(camRoot.GetOccPos());
if(pVisArea)
pVisArea->DrawVolume(pObjManager, 3, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible);
}
else if(m_pCurArea)
{ // camera inside some sector
m_pCurArea->DrawVolume(pObjManager, 6, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible);
for(int i=0; i<m_lstOutdoorPortalCameras.Count(); i++) // process all exit portals
{ // for each portal build list of potentially visible entrances into other areas
MakeActiveEntransePortalsList(m_lstOutdoorPortalCameras[i], m_lstActiveEntransePortals, (CVisArea*)m_lstOutdoorPortalCameras[i].m_pPortal, pObjManager);
for(int i=0; i<m_lstActiveEntransePortals.Count(); i++) // entrance into another building is visible
m_lstActiveEntransePortals[i]->DrawVolume(pObjManager, i==0 ? 5 : 1,
m_lstOutdoorPortalCameras.Count() ? m_lstOutdoorPortalCameras[0] : camRoot, 0, m_pCurPortal, 0, 0, 0);
}
// make one final camera
/* while(m_lstOutdoorPortalCameras.Count()>1)
{
MergeCameras(m_lstOutdoorPortalCameras[0], m_lstOutdoorPortalCameras[1]);
m_lstOutdoorPortalCameras.Delete(1);
}*/
if(m_lstOutdoorPortalCameras.Count()>1)
m_lstOutdoorPortalCameras.Clear(); // use default camera if more than two exits found
// 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->DrawVolume(pObjManager, 5, camRoot, 0, m_pCurPortal, &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible);
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, pObjManager);
for(int i=0; i<m_lstActiveEntransePortals.Count(); i++) // entrance into another building is visible
m_lstActiveEntransePortals[i]->DrawVolume(pObjManager, i==0 ? 5 : 1,
m_lstOutdoorPortalCameras.Count() ? m_lstOutdoorPortalCameras[0] : camRoot, 0, m_pCurPortal, 0, 0, 0);
m_lstOutdoorPortalCameras.Clear();
}
}
else if(m_lstActiveEntransePortals.Count())
{ // camera in outdoors - process visible entrance portals
for(int i=0; i<m_lstActiveEntransePortals.Count(); i++)
m_lstActiveEntransePortals[i]->DrawVolume(pObjManager, 5, camRoot, 0, m_lstActiveEntransePortals[i], &m_bOutdoorVisible, &m_lstOutdoorPortalCameras, &m_bSkyVisible);
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 Vec3d &vPos, bool bActivate, IEntityRender *pEntity)
{
for(int v=0; v<m_lstPortals.Count(); v++)
if(Overlap::Point_AABB(vPos, m_lstPortals[v]->m_vBoxMin-Vec3d(1,1,1), m_lstPortals[v]->m_vBoxMax+Vec3d(1,1,1)))
m_lstPortals[v]->m_bActive = bActivate;
}
/*
bool CVisAreaManager::IsEntityInVisibleArea(IEntityRenderState * pRS)
{
if( pRS && pRS->plstVisAreaId && pRS->plstVisAreaId->Count() )
{
list2<int> * pVisAreas = pRS->plstVisAreaId;
for(int n=0; n<pVisAreas->Count(); n++)
if( m_lstVisAreas[pVisAreas->GetAt(n)].m_nVisFrameId==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;
}
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_pCurArea = 0;
m_pCurPortal = 0;
UpdateConnections();
return bFound;
}
void CVisAreaManager::LoadVisAreaShapeFromXML(XDOM::IXMLDOMDocumentPtr pDoc)
{
{ // reset only shape volumes
for(int i=0; i<m_lstVisAreas.Count(); i++)
{
if(!m_lstVisAreas[i]->m_bLoadedAsAreaBox)
{
delete m_lstVisAreas[i];
m_lstVisAreas.Delete(i);
i--;
}
}
for(int i=0; i<m_lstPortals.Count(); i++)
{
if(!m_lstPortals[i]->m_bLoadedAsAreaBox)
{
delete m_lstPortals[i];
m_lstPortals.Delete(i);
i--;
}
}
}
// fill list of volumes of shape points
XDOM::IXMLDOMNodeListPtr pNodeTagList;
XDOM::IXMLDOMNodePtr pNodeTag;
pNodeTagList = pDoc->getElementsByTagName("Objects");
if (pNodeTagList)
{
pNodeTagList->reset();
pNodeTag = pNodeTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pNodeList;
pNodeList = pNodeTag->getElementsByTagName("Object");
if (pNodeList)
{
pNodeList->reset();
XDOM::IXMLDOMNodePtr pNode;
while (pNode = pNodeList->nextNode())
{
XDOM::IXMLDOMNodePtr pName = pNode->getAttribute("Type");
if (pName)
{
const char * pType = pName->getText();
if (strstr(pType,"OccluderArea") || strstr(pType,"VisArea") || strstr(pType,"Portal"))
{
CVisArea * pArea = new CVisArea(false);
pArea->m_vBoxMax=SetMinBB();
pArea->m_vBoxMin=SetMaxBB();
// set shader
XDOM::IXMLDOMNodePtr pAttr5 = pNode->getAttribute("Name");
if(pAttr5)
strcpy(pArea->m_sName, pAttr5->getText());
// set height
XDOM::IXMLDOMNodePtr pAttr6 = pNode->getAttribute("Height");
if(pAttr6)
pArea->m_fHeight = (float)atof(pAttr6->getText());
// set ambient color
XDOM::IXMLDOMNodePtr pAttr7 = pNode->getAttribute("AmbientColor");
if(pAttr7)
pArea->m_vAmbColor = StringToVector(pAttr7->getText());
// set dyn ambient color
XDOM::IXMLDOMNodePtr pDynAmbClr = pNode->getAttribute("DynAmbientColor");
if(pDynAmbClr)
pArea->m_vDynAmbColor = StringToVector(pDynAmbClr->getText());
// set SkyOnly flag
XDOM::IXMLDOMNodePtr pAttr8 = pNode->getAttribute("SkyOnly");
if(pAttr8)
pArea->m_bSkyOnly = atol(pAttr8->getText())!=0;
// set AfectedByOutLights flag
XDOM::IXMLDOMNodePtr pAttr9 = pNode->getAttribute("AffectedBySun");
if(pAttr9)
pArea->m_bAfectedByOutLights = atol(pAttr9->getText())!=0;
// set ViewDistRatio
XDOM::IXMLDOMNodePtr pAttr10 = pNode->getAttribute("ViewDistRatio");
if(pAttr10)
pArea->m_fViewDistRatio = (float)atof(pAttr10->getText());
// set DoubleSide flag
XDOM::IXMLDOMNodePtr pAttr11 = pNode->getAttribute("DoubleSide");
if(pAttr11)
pArea->m_bDoubleSide = atol(pAttr11->getText())!=0;
// set UseDeepness flag
// XDOM::IXMLDOMNodePtr pAttr12 = pNode->getAttribute("UseDeepness");
// if(pAttr12)
// pArea->m_bUseDeepness = atol(pAttr12->getText())!=0;
// set UseInIndoors flag
XDOM::IXMLDOMNodePtr pAttr13 = pNode->getAttribute("UseInIndoors");
if(pAttr13)
pArea->m_bUseInIndoors = atol(pAttr13->getText())!=0;
// load vertices
if(pAttr5!=0 && pAttr6!=0)
{
strlwr(pArea->m_sName);
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);
XDOM::IXMLDOMNodeListPtr pNodeTagList;
XDOM::IXMLDOMNodePtr pNodeTag;
pNodeTagList = pNode->getElementsByTagName("Points");
if (pNodeTagList)
{
pNodeTagList->reset();
pNodeTag = pNodeTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pNodeList;
pNodeList = pNodeTag->getElementsByTagName("Point");
if (pNodeList)
{
pNodeList->reset();
XDOM::IXMLDOMNodePtr pNode;
while (pNode = pNodeList->nextNode())
{
XDOM::IXMLDOMNodePtr pPos = pNode->getAttribute("Pos");
if (pPos)
{
Vec3d vPos = StringToVector(pPos->getText());
pArea->m_lstShapePoints.Add(vPos);
pArea->m_vBoxMax.CheckMax(vPos);
pArea->m_vBoxMin.CheckMin(vPos);
pArea->m_vBoxMax.CheckMax(vPos+Vec3d(0,0,pArea->m_fHeight));
pArea->m_vBoxMin.CheckMin(vPos+Vec3d(0,0,pArea->m_fHeight));
}
}
}
pArea->UpdateGeometryBBox();
}
}
}
}
}
}
}
// load area boxes to support old way
// LoadVisAreaBoxFromXML(pDoc);
}
void CVisAreaManager::UpdateVisArea(CVisArea * pArea, const Vec3d * pPoints, int nCount, const char * szName, float fHeight, const Vec3d & vAmbientColor, bool bAfectedByOutLights, bool bSkyOnly, CTerrain*pTerrain, const Vec3 & vDynAmbientColor, float fViewDistRatio, bool bDoubleSide, bool bUseDeepness, bool bUseInIndoors)
{ // on first update there will be nothing to delete, area will be added into list only in this function
m_lstPortals.Delete(pArea);
m_lstVisAreas.Delete(pArea);
m_lstOcclAreas.Delete(pArea);
pArea->Update(pPoints, nCount, szName, fHeight, vAmbientColor, bAfectedByOutLights, bSkyOnly, vDynAmbientColor, fViewDistRatio, bDoubleSide, bUseDeepness, bUseInIndoors);
strlwr(pArea->m_sName);
if(strstr(pArea->m_sName,"portal"))
{
if(pArea->m_lstConnections.Count()==1)
pArea->UpdateGeometryBBox();
m_lstPortals.Add(pArea);
}
else if(strstr(pArea->m_sName,"visarea"))
m_lstVisAreas.Add(pArea);
else if(strstr(pArea->m_sName, "occlarea"))
m_lstOcclAreas.Add(pArea);
UpdateConnections();
SetAreaFogVolume(pTerrain, pArea);
}
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++)
{
// if(strstr(m_lstPortals[p]->m_sName,"l5"))
// int y=0;
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
Vec3d 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::MoveAllEntitiesIntoList(list2<IEntityRender*> * plstVisAreasEntities,
const Vec3d & vBoxMin, const Vec3d & vBoxMax)
{
for(int p=0; p<m_lstPortals.Count(); p++)
{
if( m_lstPortals[p]->m_vBoxMin.x < vBoxMax.x && m_lstPortals[p]->m_vBoxMax.x > vBoxMin.x &&
m_lstPortals[p]->m_vBoxMin.y < vBoxMax.y && m_lstPortals[p]->m_vBoxMax.y > vBoxMin.y )
{
plstVisAreasEntities->AddList(m_lstPortals[p]->m_lstEntities[DYNAMIC_ENTITIES]);
plstVisAreasEntities->AddList(m_lstPortals[p]->m_lstEntities[STATIC_ENTITIES]);
m_lstPortals[p]->m_lstEntities[DYNAMIC_ENTITIES].Clear();
m_lstPortals[p]->m_lstEntities[STATIC_ENTITIES].Clear();
}
}
for(int v=0; v<m_lstVisAreas.Count(); v++)
{
if( m_lstVisAreas[v]->m_vBoxMin.x < vBoxMax.x && m_lstVisAreas[v]->m_vBoxMax.x > vBoxMin.x &&
m_lstVisAreas[v]->m_vBoxMin.y < vBoxMax.y && m_lstVisAreas[v]->m_vBoxMax.y > vBoxMin.y )
{
plstVisAreasEntities->AddList(m_lstVisAreas[v]->m_lstEntities[DYNAMIC_ENTITIES]);
plstVisAreasEntities->AddList(m_lstVisAreas[v]->m_lstEntities[STATIC_ENTITIES]);
m_lstVisAreas[v]->m_lstEntities[DYNAMIC_ENTITIES].Clear();
m_lstVisAreas[v]->m_lstEntities[STATIC_ENTITIES].Clear();
}
}
}
IVisArea * CVisAreaManager::GetVisAreaFromPos(const Vec3d &vPos)
{
// check areas
for(int v=0; v<m_lstVisAreas.Count(); v++)
if(m_lstVisAreas[v]->IsPointInsideVisArea(vPos))
return m_lstVisAreas[v];
// check portals
for(int v=0; v<m_lstPortals.Count(); v++)
if(m_lstPortals[v]->IsPointInsideVisArea(vPos))
return m_lstPortals[v];
return 0;
}
CVisArea * CVisAreaManager::CreateVisArea()
{
CVisArea * p = new CVisArea(false);
return p;
}
/*
void CVisAreaManager::DefineTrees()
{
int nTreeId=0;
for(int v=0; v<m_lstVisAreas.Count(); v++)
{
if(m_lstVisAreas[v]->m_nTreeId != nTreeId)
{
m_lstVisAreas[v]->SetTreeId(nTreeId);
nTreeId++;
}
}
}
*/
bool CVisAreaManager::IsEntityVisAreaVisible(IEntityRender * pEnt, bool nCheckNeighbors)
{
if(pEnt->GetEntityVisArea())
{
if(pEnt->m_pVisArea)//->IsPortal())
{ // check is lsource area was rendered in prev frame
CVisArea * pVisArea = pEnt->m_pVisArea;
int nRndFrameId = 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->m_pVisArea->IsPortal())
{
CVisArea * pPort = pEnt->m_pVisArea;
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 - 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 - 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 - 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 & curCamera, list2<CVisArea *> & lstActiveEntransePortals, CVisArea * pThisPortal, CObjManager * pObjManager)
{
lstActiveEntransePortals.Clear();
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(curCamera.IsAABBVisibleFast( AABB(pPortal->m_vGeomBoxMin,pPortal->m_vGeomBoxMax) ))
{
Vec3d vNormal = pPortal->m_lstConnections[0]->GetConnectionNormal(pPortal);
Vec3d vCenter = (pPortal->m_vBoxMin+pPortal->m_vBoxMax)*0.5f;
if(vNormal.Dot(vCenter - curCamera.GetPos())<0)
continue;
/*
if(pCurPortal)
{
vNormal = pCurPortal->m_vConnNormals[0];
if(vNormal.Dot(vCenter - curCamera.GetPos())<0)
continue;
}
*/
pPortal->m_fDistance = GetDistance( (pPortal->m_vBoxMin+pPortal->m_vBoxMax)*0.5f, curCamera.GetPos() );
float fZoomFactor = 0.2f+0.8f*(RAD2DEG(curCamera.GetFov())/90.f);
float fRadius = (pPortal->m_vBoxMax-pPortal->m_vBoxMin).Length()*0.5f;
if(pPortal->m_fDistance > fRadius*pPortal->m_fViewDistRatio/fZoomFactor)
continue;
// test occlusion by mountains
if(pObjManager->IsBoxOccluded( pPortal->m_vGeomBoxMin, pPortal->m_vGeomBoxMax,pPortal->m_fDistance, &pPortal->m_OcclState))
continue;
// test occlusion by antiportals
if(GetVisAreaManager()->IsOccludedByOcclVolumes(pPortal->m_vGeomBoxMin,pPortal->m_vGeomBoxMax))
continue;
lstActiveEntransePortals.Add(pPortal);
// if(GetCVars()->e_portals==3)
// GetRenderer()->Draw3dBBox(pPortal->m_vGeomBoxMin, pPortal->m_vGeomBoxMax);
}
}
}
// sort by distance
if(lstActiveEntransePortals.Count())
{
qsort(&lstActiveEntransePortals[0], lstActiveEntransePortals.Count(),
sizeof(lstActiveEntransePortals[0]), CVisAreaManager__CmpDistToPortal);
// m_pCurPortal = lstActiveEntransePortals[0];
}
}
void CVisAreaManager::MergeCameras(CCamera & cam1, const CCamera & cam2)
{
assert(0); // under development
/* {
float fDotLR1 = cam1.GetFrustumPlane(FR_PLANE_LEFT )->n.Dot(cam1.GetFrustumPlane(FR_PLANE_RIGHT)->n);
float fDotRL2 = cam2.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_LEFT)->n);
int y=0;
}
*/
// left-right
float fDotLR = cam1.GetFrustumPlane(FR_PLANE_LEFT )->n.Dot(cam2.GetFrustumPlane(FR_PLANE_RIGHT)->n);
float fDotRL = cam1.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_LEFT)->n);
if(fabs(fDotLR)<fabs(fDotRL))
{
cam1.SetFrustumPlane(FR_PLANE_RIGHT, *cam2.GetFrustumPlane(FR_PLANE_RIGHT));
cam1.SetFrustumVertex(2,cam2.GetFrustumVertex(2));
cam1.SetFrustumVertex(3,cam2.GetFrustumVertex(3));
}
else
{
cam1.SetFrustumPlane(FR_PLANE_LEFT, *cam2.GetFrustumPlane(FR_PLANE_LEFT));
cam1.SetFrustumVertex(0,cam2.GetFrustumVertex(0));
cam1.SetFrustumVertex(1,cam2.GetFrustumVertex(1));
}
/*
{
float fDotLR1 = cam1.GetFrustumPlane(FR_PLANE_LEFT )->n.Dot(cam1.GetFrustumPlane(FR_PLANE_RIGHT)->n);
float fDotRL2 = cam2.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_LEFT)->n);
int y=0;
}*/
/*
// top-bottom
float fDotTB = cam1.GetFrustumPlane(FR_PLANE_TOP )->n.Dot(cam2.GetFrustumPlane(FR_PLANE_BOTTOM)->n);
float fDotBT = cam1.GetFrustumPlane(FR_PLANE_BOTTOM)->n.Dot(cam2.GetFrustumPlane(FR_PLANE_TOP )->n);
if(fDotTB>fDotBT)
cam1.SetFrustumPlane(FR_PLANE_BOTTOM, *cam2.GetFrustumPlane(FR_PLANE_BOTTOM));
else
cam1.SetFrustumPlane(FR_PLANE_TOP, *cam2.GetFrustumPlane(FR_PLANE_TOP));
*/
cam1.SetFrustumPlane(FR_PLANE_NEAR, *GetViewCamera().GetFrustumPlane(FR_PLANE_NEAR));
cam1.SetFrustumPlane(FR_PLANE_FAR, *GetViewCamera().GetFrustumPlane(FR_PLANE_FAR));
cam1.SetFrustumPlane(FR_PLANE_TOP, *GetViewCamera().GetFrustumPlane(FR_PLANE_TOP));
cam1.SetFrustumPlane(FR_PLANE_BOTTOM, *GetViewCamera().GetFrustumPlane(FR_PLANE_BOTTOM));
/*
if(GetCVars()->e_portals==4)
{
GetRenderer()->SetMaterialColor(1,1,1,1);
GetRenderer()->Draw3dBBox(pVerts[0],pVerts[1],DPRIM_LINE);
GetRenderer()->DrawLabel(pVerts[0],2,"0");
GetRenderer()->Draw3dBBox(pVerts[1],pVerts[2],DPRIM_LINE);
GetRenderer()->DrawLabel(pVerts[1],2,"1");
GetRenderer()->Draw3dBBox(pVerts[2],pVerts[3],DPRIM_LINE);
GetRenderer()->DrawLabel(pVerts[2],2,"2");
GetRenderer()->Draw3dBBox(pVerts[3],pVerts[0],DPRIM_LINE);
GetRenderer()->DrawLabel(pVerts[3],2,"3");
}*/
}
void CVisAreaManager::DrawOcclusionAreasIntoCBuffer(CCoverageBuffer * pCBuffer)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
m_lstActiveOcclVolumes.Clear();
m_lstIndoorActiveOcclVolumes.Clear();
if(GetCVars()->e_occlusion_volumes)
for(int i=0; i<m_lstOcclAreas.Count(); i++)
{
CVisArea * pArea = m_lstOcclAreas[i];
if(GetViewCamera().IsAABBVisibleFast( AABB(pArea->m_vBoxMin,pArea->m_vBoxMax)))
{
Vec3d vPos = (pArea->m_vBoxMin+pArea->m_vBoxMax)*0.5f;
float fRadius = (pArea->m_vBoxMin-pArea->m_vBoxMax).GetLength();
float fDist = GetViewCamera().GetPos().GetDistance(vPos);
float fZoomFactor = 0.2f+0.8f*(RAD2DEG(GetViewCamera().GetFov())/90.f);
if(fDist<fRadius*pArea->m_fViewDistRatio/fZoomFactor*0.125f && pArea->m_lstShapePoints.Count()>=2)
{
// pArea->DrawAreaBoundsIntoCBuffer(pCBuffer);
if(!pArea->m_pOcclCamera)
pArea->m_pOcclCamera = new CCamera;
*pArea->m_pOcclCamera = GetViewCamera();
int nShift = pArea->m_lstShapePoints.Count()>2 &&
(GetSquaredDistance(pArea->m_lstShapePoints[0], pArea->m_lstShapePoints[1])
<GetSquaredDistance(pArea->m_lstShapePoints[1], pArea->m_lstShapePoints[2]));
pArea->m_arrvActiveVerts[0] = pArea->m_lstShapePoints[0+nShift];
pArea->m_arrvActiveVerts[1] = pArea->m_lstShapePoints[0+nShift]+Vec3d(0,0,pArea->m_fHeight);
pArea->m_arrvActiveVerts[2] = pArea->m_lstShapePoints[1+nShift]+Vec3d(0,0,pArea->m_fHeight);
pArea->m_arrvActiveVerts[3] = pArea->m_lstShapePoints[1+nShift];
Plane plane;
plane.CalcPlane(pArea->m_arrvActiveVerts[0], pArea->m_arrvActiveVerts[1], pArea->m_arrvActiveVerts[2]);
if(plane.DistFromPlane(GetViewCamera().GetPos())<0)
{
pArea->m_arrvActiveVerts[3] = pArea->m_lstShapePoints[0+nShift];
pArea->m_arrvActiveVerts[2] = pArea->m_lstShapePoints[0+nShift]+Vec3d(0,0,pArea->m_fHeight);
pArea->m_arrvActiveVerts[1] = pArea->m_lstShapePoints[1+nShift]+Vec3d(0,0,pArea->m_fHeight);
pArea->m_arrvActiveVerts[0] = pArea->m_lstShapePoints[1+nShift];
}
else if(!pArea->m_bDoubleSide)
continue;
GetRenderer()->SetMaterialColor(1,0,0,1);
pArea->UpdatePortalCameraPlanes(*pArea->m_pOcclCamera, pArea->m_arrvActiveVerts, false);
// make far plane never clip anything
Plane newFarPlane;
newFarPlane.CalcPlane(Vec3d(0,1,-1024), Vec3d(0,0,-1024), Vec3d(1,0,-1024));
pArea->m_pOcclCamera->SetFrustumPlane(FR_PLANE_FAR, newFarPlane);
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; i--)
{
CVisArea * pArea = m_lstActiveOcclVolumes[i];
if(IsOccludedByOcclVolumes(pArea->m_vGeomBoxMin,pArea->m_vGeomBoxMax))
m_lstActiveOcclVolumes.Delete(i);
}
// put indoor occluders into separate list
for(int i=m_lstActiveOcclVolumes.Count()-1; i; 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);
GetRenderer()->Draw3dBBox(pArea->m_vGeomBoxMin,pArea->m_vGeomBoxMax);
}
}
}
}
bool CVisAreaManager::IsOccludedByOcclVolumes(Vec3d vBoxMin, Vec3d vBoxMax, bool bCheckOnlyIndoorVolumes)
{
list2<CVisArea*> & rList = bCheckOnlyIndoorVolumes ? m_lstIndoorActiveOcclVolumes : m_lstActiveOcclVolumes;
for(int i=0; i<rList.Count(); i++)
{
bool bAllIn=0;
if(rList[i]->m_pOcclCamera->IsAABBVisible_hierarchical(AABB(vBoxMin, vBoxMax), &bAllIn) && bAllIn)
return true;
}
return false;
}
void CVisAreaManager::SortStaticInstancesBySize()
{
// areas
for(int v=0; v<m_lstVisAreas.Count(); v++)
m_lstVisAreas[v]->SortStaticInstancesBySize();
// portals
for(int v=0; v<m_lstPortals.Count(); v++)
m_lstPortals[v]->SortStaticInstancesBySize();
}
bool CVisAreaManager::PreloadResources()
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
bool bPreloadOutdoor = false;
CVisArea * pVisArea = m_pCurArea ? m_pCurArea : m_pCurPortal;
if(pVisArea)
pVisArea->PreloadVisArea(GetCVars()->e_stream_preload_textures*2, &bPreloadOutdoor, 0, GetViewCamera().GetPos(), 0);
else
bPreloadOutdoor |= true;
// areas
// for(int v=0; v<m_lstVisAreas.Count(); v++)
// m_lstVisAreas[v]->PreloadResources();
// portals
// for(int v=0; v<m_lstPortals.Count(); v++)
// m_lstPortals[v]->PreloadResources();
/*
CVisArea * pVisArea = m_pCurArea ? m_pCurArea : m_pCurPortal;
if(pVisArea)
{
pVisArea->PreloadResources();
CVisArea * areaArray[8]={0,0,0,0,0,0,0,0};
int nCount = pVisArea->GetVisAreaConnections((IVisArea **)&areaArray,8);
for(int n=0; n<nCount; n++)
areaArray[n]->PreloadResources();
}*/
// GetLog()->Log("CVisAreaManager::PreloadResources: %d", (int)bPreloadOutdoor);
return bPreloadOutdoor;
}
void CVisAreaManager::CheckUnload()
{
m_nLoadedSectors=0;
// areas
for(int v=0; v<m_lstVisAreas.Count(); v++)
m_nLoadedSectors += m_lstVisAreas[v]->CheckUnload();
// portals
for(int v=0; v<m_lstPortals.Count(); v++)
m_nLoadedSectors += m_lstPortals[v]->CheckUnload();
}
void CVisAreaManager::GetStreamingStatus(int & nLoadedSectors, int & nTotalSectors)
{
nLoadedSectors = m_nLoadedSectors;
nTotalSectors = m_lstPortals.Count() + m_lstVisAreas.Count();
}
void CVisAreaManager::GetMemoryUsage(ICrySizer*pSizer)
{
// 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);
pSizer->AddObject(this,sizeof(*this));
}
bool CVisAreaManager::UnRegisterInAllSectors(IEntityRender * pEntityRS)
{
bool bRes = 0;
int nStatic = pEntityRS->IsStatic();
// areas
for(int v=0; v<m_lstVisAreas.Count(); v++)
bRes |= m_lstVisAreas[v]->m_lstEntities[nStatic].Delete(pEntityRS);
// portals
for(int v=0; v<m_lstPortals.Count(); v++)
bRes |= m_lstPortals[v]->m_lstEntities[nStatic].Delete(pEntityRS);
pEntityRS->m_pVisArea=0;
return bRes;
}
Vec3 CamAngles[6] =
{
Vec3( 90, -90, 0), //posx
Vec3( 90, 90, 0 ), //negx
Vec3(180, 180, 0 ), //posy
Vec3( 0, 180, 0 ), //negy
Vec3( 90, 180, 0 ), //posz
Vec3( 90, 0, 0 ) //negz
};
void CVisAreaManager::Preceche(CObjManager * pObjManager)
{
if(!GetCVars()->e_precache_level)
return;
//--------------------------------------------------------------------------------------
//---- PRE-FETCHING OF RENDER-DATA IN INDOORS ----
//--------------------------------------------------------------------------------------
GetRenderer()->EnableSwapBuffers(false);
//loop over all sectors and place a light in the middle of the sector
for(int v=0; v<m_lstVisAreas.Count(); v++)
{
unsigned short * pPtr2FrameID = (unsigned short *)GetRenderer()->EF_Query(EFQ_Pointer2FrameID);
if(pPtr2FrameID)
(*pPtr2FrameID)++;
m_nRenderFrameID = GetRenderer()->GetFrameID();
CDLight DynLight;
//place camera in the middle of a sector and render sector form
//different directions
for(int i=0; i<6; i++) {
GetRenderer()->BeginFrame();
// Add sun lsource
DynLight.m_Origin = (m_lstVisAreas[v]->m_vBoxMin + m_lstVisAreas[v]->m_vBoxMax)*0.5f;
DynLight.m_fRadius = 100;
DynLight.m_Flags |= DLF_LM;
Get3DEngine()->AddDynamicLightSource(DynLight,(IEntityRender*)-1);
CCamera cam = GetViewCamera();
cam.SetPos( DynLight.m_Origin );
cam.SetAngle( CamAngles[i] );
cam.SetFov(1.7f); //very wide-opend fov
Get3DEngine()->SetCamera(cam);
Get3DEngine()->Draw();
GetRenderer()->Update();
}
}
//--------------------------------------------------------------------------------------
//---- PRE-FETCHING OF RENDER-DATA IN OUTDOORS ----
//--------------------------------------------------------------------------------------
//we search all TagPoints with the label "Cam_PreFetch??" in the level
//and store the positions in an array
Vec3 CamOutdoorPositions[100]; //array for 100 cam-postionin outdoors ()
int ValidPosition=0;
char TagName[80];
IGame *pGame = GetISystem()->GetIGame();
if (pGame)
{
for (int cp=0; cp<99; cp++ )
{
sprintf(TagName, "Cam_PreFetch%02d", cp);
ITagPoint *pTagPoint = pGame->GetTagPointManager()->GetTagPoint( TagName );
if (pTagPoint)
{
pTagPoint->GetPos( CamOutdoorPositions[ValidPosition] );
ValidPosition++;
}
}
}
//loop over all cam-position in the level and render this part of the level
//from 6 different directions
for(int p=0; p<ValidPosition; p++) //loop over outdoor-camera position
{
for(int i=0; i<6; i++) //loop over 6 camera orientations
{
GetRenderer()->BeginFrame();
CCamera cam = GetViewCamera();
cam.SetPos( CamOutdoorPositions[p] );
cam.SetAngle( CamAngles[i] );
cam.SetFov(1.7f); //very wide-opend fov
Get3DEngine()->SetCamera(cam);
Get3DEngine()->Draw();
GetRenderer()->Update();
}
}
GetCVars()->e_sleep = 0;
((C3DEngine*)Get3DEngine())->GetDynamicLightSources()->Clear();
GetRenderer()->EF_ClearLightsList();
((C3DEngine*)Get3DEngine())->UpdateLightSources();
((C3DEngine*)Get3DEngine())->PrepareLightSourcesForRendering();
GetRenderer()->EnableSwapBuffers(true);
}
void CVisAreaManager::GetObjectsAround(Vec3d vExploPos, float fExploRadius, list2<IEntityRender*> * pEntList)
{
CVisArea * pVisArea = (CVisArea *)GetVisAreaFromPos(vExploPos);
// find static objects around
for(int i=0; pVisArea && i<pVisArea->m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
IEntityRender * pEntityRender = pVisArea->m_lstEntities[STATIC_ENTITIES][i];
Vec3d vEntBoxMin, vEntBoxMax;
pEntityRender->GetBBox(vEntBoxMin, vEntBoxMax);
if(Overlap::Sphere_AABB(Sphere(vExploPos,fExploRadius), AABB(vEntBoxMin,vEntBoxMax)))
if(pEntList->Find(pEntityRender)<0)
pEntList->Add(pEntityRender);
}
}