BVB Source Codes

CRYENGINE Show terrain_sector_render.cpp Source code

Return Download CRYENGINE: download terrain_sector_render.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. // -------------------------------------------------------------------------
  4. //  File name:   terrain_sector_render.cpp
  5. //  Version:     v1.00
  6. //  Created:     28/5/2001 by Vladimir Kajalin
  7. //  Compilers:   Visual Studio.NET
  8. //  Description: Create buffer, copy it into var memory, draw
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15.  
  16. #include "terrain.h"
  17. #include "terrain_sector.h"
  18. #include "ObjMan.h"
  19. #include "terrain_water.h"
  20. #include <CryThreading/IJobManager_JobDelegator.h>
  21.  
  22. DECLARE_JOB("Terrain_BuildIndices", TBuildIndicesJob, CTerrainNode::BuildIndices_Wrapper);
  23. DECLARE_JOB("Terrain_BuildVertices", TBuildVerticesJob, CTerrainNode::BuildVertices_Wrapper);
  24.  
  25. // special class to wrap the terrain node allocator functions with a vector like interface
  26. template<typename Type>
  27. class CTerrainTempDataStorage
  28. {
  29. public:
  30.         CTerrainTempDataStorage();
  31.  
  32.         void  Clear();
  33.         void  Free();
  34.  
  35.         void  PreAllocate(Type* pMemory, size_t nSize);
  36.  
  37.         int   Count() const       { return m_nCount; }
  38.         Type* GetElements() const { return m_pMemory; }
  39.  
  40.         void  Add(const Type& obj);
  41.  
  42.         int   MemorySize() const { return m_nCap * sizeof(Type); }
  43.  
  44.         void  GetMemoryUsage(ICrySizer* pSizer) const
  45.         {
  46.                 pSizer->AddObject(GetElements(), MemorySize());
  47.         }
  48.  
  49. private:
  50.         Type* m_pMemory;      // continuous memory block to store objects in main memory
  51.         int   m_nCount;       // number of objects in the container
  52.         int   m_nCap;         // maximum number of objects fitting into the allocated memory
  53. };
  54.  
  55. template<typename Type>
  56. CTerrainTempDataStorage<Type>::CTerrainTempDataStorage() :
  57.         m_pMemory(NULL),
  58.         m_nCount(0),
  59.         m_nCap(0)
  60. {}
  61.  
  62. template<typename Type>
  63. void CTerrainTempDataStorage<Type >::Clear()
  64. {
  65.         m_nCount = 0;
  66. }
  67.  
  68. template<typename Type>
  69. void CTerrainTempDataStorage<Type >::Free()
  70. {
  71.         m_pMemory = NULL;
  72.         m_nCount = 0;
  73.         m_nCap = 0;
  74. }
  75.  
  76. template<typename Type>
  77. void CTerrainTempDataStorage<Type >::PreAllocate(Type* pMemory, size_t nSize)
  78. {
  79.         m_pMemory = pMemory;
  80.         m_nCap = nSize;
  81. }
  82.  
  83. template<typename Type>
  84. void CTerrainTempDataStorage<Type >::Add(const Type& obj)
  85. {
  86.         assert(m_nCount < m_nCap);
  87.  
  88.         // special case for when a reallocation is needed
  89.         IF (m_nCount == m_nCap, false)
  90.         {
  91.                 CryFatalError("terrain sector scheduled update error");
  92.                 return;
  93.         }
  94.  
  95.         // add object
  96.         Type* pMemory = m_pMemory;
  97.         pMemory[m_nCount] = obj;
  98.         ++m_nCount;
  99.  
  100. }
  101.  
  102. struct CStripInfo
  103. {
  104.         int begin;
  105. };
  106.  
  107. struct CStripsInfo
  108. {
  109.         CTerrainTempDataStorage<vtx_idx> idx_array;
  110.         int                              nNonBorderIndicesCount;
  111.  
  112.         inline void Clear() { idx_array.Clear(); nNonBorderIndicesCount = 0; }
  113.  
  114.         inline void AddIndex(int _x, int _y, int _step, int nSectorSize)
  115.         {
  116.                 vtx_idx id = _x / _step * (nSectorSize / _step + 1) + _y / _step;
  117.                 idx_array.Add(id);
  118.         }
  119.  
  120.         static vtx_idx GetIndex(int _x, int _y, int _step, int nSectorSize)
  121.         {
  122.                 vtx_idx id = _x / _step * (nSectorSize / _step + 1) + _y / _step;
  123.                 return id;
  124.         }
  125.  
  126.         void GetMemoryUsage(ICrySizer* pSizer) const
  127.         {
  128.                 pSizer->AddObject(idx_array);
  129.         }
  130. };
  131.  
  132. class CUpdateTerrainTempData
  133. {
  134. public:
  135.  
  136.         JobManager::SJobState m_JobStateBuildIndices;
  137.         JobManager::SJobState m_JobStateBuildVertices;
  138.  
  139.         void GetMemoryUsage(ICrySizer* pSizer) const
  140.         {
  141.                 pSizer->AddObject(m_StripsInfo);
  142.                 pSizer->AddObject(m_lstTmpVertArray);
  143.         }
  144.  
  145.         // align objects to 128 byte to provide each with an own cacheline since they are updated in parallel
  146.         // for Update Indices
  147.         CRY_ALIGN(128) CStripsInfo m_StripsInfo;
  148.         // for update vectices
  149.         CRY_ALIGN(128) CTerrainTempDataStorage<SVF_P2S_N4B_C4B_T1F> m_lstTmpVertArray;
  150. };
  151.  
  152. CTerrainUpdateDispatcher::CTerrainUpdateDispatcher()
  153. {
  154.         m_pHeapStorage = CryGetIMemoryManager()->AllocPages(TempPoolSize);
  155.         m_pHeap = CryGetIMemoryManager()->CreateGeneralMemoryHeap(m_pHeapStorage, TempPoolSize, "Terrain temp pool");
  156. }
  157.  
  158. CTerrainUpdateDispatcher::~CTerrainUpdateDispatcher()
  159. {
  160.         SyncAllJobs(true, SRenderingPassInfo::CreateGeneralPassRenderingInfo(gEnv->p3DEngine->GetRenderingCamera()));
  161.         if (m_queuedJobs.size() || m_arrRunningJobs.size())
  162.         {
  163.                 CryFatalError(
  164.                   "CTerrainUpdateDispatcher::~CTerrainUpdateDispatcher(): instance still has jobs "
  165.                   "queued while being destructed!\n");
  166.         }
  167.  
  168.         m_pHeap = NULL;
  169.         CryGetIMemoryManager()->FreePages(m_pHeapStorage, TempPoolSize);
  170. }
  171.  
  172. void CTerrainUpdateDispatcher::QueueJob(CTerrainNode* pNode, const SRenderingPassInfo& passInfo)
  173. {
  174.         if (pNode && !Contains(pNode))
  175.         {
  176.                 if (!AddJob(pNode, true, passInfo))
  177.                 {
  178.                         // if job submission was unsuccessful, queue the terrain job
  179.                         m_queuedJobs.Add(pNode);
  180.                 }
  181.         }
  182. }
  183.  
  184. bool CTerrainUpdateDispatcher::AddJob(CTerrainNode* pNode, bool executeAsJob, const SRenderingPassInfo& passInfo)
  185. {
  186.         // 1U<<MML_NOT_SET will generate 0!
  187.         if (pNode->m_cNewGeomMML == MML_NOT_SET)
  188.                 return true;
  189.         STerrainNodeLeafData* pLeafData = pNode->GetLeafData();
  190.         if (!pLeafData)
  191.                 return true;
  192.  
  193.         const unsigned alignPad = TARGET_DEFAULT_ALIGN;
  194.  
  195.         // Preallocate enough temp memory to prevent reallocations
  196.         const int nStep = (1 << pNode->m_cNewGeomMML) * CTerrain::GetHeightMapUnitSize();
  197.         const int nSectorSize = CTerrain::GetSectorSize() << pNode->m_nTreeLevel;
  198.  
  199.         int nNumVerts = (nStep) ? ((nSectorSize / nStep) + 1) * ((nSectorSize / nStep) + 1) : 0;
  200.         int nNumIdx = (nStep) ? (nSectorSize / nStep) * (nSectorSize / nStep) * 6 : 0;
  201.  
  202.         if (nNumVerts == 0 || nNumIdx == 0)
  203.                 return true;
  204.  
  205.         size_t allocSize = sizeof(CUpdateTerrainTempData);
  206.         allocSize += alignPad;
  207.  
  208.         allocSize += sizeof(vtx_idx) * nNumIdx;
  209.         allocSize += alignPad;
  210.  
  211.         allocSize += sizeof(SVF_P2S_N4B_C4B_T1F) * nNumVerts;
  212.  
  213.         uint8* pTempData = (uint8*)m_pHeap->Memalign(__alignof(CUpdateTerrainTempData), allocSize, ""); // /*NOTE: Disabled due aliasing issues in the allocator with SNC compiler */m_TempStorage.Allocate<uint8*>(allocSize, __alignof(CUpdateTerrainTempData));
  214.         if (pTempData)
  215.         {
  216.                 CUpdateTerrainTempData* pUpdateTerrainTempData = new(pTempData) CUpdateTerrainTempData();
  217.                 pTempData += sizeof(CUpdateTerrainTempData);
  218.                 pTempData = (uint8*)((reinterpret_cast<uintptr_t>(pTempData) + alignPad) & ~uintptr_t(alignPad));
  219.  
  220.                 pUpdateTerrainTempData->m_StripsInfo.idx_array.PreAllocate(reinterpret_cast<vtx_idx*>(pTempData), nNumIdx);
  221.                 pTempData += sizeof(vtx_idx) * nNumIdx;
  222.                 pTempData = (uint8*)((reinterpret_cast<uintptr_t>(pTempData) + alignPad) & ~uintptr_t(alignPad));
  223.  
  224.                 pUpdateTerrainTempData->m_lstTmpVertArray.PreAllocate(reinterpret_cast<SVF_P2S_N4B_C4B_T1F*>(pTempData), nNumVerts);
  225.  
  226.                 pNode->m_pUpdateTerrainTempData = pUpdateTerrainTempData;
  227.  
  228.                 PodArray<CTerrainNode*>& lstNeighbourSectors = pLeafData->m_lstNeighbourSectors;
  229.                 PodArray<uint8>& lstNeighbourLods = pLeafData->m_lstNeighbourLods;
  230.  
  231. #ifdef SEG_WORLD
  232.                 lstNeighbourSectors.reserve(128U);
  233.                 lstNeighbourLods.PreAllocate(128U, 128U);
  234. #else
  235.                 lstNeighbourSectors.reserve(64U);
  236.                 lstNeighbourLods.PreAllocate(64U, 64U);
  237. #endif
  238.  
  239.                 // dont run async in case of editor or if we render into shadowmap
  240.                 executeAsJob &= !gEnv->IsEditor();
  241.                 executeAsJob &= !passInfo.IsShadowPass();
  242.  
  243.                 if (executeAsJob)
  244.                 {
  245.                         TBuildIndicesJob jobIndice(passInfo);
  246.                         jobIndice.SetClassInstance(pNode);
  247.                         jobIndice.RegisterJobState(&pUpdateTerrainTempData->m_JobStateBuildIndices);
  248.                         jobIndice.Run();
  249.  
  250.                         TBuildVerticesJob jobVertices;
  251.                         jobVertices.SetClassInstance(pNode);
  252.                         jobVertices.RegisterJobState(&pUpdateTerrainTempData->m_JobStateBuildVertices);
  253.                         jobVertices.Run();
  254.                 }
  255.                 else
  256.                 {
  257.                         pNode->BuildIndices_Wrapper(passInfo);
  258.                         pNode->BuildVertices_Wrapper();
  259.                 }
  260.  
  261.                 m_arrRunningJobs.Add(pNode);
  262.                 return true;
  263.         }
  264.  
  265.         return false;
  266. }
  267.  
  268. void CTerrainUpdateDispatcher::SyncAllJobs(bool bForceAll, const SRenderingPassInfo& passInfo)
  269. {
  270.         FUNCTION_PROFILER_3DENGINE;
  271.  
  272.         uint32 nNothingQueued = 0;
  273.         do
  274.         {
  275.                 bool bQueued = m_queuedJobs.size() ? false : true;
  276.                 size_t i = 0, nEnd = m_queuedJobs.size();
  277.                 while (i < nEnd)
  278.                 {
  279.                         CTerrainNode* pNode = m_queuedJobs[i];
  280.                         if (AddJob(pNode, false, passInfo))
  281.                         {
  282.                                 bQueued = true;
  283.                                 m_queuedJobs[i] = m_queuedJobs.Last();
  284.                                 m_queuedJobs.DeleteLast();
  285.                                 --nEnd;
  286.                                 continue;
  287.                         }
  288.                         ++i;
  289.                 }
  290.  
  291.                 i = 0;
  292.                 nEnd = m_arrRunningJobs.size();
  293.                 while (i < nEnd)
  294.                 {
  295.                         CTerrainNode* pNode = m_arrRunningJobs[i];
  296.                         CUpdateTerrainTempData* pTempStorage = pNode->m_pUpdateTerrainTempData;
  297.                         assert(pTempStorage);
  298.                         PREFAST_ASSUME(pTempStorage);
  299.                         if (!pTempStorage->m_JobStateBuildIndices.IsRunning() && !pTempStorage->m_JobStateBuildVertices.IsRunning())
  300.                         {
  301.                                 // Finish the render mesh update
  302.                                 pNode->RenderSectorUpdate_Finish(passInfo);
  303.                                 pTempStorage->~CUpdateTerrainTempData();
  304.                                 m_pHeap->Free(pTempStorage);
  305.                                 pNode->m_pUpdateTerrainTempData = NULL;
  306.  
  307.                                 // Remove from running list
  308.                                 m_arrRunningJobs[i] = m_arrRunningJobs.Last();
  309.                                 m_arrRunningJobs.DeleteLast();
  310.                                 --nEnd;
  311.                                 continue;
  312.                         }
  313.                         ++i;
  314.                 }
  315.  
  316.                 if (m_arrRunningJobs.size() == 0 && !bQueued)
  317.                         ++nNothingQueued;
  318.                 if (!bForceAll && nNothingQueued > 4)
  319.                 {
  320.                         CryLogAlways("ERROR: not all terrain sector vertex/index update requests could be scheduled");
  321.                         break;
  322.                 }
  323.         }
  324.         while (m_queuedJobs.size() != 0 || m_arrRunningJobs.size() != 0);
  325. }
  326.  
  327. void CTerrainUpdateDispatcher::GetMemoryUsage(ICrySizer* pSizer) const
  328. {
  329.         pSizer->AddObject(m_pHeapStorage, TempPoolSize);
  330.         pSizer->AddObject(m_arrRunningJobs);
  331.         pSizer->AddObject(m_queuedJobs);
  332. }
  333.  
  334. PodArray<vtx_idx> CTerrainNode::m_arrIndices[SRangeInfo::e_max_surface_types][4];
  335. PodArray<SSurfaceType*> CTerrainNode::m_lstReadyTypes(9);
  336.  
  337. void CTerrainNode::ResetStaticData()
  338. {
  339.         for (int s = 0; s < SRangeInfo::e_max_surface_types; s++)
  340.         {
  341.                 for (int p = 0; p < 4; p++)
  342.                 {
  343.                         stl::free_container(m_arrIndices[s][p]);
  344.                 }
  345.         }
  346.         stl::free_container(m_lstReadyTypes);
  347. }
  348.  
  349. void CTerrainNode::SetupTexGenParams(SSurfaceType* pSurfaceType, float* pOutParams, uint8 ucProjAxis, bool bOutdoor, float fTexGenScale)
  350. {
  351.         assert(pSurfaceType);
  352.  
  353.         if (pSurfaceType->fCustomMaxDistance > 0)
  354.         {
  355.                 pSurfaceType->fMaxMatDistanceZ = pSurfaceType->fMaxMatDistanceXY = pSurfaceType->fCustomMaxDistance;
  356.         }
  357.         else
  358.         {
  359.                 pSurfaceType->fMaxMatDistanceZ = float(GetFloatCVar(e_TerrainDetailMaterialsViewDistZ) * Get3DEngine()->m_fTerrainDetailMaterialsViewDistRatio);
  360.                 pSurfaceType->fMaxMatDistanceXY = float(GetFloatCVar(e_TerrainDetailMaterialsViewDistXY) * Get3DEngine()->m_fTerrainDetailMaterialsViewDistRatio);
  361.         }
  362.  
  363.         // setup projection direction
  364.         if (ucProjAxis == 'X')
  365.         {
  366.                 pOutParams[0] = 0;
  367.                 pOutParams[1] = pSurfaceType->fScale * fTexGenScale;
  368.                 pOutParams[2] = 0;
  369.                 pOutParams[3] = pSurfaceType->fMaxMatDistanceXY;
  370.  
  371.                 pOutParams[4] = 0;
  372.                 pOutParams[5] = 0;
  373.                 pOutParams[6] = -pSurfaceType->fScale * fTexGenScale;
  374.                 pOutParams[7] = 0;
  375.         }
  376.         else if (ucProjAxis == 'Y')
  377.         {
  378.                 pOutParams[0] = pSurfaceType->fScale * fTexGenScale;
  379.                 pOutParams[1] = 0;
  380.                 pOutParams[2] = 0;
  381.                 pOutParams[3] = pSurfaceType->fMaxMatDistanceXY;
  382.  
  383.                 pOutParams[4] = 0;
  384.                 pOutParams[5] = 0;
  385.                 pOutParams[6] = -pSurfaceType->fScale * fTexGenScale;
  386.                 pOutParams[7] = 0;
  387.         }
  388.         else // Z
  389.         {
  390.                 pOutParams[0] = pSurfaceType->fScale * fTexGenScale;
  391.                 pOutParams[1] = 0;
  392.                 pOutParams[2] = 0;
  393.                 pOutParams[3] = pSurfaceType->fMaxMatDistanceZ;
  394.  
  395.                 pOutParams[4] = 0;
  396.                 pOutParams[5] = -pSurfaceType->fScale * fTexGenScale;
  397.                 pOutParams[6] = 0;
  398.                 pOutParams[7] = 0;
  399.         }
  400. }
  401.  
  402. void CTerrainNode::DrawArray(const SRenderingPassInfo& passInfo)
  403. {
  404.         if (!Get3DEngine()->CheckAndCreateRenderNodeTempData(&m_pTempData, this, passInfo))
  405.                 return;
  406.  
  407.         // Use mesh instancing for distant low-lod sectors and during shadow map generation
  408.         if(passInfo.IsShadowPass() || (m_nTreeLevel >= GetCVars()->e_TerrainMeshInstancingMinLod))
  409.         {
  410.                 SetupTexturing(false, passInfo);
  411.  
  412.                 IRenderMesh * pRenderMesh = GetSharedRenderMesh();
  413.  
  414.                 CRenderObject* pTerrainRenderObject = 0;
  415.  
  416.                 CLodValue dymmyLod(3, 0, 3);
  417.                 if (!GetObjManager()->AddOrCreatePersistentRenderObject(m_pTempData, pTerrainRenderObject, &dymmyLod, passInfo))
  418.                 {
  419.                         pTerrainRenderObject->m_pRenderNode = 0;
  420.                         pTerrainRenderObject->m_II.m_AmbColor = Get3DEngine()->GetSkyColor();
  421.                         pTerrainRenderObject->m_fDistance = m_arrfDistance[passInfo.GetRecursiveLevel()];
  422.  
  423.                         Vec3 vScale = GetBBox().GetSize();
  424.                         vScale.z = 1.f;
  425.                         pTerrainRenderObject->m_II.m_Matrix.SetIdentity();
  426.                         pTerrainRenderObject->m_II.m_Matrix.SetScale(vScale, Vec3(m_nOriginX, m_nOriginY, 0));
  427.                         pTerrainRenderObject->m_ObjFlags |= FOB_TRANS_TRANSLATE | FOB_TRANS_SCALE;
  428.  
  429.                         pTerrainRenderObject->m_nTextureID = -(int)m_nTexSet.nSlot0 - 1;
  430.                         pTerrainRenderObject->m_data.m_pTerrainSectorTextureInfo = &m_nTexSet;
  431.                         pTerrainRenderObject->m_data.m_fMaxViewDistance = min(-0.01f, -GetCVars()->e_TerrainMeshInstancingShadowBias * powf(2.f, (float)m_nTreeLevel));
  432.  
  433.                         pRenderMesh->SetCustomTexID(m_nTexSet.nTex0);
  434.  
  435.                         pRenderMesh->AddRenderElements(GetTerrain()->m_pTerrainEf, pTerrainRenderObject, passInfo, EFSLIST_GENERAL, 1);
  436.                 }
  437.  
  438.                 return;
  439.         }
  440.  
  441.         _smart_ptr<IRenderMesh>& pRenderMesh = GetLeafData()->m_pRenderMesh;
  442.  
  443.         CRenderObject* pTerrainRenderObject = 0;
  444.  
  445.         CLodValue dymmyLod(0, 0, 0);
  446.         if (!GetObjManager()->AddOrCreatePersistentRenderObject(m_pTempData, pTerrainRenderObject, &dymmyLod, passInfo))
  447.         {
  448.                 pTerrainRenderObject->m_pRenderNode = 0;
  449.                 pTerrainRenderObject->m_II.m_AmbColor = Get3DEngine()->GetSkyColor();
  450.                 pTerrainRenderObject->m_fDistance = m_arrfDistance[passInfo.GetRecursiveLevel()];
  451.  
  452.                 pTerrainRenderObject->m_II.m_Matrix.SetIdentity();
  453.                 Vec3 vOrigin(m_nOriginX, m_nOriginY, 0);
  454.                 vOrigin += GetTerrain()->m_arrSegmentOrigns[m_nSID];
  455.                 pTerrainRenderObject->m_II.m_Matrix.SetTranslation(vOrigin);
  456.                 pTerrainRenderObject->m_ObjFlags |= FOB_TRANS_TRANSLATE;
  457.  
  458.                 if (!passInfo.IsShadowPass() && passInfo.RenderShadows())
  459.                         pTerrainRenderObject->m_ObjFlags |= FOB_INSHADOW;
  460.  
  461.                 pTerrainRenderObject->m_nTextureID = -(int)m_nTexSet.nSlot0 - 1;
  462.                 pTerrainRenderObject->m_data.m_pTerrainSectorTextureInfo = &m_nTexSet;
  463.  
  464.                 pRenderMesh->SetCustomTexID(m_nTexSet.nTex0);
  465.  
  466.                 pRenderMesh->AddRenderElements(GetTerrain()->m_pTerrainEf, pTerrainRenderObject, passInfo, EFSLIST_GENERAL, 1);
  467.         }
  468.  
  469.         if (passInfo.RenderTerrainDetailMaterial() && !passInfo.IsShadowPass())
  470.         {
  471.                 bool bDrawDetailLayersXYZ[2] =
  472.                 {
  473.                         false, // XY
  474.                         false  // Z
  475.                 };
  476.  
  477.                 for (int i = 0; i < m_lstSurfaceTypeInfo.Count(); i++)
  478.                 {
  479.                         assert(1 || m_lstSurfaceTypeInfo[i].pSurfaceType->HasMaterial() && m_lstSurfaceTypeInfo[i].HasRM());
  480.  
  481.                         if (!m_lstSurfaceTypeInfo[i].pSurfaceType->HasMaterial() || !m_lstSurfaceTypeInfo[i].HasRM())
  482.                                 continue;
  483.  
  484.                         uint8 szProj[] = "XYZ";
  485.                         for (int p = 0; p < 3; p++)
  486.                         {
  487.                                 if (SSurfaceType* pSurf = m_lstSurfaceTypeInfo[i].pSurfaceType)
  488.                                         if (IMaterial* pMat = pSurf->GetMaterialOfProjection(szProj[p]))
  489.                                         {
  490.                                                 pSurf->fMaxMatDistanceZ = float(GetFloatCVar(e_TerrainDetailMaterialsViewDistZ) * Get3DEngine()->m_fTerrainDetailMaterialsViewDistRatio);
  491.                                                 pSurf->fMaxMatDistanceXY = float(GetFloatCVar(e_TerrainDetailMaterialsViewDistXY) * Get3DEngine()->m_fTerrainDetailMaterialsViewDistRatio);
  492.  
  493.                                                 if (m_arrfDistance[passInfo.GetRecursiveLevel()] < pSurf->GetMaxMaterialDistanceOfProjection(szProj[p]))
  494.                                                         if (IRenderMesh* pMesh = m_lstSurfaceTypeInfo[i].arrpRM[p])
  495.                                                         {
  496.                                                                 bDrawDetailLayersXYZ[p == 2] = true;
  497.                                                         }
  498.                                         }
  499.                         }
  500.                 }
  501.  
  502.                 // One iteration for XY projections and one for Z projection
  503.                 for (int nP = 0; nP < 2; nP++)
  504.                         if (bDrawDetailLayersXYZ[nP])
  505.                         {
  506.                                 CRenderObject* pDetailObj = nullptr;
  507.  
  508.                                 CLodValue dymmyLod(1 + nP, 0, 1 + nP);
  509.                                 if (GetObjManager()->AddOrCreatePersistentRenderObject(m_pTempData, pDetailObj, &dymmyLod, passInfo))
  510.                                         continue;
  511.                                 ;
  512.  
  513.                                 pDetailObj->m_pRenderNode = 0;
  514.                                 pDetailObj->m_ObjFlags |= (((passInfo.IsGeneralPass()) ? FOB_NO_FOG : 0)); // enable fog on recursive rendering (per-vertex)
  515.                                 pDetailObj->m_II.m_AmbColor = Get3DEngine()->GetSkyColor();
  516.                                 pDetailObj->m_fDistance = m_arrfDistance[passInfo.GetRecursiveLevel()];
  517.                                 pDetailObj->m_II.m_Matrix = pTerrainRenderObject->m_II.m_Matrix;
  518.                                 pDetailObj->m_ObjFlags |= FOB_TRANS_TRANSLATE | FOB_TERRAIN_LAYER;
  519.  
  520.                                 if (passInfo.RenderShadows())
  521.                                 {
  522.                                         pDetailObj->m_ObjFlags |= FOB_INSHADOW;
  523.                                 }
  524.  
  525.                                 pDetailObj->m_nTextureID = -(int)m_nTexSet.nSlot0 - 1;
  526.                                 pDetailObj->m_data.m_pTerrainSectorTextureInfo = &m_nTexSet;
  527.  
  528.                                 for (int i = 0; i < m_lstSurfaceTypeInfo.Count(); i++)
  529.                                 {
  530.                                         if (!m_lstSurfaceTypeInfo[i].pSurfaceType->HasMaterial() || !m_lstSurfaceTypeInfo[i].HasRM())
  531.                                                 continue;
  532.  
  533.                                         uint8 szProj[] = "XYZ";
  534.                                         for (int p = 0; p < 3; p++)
  535.                                         {
  536.                                                 if ((p == 2) != (nP))
  537.                                                         continue;
  538.  
  539.                                                 if (SSurfaceType* pSurf = m_lstSurfaceTypeInfo[i].pSurfaceType)
  540.                                                         if (IMaterial* pMat = pSurf->GetMaterialOfProjection(szProj[p]))
  541.                                                         {
  542.                                                                 pSurf->fMaxMatDistanceZ = float(GetFloatCVar(e_TerrainDetailMaterialsViewDistZ) * Get3DEngine()->m_fTerrainDetailMaterialsViewDistRatio);
  543.                                                                 pSurf->fMaxMatDistanceXY = float(GetFloatCVar(e_TerrainDetailMaterialsViewDistXY) * Get3DEngine()->m_fTerrainDetailMaterialsViewDistRatio);
  544.  
  545.                                                                 //if(m_arrfDistance[passInfo.GetRecursiveLevel()]<pSurf->GetMaxMaterialDistanceOfProjection(szProj[p]))
  546.                                                                 if (IRenderMesh* pMesh = m_lstSurfaceTypeInfo[i].arrpRM[p])
  547.                                                                 {
  548.                                                                         AABB aabb;
  549.                                                                         pMesh->GetBBox(aabb.min, aabb.max);
  550.                                                                         //              if(passInfo.GetCamera().IsAABBVisible_F(aabb))
  551.                                                                         if (pMesh->GetVertexContainer() == pRenderMesh && pMesh->GetIndicesCount())
  552.                                                                         {
  553.                                                                                 if (GetCVars()->e_TerrainBBoxes == 2)
  554.                                                                                         GetRenderer()->GetIRenderAuxGeom()->DrawAABB(aabb, false, ColorB(255 * ((m_nTreeLevel & 1) > 0), 255 * ((m_nTreeLevel & 2) > 0), 0, 255), eBBD_Faceted);
  555.  
  556.                                                                                 pMesh->SetCustomTexID(m_nTexSet.nTex0);
  557.  
  558.                                                                                 // every draw call uses custom constants (at least surface type id and direction of projection) so we have to duplicate render object
  559.                                                                                 pDetailObj = GetRenderer()->EF_DuplicateRO(pDetailObj, passInfo);
  560.  
  561.                                                                                 pMesh->AddRenderElements(pMat, pDetailObj, passInfo, EFSLIST_TERRAINLAYER, 1);
  562.                                                                         }
  563.                                                                 }
  564.                                                         }
  565.                                         }
  566.                                 }
  567.                         }
  568.         }
  569. }
  570.  
  571. // update data in video buffer
  572. void CTerrainNode::UpdateRenderMesh(CStripsInfo* pArrayInfo, bool bUpdateVertices)
  573. {
  574.         FUNCTION_PROFILER_3DENGINE;
  575.  
  576.         _smart_ptr<IRenderMesh>& pRenderMesh = GetLeafData()->m_pRenderMesh;
  577.         bool bIndicesUpdated = false;
  578.  
  579.         // if changing lod or there is no buffer allocated - reallocate
  580.         if (!pRenderMesh || m_cCurrGeomMML != m_cNewGeomMML || bUpdateVertices)// || GetCVars()->e_TerrainDrawThisSectorOnly)
  581.         {
  582.                 assert(m_pUpdateTerrainTempData->m_lstTmpVertArray.Count() < 65536);
  583.  
  584.                 static PodArray<SPipTangents> lstTangents;
  585.                 lstTangents.Clear();
  586.  
  587.                 if (GetCVars()->e_DefaultMaterial && m_pUpdateTerrainTempData->m_lstTmpVertArray.Count())
  588.                 {
  589.                         lstTangents.PreAllocate(m_pUpdateTerrainTempData->m_lstTmpVertArray.Count(), m_pUpdateTerrainTempData->m_lstTmpVertArray.Count());
  590.  
  591.                         Vec3 vTang(0, 1, 0);
  592.                         Vec3 vBitang(1, 0, 0);
  593.                         Vec3 vNormal(0, 0, 1);
  594.  
  595.                         // Orthonormalize Tangent Frame
  596.                         vBitang = -vNormal.Cross(vTang);
  597.                         vTang = vNormal.Cross(vBitang);
  598.  
  599.                         lstTangents[0] = SPipTangents(vTang, vBitang, -1);
  600.                         for (int i = 1; i < lstTangents.Count(); i++)
  601.                                 lstTangents[i] = lstTangents[0];
  602.                 }
  603.  
  604.                 ERenderMeshType eRMType = eRMT_Static;
  605.  
  606.                 bool bMultiGPU;
  607.                 gEnv->pRenderer->EF_Query(EFQ_MultiGPUEnabled, bMultiGPU);
  608.  
  609.                 pRenderMesh = GetRenderer()->CreateRenderMeshInitialized(
  610.                   m_pUpdateTerrainTempData->m_lstTmpVertArray.GetElements(), m_pUpdateTerrainTempData->m_lstTmpVertArray.Count(), eVF_P2S_N4B_C4B_T1F,
  611.                   pArrayInfo->idx_array.GetElements(), pArrayInfo->idx_array.Count(),
  612.                   prtTriangleList, "TerrainSector", "TerrainSector", eRMType, 1,
  613.                   m_nTexSet.nTex0, NULL, NULL, false, true, lstTangents.Count() ? lstTangents.GetElements() : NULL);
  614.                 AABB boxWS = GetBBox();
  615.                 pRenderMesh->SetBBox(boxWS.min, boxWS.max);
  616.                 bIndicesUpdated = true;
  617.         }
  618.  
  619.         if (!bUpdateVertices && !GetCVars()->e_TerrainDrawThisSectorOnly)
  620.         {
  621.                 assert(pArrayInfo->idx_array.Count() <= (int)pRenderMesh->GetIndicesCount());
  622.         }
  623.  
  624.         if (!bIndicesUpdated)
  625.                 pRenderMesh->UpdateIndices(pArrayInfo->idx_array.GetElements(), pArrayInfo->idx_array.Count(), 0, 0u);
  626.  
  627.         pRenderMesh->SetChunk(GetTerrain()->m_pTerrainEf, 0, pRenderMesh->GetVerticesCount(), 0, pArrayInfo->idx_array.Count(), 1.0f, 0);
  628.  
  629.         if (pRenderMesh->GetChunks().size() && pRenderMesh->GetChunks()[0].pRE)
  630.                 pRenderMesh->GetChunks()[0].pRE->m_CustomData = GetLeafData()->m_arrTexGen[0];
  631.  
  632.         assert(pRenderMesh->GetChunks().size() <= 256); // holes may cause more than 100 chunks
  633. }
  634.  
  635. void CTerrainNode::UpdateRangeInfoShift()
  636. {
  637.         if (!m_pChilds || !m_nTreeLevel)
  638.                 return;
  639.  
  640.         m_rangeInfo.nUnitBitShift = GetTerrain()->m_nUnitsToSectorBitShift;
  641.  
  642.         for (int i = 0; i < 4; i++)
  643.         {
  644.                 m_pChilds[i].UpdateRangeInfoShift();
  645.                 m_rangeInfo.nUnitBitShift = min(m_pChilds[i].m_rangeInfo.nUnitBitShift, m_rangeInfo.nUnitBitShift);
  646.         }
  647. }
  648.  
  649. void CTerrainNode::ReleaseHeightMapGeometry(bool bRecursive, const AABB* pBox)
  650. {
  651.         if (pBox && !Overlap::AABB_AABB(*pBox, GetBBox()))
  652.                 return;
  653.  
  654.         for (int i = 0; i < m_lstSurfaceTypeInfo.Count(); i++)
  655.                 m_lstSurfaceTypeInfo[i].DeleteRenderMeshes(GetRenderer());
  656.  
  657.         if (GetLeafData() && GetLeafData()->m_pRenderMesh)
  658.         {
  659.                 _smart_ptr<IRenderMesh>& pRenderMesh = GetLeafData()->m_pRenderMesh;
  660.                 pRenderMesh = NULL;
  661.         }
  662.  
  663.         delete m_pLeafData;
  664.         m_pLeafData = NULL;
  665.  
  666.         if (bRecursive && m_pChilds)
  667.                 for (int i = 0; i < 4; i++)
  668.                         m_pChilds[i].ReleaseHeightMapGeometry(bRecursive, pBox);
  669. }
  670.  
  671. void CTerrainNode::ResetHeightMapGeometry(bool bRecursive, const AABB* pBox)
  672. {
  673.         if (pBox && !Overlap::AABB_AABB(*pBox, GetBBox()))
  674.                 return;
  675.  
  676.         if (m_pLeafData)
  677.                 m_pLeafData->m_lstNeighbourSectors.Clear();
  678.  
  679.         if (bRecursive && m_pChilds)
  680.                 for (int i = 0; i < 4; i++)
  681.                         m_pChilds[i].ResetHeightMapGeometry(bRecursive, pBox);
  682. }
  683.  
  684. // fill vertex buffer
  685. void CTerrainNode::BuildVertices(int nStep, bool bSafetyBorder)
  686. {
  687.         FUNCTION_PROFILER_3DENGINE;
  688.  
  689.         m_pUpdateTerrainTempData->m_lstTmpVertArray.Clear();
  690.  
  691.         int nSectorSize = CTerrain::GetSectorSize() << m_nTreeLevel;
  692.  
  693.         int nSafetyBorder = 0;
  694.  
  695.         // keep often used variables on stack
  696.         const int nOriginX = m_nOriginX;
  697.         const int nOriginY = m_nOriginY;
  698.         const int nSID = m_nSID;
  699.         const int nTerrainSize = CTerrain::GetTerrainSize();
  700.         const int iLookupRadius = 2 * CTerrain::GetHeightMapUnitSize();
  701.         CTerrain* pTerrain = GetTerrain();
  702.  
  703.         for (int x = nOriginX - nSafetyBorder; x <= nOriginX + nSectorSize + nSafetyBorder; x += nStep)
  704.         {
  705.                 for (int y = nOriginY - nSafetyBorder; y <= nOriginY + nSectorSize + nSafetyBorder; y += nStep)
  706.                 {
  707.                         int _x = CLAMP(x, nOriginX, nOriginX + nSectorSize);
  708.                         int _y = CLAMP(y, nOriginY, nOriginY + nSectorSize);
  709.                         float _z = pTerrain->GetZ(_x, _y, nSID);
  710.  
  711.                         SVF_P2S_N4B_C4B_T1F vert;
  712.  
  713.                         vert.xy = CryHalf2((float)(_x - nOriginX), (float)(_y - nOriginY));
  714.                         vert.z = _z;
  715.  
  716.                         // calculate surface normal
  717. #ifdef SEG_WORLD
  718.                         bool bOutOfBound = (x + iLookupRadius) >= nTerrainSize || x <= iLookupRadius;
  719.                         float sx = pTerrain->GetZ(x + iLookupRadius, y, nSID, bOutOfBound) - pTerrain->GetZ(x - iLookupRadius, y, nSID, bOutOfBound);
  720.  
  721.                         bOutOfBound = (y + iLookupRadius) >= nTerrainSize || y <= iLookupRadius;
  722.                         float sy = pTerrain->GetZ(x, y + iLookupRadius, nSID, bOutOfBound) - pTerrain->GetZ(x, y - iLookupRadius, nSID, bOutOfBound);
  723. #else
  724.                         float sx;
  725.                         if ((x + iLookupRadius) < nTerrainSize && x > iLookupRadius)
  726.                                 sx = pTerrain->GetZ(x + iLookupRadius, y, nSID) - pTerrain->GetZ(x - iLookupRadius, y, nSID);
  727.                         else
  728.                                 sx = 0;
  729.  
  730.                         float sy;
  731.                         if ((y + iLookupRadius) < nTerrainSize && y > iLookupRadius)
  732.                                 sy = pTerrain->GetZ(x, y + iLookupRadius, nSID) - pTerrain->GetZ(x, y - iLookupRadius, nSID);
  733.                         else
  734.                                 sy = 0;
  735. #endif
  736.                         // z component of normal will be used as point brightness ( for burned terrain )
  737.                         Vec3 vNorm(-sx, -sy, iLookupRadius * 2.0f);
  738.                         vNorm.Normalize();
  739.  
  740.                         vert.normal.bcolor[0] = (byte)(vNorm[0] * 127.5f + 128.0f);
  741.                         vert.normal.bcolor[1] = (byte)(vNorm[1] * 127.5f + 128.0f);
  742.                         vert.normal.bcolor[2] = (byte)(vNorm[2] * 127.5f + 128.0f);
  743.                         vert.normal.bcolor[3] = 255;
  744.                         SwapEndian(vert.normal.dcolor, eLittleEndian);
  745.  
  746.                         uint8 ucSurfaceTypeID = pTerrain->GetSurfaceTypeID(x, y, nSID);
  747.                         if (ucSurfaceTypeID == SRangeInfo::e_hole)
  748.                         {
  749.                                 // in case of hole - try to find some valid surface type around
  750.                                 for (int i = -nStep; i <= nStep && (ucSurfaceTypeID == SRangeInfo::e_hole); i += nStep)
  751.                                         for (int j = -nStep; j <= nStep && (ucSurfaceTypeID == SRangeInfo::e_hole); j += nStep)
  752.                                                 ucSurfaceTypeID = pTerrain->GetSurfaceTypeID(x + i, y + j, nSID);
  753.                         }
  754.  
  755.                         vert.color.bcolor[0] = 255;
  756.                         vert.color.bcolor[1] = ucSurfaceTypeID;
  757.                         vert.color.bcolor[2] = 255;
  758.                         vert.color.bcolor[3] = 255;
  759.                         SwapEndian(vert.color.dcolor, eLittleEndian);
  760.  
  761.                         m_pUpdateTerrainTempData->m_lstTmpVertArray.Add(vert);
  762.                 }
  763.         }
  764. }
  765.  
  766. namespace Util
  767. {
  768. void AddNeighbourNode(PodArray<CTerrainNode*>* plstNeighbourSectors, CTerrainNode* pNode)
  769. {
  770.         // todo: cache this list, it is always the same
  771.         if (pNode && plstNeighbourSectors->Find(pNode) < 0)
  772.                 plstNeighbourSectors->Add(pNode);
  773. }
  774. }
  775.  
  776. void CTerrainNode::AddIndexAliased(int _x, int _y, int _step, int nSectorSize, PodArray<CTerrainNode*>* plstNeighbourSectors, CStripsInfo* pArrayInfo, const SRenderingPassInfo& passInfo)
  777. {
  778.         int nAliasingX = 1, nAliasingY = 1;
  779.         int nShiftX = 0, nShiftY = 0;
  780.  
  781.         CTerrain* pTerrain = GetTerrain();
  782.         int nHeightMapUnitSize = CTerrain::GetHeightMapUnitSize();
  783.  
  784.         IF (_x && _x < nSectorSize && plstNeighbourSectors, true)
  785.         {
  786.                 IF (_y == 0, false)
  787.                 {
  788.                         if (CTerrainNode* pNode = pTerrain->GetSecInfo(m_nOriginX + _x, m_nOriginY + _y - _step, m_nSID))
  789.                         {
  790.                                 int nAreaMML = pNode->GetAreaLOD(passInfo);
  791.                                 if (nAreaMML != MML_NOT_SET)
  792.                                 {
  793.                                         nAliasingX = nHeightMapUnitSize * (1 << nAreaMML);
  794.                                         nShiftX = nAliasingX / 4;
  795.                                 }
  796.                                 Util::AddNeighbourNode(plstNeighbourSectors, pNode);
  797.                         }
  798.                 }
  799.                 else if (_y == nSectorSize)
  800.                 {
  801.                         if (CTerrainNode* pNode = pTerrain->GetSecInfo(m_nOriginX + _x, m_nOriginY + _y + _step, m_nSID))
  802.                         {
  803.                                 int nAreaMML = pNode->GetAreaLOD(passInfo);
  804.                                 if (nAreaMML != MML_NOT_SET)
  805.                                 {
  806.                                         nAliasingX = nHeightMapUnitSize * (1 << nAreaMML);
  807.                                         nShiftX = nAliasingX / 2;
  808.                                 }
  809.                                 Util::AddNeighbourNode(plstNeighbourSectors, pNode);
  810.                         }
  811.                 }
  812.         }
  813.  
  814.         IF (_y && _y < nSectorSize && plstNeighbourSectors, true)
  815.         {
  816.                 IF (_x == 0, false)
  817.                 {
  818.                         if (CTerrainNode* pNode = pTerrain->GetSecInfo(m_nOriginX + _x - _step, m_nOriginY + _y, m_nSID))
  819.                         {
  820.                                 int nAreaMML = pNode->GetAreaLOD(passInfo);
  821.                                 if (nAreaMML != MML_NOT_SET)
  822.                                 {
  823.                                         nAliasingY = nHeightMapUnitSize * (1 << nAreaMML);
  824.                                         nShiftY = nAliasingY / 4;
  825.                                 }
  826.                                 Util::AddNeighbourNode(plstNeighbourSectors, pNode);
  827.                         }
  828.                 }
  829.                 else if (_x == nSectorSize)
  830.                 {
  831.                         if (CTerrainNode* pNode = pTerrain->GetSecInfo(m_nOriginX + _x + _step, m_nOriginY + _y, m_nSID))
  832.                         {
  833.                                 int nAreaMML = pNode->GetAreaLOD(passInfo);
  834.                                 if (nAreaMML != MML_NOT_SET)
  835.                                 {
  836.                                         nAliasingY = nHeightMapUnitSize * (1 << nAreaMML);
  837.                                         nShiftY = nAliasingY / 2;
  838.                                 }
  839.                                 Util::AddNeighbourNode(plstNeighbourSectors, pNode);
  840.                         }
  841.                 }
  842.         }
  843.  
  844.         int XA = nAliasingX ? (_x + nShiftX) / nAliasingX * nAliasingX : _x;
  845.         int YA = nAliasingY ? (_y + nShiftY) / nAliasingY * nAliasingY : _y;
  846.  
  847.         assert(XA >= 0 && XA <= nSectorSize);
  848.         assert(YA >= 0 && YA <= nSectorSize);
  849.  
  850.         pArrayInfo->AddIndex(XA, YA, _step, nSectorSize);
  851. }
  852.  
  853. void CTerrainNode::BuildIndices(CStripsInfo& si, PodArray<CTerrainNode*>* pNeighbourSectors, bool bSafetyBorder, const SRenderingPassInfo& passInfo)
  854. {
  855.         FUNCTION_PROFILER_3DENGINE;
  856.  
  857.         // 1<<MML_NOT_SET will generate 0;
  858.         if (m_cNewGeomMML == MML_NOT_SET)
  859.                 return;
  860.  
  861.         int nStep = (1 << m_cNewGeomMML) * CTerrain::GetHeightMapUnitSize();
  862.         int nSectorSize = CTerrain::GetSectorSize() << m_nTreeLevel;
  863.  
  864.         int nSafetyBorder = bSafetyBorder ? nStep : 0;
  865.  
  866.         int nSectorSizeSB = nSectorSize + nSafetyBorder * 2;
  867.  
  868.         si.Clear();
  869.  
  870.         CStripsInfo* pSI = &si;
  871.         CTerrain* pTerrain = GetTerrain();
  872.  
  873.         int nHalfStep = nStep / 2;
  874.  
  875.         // add non borders
  876.         for (int x = 0; x < nSectorSizeSB; x += nStep)
  877.         {
  878.                 for (int y = 0; y < nSectorSizeSB; y += nStep)
  879.                 {
  880.                         if (!m_bHasHoles || !pTerrain->GetHole(m_nOriginX + x + nHalfStep, m_nOriginY + y + nHalfStep, m_nSID))
  881.                         {
  882.                                 if (pTerrain->IsMeshQuadFlipped(m_nOriginX + x, m_nOriginY + y, nStep, 0))
  883.                                 {
  884.                                         AddIndexAliased(x + nStep, y, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  885.                                         AddIndexAliased(x + nStep, y + nStep, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  886.                                         AddIndexAliased(x, y, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  887.  
  888.                                         AddIndexAliased(x, y, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  889.                                         AddIndexAliased(x + nStep, y + nStep, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  890.                                         AddIndexAliased(x, y + nStep, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  891.                                 }
  892.                                 else
  893.                                 {
  894.                                         AddIndexAliased(x, y, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  895.                                         AddIndexAliased(x + nStep, y, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  896.                                         AddIndexAliased(x, y + nStep, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  897.  
  898.                                         AddIndexAliased(x + nStep, y, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  899.                                         AddIndexAliased(x + nStep, y + nStep, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  900.                                         AddIndexAliased(x, y + nStep, nStep, nSectorSizeSB, pNeighbourSectors, pSI, passInfo);
  901.                                 }
  902.                         }
  903.                 }
  904.         }
  905.  
  906.         si.nNonBorderIndicesCount = si.idx_array.Count();
  907. }
  908.  
  909. // entry point
  910. bool CTerrainNode::RenderSector(const SRenderingPassInfo& passInfo)
  911. {
  912.         FUNCTION_PROFILER_3DENGINE;
  913.  
  914.         //m_nNodeRenderLastFrameId = passInfo.GetMainFrameID();
  915.  
  916.         assert(m_cNewGeomMML == MML_NOT_SET || m_cNewGeomMML < GetTerrain()->m_nUnitsToSectorBitShift);
  917.  
  918.         STerrainNodeLeafData* pLeafData = GetLeafData();
  919.  
  920.         // detect if any neighbors switched lod since previous frame
  921.         bool bNeighbourChanged = false;
  922.  
  923.         if (!passInfo.IsShadowPass())
  924.         {
  925.                 for (int i = 0; i < pLeafData->m_lstNeighbourSectors.Count(); i++)
  926.                 {
  927.                         if (!pLeafData->m_lstNeighbourSectors[i])
  928.                                 continue;
  929.                         int nNeighbourNewMML = pLeafData->m_lstNeighbourSectors[i]->GetAreaLOD(passInfo);
  930.                         if (nNeighbourNewMML == MML_NOT_SET)
  931.                                 continue;
  932.                         if (nNeighbourNewMML != pLeafData->m_lstNeighbourLods[i] && (nNeighbourNewMML > m_cNewGeomMML || pLeafData->m_lstNeighbourLods[i] > m_cNewGeomMML))
  933.                         {
  934.                                 bNeighbourChanged = true;
  935.                                 break;
  936.                         }
  937.                 }
  938.         }
  939.         else
  940.         {
  941.                 assert(!"Shadow-gen is not supposed to be rendered this way");
  942.         }
  943.  
  944.         IRenderMesh * pRenderMesh = (m_nTreeLevel >= GetCVars()->e_TerrainMeshInstancingMinLod) ? GetSharedRenderMesh() : GetLeafData()->m_pRenderMesh;
  945.  
  946.         bool bDetailLayersReady = passInfo.IsShadowPass() ||
  947.                                   !m_lstSurfaceTypeInfo.Count() ||
  948.                                   !passInfo.RenderTerrainDetailMaterial();
  949.         for (int i = 0; i < m_lstSurfaceTypeInfo.Count() && !bDetailLayersReady; ++i)
  950.         {
  951.                 bDetailLayersReady =
  952.                   m_lstSurfaceTypeInfo[i].HasRM() ||
  953.                   m_lstSurfaceTypeInfo[i].pSurfaceType ||
  954.                   !m_lstSurfaceTypeInfo[i].pSurfaceType->HasMaterial();
  955.         }
  956.  
  957.         // just draw if everything is up to date already
  958.         if (!GetLeafData())
  959.                 return false;
  960.  
  961.         if (pRenderMesh && GetCVars()->e_TerrainDrawThisSectorOnly < 2 && bDetailLayersReady)
  962.         {
  963.                 if (passInfo.GetRecursiveLevel() || (m_cCurrGeomMML == m_cNewGeomMML && !bNeighbourChanged) || m_nTreeLevel >= GetCVars()->e_TerrainMeshInstancingMinLod ||
  964.                     (passInfo.IsCachedShadowPass() && passInfo.GetShadowMapType() == SRenderingPassInfo::SHADOW_MAP_CACHED_MGPU_COPY))
  965.                 {
  966.                         DrawArray(passInfo);
  967.                         return true;
  968.                 }
  969.         }
  970.  
  971.         if (passInfo.GetRecursiveLevel())
  972.                 if (pRenderMesh)
  973.                         return true;
  974.  
  975.         return false;
  976. }
  977.  
  978. void CTerrainNode::RenderSectorUpdate_Finish(const SRenderingPassInfo& passInfo)
  979. {
  980.         assert(m_pUpdateTerrainTempData != NULL);
  981.         if (passInfo.IsGeneralPass())
  982.         {
  983.                 FRAME_PROFILER("Sync_UpdateTerrain", GetSystem(), PROFILE_3DENGINE);
  984.                 gEnv->GetJobManager()->WaitForJob(m_pUpdateTerrainTempData->m_JobStateBuildIndices);
  985.                 gEnv->GetJobManager()->WaitForJob(m_pUpdateTerrainTempData->m_JobStateBuildVertices);
  986.  
  987.                 if (m_pUpdateTerrainTempData->m_StripsInfo.idx_array.Count() == 0)
  988.                         m_pUpdateTerrainTempData->m_lstTmpVertArray.Clear();
  989.         }
  990.  
  991.         // if an allocation failed, destroy the temp data and return
  992.         if (m_pUpdateTerrainTempData->m_StripsInfo.idx_array.MemorySize() == 0 ||
  993.             m_pUpdateTerrainTempData->m_lstTmpVertArray.MemorySize() == 0)
  994.                 return;
  995.  
  996.         STerrainNodeLeafData* pLeafData = GetLeafData();
  997.         if (!pLeafData)
  998.                 return;
  999.  
  1000.         _smart_ptr<IRenderMesh>& pRenderMesh = pLeafData->m_pRenderMesh;
  1001.  
  1002.         InvalidatePermanentRenderObject();
  1003.  
  1004.         UpdateRenderMesh(&m_pUpdateTerrainTempData->m_StripsInfo, !m_bUpdateOnlyBorders);
  1005.  
  1006.         m_cCurrGeomMML = m_cNewGeomMML;
  1007.  
  1008.         // update detail layers indices
  1009.         if (passInfo.RenderTerrainDetailMaterial())
  1010.         {
  1011.                 // build all indices
  1012.                 GenerateIndicesForAllSurfaces(pRenderMesh, m_bUpdateOnlyBorders, pLeafData->m_arrpNonBorderIdxNum, m_pUpdateTerrainTempData->m_StripsInfo.nNonBorderIndicesCount, 0, m_nSID, m_pUpdateTerrainTempData);
  1013.  
  1014.                 m_lstReadyTypes.Clear(); // protection from duplications in palette of types
  1015.  
  1016.                 uint8 szProj[] = "XYZ";
  1017.                 for (int i = 0; i < m_lstSurfaceTypeInfo.Count(); i++)
  1018.                 {
  1019.                         SSurfaceType* pSurfaceType = m_lstSurfaceTypeInfo[i].pSurfaceType;
  1020.  
  1021.                         if (pSurfaceType && pSurfaceType->ucThisSurfaceTypeId < SRangeInfo::e_undefined)
  1022.                         {
  1023.                                 if (m_lstReadyTypes.Find(pSurfaceType) < 0)
  1024.                                 {
  1025.                                         bool b3D = pSurfaceType->IsMaterial3D();
  1026.                                         for (int p = 0; p < 3; p++)
  1027.                                         {
  1028.                                                 if (b3D || pSurfaceType->GetMaterialOfProjection(szProj[p]))
  1029.                                                 {
  1030.                                                         int nProjId = b3D ? p : 3;
  1031.                                                         PodArray<vtx_idx>& lstIndices = m_arrIndices[pSurfaceType->ucThisSurfaceTypeId][nProjId];
  1032.  
  1033.                                                         if (!m_bUpdateOnlyBorders && m_lstSurfaceTypeInfo[i].arrpRM[p] && (lstIndices.Count() != m_lstSurfaceTypeInfo[i].arrpRM[p]->GetIndicesCount()))
  1034.                                                         {
  1035.                                                                 m_lstSurfaceTypeInfo[i].arrpRM[p] = NULL;
  1036.                                                         }
  1037.  
  1038.                                                         if (lstIndices.Count())
  1039.                                                                 UpdateSurfaceRenderMeshes(pRenderMesh, pSurfaceType, m_lstSurfaceTypeInfo[i].arrpRM[p], p, lstIndices, "TerrainMaterialLayer", m_bUpdateOnlyBorders, pLeafData->m_arrpNonBorderIdxNum[pSurfaceType->ucThisSurfaceTypeId][nProjId], passInfo);
  1040.  
  1041.                                                         if (!b3D)
  1042.                                                                 break;
  1043.                                                 }
  1044.                                         }
  1045.                                         m_lstReadyTypes.Add(pSurfaceType);
  1046.                                 }
  1047.                         }
  1048.                 }
  1049.         }
  1050.  
  1051.         DrawArray(passInfo);
  1052. }
  1053.  
  1054. void CTerrainNode::BuildIndices_Wrapper(SRenderingPassInfo passInfo)
  1055. {
  1056.         CUpdateTerrainTempData* pUpdateTerrainTempData = m_pUpdateTerrainTempData;
  1057.  
  1058.         // don't try to create terrain data if an allocation failed
  1059.         if (pUpdateTerrainTempData->m_StripsInfo.idx_array.MemorySize() == 0) return;
  1060.  
  1061.         STerrainNodeLeafData* pLeafData = GetLeafData();
  1062.         PodArray<CTerrainNode*>& lstNeighbourSectors = pLeafData->m_lstNeighbourSectors;
  1063.         PodArray<uint8>& lstNeighbourLods = pLeafData->m_lstNeighbourLods;
  1064.         lstNeighbourSectors.Clear();
  1065.         BuildIndices(pUpdateTerrainTempData->m_StripsInfo, &lstNeighbourSectors, false, passInfo);
  1066.  
  1067.         // remember neighbor LOD's
  1068.         for (int i = 0; i < lstNeighbourSectors.Count(); i++)
  1069.         {
  1070.                 int nNeighbourMML = lstNeighbourSectors[i]->GetAreaLOD(passInfo);
  1071.                 assert(0 <= nNeighbourMML && nNeighbourMML <= ((uint8) - 1));
  1072.                 lstNeighbourLods[i] = nNeighbourMML;
  1073.         }
  1074. }
  1075.  
  1076. void CTerrainNode::BuildVertices_Wrapper()
  1077. {
  1078.         // don't try to create terrain data if an allocation failed
  1079.         if (m_pUpdateTerrainTempData->m_lstTmpVertArray.MemorySize() == 0)
  1080.                 return;
  1081.  
  1082.         STerrainNodeLeafData* pLeafData = GetLeafData();
  1083.         if (!pLeafData)
  1084.                 return;
  1085.  
  1086.         _smart_ptr<IRenderMesh>& pRenderMesh = pLeafData->m_pRenderMesh;
  1087.  
  1088.         // 1U<<MML_NOT_SET will generate zero
  1089.         if (m_cNewGeomMML == MML_NOT_SET)
  1090.                 return;
  1091.  
  1092.         int nStep = (1 << m_cNewGeomMML) * CTerrain::GetHeightMapUnitSize();
  1093.         int nSectorSize = CTerrain::GetSectorSize() << m_nTreeLevel;
  1094.         assert(nStep && nStep <= nSectorSize);
  1095.         if (nStep > nSectorSize)
  1096.                 nStep = nSectorSize;
  1097.  
  1098.         // this could cost performace? to allow parallel execution, we cannot check for unchanged indices
  1099. #if 1
  1100.         BuildVertices(nStep, false);
  1101.         m_bUpdateOnlyBorders = false;
  1102. #else
  1103.         // update vertices if needed
  1104.         int nVertsNumRequired = (nSectorSize / nStep) * (nSectorSize / nStep) + (nSectorSize / nStep) + (nSectorSize / nStep) + 1;
  1105.         if (!pRenderMesh || m_cCurrGeomMML != m_cNewGeomMML || nVertsNumRequired != pRenderMesh->GetVerticesCount() || m_bEditor || !m_cNewGeomMML)
  1106.         {
  1107.                 if (m_pUpdateTerrainTempData->m_StripsInfo.idx_array.Count())
  1108.                         BuildVertices(nStep, false);
  1109.                 else
  1110.                         m_pUpdateTerrainTempData->m_lstTmpVertArray.Clear();
  1111.  
  1112.                 m_bUpdateOnlyBorders = false;
  1113.         }
  1114.         else
  1115.         {
  1116.                 m_bUpdateOnlyBorders = true;
  1117.         }
  1118. #endif
  1119.  
  1120. }
  1121.  
  1122. int GetVecProjectId(const Vec3& vNorm)
  1123. {
  1124.         Vec3 vNormAbs = vNorm.abs();
  1125.  
  1126.         int nOpenId = 0;
  1127.  
  1128.         if (vNormAbs.x >= vNormAbs.y && vNormAbs.x >= vNormAbs.z)
  1129.                 nOpenId = 0;
  1130.         else if (vNormAbs.y >= vNormAbs.x && vNormAbs.y >= vNormAbs.z)
  1131.                 nOpenId = 1;
  1132.         else
  1133.                 nOpenId = 2;
  1134.  
  1135.         return nOpenId;
  1136. }
  1137.  
  1138. void CTerrainNode::GenerateIndicesForAllSurfaces(IRenderMesh* pRM, bool bOnlyBorder, int arrpNonBorderIdxNum[SRangeInfo::e_max_surface_types][4], int nBorderStartIndex, SSurfaceTypeInfo* pSurfaceTypeInfos, int nSID, CUpdateTerrainTempData* pUpdateTerrainTempData)
  1139. {
  1140.         FUNCTION_PROFILER_3DENGINE;
  1141.  
  1142.         byte arrMat3DFlag[SRangeInfo::e_max_surface_types];
  1143.  
  1144.         enum { ARR_INDICES_0_BUFFER_SIZE = 8192 * 3, ARR_INDICES_BUFFER_SIZE = 2048 * 3 };
  1145.  
  1146.         m_arrIndices[0][3].reserve(ARR_INDICES_0_BUFFER_SIZE);
  1147.  
  1148.         for (int s = 0; s < SRangeInfo::e_max_surface_types; s++)
  1149.         {
  1150.                 if (s < 10)
  1151.                 {
  1152.                         m_arrIndices[s][3].reserve(ARR_INDICES_BUFFER_SIZE);
  1153.                 }
  1154.  
  1155.                 for (int p = 0; p < 4; p++)
  1156.                 {
  1157.                         m_arrIndices[s][p].Clear();
  1158.  
  1159.                         if (!bOnlyBorder)
  1160.                                 arrpNonBorderIdxNum[s][p] = -1;
  1161.                 }
  1162.  
  1163.                 if (pSurfaceTypeInfos)
  1164.                 {
  1165.                         if (pSurfaceTypeInfos[s].pSurfaceType)
  1166.                                 arrMat3DFlag[s] = pSurfaceTypeInfos[s].pSurfaceType->IsMaterial3D();
  1167.                 }
  1168.                 else
  1169.                         arrMat3DFlag[s] = GetTerrain()->GetSurfaceTypes(nSID)[s].IsMaterial3D();
  1170.         }
  1171.  
  1172.         int nSrcCount = 0;
  1173.         vtx_idx* pSrcInds = NULL;
  1174.         byte* pPosPtr = NULL;
  1175.         int nColorStride = 0;
  1176.         byte* pColor = NULL;
  1177.         int nNormStride = 0;
  1178.         byte* pNormB = NULL;
  1179.  
  1180.         bool useMesh = false;
  1181.  
  1182.         // when possible, use the already on ppu computed data instead of going through the rendermesh
  1183.         if (pUpdateTerrainTempData && !bOnlyBorder)
  1184.         {
  1185.                 nSrcCount = pUpdateTerrainTempData->m_StripsInfo.idx_array.Count();
  1186.                 if (!nSrcCount)
  1187.                         return;
  1188.                 pSrcInds = pUpdateTerrainTempData->m_StripsInfo.idx_array.GetElements();
  1189.                 assert(pSrcInds);
  1190.                 if (!pSrcInds)
  1191.                         return;
  1192.  
  1193.                 pPosPtr = reinterpret_cast<byte*>(pUpdateTerrainTempData->m_lstTmpVertArray.GetElements());
  1194.                 uint32 nColorOffset = offsetof(SVF_P2S_N4B_C4B_T1F, color.dcolor);
  1195.                 nColorStride = sizeof(SVF_P2S_N4B_C4B_T1F);
  1196.                 pColor = pPosPtr + nColorOffset;
  1197.  
  1198.                 nNormStride = sizeof(SVF_P2S_N4B_C4B_T1F);
  1199.                 uint32 nNormOffset = offsetof(SVF_P2S_N4B_C4B_T1F, normal);
  1200.                 pNormB = pPosPtr + nNormOffset;
  1201.         }
  1202.         else
  1203.         {
  1204.                 pRM->LockForThreadAccess();
  1205.  
  1206.                 // we don't have all data we need, get it from the rendermesh
  1207.                 nSrcCount = pRM->GetIndicesCount();
  1208.                 if (!nSrcCount)
  1209.                         return;
  1210.                 pSrcInds = pRM->GetIndexPtr(FSL_READ);
  1211.                 assert(pSrcInds);
  1212.                 if (!pSrcInds)
  1213.                         return;
  1214.  
  1215.                 pColor = pRM->GetColorPtr(nColorStride, FSL_READ);
  1216.                 pNormB = pRM->GetNormPtr(nNormStride, FSL_READ);
  1217.  
  1218.                 if (!pColor || !pNormB)
  1219.                 {
  1220.                         pRM->UnlockStream(VSF_GENERAL);
  1221.                         pRM->UnLockForThreadAccess();
  1222.                         return;
  1223.                 }
  1224.                 else assert(0);
  1225.  
  1226.                 useMesh = true;
  1227.         }
  1228.  
  1229.         //      for(int i=0; pColor && i<pRM->GetChunks()->Count(); i++)
  1230.         {
  1231.                 //      CRenderChunk * pChunk = pRM->GetChunks()->Get(i);
  1232.  
  1233.                 int nVertCount = pRM->GetVerticesCount();
  1234.  
  1235.                 for (int j = (bOnlyBorder ? nBorderStartIndex : 0); j < nSrcCount; j += 3)
  1236.                 {
  1237.                         vtx_idx arrTriangle[3] = { pSrcInds[j + 0], pSrcInds[j + 1], pSrcInds[j + 2] };
  1238.  
  1239.                         // ignore invalid triangles
  1240.                         if (arrTriangle[0] == arrTriangle[1] || arrTriangle[1] == arrTriangle[2] || arrTriangle[2] == arrTriangle[0])
  1241.                                 continue;
  1242.  
  1243.                         assert(arrTriangle[0] < (unsigned)nVertCount && arrTriangle[1] < (unsigned)nVertCount && arrTriangle[2] < (unsigned)nVertCount);
  1244.  
  1245.                         if (arrTriangle[0] >= (unsigned)nVertCount || arrTriangle[1] >= (unsigned)nVertCount || arrTriangle[2] >= (unsigned)nVertCount)
  1246.                                 continue;
  1247.  
  1248.                         UCol& Color0 = *(UCol*)&pColor[arrTriangle[0] * nColorStride];
  1249.                         UCol& Color1 = *(UCol*)&pColor[arrTriangle[1] * nColorStride];
  1250.                         UCol& Color2 = *(UCol*)&pColor[arrTriangle[2] * nColorStride];
  1251.  
  1252.                         uint32 nVertSurfId0 = Color0.bcolor[1] & SRangeInfo::e_undefined;
  1253.                         uint32 nVertSurfId1 = Color1.bcolor[1] & SRangeInfo::e_undefined;
  1254.                         uint32 nVertSurfId2 = Color2.bcolor[1] & SRangeInfo::e_undefined;
  1255.  
  1256.                         nVertSurfId0 = CLAMP(nVertSurfId0, 0, SRangeInfo::e_undefined);
  1257.                         nVertSurfId1 = CLAMP(nVertSurfId1, 0, SRangeInfo::e_undefined);
  1258.                         nVertSurfId2 = CLAMP(nVertSurfId2, 0, SRangeInfo::e_undefined);
  1259.  
  1260.                         int lstSurfTypes[3];
  1261.                         int idxSurfTypes(0);
  1262.                         lstSurfTypes[idxSurfTypes++] = nVertSurfId0;
  1263.                         if (nVertSurfId1 != nVertSurfId0)
  1264.                                 lstSurfTypes[idxSurfTypes++] = nVertSurfId1;
  1265.                         if (nVertSurfId2 != nVertSurfId0 && nVertSurfId2 != nVertSurfId1)
  1266.                                 lstSurfTypes[idxSurfTypes++] = nVertSurfId2;
  1267.  
  1268.                         int lstProjIds[3];
  1269.                         int idxProjIds(0);
  1270.  
  1271.                         byte* pNorm;
  1272.                         Vec3 vNorm;
  1273.  
  1274.                         // if there are 3d materials - analyze normals
  1275.                         if (arrMat3DFlag[nVertSurfId0])
  1276.                         {
  1277.                                 pNorm = &pNormB[arrTriangle[0] * nNormStride];
  1278.                                 vNorm.Set(((float)pNorm[0] - 127.5f), ((float)pNorm[1] - 127.5f), ((float)pNorm[2] - 127.5f));
  1279.                                 int nProjId0 = GetVecProjectId(vNorm);
  1280.                                 lstProjIds[idxProjIds++] = nProjId0;
  1281.                         }
  1282.  
  1283.                         if (arrMat3DFlag[nVertSurfId1])
  1284.                         {
  1285.                                 pNorm = &pNormB[arrTriangle[1] * nNormStride];
  1286.                                 vNorm.Set(((float)pNorm[0] - 127.5f), ((float)pNorm[1] - 127.5f), ((float)pNorm[2] - 127.5f));
  1287.                                 int nProjId1 = GetVecProjectId(vNorm);
  1288.                                 if (idxProjIds == 0 || lstProjIds[0] != nProjId1)
  1289.                                         lstProjIds[idxProjIds++] = nProjId1;
  1290.                         }
  1291.  
  1292.                         if (arrMat3DFlag[nVertSurfId2])
  1293.                         {
  1294.                                 pNorm = &pNormB[arrTriangle[2] * nNormStride];
  1295.                                 vNorm.Set(((float)pNorm[0] - 127.5f), ((float)pNorm[1] - 127.5f), ((float)pNorm[2] - 127.5f));
  1296.                                 int nProjId2 = GetVecProjectId(vNorm);
  1297.                                 if ((idxProjIds < 2 || lstProjIds[1] != nProjId2) &&
  1298.                                     (idxProjIds < 1 || lstProjIds[0] != nProjId2))
  1299.                                         lstProjIds[idxProjIds++] = nProjId2;
  1300.                         }
  1301.  
  1302.                         // if not 3d materials found
  1303.                         if (!arrMat3DFlag[nVertSurfId0] || !arrMat3DFlag[nVertSurfId1] || !arrMat3DFlag[nVertSurfId2])
  1304.                                 lstProjIds[idxProjIds++] = 3;
  1305.  
  1306.                         for (int s = 0; s < idxSurfTypes; s++)
  1307.                         {
  1308.                                 if (lstSurfTypes[s] == SRangeInfo::e_undefined)
  1309.                                 {
  1310.                                         continue;
  1311.                                 }
  1312.  
  1313.                                 for (int p = 0; p < idxProjIds; p++)
  1314.                                 {
  1315.                                         assert(lstSurfTypes[s] >= 0 && lstSurfTypes[s] < SRangeInfo::e_undefined);
  1316.                                         assert(lstProjIds[p] >= 0 && lstProjIds[p] < 4);
  1317.                                         PodArray<vtx_idx>& rList = m_arrIndices[lstSurfTypes[s]][lstProjIds[p]];
  1318.  
  1319.                                         if (!bOnlyBorder && j >= nBorderStartIndex && arrpNonBorderIdxNum[lstSurfTypes[s]][lstProjIds[p]] < 0)
  1320.                                                 arrpNonBorderIdxNum[lstSurfTypes[s]][lstProjIds[p]] = rList.Count();
  1321.  
  1322.                                         rList.AddList(arrTriangle, 3);
  1323.                                 }
  1324.                         }
  1325.                 }
  1326.         }
  1327.  
  1328.         if (useMesh)
  1329.         {
  1330.                 pRM->UnlockStream(VSF_GENERAL);
  1331.                 pRM->UnLockForThreadAccess();
  1332.         }
  1333.  
  1334. }
  1335.  
  1336. void CTerrainNode::UpdateSurfaceRenderMeshes(const _smart_ptr<IRenderMesh> pSrcRM, SSurfaceType* pSurface, _smart_ptr<IRenderMesh>& pMatRM, int nProjectionId,
  1337.                                              PodArray<vtx_idx>& lstIndices, const char* szComment, bool bUpdateOnlyBorders, int nNonBorderIndicesCount,
  1338.                                              const SRenderingPassInfo& passInfo)
  1339. {
  1340.         FUNCTION_PROFILER_3DENGINE;
  1341.  
  1342.         // force new rendermesh if vertex container has changed. Vertex containers aren't thread
  1343.         // safe, but seems like maybe something relies on this behaviour since fixing it on RM side
  1344.         // causes flickering.
  1345.         if (!pMatRM || (pMatRM && pMatRM->GetVertexContainer() != pSrcRM))
  1346.         {
  1347.                 ERenderMeshType eRMType = eRMT_Static;
  1348.  
  1349.                 bool bMultiGPU;
  1350.                 gEnv->pRenderer->EF_Query(EFQ_MultiGPUEnabled, bMultiGPU);
  1351.  
  1352.                 if (bMultiGPU && gEnv->pRenderer->GetRenderType() != eRT_DX12)
  1353.                         eRMType = eRMT_Dynamic;
  1354.  
  1355.                 pMatRM = GetRenderer()->CreateRenderMeshInitialized(
  1356.                   NULL, 0, eVF_P2S_N4B_C4B_T1F, NULL, 0,
  1357.                   prtTriangleList, szComment, szComment, eRMType, 1, 0, NULL, NULL, false, false);
  1358.         }
  1359.  
  1360.         uint8 szProj[] = "XYZ";
  1361.  
  1362.         pMatRM->LockForThreadAccess();
  1363.         pMatRM->SetVertexContainer(pSrcRM);
  1364.  
  1365.         assert(1 || nNonBorderIndicesCount >= 0);
  1366.  
  1367.         if (bUpdateOnlyBorders)
  1368.         {
  1369.                 int nOldIndexCount = pMatRM->GetIndicesCount();
  1370.  
  1371.                 if (nNonBorderIndicesCount < 0 || !nOldIndexCount)
  1372.                 {
  1373.                         pMatRM->UnLockForThreadAccess();
  1374.                         return; // no borders involved
  1375.                 }
  1376.  
  1377.                 vtx_idx* pIndicesOld = pMatRM->GetIndexPtr(FSL_READ);
  1378.  
  1379.                 int nIndexCountNew = nNonBorderIndicesCount + lstIndices.Count();
  1380.  
  1381.                 assert(true || nIndexCountNew >= lstIndices.Count());
  1382.  
  1383.                 //C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead
  1384.                 PREFAST_SUPPRESS_WARNING(6255)
  1385.                 vtx_idx * pIndicesNew = (vtx_idx*) alloca(sizeof(vtx_idx) * nIndexCountNew);
  1386.  
  1387.                 memcpy(pIndicesNew, pIndicesOld, sizeof(vtx_idx) * nNonBorderIndicesCount);
  1388.  
  1389.                 memcpy(pIndicesNew + nNonBorderIndicesCount, lstIndices.GetElements(), sizeof(vtx_idx) * lstIndices.Count());
  1390.  
  1391.                 pMatRM->UpdateIndices(pIndicesNew, nIndexCountNew, 0, 0u);
  1392.                 pMatRM->SetChunk(pSurface->GetMaterialOfProjection(szProj[nProjectionId]), 0, pSrcRM->GetVerticesCount(), 0, nIndexCountNew, 1.0f);
  1393.         }
  1394.         else
  1395.         {
  1396.                 pMatRM->UpdateIndices(lstIndices.GetElements(), lstIndices.Count(), 0, 0u);
  1397.                 pMatRM->SetChunk(pSurface->GetMaterialOfProjection(szProj[nProjectionId]), 0, pSrcRM->GetVerticesCount(), 0, lstIndices.Count(), 1.0f);
  1398.         }
  1399.  
  1400.         assert(nProjectionId >= 0 && nProjectionId < 3);
  1401.         float* pParams = pSurface->arrRECustomData[nProjectionId];
  1402.         SetupTexGenParams(pSurface, pParams, szProj[nProjectionId], true);
  1403.  
  1404.         // set surface type
  1405.         if (pSurface->IsMaterial3D())
  1406.         {
  1407.                 pParams[8] = (nProjectionId == 0);
  1408.                 pParams[9] = (nProjectionId == 1);
  1409.                 pParams[10] = (nProjectionId == 2);
  1410.         }
  1411.         else
  1412.         {
  1413.                 pParams[8] = 1.f;
  1414.                 pParams[9] = 1.f;
  1415.                 pParams[10] = 1.f;
  1416.         }
  1417.  
  1418.         pParams[11] = pSurface->ucThisSurfaceTypeId;
  1419.  
  1420.         // set texgen offset
  1421.         Vec3 vCamPos = passInfo.GetCamera().GetPosition();
  1422.  
  1423.         pParams[12] = pParams[13] = pParams[14] = pParams[15] = 0;
  1424.  
  1425.         // for diffuse
  1426.         if (IMaterial* pMat = pSurface->GetMaterialOfProjection(szProj[nProjectionId]))
  1427.                 if (pMat->GetShaderItem().m_pShaderResources)
  1428.                 {
  1429.                         if (SEfResTexture* pTex = pMat->GetShaderItem().m_pShaderResources->GetTexture(EFTT_DIFFUSE))
  1430.                         {
  1431.                                 float fScaleX = pTex->m_bUTile ? pTex->GetTiling(0) * pSurface->fScale : 1.f;
  1432.                                 float fScaleY = pTex->m_bVTile ? pTex->GetTiling(1) * pSurface->fScale : 1.f;
  1433.  
  1434.                                 pParams[12] = int(vCamPos.x * fScaleX) / fScaleX;
  1435.                                 pParams[13] = int(vCamPos.y * fScaleY) / fScaleY;
  1436.                         }
  1437.  
  1438.                         if (SEfResTexture* pTex = pMat->GetShaderItem().m_pShaderResources->GetTexture(EFTT_NORMALS))
  1439.                         {
  1440.                                 float fScaleX = pTex->m_bUTile ? pTex->GetTiling(0) * pSurface->fScale : 1.f;
  1441.                                 float fScaleY = pTex->m_bVTile ? pTex->GetTiling(1) * pSurface->fScale : 1.f;
  1442.  
  1443.                                 pParams[14] = int(vCamPos.x * fScaleX) / fScaleX;
  1444.                                 pParams[15] = int(vCamPos.y * fScaleY) / fScaleY;
  1445.                         }
  1446.                 }
  1447.  
  1448.         assert(8 + 8 <= ARR_TEX_OFFSETS_SIZE_DET_MAT);
  1449.  
  1450.         if (pMatRM->GetChunks().size() && pMatRM->GetChunks()[0].pRE)
  1451.         {
  1452.                 pMatRM->GetChunks()[0].pRE->m_CustomData = pParams;
  1453.                 pMatRM->GetChunks()[0].pRE->mfUpdateFlags(FCEF_DIRTY);
  1454.         }
  1455.  
  1456.         Vec3 vMin, vMax;
  1457.         pSrcRM->GetBBox(vMin, vMax);
  1458.         pMatRM->SetBBox(vMin, vMax);
  1459.         pMatRM->UnLockForThreadAccess();
  1460. }
  1461.  
  1462. STerrainNodeLeafData::~STerrainNodeLeafData()
  1463. {
  1464.         m_pRenderMesh = NULL;
  1465. }
  1466.  
  1467. void CTerrainUpdateDispatcher::RemoveJob(CTerrainNode* pNode)
  1468. {
  1469.         int index = m_arrRunningJobs.Find(pNode);
  1470.         if (index >= 0)
  1471.         {
  1472.                 m_arrRunningJobs.Delete(index);
  1473.                 return;
  1474.         }
  1475.  
  1476.         index = m_queuedJobs.Find(pNode);
  1477.         if (index >= 0)
  1478.         {
  1479.                 m_queuedJobs.Delete(index);
  1480.                 return;
  1481.         }
  1482. }
  1483.  
  1484. void AddIndexShared(int _x, int _y, PodArray<vtx_idx> & arrIndices, int nSectorSize)
  1485. {
  1486.         int _step = 1;
  1487.  
  1488.         vtx_idx id = _x / _step * (nSectorSize / _step + 1) + _y / _step;
  1489.  
  1490.         arrIndices.Add(id);
  1491. }
  1492.  
  1493. // Build single render mesh (with safety borders) to be re-used for multiple sectors
  1494. _smart_ptr<IRenderMesh> CTerrainNode::GetSharedRenderMesh()
  1495. {
  1496.         if (m_pTerrain->m_pSharedRenderMesh)
  1497.                 return m_pTerrain->m_pSharedRenderMesh;
  1498.  
  1499.         int nDim = 32;
  1500.         int nBorder = 1;
  1501.  
  1502.         SVF_P2S_N4B_C4B_T1F vert;
  1503.         ZeroStruct(vert);
  1504.  
  1505.         vert.normal.bcolor[0] = 128l;
  1506.         vert.normal.bcolor[1] = 128l;
  1507.         vert.normal.bcolor[2] = 255l;
  1508.         vert.normal.bcolor[3] = 255l;
  1509.  
  1510.         vert.color.bcolor[0] = 255l;
  1511.         vert.color.bcolor[1] = 0l;
  1512.         vert.color.bcolor[2] = 255l;
  1513.         vert.color.bcolor[3] = 255l;
  1514.  
  1515.         PodArray<SVF_P2S_N4B_C4B_T1F> arrVertices;
  1516.  
  1517.         for (int x = -nBorder; x <= (nDim + nBorder); x++)
  1518.         {
  1519.                 for (int y = -nBorder; y <= (nDim + nBorder); y++)
  1520.                 {
  1521.                         vert.xy = CryHalf2(SATURATE(float(x)/float(nDim)), SATURATE(float(y) / float(nDim)));
  1522.  
  1523.                         if(x<0 || y<0 || x>nDim || y>nDim)
  1524.                                 vert.z = -0.1f;
  1525.                         else
  1526.                                 vert.z = 0.f;
  1527.  
  1528.                         arrVertices.Add(vert);
  1529.                 }
  1530.         }
  1531.  
  1532.         PodArray<vtx_idx> arrIndices;
  1533.  
  1534.         int nDimEx = nDim + nBorder * 2;
  1535.  
  1536.         for (int x = 0; x < nDimEx; x++)
  1537.         {
  1538.                 for (int y = 0; y < nDimEx; y++)
  1539.                 {
  1540.                         AddIndexShared(x + 1, y + 0, arrIndices, nDimEx);
  1541.                         AddIndexShared(x + 1, y + 1, arrIndices, nDimEx);
  1542.                         AddIndexShared(x + 0, y + 0, arrIndices, nDimEx);
  1543.  
  1544.                         AddIndexShared(x + 0, y + 0, arrIndices, nDimEx);
  1545.                         AddIndexShared(x + 1, y + 1, arrIndices, nDimEx);
  1546.                         AddIndexShared(x + 0, y + 1, arrIndices, nDimEx);
  1547.                 }
  1548.         }
  1549.  
  1550.         m_pTerrain->m_pSharedRenderMesh = GetRenderer()->CreateRenderMeshInitialized(
  1551.                 arrVertices.GetElements(),
  1552.                 arrVertices.Count(),
  1553.                 eVF_P2S_N4B_C4B_T1F,
  1554.                 arrIndices.GetElements(),
  1555.                 arrIndices.Count(),
  1556.                 prtTriangleList,
  1557.                 "TerrainSectorSharedRenderMesh", "TerrainSectorSharedRenderMesh",
  1558.                 eRMT_Static);
  1559.  
  1560.         m_pTerrain->m_pSharedRenderMesh->SetChunk(NULL, 0, arrVertices.Count(), 0, arrIndices.Count(), 1.0f, 0);
  1561.  
  1562.         return m_pTerrain->m_pSharedRenderMesh;
  1563. }
  1564.  
  1565. uint32 CTerrainNode::GetMaterialsModificationId()
  1566. {
  1567.         uint32 nModificationId = 0;
  1568.  
  1569.         for (int i = 0; i < m_lstSurfaceTypeInfo.Count(); i++)
  1570.         {
  1571.                 if (!m_lstSurfaceTypeInfo[i].pSurfaceType->HasMaterial() || !m_lstSurfaceTypeInfo[i].HasRM())
  1572.                         continue;
  1573.  
  1574.                 uint8 szProj[] = "XYZ";
  1575.                 for (int p = 0; p < 3; p++)
  1576.                 {
  1577.                         if (SSurfaceType* pSurf = m_lstSurfaceTypeInfo[i].pSurfaceType)
  1578.                                 if (IMaterial* pMat = pSurf->GetMaterialOfProjection(szProj[p]))
  1579.                                 {
  1580.                                         if (CMatInfo* pMatInfo = (CMatInfo*)pMat)
  1581.                                                 nModificationId += pMatInfo->GetModificationId();
  1582.                                 }
  1583.                 }
  1584.         }
  1585.  
  1586.         return nModificationId;
  1587. }
  1588.  
downloadterrain_sector_render.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top