BVB Source Codes

CRYENGINE Show VoxelSegment.cpp Source code

Return Download CRYENGINE: download VoxelSegment.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:   VoxelSegment.cpp
  5. //  Created:     2012 by Vladimir Kajalin.
  6. //  Description: SVO brick implementation
  7. // -------------------------------------------------------------------------
  8. //  History:
  9. //
  10. ////////////////////////////////////////////////////////////////////////////
  11.  
  12. #include "StdAfx.h"
  13.  
  14. #if defined(FEATURE_SVO_GI)
  15.  
  16.         #include <CryCore/Platform/CryWindows.h>
  17.         #include "VoxelSegment.h"
  18.         #include "BlockPacker.h"
  19.         #include "visareas.h"
  20.         #include "brush.h"
  21.         #include "SceneTree.h"
  22.         #include <CryThreading/IJobManager_JobDelegator.h>
  23.         #include <CryAnimation/ICryAnimation.h>
  24.  
  25.         #define SVO_CPU_VOXELIZATION_OFFSET_MESH    0
  26.         #define SVO_CPU_VOXELIZATION_OFFSET_TERRAIN -0.04f
  27.         #define SVO_CPU_VOXELIZATION_OFFSET_VISAREA (Cry3DEngineBase::GetCVars()->e_svoMinNodeSize / (float)nVoxTexMaxDim)
  28.         #define SVO_CPU_VOXELIZATION_POOL_SIZE_MB   (12 * 1024)
  29.         #define SVO_CPU_VOXELIZATION_AREA_SCALE     200.f
  30.  
  31. CBlockPacker3D* CVoxelSegment::m_pBlockPacker = 0;
  32. CCamera CVoxelSegment::m_voxCam;
  33. const int nDistToSurfRange = 4;
  34. extern CSvoEnv* gSvoEnv;
  35. int CVoxelSegment::m_nAddPolygonToSceneCounter = 0;
  36. int CVoxelSegment::m_nCheckReadyCounter = 0;
  37. int CVoxelSegment::m_nCloudsCounter = 0;
  38. int CVoxelSegment::m_nPostponedCounter = 0;
  39. int CVoxelSegment::m_nCurrPassMainFrameID = 0;
  40. int CVoxelSegment::m_nMaxBrickUpdates = 128;
  41. int CVoxelSegment::m_nNextCloudId = 0;
  42. int CVoxelSegment::m_nPoolUsageBytes = 0;
  43. int CVoxelSegment::m_nPoolUsageItems = 0;
  44. int CVoxelSegment::m_nStreamingTasksInProgress = 0;
  45. int CVoxelSegment::m_nSvoDataPoolsCounter = 0;
  46. int CVoxelSegment::m_nTasksInProgressALL = 0;
  47. int CVoxelSegment::m_nUpdatesInProgressBri = 0;
  48. int CVoxelSegment::m_nUpdatesInProgressTex = 0;
  49. int CVoxelSegment::m_nVoxTrisCounter = 0;
  50. int CVoxelSegment::nVoxTexPoolDimXY = 0;
  51. int CVoxelSegment::nVoxTexPoolDimZ = 0;
  52. std::map<CStatObj*, float> CVoxelSegment::m_cgfTimeStats;
  53. CryReadModifyLock CVoxelSegment::m_cgfTimeStatsLock;
  54.  
  55. PodArrayRT<ITexture*> CVoxelSegment::m_arrLockedTextures;
  56. PodArrayRT<IMaterial*> CVoxelSegment::m_arrLockedMaterials;
  57.  
  58. PodArray<CVoxelSegment*> CVoxelSegment::m_arrLoadedSegments;
  59. SRenderingPassInfo* CVoxelSegment::m_pCurrPassInfo = 0;
  60.  
  61. #if CRY_PLATFORM_ORBIS
  62. int   _fseeki64(FILE* pFile, int64 nOffset, int nOrigin) { return fseek(pFile, (int32)nOffset, nOrigin); }
  63. int64 _ftelli64(FILE* pFile)                             { return ftell(pFile); }
  64. #endif
  65.  
  66. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  67. // Streaming engine
  68. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  69.  
  70. class CVoxStreamEngine
  71. {
  72. public:
  73.  
  74.         struct SVoxStreamItem
  75.         {
  76.                 static int32 Compare(const void* v1, const void* v2)
  77.                 {
  78.                         SVoxStreamItem* p[2] = { *(SVoxStreamItem**)v1, *(SVoxStreamItem**)v2 };
  79.  
  80.                         if (p[0]->nRequestFrameId > p[1]->nRequestFrameId)
  81.                                 return 1;
  82.                         if (p[0]->nRequestFrameId < p[1]->nRequestFrameId)
  83.                                 return -1;
  84.  
  85.         #ifdef FEATURE_SVO_GI_USE_FILE_STREAMING
  86.                         if (p[0]->nFileOffset > p[1]->nFileOffset)
  87.                                 return 1;
  88.                         if (p[0]->nFileOffset < p[1]->nFileOffset)
  89.                                 return -1;
  90.         #endif
  91.                         return 0;
  92.                 }
  93.  
  94.                 CVoxelSegment* pObj;
  95.         #ifdef FEATURE_SVO_GI_USE_FILE_STREAMING
  96.                 int64          nFileOffset;
  97.                 int            nBytesToRead;
  98.                 byte*          pReadData;
  99.         #endif
  100.                 uint           nRequestFrameId;
  101.         };
  102.  
  103.         void        ThreadEntry();
  104.  
  105.   #if CRY_PLATFORM_ORBIS
  106.         static void* FileReadThreadFunc(void* pUD)
  107.         {
  108.                 CVoxStreamEngine* pEng = (CVoxStreamEngine*)pUD;
  109.                 pEng->ThreadEntry();
  110.                 return NULL;
  111.         }
  112.   #else
  113.         static void FileReadThreadFunc(void* pUD)
  114.         {
  115.                 CVoxStreamEngine* pEng = (CVoxStreamEngine*)pUD;
  116.                 pEng->ThreadEntry();
  117.         }
  118.   #endif
  119.  
  120.         SThreadSafeArray<SVoxStreamItem*, 512> m_arrForFileRead;
  121.         SThreadSafeArray<SVoxStreamItem*, 512> m_arrForSyncCallBack;
  122.         #ifdef FEATURE_SVO_GI_USE_FILE_STREAMING
  123.         byte* m_pMemPool;
  124.         int   m_nPoolSize;
  125.         int   m_nPoolPos;
  126.         FILE* m_pFile;
  127.         #endif
  128.         bool  m_bDoResort;
  129.  
  130.         CVoxStreamEngine(string strFileName, int nPoolSize)
  131.         {
  132.                 m_bDoResort = false;
  133.         #ifdef FEATURE_SVO_GI_USE_FILE_STREAMING
  134.                 m_nPoolSize = nPoolSize;
  135.                 m_pMemPool = NULL;
  136.                 m_nPoolPos = 0;
  137.                 m_pFile = fopen(strFileName, "rb");
  138.                 if (m_pFile || Cry3DEngineBase::GetCVars()->e_svoTI_Active)
  139.         #endif
  140.                 {
  141.                         //                      const char * szThreadName = "SvoStreamEngine";
  142.                         //      if(!gEnv->pThreadManager->SpawnThread(this, szThreadName))
  143.                         //      {
  144.                         //        CRY_ASSERT_MESSAGE(false, string().Format("Error spawning \"%s\" thread.", szThreadName).c_str());
  145.                         //        __debugbreak();
  146.                         //      }
  147.                         //                      _beginthread(FileReadThreadFunc,0,(void*)this);
  148.  
  149.         #if CRY_PLATFORM_DURANGO
  150.                         void* m_thread;
  151.                         uint32 m_threadId;
  152.  
  153.                         m_threadId = 0;
  154.                         m_thread = (void*)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FileReadThreadFunc, (void*)this, 0, (LPDWORD)&m_threadId);
  155.                         SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
  156.  
  157.                         m_threadId = 0;
  158.                         m_thread = (void*)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FileReadThreadFunc, (void*)this, 0, (LPDWORD)&m_threadId);
  159.                         SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
  160.         #elif CRY_PLATFORM_ORBIS
  161.                         ScePthread m_thread0;
  162.                         ::scePthreadCreate(&m_thread0, nullptr, FileReadThreadFunc, (void*)this, "VoxelThread_0");
  163.                         ::scePthreadSetprio(m_thread0, THREAD_PRIORITY_BELOW_NORMAL);
  164.  
  165.                         ScePthread m_thread1;
  166.                         ::scePthreadCreate(&m_thread1, nullptr, FileReadThreadFunc, (void*)this, "VoxelThread_1");
  167.                         ::scePthreadSetprio(m_thread1, THREAD_PRIORITY_BELOW_NORMAL);
  168.         #else
  169.                         _beginthread(FileReadThreadFunc, 0, (void*)this);
  170.                         _beginthread(FileReadThreadFunc, 0, (void*)this);
  171.         #endif
  172.                 }
  173.         }
  174.  
  175.         ~CVoxStreamEngine()
  176.         {
  177.                 m_arrForFileRead.m_bThreadDone = true;
  178.  
  179.                 while (m_arrForFileRead.m_bThreadDone || CVoxelSegment::m_nTasksInProgressALL)
  180.                 {
  181.                         CrySleep(1);
  182.                 }
  183.         }
  184.  
  185.         void DecompressVoxStreamItem(SVoxStreamItem item)
  186.         {
  187.         #ifdef FEATURE_SVO_GI_USE_FILE_STREAMING
  188.                 item.pObj->StreamAsyncOnComplete(item.pReadData, item.nBytesToRead, (int)0);
  189.         #else
  190.                 item.pObj->StreamAsyncOnComplete(0, 0, 0);
  191.         #endif
  192.                 SVoxStreamItem* pNewItem = new SVoxStreamItem;
  193.                 *pNewItem = item;
  194.  
  195.                 m_arrForSyncCallBack.AddNewTaskToQeue(pNewItem);
  196.         }
  197.  
  198.         void ProcessSyncCallBacks()
  199.         {
  200.                 while (SVoxStreamItem* pItem = m_arrForSyncCallBack.GetNextTaskFromQeue())
  201.                 {
  202.                         pItem->pObj->StreamOnComplete();
  203.                         delete pItem;
  204.                         CVoxelSegment::m_nTasksInProgressALL--;
  205.                 }
  206.         }
  207.  
  208.         bool StartRead(CVoxelSegment* pObj, int64 nFileOffset, int nBytesToRead);
  209.  
  210. }* pVoxStreamEngine = 0;
  211.  
  212. DECLARE_JOB("VoxelSegmentFileDecompress", TDecompressVoxStreamItemJob, CVoxStreamEngine::DecompressVoxStreamItem);
  213.  
  214. void CVoxStreamEngine::ThreadEntry()
  215. {
  216.         while (1)
  217.         {
  218.                 if (m_bDoResort)
  219.                 {
  220.                         AUTO_LOCK(m_arrForFileRead.m_csQeue);
  221.                         qsort(m_arrForFileRead.m_arrQeue.GetElements(), m_arrForFileRead.m_arrQeue.Count(), sizeof(SVoxStreamItem*), SVoxStreamItem::Compare);
  222.                         m_bDoResort = false;
  223.                 }
  224.  
  225.                 if (SVoxStreamItem* pItem = m_arrForFileRead.GetNextTaskFromQeue())
  226.                 {
  227.         #ifdef FEATURE_SVO_GI_USE_FILE_STREAMING
  228.                         if (pItem->nBytesToRead > 0)
  229.                         {
  230.                                 // load data
  231.                                 _fseeki64(m_pFile, pItem->nFileOffset, SEEK_SET);
  232.  
  233.                                 if (m_nPoolPos + pItem->nBytesToRead >= m_nPoolSize)
  234.                                 {
  235.                                         m_nPoolPos = 0;
  236.                                         // Cry3DEngineBase::PrintMessage("Pool restart");
  237.                                 }
  238.  
  239.                                 if (!m_pMemPool)
  240.                                         m_pMemPool = new byte[m_nPoolSize];
  241.  
  242.                                 pItem->pReadData = &m_pMemPool[m_nPoolPos];
  243.                                 m_nPoolPos += pItem->nBytesToRead;
  244.  
  245.                                 if (pItem->nBytesToRead != ::fread(pItem->pReadData, 1, pItem->nBytesToRead, m_pFile))
  246.                                         CVoxelSegment::ErrorTerminate("FileReadThreadFunc, fread");
  247.                         }
  248.         #endif
  249.                         if (Cry3DEngineBase::GetCVars()->e_svoMaxStreamRequests > 4)
  250.                         {
  251.                                 TDecompressVoxStreamItemJob job(*pItem);
  252.                                 job.SetClassInstance(this);
  253.                                 job.SetPriorityLevel(JobManager::eStreamPriority);
  254.                                 job.Run();
  255.                         }
  256.                         else
  257.                         {
  258.                                 DecompressVoxStreamItem(*pItem);
  259.                                 // todo: wait in loop until all done, don't uase jobs
  260.                         }
  261.  
  262.                         delete pItem;
  263.                 }
  264.                 else
  265.                 {
  266.                         if (m_arrForFileRead.m_bThreadDone && !CVoxelSegment::m_nTasksInProgressALL)
  267.                                 break;
  268.  
  269.                         CrySleep(1);
  270.                 }
  271.         }
  272.  
  273.         m_arrForFileRead.m_bThreadDone = false;
  274. }
  275.  
  276. bool CVoxStreamEngine::StartRead(CVoxelSegment* pObj, int64 nFileOffset, int nBytesToRead)
  277. {
  278.         if (m_arrForFileRead.Count() >= m_arrForFileRead.m_nMaxQeueSize)
  279.                 return false;
  280.  
  281.         FUNCTION_PROFILER_3DENGINE;
  282.  
  283.         SVoxStreamItem* pNewItem = new SVoxStreamItem;
  284.         pNewItem->pObj = pObj;
  285.         #ifdef FEATURE_SVO_GI_USE_FILE_STREAMING
  286.         pNewItem->nFileOffset = nFileOffset;
  287.         pNewItem->nBytesToRead = nBytesToRead;
  288.         pNewItem->pReadData = 0;
  289.         #endif
  290.         pNewItem->nRequestFrameId = GetCurrPassMainFrameID() / 10;
  291.  
  292.         CVoxelSegment::m_nTasksInProgressALL++;
  293.  
  294.         m_arrForFileRead.AddNewTaskToQeue(pNewItem);
  295.  
  296.         m_bDoResort = true;
  297.  
  298.         return true;
  299. }
  300.  
  301. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  302. // Voxel Segment
  303. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  304.  
  305. CryCriticalSection CVoxelSegment::m_csLockBrick;
  306.  
  307. CVoxelSegment::CVoxelSegment(class CSvoNode* pNode, bool bDumpToDiskInUse, EFileStreamingStatus eStreamingStatus, bool bDroppedOnDisk)
  308. {
  309.         m_boxTris.Reset();
  310.         m_boxOS.Reset();
  311.         m_boxClipped.Reset();
  312.         m_dwChildTrisTest = 0;
  313.         m_eStreamingStatus = eStreamingStatus;
  314.         m_fMaxAlphaInBrick = 0;
  315.         m_nAllocatedAtlasOffset = -2;
  316.         m_nLastTexUpdateFrameId = m_nLastRendFrameId = 0;
  317.         m_nFileStreamOffset64 = m_nFileStreamSize = -1;
  318.         m_nChildOffsetsDirty = 0;
  319.         m_nCloudsCounter++;
  320.         m_nSegID = -1;
  321.         m_bStatLightsChanged = 0;
  322.         m_nVoxNum = 0;
  323.         m_pBlockInfo = 0;
  324.         m_pNode = pNode;
  325.         m_pParentCloud = 0;
  326.         m_pVoxOpacit = 0;
  327.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  328.         m_pVoxVolume = m_pVoxNormal = 0;
  329.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  330.         m_pVoxTris = 0;
  331.                 #endif
  332.         #endif
  333.         m_vCropBoxMin.zero();
  334.         m_vCropTexSize.zero();
  335.         m_vSegOrigin = Vec3(0, 0, 0);
  336.         m_vStaticGeomCheckSumm.zero();
  337.         m_vStatLightsCheckSumm.zero();
  338.         ZeroStruct(m_arrChildOffset);
  339. }
  340.  
  341. int32 CVoxelSegment::ComparemLastVisFrameID(const void* v1, const void* v2)
  342. {
  343.         CVoxelSegment* p[2] = { *(CVoxelSegment**)v1, *(CVoxelSegment**)v2 };
  344.  
  345.         uint arrNodeSize[2] =
  346.         {
  347.                 uint((p[0]->m_boxOS.max.x - p[0]->m_boxOS.min.x) * 4),
  348.                 uint((p[1]->m_boxOS.max.x - p[1]->m_boxOS.min.x) * 4)
  349.         };
  350.  
  351.         if ((p[0]->m_nLastRendFrameId + arrNodeSize[0]) > (p[1]->m_nLastRendFrameId + arrNodeSize[1]))
  352.                 return 1;
  353.         if ((p[0]->m_nLastRendFrameId + arrNodeSize[0]) < (p[1]->m_nLastRendFrameId + arrNodeSize[1]))
  354.                 return -1;
  355.  
  356.         if (p[0] > p[1])
  357.                 return 1;
  358.         if (p[0] < p[1])
  359.                 return -1;
  360.  
  361.         return 0;
  362. }
  363.  
  364. int CVoxelSegment::GetBrickPoolUsageMB()
  365. {
  366.         return gSvoEnv->m_cpuBricksAllocator.GetCapacity() * nVoxTexMaxDim * nVoxTexMaxDim * nVoxTexMaxDim * sizeof(ColorB) / 1024 / 1024;
  367. }
  368.  
  369. int CVoxelSegment::GetBrickPoolUsageLoadedMB()
  370. {
  371.         return gSvoEnv->m_cpuBricksAllocator.GetCount() * nVoxTexMaxDim * nVoxTexMaxDim * nVoxTexMaxDim * sizeof(ColorB) / 1024 / 1024;
  372. }
  373.  
  374. void CVoxelSegment::CheckAllocateBrick(ColorB*& pPtr, int nElems, bool bClean)
  375. {
  376.         if (pPtr)
  377.         {
  378.                 if (bClean)
  379.                         memset(pPtr, 0, nVoxTexMaxDim * nVoxTexMaxDim * nVoxTexMaxDim * sizeof(ColorB));
  380.  
  381.                 return;
  382.         }
  383.  
  384.         {
  385.                 AUTO_LOCK(m_csLockBrick);
  386.  
  387.                 pPtr = (ColorB*)gSvoEnv->m_cpuBricksAllocator.GetNewElement();
  388.         }
  389.  
  390.         memset(pPtr, 0, nVoxTexMaxDim * nVoxTexMaxDim * nVoxTexMaxDim * sizeof(ColorB));
  391. }
  392.  
  393. void CVoxelSegment::FreeBrick(ColorB*& pPtr)
  394. {
  395.         if (pPtr)
  396.         {
  397.                 AUTO_LOCK(m_csLockBrick);
  398.  
  399.                 gSvoEnv->m_cpuBricksAllocator.ReleaseElement((SCpuBrickItem*)pPtr);
  400.  
  401.                 pPtr = 0;
  402.         }
  403. }
  404.  
  405. int GetBrickDataSize(ColorB*& pPtr)
  406. {
  407.         return pPtr ? nVoxTexMaxDim * nVoxTexMaxDim * nVoxTexMaxDim * sizeof(ColorB) : 0;
  408. }
  409.  
  410. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  411. // CVoxelSegment
  412. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  413.  
  414. CVoxelSegment::~CVoxelSegment()
  415. {
  416.         m_arrLoadedSegments.Delete(this);
  417.         m_nCloudsCounter--;
  418.         FreeAllBrickData();
  419.         FreeRenderData();
  420. }
  421.  
  422. int32 IntersectPlaneAABB(const Plane& plane, const AABB& aabb)
  423. {
  424.         Vec3 extents = aabb.GetSize() * 0.5f;
  425.  
  426.         f32 d1 = plane.DistFromPlane(aabb.GetCenter());
  427.  
  428.         f32 d2 =
  429.           fabs(extents.x * plane.n.Dot(Vec3(1, 0, 0))) +
  430.           fabs(extents.y * plane.n.Dot(Vec3(0, 1, 0))) +
  431.           fabs(extents.z * plane.n.Dot(Vec3(0, 0, 1)));
  432.  
  433.         if (d1 - d2 > FLT_EPSILON)
  434.                 return +1;
  435.         if (d1 + d2 < -FLT_EPSILON)
  436.                 return -1;
  437.  
  438.         return 0;
  439. }
  440.  
  441. void CVoxelSegment::RenderMesh(CRenderObject* pObj, PodArray<SVF_P3F_C4B_T2F>& arrVertsOut)
  442. {
  443.         m_nLastRendFrameId = GetCurrPassMainFrameID();
  444.  
  445.         if (m_eStreamingStatus == ecss_Ready)
  446.         {
  447.                 if (!CheckUpdateBrickRenderData(true))
  448.                         return;
  449.  
  450.                 // accumulate DVR proxy mesh
  451.                 if ((GetCVars()->e_svoDVR == 10 && m_fMaxAlphaInBrick > 0.05) || GetCVars()->e_svoTI_Active)
  452.                         if (GetBoxSize() <= Cry3DEngineBase::GetCVars()->e_svoMaxNodeSize)
  453.                         {
  454.                                 arrVertsOut.Add(m_vertForGS);
  455.                                 m_nAddPolygonToSceneCounter++;
  456.                         }
  457.  
  458.                 DebugDrawVoxels();
  459.         }
  460. }
  461.  
  462. bool CVoxelSegment::LoadFromMem(CMemoryBlock* pMB)
  463. {
  464.         byte* pData = (byte*)pMB->GetData();
  465.         SVoxSegmentFileHeader* pHeader = (SVoxSegmentFileHeader*)pData;
  466.         m_nSegID = pHeader->nSecId;
  467.         m_boxOS = pHeader->box;
  468.         //m_vAverNormal = pHeader->vAverNormal;
  469.  
  470.         pData += sizeof(SVoxSegmentFileHeader);
  471.  
  472.         FreeAllBrickData();
  473.  
  474.         m_vCropTexSize = pHeader->vCropTexSize;
  475.         m_vCropBoxMin = pHeader->vCropBoxMin;
  476.  
  477.         int nTexDataSize = (m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z * sizeof(ColorB));
  478.  
  479.         if (gSvoEnv->m_nVoxTexFormat == eTF_BC3)
  480.         {
  481.                 Vec3i vDxtDim = GetDxtDim();
  482.                 nTexDataSize = (vDxtDim.x * vDxtDim.y * vDxtDim.z * sizeof(ColorB)) / 4;
  483.         }
  484.  
  485.         if (int nDataSize = nTexDataSize)
  486.         {
  487.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  488.                 // loads RGB
  489.                 CheckAllocateBrick(m_pVoxVolume, nDataSize / sizeof(ColorB));
  490.                 memcpy(m_pVoxVolume, pData, nDataSize);
  491.                 pData += nDataSize;
  492.  
  493.                 // load normals
  494.                 CheckAllocateBrick(m_pVoxNormal, nDataSize / sizeof(ColorB));
  495.                 memcpy(m_pVoxNormal, pData, nDataSize);
  496.                 pData += nDataSize;
  497.         #endif
  498.  
  499.                 CheckAllocateBrick(m_pVoxOpacit, nDataSize / sizeof(ColorB));
  500.                 memcpy(m_pVoxOpacit, pData, nDataSize);
  501.                 pData += nDataSize;
  502.  
  503.                 if (gSvoEnv->m_nVoxTexFormat == eTF_R8G8B8A8)
  504.                 {
  505.                         uint8 nMaxAlphaInBrick = 0;
  506.  
  507.                         int nPixNum = m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z;
  508.                         for (int i = 0; i < nPixNum; i++)
  509.                         {
  510.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  511.                                 ColorB& col = m_pVoxVolume[i];
  512.                                 std::swap(col.r, col.b);
  513.                                 nMaxAlphaInBrick = max(nMaxAlphaInBrick, col.a);
  514.  
  515.                                 ColorB& nor = m_pVoxNormal[i];
  516.                                 std::swap(nor.r, nor.b);
  517.         #endif
  518.                                 ColorB& op = m_pVoxOpacit[i];
  519.                                 std::swap(op.r, op.b);
  520.                         }
  521.  
  522.                         m_fMaxAlphaInBrick = 1.f / 255.f * (float)nMaxAlphaInBrick;
  523.                 }
  524.         }
  525.  
  526.         return true;
  527. }
  528.  
  529. Vec3i CVoxelSegment::GetDxtDim()
  530. {
  531.         if (m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z == 0)
  532.                 return Vec3i(0, 0, 0);
  533.  
  534.         Vec3i vDxtSize = m_vCropTexSize;
  535.  
  536.         // adjust X and Y sizes for DXT
  537.         for (int nC = 0; nC < 2; nC++)
  538.         {
  539.                 while (1)
  540.                 {
  541.                         if (((vDxtSize[nC]) % 4) == 0)
  542.                                 break;
  543.  
  544.                         vDxtSize[nC]++;
  545.                 }
  546.         }
  547.  
  548.         return vDxtSize;
  549. }
  550.  
  551. void CVoxelSegment::FreeAllBrickData()
  552. {
  553.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  554.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  555.         FreeBrick(m_pVoxTris);
  556.                 #endif
  557.         FreeBrick(m_pVoxNormal);
  558.         FreeBrick(m_pVoxVolume);
  559.         #endif
  560.         FreeBrick(m_pVoxOpacit);
  561.  
  562.         m_nodeTrisAllMerged.Reset();
  563.         m_boxTris.Reset();
  564.  
  565.         if (m_pTrisInArea && (!m_pParentCloud || !m_pParentCloud->m_pTrisInArea))
  566.         {
  567.                 m_pTrisInArea->Reset();
  568.                 m_pVertInArea->Reset();
  569.                 m_pMatsInArea->Reset();
  570.         }
  571. }
  572.  
  573. void CVoxelSegment::FreeRenderData()
  574. {
  575.         FreeAllBrickData();
  576.  
  577.         ReleaseAtlasBlock();
  578.  
  579.         m_eStreamingStatus = ecss_NotLoaded;
  580. }
  581.  
  582. void CVoxelSegment::MakeFolderName(char szFolder[256], bool bCreateDirectory)
  583. {
  584.         char szLevelFolder[MAX_PATH_LENGTH];
  585.         cry_strcpy(szLevelFolder, Cry3DEngineBase::Get3DEngine()->GetLevelFolder());
  586.         cry_strcat(szLevelFolder, "SvoData");
  587.         cry_sprintf(szFolder, 256, "%s/", szLevelFolder);
  588. }
  589.  
  590. string CVoxelSegment::m_strRenderDataFileName = "";
  591.  
  592. void CVoxelSegment::StreamAsyncOnComplete(byte* pDataRead, int nBytesRead, int nTID)
  593. {
  594.         FUNCTION_PROFILER_3DENGINE;
  595.  
  596.         if (m_nFileStreamSize < 0)
  597.         {
  598.                 VoxelizeMeshes(nTID);
  599.                 return;
  600.         }
  601.  
  602.         byte* pData = (byte*)pDataRead;
  603.         int nCompressedSize = *(int*)pData;
  604.         pData += 4;
  605.  
  606.         if (nCompressedSize)
  607.         {
  608.                 if ((nCompressedSize < 0) || (nCompressedSize > nVoxTexMaxDim * nVoxTexMaxDim * nVoxTexMaxDim * 4 * 4))
  609.                         ErrorTerminate("%s: Data corruption detected", __FUNCTION__);
  610.  
  611.                 CMemoryBlock mbComp;
  612.                 mbComp.Allocate(nCompressedSize);
  613.                 memcpy(mbComp.GetData(), pData, mbComp.GetSize());
  614.                 pData += mbComp.GetSize();
  615.  
  616.                 CMemoryBlock* pUnpacked = CMemoryBlock::DecompressFromMemBlock(&mbComp, GetSystem());
  617.                 if (!pUnpacked || !pUnpacked->GetSize())
  618.                         ErrorTerminate("%s: DecompressFromMemBlock error %s", __FUNCTION__, m_strRenderDataFileName.c_str());
  619.                 else
  620.                         LoadFromMem(pUnpacked);
  621.  
  622.                 delete pUnpacked;
  623.         }
  624.  
  625.         if (pData - (byte*)pDataRead != nBytesRead)
  626.                 PrintMessage("Error reading mesh from %s, %.1f", m_strRenderDataFileName.c_str(), float(nBytesRead) / 1024.f / 1024.f);
  627.         //      else
  628.         //      PrintMessage("Loaded mesh from %s, %.1f", m_strRenderDataFileName.c_str(), float(nBytesRead)/1024.f/1024.f);
  629. }
  630.  
  631. void CVoxelSegment::StreamOnComplete()
  632. {
  633.         FUNCTION_PROFILER_3DENGINE;
  634.  
  635.         m_eStreamingStatus = ecss_Ready;
  636.  
  637.         m_nStreamingTasksInProgress--;
  638.  
  639.         if (m_arrLoadedSegments.Find(this) < 0)
  640.                 m_arrLoadedSegments.Add(this);
  641.  
  642.         if (m_vCropTexSize.GetVolume() == 0 || !m_pVoxOpacit)
  643.         {
  644.                 if (GetBoxSize() <= GetCVars()->e_svoMaxNodeSize && m_pParentCloud && !Cry3DEngineBase::GetCVars()->e_svoTI_Troposphere_Subdivide)
  645.                 {
  646.                         CSvoNode** ppChilds = m_pParentCloud->m_pNode->m_ppChilds;
  647.  
  648.                         for (int nChildId = 0; nChildId < 8; nChildId++)
  649.                         {
  650.                                 if (ppChilds[nChildId] == m_pNode)
  651.                                 {
  652.                                         m_pParentCloud->m_pNode->m_arrChildNotNeeded[nChildId] = true;
  653.                                 }
  654.                         }
  655.                 }
  656.         }
  657. }
  658.  
  659. void CVoxelSegment::UnloadStreamableData()
  660. {
  661.         FreeRenderData();
  662.  
  663.         m_arrLoadedSegments.Delete(this);
  664.  
  665.         m_eStreamingStatus = ecss_NotLoaded;
  666.  
  667.         //      char szFileName[256];
  668.         //MakeFileName("CCM", szFileName);
  669.  
  670.         //      PrintMessage("Unloaded mesh (%d) %s", m_arrLoadedSegments.Count(), szFileName);
  671. }
  672.  
  673. bool CVoxelSegment::StartStreaming()
  674. {
  675.         if (m_eStreamingStatus == ecss_InProgress)
  676.                 return true;
  677.  
  678.         if (m_eStreamingStatus != ecss_NotLoaded)
  679.                 return true;
  680.  
  681.         if (!pVoxStreamEngine)
  682.                 pVoxStreamEngine = new CVoxStreamEngine(m_strRenderDataFileName, 128 * 1024 * 1024);
  683.  
  684.         if (!pVoxStreamEngine->StartRead(this, m_nFileStreamOffset64, m_nFileStreamSize))
  685.                 return false;
  686.  
  687.         m_eStreamingStatus = ecss_InProgress;
  688.  
  689.         m_nStreamingTasksInProgress++;
  690.  
  691.         return true;
  692. }
  693.  
  694. void CVoxelSegment::CropVoxTexture(int nTID, bool bCompSurfDist)
  695. {
  696.         m_vCropTexSize.Set(0, 0, 0);
  697.  
  698.         if (!GetBrickDataSize(m_pVoxOpacit))
  699.                 return;
  700.  
  701.         Vec3i vMin(nVoxTexMaxDim, nVoxTexMaxDim, nVoxTexMaxDim);
  702.         Vec3i vMax(0, 0, 0);
  703.  
  704.         for (int x = 0; x < nVoxTexMaxDim; x++)
  705.                 for (int y = 0; y < nVoxTexMaxDim; y++)
  706.                         for (int z = 0; z < nVoxTexMaxDim; z++)
  707.                         {
  708.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  709.                                 ColorB& colOut = m_pVoxVolume[z * nVoxTexMaxDim * nVoxTexMaxDim + y * nVoxTexMaxDim + x];
  710.                                 ColorB& norOut = m_pVoxNormal[z * nVoxTexMaxDim * nVoxTexMaxDim + y * nVoxTexMaxDim + x];
  711.         #endif
  712.  
  713.                                 ColorB& opaOut = m_pVoxOpacit[z * nVoxTexMaxDim * nVoxTexMaxDim + y * nVoxTexMaxDim + x];
  714.  
  715.                                 if (opaOut.r || opaOut.g || opaOut.b)
  716.                                 {
  717.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  718.                                         norOut.a = 255;
  719.         #endif
  720.                                 }
  721.  
  722.                                 if ((opaOut.r || opaOut.g || opaOut.b) /*|| GetCVars()->e_svoTI_Active*/ || Cry3DEngineBase::GetCVars()->e_svoTI_Troposphere_Subdivide)
  723.                                 {
  724.                                         vMin.CheckMin(Vec3i(x, y, z));
  725.                                         vMax.CheckMax(Vec3i(x + 1, y + 1, z + 1));
  726.                                 }
  727.                         }
  728.  
  729.         m_vCropTexSize = vMax - vMin;
  730.  
  731.         for (int d = 0; d < 3; d++)
  732.         {
  733.                 if (vMax[d] < nVoxTexMaxDim)
  734.                         vMax[d]++;
  735.  
  736.                 if (vMin[d] > 0)
  737.                         vMin[d]--;
  738.         }
  739.  
  740.         m_vCropTexSize = vMax - vMin;
  741.  
  742.         if (m_vCropTexSize.x > 0 && m_vCropTexSize.y > 0 && m_vCropTexSize.z > 0)
  743.         {
  744.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  745.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  746.                 ColorB* pTex3dOptTRIS = new ColorB[m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z];
  747.                 memset(pTex3dOptTRIS, 0, m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z * sizeof(ColorB));
  748.                 #endif
  749.                 ColorB* pTex3dOptRGBA = new ColorB[m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z];
  750.                 memset(pTex3dOptRGBA, 0, m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z * sizeof(ColorB));
  751.  
  752.                 ColorB* pTex3dOptNorm = new ColorB[m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z];
  753.                 memset(pTex3dOptNorm, 0, m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z * sizeof(ColorB));
  754.         #endif
  755.  
  756.                 ColorB* pTex3dOptOpas = new ColorB[m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z];
  757.                 memset(pTex3dOptOpas, 0, m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z * sizeof(ColorB));
  758.  
  759.                 for (int x = 0; x < m_vCropTexSize.x; x++)
  760.                         for (int y = 0; y < m_vCropTexSize.y; y++)
  761.                                 for (int z = 0; z < m_vCropTexSize.z; z++)
  762.                                 {
  763.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  764.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  765.                                         ColorB& triOut = pTex3dOptTRIS[z * m_vCropTexSize.x * m_vCropTexSize.y + y * m_vCropTexSize.x + x];
  766.                 #endif
  767.                                         ColorB& colOut = pTex3dOptRGBA[z * m_vCropTexSize.x * m_vCropTexSize.y + y * m_vCropTexSize.x + x];
  768.                                         ColorB& norOut = pTex3dOptNorm[z * m_vCropTexSize.x * m_vCropTexSize.y + y * m_vCropTexSize.x + x];
  769.         #endif
  770.                                         ColorB& opaOut = pTex3dOptOpas[z * m_vCropTexSize.x * m_vCropTexSize.y + y * m_vCropTexSize.x + x];
  771.  
  772.                                         int x_in = x + vMin.x;
  773.                                         int y_in = y + vMin.y;
  774.                                         int z_in = z + vMin.z;
  775.  
  776.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  777.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  778.                                         ColorB& triIn = m_pVoxTris[z_in * nVoxTexMaxDim * nVoxTexMaxDim + y_in * nVoxTexMaxDim + x_in];
  779.                 #endif
  780.                                         ColorB& colIn = m_pVoxVolume[z_in * nVoxTexMaxDim * nVoxTexMaxDim + y_in * nVoxTexMaxDim + x_in];
  781.                                         ColorB& norIn = m_pVoxNormal[z_in * nVoxTexMaxDim * nVoxTexMaxDim + y_in * nVoxTexMaxDim + x_in];
  782.         #endif
  783.                                         ColorB& opaIn = m_pVoxOpacit[z_in * nVoxTexMaxDim * nVoxTexMaxDim + y_in * nVoxTexMaxDim + x_in];
  784.  
  785.                                         if (opaIn.r || opaIn.g || opaIn.b)
  786.                                         {
  787.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  788.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  789.                                                 if (m_pVoxTris)
  790.                                                         triOut = triIn;
  791.                 #endif
  792.                                                 colOut = colIn;
  793.                                                 norOut = norIn;
  794.         #endif
  795.  
  796.                                                 opaOut = opaIn;
  797.                                         }
  798.                                 }
  799.                 /*
  800.                    static float fTimeSumm = 0;
  801.  
  802.                    {
  803.                    float fTimeStart = GetCurAsyncTimeSec();
  804.  
  805.                    if(bCompSurfDist)
  806.                    {
  807.                    #ifdef FEATURE_SVO_GI_ALLOW_HQ
  808.                     ComputeDistancesFast_MinDistToSurf(pTex3dOptRGBA, pTex3dOptNorm, pTex3dOptOpas, nTID);
  809.                    #endif
  810.                    }
  811.  
  812.                    fTimeSumm += GetCurAsyncTimeSec()-fTimeStart;
  813.                    }
  814.  
  815.                    static int nCount = 0;
  816.                    nCount++;
  817.                    if(nCount==1000)
  818.                    {
  819.                    Cry3DEngineBase::PrintMessage("%s: fTimeSumm = %.1f for %d nodes", __FUNCTION__, fTimeSumm, nCount);
  820.                    //CVoxelSegment::ErrorTerminate("CVoxelSegment::SetDistanceToClosestVoxel: fTimeSumm = %.1f for %d nodes", fTimeSumm, nCount);
  821.                    }
  822.                  */
  823.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  824.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  825.                 if (m_pVoxTris)
  826.                         memcpy(m_pVoxTris, pTex3dOptTRIS, sizeof(ColorB) * m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z);
  827.                 SAFE_DELETE_ARRAY(pTex3dOptTRIS);
  828.                 #endif
  829.                 memcpy(m_pVoxVolume, pTex3dOptRGBA, sizeof(ColorB) * m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z);
  830.                 SAFE_DELETE_ARRAY(pTex3dOptRGBA);
  831.  
  832.                 memcpy(m_pVoxNormal, pTex3dOptNorm, sizeof(ColorB) * m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z);
  833.                 SAFE_DELETE_ARRAY(pTex3dOptNorm);
  834.         #endif
  835.  
  836.                 memcpy(m_pVoxOpacit, pTex3dOptOpas, sizeof(ColorB) * m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z);
  837.                 SAFE_DELETE_ARRAY(pTex3dOptOpas);
  838.  
  839.                 m_vCropBoxMin = vMin;
  840.         }
  841.         else
  842.         {
  843.                 FreeAllBrickData();
  844.  
  845.                 m_vCropTexSize.zero();
  846.                 m_vCropBoxMin.zero();
  847.         }
  848. }
  849.  
  850. void CVoxelSegment::ComputeDistancesFast_MinDistToSurf(ColorB* pTex3dOptRGBA, ColorB* pTex3dOptNorm, ColorB* pTex3dOptOpac, int nTID)
  851. {
  852.         for (int Z = 0; Z < m_vCropTexSize.z; Z++)
  853.         {
  854.                 for (int Y = 0; Y < m_vCropTexSize.y; Y++)
  855.                 {
  856.                         for (int X = 0; X < m_vCropTexSize.x; X++)
  857.                         {
  858.                                 int idOut_ = Z * m_vCropTexSize.x * m_vCropTexSize.y + Y * m_vCropTexSize.x + X;
  859.  
  860.                                 ColorB& colOut_ = pTex3dOptRGBA[idOut_];
  861.                                 ColorB& norOut_ = pTex3dOptNorm[idOut_];
  862.  
  863.                                 if (colOut_.a != 255) // if empty
  864.                                 {
  865.                                         norOut_.a = 0;
  866.  
  867.                                         Vec3 v1((float)X, (float)Y, (float)Z);
  868.  
  869.                                         float fMinDistSq = 255 * 255 * 2;
  870.  
  871.                                         int _nNearestId = 0;
  872.  
  873.                                         int X1 = CLAMP(X - nDistToSurfRange, 0, m_vCropTexSize.x - 1);
  874.                                         int X2 = CLAMP(X + nDistToSurfRange, 0, m_vCropTexSize.x - 1);
  875.                                         int Y1 = CLAMP(Y - nDistToSurfRange, 0, m_vCropTexSize.y - 1);
  876.                                         int Y2 = CLAMP(Y + nDistToSurfRange, 0, m_vCropTexSize.y - 1);
  877.                                         int Z1 = CLAMP(Z - nDistToSurfRange, 0, m_vCropTexSize.z - 1);
  878.                                         int Z2 = CLAMP(Z + nDistToSurfRange, 0, m_vCropTexSize.z - 1);
  879.  
  880.                                         // find nearest voxel
  881.                                         for (int _x = X1; _x <= X2; _x++)
  882.                                                 for (int _y = Y1; _y <= Y2; _y++)
  883.                                                         for (int _z = Z1; _z <= Z2; _z++)
  884.                                                         {
  885.                                                                 int _idOut = (_z) * m_vCropTexSize.x * m_vCropTexSize.y + (_y) * m_vCropTexSize.x + (_x);
  886.  
  887.                                                                 const ColorB& colOut = pTex3dOptRGBA[_idOut];
  888.  
  889.                                                                 if (colOut.a == 255)
  890.                                                                 {
  891.                                                                         Vec3 v0((float)_x, (float)_y, (float)_z);
  892.                                                                         float fDistSq = v1.GetSquaredDistance(v0);
  893.  
  894.                                                                         if (fDistSq < fMinDistSq)
  895.                                                                         {
  896.                                                                                 fMinDistSq = fDistSq;
  897.                                                                                 _nNearestId = _idOut;
  898.                                                                         }
  899.                                                                 }
  900.                                                         }
  901.  
  902.                                         fMinDistSq = sqrt(fMinDistSq);
  903.  
  904.                                         if (fMinDistSq <= 4)
  905.                                                 norOut_.a = SATURATEB(255 - (int)fMinDistSq);
  906.                                 }
  907.                         }
  908.                 }
  909.         }
  910. }
  911.  
  912. bool CVoxelSegment::UpdateBrickRenderData()
  913. {
  914.         FUNCTION_PROFILER_3DENGINE;
  915.  
  916.         ReleaseAtlasBlock();
  917.  
  918.         if (!m_pBlockPacker)
  919.                 m_pBlockPacker = new CBlockPacker3D(nAtlasDimMaxXY, nAtlasDimMaxXY, nAtlasDimMaxZ, true);
  920.  
  921.         int nBlockW = max(1, (m_vCropTexSize.x + nVoxBloMaxDim - 1) / nVoxBloMaxDim);
  922.         int nBlockH = max(1, (m_vCropTexSize.y + nVoxBloMaxDim - 1) / nVoxBloMaxDim);
  923.         int nBlockD = max(1, (m_vCropTexSize.z + nVoxBloMaxDim - 1) / nVoxBloMaxDim);
  924.  
  925.         const float fMinNodeSize = Cry3DEngineBase::GetCVars()->e_svoMinNodeSize;
  926.  
  927.         const int nDataSizeStatsScale = 4;
  928.  
  929.         static int nLastStatFrame = 0;
  930.         if (nLastStatFrame != GetCurrPassMainFrameID())
  931.         {
  932.                 nLastStatFrame = GetCurrPassMainFrameID();
  933.  
  934.                 // count stats
  935.                 m_nPoolUsageItems = 0;
  936.                 m_nPoolUsageBytes = 0;
  937.  
  938.                 // remove 4 oldest blocks
  939.                 SBlockMinMax* pOldestBlockInfo[4] = { 0, 0, 0, 0 };
  940.                 uint nOldestVisFrameId[4] = { ~0U, ~0U, ~0U, ~0U };
  941.                 const uint nMaxAllowedFrameId = GetCurrPassMainFrameID() - 16;
  942.                 const uint nNumBlocks = m_pBlockPacker->GetNumBlocks();
  943.                 for (uint nBlockId = 0; nBlockId < nNumBlocks; nBlockId++)
  944.                 {
  945.                         if (SBlockMinMax* pInfo = m_pBlockPacker->GetBlockInfo(nBlockId))
  946.                         {
  947.                                 m_nPoolUsageItems++;
  948.                                 m_nPoolUsageBytes += nDataSizeStatsScale * pInfo->m_nDataSize;
  949.                         }
  950.                 }
  951.         }
  952.  
  953.         // TODO: pack multiple bricks into single compressed block and upload to GPU only once
  954.  
  955.         for (int nPass = 0; nPass < 16; nPass++)
  956.         {
  957.                 m_pBlockInfo = m_pBlockPacker->AddBlock(nBlockW, nBlockH, nBlockD,
  958.                                                         this, GetCurrPassMainFrameID(), m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z * (gSvoEnv->m_nVoxTexFormat == eTF_BC3 ? 1 : 4) / nDataSizeStatsScale);
  959.                 if (m_pBlockInfo)
  960.                 {
  961.                         bool bIsMultiThreadedRenderer = false;
  962.                         gEnv->pRenderer->EF_Query(EFQ_RenderMultithreaded, bIsMultiThreadedRenderer);
  963.  
  964.                         if (bIsMultiThreadedRenderer)
  965.                                 m_pNode->m_nRequestSegmentUpdateFrametId = max(m_pNode->m_nRequestSegmentUpdateFrametId, GetCurrPassMainFrameID() + 1);
  966.                         else
  967.                                 m_pNode->m_nRequestSegmentUpdateFrametId = max(m_pNode->m_nRequestSegmentUpdateFrametId, GetCurrPassMainFrameID() + 0);
  968.  
  969.                         m_vStatLightsCheckSumm.zero();
  970.                         break;
  971.                 }
  972.  
  973.                 // remove 4 oldest blocks
  974.                 SBlockMinMax* pOldestBlockInfo[4] = { 0, 0, 0, 0 };
  975.                 uint nOldestVisFrameId[4] = { ~0U, ~0U, ~0U, ~0U };
  976.                 const uint nMaxAllowedFrameId = GetCurrPassMainFrameID() - 16;
  977.                 const uint nNumBlocks = m_pBlockPacker->GetNumBlocks();
  978.                 for (uint nBlockId = 0; nBlockId < nNumBlocks; nBlockId++)
  979.                 {
  980.                         if (SBlockMinMax* pInfo = m_pBlockPacker->GetBlockInfo(nBlockId))
  981.                         {
  982.                                 int nNewestSlotId = 0;
  983.                                 for (int i = 0; i < 4; i++)
  984.                                         if (nOldestVisFrameId[i] > nOldestVisFrameId[nNewestSlotId])
  985.                                                 nNewestSlotId = i;
  986.  
  987.                                 if (pInfo->m_nLastVisFrameId < nOldestVisFrameId[nNewestSlotId] && pInfo->m_nLastVisFrameId < nMaxAllowedFrameId)
  988.                                 {
  989.                                         CVoxelSegment* pSeg = (CVoxelSegment*)pInfo->m_pUserData;
  990.                                         pInfo->m_nLastVisFrameId = pSeg->m_nLastRendFrameId;
  991.  
  992.                                         uint nFrameIdWeighted = pSeg->m_nLastRendFrameId + int(pSeg->GetBoxSize() / fMinNodeSize);
  993.  
  994.                                         if ((nFrameIdWeighted < nOldestVisFrameId[nNewestSlotId])
  995.                                             && (pSeg->m_nLastTexUpdateFrameId < nMaxAllowedFrameId)
  996.                                             && (pSeg->m_nLastRendFrameId < nMaxAllowedFrameId))
  997.                                         {
  998.                                                 pOldestBlockInfo[nNewestSlotId] = pInfo;
  999.                                                 nOldestVisFrameId[nNewestSlotId] = nFrameIdWeighted;
  1000.                                         }
  1001.                                 }
  1002.                         }
  1003.                 }
  1004.  
  1005.                 int nNumRemovedBlocks = 0;
  1006.  
  1007.                 for (int i = 0; i < 4; i++)
  1008.                         if (pOldestBlockInfo[i])
  1009.                         {
  1010.                                 CVoxelSegment* pSeg = (CVoxelSegment*)pOldestBlockInfo[i]->m_pUserData;
  1011.                                 if (pSeg->m_pBlockInfo != pOldestBlockInfo[i])
  1012.                                         ErrorTerminate("pSeg->m_pBlockInfo != pOldestBlockInfo[i]");
  1013.                                 pSeg->ReleaseAtlasBlock();
  1014.                                 nNumRemovedBlocks++;
  1015.                         }
  1016.  
  1017.                 if (!nNumRemovedBlocks)
  1018.                 {
  1019.                         break;
  1020.                 }
  1021.         }
  1022.  
  1023.         if (m_pBlockInfo == 0)
  1024.         {
  1025.                 Cry3DEngineBase::PrintMessage("UpdateBrickRenderData postponed %d", GetCurrPassMainFrameID());
  1026.                 return false;
  1027.         }
  1028.  
  1029.         m_nLastTexUpdateFrameId = GetCurrPassMainFrameID();
  1030.         m_nLastRendFrameId = GetCurrPassMainFrameID();
  1031.  
  1032.         assert(m_pBlockInfo->m_pUserData == this);
  1033.         Vec3i vOffset(m_pBlockInfo->m_dwMinX, m_pBlockInfo->m_dwMinY, m_pBlockInfo->m_dwMinZ);
  1034.         m_nAllocatedAtlasOffset = vOffset.z * nAtlasDimMaxXY * nAtlasDimMaxXY + vOffset.y * nAtlasDimMaxXY + vOffset.x;
  1035.  
  1036.         if (m_vCropTexSize.GetVolume() && m_pVoxOpacit)
  1037.                 UpdateVoxRenderData();
  1038.  
  1039.         UpdateNodeRenderData();
  1040.  
  1041.         UpdateMeshRenderData();
  1042.  
  1043.         return true;
  1044. }
  1045.  
  1046. bool CVoxelSegment::CheckUpdateBrickRenderData(bool bJustCheck)
  1047. {
  1048.         bool bRes = true;
  1049.  
  1050.         if (m_nAllocatedAtlasOffset < 0)
  1051.         {
  1052.                 if (bJustCheck)
  1053.                         bRes = false;
  1054.                 else
  1055.                         bRes = UpdateBrickRenderData();
  1056.         }
  1057.  
  1058.         return bRes;
  1059. }
  1060.  
  1061. void CVoxelSegment::UpdateStreamingEngine()
  1062. {
  1063.         FUNCTION_PROFILER_3DENGINE;
  1064.  
  1065.         if (pVoxStreamEngine)
  1066.                 pVoxStreamEngine->ProcessSyncCallBacks();
  1067. }
  1068.  
  1069. void CVoxelSegment::CheckAllocateTexturePool()
  1070. {
  1071.         int nFlagsReadOnly = FT_DONT_STREAM;
  1072.         int nFlagsReadWrite = FT_DONT_STREAM | FT_USAGE_UNORDERED_ACCESS | FT_USAGE_UAV_RWTEXTURE;
  1073.  
  1074.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1075.         if (!gSvoEnv->m_nTexRgb0PoolId)
  1076.         {
  1077.                 gSvoEnv->m_nTexRgb0PoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1078.                                                                                      nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadWrite);
  1079.                 m_nSvoDataPoolsCounter++;
  1080.         }
  1081.  
  1082.         if (Cry3DEngineBase::GetCVars()->e_svoTI_Active && Cry3DEngineBase::GetCVars()->e_svoTI_IntegrationMode)
  1083.         {
  1084.                 // direct lighting
  1085.                 if (!gSvoEnv->m_nTexRgb1PoolId)
  1086.                 {
  1087.                         gSvoEnv->m_nTexRgb1PoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1088.                                                                                              nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadWrite);
  1089.                         m_nSvoDataPoolsCounter++;
  1090.                 }
  1091.  
  1092.                 // dyn direct lighting
  1093.                 if (!gSvoEnv->m_nTexDynlPoolId && Cry3DEngineBase::GetCVars()->e_svoTI_DynLights)
  1094.                 {
  1095.                         gSvoEnv->m_nTexDynlPoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1096.                                                                                              nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadWrite);
  1097.                         m_nSvoDataPoolsCounter++;
  1098.                 }
  1099.  
  1100.                 // propagation
  1101.                 if (!gSvoEnv->m_nTexRgb2PoolId && Cry3DEngineBase::GetCVars()->e_svoTI_NumberOfBounces > 1)
  1102.                 {
  1103.                         gSvoEnv->m_nTexRgb2PoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1104.                                                                                              nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadWrite);
  1105.                         m_nSvoDataPoolsCounter++;
  1106.                 }
  1107.  
  1108.                 // propagation
  1109.                 if (!gSvoEnv->m_nTexRgb3PoolId && Cry3DEngineBase::GetCVars()->e_svoTI_NumberOfBounces > 2)
  1110.                 {
  1111.                         gSvoEnv->m_nTexRgb3PoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1112.                                                                                              nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadWrite);
  1113.                         m_nSvoDataPoolsCounter++;
  1114.                 }
  1115.  
  1116.                 // mesh
  1117.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  1118.                 if (!gSvoEnv->m_nTexTrisPoolId && Cry3DEngineBase::GetCVars()->e_svoTI_RT_MaxDist)
  1119.                 {
  1120.                         gSvoEnv->m_nTexTrisPoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1121.                                                                                              nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadWrite);
  1122.                         m_nSvoDataPoolsCounter++;
  1123.                 }
  1124.                 #endif
  1125.                 // snow
  1126.                 if (!gSvoEnv->m_nTexRgb4PoolId && Cry3DEngineBase::GetCVars()->e_svoTI_Troposphere_Snow_Height)
  1127.                 {
  1128.                         gSvoEnv->m_nTexRgb4PoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1129.                                                                                              nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadWrite);
  1130.                         m_nSvoDataPoolsCounter++;
  1131.                 }
  1132.         }
  1133.  
  1134.         {
  1135.                 if (!gSvoEnv->m_nTexNormPoolId)
  1136.                 {
  1137.                         gSvoEnv->m_nTexNormPoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1138.                                                                                              nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadOnly);
  1139.                         m_nSvoDataPoolsCounter++;
  1140.                 }
  1141.  
  1142.                 if (!gSvoEnv->m_nTexAldiPoolId && Cry3DEngineBase::GetCVars()->e_svoTI_Diffuse_Cache)
  1143.                 {
  1144.                         gSvoEnv->m_nTexAldiPoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1145.                                                                                              nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadWrite);
  1146.                         m_nSvoDataPoolsCounter++;
  1147.                 }
  1148.         }
  1149.         #endif
  1150.  
  1151.         if (!gSvoEnv->m_nTexOpasPoolId)
  1152.         {
  1153.                 gSvoEnv->m_nTexOpasPoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1154.                                                                                      nVoxTexPoolDimXY, nVoxTexPoolDimXY, nVoxTexPoolDimZ, gSvoEnv->m_nVoxTexFormat, gSvoEnv->m_nVoxTexFormat, 1, false, FILTER_LINEAR, 0, 0, nFlagsReadOnly);
  1155.                 m_nSvoDataPoolsCounter++;
  1156.         }
  1157.  
  1158.         if (!gSvoEnv->m_nTexNodePoolId)
  1159.                 gSvoEnv->m_nTexNodePoolId = gEnv->pRenderer->DownLoadToVideoMemory3D(NULL,
  1160.                                                                                      nVoxNodPoolDimXY, nVoxNodPoolDimXY, nVoxNodPoolDimZ, eTF_R32G32B32A32F, eTF_R32G32B32A32F, 1, false, FILTER_POINT, 0, 0, nFlagsReadOnly);
  1161. }
  1162.  
  1163. void CVoxelSegment::UpdateNodeRenderData()
  1164. {
  1165.         FUNCTION_PROFILER_3DENGINE;
  1166.  
  1167.         assert(m_pBlockInfo->m_pUserData == this);
  1168.         Vec3i vOffset(m_pBlockInfo->m_dwMinX, m_pBlockInfo->m_dwMinY, m_pBlockInfo->m_dwMinZ);
  1169.  
  1170.         static Vec4 voxNodeData[nVoxNodMaxDim * nVoxNodMaxDim * nVoxNodMaxDim];
  1171.         ZeroStruct(voxNodeData);
  1172.  
  1173.         voxNodeData[0] = Vec4(m_boxOS.min + m_vSegOrigin, 0);
  1174.         voxNodeData[1] = Vec4(m_boxOS.max + m_vSegOrigin, 0);
  1175.         voxNodeData[0] = voxNodeData[0] + Vec4(Vec3((float)m_vCropBoxMin.x / nVoxTexMaxDim, (float)m_vCropBoxMin.y / nVoxTexMaxDim, (float)m_vCropBoxMin.z / nVoxTexMaxDim) * GetBoxSize(), 0);
  1176.         voxNodeData[1] = voxNodeData[0] + Vec4(Vec3((float)m_vCropTexSize.x / nVoxTexMaxDim, (float)m_vCropTexSize.y / nVoxTexMaxDim, (float)m_vCropTexSize.z / nVoxTexMaxDim) * GetBoxSize(), 0);
  1177.         voxNodeData[0].w = GetBoxSize();
  1178.         voxNodeData[1].w = m_pParentCloud ? (0.1f + (float)m_pParentCloud->m_nAllocatedAtlasOffset) : -2.f;
  1179.  
  1180.         for (int c = 0; c < 4; c++)
  1181.         {
  1182.                 if (m_arrChildOffset[c + 0] >= 0)
  1183.                         voxNodeData[2][c] = 0.1f + (float)m_arrChildOffset[c + 0];
  1184.                 else
  1185.                         voxNodeData[2][c] = -0.1f + (float)m_arrChildOffset[c + 0];
  1186.  
  1187.                 if (m_arrChildOffset[c + 4] >= 0)
  1188.                         voxNodeData[3][c] = 0.1f + (float)m_arrChildOffset[c + 4];
  1189.                 else
  1190.                         voxNodeData[3][c] = -0.1f + (float)m_arrChildOffset[c + 4];
  1191.         }
  1192.  
  1193.         voxNodeData[4][0] = 0.1f + (float)GetRenderer()->GetFrameID(false);
  1194.  
  1195.         gEnv->pRenderer->UpdateTextureInVideoMemory(
  1196.           gSvoEnv->m_nTexNodePoolId,
  1197.           (byte*)&voxNodeData[0],
  1198.           vOffset.x * nVoxNodMaxDim,
  1199.           vOffset.y * nVoxNodMaxDim,
  1200.           nVoxNodMaxDim,
  1201.           nVoxNodMaxDim,
  1202.           eTF_R32G32B32A32F,
  1203.           vOffset.z * nVoxNodMaxDim,
  1204.           nVoxNodMaxDim);
  1205.         CVoxelSegment::m_nUpdatesInProgressTex++;
  1206.  
  1207.         m_boxClipped.min = Vec3(voxNodeData[0].x, voxNodeData[0].y, voxNodeData[0].z);
  1208.         m_boxClipped.max = Vec3(voxNodeData[1].x, voxNodeData[1].y, voxNodeData[1].z);
  1209. }
  1210.  
  1211. void CVoxelSegment::UpdateMeshRenderData()
  1212. {
  1213.         FUNCTION_PROFILER_3DENGINE;
  1214.  
  1215.         assert(m_pBlockInfo->m_pUserData == this);
  1216.  
  1217.         // define single vertex for GS
  1218.         {
  1219.                 // set box origin
  1220.                 m_vertForGS.xyz = m_boxClipped.min;
  1221.  
  1222.                 // set pinter to brick data
  1223.                 m_vertForGS.st.x = (0.5f + (float)m_nAllocatedAtlasOffset);
  1224.  
  1225.                 // pack box size
  1226.                 float fNodeSize = m_vertForGS.st.y = GetBoxSize();
  1227.                 Vec3 vBoxSize = m_boxClipped.GetSize();
  1228.                 m_vertForGS.color.bcolor[0] = SATURATEB(int(vBoxSize.x / fNodeSize * 255.f));
  1229.                 m_vertForGS.color.bcolor[1] = SATURATEB(int(vBoxSize.y / fNodeSize * 255.f));
  1230.                 m_vertForGS.color.bcolor[2] = SATURATEB(int(vBoxSize.z / fNodeSize * 255.f));
  1231.                 m_vertForGS.color.bcolor[3] = SATURATEB(int(m_fMaxAlphaInBrick * 255.f));
  1232.         }
  1233. }
  1234.  
  1235. void CVoxelSegment::UpdateVoxRenderData()
  1236. {
  1237.         FUNCTION_PROFILER_3DENGINE;
  1238.  
  1239.         assert(m_pBlockInfo->m_pUserData == this);
  1240.         Vec3i vOffset(m_pBlockInfo->m_dwMinX, m_pBlockInfo->m_dwMinY, m_pBlockInfo->m_dwMinZ);
  1241.  
  1242.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1243.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  1244.         byte* pImgTri = (byte*)m_pVoxTris;
  1245.                 #endif
  1246.         byte* pImgRgb = (byte*)m_pVoxVolume;
  1247.         byte* pImgNor = (byte*)m_pVoxNormal;
  1248.         #endif
  1249.         byte* pImgOpa = (byte*)m_pVoxOpacit;
  1250.  
  1251.         Vec3i vSizeFin;
  1252.         vSizeFin.x = (m_vCropTexSize.x);
  1253.         vSizeFin.y = (m_vCropTexSize.y);
  1254.         vSizeFin.z = (m_vCropTexSize.z);
  1255.  
  1256.         if (gSvoEnv->m_nVoxTexFormat == eTF_BC3)
  1257.         {
  1258.                 vSizeFin = GetDxtDim();
  1259.         }
  1260.  
  1261.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1262.  
  1263.         gEnv->pRenderer->UpdateTextureInVideoMemory(
  1264.           gSvoEnv->m_nTexRgb0PoolId,
  1265.           pImgRgb,
  1266.           vOffset.x * nVoxBloMaxDim,
  1267.           vOffset.y * nVoxBloMaxDim,
  1268.           vSizeFin.x,
  1269.           vSizeFin.y,
  1270.           gSvoEnv->m_nVoxTexFormat,
  1271.           vOffset.z * nVoxBloMaxDim,
  1272.           vSizeFin.z);
  1273.         CVoxelSegment::m_nUpdatesInProgressTex++;
  1274.  
  1275.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  1276.         if (Cry3DEngineBase::GetCVars()->e_svoTI_Active && gSvoEnv->m_nTexTrisPoolId)
  1277.         {
  1278.                 gEnv->pRenderer->UpdateTextureInVideoMemory(
  1279.                   gSvoEnv->m_nTexTrisPoolId,
  1280.                   pImgTri,
  1281.                   vOffset.x * nVoxBloMaxDim,
  1282.                   vOffset.y * nVoxBloMaxDim,
  1283.                   vSizeFin.x,
  1284.                   vSizeFin.y,
  1285.                   gSvoEnv->m_nVoxTexFormat,
  1286.                   vOffset.z * nVoxBloMaxDim,
  1287.                   vSizeFin.z);
  1288.                 CVoxelSegment::m_nUpdatesInProgressTex++;
  1289.         }
  1290.                 #endif
  1291.  
  1292.         gEnv->pRenderer->UpdateTextureInVideoMemory(
  1293.           gSvoEnv->m_nTexNormPoolId,
  1294.           pImgNor,
  1295.           vOffset.x * nVoxBloMaxDim,
  1296.           vOffset.y * nVoxBloMaxDim,
  1297.           vSizeFin.x,
  1298.           vSizeFin.y,
  1299.           gSvoEnv->m_nVoxTexFormat,
  1300.           vOffset.z * nVoxBloMaxDim,
  1301.           vSizeFin.z);
  1302.         CVoxelSegment::m_nUpdatesInProgressTex++;
  1303.  
  1304.         #endif
  1305.  
  1306.         gEnv->pRenderer->UpdateTextureInVideoMemory(
  1307.           gSvoEnv->m_nTexOpasPoolId,
  1308.           pImgOpa,
  1309.           vOffset.x * nVoxBloMaxDim,
  1310.           vOffset.y * nVoxBloMaxDim,
  1311.           vSizeFin.x,
  1312.           vSizeFin.y,
  1313.           gSvoEnv->m_nVoxTexFormat,
  1314.           vOffset.z * nVoxBloMaxDim,
  1315.           vSizeFin.z);
  1316.         CVoxelSegment::m_nUpdatesInProgressTex++;
  1317. }
  1318.  
  1319. void CVoxelSegment::ReleaseAtlasBlock()
  1320. {
  1321.         if (m_pBlockInfo)
  1322.                 m_pBlockPacker->RemoveBlock(m_pBlockInfo);
  1323.         m_pBlockInfo = 0;
  1324.         m_nAllocatedAtlasOffset = -2;
  1325.  
  1326.         m_pNode->m_nRequestSegmentUpdateFrametId = 0;
  1327.         m_vStatLightsCheckSumm.zero();
  1328.  
  1329.         PropagateDirtyFlag();
  1330. }
  1331.  
  1332. void CVoxelSegment::PropagateDirtyFlag()
  1333. {
  1334.         if (CVoxelSegment* pParent = m_pParentCloud)
  1335.         {
  1336.                 pParent->m_nChildOffsetsDirty = 2;
  1337.  
  1338.                 if (pParent->m_pParentCloud)
  1339.                         pParent->m_pParentCloud->m_nChildOffsetsDirty = 2;
  1340.  
  1341.                 while (pParent->m_pParentCloud)
  1342.                 {
  1343.                         pParent = pParent->m_pParentCloud;
  1344.                         pParent->m_nChildOffsetsDirty = max(pParent->m_nChildOffsetsDirty, (byte)1);
  1345.                 }
  1346.         }
  1347. }
  1348.  
  1349. AABB CVoxelSegment::GetChildBBox(const AABB& parentBox, int nChildId)
  1350. {
  1351.         int x = (nChildId / 4);
  1352.         int y = (nChildId - x * 4) / 2;
  1353.         int z = (nChildId - x * 4 - y * 2);
  1354.         Vec3 vSize = parentBox.GetSize() * 0.5f;
  1355.         Vec3 vOffset = vSize;
  1356.         vOffset.x *= x;
  1357.         vOffset.y *= y;
  1358.         vOffset.z *= z;
  1359.         AABB childBox;
  1360.         childBox.min = parentBox.min + vOffset;
  1361.         childBox.max = childBox.min + vSize;
  1362.         return childBox;
  1363. }
  1364.  
  1365. bool GetBarycentricTC(const Vec3& a, const Vec3& b, const Vec3& c, float& u, float& v, float& w, const Vec3& p, const float& fBorder)
  1366. {
  1367.         Vec3 v0 = b - a, v1 = c - a, v2 = p - a;
  1368.         float d00 = v0.Dot(v0);
  1369.         float d01 = v0.Dot(v1);
  1370.         float d11 = v1.Dot(v1);
  1371.         float d20 = v2.Dot(v0);
  1372.         float d21 = v2.Dot(v1);
  1373.         float d = d00 * d11 - d01 * d01;
  1374.         float invDenom = d ? (1.0f / d) : 1000000.f;
  1375.         v = (d11 * d20 - d01 * d21) * invDenom;
  1376.         w = (d00 * d21 - d01 * d20) * invDenom;
  1377.         u = 1.0f - v - w;
  1378.         return (u >= -fBorder) && (v >= -fBorder) && (w >= -fBorder);
  1379. }
  1380.  
  1381. ColorF CVoxelSegment::GetColorF_255(int x, int y, const ColorB* pImg, int nImgSizeW, int nImgSizeH)
  1382. {
  1383.         const ColorB& colB = pImg[x + y * nImgSizeW];
  1384.         ColorF colF;
  1385.         colF.r = colB.r;
  1386.         colF.g = colB.g;
  1387.         colF.b = colB.b;
  1388.         colF.a = colB.a;
  1389.  
  1390.         return colF;
  1391. }
  1392.  
  1393. ColorF CVoxelSegment::GetBilinearAt(float iniX, float iniY, const ColorB* pImg, int nDimW, int nDimH, float fBr)
  1394. {
  1395.         int nImgSizeW = nDimW;
  1396.         int nImgSizeH = nDimH;
  1397.  
  1398.         iniX *= nImgSizeW;
  1399.         iniY *= nImgSizeH;
  1400.  
  1401.         //  iniX -= .5f;
  1402.         //  iniY -= .5f;
  1403.  
  1404.         int x = (int)floor(iniX);
  1405.         int y = (int)floor(iniY);
  1406.  
  1407.         float rx = iniX - x;    // fractional part
  1408.         float ry = iniY - y;    // fractional part
  1409.  
  1410.         int nMaskW = nImgSizeW - 1;
  1411.         int nMaskH = nImgSizeH - 1;
  1412.  
  1413.         //  return GetColorF_255(nMaskW&(x  ),nMaskH&(y  ), pImg, nImgSizeW, nImgSizeH) * fBr;
  1414.  
  1415.         ColorF top = GetColorF_255(nMaskW & (x), nMaskH & (y), pImg, nImgSizeW, nImgSizeH) * (1.f - rx)     // left top
  1416.                      + GetColorF_255(nMaskW & (x + 1), nMaskH & (y), pImg, nImgSizeW, nImgSizeH) * rx;      // right top
  1417.         ColorF bot = GetColorF_255(nMaskW & (x), nMaskH & (y + 1), pImg, nImgSizeW, nImgSizeH) * (1.f - rx) // left bottom
  1418.                      + GetColorF_255(nMaskW & (x + 1), nMaskH & (y + 1), pImg, nImgSizeW, nImgSizeH) * rx;  // right bottom
  1419.  
  1420.         return (top * (1.f - ry) + bot * ry) * fBr;
  1421. }
  1422.  
  1423. void CVoxelSegment::VoxelizeMeshes(int nTID)
  1424. {
  1425.         m_vCropBoxMin.Set(0, 0, 0);
  1426.         m_vCropTexSize.Set(nVoxTexMaxDim, nVoxTexMaxDim, nVoxTexMaxDim);
  1427.  
  1428.         PodArray<int>* pNodeTrisXYZ = 0;
  1429.  
  1430.         if (GetBoxSize() <= GetCVars()->e_svoMaxNodeSize)
  1431.         {
  1432.                 pNodeTrisXYZ = new PodArray<int>[nVoxTexMaxDim * nVoxTexMaxDim * nVoxTexMaxDim];
  1433.                 FindTrianglesForVoxelization(nTID, pNodeTrisXYZ, GetBoxSize() == GetCVars()->e_svoMaxNodeSize);
  1434.  
  1435.                 gSvoEnv->m_arrVoxelizeMeshesCounter[0]++;
  1436.                 if (GetBoxSize() == GetCVars()->e_svoMaxNodeSize)
  1437.                         gSvoEnv->m_arrVoxelizeMeshesCounter[1]++;
  1438.         }
  1439.  
  1440.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1441.                 #ifdef FEATURE_SVO_GI_USE_MESH_RT
  1442.         CheckAllocateBrick(m_pVoxTris, m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z, true);
  1443.                 #endif
  1444.         CheckAllocateBrick(m_pVoxVolume, m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z, true);
  1445.         CheckAllocateBrick(m_pVoxNormal, m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z, true);
  1446.         #endif
  1447.         CheckAllocateBrick(m_pVoxOpacit, m_vCropTexSize.x * m_vCropTexSize.y * m_vCropTexSize.z, true);
  1448.  
  1449.         Vec3 vBoxCenter = m_pNode->m_nodeBox.GetCenter();
  1450.  
  1451.         // voxelize node tris
  1452.         if ((m_nodeTrisAllMerged.Count() || Cry3DEngineBase::GetCVars()->e_svoTI_Troposphere_Subdivide) && m_pVoxOpacit && m_pTrisInArea && pNodeTrisXYZ)
  1453.         {
  1454.                 Vec4 voxNodeData[nVoxNodMaxDim * nVoxNodMaxDim * nVoxNodMaxDim];
  1455.                 ZeroStruct(voxNodeData);
  1456.                 voxNodeData[0] = Vec4(m_boxOS.min + m_vSegOrigin, 0);
  1457.                 voxNodeData[1] = Vec4(m_boxOS.max + m_vSegOrigin, 0);
  1458.  
  1459.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1460.                 // collect overlapping portals
  1461.                 PodArray<CVisArea*> arrPortals;
  1462.                 {
  1463.                         for (int v = 0;; v++)
  1464.                         {
  1465.                                 CVisArea* pVisArea = (CVisArea*)GetVisAreaManager()->GetVisAreaById(v);
  1466.                                 if (!pVisArea)
  1467.                                         break;
  1468.  
  1469.                                 if (pVisArea->IsPortal() && Overlap::AABB_AABB(*pVisArea->GetAABBox(), m_pNode->m_nodeBox))
  1470.                                         arrPortals.Add(pVisArea);
  1471.                         }
  1472.                 }
  1473.         #endif
  1474.  
  1475.                 for (int X = 0; X < nVoxTexMaxDim; X++)
  1476.                         for (int Y = 0; Y < nVoxTexMaxDim; Y++)
  1477.                                 for (int Z = 0; Z < nVoxTexMaxDim; Z++)
  1478.                                 {
  1479.                                         const int id = Z * nVoxTexMaxDim * nVoxTexMaxDim + Y * nVoxTexMaxDim + X;
  1480.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1481.                                         ColorB& colOut = m_pVoxVolume[id];
  1482.                                         ColorB& norOut = m_pVoxNormal[id];
  1483.         #endif
  1484.                                         ColorB& opaOutFin = m_pVoxOpacit[id];
  1485.                                         Vec4 vMin = voxNodeData[0] + (voxNodeData[1] - voxNodeData[0]) * Vec4((float) X / nVoxTexMaxDim, (float) Y / nVoxTexMaxDim, (float) Z / nVoxTexMaxDim, 1);
  1486.                                         Vec4 vMax = voxNodeData[0] + (voxNodeData[1] - voxNodeData[0]) * Vec4((float) (X + 1) / nVoxTexMaxDim, (float) (Y + 1) / nVoxTexMaxDim, (float) (Z + 1) / nVoxTexMaxDim, 1);
  1487.  
  1488.                                         // safety border support
  1489.                                         //      Vec4 vCenter(m_vOrigin.x,m_vOrigin.y,m_vOrigin.z,0);
  1490.                                         //        vMin += (vMin - vCenter)/(nVoxTexMaxDim/2)/2;
  1491.                                         //        vMax += (vMax - vCenter)/(nVoxTexMaxDim/2)/2;
  1492.  
  1493.                                         AABB voxBox;
  1494.                                         voxBox.min.Set(vMin.x, vMin.y, vMin.z);
  1495.                                         voxBox.max.Set(vMax.x, vMax.y, vMax.z);
  1496.  
  1497.                                         AABB voxBoxRT = voxBox;
  1498.                                         voxBoxRT.Expand(voxBoxRT.GetSize() / 2);
  1499.  
  1500.                                         if (Overlap::AABB_AABB(voxBox, m_boxTris))
  1501.                                         {
  1502.                                                 PodArray<int> trisInt;
  1503.                                                 PodArray<int> trisIntRT;
  1504.                                                 bool bVisAreaTrisDetected = false;
  1505.  
  1506.                                                 AUTO_READLOCK(m_superMeshLock);
  1507.  
  1508.                                                 // collect tris only for this voxel; TODO: check maybe pNodeTrisXYZ[id] already have only what is needed and trisInt can be dropped
  1509.                                                 for (int d = 0; d < pNodeTrisXYZ[id].Count(); d++)
  1510.                                                 {
  1511.                                                         int trId = pNodeTrisXYZ[id].GetAt(d);
  1512.  
  1513.                                                         SRayHitTriangleIndexed& tr = (*m_pTrisInArea)[trId];
  1514.  
  1515.                                                         Vec3 arrV[3] = { (*m_pVertInArea)[tr.arrVertId[0]].v, (*m_pVertInArea)[tr.arrVertId[1]].v, (*m_pVertInArea)[tr.arrVertId[2]].v };
  1516.  
  1517.                                                         if (Overlap::AABB_Triangle(voxBoxRT, arrV[0], arrV[1], arrV[2])) // 14s
  1518.                                                         {
  1519.                                                                 trisIntRT.Add(trId);
  1520.  
  1521.                                                                 if (Overlap::AABB_Triangle(voxBox, arrV[0], arrV[1], arrV[2])) // 14s
  1522.                                                                 {
  1523.                                                                         if (tr.nHitObjType == HIT_OBJ_TYPE_VISAREA)
  1524.                                                                                 bVisAreaTrisDetected = true;
  1525.  
  1526.                                                                         assert(trisInt.Find(trId) < 0);
  1527.  
  1528.                                                                         trisInt.Add(trId);
  1529.                                                                 }
  1530.                                                         }
  1531.                                                 }
  1532.  
  1533.         #ifdef FEATURE_SVO_GI_USE_MESH_RT
  1534.                                                 if (GetCVars()->e_svoTI_RT_MaxDist && gSvoEnv->m_nTexTrisPoolId)
  1535.                                                 {
  1536.                                                         int nTrisCount = 0;
  1537.                                                         int nFirstTriIndex = StoreIndicesIntoPool(trisIntRT, nTrisCount);
  1538.                                                         int nId = nFirstTriIndex;
  1539.                                                         m_pVoxTris[id].r = nId & 255;
  1540.                                                         nId /= 256;
  1541.                                                         m_pVoxTris[id].g = nId & 255;
  1542.                                                         nId /= 256;
  1543.                                                         m_pVoxTris[id].b = nId & 255;
  1544.                                                         nId /= 256;
  1545.                                                         m_pVoxTris[id].a = nTrisCount;
  1546.                                                 }
  1547.         #endif
  1548.  
  1549.                                                 // OPA
  1550.                                                 {
  1551.                                                         const int nSSDim = 4;
  1552.  
  1553.                                                         const int nSDim = nSSDim / 2;
  1554.  
  1555.                                                         PodArray<int> arrSubOpa[nSDim][nSDim][nSDim];
  1556.  
  1557.                                                         {
  1558.                                                                 // Fill nSDim x nSDim x nSDim super voxel
  1559.  
  1560.                                                                 Vec3 vSubVoxSize = voxBox.GetSize() / (float)nSDim;
  1561.  
  1562.                                                                 for (int x = 0; x < nSDim; x++)
  1563.                                                                         for (int y = 0; y < nSDim; y++)
  1564.                                                                                 for (int z = 0; z < nSDim; z++)
  1565.                                                                                 {
  1566.                                                                                         PodArray<int>& opaOutSub = arrSubOpa[x][y][z];
  1567.  
  1568.                                                                                         AABB SubBox;
  1569.                                                                                         SubBox.min = voxBox.min + vSubVoxSize.CompMul(Vec3((float)x, (float)y, (float)z));
  1570.                                                                                         SubBox.max = SubBox.min + vSubVoxSize;
  1571.  
  1572.                                                                                         AABB SubBoxT = SubBox;
  1573.                                                                                         SubBoxT.max.z++;
  1574.  
  1575.                                                                                         for (int c = 0; c < trisInt.Count(); c++)
  1576.                                                                                         {
  1577.                                                                                                 int nTrId = trisInt.GetAt(c);
  1578.  
  1579.                                                                                                 SRayHitTriangleIndexed& tr = (*m_pTrisInArea)[nTrId];
  1580.  
  1581.                                                                                                 Vec3 arrV[3] = { (*m_pVertInArea)[tr.arrVertId[0]].v, (*m_pVertInArea)[tr.arrVertId[1]].v, (*m_pVertInArea)[tr.arrVertId[2]].v };
  1582.  
  1583.                                                                                                 if (Overlap::AABB_Triangle(tr.nMatID ? SubBox : SubBoxT, arrV[0], arrV[1], arrV[2])) // 40 ms
  1584.                                                                                                 {
  1585.                                                                                                         opaOutSub.Add(nTrId);
  1586.                                                                                                 }
  1587.                                                                                         }
  1588.                                                                                 }
  1589.                                                         }
  1590.  
  1591.                                                         uint8 arrSubSubOpa[nSSDim][nSSDim][nSSDim];
  1592.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1593.                                                         Vec4 arrSubSubNor[nSSDim][nSSDim][nSSDim];
  1594.                                                         ColorF arrSubSubCol[nSSDim][nSSDim][nSSDim];
  1595.                                                         float arrSubSubEmi[nSSDim][nSSDim][nSSDim];
  1596.         #endif
  1597.                                                         ZeroStruct(arrSubSubOpa);
  1598.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1599.                                                         ZeroStruct(arrSubSubNor);
  1600.                                                         ZeroStruct(arrSubSubCol);
  1601.                                                         ZeroStruct(arrSubSubEmi);
  1602.         #endif
  1603.  
  1604.                                                         // Fill nSSDim x nSSDim x nSSDim super voxel
  1605.  
  1606.                                                         Vec3 vSubSubVoxSize = voxBox.GetSize() / (float)nSSDim;
  1607.  
  1608.                                                         for (int x = 0; x < nSSDim; x++)
  1609.                                                                 for (int y = 0; y < nSSDim; y++)
  1610.                                                                         for (int z = 0; z < nSSDim; z++)
  1611.                                                                         {
  1612.                                                                                 PodArray<int>& opaOutSub = arrSubOpa[x / 2][y / 2][z / 2];
  1613.  
  1614.                                                                                 uint8& opaOutSubSub = arrSubSubOpa[x][y][z];
  1615.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1616.                                                                                 Vec4& norOutSubSub = arrSubSubNor[x][y][z];
  1617.                                                                                 ColorF& colOutSubSub = arrSubSubCol[x][y][z];
  1618.                                                                                 float& EmiOutSubSub = arrSubSubEmi[x][y][z];
  1619.         #endif
  1620.  
  1621.                                                                                 AABB SubSubBox;
  1622.                                                                                 SubSubBox.min = voxBox.min + vSubSubVoxSize.CompMul(Vec3((float)x, (float)y, (float)z));
  1623.                                                                                 SubSubBox.max = SubSubBox.min + vSubSubVoxSize;
  1624.  
  1625.                                                                                 AABB SubSubBoxT = SubSubBox;
  1626.                                                                                 SubSubBoxT.max.z++;
  1627.  
  1628.                                                                                 AABB SubSubBoxP = SubSubBox;
  1629.                                                                                 SubSubBoxP.Expand(Vec3(.25, .25, .25));
  1630.  
  1631.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1632.                                                                                 bool bVoxelInPortal = false;
  1633.  
  1634.                                                                                 for (int v = 0; v < arrPortals.Count(); v++)
  1635.                                                                                 {
  1636.                                                                                         if (Overlap::AABB_AABB(*arrPortals[v]->GetAABBox(), SubSubBoxP))
  1637.                                                                                         {
  1638.                                                                                                 bVoxelInPortal = true;
  1639.                                                                                                 break;
  1640.                                                                                         }
  1641.                                                                                 }
  1642.  
  1643.                                                                                 if (bVoxelInPortal) // skip sub-voxels in the portal
  1644.                                                                                         continue;
  1645.         #endif
  1646.  
  1647.                                                                                 for (int c = 0; c < opaOutSub.Count(); c++)
  1648.                                                                                 {
  1649.                                                                                         if (opaOutSub.GetAt(c) >= (*m_pTrisInArea).Count())
  1650.                                                                                         {
  1651.                                                                                                 PrintMessage("%s warning: trId>=(*m_pTrisInArea).Count()", __FUNC__);
  1652.                                                                                                 break;
  1653.                                                                                         }
  1654.  
  1655.                                                                                         SRayHitTriangleIndexed& tr = (*m_pTrisInArea)[opaOutSub.GetAt(c)];
  1656.  
  1657.                                                                                         Vec3 arrV[3] = { (*m_pVertInArea)[tr.arrVertId[0]].v, (*m_pVertInArea)[tr.arrVertId[1]].v, (*m_pVertInArea)[tr.arrVertId[2]].v };
  1658.  
  1659.                                                                                         if (Overlap::AABB_Triangle(tr.nMatID ? SubSubBox : SubSubBoxT, arrV[0], arrV[1], arrV[2])) // 8ms
  1660.                                                                                         {
  1661.                                                                                                 ColorF colTraced = ProcessMaterial(tr, SubSubBox.GetCenter());
  1662.                                                                                                 if (colTraced.a)
  1663.                                                                                                 {
  1664.                                                                                                         opaOutSubSub = max(opaOutSubSub, min(tr.nOpacity, (uint8)SATURATEB(colTraced.a * 255.f)));
  1665.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1666.                                                                                                         norOutSubSub += Vec4(tr.vFaceNorm, 1);
  1667.  
  1668.                                                                                                         colOutSubSub.r += colTraced.r;
  1669.                                                                                                         colOutSubSub.g += colTraced.g;
  1670.                                                                                                         colOutSubSub.b += colTraced.b;
  1671.                                                                                                         colOutSubSub.a += 1.f;
  1672.  
  1673.                                                                                                         SSvoMatInfo& rMI = m_pMatsInArea->GetAt(tr.nMatID);
  1674.                                                                                                         if (rMI.pMat)
  1675.                                                                                                                 EmiOutSubSub = +rMI.pMat->GetShaderItem(0).m_pShaderResources->GetFinalEmittance().Luminance();
  1676.         #else
  1677.                                                                                                         if (opaOutSubSub == 255)
  1678.                                                                                                                 break;
  1679.         #endif
  1680.                                                                                                 }
  1681.                                                                                         }
  1682.                                                                                 }
  1683.                                                                         }
  1684.  
  1685.                                                         // Compute tri-planar opacity
  1686.  
  1687.                                                         uint8 arrQuad[3][nSSDim][nSSDim];
  1688.                                                         ZeroStruct(arrQuad);
  1689.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1690.                                                         Vec4 vNorFin(0, 0, 0, 0);
  1691.                                                         ColorF vColFin(0, 0, 0, 0);
  1692.                                                         float fEmiFin(0);
  1693.         #endif
  1694.  
  1695.                                                         for (int _x = 0; _x < nSSDim; _x++)
  1696.                                                                 for (int _y = 0; _y < nSSDim; _y++)
  1697.                                                                         for (int _z = 0; _z < nSSDim; _z++)
  1698.                                                                         {
  1699.                                                                                 uint8& opaCh = arrSubSubOpa[_x][_y][_z];
  1700.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1701.                                                                                 Vec4& norCh = arrSubSubNor[_x][_y][_z];
  1702.                                                                                 ColorF& colCh = arrSubSubCol[_x][_y][_z];
  1703.                                                                                 float& EmiCh = arrSubSubEmi[_x][_y][_z];
  1704.         #endif
  1705.  
  1706.                                                                                 arrQuad[0][_y][_z] = max(arrQuad[0][_y][_z], opaCh);
  1707.                                                                                 arrQuad[1][_x][_z] = max(arrQuad[1][_x][_z], opaCh);
  1708.                                                                                 arrQuad[2][_x][_y] = max(arrQuad[2][_x][_y], opaCh);
  1709.  
  1710.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1711.                                                                                 vNorFin += norCh;
  1712.                                                                                 vColFin += colCh;
  1713.                                                                                 fEmiFin += EmiCh;
  1714.         #endif
  1715.                                                                         }
  1716.  
  1717.                                                         // we do not normalize normal, length of the normal says how reliable the normal is
  1718.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1719.                                                         if (vNorFin.w)
  1720.                                                                 vNorFin = vNorFin / vNorFin.w;
  1721.  
  1722.                                                         if (vColFin.a)
  1723.                                                         {
  1724.                                                                 fEmiFin /= vColFin.a;
  1725.  
  1726.                                                                 vColFin /= vColFin.a;
  1727.                                                         }
  1728.         #endif
  1729.  
  1730.                                                         ColorF opaSummF(0, 0, 0, 0);
  1731.  
  1732.                                                         for (int k = 0; k < nSSDim; k++)
  1733.                                                                 for (int m = 0; m < nSSDim; m++)
  1734.                                                                 {
  1735.                                                                         opaSummF.r += arrQuad[0][k][m];
  1736.                                                                         opaSummF.g += arrQuad[1][k][m];
  1737.                                                                         opaSummF.b += arrQuad[2][k][m];
  1738.                                                                 }
  1739.  
  1740.                                                         opaSummF.r /= nSSDim * nSSDim;
  1741.                                                         opaSummF.g /= nSSDim * nSSDim;
  1742.                                                         opaSummF.b /= nSSDim * nSSDim;
  1743.  
  1744.                                                         opaOutFin.r = SATURATEB((int)opaSummF.b);
  1745.                                                         opaOutFin.g = SATURATEB((int)opaSummF.g);
  1746.                                                         opaOutFin.b = SATURATEB((int)opaSummF.r);
  1747.  
  1748.                                                         bool bTerrainTrisDetected;
  1749.                                                         Vec3 vH = voxBox.GetCenter();
  1750.                                                         if (vH.z > (GetTerrain()->GetZ((int)vH.x, (int)vH.y, 0) + 1.5f))
  1751.                                                                 bTerrainTrisDetected = false;
  1752.                                                         else
  1753.                                                                 bTerrainTrisDetected = true;
  1754.  
  1755.                                                         opaOutFin.a = bTerrainTrisDetected ? 0 : 1; // reserved for opacity of dynamic voxels or [0 = triangle is missing in RSM]
  1756.  
  1757.                                                         if (bVisAreaTrisDetected && (opaOutFin.r || opaOutFin.g || opaOutFin.b))
  1758.                                                         {
  1759.                                                                 opaOutFin.r = opaOutFin.g = opaOutFin.b = 255; // full opaque
  1760.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1761.                                                                 vColFin.r = vColFin.g = vColFin.b = 0; // full black
  1762.         #endif
  1763.                                                         }
  1764.  
  1765.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  1766.                                                         norOut.a = (opaOutFin.r || opaOutFin.g || opaOutFin.b) ? 255 : 0; // contains 255 for any geometry and 0 for empty space
  1767.  
  1768.                                                         for (int c = 0; c < 3; c++)
  1769.                                                                 norOut[c] = SATURATEB(int(vNorFin[2 - c] * 127.5f + 127.5f));
  1770.  
  1771.                                                         colOut.r = SATURATEB((int)(vColFin.r * 255.f));
  1772.                                                         colOut.g = SATURATEB((int)(vColFin.g * 255.f));
  1773.                                                         colOut.b = SATURATEB((int)(vColFin.b * 255.f));
  1774.                                                         colOut.a = SATURATEB((int)(fEmiFin * 255.f));
  1775.         #endif
  1776.                                                         if (opaOutFin.r || opaOutFin.g || opaOutFin.b)
  1777.                                                                 m_nVoxNum++;
  1778.                                                 }
  1779.                                         }
  1780.                                 }
  1781.  
  1782.                 //              UpdateTerrainNormals(m_pNode->m_nodeBox.GetCenter(), 1000000, m_pVoxTerrain);
  1783.  
  1784.                 // dilation
  1785.                 //ComputeDistancesFast( m_pVoxVolume, m_pVoxNormal, m_pVoxOpacit, nTID );
  1786.  
  1787.                 if (!Cry3DEngineBase::GetCVars()->e_svoTI_Troposphere_Subdivide)
  1788.                         CropVoxTexture(nTID, true);
  1789.         }
  1790.         else
  1791.         {
  1792.                 m_vCropTexSize.zero();
  1793.                 m_vCropBoxMin.zero();
  1794.         }
  1795.  
  1796.         if (Cry3DEngineBase::GetCVars()->e_svoTI_Troposphere_Subdivide)
  1797.         {
  1798.                 // allocate all nodes
  1799.                 m_vCropTexSize.zero();
  1800.                 m_vCropTexSize.Set(nVoxTexMaxDim, nVoxTexMaxDim, nVoxTexMaxDim);
  1801.         }
  1802.  
  1803.         //  if(m_pVoxVolume)
  1804.         //  {
  1805.         //    int nPixNum = m_vCropTexSize.x *m_vCropTexSize.y * m_vCropTexSize.z;
  1806.         //    FILE * f = 0;
  1807.         //    char fName[128];
  1808.         //    cry_sprintf(fName, "E:\\BR\\brick_%5d__%2d_%2d_%2d.BR", m_nId, m_vCropTexSize.x, m_vCropTexSize.y, m_vCropTexSize.z);
  1809.         //    fopen_s(&f, fName, "wb");
  1810.         //    if(f)
  1811.         //    {
  1812.         //      fwrite(m_pVoxVolume, sizeof(ColorB), nPixNum, f);
  1813.         //      fclose(f);
  1814.         //    }
  1815.         //  }
  1816.  
  1817.         SAFE_DELETE_ARRAY(pNodeTrisXYZ);
  1818. }
  1819.  
  1820. static int32 CompareTriArea(const void* v1, const void* v2)
  1821. {
  1822.         SRayHitTriangle* t1 = (SRayHitTriangle*)v1;
  1823.         SRayHitTriangle* t2 = (SRayHitTriangle*)v2;
  1824.  
  1825.         if (t1->nTriArea > t2->nTriArea)
  1826.                 return -1;
  1827.         if (t1->nTriArea < t2->nTriArea)
  1828.                 return 1;
  1829.  
  1830.         return 0;
  1831. };
  1832.  
  1833. bool CVoxelSegment::CheckCollectObjectsForVoxelization(const AABB& cloudBoxWS, PodArray<SObjInfo>* parrObjects, bool& bThisIsAreaParent, bool& bThisIsLowLodNode, bool bAllowStartStreaming)
  1834. {
  1835.         FUNCTION_PROFILER_3DENGINE;
  1836.  
  1837.         bool bSuccess = true;
  1838.  
  1839.         bThisIsAreaParent = (cloudBoxWS.GetSize().z == GetCVars()->e_svoMaxAreaSize);
  1840.         bThisIsLowLodNode = (cloudBoxWS.GetSize().z > GetCVars()->e_svoMaxAreaSize);
  1841.  
  1842.         if (bThisIsAreaParent || bThisIsLowLodNode)
  1843.         {
  1844.                 for (int nObjType = 0; nObjType < eERType_TypesNum; nObjType++)
  1845.                 {
  1846.                         if ((bThisIsAreaParent && (nObjType == eERType_Brush || nObjType == eERType_RenderProxy)) || (nObjType == eERType_Vegetation))
  1847.                         {
  1848.                                 PodArray<IRenderNode*> arrRenderNodes;
  1849.  
  1850.                                 Get3DEngine()->GetObjectsByTypeGlobal(arrRenderNodes, (EERType)nObjType, &cloudBoxWS, bAllowStartStreaming ? &bSuccess : 0, ERF_GI_MODE_BIT0);
  1851.                                 if (Get3DEngine()->GetVisAreaManager())
  1852.                                         Get3DEngine()->GetVisAreaManager()->GetObjectsByType(arrRenderNodes, (EERType)nObjType, &cloudBoxWS, bAllowStartStreaming ? &bSuccess : 0, ERF_GI_MODE_BIT0);
  1853.  
  1854.                                 if (!arrRenderNodes.Count())
  1855.                                         continue;
  1856.  
  1857.                                 int nCulled = 0;
  1858.  
  1859.                                 for (int d = 0; d < arrRenderNodes.Count(); d++)
  1860.                                 {
  1861.                                         IRenderNode* pNode = arrRenderNodes[d];
  1862.  
  1863.                                         if (pNode->GetRndFlags() & (ERF_COLLISION_PROXY | ERF_RAYCAST_PROXY))
  1864.                                                 continue;
  1865.  
  1866.                                         if (!GetCVars()->e_svoTI_VoxelizeHiddenObjects && (pNode->GetRndFlags() & ERF_HIDDEN))
  1867.                                                 continue;
  1868.  
  1869.                                         if (bThisIsLowLodNode)
  1870.                                                 if (!(pNode->GetRndFlags() & ERF_CASTSHADOWMAPS))
  1871.                                                         continue;
  1872.  
  1873.                                         if (pNode->GetGIMode() != IRenderNode::eGM_StaticVoxelization)
  1874.                                                 continue;
  1875.  
  1876.                                         float fMaxViewDist = pNode->GetBBox().GetRadius() * GetCVars()->e_ViewDistRatio;
  1877.  
  1878.                                         float fMinAllowedViewDist = (pNode->GetRenderNodeType() == eERType_Vegetation) ? (GetCVars()->e_svoTI_ObjectsMaxViewDistance * 2) : GetCVars()->e_svoTI_ObjectsMaxViewDistance;
  1879.  
  1880.                                         if (bThisIsLowLodNode)
  1881.                                         {
  1882.                                                 if (pNode->GetBBox().GetSize().z < cloudBoxWS.GetSize().z * 0.25f)
  1883.                                                         continue;
  1884.  
  1885.                                                 fMinAllowedViewDist *= 4.f;
  1886.                                         }
  1887.  
  1888.                                         if (fMaxViewDist < fMinAllowedViewDist)
  1889.                                         {
  1890.                                                 nCulled++;
  1891.                                                 continue;
  1892.                                         }
  1893.  
  1894.                                         int nMaxSlots = 1;
  1895.                                         int nMaxSubSlots = 1;
  1896.                                         if (pNode->GetRenderNodeType() == eERType_RenderProxy)
  1897.                                         {
  1898.                                                 nMaxSlots = 32;
  1899.                                                 nMaxSubSlots = 32;
  1900.                                         }
  1901.  
  1902.                                         for (int nSlotId = 0; nSlotId < nMaxSlots; nSlotId++)
  1903.                                         {
  1904.                                                 for (int nSubSlotId = 0; nSubSlotId < nMaxSubSlots; nSubSlotId++)
  1905.                                                 {
  1906.                                                         Matrix34A nodeTM;
  1907.                                                         CStatObj* pStatObj = (CStatObj*)pNode->GetEntityStatObj(nSlotId, nSubSlotId, &nodeTM);
  1908.  
  1909.                                                         IMaterial* pMaterial = pNode->GetMaterial();
  1910.                                                         if (!pMaterial && pStatObj)
  1911.                                                                 pMaterial = pStatObj->GetMaterial();
  1912.  
  1913.                                                         if (pMaterial)
  1914.                                                         {
  1915.                                                                 SObjInfo info;
  1916.                                                                 info.matObjInv = nodeTM.GetInverted();
  1917.                                                                 info.matObj = nodeTM;
  1918.                                                                 info.pStatObj = (CStatObj*)pNode->GetEntityStatObj(nSlotId, nSubSlotId, NULL);
  1919.  
  1920.                                                                 if (!info.pStatObj && nObjType == eERType_Character)
  1921.                                                                 {
  1922.                                                                         if (ICharacterInstance* pChar = pNode->GetEntityCharacter(nSlotId, &nodeTM))
  1923.                                                                         {
  1924.                                                                                 // spawn decals on CGA components
  1925.                                                                                 ISkeletonPose* pSkeletonPose = pChar->GetISkeletonPose();
  1926.                                                                                 uint32 numJoints = pChar->GetIDefaultSkeleton().GetJointCount();
  1927.  
  1928.                                                                                 // spawn decal on every sub-object intersecting decal bbox
  1929.                                                                                 uint32 nJointId = nSubSlotId;
  1930.  
  1931.                                                                                 if (nJointId >= numJoints)
  1932.                                                                                         break;
  1933.  
  1934.                                                                                 CStatObj* pStatObj = (CStatObj*)pSkeletonPose->GetStatObjOnJoint(nJointId);
  1935.  
  1936.                                                                                 if (pStatObj && !(pStatObj->GetFlags() & STATIC_OBJECT_HIDDEN) && pStatObj->GetRenderMesh())
  1937.                                                                                 {
  1938.                                                                                         assert(!pStatObj->GetSubObjectCount());
  1939.  
  1940.                                                                                         Matrix34 subSlotTM = nodeTM * Matrix34(pSkeletonPose->GetAbsJointByID(nJointId));
  1941.                                                                                         AABB objBoxWS = AABB::CreateTransformedAABB(subSlotTM, pStatObj->GetAABB());
  1942.  
  1943.                                                                                         if (Overlap::AABB_AABB(objBoxWS, cloudBoxWS))
  1944.                                                                                         {
  1945.                                                                                                 info.matObjInv = subSlotTM.GetInverted();
  1946.                                                                                                 info.matObj = subSlotTM;
  1947.                                                                                                 info.pStatObj = pStatObj;
  1948.                                                                                                 pMaterial = pSkeletonPose->GetMaterialOnJoint(nJointId);
  1949.                                                                                                 if (!pMaterial)
  1950.                                                                                                         pMaterial = pStatObj->GetMaterial();
  1951.                                                                                         }
  1952.                                                                                 }
  1953.                                                                         }
  1954.                                                                 }
  1955.  
  1956.                                                                 if (!info.pStatObj)
  1957.                                                                         continue;
  1958.  
  1959.                                                                 int nLod = GetCVars()->e_svoTI_ObjectsLod;
  1960.  
  1961.                                                                 if (bThisIsLowLodNode)
  1962.                                                                         nLod++;
  1963.  
  1964.                                                                 info.pStatObj = (CStatObj*)info.pStatObj->GetLodObject(nLod, true);
  1965.  
  1966.                                                                 CStatObj* pParent = info.pStatObj->GetParentObject() ? ((CStatObj*)info.pStatObj->GetParentObject()) : (CStatObj*)info.pStatObj;
  1967.                                                                 EFileStreamingStatus eStreamingStatusParent = pParent->m_eStreamingStatus;
  1968.                                                                 bool bUnloadable = pParent->IsUnloadable();
  1969.  
  1970.                                                                 if (pNode->GetRenderNodeType() == eERType_Vegetation)
  1971.                                                                 {
  1972.                                                                         info.fObjScale = ((CVegetation*)pNode)->GetScale();
  1973.                                                                 }
  1974.                                                                 else if (pNode->GetRenderNodeType() == eERType_RenderProxy || pNode->GetRenderNodeType() == eERType_Brush)
  1975.                                                                 {
  1976.                                                                         Vec3 vScaleAbs = info.matObj.TransformVector(Vec3(1, 1, 1)).abs();
  1977.                                                                         info.fObjScale = min(min(vScaleAbs.x, vScaleAbs.y), vScaleAbs.z);
  1978.                                                                 }
  1979.                                                                 else
  1980.                                                                         assert(!"Undefined object type");
  1981.  
  1982.                                                                 info.pMat = pMaterial;
  1983.  
  1984.                                                                 if (info.pStatObj->m_nFlags & STATIC_OBJECT_HIDDEN)
  1985.                                                                         continue;
  1986.  
  1987.                                                                 info.bIndoor = pNode->GetEntityVisArea() != 0;
  1988.  
  1989.                                                                 info.bVegetation = (nObjType == eERType_Vegetation);
  1990.  
  1991.                                                                 if (parrObjects)
  1992.                                                                 {
  1993.                                                                         parrObjects->Add(info);
  1994.                                                                 }
  1995.                                                                 else if (eStreamingStatusParent != ecss_Ready && bUnloadable)
  1996.                                                                 {
  1997.                                                                         // request streaming of missing meshes
  1998.                                                                         if (Cry3DEngineBase::GetCVars()->e_svoTI_VoxelizaionPostpone == 2)
  1999.                                                                         {
  2000.                                                                                 info.pStatObj->UpdateStreamableComponents(0.5f, info.matObj, false, nLod);
  2001.                                                                         }
  2002.  
  2003.                                                                         if (Cry3DEngineBase::GetCVars()->e_svoDebug == 7)
  2004.                                                                         {
  2005.                                                                                 Cry3DEngineBase::Get3DEngine()->DrawBBox(pNode->GetBBox(), Col_Red);
  2006.                                                                                 IRenderAuxText::DrawLabel(pNode->GetBBox().GetCenter(), 1.3f, info.pStatObj->GetFilePath());
  2007.                                                                         }
  2008.                                                                         bSuccess = false;
  2009.                                                                 }
  2010.                                                         }
  2011.                                                 }
  2012.                                         }
  2013.                                 }
  2014.                         }
  2015.                 }
  2016.         }
  2017.  
  2018.         return bSuccess;
  2019. }
  2020.  
  2021. void CVoxelSegment::FindTrianglesForVoxelization(int nTID, PodArray<int>*& rpNodeTrisXYZ, bool _bThisIsAreaParent)
  2022. {
  2023.         AABB cloudBoxWS;
  2024.         cloudBoxWS.min = m_boxOS.min + m_vSegOrigin;
  2025.         cloudBoxWS.max = m_boxOS.max + m_vSegOrigin;
  2026.  
  2027.         PodArray<SObjInfo> arrObjects;
  2028.         bool bThisIsAreaParent, bThisIsLowLodNode;
  2029.  
  2030.         CVoxelSegment::CheckCollectObjectsForVoxelization(cloudBoxWS, &arrObjects, bThisIsAreaParent, bThisIsLowLodNode, false);
  2031.  
  2032.         m_nodeTrisAllMerged.Reset();
  2033.         m_boxTris.Reset();
  2034.  
  2035.         // safety border support
  2036.         //  Vec3 vCloudSize = cloudBoxWS.GetSize();
  2037.         //    cloudBoxWS.min -= (vCloudSize/nVoxTexMaxDim)/2;
  2038.         //    cloudBoxWS.max += (vCloudSize/nVoxTexMaxDim)/2;
  2039.  
  2040.         //if(!m_pParentCloud)
  2041.         if (bThisIsAreaParent || bThisIsLowLodNode)
  2042.         {
  2043.                 // get tris from real level geometry
  2044.  
  2045.                 //              PodArray<SRayHitTriangle> allTrisInArea;
  2046.                 //      allTrisInArea.PreAllocate(4000);
  2047.  
  2048.                 float fStartTimeAll = GetCurAsyncTimeSec();
  2049.                 //              PrintMessage("VoxelizeMeshes: starting triangle search for node id %d (size=%d)", m_nId, (int)GetBoxSize());
  2050.  
  2051.                 SSuperMesh superMesh;
  2052.                 PodArray<SMINDEX> arrVertHash[nHashDim][nHashDim][nHashDim];
  2053.  
  2054.                 //      if(nCulled)
  2055.                 //        PrintMessage("  %d objects culled", nCulled);
  2056.  
  2057.                 PodArray<SRayHitTriangle> arrTris;
  2058.  
  2059.                 for (int d = 0; d < arrObjects.Count(); d++)
  2060.                 {
  2061.                         SRayHitInfo nodeHitInfo;
  2062.                         nodeHitInfo.bInFirstHit = true;
  2063.                         nodeHitInfo.bUseCache = false;
  2064.                         nodeHitInfo.bGetVertColorAndTC = true;
  2065.  
  2066.                         SObjInfo& info = arrObjects[d];
  2067.  
  2068.                         nodeHitInfo.nHitTriID = HIT_UNKNOWN;
  2069.                         nodeHitInfo.nHitMatID = HIT_UNKNOWN;
  2070.                         nodeHitInfo.inRay.origin = info.matObjInv.TransformPoint(m_vSegOrigin);
  2071.                         nodeHitInfo.inRay.direction = Vec3(0, 0, 0);
  2072.                         nodeHitInfo.inReferencePoint = nodeHitInfo.inRay.origin + nodeHitInfo.inRay.direction * 0.5f;
  2073.                         nodeHitInfo.fMaxHitDistance = GetBoxSize() / 2.f / info.fObjScale * sqrt(3.f);
  2074.  
  2075.                         arrTris.Clear();
  2076.                         nodeHitInfo.pHitTris = &arrTris;
  2077.  
  2078.                         nodeHitInfo.fMinHitOpacity = GetCVars()->e_svoTI_MinVoxelOpacity;
  2079.                         int nMinVoxelOpacity = (int)(GetCVars()->e_svoTI_MinVoxelOpacity * 255.f);
  2080.  
  2081.                         float fTimeRayIntersection = Cry3DEngineBase::GetTimer()->GetAsyncCurTime();
  2082.  
  2083.                         info.pStatObj->RayIntersection(nodeHitInfo, info.pMat);
  2084.  
  2085.                         if (arrTris.Count())
  2086.                         {
  2087.                                 {
  2088.                                         AUTO_MODIFYLOCK(CVoxelSegment::m_arrLockedMaterials.m_Lock);
  2089.                                         CVoxelSegment::m_arrLockedMaterials.Add(info.pMat);
  2090.                                         info.pMat->AddRef();
  2091.                                         for (int s = 0; s < info.pMat->GetSubMtlCount(); s++)
  2092.                                         {
  2093.                                                 IMaterial* pSubMtl = info.pMat->GetSafeSubMtl(s);
  2094.                                                 CVoxelSegment::m_arrLockedMaterials.Add(pSubMtl);
  2095.                                                 pSubMtl->AddRef();
  2096.                                         }
  2097.                                 }
  2098.  
  2099.                                 superMesh.Clear(&arrVertHash[0][0][0]);
  2100.  
  2101.                                 float fEpsilon = GetCVars()->e_svoTI_ObjectsMaxViewDistance ? (VEC_EPSILON / 2) : (VEC_EPSILON / 10);
  2102.  
  2103.                                 for (int t = 0; t < arrTris.Count(); t++)
  2104.                                 {
  2105.                                         SRayHitTriangle ht = arrTris[t];
  2106.  
  2107.                                         // Workaround for over occlusion from vegetation; TODO: make thin geoemtry produce less occlusion
  2108.                                         if (info.bVegetation && ht.pMat)
  2109.                                         {
  2110.                                                 float fMidZ = 0;
  2111.                                                 for (int v = 0; v < 3; v++)
  2112.                                                         fMidZ += ht.v[v].z;
  2113.                                                 fMidZ *= 0.333f;
  2114.  
  2115.                                                 SShaderItem& rSI = ht.pMat->GetShaderItem();
  2116.  
  2117.                                                 if (rSI.m_pShaderResources && rSI.m_pShader)
  2118.                                                 {
  2119.                                                         bool bVegetationLeaves = (rSI.m_pShaderResources->GetAlphaRef() > 0.05f && rSI.m_pShader->GetShaderType() == eST_Vegetation);
  2120.  
  2121.                                                         if (bVegetationLeaves)
  2122.                                                                 ht.nOpacity = min(ht.nOpacity, uint8(SATURATEB(GetCVars()->e_svoTI_VegetationMaxOpacity * 255.f)));
  2123.                                                         else
  2124.                                                                 ht.nOpacity = min(ht.nOpacity, uint8(SATURATEB(LERP(255.f, GetCVars()->e_svoTI_VegetationMaxOpacity * 255.f, SATURATE(fMidZ * .5f)))));
  2125.                                                 }
  2126.                                         }
  2127.  
  2128.                                         if (ht.nOpacity < nMinVoxelOpacity)
  2129.                                                 continue;
  2130.  
  2131.                                         for (int v = 0; v < 3; v++)
  2132.                                                 ht.v[v] = info.matObj.TransformPoint(ht.v[v]);
  2133.  
  2134.                                         ht.nTriArea = SATURATEB(int(SVO_CPU_VOXELIZATION_AREA_SCALE * 0.5f * (ht.v[1] - ht.v[0]).Cross(ht.v[2] - ht.v[0]).GetLength()));
  2135.                                         Plane pl;
  2136.                                         pl.SetPlane(ht.v[0], ht.v[1], ht.v[2]);
  2137.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  2138.                                         ht.n = pl.n;
  2139.         #endif
  2140.                                         if (!ht.v[0].IsEquivalent(ht.v[1], fEpsilon) && !ht.v[1].IsEquivalent(ht.v[2], fEpsilon) && !ht.v[2].IsEquivalent(ht.v[0], fEpsilon))
  2141.                                                 if ((ht.nTriArea || !GetCVars()->e_svoTI_ObjectsMaxViewDistance) && Overlap::AABB_Triangle(cloudBoxWS, ht.v[0], ht.v[1], ht.v[2]))
  2142.                                                 {
  2143.                                                         bool bSkipUnderTerrain = Get3DEngine()->m_bShowTerrainSurface && !info.bIndoor && (!GetCVars()->e_svoTI_VoxelizeUnderTerrain || info.bVegetation);
  2144.  
  2145.                                                         if (bSkipUnderTerrain)
  2146.                                                         {
  2147.                                                                 for (int h = 0; h < 3; h++)
  2148.                                                                 {
  2149.                                                                         Vec3 vH = ht.v[h];
  2150.                                                                         vH.CheckMax(cloudBoxWS.min);
  2151.                                                                         vH.CheckMin(cloudBoxWS.max);
  2152.                                                                         if (vH.z > (GetTerrain()->GetZ((int)vH.x, (int)vH.y, 0) - 1.f) || GetTerrain()->GetHole((int)vH.x, (int)vH.y, 0))
  2153.                                                                         {
  2154.                                                                                 bSkipUnderTerrain = false;
  2155.                                                                                 break;
  2156.                                                                         }
  2157.                                                                 }
  2158.                                                         }
  2159.  
  2160.                                                         if (!bSkipUnderTerrain)
  2161.                                                                 superMesh.AddSuperTriangle(ht, arrVertHash);
  2162.                                                 }
  2163.                                 }
  2164.  
  2165.                                 {
  2166.                                         AUTO_MODIFYLOCK(m_superMeshLock);
  2167.  
  2168.                                         AddSuperMesh(superMesh, SVO_CPU_VOXELIZATION_OFFSET_MESH);
  2169.                                 }
  2170.                         }
  2171.  
  2172.                         fTimeRayIntersection = Cry3DEngineBase::GetTimer()->GetAsyncCurTime() - fTimeRayIntersection;
  2173.  
  2174.                         if (GetCVars()->e_svoDebug)
  2175.                         {
  2176.                                 AUTO_MODIFYLOCK(CVoxelSegment::m_cgfTimeStatsLock);
  2177.                                 m_cgfTimeStats[info.pStatObj] += fTimeRayIntersection;
  2178.                         }
  2179.                 }
  2180.  
  2181.                 // add terrain
  2182.                 if (Get3DEngine()->m_bShowTerrainSurface)
  2183.                 {
  2184.                         float fStartTime = GetCurAsyncTimeSec();
  2185.  
  2186.                         CTerrain* pTerrain = GetTerrain();
  2187.                         int nWorldSize = pTerrain->GetTerrainSize();
  2188.                         int S = pTerrain->GetHeightMapUnitSize();
  2189.  
  2190.                         if (bThisIsLowLodNode)
  2191.                                 S *= 4;
  2192.  
  2193.                         int nHalfStep = S / 2;
  2194.                         //                      int nInitTriCount = allTrisInArea.Count();
  2195.  
  2196.                         SRayHitTriangle ht;
  2197.                         ZeroStruct(ht);
  2198.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  2199.                         ht.c[0] = ht.c[1] = ht.c[2] = Col_White;
  2200.         #endif
  2201.                         ht.nOpacity = 255;
  2202.                         ht.nHitObjType = HIT_OBJ_TYPE_TERRAIN;
  2203.                         Plane pl;
  2204.  
  2205.                         int I = 0, X = 0, Y = 0;
  2206.  
  2207.                         superMesh.Clear(&arrVertHash[0][0][0]);
  2208.  
  2209.                         for (int x = (int)cloudBoxWS.min.x; x < (int)cloudBoxWS.max.x; x += S)
  2210.                         {
  2211.                                 for (int y = (int)cloudBoxWS.min.y; y < (int)cloudBoxWS.max.y; y += S)
  2212.                                 {
  2213.                                         if (!pTerrain->GetHole(x + nHalfStep, y + nHalfStep, 0))
  2214.                                         {
  2215.                                                 // prevent surface interpolation over long edge
  2216.                                                 bool bFlipTris = false;
  2217.                                                 int nType10 = pTerrain->GetSurfaceTypeID(x + S, y, 0);
  2218.                                                 int nType01 = pTerrain->GetSurfaceTypeID(x, y + S, 0);
  2219.                                                 if (nType10 != nType01)
  2220.                                                 {
  2221.                                                         int nType00 = pTerrain->GetSurfaceTypeID(x, y, 0);
  2222.                                                         int nType11 = pTerrain->GetSurfaceTypeID(x + S, y + S, 0);
  2223.                                                         if ((nType10 == nType00 && nType10 == nType11) || (nType01 == nType00 && nType01 == nType11))
  2224.                                                                 bFlipTris = true;
  2225.                                                 }
  2226.  
  2227.                                                 if (bFlipTris)
  2228.                                                 {
  2229.                                                         I = 0;
  2230.                                                         X = x + S, Y = y + 0;
  2231.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2232.                                                         I++;
  2233.                                                         X = x + S, Y = y + S;
  2234.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2235.                                                         I++;
  2236.                                                         X = x + 0, Y = y + 0;
  2237.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2238.                                                         I++;
  2239.  
  2240.                                                         if (Overlap::AABB_Triangle(cloudBoxWS, ht.v[0], ht.v[1], ht.v[2]))
  2241.                                                         {
  2242.                                                                 ht.nTriArea = SATURATEB(int(SVO_CPU_VOXELIZATION_AREA_SCALE * 0.5f * (ht.v[1] - ht.v[0]).Cross(ht.v[2] - ht.v[0]).GetLength()));
  2243.                                                                 pl.SetPlane(ht.v[0], ht.v[1], ht.v[2]);
  2244.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  2245.                                                                 ht.n = pl.n;
  2246.         #endif
  2247.                                                                 superMesh.AddSuperTriangle(ht, arrVertHash);
  2248.                                                         }
  2249.  
  2250.                                                         I = 0;
  2251.                                                         X = x + 0, Y = y + 0;
  2252.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2253.                                                         I++;
  2254.                                                         X = x + S, Y = y + S;
  2255.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2256.                                                         I++;
  2257.                                                         X = x + 0, Y = y + S;
  2258.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2259.                                                         I++;
  2260.  
  2261.                                                         if (Overlap::AABB_Triangle(cloudBoxWS, ht.v[0], ht.v[1], ht.v[2]))
  2262.                                                         {
  2263.                                                                 ht.nTriArea = SATURATEB(int(SVO_CPU_VOXELIZATION_AREA_SCALE * 0.5f * (ht.v[1] - ht.v[0]).Cross(ht.v[2] - ht.v[0]).GetLength()));
  2264.                                                                 pl.SetPlane(ht.v[0], ht.v[1], ht.v[2]);
  2265.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  2266.                                                                 ht.n = pl.n;
  2267.         #endif
  2268.                                                                 superMesh.AddSuperTriangle(ht, arrVertHash);
  2269.                                                         }
  2270.                                                 }
  2271.                                                 else
  2272.                                                 {
  2273.                                                         I = 0;
  2274.                                                         X = x + 0, Y = y + 0;
  2275.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2276.                                                         I++;
  2277.                                                         X = x + S, Y = y + 0;
  2278.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2279.                                                         I++;
  2280.                                                         X = x + 0, Y = y + S;
  2281.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2282.                                                         I++;
  2283.  
  2284.                                                         if (Overlap::AABB_Triangle(cloudBoxWS, ht.v[0], ht.v[1], ht.v[2]))
  2285.                                                         {
  2286.                                                                 ht.nTriArea = SATURATEB(int(SVO_CPU_VOXELIZATION_AREA_SCALE * 0.5f * (ht.v[1] - ht.v[0]).Cross(ht.v[2] - ht.v[0]).GetLength()));
  2287.                                                                 pl.SetPlane(ht.v[0], ht.v[1], ht.v[2]);
  2288.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  2289.                                                                 ht.n = pl.n;
  2290.         #endif
  2291.                                                                 superMesh.AddSuperTriangle(ht, arrVertHash);
  2292.                                                         }
  2293.  
  2294.                                                         I = 0;
  2295.                                                         X = x + S, Y = y + 0;
  2296.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2297.                                                         I++;
  2298.                                                         X = x + S, Y = y + S;
  2299.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2300.                                                         I++;
  2301.                                                         X = x + 0, Y = y + S;
  2302.                                                         ht.v[I].Set((float)X, (float)Y, pTerrain->GetZ(X, Y, 0));
  2303.                                                         I++;
  2304.  
  2305.                                                         if (Overlap::AABB_Triangle(cloudBoxWS, ht.v[0], ht.v[1], ht.v[2]))
  2306.                                                         {
  2307.                                                                 ht.nTriArea = SATURATEB(int(SVO_CPU_VOXELIZATION_AREA_SCALE * 0.5f * (ht.v[1] - ht.v[0]).Cross(ht.v[2] - ht.v[0]).GetLength()));
  2308.                                                                 pl.SetPlane(ht.v[0], ht.v[1], ht.v[2]);
  2309.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  2310.                                                                 ht.n = pl.n;
  2311.         #endif
  2312.                                                                 superMesh.AddSuperTriangle(ht, arrVertHash);
  2313.                                                         }
  2314.                                                 }
  2315.                                         }
  2316.                                 }
  2317.                         }
  2318.  
  2319.                         //      if(allTrisInLevel.Count()-nInitTriCount)
  2320.                         //        PrintMessage("Terrain: %d tris added (in %.2f sec) for node id %d (size=%d)",
  2321.                         //        (allTrisInLevel.Count()-nInitTriCount), GetCurAsyncTimeSec()-fStartTime,
  2322.                         //        m_nId, (int)GetBoxSize());
  2323.  
  2324.                         AUTO_MODIFYLOCK(m_superMeshLock);
  2325.  
  2326.                         AddSuperMesh(superMesh, SVO_CPU_VOXELIZATION_OFFSET_TERRAIN);
  2327.                 }
  2328.  
  2329.         #ifdef FEATURE_SVO_GI_ALLOW_HQ
  2330.                 AABB cloudBoxWS_VisAreaEx = cloudBoxWS;
  2331.                 cloudBoxWS_VisAreaEx.Expand(Vec3(SVO_CPU_VOXELIZATION_OFFSET_VISAREA, SVO_CPU_VOXELIZATION_OFFSET_VISAREA, SVO_CPU_VOXELIZATION_OFFSET_VISAREA));
  2332.  
  2333.                 // add visarea shapes
  2334.                 if (!bThisIsLowLodNode)
  2335.                         for (int v = 0;; v++)
  2336.                         {
  2337.                                 superMesh.Clear(&arrVertHash[0][0][0]);
  2338.  
  2339.                                 CVisArea* pVisArea = (CVisArea*)GetVisAreaManager()->GetVisAreaById(v);
  2340.                                 if (!pVisArea)
  2341.                                         break;
  2342.  
  2343.                                 if (pVisArea->IsPortal() || !Overlap::AABB_AABB(*pVisArea->GetAABBox(), cloudBoxWS_VisAreaEx))
  2344.                                         continue;
  2345.  
  2346.                                 size_t nPoints = 0;
  2347.                                 const Vec3* pPoints = 0;
  2348.                                 pVisArea->GetShapePoints(pPoints, nPoints);
  2349.                                 float fHeight = pVisArea->GetHeight();
  2350.  
  2351.                                 SRayHitTriangle ht;
  2352.                                 ZeroStruct(ht);
  2353.                                 ht.c[0] = ht.c[1] = ht.c[2] = Col_Black;
  2354.                                 ht.nOpacity = 255;
  2355.                                 ht.nHitObjType = HIT_OBJ_TYPE_VISAREA;
  2356.                                 Plane pl;
  2357.  
  2358.                                 // sides
  2359.                                 for (size_t i = 0; i < nPoints; i++)
  2360.                                 {
  2361.                                         const Vec3& v0 = (pPoints)[i];
  2362.                                         const Vec3& v1 = (pPoints)[(i + 1) % nPoints];
  2363.