935 lines
30 KiB
C++
935 lines
30 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"
|
|
|
|
void CVisArea::Update(const Vec3d * pPoints, int nCount, const char * szName, float fHeight, const Vec3d & vAmbientColor, bool bAfectedByOutLights, bool bSkyOnly, const Vec3d & vDynAmbientColor, float fViewDistRatio, bool bDoubleSide, bool bUseDeepness, bool bUseInIndoors)
|
|
{
|
|
strncpy(m_sName, szName, sizeof(m_sName));
|
|
strlwr(m_sName);
|
|
|
|
m_fHeight = fHeight;
|
|
m_vAmbColor = vAmbientColor;
|
|
m_vDynAmbColor = vDynAmbientColor;
|
|
m_bAfectedByOutLights = bAfectedByOutLights;
|
|
m_bSkyOnly = bSkyOnly;
|
|
m_fViewDistRatio = fViewDistRatio;
|
|
m_bDoubleSide = bDoubleSide;
|
|
// m_bUseDeepness = bUseDeepness;
|
|
m_bUseInIndoors = bUseInIndoors;
|
|
|
|
m_lstShapePoints.PreAllocate(nCount,nCount);
|
|
|
|
if(nCount)
|
|
memcpy(&m_lstShapePoints[0], pPoints, sizeof(Vec3d)*nCount);
|
|
|
|
// update bbox
|
|
m_vBoxMax=SetMinBB();
|
|
m_vBoxMin=SetMaxBB();
|
|
|
|
for(int i=0; i<nCount; i++)
|
|
{
|
|
m_vBoxMax.CheckMax(pPoints[i]);
|
|
m_vBoxMin.CheckMin(pPoints[i]);
|
|
|
|
m_vBoxMax.CheckMax(pPoints[i]+Vec3d(0,0,m_fHeight));
|
|
m_vBoxMin.CheckMin(pPoints[i]+Vec3d(0,0,m_fHeight));
|
|
}
|
|
|
|
UpdateGeometryBBox();
|
|
}
|
|
|
|
#define PORTAL_GEOM_BBOX_EXTENT 3.f
|
|
|
|
void CVisArea::UpdateGeometryBBox()
|
|
{
|
|
m_vGeomBoxMax = m_vBoxMax;
|
|
m_vGeomBoxMin = m_vBoxMin;
|
|
|
|
if(IsPortal())
|
|
{ // fix for big objects passing portal
|
|
m_vGeomBoxMax+=Vec3d(PORTAL_GEOM_BBOX_EXTENT,PORTAL_GEOM_BBOX_EXTENT,PORTAL_GEOM_BBOX_EXTENT);
|
|
m_vGeomBoxMin-=Vec3d(PORTAL_GEOM_BBOX_EXTENT,PORTAL_GEOM_BBOX_EXTENT,PORTAL_GEOM_BBOX_EXTENT);
|
|
}
|
|
|
|
for(int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
|
|
if(m_lstEntities[STATIC_ENTITIES][i]->IsStatic())
|
|
{
|
|
Vec3d vEntBoxMin,vEntBoxMax;
|
|
m_lstEntities[STATIC_ENTITIES][i]->GetRenderBBox(vEntBoxMin,vEntBoxMax);
|
|
m_vGeomBoxMin.CheckMin(vEntBoxMin);
|
|
m_vGeomBoxMax.CheckMax(vEntBoxMax);
|
|
}
|
|
}
|
|
|
|
void CVisArea::MarkForStreaming()
|
|
{
|
|
for(int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
|
|
{
|
|
if(m_lstEntities[STATIC_ENTITIES][i]->GetEntityStatObj(0))
|
|
{
|
|
((CStatObj*)m_lstEntities[STATIC_ENTITIES][i]->GetEntityStatObj(0))->m_nMarkedForStreamingFrameId = GetFrameID()+100;
|
|
// m_lstEntities[STATIC_ENTITIES][i]->CheckPhysicalized();
|
|
}
|
|
}
|
|
}
|
|
|
|
CVisArea::CVisArea(bool bLoadedAsAreaBox)
|
|
{
|
|
m_vGeomBoxMin=m_vGeomBoxMax=m_vBoxMin=m_vBoxMax=Vec3d(0,0,0);
|
|
m_sName[0]=0;
|
|
m_nRndFrameId=-1;
|
|
m_bActive=true;
|
|
m_nFogVolumeId=0;
|
|
m_fHeight=0;
|
|
m_vAmbColor(0,0,0);
|
|
m_vDynAmbColor(0,0,0);
|
|
m_bLoadedAsAreaBox = bLoadedAsAreaBox;
|
|
m_vConnNormals[0]=m_vConnNormals[1]=Vec3d(0,0,0);
|
|
m_bAfectedByOutLights = false;
|
|
m_fDistance=0;
|
|
m_bSkyOnly=false;
|
|
m_pOcclCamera=0;
|
|
m_fViewDistRatio = 100.f;
|
|
m_bDoubleSide = true;
|
|
// m_bUseDeepness = false;
|
|
m_bUseInIndoors = false;
|
|
memset(m_arrvActiveVerts,0,sizeof(m_arrvActiveVerts));
|
|
}
|
|
|
|
CVisArea::~CVisArea()
|
|
{
|
|
Unload();
|
|
UnregisterDynamicEntities();
|
|
delete m_pOcclCamera;
|
|
m_pOcclCamera=0;
|
|
|
|
/*
|
|
for(int nStatic=0; nStatic<2; nStatic++)
|
|
for(int i=0; i<m_lstEntities[nStatic].Count(); i++)
|
|
if(m_lstEntities[nStatic][i]->m_pVisArea==this)
|
|
m_lstEntities[nStatic][i]->m_pVisArea=0;
|
|
*/
|
|
}
|
|
|
|
bool InsidePolygon(Vec3 *polygon,int N,Vec3 p)
|
|
{
|
|
int counter = 0;
|
|
int i;
|
|
double xinters;
|
|
Vec3 p1,p2;
|
|
|
|
p1 = polygon[0];
|
|
for (i=1;i<=N;i++) {
|
|
p2 = polygon[i % N];
|
|
if (p.y > min(p1.y,p2.y)) {
|
|
if (p.y <= max(p1.y,p2.y)) {
|
|
if (p.x <= max(p1.x,p2.x)) {
|
|
if (p1.y != p2.y) {
|
|
xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;
|
|
if (p1.x == p2.x || p.x <= xinters)
|
|
counter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
p1 = p2;
|
|
}
|
|
|
|
if (counter % 2 == 0)
|
|
return(false);
|
|
else
|
|
return(true);
|
|
}
|
|
|
|
bool CVisArea::IsPointInsideVisArea(const Vec3d & vPos)
|
|
{
|
|
if(Overlap::Point_AABB(vPos, m_vBoxMin, m_vBoxMax))
|
|
if(InsidePolygon(&m_lstShapePoints[0], m_lstShapePoints.Count(), vPos))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CVisArea::FindVisArea(IVisArea * pAnotherArea, int nMaxReqursion, bool bSkipDisabledPortals)
|
|
{ // todo: avoid going into parent
|
|
if(pAnotherArea == this)
|
|
return true;
|
|
|
|
if(nMaxReqursion>0)
|
|
for(int p=0; p<m_lstConnections.Count(); p++)
|
|
if(!bSkipDisabledPortals || m_lstConnections[p]->IsActive())
|
|
if(m_lstConnections[p]->FindVisArea(pAnotherArea, nMaxReqursion-1, bSkipDisabledPortals))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CVisArea::PreloadVisArea(int nMaxReqursion, bool * pbOutdoorFound, CVisArea * pParentToAvoid, Vec3d vPrevPortalPos, float fPrevPortalDistance)
|
|
{
|
|
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
|
|
if(IsPortal())
|
|
{
|
|
fPrevPortalDistance += vPrevPortalPos.GetDistance((m_vBoxMin+m_vBoxMax)*0.5f);
|
|
vPrevPortalPos = (m_vBoxMin+m_vBoxMax)*0.5f;
|
|
}
|
|
|
|
PreloadResources(vPrevPortalPos, fPrevPortalDistance);
|
|
|
|
if(IsConnectedToOutdoor())
|
|
*pbOutdoorFound = true;
|
|
|
|
if(nMaxReqursion>0)
|
|
for(int p=0; p<m_lstConnections.Count(); p++)
|
|
if(m_lstConnections[p] != pParentToAvoid)
|
|
if(GetCurTimeSec()>(m_fPreloadStartTime+0.010f)||
|
|
m_lstConnections[p]->PreloadVisArea(nMaxReqursion-1, pbOutdoorFound, this, vPrevPortalPos, fPrevPortalDistance))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
int CVisArea::GetVisFrameId()
|
|
{
|
|
return m_nRndFrameId;
|
|
}
|
|
|
|
bool CVisArea::IsConnectedToOutdoor()
|
|
{
|
|
if(IsPortal()) // check if this portal has just one conection
|
|
return m_lstConnections.Count()==1;
|
|
|
|
// find portals with just one conection
|
|
for(int p=0; p<m_lstConnections.Count(); p++)
|
|
{
|
|
CVisArea * pPortal = m_lstConnections[p];
|
|
if(pPortal->m_lstConnections.Count()==1)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Is2dLinesIntersect(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)
|
|
{
|
|
float ua = ((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1));
|
|
float ub = ((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1));
|
|
return ua>0 && ua<1 && ub>0 && ub<1;
|
|
}
|
|
|
|
Vec3d CVisArea::GetConnectionNormal(CVisArea * pPortal)
|
|
{
|
|
// if(strstr(pPortal->m_sName,"ab09_portal11"))
|
|
// int t=0;
|
|
|
|
assert(m_lstShapePoints.Count()>=3);
|
|
// find side of shape intersecting with portal
|
|
int nIntersNum = 0;
|
|
Vec3d arrNormals[2]={Vec3d(0,0,0),Vec3d(0,0,0)};
|
|
for(int v=0; v<m_lstShapePoints.Count(); v++)
|
|
{
|
|
nIntersNum=0;
|
|
arrNormals[0]=Vec3d(0,0,0);
|
|
arrNormals[1]=Vec3d(0,0,0);
|
|
for(int p=0; p<pPortal->m_lstShapePoints.Count(); p++)
|
|
{
|
|
const Vec3d & v0 = m_lstShapePoints[v];
|
|
const Vec3d & v1 = m_lstShapePoints[(v+1)%m_lstShapePoints.Count()];
|
|
const Vec3d & p0 = pPortal->m_lstShapePoints[p];
|
|
const Vec3d & p1 = pPortal->m_lstShapePoints[(p+1)%pPortal->m_lstShapePoints.Count()];
|
|
|
|
if(Is2dLinesIntersect(v0.x,v0.y,v1.x,v1.y,p0.x,p0.y,p1.x,p1.y))
|
|
{
|
|
Vec3d vNormal = GetNormalized(v0-v1).Cross(Vec3d(0,0,1.f));
|
|
if(nIntersNum<2)
|
|
arrNormals[nIntersNum++] = (IsShapeClockwise()) ? -vNormal : vNormal;
|
|
}
|
|
}
|
|
|
|
if(nIntersNum==2)
|
|
break;
|
|
}
|
|
|
|
if(nIntersNum == 2 &&
|
|
//IsEquivalent(arrNormals[0] == arrNormals[1])
|
|
IsEquivalent(arrNormals[0],arrNormals[1],VEC_EPSILON)
|
|
)
|
|
return arrNormals[0];
|
|
|
|
{
|
|
int nBottomPoints=0;
|
|
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
|
|
if(IsPointInsideVisArea(pPortal->m_lstShapePoints[p]))
|
|
nBottomPoints++;
|
|
|
|
int nUpPoints=0;
|
|
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
|
|
if(IsPointInsideVisArea(pPortal->m_lstShapePoints[p]+Vec3d(0,0,pPortal->m_fHeight)))
|
|
nUpPoints++;
|
|
|
|
if(nBottomPoints==0 && nUpPoints==4)
|
|
return Vec3d(0,0,1);
|
|
|
|
if(nBottomPoints==4 && nUpPoints==0)
|
|
return Vec3d(0,0,-1);
|
|
}
|
|
|
|
return Vec3d(0,0,0);
|
|
}
|
|
|
|
bool CVisArea::UpdatePortalCameraScissor(CCamera & cam, list2<Vec3d> * lstVerts, bool bMergeFrustums)
|
|
{
|
|
IRenderer * pRend = GetRenderer();
|
|
CVars * pCVars = GetCVars();
|
|
|
|
Vec3d arrScreenSpacePos[8];
|
|
memset(arrScreenSpacePos,0,sizeof(arrScreenSpacePos));
|
|
for(int i=0; i<lstVerts->Count() && i<8; i++)
|
|
{ // result is in range from 0 to 100
|
|
const Vec3d & v3d = lstVerts->GetAt(i);
|
|
|
|
if(pCVars->e_portals == 4)
|
|
pRend->Draw3dBBox(v3d-Vec3d(0.1f,0.1f,0.1f),v3d+Vec3d(0.1f,0.1f,0.1f));
|
|
|
|
pRend->ProjectToScreen(v3d.x, v3d.y, v3d.z,
|
|
&arrScreenSpacePos[i].x, &arrScreenSpacePos[i].y, &arrScreenSpacePos[i].z);
|
|
|
|
arrScreenSpacePos[i].x = arrScreenSpacePos[i].x*pRend->GetWidth()/100.f;
|
|
arrScreenSpacePos[i].y = arrScreenSpacePos[i].y*pRend->GetHeight()/100.f;
|
|
}
|
|
|
|
// find 2d bounds in screen space
|
|
Vec3d vMin2d = arrScreenSpacePos[0], vMax2d = arrScreenSpacePos[0];
|
|
for(int i=0; i<lstVerts->Count() && i<8; i++)
|
|
{
|
|
if(arrScreenSpacePos[i].x < vMin2d.x)
|
|
vMin2d.x = arrScreenSpacePos[i].x;
|
|
if(arrScreenSpacePos[i].x > vMax2d.x)
|
|
vMax2d.x = arrScreenSpacePos[i].x;
|
|
if(arrScreenSpacePos[i].y < vMin2d.y)
|
|
vMin2d.y = arrScreenSpacePos[i].y;
|
|
if(arrScreenSpacePos[i].y > vMax2d.y)
|
|
vMax2d.y = arrScreenSpacePos[i].y;
|
|
}
|
|
|
|
vMin2d.x = max(vMin2d.x,0);
|
|
vMin2d.y = max(vMin2d.y,0);
|
|
vMax2d.x = min(vMax2d.x,GetRenderer()->GetWidth());
|
|
vMax2d.y = min(vMax2d.y,GetRenderer()->GetHeight());
|
|
|
|
if(vMax2d.x <= vMin2d.x || vMax2d.y < vMin2d.y)
|
|
return false;
|
|
|
|
assert(vMin2d.x>=0 && vMin2d.x<=GetRenderer()->GetWidth());
|
|
assert(vMin2d.y>=0 && vMin2d.y<=GetRenderer()->GetHeight());
|
|
assert(vMax2d.x>=0 && vMax2d.x<=GetRenderer()->GetWidth());
|
|
assert(vMax2d.y>=0 && vMax2d.y<=GetRenderer()->GetHeight());
|
|
|
|
cam.m_ScissorInfo.x1 = ushort(vMin2d.x);
|
|
cam.m_ScissorInfo.y1 = ushort(vMin2d.y);
|
|
cam.m_ScissorInfo.x2 = ushort(vMax2d.x);
|
|
cam.m_ScissorInfo.y2 = ushort(vMax2d.y);
|
|
|
|
if(GetCVars()->e_scissor_debug)
|
|
{
|
|
float color[] = {1,0,0,1};
|
|
pRend->Draw2dLabel(vMax2d.x, vMax2d.y, 2 , color, false, "br");
|
|
pRend->Draw2dLabel(vMin2d.x, vMax2d.y, 2 , color, false, "bl");
|
|
pRend->Draw2dLabel(vMax2d.x, vMin2d.y, 2 , color, false, "tr");
|
|
pRend->Draw2dLabel(vMin2d.x, vMin2d.y, 2 , color, false, "tl");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CVisArea::UpdatePortalCameraPlanes(CCamera & cam, Vec3d * pVerts, bool bMergeFrustums)
|
|
{ // todo: do also take into account GetViewCamera()
|
|
Vec3d vCamPos = GetViewCamera().GetPos();
|
|
Plane plane;
|
|
|
|
plane.CalcPlane(pVerts[0],pVerts[1],pVerts[2]);
|
|
cam.SetFrustumPlane(FR_PLANE_NEAR, plane);
|
|
|
|
plane = *GetViewCamera().GetFrustumPlane(FR_PLANE_FAR);
|
|
cam.SetFrustumPlane(FR_PLANE_FAR, plane);
|
|
|
|
plane.CalcPlane(vCamPos,pVerts[2],pVerts[3]); // update plane only if it reduces fov
|
|
if(!bMergeFrustums || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_LEFT)->n)<
|
|
cam.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam.GetFrustumPlane(FR_PLANE_LEFT)->n))
|
|
cam.SetFrustumPlane(FR_PLANE_RIGHT, plane);
|
|
|
|
plane.CalcPlane(vCamPos,pVerts[0],pVerts[1]); // update plane only if it reduces fov
|
|
if(!bMergeFrustums || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_RIGHT)->n)<
|
|
cam.GetFrustumPlane(FR_PLANE_LEFT)->n.Dot(cam.GetFrustumPlane(FR_PLANE_RIGHT)->n))
|
|
cam.SetFrustumPlane(FR_PLANE_LEFT, plane);
|
|
|
|
plane.CalcPlane(vCamPos,pVerts[3],pVerts[0]); // update plane only if it reduces fov
|
|
if(!bMergeFrustums || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_TOP)->n)<
|
|
cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n.Dot(cam.GetFrustumPlane(FR_PLANE_TOP)->n))
|
|
cam.SetFrustumPlane(FR_PLANE_BOTTOM, plane);
|
|
|
|
plane.CalcPlane(vCamPos,pVerts[1],pVerts[2]); // update plane only if it reduces fov
|
|
if(!bMergeFrustums || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n)<
|
|
cam.GetFrustumPlane(FR_PLANE_TOP)->n.Dot(cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n))
|
|
cam.SetFrustumPlane(FR_PLANE_TOP, plane);
|
|
|
|
Vec3d arrvPortVertsCamSpace[4];
|
|
for(int i=0; i<4; i++)
|
|
arrvPortVertsCamSpace[i] = pVerts[i]-cam.GetPos();
|
|
cam.SetFrustumVertices(arrvPortVertsCamSpace);
|
|
|
|
if(GetCVars()->e_portals==4)
|
|
{
|
|
float farrColor[4] = {1,1,1,1};
|
|
// GetRenderer()->SetMaterialColor(1,1,1,1);
|
|
GetRenderer()->Draw3dBBox(pVerts[0],pVerts[1],DPRIM_LINE);
|
|
GetRenderer()->DrawLabelEx(pVerts[0],1,farrColor,false,true,"0");
|
|
GetRenderer()->Draw3dBBox(pVerts[1],pVerts[2],DPRIM_LINE);
|
|
GetRenderer()->DrawLabelEx(pVerts[1],1,farrColor,false,true,"1");
|
|
GetRenderer()->Draw3dBBox(pVerts[2],pVerts[3],DPRIM_LINE);
|
|
GetRenderer()->DrawLabelEx(pVerts[2],1,farrColor,false,true,"2");
|
|
GetRenderer()->Draw3dBBox(pVerts[3],pVerts[0],DPRIM_LINE);
|
|
GetRenderer()->DrawLabelEx(pVerts[3],1,farrColor,false,true,"3");
|
|
}
|
|
}
|
|
|
|
int __cdecl CVisAreaManager__CmpDistToPortal(const void* v1, const void* v2);
|
|
|
|
void CVisArea::DrawVolume(CObjManager * pObjManager, int nReqursionLevel,
|
|
CCamera CurCamera, CVisArea * pParent, CVisArea * pCurPortal,
|
|
bool * pbOutdoorVisible, list2<CCamera> * plstOutPortCameras, bool * pbSkyVisible)
|
|
{
|
|
IRenderer * pRenderer = GetRenderer();
|
|
|
|
// mark as rendered
|
|
if(!pObjManager->m_nRenderStackLevel)
|
|
m_nRndFrameId = GetFrameID();
|
|
|
|
// get area light mask
|
|
Vec3d vCenter = (m_vBoxMin+m_vBoxMax)*0.5f;
|
|
float fRadius = (m_vBoxMax-m_vBoxMin).Length()*0.5f;
|
|
int nDLMask = Get3DEngine()->GetLightMaskFromPosition(vCenter, fRadius);
|
|
|
|
// todo: prepare flag once
|
|
bool bThisIsPortal = strstr(m_sName,"portal") != 0;
|
|
|
|
// remove sun bit if it not allowed on exit portal geometry
|
|
if(!bThisIsPortal || !m_bAfectedByOutLights || m_lstConnections.Count()!=1)
|
|
for(int nId=0; nId<32; nId++)
|
|
{
|
|
if(nDLMask & (1<<nId))
|
|
{
|
|
CDLight * pDLight = (CDLight*)pRenderer->EF_Query(EFQ_LightSource, nId);
|
|
if(pDLight && pDLight->m_Flags & DLF_SUN)
|
|
{
|
|
nDLMask = nDLMask & ~(1<<nId);
|
|
break;
|
|
}
|
|
|
|
if(!pObjManager->m_nRenderStackLevel) // light scissor can not be shared between reqursion levels because same CDlight objects are used
|
|
if(pDLight && pDLight->m_Flags & DLF_THIS_AREA_ONLY && pDLight->m_pOwner)
|
|
if(pDLight->m_pOwner->GetEntityVisArea() == this)
|
|
{
|
|
if(!pDLight->m_sWidth || pDLight->m_sWidth == (CurCamera.m_ScissorInfo.x2-CurCamera.m_ScissorInfo.x1))
|
|
{ // first time - set
|
|
pDLight->m_sX = CurCamera.m_ScissorInfo.x1;
|
|
pDLight->m_sY = CurCamera.m_ScissorInfo.y1;
|
|
pDLight->m_sWidth = CurCamera.m_ScissorInfo.x2-CurCamera.m_ScissorInfo.x1;
|
|
pDLight->m_sHeight = CurCamera.m_ScissorInfo.y2-CurCamera.m_ScissorInfo.y1;
|
|
}
|
|
else
|
|
{ // not first time - merge
|
|
int nMaxX = max(pDLight->m_sX + pDLight->m_sWidth, CurCamera.m_ScissorInfo.x2);
|
|
int nMaxY = max(pDLight->m_sY + pDLight->m_sHeight, CurCamera.m_ScissorInfo.y2);
|
|
pDLight->m_sX = min(pDLight->m_sX, CurCamera.m_ScissorInfo.x1);
|
|
pDLight->m_sY = min(pDLight->m_sY, CurCamera.m_ScissorInfo.y1);
|
|
pDLight->m_sWidth = nMaxX - pDLight->m_sX;
|
|
pDLight->m_sHeight = nMaxY - pDLight->m_sY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// render area statics
|
|
DrawEntities( m_nFogVolumeId, nDLMask, 0, CurCamera,
|
|
m_lstShapePoints.Count() ? &m_vAmbColor : 0, m_lstShapePoints.Count() ? &m_vDynAmbColor : 0,
|
|
NULL, true, 0, pObjManager,
|
|
IsPointInsideVisArea(GetViewCamera().GetPos()), "", STATIC_ENTITIES);
|
|
|
|
// render area entities
|
|
DrawEntities( m_nFogVolumeId, nDLMask, 0, CurCamera,
|
|
m_lstShapePoints.Count() ? &m_vAmbColor : 0, m_lstShapePoints.Count() ? &m_vDynAmbColor : 0,
|
|
NULL, true, 0, pObjManager,
|
|
IsPointInsideVisArea(GetViewCamera().GetPos()), "", DYNAMIC_ENTITIES);
|
|
|
|
// limit recursion and portal activity
|
|
if(!nReqursionLevel || !m_bActive)
|
|
return;
|
|
|
|
if( bThisIsPortal && m_lstConnections.Count()==1 && // detect entrance
|
|
!IsPointInsideVisArea(GetViewCamera().GetPos()) && // detect camera in outdoors
|
|
!CurCamera.IsAABBVisibleFast( AABB(m_vGeomBoxMin,m_vGeomBoxMax) )) // if invisible
|
|
return; // stop recursion
|
|
|
|
bool bScisorValid = true;
|
|
|
|
// prepare new camera for next areas
|
|
if(bThisIsPortal && m_lstConnections.Count() && (this!=pCurPortal || !pCurPortal->IsPointInsideVisArea(CurCamera.GetPos())))
|
|
{
|
|
Vec3d vPortNorm = (!pParent || pParent == m_lstConnections[0] || m_lstConnections.Count()==1) ?
|
|
m_vConnNormals[0] : m_vConnNormals[1];
|
|
|
|
// exit/entrance portal has only one normal in direction to outdoors, so flip it to the camera
|
|
if(m_lstConnections.Count()==1 && !pParent)
|
|
vPortNorm = -vPortNorm;
|
|
|
|
// back face check
|
|
Vec3d vPortToCamDir = CurCamera.GetPos() - (m_vBoxMin+m_vBoxMax)*0.5f;
|
|
if(vPortToCamDir.Dot(vPortNorm)<0)
|
|
return;
|
|
|
|
if(!m_bDoubleSide)
|
|
if(vPortToCamDir.Dot(m_vConnNormals[0])<0)
|
|
return;
|
|
|
|
Vec3d arrPortVerts[4];
|
|
Vec3d arrPortVertsOtherSide[4];
|
|
bool barrPortVertsOtherSideValid = false;
|
|
if(pParent && !IsEquivalent(vPortNorm,Vec3d(0,0,0),VEC_EPSILON) && vPortNorm.z)
|
|
{ // up/down portal
|
|
int nEven = IsShapeClockwise();
|
|
if(vPortNorm.z>0)
|
|
nEven=!nEven;
|
|
for(int i=0; i<4; i++)
|
|
{
|
|
arrPortVerts[i] = m_lstShapePoints[nEven ? (3-i) : i]+Vec3d(0,0,m_fHeight)*(vPortNorm.z>0);
|
|
arrPortVertsOtherSide[i] = m_lstShapePoints[nEven ? (3-i) : i]+Vec3d(0,0,m_fHeight)*(vPortNorm.z<0);
|
|
}
|
|
barrPortVertsOtherSideValid = true;
|
|
}
|
|
else if(!IsEquivalent(vPortNorm,Vec3d(0,0,0),VEC_EPSILON) && vPortNorm.z==0)
|
|
{ // basic portal
|
|
Vec3d arrInAreaPoint[2]={Vec3d(0,0,0),Vec3d(0,0,0)};
|
|
int arrInAreaPointId[2]={-1,-1};
|
|
int nInAreaPointCounter=0;
|
|
// find 2 points of portal in this area (or in this outdoors)
|
|
for(int i=0; i<m_lstShapePoints.Count() && nInAreaPointCounter<2; i++)
|
|
{
|
|
Vec3d vTestPoint = m_lstShapePoints[i]+Vec3d(0,0,m_fHeight*0.5f);
|
|
CVisArea * pAnotherArea = m_lstConnections[0];
|
|
if((pParent && (pParent->IsPointInsideVisArea(vTestPoint))) ||
|
|
(!pParent && (!pAnotherArea->IsPointInsideVisArea(vTestPoint))) )
|
|
{
|
|
arrInAreaPointId[nInAreaPointCounter] = i;
|
|
arrInAreaPoint[nInAreaPointCounter++] = m_lstShapePoints[i];
|
|
}
|
|
}
|
|
|
|
if(nInAreaPointCounter==2)
|
|
{ // success, take into account volume and portal shape versts order
|
|
int nEven = IsShapeClockwise();
|
|
if(arrInAreaPointId[1]-arrInAreaPointId[0] != 1)
|
|
nEven = !nEven;
|
|
|
|
arrPortVerts[0] = arrInAreaPoint[nEven];
|
|
arrPortVerts[1] = arrInAreaPoint[nEven]+Vec3d(0,0,m_fHeight);
|
|
arrPortVerts[2] = arrInAreaPoint[!nEven]+Vec3d(0,0,m_fHeight);
|
|
arrPortVerts[3] = arrInAreaPoint[!nEven];
|
|
|
|
nEven = !nEven;
|
|
|
|
arrPortVertsOtherSide[0] = arrInAreaPoint[nEven];
|
|
arrPortVertsOtherSide[1] = arrInAreaPoint[nEven]+Vec3d(0,0,m_fHeight);
|
|
arrPortVertsOtherSide[2] = arrInAreaPoint[!nEven]+Vec3d(0,0,m_fHeight);
|
|
arrPortVertsOtherSide[3] = arrInAreaPoint[!nEven];
|
|
barrPortVertsOtherSideValid = true;
|
|
}
|
|
else
|
|
{ // something wrong
|
|
Warning(0,0,"CVisArea::DrawVolume: Invalid portal: %s", m_sName);
|
|
return;
|
|
}
|
|
}
|
|
else if(!pParent && vPortNorm.z==0 && m_lstConnections.Count()==1)
|
|
{ // basic entrance portal
|
|
Vec3d vBorder = GetNormalized(vPortNorm.Cross(Vec3d(0,0,1.f)))*fRadius;
|
|
arrPortVerts[0] = vCenter - Vec3d(0,0,1.f)*fRadius - vBorder;
|
|
arrPortVerts[1] = vCenter + Vec3d(0,0,1.f)*fRadius - vBorder;
|
|
arrPortVerts[2] = vCenter + Vec3d(0,0,1.f)*fRadius + vBorder;
|
|
arrPortVerts[3] = vCenter - Vec3d(0,0,1.f)*fRadius + vBorder;
|
|
}
|
|
else if(!pParent && vPortNorm.z!=0 && m_lstConnections.Count()==1)
|
|
{ // up/down entrance portal
|
|
Vec3d vBorder = GetNormalized(vPortNorm.Cross(Vec3d(0,1,0.f)))*fRadius;
|
|
arrPortVerts[0] = vCenter - Vec3d(0,1,0.f)*fRadius + vBorder;
|
|
arrPortVerts[1] = vCenter + Vec3d(0,1,0.f)*fRadius + vBorder;
|
|
arrPortVerts[2] = vCenter + Vec3d(0,1,0.f)*fRadius - vBorder;
|
|
arrPortVerts[3] = vCenter - Vec3d(0,1,0.f)*fRadius - vBorder;
|
|
}
|
|
else
|
|
{ // something wrong or areabox portal - use simple solution
|
|
if(
|
|
//vPortNorm == Vec3d(0,0,0)
|
|
IsEquivalent(vPortNorm,Vec3d(0,0,0),VEC_EPSILON)
|
|
)
|
|
vPortNorm = GetNormalized((vCenter - GetViewCamera().GetPos()));
|
|
|
|
Vec3d vBorder = GetNormalized(vPortNorm.Cross(Vec3d(0,0,1.f)))*fRadius;
|
|
arrPortVerts[0] = vCenter - Vec3d(0,0,1.f)*fRadius - vBorder;
|
|
arrPortVerts[1] = vCenter + Vec3d(0,0,1.f)*fRadius - vBorder;
|
|
arrPortVerts[2] = vCenter + Vec3d(0,0,1.f)*fRadius + vBorder;
|
|
arrPortVerts[3] = vCenter - Vec3d(0,0,1.f)*fRadius + vBorder;
|
|
}
|
|
|
|
if(GetCVars()->e_portals==4) // make color reqursion dependent
|
|
GetRenderer()->SetMaterialColor(1,1,pObjManager->m_nRenderStackLevel==0,1);
|
|
|
|
CCamera camParent = CurCamera;
|
|
UpdatePortalCameraPlanes(CurCamera, arrPortVerts, vPortNorm.z==0);
|
|
|
|
static list2<Vec3d> lstPortVertsClipped; // Timur, keep this list static so it is not reallocated every time.
|
|
lstPortVertsClipped.Clear();
|
|
lstPortVertsClipped.AddList(arrPortVerts, 4);
|
|
ClipPortalVerticesByCameraFrustum(&lstPortVertsClipped, camParent);
|
|
|
|
bScisorValid = UpdatePortalCameraScissor(CurCamera, &lstPortVertsClipped, vPortNorm.z==0);
|
|
|
|
if(bScisorValid && barrPortVertsOtherSideValid)
|
|
{
|
|
Vec3d vOtherSizeBoxMax = SetMinBB();
|
|
Vec3d vOtherSizeBoxMin = SetMaxBB();
|
|
for(int i=0; i<4; i++)
|
|
{
|
|
vOtherSizeBoxMin.CheckMin(arrPortVertsOtherSide[i]-Vec3d(0.01f,0.01f,0.01f));
|
|
vOtherSizeBoxMax.CheckMax(arrPortVertsOtherSide[i]+Vec3d(0.01f,0.01f,0.01f));
|
|
}
|
|
|
|
bScisorValid = CurCamera.IsAABBVisible_exact(AABB(vOtherSizeBoxMin,vOtherSizeBoxMax));
|
|
}
|
|
|
|
if(bScisorValid && pParent && m_lstConnections.Count()==1)
|
|
{ // set this camera for outdoor
|
|
if(nReqursionLevel>=1)
|
|
{
|
|
if(!m_bSkyOnly)
|
|
{
|
|
if(plstOutPortCameras)
|
|
{
|
|
plstOutPortCameras->Add(CurCamera);
|
|
plstOutPortCameras->Last().m_pPortal = this;
|
|
}
|
|
if(pbOutdoorVisible)
|
|
*pbOutdoorVisible = true;
|
|
}
|
|
else if(pbSkyVisible)
|
|
*pbSkyVisible = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// sort portals by distance
|
|
if(!bThisIsPortal && m_lstConnections.Count())
|
|
{
|
|
for(int p=0; p<m_lstConnections.Count(); p++)
|
|
{
|
|
CVisArea * pNeibVolume = m_lstConnections[p];
|
|
pNeibVolume->m_fDistance = CurCamera.GetPos().GetDistance((pNeibVolume->m_vBoxMin+pNeibVolume->m_vBoxMax)*0.5f);
|
|
}
|
|
|
|
qsort(&m_lstConnections[0], m_lstConnections.Count(),
|
|
sizeof(m_lstConnections[0]), CVisAreaManager__CmpDistToPortal);
|
|
}
|
|
|
|
float fZoomFactor = 0.2f+0.8f*(RAD2DEG(CurCamera.GetFov())/90.f);
|
|
|
|
// recurse to connetions
|
|
for(int p=0; p<m_lstConnections.Count(); p++)
|
|
{
|
|
CVisArea * pNeibVolume = m_lstConnections[p];
|
|
if(pNeibVolume != pParent)
|
|
{
|
|
if(!bThisIsPortal)
|
|
{ // skip far portals
|
|
float fRadius = (pNeibVolume->m_vBoxMax-pNeibVolume->m_vBoxMin).Length()*0.5f;
|
|
if(pNeibVolume->m_fDistance*fZoomFactor > fRadius*pNeibVolume->m_fViewDistRatio)
|
|
continue;
|
|
}
|
|
|
|
if((bScisorValid || m_lstConnections.Count()==1) && (bThisIsPortal || CurCamera.IsAABBVisibleFast( AABB(pNeibVolume->m_vGeomBoxMin,pNeibVolume->m_vGeomBoxMax) )))
|
|
pNeibVolume->DrawVolume(pObjManager, nReqursionLevel-1, CurCamera, this, pCurPortal, pbOutdoorVisible, plstOutPortCameras, pbSkyVisible);
|
|
else
|
|
pNeibVolume->DrawVolume_NotThisAreaOnlyLights(pObjManager, nReqursionLevel-1, CurCamera, this, pCurPortal, pbOutdoorVisible, plstOutPortCameras, pbSkyVisible);
|
|
}
|
|
}
|
|
}
|
|
|
|
//! return list of visareas connected to specified visarea (can return portals and sectors)
|
|
int CVisArea::GetRealConnections(IVisArea ** pAreas, int nMaxConnNum, bool bSkipDisabledPortals)
|
|
{
|
|
int nOut = 0;
|
|
for(int nArea=0; nArea<m_lstConnections.Count(); nArea++)
|
|
{
|
|
if(nOut<nMaxConnNum)
|
|
pAreas[nOut] = (IVisArea*)m_lstConnections[nArea];
|
|
nOut++;
|
|
}
|
|
return nOut;
|
|
}
|
|
|
|
//! return list of sectors conected to specified sector or portal (returns sectors only)
|
|
// todo: change the way it returns data
|
|
int CVisArea::GetVisAreaConnections(IVisArea ** pAreas, int nMaxConnNum, bool bSkipDisabledPortals)
|
|
{
|
|
int nOut = 0;
|
|
if(IsPortal())
|
|
{
|
|
/* for(int nArea=0; nArea<m_lstConnections.Count(); nArea++)
|
|
{
|
|
if(nOut<nMaxConnNum)
|
|
pAreas[nOut] = (IVisArea*)m_lstConnections[nArea];
|
|
nOut++;
|
|
}*/
|
|
return min(nMaxConnNum,GetRealConnections(pAreas, nMaxConnNum, bSkipDisabledPortals));
|
|
}
|
|
else
|
|
{
|
|
for(int nPort=0; nPort<m_lstConnections.Count(); nPort++)
|
|
{
|
|
CVisArea * pPortal = m_lstConnections[nPort];
|
|
assert(pPortal->IsPortal());
|
|
for(int nArea=0; nArea<pPortal->m_lstConnections.Count(); nArea++)
|
|
{
|
|
if(pPortal->m_lstConnections[nArea]!=this)
|
|
if(!bSkipDisabledPortals || pPortal->IsActive())
|
|
{
|
|
if(nOut<nMaxConnNum)
|
|
pAreas[nOut] = (IVisArea*)pPortal->m_lstConnections[nArea];
|
|
nOut++;
|
|
break; // take first valid connection
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return min(nMaxConnNum,nOut);
|
|
}
|
|
|
|
bool CVisArea::IsPortalValid()
|
|
{
|
|
if(m_lstConnections.Count()>2 || m_lstConnections.Count()==0)
|
|
return false;
|
|
|
|
for(int i=0; i<m_lstConnections.Count(); i++)
|
|
if(IsEquivalent(m_vConnNormals[i],Vec3d(0,0,0),VEC_EPSILON))
|
|
return false;
|
|
|
|
if(m_lstConnections.Count()>1)
|
|
if( m_vConnNormals[0].Dot(m_vConnNormals[1])>-0.99f )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CVisArea::IsPortalIntersectAreaInValidWay(CVisArea * pPortal)
|
|
{
|
|
const Vec3d & v1Min = pPortal->m_vBoxMin;
|
|
const Vec3d & v1Max = pPortal->m_vBoxMax;
|
|
const Vec3d & v2Min = m_vBoxMin;
|
|
const Vec3d & v2Max = 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)
|
|
{
|
|
// vertical portal
|
|
for(int v=0; v<m_lstShapePoints.Count(); v++)
|
|
{
|
|
int nIntersNum=0;
|
|
bool arrIntResult[4] = { 0,0,0,0 };
|
|
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
|
|
{
|
|
const Vec3d & v0 = m_lstShapePoints[v];
|
|
const Vec3d & v1 = m_lstShapePoints[(v+1)%m_lstShapePoints.Count()];
|
|
const Vec3d & p0 = pPortal->m_lstShapePoints[p];
|
|
const Vec3d & p1 = pPortal->m_lstShapePoints[(p+1)%pPortal->m_lstShapePoints.Count()];
|
|
|
|
if(Is2dLinesIntersect(v0.x,v0.y,v1.x,v1.y,p0.x,p0.y,p1.x,p1.y))
|
|
{
|
|
nIntersNum++;
|
|
arrIntResult[p] = true;
|
|
}
|
|
}
|
|
if(nIntersNum==2 && arrIntResult[0]==arrIntResult[2] && arrIntResult[1]==arrIntResult[3])
|
|
return true;
|
|
}
|
|
|
|
// horisontal portal
|
|
{
|
|
int nBottomPoints=0, nUpPoints=0;
|
|
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
|
|
if(IsPointInsideVisArea(pPortal->m_lstShapePoints[p]))
|
|
nBottomPoints++;
|
|
|
|
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
|
|
if(IsPointInsideVisArea(pPortal->m_lstShapePoints[p]+Vec3d(0,0,pPortal->m_fHeight)))
|
|
nUpPoints++;
|
|
|
|
if(nBottomPoints==0 && nUpPoints==4)
|
|
return true;
|
|
|
|
if(nBottomPoints==4 && nUpPoints==0)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CVisArea::IsPortal()
|
|
{
|
|
bool bThisIsPortal = strstr(m_sName,"portal") != 0;
|
|
return bThisIsPortal;
|
|
}
|
|
/*
|
|
void CVisArea::SetTreeId(int nTreeId)
|
|
{
|
|
if(m_nTreeId == nTreeId)
|
|
return;
|
|
|
|
m_nTreeId = nTreeId;
|
|
|
|
for(int p=0; p<m_lstConnections.Count(); p++)
|
|
m_lstConnections[p]->SetTreeId(nTreeId);
|
|
}
|
|
*/
|
|
bool CVisArea::IsShapeClockwise()
|
|
{
|
|
float fClockWise =
|
|
(m_lstShapePoints[0].x-m_lstShapePoints[1].x)*(m_lstShapePoints[2].y-m_lstShapePoints[1].y)-
|
|
(m_lstShapePoints[0].y-m_lstShapePoints[1].y)*(m_lstShapePoints[2].x-m_lstShapePoints[1].x);
|
|
|
|
return fClockWise>0;
|
|
}
|
|
|
|
void CVisArea::DrawAreaBoundsIntoCBuffer(CCoverageBuffer * pCBuffer)
|
|
{
|
|
if(m_lstShapePoints.Count()!=4)
|
|
return;
|
|
|
|
Vec3d arrVerts[8];
|
|
int arrIndices[24];
|
|
|
|
int v=0;
|
|
int i=0;
|
|
for(int p=0; p<4 && p<m_lstShapePoints.Count(); p++)
|
|
{
|
|
arrVerts[v++] = m_lstShapePoints[p];
|
|
arrVerts[v++] = m_lstShapePoints[p] + Vec3d(0,0,m_fHeight);
|
|
|
|
arrIndices[i++] = (p*2+0)%8;
|
|
arrIndices[i++] = (p*2+1)%8;
|
|
arrIndices[i++] = (p*2+2)%8;
|
|
arrIndices[i++] = (p*2+3)%8;
|
|
arrIndices[i++] = (p*2+2)%8;
|
|
arrIndices[i++] = (p*2+1)%8;
|
|
}
|
|
|
|
Matrix44 mat;
|
|
mat.SetIdentity();
|
|
pCBuffer->AddMesh(arrVerts,8,arrIndices,24,&mat);
|
|
}
|
|
|
|
void CVisArea::ClipPortalVerticesByCameraFrustum(list2<Vec3d> * pPolygon, const CCamera & cam)
|
|
{
|
|
CCoverageBuffer::ClipPolygon(pPolygon, *cam.GetFrustumPlane(FR_PLANE_RIGHT));
|
|
CCoverageBuffer::ClipPolygon(pPolygon, *cam.GetFrustumPlane(FR_PLANE_LEFT));
|
|
CCoverageBuffer::ClipPolygon(pPolygon, *cam.GetFrustumPlane(FR_PLANE_TOP));
|
|
CCoverageBuffer::ClipPolygon(pPolygon, *cam.GetFrustumPlane(FR_PLANE_BOTTOM));
|
|
}
|
|
|
|
void CVisArea::GetMemoryUsage(ICrySizer*pSizer)
|
|
{
|
|
pSizer->AddContainer(m_lstEntities[STATIC_ENTITIES]);
|
|
pSizer->AddContainer(m_lstEntities[DYNAMIC_ENTITIES]);
|
|
|
|
int nSize=0;
|
|
for(int nStatic=0; nStatic<2; nStatic++)
|
|
for(int i=0; i<m_lstEntities[nStatic].Count(); i++)
|
|
nSize += m_lstEntities[nStatic][i]->GetMemoryUsage();
|
|
|
|
pSizer->AddObject(this,sizeof(*this)+nSize);
|
|
}
|
|
|
|
void CVisArea::DrawVolume_NotThisAreaOnlyLights(CObjManager * pObjManager, int nReqursionLevel, CCamera CurCamera, CVisArea * pParent, CVisArea * pCurPortal, bool * pbOutdoorVisible, list2<CCamera> * plstOutPortCameras, bool * pbSkyVisible)
|
|
{
|
|
if(!pParent)
|
|
return;
|
|
|
|
IRenderer * pRenderer = GetRenderer();
|
|
|
|
// mark as rendered
|
|
m_nRndFrameId = GetFrameID();
|
|
|
|
// render lsources
|
|
{
|
|
for( int i=0; i<m_lstEntities[DYNAMIC_ENTITIES].Count(); i++ )
|
|
{
|
|
IEntityRender * pEntityRender = m_lstEntities[DYNAMIC_ENTITIES].GetAt(i);
|
|
CDLight * pLight = pEntityRender->GetLight();
|
|
if(pLight && !(pLight->m_Flags & DLF_THIS_AREA_ONLY))
|
|
{ // process light sources
|
|
Vec3d vBoxMin,vBoxMax;
|
|
pEntityRender->GetRenderBBox(vBoxMin,vBoxMax);
|
|
if( AABB(pParent->m_vBoxMin,pParent->m_vBoxMax).IsIntersectBox( AABB(vBoxMin,vBoxMax)))
|
|
pObjManager->RenderObject( pEntityRender, 0, 0, false, CurCamera, 0, 0, 0, true,
|
|
pEntityRender->GetMaxViewDist());
|
|
}
|
|
else if(pEntityRender->GetRndFlags() & ERF_DONOTCHECKVIS)
|
|
{ // process 1p weapon
|
|
pEntityRender->m_fWSMaxViewDist = pEntityRender->GetMaxViewDist();
|
|
uint nDLightMask = ((C3DEngine*)Get3DEngine())->GetFullLightMask();
|
|
pObjManager->RenderObject( pEntityRender, m_nFogVolumeId,
|
|
nDLightMask, false, CurCamera, &m_vAmbColor, &m_vDynAmbColor, 0, true,
|
|
pEntityRender->m_fWSMaxViewDist);
|
|
}
|
|
}
|
|
}
|
|
|
|
// todo: prepare flag once
|
|
bool bThisIsPortal = strstr(m_sName,"portal") != 0;
|
|
|
|
if(bThisIsPortal && nReqursionLevel>0)
|
|
{ // recurse to not rendered connetions
|
|
for(int p=0; p<m_lstConnections.Count(); p++)
|
|
{
|
|
CVisArea * pNeibVolume = m_lstConnections[p];
|
|
if(pNeibVolume != pParent)
|
|
{
|
|
pNeibVolume->DrawVolume_NotThisAreaOnlyLights(pObjManager, nReqursionLevel-1, CurCamera, this, pCurPortal, pbOutdoorVisible, plstOutPortCameras, pbSkyVisible);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} |