BVB Source Codes

CRYENGINE Show VisAreas.cpp Source code

Return Download CRYENGINE: download VisAreas.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  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:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15.  
  16. #include "VisAreas.h"
  17. #include "3dEngine.h"
  18. #include "TimeOfDay.h"
  19.  
  20. PodArray<CVisArea*> CVisArea::m_lUnavailableAreas;
  21. PodArray<Vec3> CVisArea::s_tmpLstPortVertsClipped;
  22. PodArray<Vec3> CVisArea::s_tmpLstPortVertsSS;
  23. PodArray<Vec3> CVisArea::s_tmpPolygonA;
  24. PodArray<IRenderNode*> CVisArea::s_tmpLstLights;
  25. PodArray<CTerrainNode*> CVisArea::s_tmpLstTerrainNodeResult;
  26. CPolygonClipContext CVisArea::s_tmpClipContext;
  27. PodArray<CCamera> CVisArea::s_tmpCameras;
  28. int CVisArea::s_nGetDistanceThruVisAreasCallCounter = 0;
  29.  
  30. void CVisArea::Update(const Vec3* pPoints, int nCount, const char* szName, const SVisAreaInfo& info)
  31. {
  32.         assert(m_pVisAreaColdData);
  33.  
  34.         cry_strcpy(m_pVisAreaColdData->m_sName, szName);
  35.         _strlwr_s(m_pVisAreaColdData->m_sName, sizeof(m_pVisAreaColdData->m_sName));
  36.  
  37.         m_bThisIsPortal = strstr(m_pVisAreaColdData->m_sName, "portal") != 0;
  38.         m_bIgnoreSky = (strstr(m_pVisAreaColdData->m_sName, "ignoresky") != 0) || info.bIgnoreSkyColor;
  39.  
  40.         m_fHeight = info.fHeight;
  41.         m_vAmbientColor = info.vAmbientColor;
  42.         m_bAffectedByOutLights = info.bAffectedByOutLights;
  43.         m_bSkyOnly = info.bSkyOnly;
  44.         m_fViewDistRatio = info.fViewDistRatio;
  45.         m_bDoubleSide = info.bDoubleSide;
  46.         m_bUseDeepness = info.bUseDeepness;
  47.         m_bUseInIndoors = info.bUseInIndoors;
  48.         m_bOceanVisible = info.bOceanIsVisible;
  49.         m_bIgnoreGI = info.bIgnoreGI;
  50.         m_bIgnoreOutdoorAO = info.bIgnoreOutdoorAO;
  51.         m_fPortalBlending = info.fPortalBlending;
  52.  
  53.         m_lstShapePoints.PreAllocate(nCount, nCount);
  54.  
  55.         if (nCount)
  56.                 memcpy(&m_lstShapePoints[0], pPoints, sizeof(Vec3) * nCount);
  57.  
  58.         // update bbox
  59.         m_boxArea.max = SetMinBB();
  60.         m_boxArea.min = SetMaxBB();
  61.  
  62.         for (int i = 0; i < nCount; i++)
  63.         {
  64.                 m_boxArea.max.CheckMax(pPoints[i]);
  65.                 m_boxArea.min.CheckMin(pPoints[i]);
  66.  
  67.                 m_boxArea.max.CheckMax(pPoints[i] + Vec3(0, 0, m_fHeight));
  68.                 m_boxArea.min.CheckMin(pPoints[i] + Vec3(0, 0, m_fHeight));
  69.         }
  70.  
  71.         UpdateGeometryBBox();
  72.         UpdateClipVolume();
  73. }
  74.  
  75. void CVisArea::StaticReset()
  76. {
  77.         stl::free_container(m_lUnavailableAreas);
  78.         stl::free_container(s_tmpLstPortVertsClipped);
  79.         stl::free_container(s_tmpLstPortVertsSS);
  80.         stl::free_container(s_tmpPolygonA);
  81.         stl::free_container(s_tmpLstLights);
  82.         stl::free_container(s_tmpLstTerrainNodeResult);
  83.         stl::free_container(s_tmpCameras);
  84.         s_tmpClipContext.Reset();
  85. }
  86.  
  87. void CVisArea::Init()
  88. {
  89.         m_fGetDistanceThruVisAreasMinDistance = 10000.f;
  90.         m_nGetDistanceThruVisAreasLastCallID = -1;
  91.         m_pVisAreaColdData = NULL;
  92.         m_boxStatics.min = m_boxStatics.max = m_boxArea.min = m_boxArea.max = Vec3(0, 0, 0);
  93.         m_nRndFrameId = -1;
  94.         m_bActive = true;
  95.         m_fHeight = 0;
  96.         m_vAmbientColor(0, 0, 0);
  97.         m_vConnNormals[0] = m_vConnNormals[1] = Vec3(0, 0, 0);
  98.         m_bAffectedByOutLights = false;
  99.         m_fDistance = 0;
  100.         m_bOceanVisible = m_bSkyOnly = false;
  101.         memset(m_arrOcclCamera, 0, sizeof(m_arrOcclCamera));
  102.         m_fViewDistRatio = 100.f;
  103.         m_bDoubleSide = true;
  104.         m_bUseDeepness = false;
  105.         m_bUseInIndoors = false;
  106.         m_bIgnoreSky = m_bThisIsPortal = false;
  107.         m_bIgnoreGI = false;
  108.         m_bIgnoreOutdoorAO = false;
  109.         m_lstCurCamerasCap = 0;
  110.         m_lstCurCamerasLen = 0;
  111.         m_lstCurCamerasIdx = 0;
  112.         m_nVisGUID = 0;
  113.         m_fPortalBlending = 0.5f;
  114.         m_nStencilRef = 0;
  115. }
  116.  
  117. CVisArea::CVisArea()
  118. {
  119.         Init();
  120. }
  121.  
  122. CVisArea::CVisArea(VisAreaGUID visGUID)
  123. {
  124.         Init();
  125.         m_nVisGUID = visGUID;
  126. }
  127.  
  128. CVisArea::~CVisArea()
  129. {
  130.         for (int i = 0; i < MAX_RECURSION_LEVELS; i++)
  131.                 SAFE_DELETE(m_arrOcclCamera[i]);
  132.  
  133.         GetVisAreaManager()->OnVisAreaDeleted(this);
  134. }
  135.  
  136. float LineSegDistanceSqr(const Vec3& vPos, const Vec3& vP0, const Vec3& vP1)
  137. {
  138.         // Dist of line seg A(+D) from origin:
  139.         // P = A + D t[0..1]
  140.         // d^2(t) = (A + D t)^2 = A^2 + 2 A*D t + D^2 t^2
  141.         // d^2\t = 2 A*D + 2 D^2 t = 0
  142.         // tmin = -A*D / D^2 clamp_tpl(0,1)
  143.         // Pmin = A + D tmin
  144.         Vec3 vP = vP0 - vPos;
  145.         Vec3 vD = vP1 - vP0;
  146.         float fN = -(vP * vD);
  147.         if (fN > 0.f)
  148.         {
  149.                 float fD = vD.GetLengthSquared();
  150.                 if (fN >= fD)
  151.                         vP += vD;
  152.                 else
  153.                         vP += vD * (fN / fD);
  154.         }
  155.         return vP.GetLengthSquared();
  156. }
  157.  
  158. void CVisArea::FindSurroundingVisAreaReqursive(int nMaxReqursion, bool bSkipDisabledPortals, PodArray<IVisArea*>* pVisitedAreas, int nMaxVisitedAreas, int nDeepness, PodArray<CVisArea*>* pUnavailableAreas)
  159. {
  160.         pUnavailableAreas->Add(this);
  161.  
  162.         if (pVisitedAreas && pVisitedAreas->Count() < nMaxVisitedAreas)
  163.                 pVisitedAreas->Add(this);
  164.  
  165.         if (nMaxReqursion > (nDeepness + 1))
  166.                 for (int p = 0; p < m_lstConnections.Count(); p++)
  167.                         if (!bSkipDisabledPortals || m_lstConnections[p]->IsActive())
  168.                         {
  169.                                 if (-1 == pUnavailableAreas->Find(m_lstConnections[p]))
  170.                                         m_lstConnections[p]->FindSurroundingVisAreaReqursive(nMaxReqursion, bSkipDisabledPortals, pVisitedAreas, nMaxVisitedAreas, nDeepness + 1, pUnavailableAreas);
  171.                         }
  172. }
  173.  
  174. void CVisArea::FindSurroundingVisArea(int nMaxReqursion, bool bSkipDisabledPortals, PodArray<IVisArea*>* pVisitedAreas, int nMaxVisitedAreas, int nDeepness)
  175. {
  176.         if (pVisitedAreas)
  177.         {
  178.                 if (pVisitedAreas->capacity() < (uint32)nMaxVisitedAreas)
  179.                         pVisitedAreas->PreAllocate(nMaxVisitedAreas);
  180.         }
  181.  
  182.         m_lUnavailableAreas.Clear();
  183.         m_lUnavailableAreas.PreAllocate(nMaxVisitedAreas, 0);
  184.  
  185.         FindSurroundingVisAreaReqursive(nMaxReqursion, bSkipDisabledPortals, pVisitedAreas, nMaxVisitedAreas, nDeepness, &m_lUnavailableAreas);
  186. }
  187.  
  188. int CVisArea::GetVisFrameId()
  189. {
  190.         return m_nRndFrameId;
  191. }
  192.  
  193. bool Is2dLinesIntersect(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
  194. {
  195.         float fDiv = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
  196.  
  197.         if (fabs(fDiv) < 0.00001f)
  198.                 return false;
  199.  
  200.         float ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / fDiv;
  201.         float ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / fDiv;
  202.  
  203.         return ua > 0 && ua < 1 && ub > 0 && ub < 1;
  204. }
  205.  
  206. Vec3 CVisArea::GetConnectionNormal(CVisArea* pPortal)
  207. {
  208.         assert(m_lstShapePoints.Count() >= 3);
  209.         // find side of shape intersecting with portal
  210.         int nIntersNum = 0;
  211.         Vec3 arrNormals[2] = { Vec3(0, 0, 0), Vec3(0, 0, 0) };
  212.         for (int v = 0; v < m_lstShapePoints.Count(); v++)
  213.         {
  214.                 nIntersNum = 0;
  215.                 arrNormals[0] = Vec3(0, 0, 0);
  216.                 arrNormals[1] = Vec3(0, 0, 0);
  217.                 const Vec3& v0 = m_lstShapePoints[v];
  218.                 const Vec3& v1 = m_lstShapePoints[(v + 1) % m_lstShapePoints.Count()];
  219.                 for (int p = 0; p < pPortal->m_lstShapePoints.Count(); p++)
  220.                 {
  221.                         const Vec3& p0 = pPortal->m_lstShapePoints[p];
  222.                         const Vec3& p1 = pPortal->m_lstShapePoints[(p + 1) % pPortal->m_lstShapePoints.Count()];
  223.  
  224.                         if (Is2dLinesIntersect(v0.x, v0.y, v1.x, v1.y, p0.x, p0.y, p1.x, p1.y))
  225.                         {
  226.                                 Vec3 vNormal = (v0 - v1).GetNormalized().Cross(Vec3(0, 0, 1.f));
  227.                                 if (nIntersNum < 2)
  228.                                         arrNormals[nIntersNum++] = (IsShapeClockwise()) ? -vNormal : vNormal;
  229.                         }
  230.                 }
  231.  
  232.                 if (nIntersNum == 2)
  233.                         break;
  234.         }
  235.  
  236.         if (nIntersNum == 2 &&
  237.             //IsEquivalent(arrNormals[0] == arrNormals[1])
  238.             arrNormals[0].IsEquivalent(arrNormals[1], VEC_EPSILON)
  239.             )
  240.                 return arrNormals[0];
  241.  
  242.         {
  243.                 int nBottomPoints = 0;
  244.                 for (int p = 0; p < pPortal->m_lstShapePoints.Count() && p < 4; p++)
  245.                         if (IsPointInsideVisArea(pPortal->m_lstShapePoints[p]))
  246.                                 nBottomPoints++;
  247.  
  248.                 int nUpPoints = 0;
  249.                 for (int p = 0; p < pPortal->m_lstShapePoints.Count() && p < 4; p++)
  250.                         if (IsPointInsideVisArea(pPortal->m_lstShapePoints[p] + Vec3(0, 0, pPortal->m_fHeight)))
  251.                                 nUpPoints++;
  252.  
  253.                 if (nBottomPoints == 0 && nUpPoints == 4)
  254.                         return Vec3(0, 0, 1);
  255.  
  256.                 if (nBottomPoints == 4 && nUpPoints == 0)
  257.                         return Vec3(0, 0, -1);
  258.         }
  259.  
  260.         return Vec3(0, 0, 0);
  261. }
  262.  
  263. void CVisArea::UpdatePortalCameraPlanes(CCamera& cam, Vec3* pVerts, bool NotForcePlaneSet, const SRenderingPassInfo& passInfo)
  264. {
  265.         const Vec3& vCamPos = passInfo.GetCamera().GetPosition();
  266.         Plane plane, farPlane;
  267.  
  268.         farPlane = *passInfo.GetCamera().GetFrustumPlane(FR_PLANE_FAR);
  269.         cam.SetFrustumPlane(FR_PLANE_FAR, farPlane);
  270.  
  271.         //plane.SetPlane(pVerts[0],pVerts[2],pVerts[1]);  // can potentially create a plane facing the wrong way
  272.         plane.SetPlane(-farPlane.n, pVerts[0]);
  273.         cam.SetFrustumPlane(FR_PLANE_NEAR, plane);
  274.  
  275.         plane.SetPlane(vCamPos, pVerts[3], pVerts[2]);  // update plane only if it reduces fov
  276.         if (!NotForcePlaneSet || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_LEFT)->n) <
  277.             cam.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam.GetFrustumPlane(FR_PLANE_LEFT)->n))
  278.                 cam.SetFrustumPlane(FR_PLANE_RIGHT, plane);
  279.  
  280.         plane.SetPlane(vCamPos, pVerts[1], pVerts[0]);  // update plane only if it reduces fov
  281.         if (!NotForcePlaneSet || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_RIGHT)->n) <
  282.             cam.GetFrustumPlane(FR_PLANE_LEFT)->n.Dot(cam.GetFrustumPlane(FR_PLANE_RIGHT)->n))
  283.                 cam.SetFrustumPlane(FR_PLANE_LEFT, plane);
  284.  
  285.         plane.SetPlane(vCamPos, pVerts[0], pVerts[3]);  // update plane only if it reduces fov
  286.         if (!NotForcePlaneSet || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_TOP)->n) <
  287.             cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n.Dot(cam.GetFrustumPlane(FR_PLANE_TOP)->n))
  288.                 cam.SetFrustumPlane(FR_PLANE_BOTTOM, plane);
  289.  
  290.         plane.SetPlane(vCamPos, pVerts[2], pVerts[1]); // update plane only if it reduces fov
  291.         if (!NotForcePlaneSet || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n) <
  292.             cam.GetFrustumPlane(FR_PLANE_TOP)->n.Dot(cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n))
  293.                 cam.SetFrustumPlane(FR_PLANE_TOP, plane);
  294.  
  295.         Vec3 arrvPortVertsCamSpace[4];
  296.         for (int i = 0; i < 4; i++)
  297.                 arrvPortVertsCamSpace[i] = pVerts[i] - cam.GetPosition();
  298.         cam.SetFrustumVertices(arrvPortVertsCamSpace);
  299.  
  300.         //cam.UpdateFrustum();
  301.  
  302.         if (GetCVars()->e_Portals == 5)
  303.         {
  304.                 float farrColor[4] = { 1, 1, 1, 1 };
  305.                 //              GetRenderer()->SetMaterialColor(1,1,1,1);
  306.                 DrawLine(pVerts[0], pVerts[1]);
  307.                 IRenderAuxText::DrawLabelEx(pVerts[0], 1, farrColor, false, true, "0");
  308.                 DrawLine(pVerts[1], pVerts[2]);
  309.                 IRenderAuxText::DrawLabelEx(pVerts[1], 1, farrColor, false, true, "1");
  310.                 DrawLine(pVerts[2], pVerts[3]);
  311.                 IRenderAuxText::DrawLabelEx(pVerts[2], 1, farrColor, false, true, "2");
  312.                 DrawLine(pVerts[3], pVerts[0]);
  313.                 IRenderAuxText::DrawLabelEx(pVerts[3], 1, farrColor, false, true, "3");
  314.         }
  315. }
  316.  
  317. int __cdecl CVisAreaManager__CmpDistToPortal(const void* v1, const void* v2);
  318.  
  319. void        CVisArea::PreRender(int nReqursionLevel,
  320.                                 CCamera CurCamera, CVisArea* pParent, CVisArea* pCurPortal,
  321.                                 bool* pbOutdoorVisible, PodArray<CCamera>* plstOutPortCameras, bool* pbSkyVisible, bool* pbOceanVisible,
  322.                                 PodArray<CVisArea*>& lstVisibleAreas,
  323.                                 const SRenderingPassInfo& passInfo)
  324. {
  325.         // mark as rendered
  326.         if (m_nRndFrameId != passInfo.GetFrameID())
  327.         {
  328.                 m_lstCurCamerasIdx = 0;
  329.                 m_lstCurCamerasLen = 0;
  330.                 if (m_lstCurCamerasCap)
  331.                 {
  332.                         m_lstCurCamerasIdx = s_tmpCameras.size();
  333.                         s_tmpCameras.resize(s_tmpCameras.size() + m_lstCurCamerasCap);
  334.                 }
  335.         }
  336.  
  337.         m_nRndFrameId = passInfo.GetFrameID();
  338.  
  339.         if (m_bAffectedByOutLights)
  340.                 GetVisAreaManager()->m_bSunIsNeeded = true;
  341.  
  342.         if (m_lstCurCamerasLen == m_lstCurCamerasCap)
  343.         {
  344.                 int newIdx = s_tmpCameras.size();
  345.  
  346.                 m_lstCurCamerasCap += max(1, m_lstCurCamerasCap / 2);
  347.                 s_tmpCameras.resize(newIdx + m_lstCurCamerasCap);
  348.                 if (m_lstCurCamerasLen)
  349.                         memcpy(&s_tmpCameras[newIdx], &s_tmpCameras[m_lstCurCamerasIdx], m_lstCurCamerasLen * sizeof(CCamera));
  350.  
  351.                 m_lstCurCamerasIdx = newIdx;
  352.         }
  353.         s_tmpCameras[m_lstCurCamerasIdx + m_lstCurCamerasLen] = CurCamera;
  354.         ++m_lstCurCamerasLen;
  355.  
  356.         if (lstVisibleAreas.Find(this) < 0)
  357.         {
  358.                 lstVisibleAreas.Add(this);
  359.                 m_nStencilRef = passInfo.GetIRenderView()->AddClipVolume(this);
  360.         }
  361.  
  362.         // check recursion and portal activity
  363.         if (!nReqursionLevel || !m_bActive)
  364.                 return;
  365.  
  366.         if (pParent && m_bThisIsPortal && m_lstConnections.Count() == 1 && // detect entrance
  367.             !IsPointInsideVisArea(passInfo.GetCamera().GetPosition()))     // detect camera in outdoors
  368.         {
  369.                 AABB boxAreaEx = m_boxArea;
  370.                 float fZNear = CurCamera.GetNearPlane();
  371.                 boxAreaEx.min -= Vec3(fZNear, fZNear, fZNear);
  372.                 boxAreaEx.max += Vec3(fZNear, fZNear, fZNear);
  373.                 if (!CurCamera.IsAABBVisible_E(boxAreaEx)) // if portal is invisible
  374.                         return;                                  // stop recursion
  375.         }
  376.  
  377.         bool bCanSeeThruThisArea = true;
  378.  
  379.         // prepare new camera for next areas
  380.         if (m_bThisIsPortal && m_lstConnections.Count() &&
  381.             (this != pCurPortal || !pCurPortal->IsPointInsideVisArea(CurCamera.GetPosition())))
  382.         {
  383.                 Vec3 vCenter = m_boxArea.GetCenter();
  384.                 float fRadius = m_boxArea.GetRadius();
  385.  
  386.                 Vec3 vPortNorm = (!pParent || pParent == m_lstConnections[0] || m_lstConnections.Count() == 1) ?
  387.                                  m_vConnNormals[0] : m_vConnNormals[1];
  388.  
  389.                 // exit/entrance portal has only one normal in direction to outdoors, so flip it to the camera
  390.                 if (m_lstConnections.Count() == 1 && !pParent)
  391.                         vPortNorm = -vPortNorm;
  392.  
  393.                 // back face check
  394.                 Vec3 vPortToCamDir = CurCamera.GetPosition() - vCenter;
  395.                 if (vPortToCamDir.Dot(vPortNorm) < 0)
  396.                         return;
  397.  
  398.                 if (!m_bDoubleSide)
  399.                         if (vPortToCamDir.Dot(m_vConnNormals[0]) < 0)
  400.                                 return;
  401.  
  402.                 Vec3 arrPortVerts[4];
  403.                 Vec3 arrPortVertsOtherSide[4];
  404.                 bool barrPortVertsOtherSideValid = false;
  405.                 if (pParent && !vPortNorm.IsEquivalent(Vec3(0, 0, 0), VEC_EPSILON) && vPortNorm.z)
  406.                 {
  407.                         // up/down portal
  408.                         int nEven = IsShapeClockwise();
  409.                         if (vPortNorm.z > 0)
  410.                                 nEven = !nEven;
  411.                         for (int i = 0; i < 4; i++)
  412.                         {
  413.                                 arrPortVerts[i] = m_lstShapePoints[nEven ? (3 - i) : i] + Vec3(0, 0, m_fHeight) * (vPortNorm.z > 0);
  414.                                 arrPortVertsOtherSide[i] = m_lstShapePoints[nEven ? (3 - i) : i] + Vec3(0, 0, m_fHeight) * (vPortNorm.z < 0);
  415.                         }
  416.                         barrPortVertsOtherSideValid = true;
  417.                 }
  418.                 else if (!vPortNorm.IsEquivalent(Vec3(0, 0, 0), VEC_EPSILON) && vPortNorm.z == 0)
  419.                 {
  420.                         // basic portal
  421.                         Vec3 arrInAreaPoint[2] = { Vec3(0, 0, 0), Vec3(0, 0, 0) };
  422.                         int arrInAreaPointId[2] = { -1, -1 };
  423.                         int nInAreaPointCounter = 0;
  424.  
  425.                         Vec3 arrOutAreaPoint[2] = { Vec3(0, 0, 0), Vec3(0, 0, 0) };
  426.                         int nOutAreaPointCounter = 0;
  427.  
  428.                         // find 2 points of portal in this area (or in this outdoors)
  429.                         for (int i = 0; i < m_lstShapePoints.Count() && nInAreaPointCounter < 2; i++)
  430.                         {
  431.                                 Vec3 vTestPoint = m_lstShapePoints[i] + Vec3(0, 0, m_fHeight * 0.5f);
  432.                                 CVisArea* pAnotherArea = m_lstConnections[0];
  433.                                 if ((pParent && (pParent->IsPointInsideVisArea(vTestPoint))) ||
  434.                                     (!pParent && (!pAnotherArea->IsPointInsideVisArea(vTestPoint))))
  435.                                 {
  436.                                         arrInAreaPointId[nInAreaPointCounter] = i;
  437.                                         arrInAreaPoint[nInAreaPointCounter++] = m_lstShapePoints[i];
  438.                                 }
  439.                         }
  440.  
  441.                         // find 2 points of portal not in this area (or not in this outdoors)
  442.                         for (int i = 0; i < m_lstShapePoints.Count() && nOutAreaPointCounter < 2; i++)
  443.                         {
  444.                                 Vec3 vTestPoint = m_lstShapePoints[i] + Vec3(0, 0, m_fHeight * 0.5f);
  445.                                 CVisArea* pAnotherArea = m_lstConnections[0];
  446.                                 if ((pParent && (pParent->IsPointInsideVisArea(vTestPoint))) ||
  447.                                     (!pParent && (!pAnotherArea->IsPointInsideVisArea(vTestPoint))))
  448.                                 {
  449.                                 }
  450.                                 else
  451.                                 {
  452.                                         arrOutAreaPoint[nOutAreaPointCounter++] = m_lstShapePoints[i];
  453.                                 }
  454.                         }
  455.  
  456.                         if (nInAreaPointCounter == 2)
  457.                         {
  458.                                 // success, take into account volume and portal shape versts order
  459.                                 int nEven = IsShapeClockwise();
  460.                                 if (arrInAreaPointId[1] - arrInAreaPointId[0] != 1)
  461.                                         nEven = !nEven;
  462.  
  463.                                 arrPortVerts[0] = arrInAreaPoint[nEven];
  464.                                 arrPortVerts[1] = arrInAreaPoint[nEven] + Vec3(0, 0, m_fHeight);
  465.                                 arrPortVerts[2] = arrInAreaPoint[!nEven] + Vec3(0, 0, m_fHeight);
  466.                                 arrPortVerts[3] = arrInAreaPoint[!nEven];
  467.  
  468.                                 nEven = !nEven;
  469.  
  470.                                 arrPortVertsOtherSide[0] = arrOutAreaPoint[nEven];
  471.                                 arrPortVertsOtherSide[1] = arrOutAreaPoint[nEven] + Vec3(0, 0, m_fHeight);
  472.                                 arrPortVertsOtherSide[2] = arrOutAreaPoint[!nEven] + Vec3(0, 0, m_fHeight);
  473.                                 arrPortVertsOtherSide[3] = arrOutAreaPoint[!nEven];
  474.                                 barrPortVertsOtherSideValid = true;
  475.                         }
  476.                         else
  477.                         {
  478.                                 // something wrong
  479.                                 Warning("CVisArea::PreRender: Invalid portal: %s", m_pVisAreaColdData->m_sName);
  480.                                 return;
  481.                         }
  482.                 }
  483.                 else if (!pParent && vPortNorm.z == 0 && m_lstConnections.Count() == 1)
  484.                 {
  485.                         // basic entrance portal
  486.                         Vec3 vBorder = (vPortNorm.Cross(Vec3(0, 0, 1.f))).GetNormalized() * fRadius;
  487.                         arrPortVerts[0] = vCenter - Vec3(0, 0, 1.f) * fRadius - vBorder;
  488.                         arrPortVerts[1] = vCenter + Vec3(0, 0, 1.f) * fRadius - vBorder;
  489.                         arrPortVerts[2] = vCenter + Vec3(0, 0, 1.f) * fRadius + vBorder;
  490.                         arrPortVerts[3] = vCenter - Vec3(0, 0, 1.f) * fRadius + vBorder;
  491.                 }
  492.                 else if (!pParent && vPortNorm.z != 0 && m_lstConnections.Count() == 1)
  493.                 {
  494.                         // up/down entrance portal
  495.                         Vec3 vBorder = (vPortNorm.Cross(Vec3(0, 1, 0.f))).GetNormalized() * fRadius;
  496.                         arrPortVerts[0] = vCenter - Vec3(0, 1, 0.f) * fRadius + vBorder;
  497.                         arrPortVerts[1] = vCenter + Vec3(0, 1, 0.f) * fRadius + vBorder;
  498.                         arrPortVerts[2] = vCenter + Vec3(0, 1, 0.f) * fRadius - vBorder;
  499.                         arrPortVerts[3] = vCenter - Vec3(0, 1, 0.f) * fRadius - vBorder;
  500.                 }
  501.                 else
  502.                 {
  503.                         // something wrong or areabox portal - use simple solution
  504.                         if (vPortNorm.IsEquivalent(Vec3(0, 0, 0), VEC_EPSILON))
  505.                                 vPortNorm = (vCenter - passInfo.GetCamera().GetPosition()).GetNormalized();
  506.  
  507.                         Vec3 vBorder = (vPortNorm.Cross(Vec3(0, 0, 1.f))).GetNormalized() * fRadius;
  508.                         arrPortVerts[0] = vCenter - Vec3(0, 0, 1.f) * fRadius - vBorder;
  509.                         arrPortVerts[1] = vCenter + Vec3(0, 0, 1.f) * fRadius - vBorder;
  510.                         arrPortVerts[2] = vCenter + Vec3(0, 0, 1.f) * fRadius + vBorder;
  511.                         arrPortVerts[3] = vCenter - Vec3(0, 0, 1.f) * fRadius + vBorder;
  512.                 }
  513.  
  514.                 if (GetCVars()->e_Portals == 4) // make color recursion dependent
  515.                         GetRenderer()->SetMaterialColor(1, 1, passInfo.IsGeneralPass(), 1);
  516.  
  517.                 Vec3 vPortalFaceCenter = (arrPortVerts[0] + arrPortVerts[1] + arrPortVerts[2] + arrPortVerts[3]) / 4;
  518.                 vPortToCamDir = CurCamera.GetPosition() - vPortalFaceCenter;
  519.                 if (vPortToCamDir.GetNormalized().Dot(vPortNorm) < -0.01f)
  520.                 {
  521.                         UpdatePortalBlendInfo(passInfo);
  522.                         return;
  523.                 }
  524.  
  525.                 const bool Upright = (fabsf(vPortNorm.z) < FLT_EPSILON);
  526.                 CCamera camParent = CurCamera;
  527.  
  528.                 // clip portal quad by camera planes
  529.                 PodArray<Vec3>& lstPortVertsClipped = s_tmpLstPortVertsClipped;
  530.                 lstPortVertsClipped.Clear();
  531.                 lstPortVertsClipped.AddList(arrPortVerts, 4);
  532.                 ClipPortalVerticesByCameraFrustum(&lstPortVertsClipped, camParent);
  533.  
  534.                 AABB aabb;
  535.                 aabb.Reset();
  536.  
  537.                 if (lstPortVertsClipped.Count() > 2)
  538.                 {
  539.                         // find screen space bounds of clipped portal
  540.                         for (int i = 0; i < lstPortVertsClipped.Count(); i++)
  541.                         {
  542.                                 Vec3 vSS;
  543.                                 GetRenderer()->ProjectToScreen(lstPortVertsClipped[i].x, lstPortVertsClipped[i].y, lstPortVertsClipped[i].z, &vSS.x, &vSS.y, &vSS.z);
  544.                                 vSS.y = 100 - vSS.y;
  545.                                 aabb.Add(vSS);
  546.                         }
  547.                 }
  548.                 else
  549.                 {
  550.                         if (!CVisArea::IsSphereInsideVisArea(CurCamera.GetPosition(), CurCamera.GetNearPlane()))
  551.                                 bCanSeeThruThisArea = false;
  552.                 }
  553.  
  554.                 if (lstPortVertsClipped.Count() > 2 && aabb.min.z > 0.01f)
  555.                 {
  556.                         PodArray<Vec3>& lstPortVertsSS = s_tmpLstPortVertsSS;
  557.                         lstPortVertsSS.PreAllocate(4, 4);
  558.  
  559.                         // get 3d positions of portal bounds
  560.                         {
  561.                                 int i = 0;
  562.                                 float w = (float)GetRenderer()->GetWidth();
  563.                                 float h = (float)GetRenderer()->GetHeight();
  564.                                 float d = 0.01f;
  565.  
  566.                                 GetRenderer()->UnProjectFromScreen(aabb.min.x * w / 100, aabb.min.y * h / 100, d, &lstPortVertsSS[i].x, &lstPortVertsSS[i].y, &lstPortVertsSS[i].z);
  567.                                 i++;
  568.                                 GetRenderer()->UnProjectFromScreen(aabb.min.x * w / 100, aabb.max.y * h / 100, d, &lstPortVertsSS[i].x, &lstPortVertsSS[i].y, &lstPortVertsSS[i].z);
  569.                                 i++;
  570.                                 GetRenderer()->UnProjectFromScreen(aabb.max.x * w / 100, aabb.max.y * h / 100, d, &lstPortVertsSS[i].x, &lstPortVertsSS[i].y, &lstPortVertsSS[i].z);
  571.                                 i++;
  572.                                 GetRenderer()->UnProjectFromScreen(aabb.max.x * w / 100, aabb.min.y * h / 100, d, &lstPortVertsSS[i].x, &lstPortVertsSS[i].y, &lstPortVertsSS[i].z);
  573.                                 i++;
  574.  
  575.                                 CurCamera.m_ScissorInfo.x1 = uint16(CLAMP(aabb.min.x * w / 100, 0, w));
  576.                                 CurCamera.m_ScissorInfo.y1 = uint16(CLAMP(aabb.min.y * h / 100, 0, h));
  577.                                 CurCamera.m_ScissorInfo.x2 = uint16(CLAMP(aabb.max.x * w / 100, 0, w));
  578.                                 CurCamera.m_ScissorInfo.y2 = uint16(CLAMP(aabb.max.y * h / 100, 0, h));
  579.                         }
  580.  
  581.                         if (GetCVars()->e_Portals == 4)
  582.                                 for (int i = 0; i < lstPortVertsSS.Count(); i++)
  583.                                 {
  584.                                         float farrColor[4] = { float((nReqursionLevel & 1) > 0), float((nReqursionLevel & 2) > 0), float((nReqursionLevel & 4) > 0), 1 };
  585.                                         ColorF c(farrColor[0], farrColor[1], farrColor[2], farrColor[3]);
  586.                                         DrawSphere(lstPortVertsSS[i], 0.002f, c);
  587.                                         IRenderAuxText::DrawLabelExF(lstPortVertsSS[i], 0.1f, farrColor, false, true, "%d", i);
  588.                                 }
  589.  
  590.                         UpdatePortalCameraPlanes(CurCamera, lstPortVertsSS.GetElements(), Upright, passInfo);
  591.  
  592.                         bCanSeeThruThisArea =
  593.                           (CurCamera.m_ScissorInfo.x1 < CurCamera.m_ScissorInfo.x2) &&
  594.                           (CurCamera.m_ScissorInfo.y1 < CurCamera.m_ScissorInfo.y2);
  595.                 }
  596.  
  597.                 if (m_bUseDeepness && bCanSeeThruThisArea && barrPortVertsOtherSideValid)
  598.                 {
  599.                         Vec3 vOtherSideBoxMax = SetMinBB();
  600.                         Vec3 vOtherSideBoxMin = SetMaxBB();
  601.                         for (int i = 0; i < 4; i++)
  602.                         {
  603.                                 vOtherSideBoxMin.CheckMin(arrPortVertsOtherSide[i] - Vec3(0.01f, 0.01f, 0.01f));
  604.                                 vOtherSideBoxMax.CheckMax(arrPortVertsOtherSide[i] + Vec3(0.01f, 0.01f, 0.01f));
  605.                         }
  606.  
  607.                         bCanSeeThruThisArea = CurCamera.IsAABBVisible_E(AABB(vOtherSideBoxMin, vOtherSideBoxMax));
  608.                 }
  609.  
  610.                 if (bCanSeeThruThisArea && pParent && m_lstConnections.Count() == 1)
  611.                 {
  612.                         // set this camera for outdoor
  613.                         if (nReqursionLevel >= 1)
  614.                         {
  615.                                 if (!m_bSkyOnly)
  616.                                 {
  617.                                         if (plstOutPortCameras)
  618.                                         {
  619.                                                 plstOutPortCameras->Add(CurCamera);
  620.                                                 plstOutPortCameras->Last().m_pPortal = this;
  621.                                         }
  622.                                         if (pbOutdoorVisible)
  623.                                                 *pbOutdoorVisible = true;
  624.                                 }
  625.                                 else if (pbSkyVisible)
  626.                                         *pbSkyVisible = true;
  627.                         }
  628.  
  629.                         UpdatePortalBlendInfo(passInfo);
  630.                         return;
  631.                 }
  632.         }
  633.  
  634.         // sort portals by distance
  635.         if (!m_bThisIsPortal && m_lstConnections.Count())
  636.         {
  637.                 for (int p = 0; p < m_lstConnections.Count(); p++)
  638.                 {
  639.                         CVisArea* pNeibVolume = m_lstConnections[p];
  640.                         pNeibVolume->m_fDistance = CurCamera.GetPosition().GetDistance((pNeibVolume->m_boxArea.min + pNeibVolume->m_boxArea.max) * 0.5f);
  641.                 }
  642.  
  643.                 qsort(&m_lstConnections[0], m_lstConnections.Count(),
  644.                       sizeof(m_lstConnections[0]), CVisAreaManager__CmpDistToPortal);
  645.         }
  646.  
  647.         if (m_bOceanVisible && pbOceanVisible)
  648.                 *pbOceanVisible = true;
  649.  
  650.         // recurse to connections
  651.         for (int p = 0; p < m_lstConnections.Count(); p++)
  652.         {
  653.                 CVisArea* pNeibVolume = m_lstConnections[p];
  654.                 if (pNeibVolume != pParent)
  655.                 {
  656.                         if (!m_bThisIsPortal)
  657.                         {
  658.                                 // skip far portals
  659.                                 float fRadius = (pNeibVolume->m_boxArea.max - pNeibVolume->m_boxArea.min).GetLength() * 0.5f * GetFloatCVar(e_ViewDistRatioPortals) / 60.f;
  660.                                 if (pNeibVolume->m_fDistance * passInfo.GetZoomFactor() > fRadius * pNeibVolume->m_fViewDistRatio)
  661.                                         continue;
  662.  
  663.                                 Vec3 vPortNorm = (this == pNeibVolume->m_lstConnections[0] || pNeibVolume->m_lstConnections.Count() == 1) ?
  664.                                                  pNeibVolume->m_vConnNormals[0] : pNeibVolume->m_vConnNormals[1];
  665.  
  666.                                 // back face check
  667.                                 Vec3 vPortToCamDir = CurCamera.GetPosition() - pNeibVolume->GetAABBox()->GetCenter();
  668.                                 if (vPortToCamDir.Dot(vPortNorm) < 0)
  669.                                         continue;
  670.                         }
  671.  
  672.                         if ((bCanSeeThruThisArea || m_lstConnections.Count() == 1) && (m_bThisIsPortal || CurCamera.IsAABBVisible_F(pNeibVolume->m_boxStatics)))
  673.                                 pNeibVolume->PreRender(nReqursionLevel - 1, CurCamera, this, pCurPortal, pbOutdoorVisible, plstOutPortCameras, pbSkyVisible, pbOceanVisible, lstVisibleAreas, passInfo);
  674.                 }
  675.         }
  676.  
  677.         if (m_bThisIsPortal)
  678.                 UpdatePortalBlendInfo(passInfo);
  679. }
  680.  
  681. //! return list of visareas connected to specified visarea (can return portals and sectors)
  682. int CVisArea::GetRealConnections(IVisArea** pAreas, int nMaxConnNum, bool bSkipDisabledPortals)
  683. {
  684.         int nOut = 0;
  685.         for (int nArea = 0; nArea < m_lstConnections.Count(); nArea++)
  686.         {
  687.                 if (nOut < nMaxConnNum)
  688.                         pAreas[nOut] = (IVisArea*)m_lstConnections[nArea];
  689.                 nOut++;
  690.         }
  691.         return nOut;
  692. }
  693.  
  694. //! return list of sectors conected to specified sector or portal (returns sectors only)
  695. // todo: change the way it returns data
  696. int CVisArea::GetVisAreaConnections(IVisArea** pAreas, int nMaxConnNum, bool bSkipDisabledPortals)
  697. {
  698.         int nOut = 0;
  699.         if (IsPortal())
  700.         {
  701.                 /*              for(int nArea=0; nArea<m_lstConnections.Count(); nArea++)
  702.                     {
  703.                       if(nOut<nMaxConnNum)
  704.                         pAreas[nOut] = (IVisArea*)m_lstConnections[nArea];
  705.                       nOut++;
  706.                     }*/
  707.                 return min(nMaxConnNum, GetRealConnections(pAreas, nMaxConnNum, bSkipDisabledPortals));
  708.         }
  709.         else
  710.         {
  711.                 for (int nPort = 0; nPort < m_lstConnections.Count(); nPort++)
  712.                 {
  713.                         CVisArea* pPortal = m_lstConnections[nPort];
  714.                         assert(pPortal->IsPortal());
  715.                         for (int nArea = 0; nArea < pPortal->m_lstConnections.Count(); nArea++)
  716.                         {
  717.                                 if (pPortal->m_lstConnections[nArea] != this)
  718.                                         if (!bSkipDisabledPortals || pPortal->IsActive())
  719.                                         {
  720.                                                 if (nOut < nMaxConnNum)
  721.                                                         pAreas[nOut] = (IVisArea*)pPortal->m_lstConnections[nArea];
  722.                                                 nOut++;
  723.                                                 break; // take first valid connection
  724.                                         }
  725.                         }
  726.                 }
  727.         }
  728.  
  729.         return min(nMaxConnNum, nOut);
  730. }
  731.  
  732. bool CVisArea::IsPortalValid()
  733. {
  734.         int nCount = m_lstConnections.Count();
  735.         if (nCount > 2 || nCount == 0)
  736.                 return false;
  737.  
  738.         for (int i = 0; i < nCount; i++)
  739.         {
  740.                 if (m_vConnNormals[i].IsEquivalent(Vec3(0, 0, 0), VEC_EPSILON))
  741.                         return false;
  742.         }
  743.  
  744.         if (nCount > 1)
  745.                 if (m_vConnNormals[0].Dot(m_vConnNormals[1]) > -0.99f)
  746.                         return false;
  747.  
  748.         return true;
  749. }
  750.  
  751. bool CVisArea::IsPortalIntersectAreaInValidWay(CVisArea* pPortal)
  752. {
  753.         const Vec3& v1Min = pPortal->m_boxArea.min;
  754.         const Vec3& v1Max = pPortal->m_boxArea.max;
  755.         const Vec3& v2Min = m_boxArea.min;
  756.         const Vec3& v2Max = m_boxArea.max;
  757.  
  758.         if (v1Max.x > v2Min.x && v2Max.x > v1Min.x)
  759.                 if (v1Max.y > v2Min.y && v2Max.y > v1Min.y)
  760.                         if (v1Max.z > v2Min.z && v2Max.z > v1Min.z)
  761.                         {
  762.                                 // vertical portal
  763.                                 for (int v = 0; v < m_lstShapePoints.Count(); v++)
  764.                                 {
  765.                                         int nIntersNum = 0;
  766.                                         bool arrIntResult[4] = { 0, 0, 0, 0 };
  767.                                         for (int p = 0; p < pPortal->m_lstShapePoints.Count() && p < 4; p++)
  768.                                         {
  769.                                                 const Vec3& v0 = m_lstShapePoints[v];
  770.                                                 const Vec3& v1 = m_lstShapePoints[(v + 1) % m_lstShapePoints.Count()];
  771.                                                 const Vec3& p0 = pPortal->m_lstShapePoints[p];
  772.                                                 const Vec3& p1 = pPortal->m_lstShapePoints[(p + 1) % pPortal->m_lstShapePoints.Count()];
  773.  
  774.                                                 if (Is2dLinesIntersect(v0.x, v0.y, v1.x, v1.y, p0.x, p0.y, p1.x, p1.y))
  775.                                                 {
  776.                                                         nIntersNum++;
  777.                                                         arrIntResult[p] = true;
  778.                                                 }
  779.                                         }
  780.                                         if (nIntersNum == 2 && arrIntResult[0] == arrIntResult[2] && arrIntResult[1] == arrIntResult[3])
  781.                                                 return true;
  782.                                 }
  783.  
  784.                                 // horisontal portal
  785.                                 {
  786.                                         int nBottomPoints = 0, nUpPoints = 0;
  787.                                         for (int p = 0; p < pPortal->m_lstShapePoints.Count() && p < 4; p++)
  788.                                                 if (IsPointInsideVisArea(pPortal->m_lstShapePoints[p]))
  789.                                                         nBottomPoints++;
  790.  
  791.                                         for (int p = 0; p < pPortal->m_lstShapePoints.Count() && p < 4; p++)
  792.                                                 if (IsPointInsideVisArea(pPortal->m_lstShapePoints[p] + Vec3(0, 0, pPortal->m_fHeight)))
  793.                                                         nUpPoints++;
  794.  
  795.                                         if (nBottomPoints == 0 && nUpPoints == 4)
  796.                                                 return true;
  797.  
  798.                                         if (nBottomPoints == 4 && nUpPoints == 0)
  799.                                                 return true;
  800.                                 }
  801.                         }
  802.  
  803.         return false;
  804. }
  805.  
  806. /*
  807.    void CVisArea::SetTreeId(int nTreeId)
  808.    {
  809.    if(m_nTreeId == nTreeId)
  810.     return;
  811.  
  812.    m_nTreeId = nTreeId;
  813.  
  814.    for(int p=0; p<m_lstConnections.Count(); p++)
  815.     m_lstConnections[p]->SetTreeId(nTreeId);
  816.    }
  817.  */
  818. bool CVisArea::IsShapeClockwise()
  819. {
  820.         float fClockWise =
  821.           (m_lstShapePoints[0].x - m_lstShapePoints[1].x) * (m_lstShapePoints[2].y - m_lstShapePoints[1].y) -
  822.           (m_lstShapePoints[0].y - m_lstShapePoints[1].y) * (m_lstShapePoints[2].x - m_lstShapePoints[1].x);
  823.  
  824.         return fClockWise > 0;
  825. }
  826.  
  827. void CVisArea::DrawAreaBoundsIntoCBuffer(CCullBuffer* pCBuffer)
  828. {
  829.         assert(!"temprary not supported");
  830.  
  831.         /*  if(m_lstShapePoints.Count()!=4)
  832.             return;
  833.  
  834.            Vec3 arrVerts[8];
  835.            int arrIndices[24];
  836.  
  837.            int v=0;
  838.            int i=0;
  839.            for(int p=0; p<4 && p<m_lstShapePoints.Count(); p++)
  840.            {
  841.             arrVerts[v++] = m_lstShapePoints[p];
  842.             arrVerts[v++] = m_lstShapePoints[p] + Vec3(0,0,m_fHeight);
  843.  
  844.             arrIndices[i++] = (p*2+0)%8;
  845.             arrIndices[i++] = (p*2+1)%8;
  846.             arrIndices[i++] = (p*2+2)%8;
  847.             arrIndices[i++] = (p*2+3)%8;
  848.             arrIndices[i++] = (p*2+2)%8;
  849.             arrIndices[i++] = (p*2+1)%8;
  850.            }
  851.  
  852.            Matrix34 mat;
  853.            mat.SetIdentity();
  854.            pCBuffer->AddMesh(arrVerts,8,arrIndices,24,&mat);*/
  855. }
  856.  
  857. void CVisArea::ClipPortalVerticesByCameraFrustum(PodArray<Vec3>* pPolygon, const CCamera& cam)
  858. {
  859.         Plane planes[5] = {
  860.                 *cam.GetFrustumPlane(FR_PLANE_RIGHT),
  861.                 *cam.GetFrustumPlane(FR_PLANE_LEFT),
  862.                 *cam.GetFrustumPlane(FR_PLANE_TOP),
  863.                 *cam.GetFrustumPlane(FR_PLANE_BOTTOM),
  864.                 *cam.GetFrustumPlane(FR_PLANE_NEAR)
  865.         };
  866.  
  867.         const PodArray<Vec3>& clipped = s_tmpClipContext.Clip(*pPolygon, planes, 4);
  868.  
  869.         pPolygon->Clear();
  870.         pPolygon->AddList(clipped);
  871. }
  872.  
  873. void CVisArea::GetMemoryUsage(ICrySizer* pSizer)
  874. {
  875.         //  pSizer->AddContainer(m_lstEntities[STATIC_OBJECTS]);
  876.         //pSizer->AddContainer(m_lstEntities[DYNAMIC_OBJECTS]);
  877.  
  878.         // TODO: include obects tree
  879.  
  880.         if (m_pObjectsTree)
  881.         {
  882.                 SIZER_COMPONENT_NAME(pSizer, "IndoorObjectsTree");
  883.                 m_pObjectsTree->GetMemoryUsage(pSizer);
  884.         }
  885.  
  886.         //  for(int nStatic=0; nStatic<2; nStatic++)
  887.         //for(int i=0; i<m_lstEntities[nStatic].Count(); i++)
  888.         //    nSize += m_lstEntities[nStatic][i].pNode->GetMemoryUsage();
  889.  
  890.         pSizer->AddObject(this, sizeof(*this));
  891. }
  892.  
  893. void CVisArea::UpdateOcclusionFlagInTerrain()
  894. {
  895.         if (m_bAffectedByOutLights && !m_bThisIsPortal)
  896.         {
  897.                 Vec3 vCenter = GetAABBox()->GetCenter();
  898.                 if (vCenter.z < GetTerrain()->GetZApr(vCenter.x, vCenter.y, GetDefSID()))
  899.                 {
  900.                         AABB box = *GetAABBox();
  901.                         box.min.z = 0;
  902.                         box.min -= Vec3(8, 8, 8);
  903.                         box.max.z = 16000;
  904.                         box.max += Vec3(8, 8, 8);
  905.                         PodArray<CTerrainNode*>& lstResult = s_tmpLstTerrainNodeResult;
  906.                         lstResult.Clear();
  907.                         GetTerrain()->IntersectWithBox(box, &lstResult, GetDefSID());
  908.                         for (int i = 0; i < lstResult.Count(); i++)
  909.                                 if (lstResult[i]->m_nTreeLevel <= 2)
  910.                                         lstResult[i]->m_bNoOcclusion = true;
  911.                 }
  912.         }
  913. }
  914.  
  915. void CVisArea::AddConnectedAreas(PodArray<CVisArea*>& lstAreas, int nMaxRecursion)
  916. {
  917.         if (lstAreas.Find(this) < 0)
  918.         {
  919.                 lstAreas.Add(this);
  920.  
  921.                 // add connected areas
  922.                 if (nMaxRecursion)
  923.                 {
  924.                         nMaxRecursion--;
  925.  
  926.                         for (int p = 0; p < m_lstConnections.Count(); p++)
  927.                         {
  928.                                 m_lstConnections[p]->AddConnectedAreas(lstAreas, nMaxRecursion);
  929.                         }
  930.                 }
  931.         }
  932. }
  933.  
  934. bool CVisArea::GetDistanceThruVisAreas(AABB vCurBoxIn, IVisArea* pTargetArea, const AABB& targetBox, int nMaxReqursion, float& fResDist)
  935. {
  936.         return GetDistanceThruVisAreasReq(vCurBoxIn, 0, pTargetArea, targetBox, nMaxReqursion, fResDist, NULL, s_nGetDistanceThruVisAreasCallCounter++);
  937. }
  938.  
  939. float DistanceAABB(const AABB& aBox, const AABB& bBox)
  940. {
  941.         float result = 0;
  942.  
  943.         for (int i = 0; i < 3; ++i)
  944.         {
  945.                 const float& aMin = aBox.min[i];
  946.                 const float& aMax = aBox.max[i];
  947.                 const float& bMin = bBox.min[i];
  948.                 const float& bMax = bBox.max[i];
  949.  
  950.                 if (aMin > bMax)
  951.                 {
  952.                         const float delta = bMax - aMin;
  953.  
  954.                         result += delta * delta;
  955.                 }
  956.                 else if (bMin > aMax)
  957.                 {
  958.                         const float delta = aMax - bMin;
  959.  
  960.                         result += delta * delta;
  961.                 }
  962.                 // else the projection intervals overlap.
  963.         }
  964.  
  965.         return sqrt(result);
  966. }
  967.  
  968. bool CVisArea::GetDistanceThruVisAreasReq(AABB vCurBoxIn, float fCurDistIn, IVisArea* pTargetArea, const AABB& targetBox, int nMaxReqursion, float& fResDist, CVisArea* pPrevArea, int nCallID)
  969. {
  970.         if (pTargetArea == this || (pTargetArea == NULL && IsConnectedToOutdoor()))
  971.         {
  972.                 // target area is found
  973.                 fResDist = min(fResDist, fCurDistIn + DistanceAABB(vCurBoxIn, targetBox));
  974.                 return true;
  975.         }
  976.  
  977.         // if we already visited this area and last time input distance was smaller - makes no sence to continue
  978.         if (nCallID == m_nGetDistanceThruVisAreasLastCallID)
  979.                 if (fCurDistIn >= m_fGetDistanceThruVisAreasMinDistance)
  980.                         return false;
  981.  
  982.         m_nGetDistanceThruVisAreasLastCallID = nCallID;
  983.         m_fGetDistanceThruVisAreasMinDistance = fCurDistIn;
  984.  
  985.         fResDist = FLT_MAX;
  986.  
  987.         bool bFound = false;
  988.  
  989.         if (nMaxReqursion > 1)
  990.         {
  991.                 for (int p = 0; p < m_lstConnections.Count(); p++)
  992.                 {
  993.                         if ((m_lstConnections[p] != pPrevArea) && m_lstConnections[p]->IsActive())
  994.                         {
  995.                                 AABB vCurBox = vCurBoxIn;
  996.                                 float fCurDist = fCurDistIn;
  997.                                 float dist = FLT_MAX;
  998.  
  999.                                 if (IsPortal())
  1000.                                 {
  1001.                                         vCurBox = vCurBoxIn;
  1002.                                         fCurDist = fCurDistIn;
  1003.                                 }
  1004.                                 else
  1005.                                 {
  1006.                                         vCurBox = *m_lstConnections[p]->GetAABBox();
  1007.                                         fCurDist = fCurDistIn + DistanceAABB(vCurBox, vCurBoxIn);
  1008.                                 }
  1009.  
  1010.                                 if (m_lstConnections[p]->GetDistanceThruVisAreasReq(vCurBox, fCurDist, pTargetArea, targetBox, nMaxReqursion - 1, dist, this, nCallID))
  1011.                                 {
  1012.                                         bFound = true;
  1013.                                         fResDist = min(fResDist, dist);
  1014.                                 }
  1015.                         }
  1016.                 }
  1017.         }
  1018.  
  1019.         return bFound;
  1020. }
  1021.  
  1022. void CVisArea::OffsetPosition(const Vec3& delta)
  1023. {
  1024.         m_boxArea.Move(delta);
  1025.         m_boxStatics.Move(delta);
  1026.         for (int i = 0; i < m_lstShapePoints.Count(); i++)
  1027.         {
  1028.                 m_lstShapePoints[i] += delta;
  1029.         }
  1030.         if (m_pObjectsTree)
  1031.                 m_pObjectsTree->OffsetObjects(delta);
  1032. }
  1033.  
  1034. ///////////////////////////////////////////////////////////////////////////////
  1035. ///////////////////////////////////////////////////////////////////////////////
  1036. bool InsidePolygon(const Vec3* __restrict polygon, int N, const Vec3& p)
  1037. {
  1038.         int counter = 0;
  1039.         int i;
  1040.         float xinters;
  1041.         const Vec3* p1 = &polygon[0];
  1042.  
  1043.         for (i = 1; i <= N; i++)
  1044.         {
  1045.                 const Vec3* p2 = &polygon[i % N];
  1046.                 if (p.y > min(p1->y, p2->y))
  1047.                 {
  1048.                         if (p.y <= max(p1->y, p2->y))
  1049.                         {
  1050.                                 if (p.x <= max(p1->x, p2->x))
  1051.                                 {
  1052.                                         if (p1->y != p2->y)
  1053.                                         {
  1054.                                                 xinters = (p.y - p1->y) * (p2->x - p1->x) / (p2->y - p1->y) + p1->x;
  1055.                                                 if (p1->x == p2->x || p.x <= xinters)
  1056.                                                         counter++;
  1057.                                         }
  1058.                                 }
  1059.                         }
  1060.                 }
  1061.                 p1 = p2;
  1062.         }
  1063.  
  1064.         if (counter % 2 == 0)
  1065.                 return(false);
  1066.         else
  1067.                 return(true);
  1068. }
  1069.  
  1070. ///////////////////////////////////////////////////////////////////////////////
  1071. bool InsideSpherePolygon(Vec3* polygon, int N, Sphere& S)
  1072. {
  1073.         int i;
  1074.         Vec3 p1, p2;
  1075.  
  1076.         p1 = polygon[0];
  1077.         for (i = 1; i <= N; i++)
  1078.         {
  1079.                 p2 = polygon[i % N];
  1080.                 Vec3 vA(p1 - S.center);
  1081.                 Vec3 vD(p2 - p1);
  1082.                 vA.z = vD.z = 0;
  1083.                 vD.NormalizeSafe();
  1084.                 float fB = vD.Dot(vA);
  1085.                 float fC = vA.Dot(vA) - S.radius * S.radius;
  1086.                 if (fB * fB >= fC)     //at least 1 root
  1087.                         return(true);
  1088.                 p1 = p2;
  1089.         }
  1090.  
  1091.         return(false);
  1092. }
  1093.  
  1094. ///////////////////////////////////////////////////////////////////////////////
  1095. ///////////////////////////////////////////////////////////////////////////////
  1096. void CVisAreaManager::GetNearestCubeProbe(float& fMinDistance, int& nMaxPriority, CLightEntity*& pNearestLight, const AABB* pBBox)
  1097. {
  1098.         {
  1099.                 uint32 dwSize = m_lstVisAreas.Count();
  1100.  
  1101.                 for (uint32 dwI = 0; dwI < dwSize; ++dwI)
  1102.                         if (m_lstVisAreas[dwI]->m_pObjectsTree)
  1103.                                 if (!pBBox || Overlap::AABB_AABB(*m_lstVisAreas[dwI]->GetAABBox(), *pBBox))
  1104.                                         m_lstVisAreas[dwI]->m_pObjectsTree->GetNearestCubeProbe(fMinDistance, nMaxPriority, pNearestLight, pBBox);
  1105.         }
  1106.  
  1107.         {
  1108.                 uint32 dwSize = m_lstPortals.Count();
  1109.  
  1110.                 for (uint32 dwI = 0; dwI < dwSize; ++dwI)
  1111.                         if (m_lstPortals[dwI]->m_pObjectsTree)
  1112.                                 if (!pBBox || Overlap::AABB_AABB(*m_lstPortals[dwI]->GetAABBox(), *pBBox))
  1113.                                         m_lstPortals[dwI]->m_pObjectsTree->GetNearestCubeProbe(fMinDistance, nMaxPriority, pNearestLight, pBBox);
  1114.         }
  1115. }
  1116.  
  1117. ///////////////////////////////////////////////////////////////////////////////
  1118. void CVisAreaManager::GetObjectsByType(PodArray<IRenderNode*>& lstObjects, EERType objType, const AABB* pBBox, bool* pInstStreamReady, uint64 dwFlags)
  1119. {
  1120.         {
  1121.                 uint32 dwSize = m_lstVisAreas.Count();
  1122.  
  1123.                 for (uint32 dwI = 0; dwI < dwSize; ++dwI)
  1124.                         if (m_lstVisAreas[dwI]->m_pObjectsTree)
  1125.                                 if (!pBBox || Overlap::AABB_AABB(*m_lstVisAreas[dwI]->GetAABBox(), *pBBox))
  1126.                                         m_lstVisAreas[dwI]->m_pObjectsTree->GetObjectsByType(lstObjects, objType, pBBox, pInstStreamReady, dwFlags);
  1127.         }
  1128.  
  1129.         {
  1130.                 uint32 dwSize = m_lstPortals.Count();
  1131.  
  1132.                 for (uint32 dwI = 0; dwI < dwSize; ++dwI)
  1133.                         if (m_lstPortals[dwI]->m_pObjectsTree)
  1134.                                 if (!pBBox || Overlap::AABB_AABB(*m_lstPortals[dwI]->GetAABBox(), *pBBox))
  1135.                                         m_lstPortals[dwI]->m_pObjectsTree->GetObjectsByType(lstObjects, objType, pBBox, pInstStreamReady, dwFlags);
  1136.         }
  1137. }
  1138.  
  1139. ///////////////////////////////////////////////////////////////////////////////
  1140. int CVisAreaManager::GetObjectsCount(EOcTeeNodeListType eListType)
  1141. {
  1142.         int nCount = 0;
  1143.  
  1144.         {
  1145.                 uint32 dwSize = m_lstVisAreas.Count();
  1146.  
  1147.                 for (uint32 dwI = 0; dwI < dwSize; ++dwI)
  1148.                         if (m_lstVisAreas[dwI]->m_pObjectsTree)
  1149.                                 nCount += m_lstVisAreas[dwI]->m_pObjectsTree->GetObjectsCount(eListType);
  1150.         }
  1151.  
  1152.         {
  1153.                 uint32 dwSize = m_lstPortals.Count();
  1154.  
  1155.                 for (uint32 dwI = 0; dwI < dwSize; ++dwI)
  1156.                         if (m_lstPortals[dwI]->m_pObjectsTree)
  1157.                                 nCount += m_lstPortals[dwI]->m_pObjectsTree->GetObjectsCount(eListType);
  1158.         }
  1159.  
  1160.         return nCount;
  1161. }
  1162.  
  1163. ///////////////////////////////////////////////////////////////////////////////
  1164. void CVisAreaManager::GetStreamedInNodesNum(int& nAllStreamable, int& nReady)
  1165. {
  1166.         {
  1167.                 uint32 dwSize = m_lstVisAreas.Count();
  1168.  
  1169.                 for (uint32 dwI = 0; dwI < dwSize; ++dwI)
  1170.                         if (m_lstVisAreas[dwI]->m_pObjectsTree)
  1171.                                 m_lstVisAreas[dwI]->m_pObjectsTree->GetStreamedInNodesNum(nAllStreamable, nReady);
  1172.         }
  1173.  
  1174.         {
  1175.                 uint32 dwSize = m_lstPortals.Count();
  1176.  
  1177.                 for (uint32 dwI = 0; dwI < dwSize; ++dwI)
  1178.                         if (m_lstPortals[dwI]->m_pObjectsTree)
  1179.                                 m_lstPortals[dwI]->m_pObjectsTree->GetStreamedInNodesNum(nAllStreamable, nReady);
  1180.         }
  1181. }
  1182.  
  1183. ///////////////////////////////////////////////////////////////////////////////
  1184. bool CVisAreaManager::IsOccludedByOcclVolumes(const AABB& objBox, const SRenderingPassInfo& passInfo, bool bCheckOnlyIndoorVolumes)
  1185. {
  1186.         FUNCTION_PROFILER_3DENGINE;
  1187.  
  1188.         PodArray<CVisArea*>& rList = bCheckOnlyIndoorVolumes ? m_lstIndoorActiveOcclVolumes : m_lstActiveOcclVolumes;
  1189.  
  1190.         for (int i = 0; i < rList.Count(); i++)
  1191.         {
  1192.                 CCamera* pCamera = rList[i]->m_arrOcclCamera[passInfo.GetRecursiveLevel()];
  1193.                 bool bAllIn = 0;
  1194.                 if (pCamera)
  1195.                 {
  1196.                         // reduce code size by skipping many cache lookups in the camera functions as well as the camera constructor
  1197.                         CRY_ALIGN(128) char bufCamera[sizeof(CCamera)];
  1198.                         memcpy(bufCamera, pCamera, sizeof(CCamera));
  1199.                         if (alias_cast<CCamera*>(bufCamera)->IsAABBVisible_EH(objBox, &bAllIn))
  1200.                                 if (bAllIn)
  1201.                                         return true;
  1202.                 }
  1203.         }
  1204.  
  1205.         return false;
  1206. }
  1207.  
  1208. ///////////////////////////////////////////////////////////////////////////////
  1209. IVisArea* CVisAreaManager::GetVisAreaFromPos(const Vec3& vPos)
  1210. {
  1211.         FUNCTION_PROFILER_3DENGINE;
  1212.  
  1213.         if (!m_pAABBTree)
  1214.         {
  1215.                 UpdateAABBTree();
  1216.         }
  1217.  
  1218.         return m_pAABBTree->FindVisarea(vPos);
  1219. }
  1220.  
  1221. ///////////////////////////////////////////////////////////////////////////////
  1222. bool CVisArea::IsBoxOverlapVisArea(const AABB& objBox)
  1223. {
  1224.         if (!Overlap::AABB_AABB(objBox, m_boxArea))
  1225.                 return false;
  1226.  
  1227.         PodArray<Vec3>& polygonA = s_tmpPolygonA;
  1228.         polygonA.Clear();
  1229.         polygonA.Add(Vec3(objBox.min.x, objBox.min.y, objBox.min.z));
  1230.         polygonA.Add(Vec3(objBox.min.x, objBox.max.y, objBox.min.z));
  1231.         polygonA.Add(Vec3(objBox.max.x, objBox.max.y, objBox.min.z));
  1232.         polygonA.Add(Vec3(objBox.max.x, objBox.min.y, objBox.min.z));
  1233.         return Overlap::Polygon_Polygon2D<PodArray<Vec3>>(polygonA, m_lstShapePoints);
  1234. }
  1235.  
  1236. #define PORTAL_GEOM_BBOX_EXTENT 1.5f
  1237.  
  1238. ///////////////////////////////////////////////////////////////////////////////
  1239. void CVisArea::UpdateGeometryBBox()
  1240. {
  1241.         m_boxStatics.max = m_boxArea.max;
  1242.         m_boxStatics.min = m_boxArea.min;
  1243.  
  1244.         if (IsPortal())
  1245.         {
  1246.                 // fix for big objects passing portal
  1247.                 m_boxStatics.max += Vec3(PORTAL_GEOM_BBOX_EXTENT, PORTAL_GEOM_BBOX_EXTENT, PORTAL_GEOM_BBOX_EXTENT);
  1248.                 m_boxStatics.min -= Vec3(PORTAL_GEOM_BBOX_EXTENT, PORTAL_GEOM_BBOX_EXTENT, PORTAL_GEOM_BBOX_EXTENT);
  1249.         }
  1250.  
  1251.         if (m_pObjectsTree)
  1252.         {
  1253.                 PodArray<IRenderNode*> lstObjects;
  1254.                 m_pObjectsTree->GetObjectsByType(lstObjects, eERType_Brush, NULL);
  1255.  
  1256.                 for (int i = 0; i < lstObjects.Count(); i++)
  1257.                 {
  1258.                         AABB aabb;
  1259.                         lstObjects[i]->FillBBox(aabb);
  1260.                         m_boxStatics.Add(aabb);
  1261.                 }
  1262.         }
  1263. }
  1264.  
  1265. ///////////////////////////////////////////////////////////////////////////////
  1266. void CVisArea::UpdateClipVolume()
  1267. {
  1268.         if (m_lstShapePoints.Count() < 3)
  1269.                 return;
  1270.  
  1271.         const int nPoints = m_lstShapePoints.size();
  1272.         const int nVertexCount = nPoints * 2;
  1273.         const int nIndexCount = (2 * nPoints + 2 * (nPoints - 2)) * 3; // 2*nPoints for sides, nPoints-2 for top and nPoints-2 for bottom
  1274.  
  1275.         m_pClipVolumeMesh = NULL;
  1276.  
  1277.         if (nPoints < 3)
  1278.                 return;
  1279.         if (!gEnv->pRenderer)
  1280.                 return;
  1281.  
  1282.         std::vector<SVF_P3F_C4B_T2F> vertices;
  1283.         std::vector<vtx_idx> indices;
  1284.  
  1285.         vertices.resize(nVertexCount);
  1286.         indices.resize(nIndexCount);
  1287.  
  1288.         std::vector<Vec2> triangulationPoints;
  1289.         triangulationPoints.resize(nPoints + 1);
  1290.         MARK_UNUSED triangulationPoints[nPoints].x;
  1291.  
  1292.         for (int i = 0; i < nPoints; ++i)
  1293.         {
  1294.                 int nPointIdx = IsShapeClockwise() ? nPoints - 1 - i : i;
  1295.  
  1296.                 vertices[i].xyz = m_lstShapePoints[nPointIdx];
  1297.                 vertices[i].color.dcolor = 0xFFFFFFFF;
  1298.                 vertices[i].st = Vec2(ZERO);
  1299.  
  1300.                 vertices[i + nPoints].xyz = m_lstShapePoints[nPointIdx] + Vec3(0, 0, m_fHeight);
  1301.                 vertices[i + nPoints].color.dcolor = 0xFFFFFFFF;
  1302.                 vertices[i + nPoints].st = Vec2(ZERO);
  1303.  
  1304.                 triangulationPoints[i] = Vec2(m_lstShapePoints[nPointIdx]);
  1305.         }
  1306.  
  1307.         // triangulate shape first
  1308.         std::vector<int> triangleIndices;
  1309.         triangleIndices.resize((nPoints - 2) * 3);
  1310.         MARK_UNUSED triangleIndices[triangleIndices.size() - 1];
  1311.  
  1312.         int nTris = gEnv->pPhysicalWorld->GetPhysUtils()->TriangulatePoly(&triangulationPoints[0], triangulationPoints.size(), &triangleIndices[0], triangleIndices.size());
  1313.  
  1314.         if (nTris == nPoints - 2) // triangulation success?
  1315.         {
  1316.                 // top and bottom faces
  1317.                 size_t nCurIndex = 0;
  1318.                 for (; nCurIndex < triangleIndices.size(); nCurIndex += 3)
  1319.                 {
  1320.                         indices[nCurIndex + 2] = triangleIndices[nCurIndex + 0];
  1321.                         indices[nCurIndex + 1] = triangleIndices[nCurIndex + 1];
  1322.                         indices[nCurIndex + 0] = triangleIndices[nCurIndex + 2];
  1323.  
  1324.                         indices[triangleIndices.size() + nCurIndex + 0] = triangleIndices[nCurIndex + 0] + nPoints;
  1325.                         indices[triangleIndices.size() + nCurIndex + 1] = triangleIndices[nCurIndex + 1] + nPoints;
  1326.                         indices[triangleIndices.size() + nCurIndex + 2] = triangleIndices[nCurIndex + 2] + nPoints;
  1327.                 }
  1328.  
  1329.                 nCurIndex = 2 * triangleIndices.size();
  1330.  
  1331.                 // side faces
  1332.                 for (int i = 0; i < nPoints; i++)
  1333.                 {
  1334.                         vtx_idx bl = i;
  1335.                         vtx_idx br = (i + 1) % nPoints;
  1336.  
  1337.                         indices[nCurIndex++] = bl;
  1338.                         indices[nCurIndex++] = br + nPoints;
  1339.                         indices[nCurIndex++] = bl + nPoints;
  1340.  
  1341.                         indices[nCurIndex++] = bl;
  1342.                         indices[nCurIndex++] = br;
  1343.                         indices[nCurIndex++] = br + nPoints;
  1344.                 }
  1345.  
  1346.                 m_pClipVolumeMesh = gEnv->pRenderer->CreateRenderMeshInitialized(&vertices[0], vertices.size(),
  1347.                         eVF_P3F_C4B_T2F, &indices[0], indices.size(), prtTriangleList,
  1348.                         "ClipVolume", GetName(), eRMT_Dynamic);
  1349.         }
  1350. }
  1351.  
  1352. void CVisArea::GetClipVolumeMesh(_smart_ptr<IRenderMesh>& renderMesh, Matrix34& worldTM) const
  1353. {
  1354.         renderMesh = m_pClipVolumeMesh;
  1355.         worldTM = Matrix34(IDENTITY);
  1356. }
  1357.  
  1358. uint CVisArea::GetClipVolumeFlags() const
  1359. {
  1360.         int nFlags = IClipVolume::eClipVolumeIsVisArea;
  1361.         nFlags |= IsConnectedToOutdoor() ? IClipVolume::eClipVolumeConnectedToOutdoor : 0;
  1362.         nFlags |= IsAffectedByOutLights() ? IClipVolume::eClipVolumeAffectedBySun : 0;
  1363.         nFlags |= IsIgnoringGI() ? IClipVolume::eClipVolumeIgnoreGI : 0;
  1364.         nFlags |= IsIgnoringOutdoorAO() ? IClipVolume::eClipVolumeIgnoreOutdoorAO : 0;
  1365.  
  1366.         return nFlags;
  1367. }
  1368.  
  1369. ///////////////////////////////////////////////////////////////////////////////
  1370. void CVisArea::UpdatePortalBlendInfo(const SRenderingPassInfo& passInfo)
  1371. {
  1372.         if (m_bThisIsPortal && m_lstConnections.Count() > 0 && m_nStencilRef>0 && GetCVars()->e_PortalsBlend > 0 && m_fPortalBlending > 0)
  1373.         {
  1374.                 IClipVolume* blendVolumes[SDeferredClipVolume::MaxBlendInfoCount];
  1375.                 Plane blendPlanes[SDeferredClipVolume::MaxBlendInfoCount];
  1376.  
  1377.                 Vec3 vPlanePoints[2][3];
  1378.                 uint nPointCount[2] = { 0, 0 };
  1379.  
  1380.                 for (int p = 0; p < m_lstShapePoints.Count(); ++p)
  1381.                 {
  1382.                         Vec3 vTestPoint = m_lstShapePoints[p] + Vec3(0, 0, m_fHeight * 0.5f);
  1383.                         int nVisAreaIndex = (m_lstConnections[0] && m_lstConnections[0]->IsPointInsideVisArea(vTestPoint)) ? 0 : 1;
  1384.  
  1385.                         if (nPointCount[nVisAreaIndex] < 2)
  1386.                         {
  1387.                                 vPlanePoints[nVisAreaIndex][nPointCount[nVisAreaIndex]] = m_lstShapePoints[p];
  1388.                                 nPointCount[nVisAreaIndex]++;
  1389.                         }
  1390.                 }
  1391.  
  1392.                 for (int i = 0; i < 2; ++i)
  1393.                 {
  1394.                         if (nPointCount[i] == 2)
  1395.                         {
  1396.                                 if (IsShapeClockwise())
  1397.                                         std::swap(vPlanePoints[i][0], vPlanePoints[i][1]);
  1398.  
  1399.                                 blendPlanes[i] = Plane::CreatePlane(vPlanePoints[i][0], vPlanePoints[i][0] + Vec3(0, 0, m_fHeight), vPlanePoints[i][1]);
  1400.                                 blendVolumes[i] = i < m_lstConnections.Count() ? m_lstConnections[i] : NULL;
  1401.  
  1402.                                 // make sure plane normal points inside portal
  1403.                                 if (nPointCount[(i + 1) % 2] > 0)
  1404.                                 {
  1405.                                         Vec3 c(ZERO);
  1406.                                         for (uint j = 0; j < nPointCount[(i + 1) % 2]; ++j)
  1407.                                                 c += vPlanePoints[(i + 1) % 2][j];
  1408.                                         c /= (float)nPointCount[(i + 1) % 2];
  1409.  
  1410.                                         if (blendPlanes[i].DistFromPlane(c) < 0)
  1411.                                         {
  1412.                                                 blendPlanes[i].n = -blendPlanes[i].n;
  1413.                                                 blendPlanes[i].d = -blendPlanes[i].d;
  1414.                                         }
  1415.                                 }
  1416.                         }
  1417.                         else
  1418.                         {
  1419.                                 blendPlanes[i] = Plane(Vec3(ZERO), 0);
  1420.                                 blendVolumes[i] = NULL;
  1421.                         }
  1422.                 }
  1423.  
  1424.                 // weight planes by user specified importance. works because we renormalize in the shader
  1425.                 float planeWeight = clamp_tpl(m_fPortalBlending, 1e-5f, 1.f - 1e-5f);
  1426.  
  1427.                 blendPlanes[0].n *= planeWeight;
  1428.                 blendPlanes[0].d *= planeWeight;
  1429.                 blendPlanes[1].n *= 1 - planeWeight;
  1430.                 blendPlanes[1].d *= 1 - planeWeight;
  1431.  
  1432.                 passInfo.GetIRenderView()->SetClipVolumeBlendInfo(this, SDeferredClipVolume::MaxBlendInfoCount, blendVolumes, blendPlanes);
  1433.         }
  1434. }
  1435.  
  1436. ///////////////////////////////////////////////////////////////////////////////
  1437. bool CVisAreaManager::SetEntityArea(IRenderNode* pEnt, const AABB& objBox, const float fObjRadiusSqr)
  1438. {
  1439.         assert(pEnt);
  1440.  
  1441.         Vec3 vEntCenter = Get3DEngine()->GetEntityRegisterPoint(pEnt);
  1442.  
  1443.         // find portal containing object center
  1444.         CVisArea* pVisArea = NULL;
  1445.  
  1446.         const int kNumPortals = m_lstPortals.Count();
  1447.         for (int v = 0; v < kNumPortals; v++)
  1448.         {
  1449.                 CVisArea* pCurrentPortal = m_lstPortals[v];
  1450.                 PrefetchLine(pCurrentPortal, 256);
  1451.                 PrefetchLine(pCurrentPortal, 384);
  1452.                 if (pCurrentPortal->IsPointInsideVisArea(vEntCenter))
  1453.                 {
  1454.                         pVisArea = pCurrentPortal;
  1455.                         if (!pVisArea->m_pObjectsTree)
  1456.                         {
  1457.                                 pVisArea->m_pObjectsTree = COctreeNode::Create(DEFAULT_SID, pVisArea->m_boxArea, pVisArea);
  1458.                         }
  1459.                         pVisArea->m_pObjectsTree->InsertObject(pEnt, objBox, fObjRadiusSqr, vEntCenter);
  1460.                         break;
  1461.                 }
  1462.         }
  1463.  
  1464.         if (!pVisArea && pEnt->m_dwRndFlags & ERF_REGISTER_BY_BBOX)
  1465.         {
  1466.                 AABB aabb;
  1467.                 pEnt->FillBBox(aabb);
  1468.  
  1469.                 for (int v = 0; v < kNumPortals; v++)
  1470.                 {
  1471.                         CVisArea* pCurrentPortal = m_lstPortals[v];
  1472.                         PrefetchLine(pCurrentPortal, 256);
  1473.                         PrefetchLine(pCurrentPortal, 384);
  1474.                         if (pCurrentPortal->IsBoxOverlapVisArea(aabb))
  1475.                         {
  1476.                                 pVisArea = pCurrentPortal;
  1477.                                 if (!pVisArea->m_pObjectsTree)
  1478.                                 {
  1479.                                         pVisArea->m_pObjectsTree = COctreeNode::Create(DEFAULT_SID, pVisArea->m_boxArea, pVisArea);
  1480.                                 }
  1481.  
  1482.                                 pVisArea->m_pObjectsTree->InsertObject(pEnt, objBox, fObjRadiusSqr, vEntCenter);
  1483.                                 break;
  1484.                         }
  1485.                 }
  1486.         }
  1487.  
  1488.         if (!pVisArea) // if portal not found - find volume
  1489.         {
  1490.                 const int kNumVisAreas = m_lstVisAreas.Count();
  1491.                 for (int v = 0; v < kNumVisAreas; v++)
  1492.                 {
  1493.                         CVisArea* pCurrentVisArea = m_lstVisAreas[v];
  1494.                         PrefetchLine(pCurrentVisArea, 256);
  1495.                         PrefetchLine(pCurrentVisArea, 384);
  1496.                         if (pCurrentVisArea->IsPointInsideVisArea(vEntCenter))
  1497.                         {
  1498.                                 pVisArea = pCurrentVisArea;
  1499.                                 if (!pVisArea->m_pObjectsTree)
  1500.                                 {
  1501.                                         pVisArea->m_pObjectsTree = COctreeNode::Create(DEFAULT_SID, pVisArea->m_boxArea, pVisArea);
  1502.                                 }
  1503.                                 pVisArea->m_pObjectsTree->InsertObject(pEnt, objBox, fObjRadiusSqr, vEntCenter);
  1504.                                 break;
  1505.                         }
  1506.                 }
  1507.         }
  1508.  
  1509.         if (pVisArea && pEnt->GetRenderNodeType() == eERType_Brush) // update bbox of exit portal //                    if((*pVisArea)->m_lstConnections.Count()==1)
  1510.                 if (pVisArea->IsPortal())
  1511.                         pVisArea->UpdateGeometryBBox();
  1512.  
  1513.         return pVisArea != 0;
  1514. }
  1515.  
  1516. ///////////////////////////////////////////////////////////////////////////////
  1517. CVisArea* SAABBTreeNode::FindVisarea(const Vec3& vPos)
  1518. {
  1519.         if (nodeBox.IsContainPoint(vPos))
  1520.         {
  1521.                 if (nodeAreas.Count())
  1522.                 {
  1523.                         // leaf
  1524.                         for (int i = 0; i < nodeAreas.Count(); i++)
  1525.                                 if (nodeAreas[i]->m_bActive && nodeAreas[i]->IsPointInsideVisArea(vPos))
  1526.                                         return nodeAreas[i];
  1527.                 }
  1528.                 else
  1529.                 {
  1530.                         // node
  1531.                         for (int i = 0; i < 2; i++)
  1532.                                 if (arrChilds[i])
  1533.                                         if (CVisArea* pArea = arrChilds[i]->FindVisarea(vPos))
  1534.                                                 return pArea;
  1535.                 }
  1536.         }
  1537.  
  1538.         return NULL;
  1539. }
  1540.  
  1541. ///////////////////////////////////////////////////////////////////////////////
  1542. ///////////////////////////////////////////////////////////////////////////////
  1543. // Current scheme: Will never move sphere center, just clip radius, even to 0.
  1544. bool CVisArea::ClipToVisArea(bool bInside, Sphere& sphere, Vec3 const& vNormal)
  1545. {
  1546.         FUNCTION_PROFILER_3DENGINE;
  1547.  
  1548.         /*
  1549.         Clip            PointZ  PointXY
  1550.  
  1551.         In                      In                      In                                      inside, clip Z and XY
  1552.         In                      In                      Out                                     outside, return 0
  1553.         In                      Out                     In                                      outside, return 0
  1554.         In                      Out                     Out                                     outside, return 0
  1555.  
  1556.         Out                     In                      In                                      inside, return 0
  1557.         Out                     In                      Out                                     outside, clip XY
  1558.         Out                     Out                     In                                      outside, clip Z
  1559.         Out                     Out                     Out                                     outside, clip XY
  1560.         */
  1561.  
  1562.         bool bClipXY = false, bClipZ = false;
  1563.         if (bInside)
  1564.         {
  1565.                 // Clip to 0 if center outside.
  1566.                 if (!IsPointInsideVisArea(sphere.center))
  1567.                 {
  1568.                         sphere.radius = 0.f;
  1569.                         return true;
  1570.                 }
  1571.                 bClipXY = bClipZ = true;
  1572.         }
  1573.         else
  1574.         {
  1575.                 if (Overlap::Point_AABB(sphere.center, m_boxArea))
  1576.                 {
  1577.                         if (InsidePolygon(m_lstShapePoints.begin(), m_lstShapePoints.size(), sphere.center))
  1578.                         {
  1579.                                 sphere.radius = 0.f;
  1580.                                 return true;
  1581.                         }
  1582.                         else
  1583.                                 bClipXY = true;
  1584.                 }
  1585.                 else if (InsidePolygon(m_lstShapePoints.begin(), m_lstShapePoints.size(), sphere.center))
  1586.                         bClipZ = true;
  1587.                 else
  1588.                         bClipXY = true;
  1589.         }
  1590.  
  1591.         float fOrigRadius = sphere.radius;
  1592.         if (bClipZ)
  1593.         {
  1594.                 // Check against vertical planes.
  1595.                 float fDist = min(abs(m_boxArea.max.z - sphere.center.z), abs(sphere.center.z - m_boxArea.min.z));
  1596.                 float fRadiusScale = sqrt_tpl(max(1.f - sqr(vNormal.z), 0.f));
  1597.                 if (fDist < sphere.radius * fRadiusScale)
  1598.                 {
  1599.                         sphere.radius = fDist / fRadiusScale;
  1600.                         if (sphere.radius <= 0.f)
  1601.                                 return true;
  1602.                 }
  1603.         }
  1604.  
  1605.         if (bClipXY)
  1606.         {
  1607.                 Vec3 vP1 = m_lstShapePoints[0];
  1608.                 vP1.z = clamp_tpl(sphere.center.z, m_boxArea.min.z, m_boxArea.max.z);
  1609.                 for (int n = m_lstShapePoints.Count() - 1; n >= 0; n--)
  1610.                 {
  1611.                         Vec3 vP0 = m_lstShapePoints[n];
  1612.                         vP0.z = vP1.z;
  1613.  
  1614.                         // Compute nearest vector from center to plane.
  1615.                         Vec3 vP = vP0 - sphere.center;
  1616.                         Vec3 vD = vP1 - vP0;
  1617.                         float fN = -(vP * vD);
  1618.                         if (fN > 0.f)
  1619.                         {
  1620.                                 float fD = vD.GetLengthSquared();
  1621.                                 if (fN >= fD)
  1622.                                         vP += vD;
  1623.                                 else
  1624.                                         vP += vD * (fN / fD);
  1625.                         }
  1626.  
  1627.                         // Check distance only in planar direction.
  1628.                         float fDist = vP.GetLength() * 0.99f;
  1629.                         float fRadiusScale = fDist > 0.f ? sqrt_tpl(max(1.f - sqr(vNormal * vP) / sqr(fDist), 0.f)) : 1.f;
  1630.                         if (fDist < sphere.radius * fRadiusScale)
  1631.                         {
  1632.                                 sphere.radius = fDist / fRadiusScale;
  1633.                                 if (sphere.radius <= 0.f)
  1634.                                         return true;
  1635.                         }
  1636.  
  1637.                         vP1 = vP0;
  1638.                 }
  1639.         }
  1640.  
  1641.         return sphere.radius < fOrigRadius;
  1642. }
  1643.  
  1644. ///////////////////////////////////////////////////////////////////////////////
  1645. bool CVisArea::IsPointInsideVisArea(const Vec3& vPos) const
  1646. {
  1647.         const int kNumPoints = m_lstShapePoints.Count();
  1648.         if (kNumPoints)
  1649.         {
  1650.                 Vec3* pLstShapePoints = &m_lstShapePoints[0];
  1651.                 PrefetchLine(pLstShapePoints, 0);
  1652.                 if (Overlap::Point_AABB(vPos, m_boxArea))
  1653.                 {
  1654.                         if (InsidePolygon(pLstShapePoints, kNumPoints, vPos))
  1655.                                 return true;
  1656.                 }
  1657.         }
  1658.  
  1659.         return false;
  1660. }
  1661.  
  1662. ///////////////////////////////////////////////////////////////////////////////
  1663. bool CVisArea::IsSphereInsideVisArea(const Vec3& vPos, const f32 fRadius)
  1664. {
  1665.         Sphere S(vPos, fRadius);
  1666.         if (Overlap::Sphere_AABB(S, m_boxArea))
  1667.                 if (InsidePolygon(&m_lstShapePoints[0], m_lstShapePoints.Count(), vPos) || InsideSpherePolygon(&m_lstShapePoints[0], m_lstShapePoints.Count(), S))
  1668.                         return true;
  1669.  
  1670.         return false;
  1671. }
  1672.  
  1673. ///////////////////////////////////////////////////////////////////////////////
  1674. const AABB* CVisArea::GetAABBox() const
  1675. {
  1676.         return &m_boxArea;
  1677. }
  1678.  
  1679. ///////////////////////////////////////////////////////////////////////////////
  1680. const Vec3 CVisArea::GetFinalAmbientColor()
  1681. {
  1682.         float fHDRMultiplier = ((CTimeOfDay*)Get3DEngine()->GetTimeOfDay())->GetHDRMultiplier();
  1683.  
  1684.         Vec3 vAmbColor;
  1685.         if (IsAffectedByOutLights() && !m_bIgnoreSky)
  1686.         {
  1687.                 vAmbColor.x = Get3DEngine()->GetSkyColor().x * m_vAmbientColor.x;
  1688.                 vAmbColor.y = Get3DEngine()->GetSkyColor().y * m_vAmbientColor.y;
  1689.                 vAmbColor.z = Get3DEngine()->GetSkyColor().z * m_vAmbientColor.z;
  1690.         }
  1691.         else
  1692.                 vAmbColor = m_vAmbientColor * fHDRMultiplier;
  1693.  
  1694.         if (GetCVars()->e_Portals == 4)
  1695.                 vAmbColor = Vec3(fHDRMultiplier, fHDRMultiplier, fHDRMultiplier);
  1696.  
  1697.         return vAmbColor;
  1698. }
  1699.  
  1700. ///////////////////////////////////////////////////////////////////////////////
  1701. bool CVisArea::IsPortal() const
  1702. {
  1703.         return m_bThisIsPortal;
  1704. }
  1705.  
  1706. float CVisArea::CalcSignedArea()
  1707. {
  1708.         float fArea = 0;
  1709.         for (int i = 0; i < m_lstShapePoints.Count(); i++)
  1710.         {
  1711.                 const Vec3& v0 = m_lstShapePoints[i];
  1712.                 const Vec3& v1 = m_lstShapePoints[(i + 1) % m_lstShapePoints.Count()];
  1713.                 fArea += v0.x * v1.y - v1.x * v0.y;
  1714.         }
  1715.         return fArea / 2;
  1716. }
  1717.  
  1718. void CVisArea::GetShapePoints(const Vec3*& pPoints, size_t& nPoints)
  1719. {
  1720.         if (m_lstShapePoints.empty())
  1721.         {
  1722.                 pPoints = 0;
  1723.                 nPoints = 0;
  1724.         }
  1725.         else
  1726.         {
  1727.                 pPoints = &m_lstShapePoints[0];
  1728.                 nPoints = m_lstShapePoints.size();
  1729.         }
  1730. }
  1731.  
  1732. float CVisArea::GetHeight()
  1733. {
  1734.         return m_fHeight;
  1735. }
  1736.  
  1737. ///////////////////////////////////////////////////////////////////////////////
  1738. bool CVisArea::FindVisArea(IVisArea* pAnotherArea, int nMaxRecursion, bool bSkipDisabledPortals)
  1739. {
  1740.         // collect visited areas in order to prevent visiting it again
  1741.         StaticDynArray<CVisArea*, 1024> lVisitedParents;
  1742.  
  1743.         return FindVisAreaReqursive(pAnotherArea, nMaxRecursion, bSkipDisabledPortals, lVisitedParents);
  1744. }
  1745.  
  1746. ///////////////////////////////////////////////////////////////////////////////
  1747. bool CVisArea::FindVisAreaReqursive(IVisArea* pAnotherArea, int nMaxReqursion, bool bSkipDisabledPortals, StaticDynArray<CVisArea*, 1024>& arrVisitedParents)
  1748. {
  1749.         arrVisitedParents.push_back(this);
  1750.  
  1751.         if (pAnotherArea == this)
  1752.                 return true;
  1753.  
  1754.         if (pAnotherArea == NULL && IsConnectedToOutdoor())
  1755.                 return true;
  1756.  
  1757.         bool bFound = false;
  1758.  
  1759.         if (nMaxReqursion > 1)
  1760.         {
  1761.                 for (int p = 0; p < m_lstConnections.Count(); p++)
  1762.                 {
  1763.                         if (!bSkipDisabledPortals || m_lstConnections[p]->IsActive())
  1764.                         {
  1765.                                 if (std::find(arrVisitedParents.begin(), arrVisitedParents.end(), m_lstConnections[p]) == arrVisitedParents.end())
  1766.                                 {
  1767.                                         if (m_lstConnections[p]->FindVisAreaReqursive(pAnotherArea, nMaxReqursion - 1, bSkipDisabledPortals, arrVisitedParents))
  1768.                                         {
  1769.                                                 bFound = true;
  1770.                                                 break;
  1771.                                         }
  1772.                                 }
  1773.                         }
  1774.                 }
  1775.         }
  1776.  
  1777.         return bFound;
  1778. }
  1779.  
  1780. ///////////////////////////////////////////////////////////////////////////////
  1781. bool CVisArea::IsConnectedToOutdoor() const
  1782. {
  1783.         if (IsPortal()) // check if this portal has just one conection
  1784.                 return m_lstConnections.Count() == 1;
  1785.  
  1786.         // find portals with just one conection
  1787.         for (int p = 0; p < m_lstConnections.Count(); p++)
  1788.         {
  1789.                 CVisArea* pPortal = m_lstConnections[p];
  1790.                 if (pPortal->m_lstConnections.Count() == 1)
  1791.                         return true;
  1792.         }
  1793.  
  1794.         return false;
  1795. }
  1796.  
  1797. ///////////////////////////////////////////////////////////////////////////////
  1798. ///////////////////////////////////////////////////////////////////////////////
  1799.  
downloadVisAreas.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top