BVB Source Codes

CRYENGINE Show ObjectsTree.cpp Source code

Return Download CRYENGINE: download ObjectsTree.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "ObjectsTree.h"
  5. #include "PolygonClipContext.h"
  6. #include "RoadRenderNode.h"
  7. #include "Brush.h"
  8. #include "DecalRenderNode.h"
  9. #include "RenderMeshMerger.h"
  10. #include "DecalManager.h"
  11. #include "VisAreas.h"
  12. #include <CryAnimation/ICryAnimation.h>
  13. #include "LightEntity.h"
  14. #include "WaterVolumeRenderNode.h"
  15. #include "DistanceCloudRenderNode.h"
  16. #include "MergedMeshRenderNode.h"
  17. #include "MergedMeshGeometry.h"
  18. #include "ShadowCache.h"
  19. #include <CryThreading/IJobManager_JobDelegator.h>
  20.  
  21. const float COctreeNode::fMinShadowCasterViewDist = 8.f;
  22. PodArray<COctreeNode*> COctreeNode::m_arrEmptyNodes;
  23. PodArray<COctreeNode*> COctreeNode::m_arrStreamedInNodes;
  24. int COctreeNode::m_nInstStreamTasksInProgress = 0;
  25. FILE* COctreeNode::m_pFileForSyncRead = 0;
  26. int COctreeNode::m_nNodesCounterAll = 0;
  27. int COctreeNode::m_nNodesCounterStreamable = 0;
  28. int COctreeNode::m_nInstCounterLoaded = 0;
  29. void* COctreeNode::m_pRenderContentJobQueue = NULL;
  30.  
  31. DECLARE_JOB("OctreeNodeRender", TRenderContentJob, COctreeNode::RenderContentJobEntry);
  32. typedef PROD_CONS_QUEUE_TYPE(TRenderContentJob, 1024) TRenderContentJobQueue;
  33.  
  34. #define CHECK_OBJECTS_BOX_WARNING_SIZE (1.0e+10f)
  35.  
  36. COctreeNode::~COctreeNode()
  37. {
  38.         m_nNodesCounterAll--;
  39.  
  40.         ReleaseObjects();
  41.  
  42.         for (int i = 0; i < 8; i++)
  43.         {
  44.                 delete m_arrChilds[i];
  45.                 m_arrChilds[i] = NULL;
  46.         }
  47.  
  48.         m_arrEmptyNodes.Delete(this);
  49.  
  50.         m_arrStreamedInNodes.Delete(this);
  51.  
  52.         GetObjManager()->m_arrStreamingNodeStack.Delete(this);
  53.  
  54.         if (m_pReadStream)
  55.                 m_pReadStream->Abort();
  56.  
  57.         ResetStaticInstancing();
  58. }
  59.  
  60. void COctreeNode::SetVisArea(CVisArea* pVisArea)
  61. {
  62.         m_pVisArea = pVisArea;
  63.         for (int i = 0; i < 8; i++)
  64.         {
  65.                 if (m_arrChilds[i])
  66.                         m_arrChilds[i]->SetVisArea(pVisArea);
  67.         }
  68. }
  69.  
  70. extern float arrVegetation_fSpriteSwitchState[nThreadsNum];
  71.  
  72. void COctreeNode::CheckManageVegetationSprites(float fNodeDistance, int nMaxFrames, const SRenderingPassInfo& passInfo)
  73. {
  74.         const uint32 iMainFrameId = passInfo.GetMainFrameID();
  75.         if ((uint32)m_nManageVegetationsFrameId >= iMainFrameId - nMaxFrames && !passInfo.IsZoomInProgress())
  76.                 return;
  77.  
  78.         C3DEngine* p3DEngine = Get3DEngine();
  79.  
  80.         m_fNodeDistance = fNodeDistance;
  81.         m_nManageVegetationsFrameId = iMainFrameId;
  82.  
  83.         FUNCTION_PROFILER_3DENGINE;
  84.  
  85.         Vec3 sunDirReady((m_fpSunDirX - 63.5f) / 63.5f, 0.0f, (m_fpSunDirZ - 63.5f) / 63.5f);
  86.         sunDirReady.y = sqrt(clamp_tpl(1.0f - sunDirReady.x * sunDirReady.x - sunDirReady.z * sunDirReady.z, 0.0f, 1.0f));
  87.         if (m_fpSunDirYs)
  88.                 sunDirReady.y *= -1.0f;
  89.  
  90.         if (sunDirReady.Dot(p3DEngine->GetSunDirNormalized()) < 0.99f)
  91.                 SetCompiled(false);
  92.  
  93.         const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
  94.         AABB objBox;
  95.  
  96.         SSectorTextureSet* pTerrainTexInfo = NULL;
  97.         if (GetCVars()->e_VegetationUseTerrainColor)
  98.                 GetObjManager()->FillTerrainTexInfo(this, m_fNodeDistance, pTerrainTexInfo, m_objectsBox);
  99.         /*
  100.            Vec3 vD = GetBBox().GetCenter() - vCamPos;
  101.            Vec3 vCenter = GetBBox().GetCenter();
  102.            Vec3 vD1 = vCenter + vD;
  103.            m_dwSpritesAngle = ((uint32)(atan2_tpl(vD1.x, vD1.y)*(255.0f/(2*g_PI)))) & 0xff;
  104.          */
  105.  
  106.         // check if we need to add some objects to sprites array
  107.         for (CVegetation* pObj = (CVegetation*)m_arrObjects[eRNListType_Vegetation].m_pFirstNode, * pNext; pObj; pObj = pNext)
  108.         {
  109.                 pNext = (CVegetation*)pObj->m_pNext;
  110.  
  111.                 if (pObj->m_pNext)
  112.                         cryPrefetchT0SSE(pObj->m_pNext);
  113.  
  114.                 pObj->FillBBox_NonVirtual(objBox);
  115.  
  116.                 const float fEntDistanceSqr = Distance::Point_AABBSq(vCamPos, objBox) * passInfo.GetZoomFactor() * passInfo.GetZoomFactor();
  117.  
  118.                 float fEntDistance2D = sqrt_tpl(vCamPos.GetSquaredDistance2D(pObj->m_vPos)) * passInfo.GetZoomFactor();
  119.  
  120.                 StatInstGroup& vegetGroup = pObj->GetStatObjGroup();
  121.  
  122.                 const float fSpriteSwitchDist = pObj->GetSpriteSwitchDist();
  123.                 float fSwitchRange = min(fSpriteSwitchDist * GetCVars()->e_LodTransitionSpriteDistRatio, GetCVars()->e_LodTransitionSpriteMinDist);
  124.                 float fLodTransitionDistband = 1.f;
  125.  
  126.                 if (pObj->m_pSpriteInfo)
  127.                 {
  128.                         CStatObj* pStatObj = vegetGroup.GetStatObj();
  129.  
  130.                         if (fEntDistance2D < (fSpriteSwitchDist - fSwitchRange) && pObj && pObj->m_pTempData)
  131.                         {
  132.                                 int nLodA;
  133.  
  134.                                 nLodA = CLAMP(pObj->m_pTempData->userData.nWantedLod, (uint32)pStatObj->GetMinUsableLod(), (uint32)pStatObj->m_nMaxUsableLod);
  135.                                 nLodA = pStatObj->FindNearesLoadedLOD(nLodA);
  136.  
  137.                                 // TODO: start dissolve transition to 3d lod
  138.                         }
  139.  
  140.                         if (pObj->m_pTempData)
  141.                         {
  142.                                 // TODO: update dissolve transition to 3d lod, detect finish oif transition
  143.                         }
  144.  
  145.                         if (fEntDistanceSqr > sqr(pObj->m_fWSMaxViewDist * 1.1f))
  146.                         {
  147.                                 SAFE_DELETE(pObj->m_pSpriteInfo);
  148.  
  149.                                 UnlinkObject(pObj);
  150.                                 LinkObject(pObj, eERType_Vegetation); //We know that only eERType_Vegetation can get into the vegetation list, see GetRenderNodeListId()
  151.  
  152.                                 SetCompiled(false);
  153.  
  154.                                 continue;
  155.                         }
  156.  
  157.                         float dist3D = fSpriteSwitchDist - fSwitchRange + fLodTransitionDistband;
  158.  
  159.                         pObj->UpdateSpriteInfo(*pObj->m_pSpriteInfo, 0, pTerrainTexInfo, passInfo);
  160.                         pObj->m_pSpriteInfo->ucShow3DModel = (fEntDistance2D < dist3D);
  161.                 }
  162.                 else if (!pObj->m_pInstancingInfo)
  163.                 {
  164.                         if (fEntDistance2D > (fSpriteSwitchDist - fSwitchRange) && fEntDistance2D + fLodTransitionDistband < pObj->m_fWSMaxViewDist)
  165.                         {
  166.                                 UnlinkObject(pObj);
  167.                                 LinkObject(pObj, eERType_Vegetation, false); //We know that only eERType_Vegetation can get into the vegetation list, see GetRenderNodeListId()
  168.  
  169.                                 assert(pObj->m_pSpriteInfo == NULL);
  170.                                 pObj->m_pSpriteInfo = new SVegetationSpriteInfo;
  171.                                 SVegetationSpriteInfo& si = *pObj->m_pSpriteInfo;
  172.  
  173.                                 if (pObj->m_pTempData)
  174.                                 {
  175.                                         // TODO: start lod transition into sprite
  176.                                 }
  177.  
  178.                                 pObj->UpdateSpriteInfo(si, 0.0f, pTerrainTexInfo, passInfo);
  179.                                 pObj->m_pSpriteInfo->ucShow3DModel = (fEntDistance2D < fSpriteSwitchDist);
  180.  
  181.                                 SetCompiled(false);
  182.                         }
  183.                 }
  184.         }
  185. }
  186.  
  187. void COctreeNode::Render_Object_Nodes(bool bNodeCompletelyInFrustum, int nRenderMask, const Vec3& vAmbColor, const SRenderingPassInfo& passInfo)
  188. {
  189.         assert(nRenderMask & OCTREENODE_RENDER_FLAG_OBJECTS);
  190.  
  191.         const CCamera& rCam = passInfo.GetCamera();
  192.  
  193.         if (m_nOccludedFrameId == passInfo.GetFrameID())
  194.                 return;
  195.  
  196.         if (!bNodeCompletelyInFrustum && !rCam.IsAABBVisible_EH(m_objectsBox, &bNodeCompletelyInFrustum))
  197.                 return;
  198.  
  199.         const Vec3& vCamPos = rCam.GetPosition();
  200.  
  201.         float fNodeDistanceSq = Distance::Point_AABBSq(vCamPos, m_objectsBox) * sqr(passInfo.GetZoomFactor());
  202.  
  203.         if (fNodeDistanceSq > sqr(m_fObjectsMaxViewDist))
  204.                 return;
  205.  
  206.         float fNodeDistance = sqrt_tpl(fNodeDistanceSq);
  207.  
  208.         if (m_nLastVisFrameId != passInfo.GetFrameID() && m_pParent)
  209.         {
  210.                 if (GetObjManager()->IsBoxOccluded(m_objectsBox, fNodeDistance, &m_occlusionTestClient, m_pVisArea != NULL, eoot_OCCELL, passInfo))
  211.                 {
  212.                         m_nOccludedFrameId = passInfo.GetFrameID();
  213.                         return;
  214.                 }
  215.         }
  216.  
  217.         m_nLastVisFrameId = passInfo.GetFrameID();
  218.  
  219.         if (!IsCompiled())
  220.                 CompileObjects();
  221.  
  222.         CheckUpdateStaticInstancing();
  223.  
  224.         if (GetCVars()->e_ObjectsTreeBBoxes)
  225.         {
  226.                 if (GetCVars()->e_ObjectsTreeBBoxes == 1)
  227.                 {
  228.                         const AABB& nodeBox = GetNodeBox();
  229.                         DrawBBox(nodeBox, Col_Blue);
  230.                 }
  231.                 if (GetCVars()->e_ObjectsTreeBBoxes == 2)
  232.                         DrawBBox(m_objectsBox, Col_Red);
  233.         }
  234.  
  235.         m_fNodeDistance = fNodeDistance;
  236.         m_bNodeCompletelyInFrustum = bNodeCompletelyInFrustum;
  237.  
  238.         if (GetCVars()->e_VegetationSpritesBatching && GetCVars()->e_VegetationSprites)
  239.                 CheckManageVegetationSprites(fNodeDistance, (int)(fNodeDistance * 0.2f), passInfo);
  240.  
  241.         if (HasAnyRenderableCandidates(passInfo))
  242.         {
  243.                 // when using the occlusion culler, push the work to the jobs doing the occlusion checks, else just compute in main thread
  244.                 if (GetCVars()->e_StatObjBufferRenderTasks == 1 && passInfo.IsGeneralPass() && JobManager::InvokeAsJob("CheckOcclusion"))
  245.                 {
  246.                         // make sure the affected lights array is init before starting parallel execution
  247.                         CheckInitAffectingLights(passInfo);
  248.                         GetObjManager()->PushIntoCullQueue(SCheckOcclusionJobData::CreateOctreeJobData(this, nRenderMask, vAmbColor, passInfo));
  249.                 }
  250.                 else
  251.                 {
  252.                         RenderContentJobEntry(nRenderMask, vAmbColor, passInfo);
  253.                 }
  254.  
  255.                 passInfo.GetRendItemSorter().IncreaseOctreeCounter();
  256.         }
  257.  
  258.         int nFirst =
  259.           ((vCamPos.x > m_vNodeCenter.x) ? 4 : 0) |
  260.           ((vCamPos.y > m_vNodeCenter.y) ? 2 : 0) |
  261.           ((vCamPos.z > m_vNodeCenter.z) ? 1 : 0);
  262.  
  263.         if (m_arrChilds[nFirst])
  264.                 m_arrChilds[nFirst]->Render_Object_Nodes(bNodeCompletelyInFrustum, nRenderMask, vAmbColor, passInfo);
  265.  
  266.         if (m_arrChilds[nFirst ^ 1])
  267.                 m_arrChilds[nFirst ^ 1]->Render_Object_Nodes(bNodeCompletelyInFrustum, nRenderMask, vAmbColor, passInfo);
  268.  
  269.         if (m_arrChilds[nFirst ^ 2])
  270.                 m_arrChilds[nFirst ^ 2]->Render_Object_Nodes(bNodeCompletelyInFrustum, nRenderMask, vAmbColor, passInfo);
  271.  
  272.         if (m_arrChilds[nFirst ^ 4])
  273.                 m_arrChilds[nFirst ^ 4]->Render_Object_Nodes(bNodeCompletelyInFrustum, nRenderMask, vAmbColor, passInfo);
  274.  
  275.         if (m_arrChilds[nFirst ^ 3])
  276.                 m_arrChilds[nFirst ^ 3]->Render_Object_Nodes(bNodeCompletelyInFrustum, nRenderMask, vAmbColor, passInfo);
  277.  
  278.         if (m_arrChilds[nFirst ^ 5])
  279.                 m_arrChilds[nFirst ^ 5]->Render_Object_Nodes(bNodeCompletelyInFrustum, nRenderMask, vAmbColor, passInfo);
  280.  
  281.         if (m_arrChilds[nFirst ^ 6])
  282.                 m_arrChilds[nFirst ^ 6]->Render_Object_Nodes(bNodeCompletelyInFrustum, nRenderMask, vAmbColor, passInfo);
  283.  
  284.         if (m_arrChilds[nFirst ^ 7])
  285.                 m_arrChilds[nFirst ^ 7]->Render_Object_Nodes(bNodeCompletelyInFrustum, nRenderMask, vAmbColor, passInfo);
  286. }
  287.  
  288. void COctreeNode::RenderDebug()
  289. {
  290.         if (GetCVars()->e_ObjectsTreeBBoxes == 3 || GetCVars()->e_ObjectsTreeBBoxes == (int)GetNodeBox().GetSize().x)
  291.         {
  292.                 const AABB& nodeBox = GetNodeBox();
  293.  
  294.                 if (m_nFileDataOffset && m_eStreamingStatus == ecss_NotLoaded)
  295.                         DrawBBox(nodeBox, Col_Red);
  296.                 else if (m_nFileDataOffset && m_eStreamingStatus == ecss_InProgress)
  297.                         DrawBBox(nodeBox, Col_Yellow);
  298.                 else if (m_nFileDataOffset && m_eStreamingStatus == ecss_Ready)
  299.                         DrawBBox(nodeBox, Col_Green);
  300.         }
  301.  
  302.         for (int i = 0; i < 8; i++)
  303.                 if (m_arrChilds[i])
  304.                         m_arrChilds[i]->RenderDebug();
  305. }
  306.  
  307. void COctreeNode::GetStreamedInNodesNum(int& nAllStreamable, int& nReady)
  308. {
  309.         if (m_nFileDataOffset && m_eStreamingStatus == ecss_Ready)
  310.                 nReady++;
  311.  
  312.         if (m_nFileDataOffset)
  313.                 nAllStreamable++;
  314.  
  315.         for (int i = 0; i < 8; i++)
  316.                 if (m_arrChilds[i])
  317.                         m_arrChilds[i]->GetStreamedInNodesNum(nAllStreamable, nReady);
  318. }
  319.  
  320. void COctreeNode::CompileObjects()
  321. {
  322.         FUNCTION_PROFILER_3DENGINE;
  323.  
  324.         m_lstCasters.Clear();
  325.  
  326.         m_bStaticInstancingIsDirty = true;
  327.  
  328.         CheckUpdateStaticInstancing();
  329.  
  330.         float fObjMaxViewDistance = 0;
  331.  
  332.         size_t numCasters = 0;
  333.         const unsigned int nSkipShadowCastersRndFlags = ERF_HIDDEN | ERF_COLLISION_PROXY | ERF_RAYCAST_PROXY | ERF_STATIC_INSTANCING; // shadow casters with these render flags are ignored
  334.  
  335.         for (int l = 0; l < eRNListType_ListsNum; l++)
  336.         {
  337.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  338.                 {
  339.                         auto nFlags = pObj->GetRndFlags();
  340.  
  341.                         IF (nFlags & nSkipShadowCastersRndFlags, 0)
  342.                                 continue;
  343.  
  344.                         IF (GetCVars()->e_ShadowsPerObject && gEnv->p3DEngine->GetPerObjectShadow(pObj), 0)
  345.                                 continue;
  346.  
  347.                         EERType eRType = pObj->GetRenderNodeType();
  348.                         float WSMaxViewDist = pObj->GetMaxViewDist();
  349.  
  350.                         if (nFlags & ERF_CASTSHADOWMAPS && WSMaxViewDist > fMinShadowCasterViewDist && eRType != eERType_Light)
  351.                         {
  352.                                 ++numCasters;
  353.                         }
  354.                 }
  355.         }
  356.  
  357.         m_lstCasters.reserve(numCasters);
  358.  
  359.         CObjManager* pObjManager = GetObjManager();
  360.  
  361.         // update node
  362.         for (int l = 0; l < eRNListType_ListsNum; l++)
  363.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode, * pNext; pObj; pObj = pNext)
  364.                 {
  365.                         pNext = pObj->m_pNext;
  366.  
  367.                         IF (pObj->m_dwRndFlags & ERF_HIDDEN, 0)
  368.                                 continue;
  369.  
  370.                         // update vegetation instances data
  371.                         EERType eRType = pObj->GetRenderNodeType();
  372.                         if (eRType == eERType_Vegetation)
  373.                         {
  374.                                 CVegetation* pInst = (CVegetation*)pObj;
  375.                                 pInst->UpdateRndFlags();
  376.                         }
  377.  
  378.                         // update max view distances
  379.                         const float fNewMaxViewDist = pObj->GetMaxViewDist();
  380.                         pObj->m_fWSMaxViewDist = fNewMaxViewDist;
  381.  
  382.                         // update REQUIRES_FORWARD_RENDERING flag
  383.                         //IF(GetCVars()->e_ShadowsOnAlphaBlend,0)
  384.                         {
  385.                                 pObj->m_nInternalFlags &= ~(IRenderNode::REQUIRES_FORWARD_RENDERING | IRenderNode::REQUIRES_NEAREST_CUBEMAP);
  386.                                 if (eRType != eERType_Light &&
  387.                                     eRType != eERType_Cloud &&
  388.                                     eRType != eERType_FogVolume &&
  389.                                     eRType != eERType_Decal &&
  390.                                     eRType != eERType_Road &&
  391.                                     eRType != eERType_DistanceCloud &&
  392.                                     eRType != eERType_CloudBlocker)
  393.                                 {
  394.                                         if (eRType == eERType_ParticleEmitter)
  395.                                                 pObj->m_nInternalFlags |= IRenderNode::REQUIRES_FORWARD_RENDERING | IRenderNode::REQUIRES_NEAREST_CUBEMAP;
  396.  
  397.                                         if (CMatInfo* pMatInfo = (CMatInfo*)pObj->GetMaterial())
  398.                                         {
  399.                                                 if (pMatInfo->IsForwardRenderingRequired())
  400.                                                         pObj->m_nInternalFlags |= IRenderNode::REQUIRES_FORWARD_RENDERING;
  401.  
  402.                                                 if (pMatInfo->IsNearestCubemapRequired())
  403.                                                         pObj->m_nInternalFlags |= IRenderNode::REQUIRES_NEAREST_CUBEMAP;
  404.                                         }
  405.  
  406.                                         if (eRType == eERType_RenderProxy)
  407.                                         {
  408.                                                 int nSlotCount = pObj->GetSlotCount();
  409.  
  410.                                                 for (int s = 0; s < nSlotCount; s++)
  411.                                                 {
  412.                                                         if (CMatInfo* pMat = (CMatInfo*)pObj->GetEntitySlotMaterial(s))
  413.                                                         {
  414.                                                                 if (pMat->IsForwardRenderingRequired())
  415.                                                                         pObj->m_nInternalFlags |= IRenderNode::REQUIRES_FORWARD_RENDERING;
  416.                                                                 if (pMat->IsNearestCubemapRequired())
  417.                                                                         pObj->m_nInternalFlags |= IRenderNode::REQUIRES_NEAREST_CUBEMAP;
  418.                                                         }
  419.  
  420.                                                         if (IStatObj* pStatObj = pObj->GetEntityStatObj(s))
  421.                                                                 if (CMatInfo* pMat = (CMatInfo*)pStatObj->GetMaterial())
  422.                                                                 {
  423.                                                                         if (pMat->IsForwardRenderingRequired())
  424.                                                                                 pObj->m_nInternalFlags |= IRenderNode::REQUIRES_FORWARD_RENDERING;
  425.                                                                         if (pMat->IsNearestCubemapRequired())
  426.                                                                                 pObj->m_nInternalFlags |= IRenderNode::REQUIRES_NEAREST_CUBEMAP;
  427.                                                                 }
  428.                                                 }
  429.                                         }
  430.  
  431.                                         if (!(pObj->m_nInternalFlags & (IRenderNode::REQUIRES_FORWARD_RENDERING | IRenderNode::REQUIRES_NEAREST_CUBEMAP)))
  432.                                                 CompileCharacter(pObj->GetEntityCharacter(0), pObj->m_nInternalFlags);
  433.                                 }
  434.                         }
  435.  
  436.                         auto nFlags = pObj->GetRndFlags();
  437.  
  438.                         // fill shadow casters list
  439.                         const bool bHasPerObjectShadow = GetCVars()->e_ShadowsPerObject && gEnv->p3DEngine->GetPerObjectShadow(pObj);
  440.                         if (!(nFlags & nSkipShadowCastersRndFlags) && nFlags & ERF_CASTSHADOWMAPS && fNewMaxViewDist > fMinShadowCasterViewDist &&
  441.                             eRType != eERType_Light && !bHasPerObjectShadow)
  442.                         {
  443.                                 COctreeNode* pNode = this;
  444.                                 while (pNode && !(pNode->m_renderFlags & ERF_CASTSHADOWMAPS))
  445.                                 {
  446.                                         pNode->m_renderFlags |= ERF_CASTSHADOWMAPS | ERF_HAS_CASTSHADOWMAPS;
  447.                                         pNode = pNode->m_pParent;
  448.                                 }
  449.  
  450.                                 float fMaxCastDist = fNewMaxViewDist * GetCVars()->e_ShadowsCastViewDistRatio;
  451.                                 m_lstCasters.Add(SCasterInfo(pObj, fMaxCastDist, eRType));
  452.                         }
  453.  
  454.                         fObjMaxViewDistance = max(fObjMaxViewDistance, fNewMaxViewDist);
  455.                 }
  456.  
  457.         if (fObjMaxViewDistance > m_fObjectsMaxViewDist)
  458.         {
  459.                 COctreeNode* pNode = this;
  460.                 while (pNode)
  461.                 {
  462.                         pNode->m_fObjectsMaxViewDist = max(pNode->m_fObjectsMaxViewDist, fObjMaxViewDistance);
  463.                         pNode = pNode->m_pParent;
  464.                 }
  465.         }
  466.  
  467.         SetCompiled(true);
  468.  
  469.         const Vec3& sunDir = Get3DEngine()->GetSunDirNormalized();
  470.         m_fpSunDirX = (uint32) (sunDir.x * 63.5f + 63.5f);
  471.         m_fpSunDirZ = (uint32) (sunDir.z * 63.5f + 63.5f);
  472.         m_fpSunDirYs = sunDir.y < 0.0f ? 1 : 0;
  473. }
  474.  
  475. void COctreeNode::UpdateStaticInstancing()
  476. {
  477.         FUNCTION_PROFILER_3DENGINE;
  478.  
  479.         // clear
  480.         if (m_pStaticInstancingInfo)
  481.         {
  482.                 for (auto it = m_pStaticInstancingInfo->begin(); it != m_pStaticInstancingInfo->end(); ++it)
  483.                 {
  484.                         PodArray<SNodeInstancingInfo>*& pInfo = it->second;
  485.  
  486.                         pInfo->Clear();
  487.                 }
  488.         }
  489.  
  490.         // group objects by CStatObj *
  491.         for (IRenderNode* pObj = m_arrObjects[eRNListType_Vegetation].m_pFirstNode, * pNext; pObj; pObj = pNext)
  492.         {
  493.                 pNext = pObj->m_pNext;
  494.  
  495.                 CVegetation* pInst = (CVegetation*)pObj;
  496.  
  497.                 pObj->m_dwRndFlags &= ~ERF_STATIC_INSTANCING;
  498.  
  499.                 if (pInst->m_pInstancingInfo)
  500.                 {
  501.                         SAFE_DELETE(pInst->m_pInstancingInfo)
  502.  
  503.                         pInst->InvalidatePermanentRenderObject();
  504.                 }
  505.  
  506.                 IF (pObj->m_dwRndFlags & ERF_HIDDEN, 0)
  507.                         continue;
  508.  
  509.                 Matrix34A objMatrix;
  510.                 CStatObj* pStatObj = (CStatObj*)pInst->GetEntityStatObj(0, 0, &objMatrix);
  511.                 /*
  512.                    int nLodA = -1;
  513.                    {
  514.                    const Vec3 vCamPos = GetSystem()->GetViewCamera().GetPosition();
  515.  
  516.                    const float fEntDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, pInst->GetBBox()));
  517.                    int wantedLod = CObjManager::GetObjectLOD(pInst, fEntDistance);
  518.  
  519.                    int minUsableLod = pStatObj->GetMinUsableLod();
  520.                    int maxUsableLod = (int)pStatObj->m_nMaxUsableLod;
  521.                    nLodA = CLAMP(wantedLod, minUsableLod, maxUsableLod);
  522.                    if(!(pStatObj->m_nFlags & STATIC_OBJECT_COMPOUND))
  523.                     nLodA = pStatObj->FindNearesLoadedLOD(nLodA);
  524.                    }
  525.  
  526.                    if(nLodA<0)
  527.                    continue;
  528.  
  529.                    pStatObj = (CStatObj *)pStatObj->GetLodObject(nLodA);
  530.                  */
  531.                 if (!m_pStaticInstancingInfo)
  532.                         m_pStaticInstancingInfo = new std::map<std::pair<IStatObj*, IMaterial*>, PodArray<SNodeInstancingInfo>*>;
  533.  
  534.                 std::pair<IStatObj*, IMaterial*> pairKey(pStatObj, pInst->GetMaterial());
  535.  
  536.                 PodArray<SNodeInstancingInfo>*& pInfo = (*m_pStaticInstancingInfo)[pairKey];
  537.  
  538.                 if (!pInfo)
  539.                         pInfo = new PodArray<SNodeInstancingInfo>;
  540.  
  541.                 SNodeInstancingInfo ii;
  542.                 ii.pRNode = pInst;
  543.                 ii.nodeMatrix = objMatrix;
  544.  
  545.                 pInfo->Add(ii);
  546.         }
  547.  
  548.         // mark
  549.         if (m_pStaticInstancingInfo)
  550.         {
  551.                 for (auto it = m_pStaticInstancingInfo->begin(); it != m_pStaticInstancingInfo->end(); ++it)
  552.                 {
  553.                         PodArray<SNodeInstancingInfo>*& pInfo = it->second;
  554.  
  555.                         if (pInfo->Count() > GetCVars()->e_StaticInstancingMinInstNum)
  556.                         {
  557.                                 CVegetation* pFirstNode = pInfo->GetAt(0).pRNode;
  558.  
  559.                                 // put instancing into one of existing vegetations
  560.                                 PodArrayAABB<CRenderObject::SInstanceInfo>* pInsts = pFirstNode->m_pInstancingInfo = new PodArrayAABB<CRenderObject::SInstanceInfo>;
  561.                                 pInsts->PreAllocate(pInfo->Count(), pInfo->Count());
  562.                                 pInsts->m_aabbBox.Reset();
  563.  
  564.                                 pFirstNode->InvalidatePermanentRenderObject();
  565.  
  566.                                 for (int i = 0; i < pInfo->Count(); i++)
  567.                                 {
  568.                                         SNodeInstancingInfo& ii = pInfo->GetAt(i);
  569.  
  570.                                         if (i)
  571.                                         {
  572.                                                 ii.pRNode->SetRndFlags(ERF_STATIC_INSTANCING, true);
  573.  
  574.                                                 // keep inactive objects in the end of the list
  575.                                                 UnlinkObject(ii.pRNode);
  576.                                                 LinkObject(ii.pRNode, eERType_Vegetation, false);
  577.  
  578.                                                 for (int s = 0; s < m_lstCasters.Count(); s++)
  579.                                                 {
  580.                                                         if (m_lstCasters[s].pNode == ii.pRNode)
  581.                                                         {
  582.                                                                 m_lstCasters.Delete(s);
  583.                                                                 break;
  584.                                                         }
  585.                                                 }
  586.                                         }
  587.  
  588.                                         CStatObj* pStatObj = ii.pRNode->GetStatObj();
  589.                                         const StatInstGroup& vegetGroup = ii.pRNode->GetStatObjGroup();
  590.  
  591.                                         (*pInsts)[i].m_Matrix = ii.nodeMatrix;
  592.  
  593.                                         pInsts->m_aabbBox.Add(ii.pRNode->GetBBox());
  594.                                 }
  595.                         }
  596.                         else
  597.                         {
  598.                                 pInfo->Clear();
  599.                         }
  600.                 }
  601.         }
  602.  
  603.         m_bStaticInstancingIsDirty = false;
  604. }
  605.  
  606. void COctreeNode::AddLightSource(CDLight* pSource, const SRenderingPassInfo& passInfo)
  607. {
  608.         bool bIsVisible = false;
  609.         if (pSource->m_Flags & DLF_DEFERRED_CUBEMAPS)
  610.         {
  611.                 OBB obb(OBB::CreateOBBfromAABB(Matrix33(pSource->m_ObjMatrix), AABB(-pSource->m_ProbeExtents, pSource->m_ProbeExtents)));
  612.                 bIsVisible = passInfo.GetCamera().IsOBBVisible_F(pSource->m_Origin, obb);
  613.         }
  614.         else if (pSource->m_Flags & DLF_AREA_LIGHT)
  615.         {
  616.                 // OBB test for area lights.
  617.                 Vec3 vBoxMax(pSource->m_fRadius, pSource->m_fRadius + pSource->m_fAreaWidth, pSource->m_fRadius + pSource->m_fAreaHeight);
  618.                 Vec3 vBoxMin(-0.1f, -(pSource->m_fRadius + pSource->m_fAreaWidth), -(pSource->m_fRadius + pSource->m_fAreaHeight));
  619.  
  620.                 OBB obb(OBB::CreateOBBfromAABB(Matrix33(pSource->m_ObjMatrix), AABB(vBoxMin, vBoxMax)));
  621.                 bIsVisible = passInfo.GetCamera().IsOBBVisible_F(pSource->m_Origin, obb);
  622.         }
  623.         else
  624.                 bIsVisible = m_objectsBox.IsOverlapSphereBounds(pSource->m_Origin, pSource->m_fRadius);
  625.  
  626.         if (!bIsVisible)
  627.                 return;
  628.  
  629.         CheckInitAffectingLights(passInfo);
  630.  
  631.         if (m_lstAffectingLights.Find(pSource) < 0)
  632.         {
  633.                 m_lstAffectingLights.Add(pSource);
  634.  
  635.                 for (int i = 0; i < 8; i++)
  636.                         if (m_arrChilds[i])
  637.                                 m_arrChilds[i]->AddLightSource(pSource, passInfo);
  638.         }
  639. }
  640.  
  641. bool IsAABBInsideHull(const SPlaneObject* pHullPlanes, int nPlanesNum, const AABB& aabbBox);
  642. bool IsSphereInsideHull(const SPlaneObject* pHullPlanes, int nPlanesNum, const Sphere& objSphere);
  643.  
  644. void COctreeNode::FillShadowCastersList(bool bNodeCompletellyInFrustum, CDLight* pLight, ShadowMapFrustum* pFr, PodArray<SPlaneObject>* pShadowHull, uint32 nRenderNodeFlags, const SRenderingPassInfo& passInfo)
  645. {
  646.         if (GetCVars()->e_Objects)
  647.         {
  648.                 if (m_renderFlags & ERF_CASTSHADOWMAPS)
  649.                 {
  650.                         FRAME_PROFILER("COctreeNode::FillShadowMapCastersList", GetSystem(), PROFILE_3DENGINE);
  651.  
  652.                         CRY_ALIGN(64) ShadowMapFrustumParams params;
  653.                         params.pLight = pLight;
  654.                         params.pFr = pFr;
  655.                         params.pShadowHull = pShadowHull;
  656.                         params.passInfo = &passInfo;
  657.                         params.vCamPos = passInfo.GetCamera().GetPosition();
  658.                         params.bSun = (pLight->m_Flags & DLF_SUN) != 0;
  659.                         params.nRenderNodeFlags = nRenderNodeFlags;
  660.  
  661.                         FillShadowMapCastersList(params, bNodeCompletellyInFrustum);
  662.                 }
  663.         }
  664. }
  665.  
  666. void COctreeNode::FillShadowMapCastersList(const ShadowMapFrustumParams& params, bool bNodeCompletellyInFrustum)
  667. {
  668.         if (!bNodeCompletellyInFrustum && !params.pFr->IntersectAABB(m_objectsBox, &bNodeCompletellyInFrustum))
  669.                 return;
  670.  
  671.         const int frameID = params.passInfo->GetFrameID();
  672.         if (params.bSun && bNodeCompletellyInFrustum)
  673.                 nFillShadowCastersSkipFrameId = frameID;
  674.  
  675.         if (params.pShadowHull && !IsAABBInsideHull(params.pShadowHull->GetElements(), params.pShadowHull->Count(), m_objectsBox))
  676.         {
  677.                 nFillShadowCastersSkipFrameId = frameID;
  678.                 return;
  679.         }
  680.  
  681.         if (!IsCompiled())
  682.         {
  683.                 CompileObjects();
  684.         }
  685.  
  686.         PrefetchLine(&m_lstCasters, 0);
  687.  
  688.         const float fShadowsCastViewDistRatio = GetCVars()->e_ShadowsCastViewDistRatio;
  689.         if (fShadowsCastViewDistRatio != 0.0f)
  690.         {
  691.                 float fNodeDistanceSqr = Distance::Point_AABBSq(params.vCamPos, m_objectsBox);
  692.                 if (fNodeDistanceSqr > sqr(m_fObjectsMaxViewDist * fShadowsCastViewDistRatio))
  693.                 {
  694.                         nFillShadowCastersSkipFrameId = frameID;
  695.                         return;
  696.                 }
  697.         }
  698.  
  699.         PrefetchLine(m_lstCasters.begin(), 0);
  700.         PrefetchLine(m_lstCasters.begin(), 128);
  701.  
  702.         IRenderNode* pNotCaster = ((CLightEntity*)params.pLight->m_pOwner)->m_pNotCaster;
  703.         bool bParticleShadows = params.bSun && params.pFr->nShadowMapLod < GetCVars()->e_ParticleShadowsNumGSMs;
  704.  
  705.         if (m_arrChilds[0])
  706.         {
  707.                 PrefetchLine(&m_arrChilds[0]->m_nLightMaskFrameId, 0);
  708.         }
  709.  
  710.         SCasterInfo* pCastersEnd = m_lstCasters.end();
  711.         for (SCasterInfo* pCaster = m_lstCasters.begin(); pCaster < pCastersEnd; pCaster++)
  712.         {
  713. #ifdef FEATURE_SVO_GI
  714.                 if (!GetCVars()->e_svoTI_Apply || !GetCVars()->e_svoTI_InjectionMultiplier || (params.pFr->nShadowMapLod != GetCVars()->e_svoTI_GsmCascadeLod))
  715. #endif
  716.                 if (params.bSun && pCaster->nGSMFrameId == frameID && params.pShadowHull)
  717.                         continue;
  718.                 if (!IsRenderNodeTypeEnabled(pCaster->nRType))
  719.                         continue;
  720.                 if (pCaster->pNode == NULL || pCaster->pNode == pNotCaster)
  721.                         continue;
  722.                 if (!bParticleShadows && (pCaster->nRType == eERType_ParticleEmitter))
  723.                         continue;
  724.                 if ((pCaster->nRenderNodeFlags & params.nRenderNodeFlags) == 0)
  725.                         continue;
  726.  
  727.                 float fDistanceSq = Distance::Point_PointSq(params.vCamPos, pCaster->objSphere.center);
  728.                 if (fDistanceSq > sqr(pCaster->fMaxCastingDist + pCaster->objSphere.radius))
  729.                 {
  730.                         pCaster->nGSMFrameId = frameID;
  731.                         continue;
  732.                 }
  733.  
  734.                 bool bObjCompletellyInFrustum = bNodeCompletellyInFrustum;
  735.                 if (!bObjCompletellyInFrustum && !params.pFr->IntersectAABB(pCaster->objBox, &bObjCompletellyInFrustum))
  736.                         continue;
  737.                 if (params.bSun && bObjCompletellyInFrustum)
  738.                         pCaster->nGSMFrameId = frameID;
  739.  
  740.                 if (params.bSun && bObjCompletellyInFrustum)
  741.                         pCaster->nGSMFrameId = frameID;
  742.                 if (params.pShadowHull && !IsSphereInsideHull(params.pShadowHull->GetElements(), params.pShadowHull->Count(), pCaster->objSphere))
  743.                 {
  744.                         pCaster->nGSMFrameId = frameID;
  745.                         continue;
  746.                 }
  747.  
  748.                 if (pCaster->bCanExecuteAsRenderJob)
  749.                 {
  750.                         params.pFr->jobExecutedCastersList.Add(pCaster->pNode);
  751.                 }
  752.                 else
  753.                         params.pFr->castersList.Add(pCaster->pNode);
  754.  
  755.                 // This code does not exist yet!
  756.                 //if(pCaster->nRType == eERType_ParticleEmitter)
  757.                 //((CParticleEmitter*)pCaster->pNode)->AddUpdateParticlesJob();
  758.         }
  759.  
  760.         enum { maxNodeNum = 7 };
  761.         for (int i = 0; i <= maxNodeNum; i++)
  762.         {
  763.                 const bool bPrefetch = i < maxNodeNum && !!m_arrChilds[i + 1];
  764.                 if (bPrefetch)
  765.                 {
  766.                         PrefetchLine(&m_arrChilds[i + 1]->m_nLightMaskFrameId, 0);
  767.                 }
  768.  
  769.                 if (m_arrChilds[i] && (m_arrChilds[i]->m_renderFlags & ERF_CASTSHADOWMAPS))
  770.                 {
  771.                         bool bContinue = m_arrChilds[i]->nFillShadowCastersSkipFrameId != frameID;
  772.  
  773. #ifdef FEATURE_SVO_GI
  774.                         if (GetCVars()->e_svoTI_Apply && GetCVars()->e_svoTI_InjectionMultiplier && (params.pFr->nShadowMapLod == GetCVars()->e_svoTI_GsmCascadeLod))
  775.                                 bContinue = true;
  776. #endif
  777.  
  778.                         if (!params.bSun || !params.pShadowHull || bContinue)
  779.                                 m_arrChilds[i]->FillShadowMapCastersList(params, bNodeCompletellyInFrustum);
  780.                 }
  781.         }
  782. }
  783.  
  784. void COctreeNode::MarkAsUncompiled(const IRenderNode* pRenderNode)
  785. {
  786.         if (pRenderNode)
  787.         {
  788.                 for (int l = 0; l < eRNListType_ListsNum; l++)
  789.                 {
  790.                         for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  791.                         {
  792.                                 if (pObj == pRenderNode)
  793.                                 {
  794.                                         SetCompiled(false);
  795.                                         break;
  796.                                 }
  797.                         }
  798.                 }
  799.         }
  800.         else
  801.                 SetCompiled(false);
  802.  
  803.         for (int i = 0; i < 8; i++)
  804.                 if (m_arrChilds[i])
  805.                         m_arrChilds[i]->MarkAsUncompiled(pRenderNode);
  806. }
  807.  
  808. AABB COctreeNode::GetShadowCastersBox(const AABB* pBBox, const Matrix34* pShadowSpaceTransform)
  809. {
  810.         if (!IsCompiled())
  811.                 CompileObjects();
  812.  
  813.         AABB result(AABB::RESET);
  814.         if (!pBBox || Overlap::AABB_AABB(*pBBox, GetObjectsBBox()))
  815.         {
  816.                 for (size_t i = 0; i < m_lstCasters.size(); ++i)
  817.                 {
  818.                         AABB casterBox = m_lstCasters[i].objBox;
  819.                         if (!pBBox || Overlap::AABB_AABB(*pBBox, casterBox))
  820.                         {
  821.                                 if (pShadowSpaceTransform)
  822.                                         casterBox = AABB::CreateTransformedAABB(*pShadowSpaceTransform, casterBox);
  823.  
  824.                                 result.Add(casterBox);
  825.                         }
  826.                 }
  827.  
  828.                 for (int i = 0; i < 8; i++)
  829.                 {
  830.                         if (m_arrChilds[i])
  831.                                 result.Add(m_arrChilds[i]->GetShadowCastersBox(pBBox, pShadowSpaceTransform));
  832.                 }
  833.         }
  834.  
  835.         return result;
  836. }
  837.  
  838. COctreeNode* COctreeNode::FindNodeContainingBox(const AABB& objBox)
  839. {
  840.         {
  841.                 const AABB& nodeBox = GetNodeBox();
  842.                 if (!nodeBox.IsContainSphere(objBox.min, -0.01f) || !nodeBox.IsContainSphere(objBox.max, -0.01f))
  843.                         return NULL;
  844.         }
  845.  
  846.         for (int i = 0; i < 8; i++)
  847.                 if (m_arrChilds[i])
  848.                         if (COctreeNode* pFoundNode = m_arrChilds[i]->FindNodeContainingBox(objBox))
  849.                                 return pFoundNode;
  850.  
  851.         return this;
  852. }
  853.  
  854. void COctreeNode::MoveObjectsIntoList(PodArray<SRNInfo>* plstResultEntities, const AABB* pAreaBox,
  855.                                       bool bRemoveObjects, bool bSkipDecals, bool bSkip_ERF_NO_DECALNODE_DECALS, bool bSkipDynamicObjects,
  856.                                       EERType eRNType)
  857. {
  858.         FUNCTION_PROFILER_3DENGINE;
  859.  
  860.         if (pAreaBox && !Overlap::AABB_AABB(m_objectsBox, *pAreaBox))
  861.                 return;
  862.  
  863.         for (int l = 0; l < eRNListType_ListsNum; l++)
  864.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode, * pNext; pObj; pObj = pNext)
  865.                 {
  866.                         pNext = pObj->m_pNext;
  867.  
  868.                         if (eRNType < eERType_TypesNum && pObj->GetRenderNodeType() != eRNType)
  869.                                 continue;
  870.  
  871.                         if (bSkipDecals && pObj->GetRenderNodeType() == eERType_Decal)
  872.                                 continue;
  873.  
  874.                         if (bSkip_ERF_NO_DECALNODE_DECALS && pObj->GetRndFlags() & ERF_NO_DECALNODE_DECALS)
  875.                                 continue;
  876.  
  877.                         if (bSkipDynamicObjects)
  878.                         {
  879.                                 EERType eRType = pObj->GetRenderNodeType();
  880.  
  881.                                 if (pObj->GetRndFlags() & ERF_MOVES_EVERY_FRAME)
  882.                                         continue;
  883.  
  884.                                 if (
  885.                                   eRType != eERType_Brush &&
  886.                                   eRType != eERType_Vegetation)
  887.                                         continue;
  888.                         }
  889.  
  890.                         if (pAreaBox && !Overlap::AABB_AABB(pObj->GetBBox(), *pAreaBox))
  891.                                 continue;
  892.  
  893.                         if (bRemoveObjects)
  894.                         {
  895.                                 UnlinkObject(pObj);
  896.  
  897.                                 SetCompiled(false);
  898.                         }
  899.  
  900.                         plstResultEntities->Add(pObj);
  901.                 }
  902.  
  903.         for (int i = 0; i < 8; i++)
  904.         {
  905.                 if (m_arrChilds[i])
  906.                 {
  907.                         m_arrChilds[i]->MoveObjectsIntoList(plstResultEntities, pAreaBox, bRemoveObjects, bSkipDecals, bSkip_ERF_NO_DECALNODE_DECALS, bSkipDynamicObjects, eRNType);
  908.                 }
  909.         }
  910. }
  911.  
  912. void COctreeNode::DeleteObjectsByFlag(int nRndFlag)
  913. {
  914.         FUNCTION_PROFILER_3DENGINE;
  915.         for (int l = 0; l < eRNListType_ListsNum; l++)
  916.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode, * pNext; pObj; pObj = pNext)
  917.                 {
  918.                         pNext = pObj->m_pNext;
  919.  
  920.                         if (pObj->GetRndFlags() & nRndFlag)
  921.                                 DeleteObject(pObj);
  922.                 }
  923.  
  924.         for (int i = 0; i < 8; i++)
  925.                 if (m_arrChilds[i])
  926.                         m_arrChilds[i]->DeleteObjectsByFlag(nRndFlag);
  927. }
  928.  
  929. void COctreeNode::UnregisterEngineObjectsInArea(const SHotUpdateInfo* pExportInfo, PodArray<IRenderNode*>& arrUnregisteredObjects, bool bOnlyEngineObjects)
  930. {
  931.         FUNCTION_PROFILER_3DENGINE;
  932.  
  933.         const AABB* pAreaBox = (pExportInfo && !pExportInfo->areaBox.IsReset()) ? &pExportInfo->areaBox : NULL;
  934.  
  935.         {
  936.                 const AABB& nodeBox = GetNodeBox();
  937.                 if (pAreaBox && !Overlap::AABB_AABB(nodeBox, *pAreaBox))
  938.                         return;
  939.         }
  940.  
  941.         uint32 nObjTypeMask = pExportInfo ? pExportInfo->nObjTypeMask : (uint32) ~0;
  942.  
  943.         for (int l = 0; l < eRNListType_ListsNum; l++)
  944.         {
  945.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode, * pNext; pObj; pObj = pNext)
  946.                 {
  947.                         pNext = pObj->m_pNext;
  948.  
  949.                         EERType eType = pObj->GetRenderNodeType();
  950.  
  951.                         if (bOnlyEngineObjects)
  952.                         {
  953.                                 if (!(nObjTypeMask & (1 << eType)))
  954.                                         continue;
  955.  
  956.                                 if ((eType == eERType_Vegetation && !(pObj->GetRndFlags() & ERF_PROCEDURAL)) ||
  957.                                     eType == eERType_Brush ||
  958.                                     eType == eERType_Decal ||
  959.                                     eType == eERType_WaterVolume ||
  960.                                     eType == eERType_Road ||
  961.                                     eType == eERType_DistanceCloud ||
  962.                                     eType == eERType_WaterWave)
  963.                                 {
  964.                                         Get3DEngine()->UnRegisterEntityAsJob(pObj);
  965.                                         arrUnregisteredObjects.Add(pObj);
  966.                                         SetCompiled(false);
  967.                                 }
  968.                         }
  969.                         else
  970.                         {
  971.                                 Get3DEngine()->UnRegisterEntityAsJob(pObj);
  972.                                 arrUnregisteredObjects.Add(pObj);
  973.                                 SetCompiled(false);
  974.                         }
  975.                 }
  976.         }
  977.  
  978.         for (int i = 0; i < 8; i++)
  979.         {
  980.                 if (m_arrChilds[i])
  981.                         m_arrChilds[i]->UnregisterEngineObjectsInArea(pExportInfo, arrUnregisteredObjects, bOnlyEngineObjects);
  982.         }
  983. }
  984.  
  985. int COctreeNode::PhysicalizeInBox(const AABB& bbox)
  986. {
  987.         if (!Overlap::AABB_AABB(m_objectsBox, bbox))
  988.                 return 0;
  989.  
  990.         struct _Op
  991.         {
  992.                 void operator()(IRenderNode* pObj, const AABB& _bbox, int checkActive, int& _nCount) const
  993.                 {
  994.                         const AABB& objBox = pObj->GetBBox();
  995.                         if (Overlap::AABB_AABB(_bbox, objBox) &&
  996.                             max(objBox.max.x - objBox.min.x, objBox.max.y - objBox.min.y) <=
  997.                             ((C3DEngine*)gEnv->p3DEngine)->GetCVars()->e_OnDemandMaxSize)
  998.                         {
  999.                                 if (!pObj->GetPhysics() && ((checkActive && pObj->GetRndFlags() & ERF_ACTIVE_LAYER) || (!checkActive)))
  1000.                                         pObj->Physicalize(true);
  1001.                                 if (pObj->GetPhysics())
  1002.                                         pObj->GetPhysics()->AddRef(), _nCount++;
  1003.                         }
  1004.                 }
  1005.         };
  1006.  
  1007.         int nCount = 0;
  1008.         _Op physicalize;
  1009.         if (GetCVars()->e_OnDemandPhysics & 0x1)
  1010.                 for (IRenderNode* pObj = m_arrObjects[eRNListType_Vegetation].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1011.                 {
  1012.                         assert(pObj->GetRenderNodeType() == eERType_Vegetation);
  1013.                         physicalize(pObj, bbox, false, nCount);
  1014.                 }
  1015.         if (GetCVars()->e_OnDemandPhysics & 0x2)
  1016.                 for (IRenderNode* pObj = m_arrObjects[eRNListType_Brush].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1017.                 {
  1018.                         assert(pObj->GetRenderNodeType() == eERType_Brush);
  1019.                         physicalize(pObj, bbox, true, nCount);
  1020.                 }
  1021.  
  1022.         for (int i = 0; i < 8; i++)
  1023.                 if (m_arrChilds[i])
  1024.                         nCount += m_arrChilds[i]->PhysicalizeInBox(bbox);
  1025.  
  1026.         return nCount;
  1027. }
  1028.  
  1029. int COctreeNode::DephysicalizeInBox(const AABB& bbox)
  1030. {
  1031.         if (!Overlap::AABB_AABB(m_objectsBox, bbox))
  1032.                 return 0;
  1033.  
  1034.         struct _Op
  1035.         {
  1036.                 void operator()(IRenderNode* pObj, const AABB& _bbox) const
  1037.                 {
  1038.                         const AABB& objBox = pObj->GetBBox();
  1039.                         if (Overlap::AABB_AABB(_bbox, objBox) &&
  1040.                             max(objBox.max.x - objBox.min.x, objBox.max.y - objBox.min.y) <=
  1041.                             ((C3DEngine*)gEnv->p3DEngine)->GetCVars()->e_OnDemandMaxSize)
  1042.                                 pObj->Dephysicalize(true);
  1043.                 }
  1044.         };
  1045.  
  1046.         int nCount = 0;
  1047.         _Op dephysicalize;
  1048.         if (GetCVars()->e_OnDemandPhysics & 0x1)
  1049.                 for (IRenderNode* pObj = m_arrObjects[eRNListType_Vegetation].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1050.                 {
  1051.                         assert(pObj->GetRenderNodeType() == eERType_Vegetation);
  1052.                         dephysicalize(pObj, bbox);
  1053.                 }
  1054.         if (GetCVars()->e_OnDemandPhysics & 0x2)
  1055.                 for (IRenderNode* pObj = m_arrObjects[eRNListType_Brush].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1056.                 {
  1057.                         assert(pObj->GetRenderNodeType() == eERType_Brush);
  1058.                         dephysicalize(pObj, bbox);
  1059.                 }
  1060.  
  1061.         for (int i = 0; i < 8; i++)
  1062.                 if (m_arrChilds[i])
  1063.                         nCount += m_arrChilds[i]->DephysicalizeInBox(bbox);
  1064.  
  1065.         return nCount;
  1066. }
  1067.  
  1068. int COctreeNode::PhysicalizeOfType(ERNListType listType, bool bInstant)
  1069. {
  1070.         for (IRenderNode* pObj = m_arrObjects[listType].m_pFirstNode, * pNext; pObj; pObj = pNext)
  1071.         {
  1072.                 pNext = pObj->m_pNext;
  1073.                 pObj->Physicalize(bInstant);
  1074.         }
  1075.  
  1076.         for (int i = 0; i < 8; i++)
  1077.         {
  1078.                 if (m_arrChilds[i])
  1079.                         m_arrChilds[i]->PhysicalizeOfType(listType, bInstant);
  1080.         }
  1081.  
  1082.         return 0;
  1083. }
  1084.  
  1085. int COctreeNode::DePhysicalizeOfType(ERNListType listType, bool bInstant)
  1086. {
  1087.         for (IRenderNode* pObj = m_arrObjects[listType].m_pFirstNode, * pNext; pObj; pObj = pNext)
  1088.         {
  1089.                 pNext = pObj->m_pNext;
  1090.                 pObj->Dephysicalize(bInstant);
  1091.         }
  1092.  
  1093.         for (int i = 0; i < 8; i++)
  1094.         {
  1095.                 if (m_arrChilds[i])
  1096.                         m_arrChilds[i]->DePhysicalizeOfType(listType, bInstant);
  1097.         }
  1098.  
  1099.         return 0;
  1100. }
  1101.  
  1102. int COctreeNode::GetObjectsCount(EOcTeeNodeListType eListType)
  1103. {
  1104.         int nCount = 0;
  1105.  
  1106.         switch (eListType)
  1107.         {
  1108.         case eMain:
  1109.                 for (int l = 0; l < eRNListType_ListsNum; l++)
  1110.                         for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1111.                                 nCount++;
  1112.                 break;
  1113.         case eCasters:
  1114.                 for (int l = 0; l < eRNListType_ListsNum; l++)
  1115.                         for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1116.                                 if (pObj->GetRndFlags() & ERF_CASTSHADOWMAPS)
  1117.                                         nCount++;
  1118.                 break;
  1119.         case eSprites:
  1120.                 for (IRenderNode* pObj = m_arrObjects[eRNListType_Vegetation].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1121.                         if (static_cast<CVegetation*>(pObj)->m_pSpriteInfo)
  1122.                                 ++nCount;
  1123.                 break;
  1124.         case eLights:
  1125.                 nCount = m_lstAffectingLights.Count();
  1126.                 break;
  1127.         }
  1128.  
  1129.         for (int i = 0; i < 8; i++)
  1130.                 if (m_arrChilds[i])
  1131.                         nCount += m_arrChilds[i]->GetObjectsCount(eListType);
  1132.  
  1133.         return nCount;
  1134. }
  1135.  
  1136. void COctreeNode::GetMemoryUsage(ICrySizer* pSizer) const
  1137. {
  1138.         for (int l = 0; l < eRNListType_ListsNum; l++)
  1139.         {
  1140.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1141.                 {
  1142.                         EERType eType = pObj->GetRenderNodeType();
  1143.                         if (!(eType == eERType_Vegetation && pObj->GetRndFlags() & ERF_PROCEDURAL))
  1144.                                 pObj->GetMemoryUsage(pSizer);
  1145.                 }
  1146.         }
  1147.  
  1148.         {
  1149.                 SIZER_COMPONENT_NAME(pSizer, "ObjLists");
  1150.  
  1151.                 pSizer->AddObject(m_lstCasters);
  1152.                 pSizer->AddObject(m_lstAffectingLights);
  1153.         }
  1154.  
  1155.         for (int i = 0; i < 8; i++)
  1156.                 if (m_arrChilds[i])
  1157.                         m_arrChilds[i]->GetMemoryUsage(pSizer);
  1158.  
  1159.         if (pSizer)
  1160.                 pSizer->AddObject(this, sizeof(*this));
  1161. }
  1162.  
  1163. void COctreeNode::UpdateTerrainNodes(CTerrainNode* pParentNode)
  1164. {
  1165.         if (pParentNode != 0)
  1166.                 SetTerrainNode(pParentNode->FindMinNodeContainingBox(GetNodeBox()));
  1167.         else if (m_nSID >= 0 && GetTerrain() != 0)
  1168.                 SetTerrainNode(GetTerrain()->FindMinNodeContainingBox(GetNodeBox(), m_nSID));
  1169.         else
  1170.                 SetTerrainNode(NULL);
  1171.  
  1172.         for (int i = 0; i < 8; i++)
  1173.                 if (m_arrChilds[i])
  1174.                         m_arrChilds[i]->UpdateTerrainNodes();
  1175. }
  1176.  
  1177. void C3DEngine::GetObjectsByTypeGlobal(PodArray<IRenderNode*>& lstObjects, EERType objType, const AABB* pBBox, bool* pInstStreamReady, uint64 dwFlags)
  1178. {
  1179.         for (int nSID = 0; nSID < Get3DEngine()->m_pObjectsTree.Count(); nSID++)
  1180.                 if (Get3DEngine()->IsSegmentSafeToUse(nSID))
  1181.                         Get3DEngine()->m_pObjectsTree[nSID]->GetObjectsByType(lstObjects, objType, pBBox, pInstStreamReady, dwFlags);
  1182. }
  1183.  
  1184. void C3DEngine::MoveObjectsIntoListGlobal(PodArray<SRNInfo>* plstResultEntities, const AABB* pAreaBox,
  1185.                                           bool bRemoveObjects, bool bSkipDecals, bool bSkip_ERF_NO_DECALNODE_DECALS, bool bSkipDynamicObjects,
  1186.                                           EERType eRNType)
  1187. {
  1188.         for (int nSID = 0; nSID < Get3DEngine()->m_pObjectsTree.Count(); nSID++)
  1189.                 if (Get3DEngine()->IsSegmentSafeToUse(nSID))
  1190.                         Get3DEngine()->m_pObjectsTree[nSID]->MoveObjectsIntoList(plstResultEntities, pAreaBox, bRemoveObjects, bSkipDecals, bSkip_ERF_NO_DECALNODE_DECALS, bSkipDynamicObjects, eRNType);
  1191. }
  1192.  
  1193. void COctreeNode::ActivateObjectsLayer(uint16 nLayerId, bool bActivate, bool bPhys, IGeneralMemoryHeap* pHeap, const AABB& layerBox)
  1194. {
  1195.         if (nLayerId && nLayerId < 0xFFFF && !Overlap::AABB_AABB(layerBox, GetObjectsBBox()))
  1196.                 return;
  1197.  
  1198.         for (IRenderNode* pObj = m_arrObjects[eRNListType_Brush].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1199.         {
  1200.                 if (pObj->GetRenderNodeType() == eERType_Brush)
  1201.                 {
  1202.                         CBrush* pBrush = (CBrush*)pObj;
  1203.                         if (pBrush->m_nLayerId == nLayerId || nLayerId == uint16(~0))
  1204.                         {
  1205.                                 if ((bActivate && pBrush->m_dwRndFlags & ERF_HIDDEN) || (!bActivate && !(pBrush->m_dwRndFlags & ERF_HIDDEN)))
  1206.                                         SetCompiled(false);
  1207.  
  1208.                                 pBrush->SetRndFlags(ERF_HIDDEN, !bActivate);
  1209.                                 pBrush->SetRndFlags(ERF_ACTIVE_LAYER, bActivate);
  1210.  
  1211.                                 if (GetCVars()->e_ObjectLayersActivationPhysics == 1)
  1212.                                 {
  1213.                                         if (bActivate && bPhys)
  1214.                                                 pBrush->PhysicalizeOnHeap(pHeap, false);
  1215.                                         else
  1216.                                                 pBrush->Dephysicalize();
  1217.                                 }
  1218.                                 else if (!bPhys)
  1219.                                 {
  1220.                                         pBrush->Dephysicalize();
  1221.                                 }
  1222.                         }
  1223.                 }
  1224.         }
  1225.  
  1226.         for (IRenderNode* pObj = m_arrObjects[eRNListType_DecalsAndRoads].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1227.         {
  1228.                 EERType eType = pObj->GetRenderNodeType();
  1229.  
  1230.                 if (eType == eERType_Decal)
  1231.                 {
  1232.                         CDecalRenderNode* pDecal = (CDecalRenderNode*)pObj;
  1233.                         if (pDecal->GetLayerId() == nLayerId || nLayerId == uint16(~0))
  1234.                         {
  1235.                                 pDecal->SetRndFlags(ERF_HIDDEN, !bActivate);
  1236.  
  1237.                                 if (bActivate)
  1238.                                         pDecal->RequestUpdate();
  1239.                                 else
  1240.                                         pDecal->DeleteDecals();
  1241.                         }
  1242.                 }
  1243.  
  1244.                 if (eType == eERType_Road)
  1245.                 {
  1246.                         CRoadRenderNode* pDecal = (CRoadRenderNode*)pObj;
  1247.                         if (pDecal->GetLayerId() == nLayerId || nLayerId == uint16(~0))
  1248.                         {
  1249.                                 pDecal->SetRndFlags(ERF_HIDDEN, !bActivate);
  1250.                         }
  1251.                 }
  1252.         }
  1253.  
  1254.         for (IRenderNode* pObj = m_arrObjects[eRNListType_Unknown].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1255.         {
  1256.                 if (pObj->GetRenderNodeType() == eERType_WaterVolume)
  1257.                 {
  1258.                         CWaterVolumeRenderNode* pWatVol = (CWaterVolumeRenderNode*)pObj;
  1259.                         if (pWatVol->GetLayerId() == nLayerId || nLayerId == uint16(~0))
  1260.                         {
  1261.                                 pWatVol->SetRndFlags(ERF_HIDDEN, !bActivate);
  1262.  
  1263.                                 if (GetCVars()->e_ObjectLayersActivationPhysics)
  1264.                                 {
  1265.                                         if (bActivate && bPhys)
  1266.                                                 pWatVol->Physicalize();
  1267.                                         else
  1268.                                                 pWatVol->Dephysicalize();
  1269.                                 }
  1270.                                 else if (!bPhys)
  1271.                                 {
  1272.                                         pWatVol->Dephysicalize();
  1273.                                 }
  1274.                         }
  1275.                 }
  1276.  
  1277.                 if (pObj->GetRenderNodeType() == eERType_DistanceCloud)
  1278.                 {
  1279.                         CDistanceCloudRenderNode* pCloud = (CDistanceCloudRenderNode*)pObj;
  1280.                         if (pCloud->GetLayerId() == nLayerId || nLayerId == uint16(~0))
  1281.                         {
  1282.                                 pCloud->SetRndFlags(ERF_HIDDEN, !bActivate);
  1283.                         }
  1284.                 }
  1285.         }
  1286.  
  1287.         for (int i = 0; i < 8; i++)
  1288.                 if (m_arrChilds[i])
  1289.                         m_arrChilds[i]->ActivateObjectsLayer(nLayerId, bActivate, bPhys, pHeap, layerBox);
  1290. }
  1291.  
  1292. void COctreeNode::GetLayerMemoryUsage(uint16 nLayerId, ICrySizer* pSizer, int* pNumBrushes, int* pNumDecals)
  1293. {
  1294.         for (IRenderNode* pObj = m_arrObjects[eRNListType_Brush].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1295.         {
  1296.                 if (pObj->GetRenderNodeType() == eERType_Brush)
  1297.                 {
  1298.                         CBrush* pBrush = (CBrush*)pObj;
  1299.                         if (pBrush->m_nLayerId == nLayerId || nLayerId == uint16(~0))
  1300.                         {
  1301.                                 pBrush->GetMemoryUsage(pSizer);
  1302.                                 if (pNumBrushes)
  1303.                                         (*pNumBrushes)++;
  1304.                         }
  1305.                 }
  1306.         }
  1307.  
  1308.         for (IRenderNode* pObj = m_arrObjects[eRNListType_DecalsAndRoads].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1309.         {
  1310.                 EERType eType = pObj->GetRenderNodeType();
  1311.  
  1312.                 if (eType == eERType_Decal)
  1313.                 {
  1314.                         CDecalRenderNode* pDecal = (CDecalRenderNode*)pObj;
  1315.                         if (pDecal->GetLayerId() == nLayerId || nLayerId == uint16(~0))
  1316.                         {
  1317.                                 pDecal->GetMemoryUsage(pSizer);
  1318.                                 if (pNumDecals)
  1319.                                         (*pNumDecals)++;
  1320.                         }
  1321.                 }
  1322.  
  1323.                 if (eType == eERType_Road)
  1324.                 {
  1325.                         CRoadRenderNode* pDecal = (CRoadRenderNode*)pObj;
  1326.                         if (pDecal->GetLayerId() == nLayerId || nLayerId == uint16(~0))
  1327.                         {
  1328.                                 pDecal->GetMemoryUsage(pSizer);
  1329.                                 if (pNumDecals)
  1330.                                         (*pNumDecals)++;
  1331.                         }
  1332.                 }
  1333.         }
  1334.  
  1335.         for (int i = 0; i < 8; i++)
  1336.                 if (m_arrChilds[i])
  1337.                         m_arrChilds[i]->GetLayerMemoryUsage(nLayerId, pSizer, pNumBrushes, pNumDecals);
  1338. }
  1339.  
  1340. void COctreeNode::GetObjects(PodArray<IRenderNode*>& lstObjects, const AABB* pBBox)
  1341. {
  1342.         if (pBBox && !Overlap::AABB_AABB(*pBBox, GetObjectsBBox()))
  1343.                 return;
  1344.  
  1345.         unsigned int nCurrentObject(eRNListType_First);
  1346.         for (nCurrentObject = eRNListType_First; nCurrentObject < eRNListType_ListsNum; ++nCurrentObject)
  1347.         {
  1348.                 for (IRenderNode* pObj = m_arrObjects[nCurrentObject].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1349.                 {
  1350.                         if (!pBBox || Overlap::AABB_AABB(*pBBox, pObj->GetBBox()))
  1351.                         {
  1352.                                 lstObjects.Add(pObj);
  1353.                         }
  1354.                 }
  1355.         }
  1356.  
  1357.         for (int i = 0; i < 8; i++)
  1358.                 if (m_arrChilds[i])
  1359.                         m_arrChilds[i]->GetObjects(lstObjects, pBBox);
  1360. }
  1361.  
  1362. bool COctreeNode::GetShadowCastersTimeSliced(IRenderNode* pIgnoreNode, ShadowMapFrustum* pFrustum, const PodArray<struct SPlaneObject>* pShadowHull, int renderNodeExcludeFlags, int& totalRemainingNodes, int nCurLevel, const SRenderingPassInfo& passInfo)
  1363. {
  1364.         assert(pFrustum->pShadowCacheData);
  1365.  
  1366.         if (totalRemainingNodes <= 0)
  1367.                 return false;
  1368.  
  1369.         if (!pFrustum->pShadowCacheData->mOctreePathNodeProcessed[nCurLevel])
  1370.         {
  1371.                 if (!pShadowHull || IsAABBInsideHull(pShadowHull->GetElements(), pShadowHull->Count(), m_objectsBox))
  1372.                 {
  1373.                         if (pFrustum->aabbCasters.IsReset() || Overlap::AABB_AABB(pFrustum->aabbCasters, GetObjectsBBox()))
  1374.                         {
  1375.                                 for (int l = 0; l < eRNListType_ListsNum; l++)
  1376.                                 {
  1377.                                         for (IRenderNode* pNode = m_arrObjects[l].m_pFirstNode; pNode; pNode = pNode->m_pNext)
  1378.                                         {
  1379.                                                 if (!IsRenderNodeTypeEnabled(pNode->GetRenderNodeType()))
  1380.                                                         continue;
  1381.  
  1382.                                                 if (pNode == pIgnoreNode)
  1383.                                                         continue;
  1384.  
  1385.                                                 auto nFlags = pNode->GetRndFlags();
  1386.                                                 if (nFlags & (ERF_HIDDEN | ERF_COLLISION_PROXY | ERF_RAYCAST_PROXY | renderNodeExcludeFlags))
  1387.                                                         continue;
  1388.  
  1389.                                                 // Ignore ERF_CASTSHADOWMAPS for ambient occlusion casters
  1390.                                                 if (pFrustum->m_eFrustumType != ShadowMapFrustum::e_HeightMapAO && (pNode->GetRndFlags() & ERF_CASTSHADOWMAPS) == 0)
  1391.                                                         continue;
  1392.  
  1393.                                                 if (pFrustum->pShadowCacheData->mProcessedCasters.find(pNode) != pFrustum->pShadowCacheData->mProcessedCasters.end())
  1394.                                                         continue;
  1395.  
  1396.                                                 AABB objBox = pNode->GetBBox();
  1397.                                                 const float fDistanceSq = Distance::Point_PointSq(passInfo.GetCamera().GetPosition(), objBox.GetCenter());
  1398.                                                 const float fMaxDist = pNode->GetMaxViewDist() * GetCVars()->e_ShadowsCastViewDistRatio + objBox.GetRadius();
  1399.  
  1400.                                                 if (fDistanceSq > sqr(fMaxDist))
  1401.                                                         continue;
  1402.  
  1403.                                                 // find closest loaded lod
  1404.                                                 for (int nSlot = 0; nSlot < pNode->GetSlotCount(); ++nSlot)
  1405.                                                 {
  1406.                                                         bool bCanRender = false;
  1407.  
  1408.                                                         if (IStatObj* pStatObj = pNode->GetEntityStatObj(nSlot))
  1409.                                                         {
  1410.                                                                 for (int i = 0; i < MAX_STATOBJ_LODS_NUM; ++i)
  1411.                                                                 {
  1412.                                                                         IStatObj* pLod = pStatObj->GetLodObject(i);
  1413.  
  1414.                                                                         if (pLod && pLod->m_eStreamingStatus == ecss_Ready)
  1415.                                                                         {
  1416.                                                                                 bCanRender = true;
  1417.                                                                                 break;
  1418.                                                                         }
  1419.                                                                 }
  1420.                                                         }
  1421.                                                         else if (ICharacterInstance* pCharacter = pNode->GetEntityCharacter(nSlot))
  1422.                                                         {
  1423.                                                                 bCanRender = GetCVars()->e_ShadowsCacheRenderCharacters != 0;
  1424.                                                         }
  1425.  
  1426.                                                         if (bCanRender)
  1427.                                                         {
  1428.                                                                 if (pNode->CanExecuteRenderAsJob())
  1429.                                                                 {
  1430.                                                                         pFrustum->jobExecutedCastersList.Add(pNode);
  1431.                                                                 }
  1432.                                                                 else
  1433.                                                                         pFrustum->castersList.Add(pNode);
  1434.                                                         }
  1435.                                                 }
  1436.                                         }
  1437.                                 }
  1438.                         }
  1439.                 }
  1440.  
  1441.                 pFrustum->pShadowCacheData->mOctreePathNodeProcessed[nCurLevel] = true;
  1442.                 --totalRemainingNodes;
  1443.         }
  1444.  
  1445.         for (int i = pFrustum->pShadowCacheData->mOctreePath[nCurLevel]; i < 8; ++i)
  1446.         {
  1447.                 if (m_arrChilds[i] && (m_arrChilds[i]->m_renderFlags & ERF_CASTSHADOWMAPS))
  1448.                 {
  1449.                         bool bDone = m_arrChilds[i]->GetShadowCastersTimeSliced(pIgnoreNode, pFrustum, pShadowHull, renderNodeExcludeFlags, totalRemainingNodes, nCurLevel + 1, passInfo);
  1450.  
  1451.                         if (!bDone)
  1452.                                 return false;
  1453.  
  1454.                 }
  1455.  
  1456.                 pFrustum->pShadowCacheData->mOctreePath[nCurLevel] = i;
  1457.         }
  1458.  
  1459.         // this subtree is fully processed: reset traversal state
  1460.         pFrustum->pShadowCacheData->mOctreePath[nCurLevel] = 0;
  1461.         pFrustum->pShadowCacheData->mOctreePathNodeProcessed[nCurLevel] = 0;
  1462.         return true;
  1463. }
  1464.  
  1465. bool COctreeNode::IsObjectTypeInTheBox(EERType objType, const AABB& WSBBox)
  1466. {
  1467.         if (!Overlap::AABB_AABB(WSBBox, GetObjectsBBox()))
  1468.                 return false;
  1469.  
  1470.         if (objType == eERType_Road && !m_bHasRoads)
  1471.                 return false;
  1472.  
  1473.         ERNListType eListType = IRenderNode::GetRenderNodeListId(objType);
  1474.  
  1475.         for (IRenderNode* pObj = m_arrObjects[eListType].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1476.         {
  1477.                 if (pObj->GetRenderNodeType() == objType)
  1478.                 {
  1479.                         if (Overlap::AABB_AABB(WSBBox, pObj->GetBBox()))
  1480.                                 return true;
  1481.                 }
  1482.         }
  1483.  
  1484.         for (int i = 0; i < 8; i++)
  1485.                 if (m_arrChilds[i])
  1486.                         if (m_arrChilds[i]->IsObjectTypeInTheBox(objType, WSBBox))
  1487.                                 return true;
  1488.  
  1489.         return false;
  1490. }
  1491.  
  1492. void COctreeNode::GenerateStatObjAndMatTables(std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, SHotUpdateInfo* pExportInfo)
  1493. {
  1494.         static_assert(eERType_TypesNum == 26, "Array size changed, code might need to be updated!");
  1495.         AABB* pBox = (pExportInfo && !pExportInfo->areaBox.IsReset()) ? &pExportInfo->areaBox : NULL;
  1496.  
  1497.         if (pBox && !Overlap::AABB_AABB(GetNodeBox(), *pBox))
  1498.                 return;
  1499.  
  1500.         uint32 nObjTypeMask = pExportInfo ? pExportInfo->nObjTypeMask : (uint32) ~0;
  1501.  
  1502.         for (int l = 0; l < eRNListType_ListsNum; l++)
  1503.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1504.                 {
  1505.                         EERType eType = pObj->GetRenderNodeType();
  1506.  
  1507.                         if (!(nObjTypeMask & (1 << eType)))
  1508.                                 continue;
  1509.  
  1510.                         if (eType == eERType_Brush)
  1511.                         {
  1512.                                 CBrush* pBrush = (CBrush*)pObj;
  1513.                                 if (CObjManager::GetItemId<IStatObj>(pStatObjTable, pBrush->GetEntityStatObj(), false) < 0)
  1514.                                         pStatObjTable->push_back(pBrush->m_pStatObj);
  1515.                         }
  1516.  
  1517.                         if (eType == eERType_Brush ||
  1518.                             eType == eERType_Road ||
  1519.                             eType == eERType_Decal ||
  1520.                             eType == eERType_WaterVolume ||
  1521.                             eType == eERType_DistanceCloud ||
  1522.                             eType == eERType_WaterWave)
  1523.                         {
  1524.                                 if ((eType != eERType_Brush || ((CBrush*)pObj)->m_pMaterial) && CObjManager::GetItemId(pMatTable, pObj->GetMaterial(), false) < 0)
  1525.                                         pMatTable->push_back(pObj->GetMaterial());
  1526.                         }
  1527.  
  1528.                         if (eType == eERType_Vegetation)
  1529.                         {
  1530.                                 CVegetation* pVegetation = (CVegetation*)pObj;
  1531.                                 IStatInstGroup& pStatInstGroup = pVegetation->GetStatObjGroup();
  1532.                                 stl::push_back_unique(*pStatInstGroupTable, &pStatInstGroup);
  1533.                         }
  1534.                         if (eType == eERType_MergedMesh)
  1535.                         {
  1536.                                 CMergedMeshRenderNode* pRN = (CMergedMeshRenderNode*)pObj;
  1537.                                 for (uint32 i = 0; i < pRN->NumGroups(); ++i)
  1538.                                 {
  1539.                                         int grpid = pRN->Group(i)->instGroupId;
  1540.                                         IStatInstGroup& pStatInstGroup = pRN->GetStatObjGroup(grpid);
  1541.                                         stl::push_back_unique(*pStatInstGroupTable, &pStatInstGroup);
  1542.                                 }
  1543.                         }
  1544.                         if (eType == eERType_Character)
  1545.                         {
  1546.                                 ICharacterInstance* pCharacter = pObj->GetEntityCharacter(0,nullptr,false);
  1547.                                 if (pCharacter)
  1548.                                         pMatTable->push_back(pCharacter->GetMaterial());
  1549.                         }
  1550.                 }
  1551.  
  1552.         for (int i = 0; i < 8; i++)
  1553.                 if (m_arrChilds[i])
  1554.                         m_arrChilds[i]->GenerateStatObjAndMatTables(pStatObjTable, pMatTable, pStatInstGroupTable, pExportInfo);
  1555. }
  1556.  
  1557. int COctreeNode::Cmp_OctreeNodeSize(const void* v1, const void* v2)
  1558. {
  1559.         COctreeNode* pNode1 = *((COctreeNode**)v1);
  1560.         COctreeNode* pNode2 = *((COctreeNode**)v2);
  1561.  
  1562.         if (pNode1->GetNodeRadius2() > pNode2->GetNodeRadius2())
  1563.                 return +1;
  1564.         if (pNode1->GetNodeRadius2() < pNode2->GetNodeRadius2())
  1565.                 return -1;
  1566.  
  1567.         return 0;
  1568. }
  1569.  
  1570. COctreeNode* COctreeNode::FindChildFor(IRenderNode* pObj, const AABB& objBox, const float fObjRadius, const Vec3& vObjCenter)
  1571. {
  1572.         int nChildId =
  1573.           ((vObjCenter.x > m_vNodeCenter.x) ? 4 : 0) |
  1574.           ((vObjCenter.y > m_vNodeCenter.y) ? 2 : 0) |
  1575.           ((vObjCenter.z > m_vNodeCenter.z) ? 1 : 0);
  1576.  
  1577.         if (!m_arrChilds[nChildId])
  1578.         {
  1579.                 m_arrChilds[nChildId] = COctreeNode::Create(m_nSID, GetChildBBox(nChildId), m_pVisArea, this);
  1580.         }
  1581.  
  1582.         return m_arrChilds[nChildId];
  1583. }
  1584.  
  1585. bool COctreeNode::HasChildNodes()
  1586. {
  1587.         if (!m_arrChilds[0] && !m_arrChilds[1] && !m_arrChilds[2] && !m_arrChilds[3])
  1588.                 if (!m_arrChilds[4] && !m_arrChilds[5] && !m_arrChilds[6] && !m_arrChilds[7])
  1589.                         return false;
  1590.  
  1591.         return true;
  1592. }
  1593.  
  1594. int COctreeNode::CountChildNodes()
  1595. {
  1596.         return
  1597.           (m_arrChilds[0] != 0) +
  1598.           (m_arrChilds[1] != 0) +
  1599.           (m_arrChilds[2] != 0) +
  1600.           (m_arrChilds[3] != 0) +
  1601.           (m_arrChilds[4] != 0) +
  1602.           (m_arrChilds[5] != 0) +
  1603.           (m_arrChilds[6] != 0) +
  1604.           (m_arrChilds[7] != 0);
  1605. }
  1606.  
  1607. void COctreeNode::ReleaseEmptyNodes()
  1608. {
  1609.         FUNCTION_PROFILER_3DENGINE;
  1610.  
  1611.         if (!m_arrEmptyNodes.Count())
  1612.                 return;
  1613.  
  1614.         // sort childs first
  1615.         qsort(m_arrEmptyNodes.GetElements(), m_arrEmptyNodes.Count(), sizeof(m_arrEmptyNodes[0]), Cmp_OctreeNodeSize);
  1616.  
  1617.         int nInitCunt = m_arrEmptyNodes.Count();
  1618.  
  1619.         for (int i = 0; i < nInitCunt && m_arrEmptyNodes.Count(); i++)
  1620.         {
  1621.                 COctreeNode* pNode = m_arrEmptyNodes[0];
  1622.  
  1623.                 if (pNode && pNode->IsEmpty())
  1624.                 {
  1625.                         COctreeNode* pParent = pNode->m_pParent;
  1626.  
  1627.                         // unregister in parent
  1628.                         for (int n = 0; n < 8; n++)
  1629.                                 if (pParent->m_arrChilds[n] == pNode)
  1630.                                         pParent->m_arrChilds[n] = NULL;
  1631.  
  1632.                         delete pNode;
  1633.  
  1634.                         // request parent validation
  1635.                         if (pParent && pParent->IsEmpty() && m_arrEmptyNodes.Find(pParent) < 0)
  1636.                                 m_arrEmptyNodes.Add(pParent);
  1637.                 }
  1638.  
  1639.                 // remove from list
  1640.                 m_arrEmptyNodes.Delete(pNode);
  1641.         }
  1642. }
  1643.  
  1644. void COctreeNode::StreamingCheckUnload(const SRenderingPassInfo& passInfo, PodArray<SObjManPrecacheCamera>& rPreCacheCameras)
  1645. {
  1646.         FUNCTION_PROFILER_3DENGINE;
  1647.  
  1648.         if (!m_arrStreamedInNodes.Count())
  1649.                 return;
  1650.  
  1651.         // sort childs first
  1652.         qsort(m_arrStreamedInNodes.GetElements(), m_arrStreamedInNodes.Count(), sizeof(m_arrStreamedInNodes[0]), Cmp_OctreeNodeSize);
  1653.  
  1654.         int nMaxTestsPerFrame = m_arrStreamedInNodes.Count() / 30 + 1;
  1655.  
  1656.         static int nCurNodeId = -1;
  1657.  
  1658.         const float fMaxViewDistance = Get3DEngine()->GetMaxViewDistance();
  1659.  
  1660.         for (int t = 0; t < nMaxTestsPerFrame && m_arrStreamedInNodes.Count(); t++)
  1661.         {
  1662.                 nCurNodeId++;
  1663.                 if (nCurNodeId >= m_arrStreamedInNodes.Count())
  1664.                         nCurNodeId = 0;
  1665.  
  1666.                 COctreeNode* pNode = m_arrStreamedInNodes[nCurNodeId];
  1667.  
  1668.                 bool bOldRound = CObjManager::m_nUpdateStreamingPrioriryRoundId > (pNode->m_nUpdateStreamingPrioriryRoundId + (int)2);
  1669.  
  1670.                 if (pNode->m_eStreamingStatus == ecss_Ready && pNode->m_nFileDataOffset && bOldRound)
  1671.                 {
  1672.                         pNode->ReleaseStreamableContent();
  1673.  
  1674.                         m_arrStreamedInNodes.Delete(pNode);
  1675.  
  1676.                         nCurNodeId--;
  1677.                 }
  1678.         }
  1679.  
  1680.         // TODO: hard limit number of loaded nodes
  1681. }
  1682.  
  1683. void COctreeNode::StaticReset()
  1684. {
  1685.         ReleaseEmptyNodes();
  1686.         stl::free_container(m_arrEmptyNodes);
  1687.  
  1688.         if (COctreeNode::m_pFileForSyncRead)
  1689.                 GetPak()->FClose(COctreeNode::m_pFileForSyncRead);
  1690.         COctreeNode::m_pFileForSyncRead = 0;
  1691. }
  1692.  
  1693. static float Distance_PrecacheCam_AABBSq(const SObjManPrecacheCamera& a, const AABB& b)
  1694. {
  1695.         float d2 = 0.0f;
  1696.  
  1697.         if (a.bbox.max.x < b.min.x) d2 += sqr(b.min.x - a.bbox.max.x);
  1698.         if (b.max.x < a.bbox.min.x) d2 += sqr(a.bbox.min.x - b.max.x);
  1699.         if (a.bbox.max.y < b.min.y) d2 += sqr(b.min.y - a.bbox.max.y);
  1700.         if (b.max.y < a.bbox.min.y) d2 += sqr(a.bbox.min.y - b.max.y);
  1701.         if (a.bbox.max.z < b.min.z) d2 += sqr(b.min.z - a.bbox.max.z);
  1702.         if (b.max.z < a.bbox.min.z) d2 += sqr(a.bbox.min.z - b.max.z);
  1703.  
  1704.         return d2;
  1705. }
  1706.  
  1707. bool COctreeNode::UpdateStreamingPriority(PodArray<COctreeNode*>& arrRecursion, float fMinDist, float fMaxDist, bool bFullUpdate, const SObjManPrecacheCamera* pPrecacheCams, size_t nPrecacheCams, const SRenderingPassInfo& passInfo)
  1708. {
  1709.         //  FUNCTION_PROFILER_3DENGINE;
  1710.  
  1711.         float fNodeDistanceNB = GetNodeStreamingDistance(pPrecacheCams, GetNodeBox(), nPrecacheCams, passInfo);
  1712.  
  1713.         float fObjMaxViewDistance = m_vNodeAxisRadius.x * GetCVars()->e_ObjectsTreeNodeSizeRatio * GetCVars()->e_ViewDistRatio * GetCVars()->e_StreamInstancesDistRatio;
  1714.  
  1715.         if (fNodeDistanceNB > min(fObjMaxViewDistance, fMaxDist) + GetFloatCVar(e_StreamPredictionDistanceFar))
  1716.                 return true;
  1717.  
  1718.         CheckStartStreaming(bFullUpdate);
  1719.  
  1720.         float fNodeDistance = GetNodeStreamingDistance(pPrecacheCams, GetNodeBox(), nPrecacheCams, passInfo);
  1721.  
  1722.         if (fNodeDistance > min(m_fObjectsMaxViewDist, fMaxDist) + GetFloatCVar(e_StreamPredictionDistanceFar)) // add || m_objectsBox.IsReset()
  1723.                 return true;
  1724.  
  1725.         if (!IsCompiled())
  1726.                 CompileObjects();
  1727.  
  1728.         const float fPredictionDistanceFar = GetFloatCVar(e_StreamPredictionDistanceFar);
  1729.  
  1730.         if (fNodeDistance > min(m_fObjectsMaxViewDist, fMaxDist) + fPredictionDistanceFar)
  1731.                 return true;
  1732.  
  1733.         if (GetCVars()->e_VegetationSpritesBatching && GetCVars()->e_VegetationSprites)
  1734.                 CheckManageVegetationSprites(fNodeDistance, 64, passInfo);
  1735.  
  1736.         AABB objBox;
  1737.  
  1738.         const bool bEnablePerNodeDistance = GetCVars()->e_StreamCgfUpdatePerNodeDistance > 0;
  1739.         CVisArea* pRoot0 = GetVisAreaManager() ? GetVisAreaManager()->GetCurVisArea() : NULL;
  1740.  
  1741.         float fMinDistSq = fMinDist * fMinDist;
  1742.  
  1743.         PREFAST_SUPPRESS_WARNING(6255)
  1744.         float* pfMinVisAreaDistSq = (float*)alloca(sizeof(float) * nPrecacheCams);
  1745.  
  1746.         for (size_t iPrecacheCam = 0; iPrecacheCam < nPrecacheCams; ++iPrecacheCam)
  1747.         {
  1748.                 float fMinVisAreaDist = 0.0f;
  1749.  
  1750.                 if (pRoot0)
  1751.                 {
  1752.                         // search from camera to entity visarea or outdoor
  1753.                         AABB aabbCam = pPrecacheCams[iPrecacheCam].bbox;
  1754.                         float fResDist = 10000.0f;
  1755.                         if (pRoot0->GetDistanceThruVisAreas(aabbCam, m_pVisArea, m_objectsBox, bFullUpdate ? 2 : GetCVars()->e_StreamPredictionMaxVisAreaRecursion, fResDist))
  1756.                                 fMinVisAreaDist = fResDist;
  1757.                 }
  1758.                 else if (m_pVisArea)
  1759.                 {
  1760.                         // search from entity to outdoor
  1761.                         AABB aabbCam = pPrecacheCams[iPrecacheCam].bbox;
  1762.                         float fResDist = 10000.0f;
  1763.                         if (m_pVisArea->GetDistanceThruVisAreas(m_objectsBox, NULL, aabbCam, bFullUpdate ? 2 : GetCVars()->e_StreamPredictionMaxVisAreaRecursion, fResDist))
  1764.                                 fMinVisAreaDist = fResDist;
  1765.                 }
  1766.  
  1767.                 pfMinVisAreaDistSq[iPrecacheCam] = fMinVisAreaDist * fMinVisAreaDist;
  1768.         }
  1769.  
  1770.         for (int l = 0; l < eRNListType_ListsNum; l++)
  1771.         {
  1772.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  1773.                 {
  1774.                         if (pObj->m_pNext)
  1775.                                 cryPrefetchT0SSE(pObj->m_pNext);
  1776.  
  1777.                         IF (pObj->m_dwRndFlags & ERF_HIDDEN, 0)
  1778.                                 continue;
  1779.  
  1780. #ifdef _DEBUG
  1781.                         const char* szName = pObj->GetName();
  1782.                         const char* szClassName = pObj->GetEntityClassName();
  1783.  
  1784.                         if (pObj->GetRndFlags() & ERF_SELECTED)
  1785.                         {
  1786.                                 int selected = 1;
  1787.                         }
  1788. #endif // _DEBUG
  1789.  
  1790.                         pObj->FillBBox(objBox);
  1791.  
  1792.                         // stream more in zoom mode if in frustum
  1793.                         float fZoomFactorSq = (passInfo.IsZoomActive() && passInfo.GetCamera().IsAABBVisible_E(objBox))
  1794.                                               ? passInfo.GetZoomFactor() * passInfo.GetZoomFactor()
  1795.                                               : 1.0f;
  1796.  
  1797.                         for (size_t iPrecacheCam = 0; iPrecacheCam < nPrecacheCams; ++iPrecacheCam)
  1798.                         {
  1799.                                 const Vec3& pcPosition = pPrecacheCams[iPrecacheCam].vPosition;
  1800.  
  1801.                                 float fEntDistanceSq = Distance_PrecacheCam_AABBSq(pPrecacheCams[iPrecacheCam], objBox);
  1802.  
  1803.                                 if (pObj->GetRenderNodeType() == eERType_Vegetation && ((CVegetation*)pObj)->m_pInstancingInfo)
  1804.                                 {
  1805.                                         // for instance groups compute distance to the center of bbox
  1806.                                         AABB objBoxS = AABB(objBox.GetCenter() - Vec3(.1f, .1f, .1f), objBox.GetCenter() + Vec3(.1f, .1f, .1f));
  1807.                                         fEntDistanceSq = Distance_PrecacheCam_AABBSq(pPrecacheCams[iPrecacheCam], objBoxS);
  1808.                                 }
  1809.  
  1810.                                 fEntDistanceSq = max(fEntDistanceSq, fMinDistSq);
  1811.                                 fEntDistanceSq *= fZoomFactorSq;
  1812.                                 fEntDistanceSq = max(fEntDistanceSq, pfMinVisAreaDistSq[iPrecacheCam]);
  1813.  
  1814.                                 float fMaxDistComb = min(pObj->m_fWSMaxViewDist, fMaxDist) + fPredictionDistanceFar;
  1815.                                 float fMaxDistCombSq = fMaxDistComb * fMaxDistComb;
  1816.  
  1817.                                 if (/*fMinDistSq <= fEntDistanceSq &&*/ fEntDistanceSq < fMaxDistCombSq)
  1818.                                 {
  1819.                                         float fEntDistance = sqrt_tpl(fEntDistanceSq);
  1820.                                         assert(fEntDistance >= 0 && _finite(fEntDistance));
  1821.  
  1822.                                         float fDist = fEntDistance;
  1823.                                         if (!bFullUpdate && fEntDistance < fNodeDistance && bEnablePerNodeDistance)
  1824.                                                 fDist = fNodeDistance;
  1825.  
  1826.                                         // If we're inside the object, very close, or facing the object, set importance scale to 1.0f. Otherwise, 0.8f.
  1827.                                         float fImportanceScale = (float)__fsel(
  1828.                                           4.0f - fEntDistance,
  1829.                                           1.0f,
  1830.                                           (float)__fsel(
  1831.                                             (objBox.GetCenter() - pcPosition).Dot(pPrecacheCams[iPrecacheCam].vDirection),
  1832.                                             1.0f,
  1833.                                             0.8f));
  1834.  
  1835.                                         // I replaced fEntDistance with fNoideDistance here because of Timur request! It's suppose to be unified to-node-distance
  1836.                                         GetObjManager()->UpdateRenderNodeStreamingPriority(pObj, fDist, fImportanceScale, bFullUpdate, passInfo);
  1837.                                 }
  1838.                         }
  1839.                 }
  1840.         }
  1841.  
  1842.         // Prioritise the first camera (probably the real camera)
  1843.         int nFirst =
  1844.           ((pPrecacheCams[0].vPosition.x > m_vNodeCenter.x) ? 4 : 0) |
  1845.           ((pPrecacheCams[0].vPosition.y > m_vNodeCenter.y) ? 2 : 0) |
  1846.           ((pPrecacheCams[0].vPosition.z > m_vNodeCenter.z) ? 1 : 0);
  1847.  
  1848.         if (m_arrChilds[nFirst])
  1849.                 arrRecursion.Add(m_arrChilds[nFirst]);
  1850.  
  1851.         if (m_arrChilds[nFirst ^ 1])
  1852.                 arrRecursion.Add(m_arrChilds[nFirst ^ 1]);
  1853.  
  1854.         if (m_arrChilds[nFirst ^ 2])
  1855.                 arrRecursion.Add(m_arrChilds[nFirst ^ 2]);
  1856.  
  1857.         if (m_arrChilds[nFirst ^ 4])
  1858.                 arrRecursion.Add(m_arrChilds[nFirst ^ 4]);
  1859.  
  1860.         if (m_arrChilds[nFirst ^ 3])
  1861.                 arrRecursion.Add(m_arrChilds[nFirst ^ 3]);
  1862.  
  1863.         if (m_arrChilds[nFirst ^ 5])
  1864.                 arrRecursion.Add(m_arrChilds[nFirst ^ 5]);
  1865.  
  1866.         if (m_arrChilds[nFirst ^ 6])
  1867.                 arrRecursion.Add(m_arrChilds[nFirst ^ 6]);
  1868.  
  1869.         if (m_arrChilds[nFirst ^ 7])
  1870.                 arrRecursion.Add(m_arrChilds[nFirst ^ 7]);
  1871.  
  1872.         return true;
  1873. }
  1874.  
  1875. int COctreeNode::Load(FILE*& f, int& nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, EEndian eEndian, AABB* pBox, const SLayerVisibility* pLayerVisibilityMask, const Vec3& segmentOffset)
  1876. {
  1877.         return Load_T(f, nDataSize, pStatObjTable, pMatTable, eEndian, pBox, pLayerVisibilityMask, segmentOffset);
  1878. }
  1879. int COctreeNode::Load(uint8*& f, int& nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, EEndian eEndian, AABB* pBox, const SLayerVisibility* pLayerVisibilityMask, const Vec3& segmentOffset)
  1880. {
  1881.         return Load_T(f, nDataSize, pStatObjTable, pMatTable, eEndian, pBox, pLayerVisibilityMask, segmentOffset);
  1882. }
  1883.  
  1884. int FTell(FILE*& f)  { return Cry3DEngineBase::GetPak()->FTell(f); }
  1885. int FTell(uint8*& f) { return 0; }
  1886.  
  1887. template<class T>
  1888. int COctreeNode::Load_T(T*& f, int& nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, EEndian eEndian, AABB* pBox, const SLayerVisibility* pLayerVisibilityMask, const Vec3& segmentOffset)
  1889. {
  1890.         if (pBox && !Overlap::AABB_AABB(GetNodeBox(), *pBox))
  1891.                 return 0;
  1892.  
  1893.         // remember file offset for streaming
  1894.         m_nFileDataOffset = FTell(f);
  1895.  
  1896.         SOcTreeNodeChunk chunk;
  1897.  
  1898.         ELoadObjectsMode eLoadObjectsMode = (GetCVars()->e_StreamInstances && !gEnv->IsEditor()) ? LOM_LOAD_ONLY_NON_STREAMABLE : LOM_LOAD_ALL;
  1899.  
  1900.         if (!ReadObjects(f, nDataSize, eEndian, pStatObjTable, pMatTable, pLayerVisibilityMask, segmentOffset, chunk, eLoadObjectsMode))
  1901.                 return 0;
  1902.  
  1903.         if (chunk.nObjectsBlockSize)
  1904.         {
  1905.                 m_nFileDataSize = chunk.nObjectsBlockSize + sizeof(SOcTreeNodeChunk);
  1906.                 m_nNodesCounterStreamable++;
  1907.         }
  1908.         else
  1909.                 m_nFileDataSize = m_nFileDataOffset = 0;
  1910.  
  1911.         // count number of nodes loaded
  1912.         int nNodesNum = 1;
  1913.  
  1914.         // process childs
  1915.         for (int nChildId = 0; nChildId < 8; nChildId++)
  1916.         {
  1917.                 if (chunk.ucChildsMask & (1 << nChildId))
  1918.                 {
  1919.                         if (!m_arrChilds[nChildId])
  1920.                         {
  1921.                                 m_arrChilds[nChildId] = COctreeNode::Create(m_nSID, GetChildBBox(nChildId), m_pVisArea, this);
  1922.                         }
  1923.  
  1924.                         int nNewNodesNum = m_arrChilds[nChildId]->Load_T(f, nDataSize, pStatObjTable, pMatTable, eEndian, pBox, pLayerVisibilityMask, segmentOffset);
  1925.  
  1926.                         if (!nNewNodesNum && !pBox)
  1927.                                 return 0; // data error
  1928.  
  1929.                         nNodesNum += nNewNodesNum;
  1930.                 }
  1931.         }
  1932.  
  1933.         return nNodesNum;
  1934. }
  1935.  
  1936. void COctreeNode::BuildLoadingDatas(PodArray<SOctreeLoadObjectsData>* pQueue, byte* pOrigData, byte*& pData, int& nDataSize, EEndian eEndian)
  1937. {
  1938.         SOcTreeNodeChunk chunk;
  1939.         CTerrain::LoadDataFromFile(&chunk, 1, pData, nDataSize, eEndian);
  1940.  
  1941.         assert(chunk.nChunkVersion == OCTREENODE_CHUNK_VERSION);
  1942.  
  1943.         if (chunk.nObjectsBlockSize)
  1944.         {
  1945.                 SOctreeLoadObjectsData data = { this, pData - pOrigData, size_t(chunk.nObjectsBlockSize) };
  1946.                 pQueue->Add(data);
  1947.  
  1948.                 pData += chunk.nObjectsBlockSize;
  1949.                 nDataSize -= chunk.nObjectsBlockSize;
  1950.         }
  1951.  
  1952.         for (int nChildId = 0; nChildId < 8; nChildId++)
  1953.         {
  1954.                 if (chunk.ucChildsMask & (1 << nChildId))
  1955.                 {
  1956.                         if (!m_arrChilds[nChildId])
  1957.                         {
  1958.                                 MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Terrain, EMemStatContextFlags::MSF_Instance, "Octree node");
  1959.                                 m_arrChilds[nChildId] = new COctreeNode(m_nSID, GetChildBBox(nChildId), m_pVisArea, this);
  1960.                         }
  1961.  
  1962.                         m_arrChilds[nChildId]->BuildLoadingDatas(pQueue, pOrigData, pData, nDataSize, eEndian);
  1963.                 }
  1964.         }
  1965. }
  1966.  
  1967. bool COctreeNode::StreamLoad(uint8* pData, int nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, EEndian eEndian, AABB* pBox)
  1968. {
  1969.         int64 ticks = CryGetTicks();
  1970.         if (m_streamComplete)
  1971.                 return false;
  1972.  
  1973.         if (m_loadingDatas.size() == 0)
  1974.         {
  1975.                 BuildLoadingDatas(&m_loadingDatas, pData, pData, nDataSize, eEndian);
  1976.         }
  1977.         else
  1978.         {
  1979.                 SOctreeLoadObjectsData& data = m_loadingDatas[0];
  1980.  
  1981.                 if (data.pMemBlock == 0)
  1982.                 {
  1983.                         pData += data.offset;
  1984.                         nDataSize -= (int)data.offset;
  1985.  
  1986.                         // load objects data into memory buffer, make sure buffer is aligned
  1987.                         _smart_ptr<IMemoryBlock> pMemBlock = gEnv->pCryPak->PoolAllocMemoryBlock(data.size + 8, "LoadObjectInstances");
  1988.                         byte* pPtr = (byte*)pMemBlock->GetData();
  1989.                         while (UINT_PTR(pPtr) & 3)
  1990.                                 pPtr++;
  1991.  
  1992.                         if (!CTerrain::LoadDataFromFile(pPtr, data.size, pData, nDataSize, eEndian))
  1993.                                 return false;
  1994.  
  1995.                         data.pMemBlock = pMemBlock;
  1996.                         data.pObjPtr = pPtr;
  1997.                         data.pEndObjPtr = pPtr + data.size;
  1998.                 }
  1999.                 else
  2000.                 {
  2001.                         // if we are not in segmented world mode then the offset is 0
  2002.                         Vec3 segmentOffset(0, 0, 0);
  2003.                         if (Get3DEngine()->m_pSegmentsManager)
  2004.                         {
  2005.                                 segmentOffset = GetTerrain()->GetSegmentOrigin(m_nSID);
  2006.                         }
  2007.  
  2008.                         IRenderNode* pRN = 0;
  2009.                         data.pNode->LoadSingleObject(data.pObjPtr, pStatObjTable, pMatTable, eEndian, OCTREENODE_CHUNK_VERSION, NULL, m_nSID, segmentOffset, LOM_LOAD_ALL, pRN);
  2010.                         if (data.pObjPtr >= data.pEndObjPtr)
  2011.                                 m_loadingDatas.Delete(0);
  2012.                 }
  2013.         }
  2014.         m_streamComplete = m_loadingDatas.size() == 0;
  2015.         return !m_streamComplete;
  2016. }
  2017.  
  2018. #if ENGINE_ENABLE_COMPILATION
  2019. int COctreeNode::GetData(byte*& pData, int& nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, EEndian eEndian, SHotUpdateInfo* pExportInfo, const Vec3& segmentOffset)
  2020. {
  2021.         AABB* pBox = (pExportInfo && !pExportInfo->areaBox.IsReset()) ? &pExportInfo->areaBox : NULL;
  2022.  
  2023.         const AABB& nodeBox = GetNodeBox();
  2024.         if (pBox && !Overlap::AABB_AABB(nodeBox, *pBox))
  2025.                 return 0;
  2026.  
  2027.         if (pData)
  2028.         {
  2029.                 // get node data
  2030.                 SOcTreeNodeChunk chunk;
  2031.                 chunk.nChunkVersion = OCTREENODE_CHUNK_VERSION;
  2032.                 chunk.nodeBox = nodeBox;
  2033.  
  2034.                 // fill ChildsMask
  2035.                 chunk.ucChildsMask = 0;
  2036.                 for (int i = 0; i < 8; i++)
  2037.                         if (m_arrChilds[i])
  2038.                                 chunk.ucChildsMask |= (1 << i);
  2039.  
  2040.                 CMemoryBlock memblock;
  2041.                 SaveObjects(&memblock, pStatObjTable, pMatTable, pStatInstGroupTable, eEndian, pExportInfo, segmentOffset);
  2042.  
  2043.                 chunk.nObjectsBlockSize = memblock.GetSize();
  2044.  
  2045.                 AddToPtr(pData, nDataSize, chunk, eEndian);
  2046.  
  2047.                 AddToPtr(pData, nDataSize, (byte*)memblock.GetData(), memblock.GetSize(), eEndian);
  2048.         }
  2049.         else // just count size
  2050.         {
  2051.                 nDataSize += sizeof(SOcTreeNodeChunk);
  2052.                 nDataSize += SaveObjects(NULL, NULL, NULL, NULL, eEndian, pExportInfo, segmentOffset);
  2053.         }
  2054.  
  2055.         // count number of nodes loaded
  2056.         int nNodesNum = 1;
  2057.  
  2058.         // process childs
  2059.         for (int i = 0; i < 8; i++)
  2060.                 if (m_arrChilds[i])
  2061.                         nNodesNum += m_arrChilds[i]->GetData(pData, nDataSize, pStatObjTable, pMatTable, pStatInstGroupTable, eEndian, pExportInfo, segmentOffset);
  2062.  
  2063.         return nNodesNum;
  2064. }
  2065. #endif
  2066.  
  2067. bool COctreeNode::CleanUpTree()
  2068. {
  2069.         //  FreeAreaBrushes();
  2070.  
  2071.         bool bChildObjectsFound = false;
  2072.         for (int i = 0; i < 8; i++)
  2073.         {
  2074.                 if (m_arrChilds[i])
  2075.                 {
  2076.                         if (!m_arrChilds[i]->CleanUpTree())
  2077.                         {
  2078.                                 delete m_arrChilds[i];
  2079.                                 m_arrChilds[i] = NULL;
  2080.                         }
  2081.                         else
  2082.                                 bChildObjectsFound = true;
  2083.                 }
  2084.         }
  2085.  
  2086.         // update max view distances
  2087.  
  2088.         m_fObjectsMaxViewDist = 0.f;
  2089.         m_objectsBox = GetNodeBox();
  2090.  
  2091.         for (int l = 0; l < eRNListType_ListsNum; l++)
  2092.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  2093.                 {
  2094.                         pObj->m_fWSMaxViewDist = pObj->GetMaxViewDist();
  2095.                         m_fObjectsMaxViewDist = max(m_fObjectsMaxViewDist, pObj->m_fWSMaxViewDist);
  2096.                         m_objectsBox.Add(pObj->GetBBox());
  2097.                 }
  2098.  
  2099.         for (int i = 0; i < 8; i++)
  2100.         {
  2101.                 if (m_arrChilds[i])
  2102.                 {
  2103.                         m_fObjectsMaxViewDist = max(m_fObjectsMaxViewDist, m_arrChilds[i]->m_fObjectsMaxViewDist);
  2104.                         m_objectsBox.Add(m_arrChilds[i]->m_objectsBox);
  2105.                 }
  2106.         }
  2107.  
  2108.         return (bChildObjectsFound || HasObjects());
  2109. }
  2110.  
  2111. void COctreeNode::FreeLoadingCache()
  2112. {
  2113. }
  2114.  
  2115. //////////////////////////////////////////////////////////////////////////
  2116. bool COctreeNode::CheckRenderFlagsMinSpec(uint32 dwRndFlags)
  2117. {
  2118.         int nRenderNodeMinSpec = (dwRndFlags & ERF_SPEC_BITS_MASK) >> ERF_SPEC_BITS_SHIFT;
  2119.         return CheckMinSpec(nRenderNodeMinSpec);
  2120. }
  2121.  
  2122. void COctreeNode::OffsetObjects(const Vec3& offset)
  2123. {
  2124.         SetCompiled(false);
  2125.         m_objectsBox.Move(offset);
  2126.         m_vNodeCenter += offset;
  2127.  
  2128.         for (int l = 0; l < eRNListType_ListsNum; l++)
  2129.         {
  2130.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  2131.                 {
  2132.                         pObj->OffsetPosition(offset);
  2133.                 }
  2134.         }
  2135.         for (int i = 0; i < 8; ++i)
  2136.                 if (m_arrChilds[i])
  2137.                         m_arrChilds[i]->OffsetObjects(offset);
  2138. }
  2139.  
  2140. bool COctreeNode::HasAnyRenderableCandidates(const SRenderingPassInfo& passInfo) const
  2141. {
  2142.         // This checks if anything will be rendered, assuming we pass occlusion checks
  2143.         // This is based on COctreeNode::RenderContentJobEntry's implementation,
  2144.         // if that would do nothing, we can skip the running of occlusion and rendering jobs for this node
  2145.         const bool bVegetation = passInfo.RenderVegetation() && m_arrObjects[eRNListType_Vegetation].m_pFirstNode != NULL;
  2146.         const bool bBrushes = passInfo.RenderBrushes() && m_arrObjects[eRNListType_Brush].m_pFirstNode != NULL;
  2147.         const bool bDecalsAndRoads = (passInfo.RenderDecals() || passInfo.RenderRoads()) && m_arrObjects[eRNListType_DecalsAndRoads].m_pFirstNode != NULL;
  2148.         const bool bUnknown = m_arrObjects[eRNListType_Unknown].m_pFirstNode != NULL;
  2149.         return bVegetation || bBrushes || bDecalsAndRoads || bUnknown;
  2150. }
  2151.  
  2152. template<class T>
  2153. int COctreeNode::ReadObjects(T*& f, int& nDataSize, EEndian eEndian, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, const SLayerVisibility* pLayerVisibilityMask, const Vec3& segmentOffset, SOcTreeNodeChunk& chunk, ELoadObjectsMode eLoadMode)
  2154. {
  2155.         if (!CTerrain::LoadDataFromFile(&chunk, 1, f, nDataSize, eEndian))
  2156.                 return 0;
  2157.  
  2158.         assert(chunk.nChunkVersion == OCTREENODE_CHUNK_VERSION);
  2159.         if (chunk.nChunkVersion != OCTREENODE_CHUNK_VERSION)
  2160.                 return 0;
  2161.  
  2162.         if (chunk.nObjectsBlockSize)
  2163.         {
  2164.                 {
  2165.                         _smart_ptr<IMemoryBlock> pMemBlock = gEnv->pCryPak->PoolAllocMemoryBlock(chunk.nObjectsBlockSize + 8, "LoadObjectInstances");
  2166.                         byte* pPtr = (byte*)pMemBlock->GetData();
  2167.  
  2168.                         while (UINT_PTR(pPtr) & 3)
  2169.                                 pPtr++;
  2170.  
  2171.                         if (!CTerrain::LoadDataFromFile(pPtr, chunk.nObjectsBlockSize, f, nDataSize, eEndian))
  2172.                                 return 0;
  2173.  
  2174.                         if (!m_bEditor || Get3DEngine()->IsSegmentOperationInProgress())
  2175.                                 LoadObjects(pPtr, pPtr + chunk.nObjectsBlockSize, pStatObjTable, pMatTable, eEndian, chunk.nChunkVersion, pLayerVisibilityMask, segmentOffset, eLoadMode);
  2176.                 }
  2177.  
  2178.                 if (eLoadMode != LOM_LOAD_ALL)
  2179.                 {
  2180.                         float fObjMaxViewDistance = m_vNodeAxisRadius.x * GetCVars()->e_ObjectsTreeNodeSizeRatio * GetCVars()->e_ViewDistRatio * GetCVars()->e_StreamInstancesDistRatio;
  2181.  
  2182.                         COctreeNode* pNode = this;
  2183.                         while (pNode)
  2184.                         {
  2185.                                 pNode->m_fObjectsMaxViewDist = max(pNode->m_fObjectsMaxViewDist, fObjMaxViewDistance);
  2186.                                 pNode = pNode->m_pParent;
  2187.                         }
  2188.                 }
  2189.         }
  2190.  
  2191.         return 1;
  2192. }
  2193.  
  2194. void COctreeNode::StartStreaming(bool bFinishNow, IReadStream_AutoPtr* ppStream)
  2195. {
  2196.         m_nInstStreamTasksInProgress++;
  2197.  
  2198.         assert(m_eStreamingStatus == ecss_NotLoaded);
  2199.  
  2200.         m_eStreamingStatus = ecss_InProgress;
  2201.  
  2202.         const char* szFileName = Get3DEngine()->GetLevelFilePath(COMPILED_HEIGHT_MAP_FILE_NAME);
  2203.  
  2204.         if (bFinishNow)
  2205.         {
  2206.                 // sync file load
  2207.                 if (!m_pFileForSyncRead)
  2208.                         m_pFileForSyncRead = GetPak()->FOpen(szFileName, "rb");
  2209.  
  2210.                 if (m_pFileForSyncRead)
  2211.                 {
  2212.                         GetPak()->FSeek(m_pFileForSyncRead, m_nFileDataOffset, SEEK_SET);
  2213.  
  2214.                         StreamOnCompleteReadObjects(m_pFileForSyncRead, m_nFileDataSize);
  2215.                 }
  2216.                 else
  2217.                 {
  2218.                         assert(!"File open error: COMPILED_HEIGHT_MAP_FILE_NAME");
  2219.                 }
  2220.         }
  2221.         else
  2222.         {
  2223.                 // start streaming
  2224.                 StreamReadParams params;
  2225.                 params.nOffset = m_nFileDataOffset;
  2226.                 params.nSize = m_nFileDataSize;
  2227.                 params.ePriority = estpAboveNormal;// (EStreamTaskPriority)CLAMP(int((float)estpIdle - log2(GetNodeBox().GetSize().x / fNodeMinSize)), int(estpUrgent), int(estpIdle));
  2228.  
  2229.                 m_pReadStream = GetSystem()->GetStreamEngine()->StartRead(eStreamTaskTypeGeometry, szFileName, this, &params);
  2230.         }
  2231. }
  2232.  
  2233. void COctreeNode::StreamOnComplete(IReadStream* pStream, unsigned nError)
  2234. {
  2235.         if (pStream->GetError() == ERROR_USER_ABORT)
  2236.         {
  2237.                 // valid situation
  2238.                 m_eStreamingStatus = ecss_NotLoaded;
  2239.                 m_nInstStreamTasksInProgress--;
  2240.                 m_pReadStream = 0;
  2241.         }
  2242.         else if (m_pReadStream && m_pReadStream->GetBuffer() && m_pReadStream->GetBytesRead())
  2243.         {
  2244.                 StreamOnCompleteReadObjects((byte*)m_pReadStream->GetBuffer(), m_pReadStream->GetBytesRead());
  2245.         }
  2246.         else if (m_pReadStream)
  2247.         {
  2248.                 PrintMessage("%s: Error: %s, BytesRead=%d", __FUNCTION__, pStream->GetErrorName(), m_pReadStream->GetBytesRead());
  2249.         }
  2250.         else
  2251.         {
  2252.                 PrintMessage("%s: Error: %s, Stream=NULL", __FUNCTION__, pStream->GetErrorName());
  2253.         }
  2254. }
  2255.  
  2256. template<class T>
  2257. void COctreeNode::StreamOnCompleteReadObjects(T* f, int nDataSize)
  2258. {
  2259.         FUNCTION_PROFILER_3DENGINE;
  2260.  
  2261.         SOcTreeNodeChunk chunk;
  2262.  
  2263.         C3DEngine* pEng = Get3DEngine();
  2264.  
  2265.         if (!ReadObjects(f, nDataSize, pEng->m_bLevelFilesEndian, pEng->m_pLevelStatObjTable, pEng->m_pLevelMaterialsTable, NULL, Vec3(0, 0, 0), chunk, LOM_LOAD_ONLY_STREAMABLE))
  2266.         {
  2267.                 PrintMessage("%s: Instances read error", __FUNCTION__);
  2268.         }
  2269.  
  2270.         //PrintMessage("Loaded %d KB for node size %.f", chunk.nObjectsBlockSize/1024, m_vNodeAxisRadius.x);
  2271.  
  2272.         SetCompiled(false);
  2273.  
  2274.         m_eStreamingStatus = ecss_Ready;
  2275.  
  2276.         m_nInstStreamTasksInProgress--;
  2277.  
  2278.         m_pReadStream = 0;
  2279.  
  2280.         assert(m_arrStreamedInNodes.Find(this) < 0);
  2281.  
  2282.         m_arrStreamedInNodes.Add(this);
  2283. }
  2284.  
  2285. bool COctreeNode::CheckStartStreaming(bool bFullUpdate)
  2286. {
  2287.         bool bSyncLoad = Get3DEngine()->IsStatObjSyncLoad();
  2288.  
  2289.         if (!gEnv->IsEditor() && GetCVars()->e_StreamInstances == 1 && m_nFileDataOffset && (m_nInstStreamTasksInProgress < GetCVars()->e_StreamInstancesMaxTasks || bSyncLoad))
  2290.         {
  2291.                 if (m_eStreamingStatus == ecss_NotLoaded)
  2292.                 {
  2293.                         StartStreaming(bSyncLoad, 0);
  2294.                 }
  2295.                 else if (m_eStreamingStatus == ecss_InProgress && m_pReadStream && bSyncLoad)
  2296.                 {
  2297.                         m_pReadStream->Abort();
  2298.                         assert(m_pReadStream == 0 && m_eStreamingStatus == ecss_NotLoaded);
  2299.  
  2300.                         StartStreaming(bSyncLoad, 0);
  2301.                 }
  2302.         }
  2303.  
  2304.         if (GetCVars()->e_StreamInstances == 1)
  2305.                 m_nUpdateStreamingPrioriryRoundId = CObjManager::m_nUpdateStreamingPrioriryRoundId;
  2306.  
  2307.         // return true if data is ready
  2308.         return gEnv->IsEditor() || !GetCVars()->e_StreamInstances || !m_nFileDataOffset || m_eStreamingStatus == ecss_Ready;
  2309. }
  2310.  
  2311. float COctreeNode::GetNodeStreamingDistance(const SObjManPrecacheCamera* pPrecacheCams, AABB objectsBox, size_t nPrecacheCams, const SRenderingPassInfo& passInfo)
  2312. {
  2313.         // Select the minimum distance to the node
  2314.         float fNodeDistanceSq = Distance_PrecacheCam_AABBSq(pPrecacheCams[0], objectsBox);
  2315.         for (size_t iPrecacheCam = 1; iPrecacheCam < nPrecacheCams; ++iPrecacheCam)
  2316.         {
  2317.                 float fPcNodeDistanceSq = Distance_PrecacheCam_AABBSq(pPrecacheCams[iPrecacheCam], objectsBox);
  2318.                 fNodeDistanceSq = min(fNodeDistanceSq, fPcNodeDistanceSq);
  2319.         }
  2320.  
  2321.         float fNodeDistance = sqrt_tpl(fNodeDistanceSq);
  2322.  
  2323.         if (passInfo.IsZoomActive() && passInfo.GetCamera().IsAABBVisible_E(GetNodeBox()))
  2324.                 fNodeDistance *= passInfo.GetZoomFactor();
  2325.  
  2326.         return fNodeDistance;
  2327. }
  2328.  
  2329. void COctreeNode::ReleaseStreamableContent()
  2330. {
  2331.         ReleaseObjects(true);
  2332.  
  2333.         m_eStreamingStatus = ecss_NotLoaded;
  2334.  
  2335.         SetCompiled(false);
  2336. }
  2337.  
  2338. void COctreeNode::ReleaseObjects(bool bReleaseOnlyStreamable)
  2339. {
  2340.         for (int l = 0; l < eRNListType_ListsNum; l++)
  2341.         {
  2342.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode, * pNext; pObj; pObj = pNext)
  2343.                 {
  2344.                         pNext = pObj->m_pNext;
  2345.  
  2346.                         if (pObj->IsAllocatedOutsideOf3DEngineDLL())
  2347.                         {
  2348.                                 if (!bReleaseOnlyStreamable)
  2349.                                         Get3DEngine()->UnRegisterEntityDirect(pObj);
  2350.                         }
  2351.                         else
  2352.                         {
  2353.                                 if (!bReleaseOnlyStreamable || IsObjectStreamable(pObj->GetRenderNodeType(), pObj->m_dwRndFlags))
  2354.                                 {
  2355.                                         if (IsObjectStreamable(pObj->GetRenderNodeType(), pObj->m_dwRndFlags))
  2356.                                                 m_nInstCounterLoaded--;
  2357.  
  2358.                                         pObj->ReleaseNode(true);
  2359.                                 }
  2360.                         }
  2361.                 }
  2362.  
  2363.                 assert(!m_arrObjects[l].m_pFirstNode || bReleaseOnlyStreamable);
  2364.         }
  2365. }
  2366. void COctreeNode::ResetStaticInstancing()
  2367. {
  2368.         FUNCTION_PROFILER_3DENGINE;
  2369.  
  2370.         for (IRenderNode* pObj = m_arrObjects[eRNListType_Vegetation].m_pFirstNode, * pNext; pObj; pObj = pNext)
  2371.         {
  2372.                 pNext = pObj->m_pNext;
  2373.  
  2374.                 CVegetation* pInst = (CVegetation*)pObj;
  2375.  
  2376.                 pObj->m_dwRndFlags &= ~ERF_STATIC_INSTANCING;
  2377.  
  2378.                 if (pInst->m_pInstancingInfo)
  2379.                 {
  2380.                         SAFE_DELETE(pInst->m_pInstancingInfo)
  2381.  
  2382.                         pInst->InvalidatePermanentRenderObject();
  2383.                 }
  2384.         }
  2385.  
  2386.         if (m_pStaticInstancingInfo)
  2387.         {
  2388.                 for (auto it = m_pStaticInstancingInfo->begin(); it != m_pStaticInstancingInfo->end(); )
  2389.                 {
  2390.                         PodArray<SNodeInstancingInfo>*& pInfo = it->second;
  2391.  
  2392.                         pInfo->Reset();
  2393.  
  2394.                         it = m_pStaticInstancingInfo->erase(it);
  2395.                 }
  2396.  
  2397.                 SAFE_DELETE(m_pStaticInstancingInfo);
  2398.         }
  2399.  
  2400.         m_bStaticInstancingIsDirty = true;
  2401. }
  2402.  
  2403. void COctreeNode::CheckUpdateStaticInstancing()
  2404. {
  2405.         WriteLock lock(m_updateStaticInstancingLock);
  2406.  
  2407.         if (GetCVars()->e_StaticInstancing && m_arrObjects[eRNListType_Vegetation].m_pFirstNode)
  2408.         {
  2409.                 if (m_bStaticInstancingIsDirty)
  2410.                         UpdateStaticInstancing();
  2411.         }
  2412.         else if (m_pStaticInstancingInfo)
  2413.         {
  2414.                 ResetStaticInstancing();
  2415.         }
  2416. }
  2417.  
  2418. COctreeNode::COctreeNode(int nSID, const AABB& box, CVisArea* pVisArea, COctreeNode* pParent)
  2419. {
  2420.         m_fPrevTerrainTexScale = 0;
  2421.         m_updateStaticInstancingLock = 0;
  2422.  
  2423.         m_nOccludedFrameId = 0;
  2424.         m_renderFlags = 0;
  2425.         m_errTypesBitField = 0;
  2426.         m_fObjectsMaxViewDist = 0;
  2427.         m_nLastVisFrameId = 0;
  2428.  
  2429.         ZeroStruct(m_arrChilds);
  2430.         ZeroStruct(m_arrObjects);
  2431.         m_nLightMaskFrameId = 0;
  2432.         nFillShadowCastersSkipFrameId = 0;
  2433.         m_fNodeDistance = 0;
  2434.         m_nManageVegetationsFrameId = 0;
  2435.  
  2436.         m_bHasLights = 0;
  2437.         m_bHasRoads = 0;
  2438.         m_bNodeCompletelyInFrustum = 0;
  2439.  
  2440.         m_nFileDataOffset = 0;
  2441.         m_nFileDataSize = 0;
  2442.         m_eStreamingStatus = ecss_NotLoaded;
  2443.         m_pReadStream = 0;
  2444.         m_nUpdateStreamingPrioriryRoundId = -1;
  2445.  
  2446.         m_nSID = nSID;
  2447.         m_vNodeCenter = box.GetCenter();
  2448.         m_vNodeAxisRadius = box.GetSize() * 0.5f;
  2449.         m_objectsBox.min = box.max;
  2450.         m_objectsBox.max = box.min;
  2451.  
  2452. #if !defined(_RELEASE)
  2453.         // Check if bounding box is crazy
  2454. #define CHECK_OBJECTS_BOX_WARNING_SIZE (1.0e+10f)
  2455.         if (GetCVars()->e_CheckOctreeObjectsBoxSize != 0) // pParent is checked as silly sized things are added to the root (e.g. the sun)
  2456.                 if (pParent && (m_objectsBox.min.len() > CHECK_OBJECTS_BOX_WARNING_SIZE || m_objectsBox.max.len() > CHECK_OBJECTS_BOX_WARNING_SIZE))
  2457.                         CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_ERROR_DBGBRK, "COctreeNode being created with a huge m_objectsBox: [%f %f %f] -> [%f %f %f]\n", m_objectsBox.min.x, m_objectsBox.min.y, m_objectsBox.min.z, m_objectsBox.max.x, m_objectsBox.max.y, m_objectsBox.max.z);
  2458. #endif
  2459.  
  2460.         SetTerrainNode(m_nSID >= 0 && GetTerrain() ? GetTerrain()->FindMinNodeContainingBox(box, m_nSID) : NULL);
  2461.         m_pVisArea = pVisArea;
  2462.         m_pParent = pParent;
  2463.         m_streamComplete = false;
  2464.  
  2465.         //      for(int n=0; n<2 && m_pTerrainNode && m_pTerrainNode->m_pParent; n++)
  2466.         //      m_pTerrainNode = m_pTerrainNode->m_pParent;
  2467.         m_fpSunDirX = 63;
  2468.         m_fpSunDirZ = 0;
  2469.         m_fpSunDirYs = 0;
  2470.  
  2471.         m_pStaticInstancingInfo = 0;
  2472.         m_bStaticInstancingIsDirty = 0;
  2473. }
  2474.  
  2475. //////////////////////////////////////////////////////////////////////////
  2476. COctreeNode* COctreeNode::Create(int nSID, const AABB& box, struct CVisArea* pVisArea, COctreeNode* pParent)
  2477. {
  2478.         MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Terrain, EMemStatContextFlags::MSF_Instance, "Octree node");
  2479.         m_nNodesCounterAll++;
  2480.         return new COctreeNode(nSID, box, pVisArea, pParent);
  2481. }
  2482.  
  2483. //////////////////////////////////////////////////////////////////////////
  2484. bool COctreeNode::HasObjects()
  2485. {
  2486.         if (m_nFileDataOffset)
  2487.                 return true;
  2488.  
  2489.         for (int l = 0; l < eRNListType_ListsNum; l++)
  2490.                 if (m_arrObjects[l].m_pFirstNode)
  2491.                         return true;
  2492.  
  2493.         return false;
  2494. }
  2495.  
  2496. //////////////////////////////////////////////////////////////////////////
  2497. void COctreeNode::RenderContent(int nRenderMask, const Vec3& vAmbColor, const SRenderingPassInfo& passInfo)
  2498. {
  2499.         if (GetCVars()->e_StatObjBufferRenderTasks == 1 && passInfo.IsGeneralPass() && JobManager::InvokeAsJob("CheckOcclusion"))
  2500.                 GetObjManager()->AddCullJobProducer();
  2501.         IF(m_pRenderContentJobQueue == NULL, 0)
  2502.         {
  2503.                 m_pRenderContentJobQueue = CryAlignedNew<TRenderContentJobQueue>();
  2504.         }
  2505.         TRenderContentJob::packet packet(nRenderMask, vAmbColor, passInfo);
  2506.         packet.SetClassInstance(this);
  2507.         static_cast<TRenderContentJobQueue*>(m_pRenderContentJobQueue)->AddPacket(packet, JobManager::eHighPriority);
  2508. }
  2509.  
  2510. //////////////////////////////////////////////////////////////////////////
  2511. void COctreeNode::DeallocateRenderContentQueue()
  2512. {
  2513.         if (m_pRenderContentJobQueue != NULL)
  2514.         {
  2515.                 CryAlignedDelete(static_cast<TRenderContentJobQueue*>(m_pRenderContentJobQueue));
  2516.                 m_pRenderContentJobQueue = NULL;
  2517.         }
  2518. }
  2519.  
  2520. //////////////////////////////////////////////////////////////////////////
  2521. void COctreeNode::RenderContentJobEntry(int nRenderMask, Vec3 vAmbColor, SRenderingPassInfo passInfo)
  2522. {
  2523.         PodArray<CDLight*>* pAffectingLights = GetAffectingLights(passInfo);
  2524.         bool bSunOnly = pAffectingLights && (pAffectingLights->Count() == 1) && (pAffectingLights->GetAt(0)->m_Flags & DLF_SUN) && !m_pVisArea;
  2525.  
  2526.         SSectorTextureSet* pTerrainTexInfo = NULL;
  2527.  
  2528.         if (GetCVars()->e_VegetationUseTerrainColor)
  2529.                 GetObjManager()->FillTerrainTexInfo(this, m_fNodeDistance, pTerrainTexInfo, m_objectsBox);
  2530.  
  2531.         // Detect if terrain texturing is changed
  2532.         if (m_fPrevTerrainTexScale != (pTerrainTexInfo ? pTerrainTexInfo->fTexScale : 0))
  2533.         {
  2534.                 m_fPrevTerrainTexScale = (pTerrainTexInfo ? pTerrainTexInfo->fTexScale : 0);
  2535.  
  2536.                 for (unsigned int nListId = eRNListType_First; nListId < eRNListType_ListsNum; ++nListId)
  2537.                 {
  2538.                         for (IRenderNode* pObj = m_arrObjects[nListId].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  2539.                         {
  2540.                                 // Invalidate objects where terrain texture is used
  2541.                                 if (pObj->m_pTempData && pObj->m_pTempData->userData.bTerrainColorWasUsed)
  2542.                                 {
  2543.                                         pObj->InvalidatePermanentRenderObject();
  2544.                                 }
  2545.                         }
  2546.                 }
  2547.         }
  2548.  
  2549.         if (m_arrObjects[eRNListType_Vegetation].m_pFirstNode && passInfo.RenderVegetation())
  2550.         {
  2551.