BVB Source Codes

CRYENGINE Show StatObjConstr.cpp Source code

Return Download CRYENGINE: download StatObjConstr.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:   statobjconstr.cpp
  5. //  Version:     v1.00
  6. //  Created:     28/5/2001 by Vladimir Kajalin
  7. //  Compilers:   Visual Studio.NET
  8. //  Description: creation
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15.  
  16. #include "StatObj.h"
  17.  
  18. #include "IndexedMesh.h"
  19. #include "../RenderDll/Common/Shadow_Renderer.h"
  20. #include <CryRenderer/IRenderer.h>
  21. #include <CryMemory/CrySizer.h>
  22. #include "ObjMan.h"
  23. #include "PolygonClipContext.h"
  24. #include "MatMan.h"
  25. #include "RenderMeshMerger.h"
  26. #include "MergedMeshGeometry.h"
  27.  
  28. #define MAX_VERTICES_MERGABLE       15000
  29. #define MAX_TRIS_IN_LOD_0           512
  30. #define TRIS_IN_LOD_WARNING_RAIO    (1.5f)
  31. // Minimal ratio of Lod(n-1)/Lod(n) polygons to consider LOD for sub-object merging.
  32. #define MIN_TRIS_IN_MERGED_LOD_RAIO (1.5f)
  33.  
  34. DEFINE_INTRUSIVE_LINKED_LIST(CStatObj)
  35.  
  36. //////////////////////////////////////////////////////////////////////////
  37. CStatObj::CStatObj()
  38. {
  39.         m_pAsyncUpdateContext = 0;
  40.         m_nNodeCount = 0;
  41.         m_nMergedMemoryUsage = 0;
  42.         m_nUsers = 0; // reference counter
  43.         m_nLastDrawMainFrameId = 0;
  44.         m_nFlags = 0;
  45.         m_pLODs = 0;
  46.         m_lastBooleanOpScale = 1.f;
  47.         m_fGeometricMeanFaceArea = 0.f;
  48.         m_fLodDistance = 0.0f;
  49.  
  50.         Init();
  51.  
  52. #ifdef TRACE_CGF_LEAKS
  53.         m_sLoadingCallstack = GetSystem()->GetLoadingProfilerCallstack();
  54. #endif
  55. }
  56.  
  57. //////////////////////////////////////////////////////////////////////////
  58. void CStatObj::Init()
  59. {
  60.         m_pAsyncUpdateContext = 0;
  61.         m_pIndexedMesh = 0;
  62.         m_lockIdxMesh = 0;
  63.         m_nRenderTrisCount = m_nLoadedTrisCount = m_nLoadedVertexCount = 0;
  64.         m_nRenderMatIds = 0;
  65.         m_fRadiusHors = 0;
  66.         m_fRadiusVert = 0;
  67.         m_pParentObject = 0;
  68.         m_pClonedSourceObject = 0;
  69.         m_bVehicleOnlyPhysics = 0;
  70.         m_bBreakableByGame = 0;
  71.         m_idmatBreakable = -1;
  72.  
  73.         m_nLoadedLodsNum = 1;
  74.         m_nMinUsableLod0 = 0;
  75.         m_nMaxUsableLod0 = 0;
  76.         m_nMaxUsableLod = 0;
  77.         m_pLod0 = 0;
  78.  
  79.         m_aiVegetationRadius = -1.0f;
  80.         m_phys_mass = -1.0f;
  81.         m_phys_density = -1.0f;
  82.  
  83.         m_AABB = AABB(0.f);
  84.         m_vVegCenter.Set(0, 0, 0);
  85.  
  86.         m_fGeometricMeanFaceArea = 0.f;
  87.         m_fLodDistance = 0.0f;
  88.         m_depthSortOffset.Set(0, 0, 0);
  89.  
  90.         m_pRenderMesh = 0;
  91.  
  92.         m_bDefaultObject = false;
  93.  
  94.         if (m_pLODs)
  95.                 for (int i = 0; i < MAX_STATOBJ_LODS_NUM; i++)
  96.                         if (m_pLODs[i])
  97.                                 m_pLODs[i]->Init();
  98.  
  99.         m_pReadStream = 0;
  100.         m_nModificationId = 0;
  101.         m_nSubObjectMeshCount = 0;
  102.  
  103.         m_nRenderMeshMemoryUsage = 0;
  104.         m_arrRenderMeshesPotentialMemoryUsage[0] = m_arrRenderMeshesPotentialMemoryUsage[1] = -1;
  105.  
  106.         m_bCanUnload = false;
  107.         m_bLodsLoaded = false;
  108.         m_bDefaultObject = false;
  109.         m_bOpenEdgesTested = false;
  110.         m_bSubObject = false;
  111.         m_bSharesChildren = false;
  112.         m_bHasDeformationMorphs = false;
  113.         m_bTmpIndexedMesh = false;
  114.         m_bMerged = false;
  115.         m_bMergedLODs = false;
  116.         m_bUnmergable = false;
  117.         m_bLowSpecLod0Set = false;
  118.         m_bHaveOcclusionProxy = false;
  119.         m_bCheckGarbage = false;
  120.         m_bLodsAreLoadedFromSeparateFile = false;
  121.         m_bNoHitRefinement = false;
  122.         m_bDontOccludeExplosions = false;
  123.         m_isDeformable = false;
  124.         m_isProxyTooBig = false;
  125.         m_bHasStreamOnlyCGF = true;
  126.  
  127.         // Assign default material originally.
  128.         m_pMaterial = GetMatMan()->GetDefaultMaterial();
  129.  
  130.         m_pLattice = 0;
  131.         m_pSpines = 0;
  132.         m_nSpines = 0;
  133.         m_pBoneMapping = 0;
  134.         m_pLastBooleanOp = 0;
  135.         m_pMapFaceToFace0 = 0;
  136.         m_pClothTangentsData = 0;
  137.         m_pSkinInfo = 0;
  138.         m_hasClothTangentsData = m_hasSkinInfo = 0;
  139.         m_pDelayedSkinParams = 0;
  140.         m_arrPhysGeomInfo.m_array.clear();
  141.  
  142.         m_nInitialSubObjHideMask = 0;
  143.  
  144. #if !defined (_RELEASE)
  145.         m_fStreamingStart = 0.0f;
  146. #endif
  147.  
  148. #ifdef OBJMAN_STREAM_STATS
  149.         m_nStatoscopeState = 0;
  150. #endif
  151. }
  152.  
  153. //////////////////////////////////////////////////////////////////////////
  154. CStatObj::~CStatObj()
  155. {
  156.         ShutDown();
  157. }
  158.  
  159. void CStatObj::ShutDown()
  160. {
  161.         if (m_pReadStream)
  162.         {
  163.                 // We don't need this stream anymore.
  164.                 m_pReadStream->Abort();
  165.                 m_pReadStream = NULL;
  166.         }
  167.  
  168.         SAFE_DELETE(m_pAsyncUpdateContext);
  169.  
  170.         //      assert (IsHeapValid());
  171.  
  172.         SAFE_DELETE(m_pIndexedMesh);
  173.         //      assert (IsHeapValid());
  174.  
  175.         for (int n = 0; n < m_arrPhysGeomInfo.GetGeomCount(); n++)
  176.                 if (m_arrPhysGeomInfo[n])
  177.                 {
  178.                         if (m_arrPhysGeomInfo[n]->pGeom->GetForeignData() == (void*)this)
  179.                                 m_arrPhysGeomInfo[n]->pGeom->SetForeignData(0, 0);
  180.                         GetPhysicalWorld()->GetGeomManager()->UnregisterGeometry(m_arrPhysGeomInfo[n]);
  181.                 }
  182.         m_arrPhysGeomInfo.m_array.clear();
  183.  
  184.         m_pStreamedRenderMesh = 0;
  185.         m_pMergedRenderMesh = 0;
  186.         SetRenderMesh(0);
  187.  
  188.         //      assert (IsHeapValid());
  189.  
  190.         /* // SDynTexture is not accessible for 3dengine
  191.  
  192.            for(int i=0; i<FAR_TEX_COUNT; i++)
  193.             if(m_arrSpriteTexPtr[i])
  194.               m_arrSpriteTexPtr[i]->ReleaseDynamicRT(true);
  195.  
  196.            for(int i=0; i<FAR_TEX_COUNT_60; i++)
  197.             if(m_arrSpriteTexPtr_60[i])
  198.               m_arrSpriteTexPtr_60[i]->ReleaseDynamicRT(true);
  199.          */
  200.  
  201.         SAFE_RELEASE(m_pLattice);
  202.  
  203.         if (m_pLODs)
  204.                 for (int i = 0; i < MAX_STATOBJ_LODS_NUM; i++)
  205.                         if (m_pLODs[i])
  206.                         {
  207.                                 if (m_pLODs[i]->m_pParentObject)
  208.                                         GetObjManager()->UnregisterForStreaming(m_pLODs[i]->m_pParentObject);
  209.                                 else
  210.                                         GetObjManager()->UnregisterForStreaming(m_pLODs[i]);
  211.  
  212.                                 // Sub objects do not own the LODs, so they should not delete them.
  213.                                 m_pLODs[i] = 0;
  214.                         }
  215.  
  216.         //////////////////////////////////////////////////////////////////////////
  217.         // Handle sub-objects and parents.
  218.         //////////////////////////////////////////////////////////////////////////
  219.         for (size_t i = 0; i < m_subObjects.size(); i++)
  220.         {
  221.                 CStatObj* pChildObj = (CStatObj*)m_subObjects[i].pStatObj;
  222.                 if (pChildObj)
  223.                 {
  224.                         if (!m_bSharesChildren)
  225.                                 pChildObj->m_pParentObject = NULL;
  226.                         GetObjManager()->UnregisterForStreaming(pChildObj);
  227.                         pChildObj->Release();
  228.                 }
  229.         }
  230.         m_subObjects.clear();
  231.  
  232.         if (m_pParentObject && !m_pParentObject->m_subObjects.empty())
  233.         {
  234.                 // Remove this StatObject from sub-objects of the parent.
  235.                 SSubObject* pSubObjects = &m_pParentObject->m_subObjects[0];
  236.                 for (int i = 0, num = m_pParentObject->m_subObjects.size(); i < num; i++)
  237.                 {
  238.                         if (pSubObjects[i].pStatObj == this)
  239.                         {
  240.                                 m_pParentObject->m_subObjects.erase(m_pParentObject->m_subObjects.begin() + i);
  241.                                 break;
  242.                         }
  243.                 }
  244.         }
  245.  
  246.         //////////////////////////////////////////////////////////////////////////
  247.  
  248.         FreeFoliageData();
  249.  
  250.         if (m_pMapFaceToFace0)
  251.                 delete[] m_pMapFaceToFace0;
  252.         m_pMapFaceToFace0 = 0;
  253.         if (m_hasClothTangentsData && !m_pClonedSourceObject)
  254.                 delete[] m_pClothTangentsData;
  255.         if (m_hasSkinInfo && !m_pClonedSourceObject)
  256.                 delete[] m_pSkinInfo;
  257.         m_pClothTangentsData = 0;
  258.         m_hasClothTangentsData = 0;
  259.         m_pSkinInfo = 0;
  260.         m_hasSkinInfo = 0;
  261.  
  262.         SAFE_DELETE(m_pDelayedSkinParams);
  263.  
  264.         SAFE_RELEASE(m_pClonedSourceObject);
  265.  
  266.         GetObjManager()->UnregisterForStreaming(this);
  267.  
  268.         SAFE_DELETE_ARRAY(m_pLODs);
  269. }
  270.  
  271. //////////////////////////////////////////////////////////////////////////
  272. int CStatObj::Release()
  273. {
  274.         // Has to be thread safe, as it can be called by a worker thread for deferred plane breaks
  275.         int newRef = CryInterlockedDecrement(&m_nUsers);
  276.         if (newRef <= 1)
  277.         {
  278.                 if (m_pParentObject && m_pParentObject->m_nUsers <= 0)
  279.                 {
  280.                         GetObjManager()->CheckForGarbage(m_pParentObject);
  281.                 }
  282.                 if (newRef <= 0)
  283.                 {
  284.                         GetObjManager()->CheckForGarbage(this);
  285.                 }
  286.         }
  287.         return newRef;
  288. }
  289.  
  290. //////////////////////////////////////////////////////////////////////////
  291. void* CStatObj::operator new(size_t size)
  292. {
  293.         CObjManager* pObjManager = GetObjManager();
  294.         assert(size == sizeof(CStatObj));
  295.         return pObjManager->AllocateStatObj();
  296. }
  297.  
  298. void CStatObj::operator delete(void* pToFree)
  299. {
  300.         CObjManager* pObjManager = GetObjManager();
  301.         pObjManager->FreeStatObj((CStatObj*)pToFree);
  302. }
  303.  
  304. //////////////////////////////////////////////////////////////////////////
  305. void CStatObj::FreeIndexedMesh()
  306. {
  307.         if (!m_lockIdxMesh)
  308.         {
  309.                 WriteLock lock(m_lockIdxMesh);
  310.                 delete m_pIndexedMesh;
  311.                 m_pIndexedMesh = 0;
  312.         }
  313. }
  314.  
  315. //////////////////////////////////////////////////////////////////////////
  316. void CStatObj::CalcRadiuses()
  317. {
  318.         if (!m_AABB.min.IsValid() || !m_AABB.max.IsValid())
  319.         {
  320.                 Error("CStatObj::CalcRadiuses: Invalid bbox, File name: %s", m_szFileName.c_str());
  321.                 m_AABB.min.zero();
  322.                 m_AABB.max.zero();
  323.         }
  324.  
  325.         float dxh = (float)max(fabs(GetBoxMax().x), fabs(GetBoxMin().x));
  326.         float dyh = (float)max(fabs(GetBoxMax().y), fabs(GetBoxMin().y));
  327.         m_fRadiusHors = (float)sqrt_tpl(dxh * dxh + dyh * dyh);
  328.         m_fRadiusVert = (GetBoxMax().z - 0) * 0.5f;// never change this
  329.         m_vVegCenter = m_AABB.GetCenter();
  330.         m_vVegCenter.z = m_fRadiusVert;
  331. }
  332.  
  333. void CStatObj::MakeRenderMesh()
  334. {
  335.         if (gEnv->IsDedicated())
  336.                 return;
  337.  
  338.         FUNCTION_PROFILER_3DENGINE;
  339.  
  340.         SetRenderMesh(0);
  341.  
  342.         if (!m_pIndexedMesh || m_pIndexedMesh->GetSubSetCount() == 0)
  343.                 return;
  344.  
  345.         CMesh* pMesh = m_pIndexedMesh->GetMesh();
  346.  
  347.         m_nRenderTrisCount = 0;
  348.         //////////////////////////////////////////////////////////////////////////
  349.         // Initialize Mesh subset material flags.
  350.         //////////////////////////////////////////////////////////////////////////
  351.         for (int i = 0; i < pMesh->GetSubSetCount(); i++)
  352.         {
  353.                 SMeshSubset& subset = pMesh->m_subsets[i];
  354.                 if (!(subset.nMatFlags & MTL_FLAG_NODRAW))
  355.                 {
  356.                         m_nRenderTrisCount += subset.nNumIndices / 3;
  357.                 }
  358.         }
  359.         //////////////////////////////////////////////////////////////////////////
  360.         if (!m_nRenderTrisCount)
  361.                 return;
  362.  
  363.         if (!(GetFlags() & STATIC_OBJECT_DYNAMIC))
  364.                 m_pRenderMesh = GetRenderer()->CreateRenderMesh("StatObj_Static", GetFilePath(), NULL, eRMT_Static);
  365.         else
  366.         {
  367.                 m_pRenderMesh = GetRenderer()->CreateRenderMesh("StatObj_Dynamic", GetFilePath(), NULL, eRMT_Dynamic);
  368.                 m_pRenderMesh->KeepSysMesh(true);
  369.         }
  370.  
  371.         SMeshBoneMapping_uint16* const pBoneMap = pMesh->m_pBoneMapping;
  372.         pMesh->m_pBoneMapping = 0;
  373.         uint32 nFlags = 0;
  374.         nFlags |= (!GetCVars()->e_StreamCgf && Get3DEngine()->m_bInLoad) ? FSM_SETMESH_ASYNC : 0;
  375.         m_pRenderMesh->SetMesh(*pMesh, 0, nFlags, NULL, false);
  376.         pMesh->m_pBoneMapping = pBoneMap;
  377. }
  378.  
  379. //////////////////////////////////////////////////////////////////////////
  380. void CStatObj::SetMaterial(IMaterial* pMaterial)
  381. {
  382.         m_pMaterial = pMaterial;
  383. }
  384.  
  385. ///////////////////////////////////////////////////////////////////////////////////////
  386. Vec3 CStatObj::GetHelperPos(const char* szHelperName)
  387. {
  388.         SSubObject* pSubObj = FindSubObject(szHelperName);
  389.         if (!pSubObj)
  390.                 return Vec3(0, 0, 0);
  391.  
  392.         return Vec3(pSubObj->tm.m03, pSubObj->tm.m13, pSubObj->tm.m23);
  393. }
  394.  
  395. ///////////////////////////////////////////////////////////////////////////////////////
  396. const Matrix34& CStatObj::GetHelperTM(const char* szHelperName)
  397. {
  398.         SSubObject* pSubObj = FindSubObject(szHelperName);
  399.  
  400.         if (!pSubObj)
  401.         {
  402.                 static Matrix34 identity(IDENTITY);
  403.                 return identity;
  404.         }
  405.  
  406.         return pSubObj->tm;
  407. }
  408.  
  409. bool CStatObj::IsSameObject(const char* szFileName, const char* szGeomName)
  410. {
  411.         // cmp object names
  412.         if (szGeomName)
  413.         {
  414.                 if (stricmp(szGeomName, m_szGeomName) != 0)
  415.                         return false;
  416.         }
  417.  
  418.         // Normilize file name
  419.         char szFileNameNorm[MAX_PATH_LENGTH] = "";
  420.         char* pszDest = szFileNameNorm;
  421.         const char* pszSource = szFileName;
  422.         while (*pszSource)
  423.         {
  424.                 if (*pszSource == '\\')
  425.                         *pszDest++ = '/';
  426.                 else
  427.                         *pszDest++ = *pszSource;
  428.                 pszSource++;
  429.         }
  430.         *pszDest = 0;
  431.  
  432.         // cmp file names
  433.         if (stricmp(szFileNameNorm, m_szFileName) != 0)
  434.                 return false;
  435.  
  436.         return true;
  437. }
  438.  
  439. void CStatObj::GetMemoryUsage(ICrySizer* pSizer) const
  440. {
  441.         {
  442.                 SIZER_COMPONENT_NAME(pSizer, "Self");
  443.                 pSizer->AddObject(this, sizeof(*this));
  444.         }
  445.  
  446.         {
  447.                 SIZER_COMPONENT_NAME(pSizer, "subObjects");
  448.                 pSizer->AddObject(m_subObjects);
  449.         }
  450.  
  451.         {
  452.                 SIZER_COMPONENT_NAME(pSizer, "Strings");
  453.                 pSizer->AddObject(m_szFileName);
  454.                 pSizer->AddObject(m_szGeomName);
  455.                 pSizer->AddObject(m_szProperties);
  456.         }
  457.  
  458.         {
  459.                 SIZER_COMPONENT_NAME(pSizer, "Material");
  460.                 pSizer->AddObject(m_pMaterial);
  461.         }
  462.  
  463.         {
  464.                 SIZER_COMPONENT_NAME(pSizer, "PhysGeomInfo");
  465.                 pSizer->AddObject(m_arrPhysGeomInfo);
  466.         }
  467.  
  468.         if (m_pLODs)
  469.                 for (int i = 1; i < MAX_STATOBJ_LODS_NUM; i++)
  470.                 {
  471.                         SIZER_COMPONENT_NAME(pSizer, "StatObjLods");
  472.                         pSizer->AddObject(m_pLODs[i]);
  473.                 }
  474.  
  475.         if (m_pIndexedMesh)
  476.         {
  477.                 SIZER_COMPONENT_NAME(pSizer, "Mesh");
  478.                 pSizer->AddObject(m_pIndexedMesh);
  479.         }
  480.  
  481.         int nVtx = 0;
  482.         if (m_pIndexedMesh)
  483.                 nVtx = m_pIndexedMesh->GetVertexCount();
  484.         else if (m_pRenderMesh)
  485.                 nVtx = m_pRenderMesh->GetVerticesCount();
  486.  
  487.         if (m_pSpines)
  488.         {
  489.                 SIZER_COMPONENT_NAME(pSizer, "StatObj Foliage Data");
  490.                 pSizer->AddObject(m_pSpines, sizeof(m_pSpines[0]), m_nSpines);
  491.                 if (m_pBoneMapping)
  492.                         pSizer->AddObject(m_pBoneMapping, sizeof(m_pBoneMapping[0]), nVtx);
  493.                 for (int i = 0; i < m_nSpines; i++)
  494.                         pSizer->AddObject(m_pSpines[i].pVtx, sizeof(Vec3) * 2 + sizeof(Vec4), m_pSpines[i].nVtx);
  495.         }
  496.  
  497.         if (m_hasClothTangentsData && (!m_pClonedSourceObject || m_pClonedSourceObject == this))
  498.         {
  499.                 SIZER_COMPONENT_NAME(pSizer, "Deformable StatObj ClothTangents");
  500.                 pSizer->AddObject(m_pClothTangentsData, nVtx * sizeof(m_pClothTangentsData[0]));
  501.         }
  502.  
  503.         if (m_hasSkinInfo && (!m_pClonedSourceObject || m_pClonedSourceObject == this))
  504.         {
  505.                 SIZER_COMPONENT_NAME(pSizer, "Deformable StatObj SkinData");
  506.                 pSizer->AddObject(m_pSkinInfo, (nVtx + 1) * sizeof(m_pSkinInfo[0]));
  507.         }
  508.  
  509.         if (m_pMapFaceToFace0)
  510.         {
  511.                 SIZER_COMPONENT_NAME(pSizer, "Deformable StatObj Mesh");
  512.                 pSizer->AddObject(m_pMapFaceToFace0, sizeof(m_pMapFaceToFace0[0]) * max(m_nLoadedTrisCount, m_nRenderTrisCount));
  513.         }
  514. }
  515.  
  516. //////////////////////////////////////////////////////////////////////////
  517. void CStatObj::SetLodObject(int nLod, IStatObj* pObj)
  518. {
  519.         assert(nLod > 0 && nLod < MAX_STATOBJ_LODS_NUM);
  520.         if (nLod <= 0 || nLod >= MAX_STATOBJ_LODS_NUM)
  521.                 return;
  522.  
  523.         CStatObj* pLod = (CStatObj*)pObj;
  524.         if (strstr(m_szProperties, "lowspeclod0"))
  525.                 m_bLowSpecLod0Set = true;
  526.  
  527.         bool bLodCompound = pLod && (pLod->GetFlags() & STATIC_OBJECT_COMPOUND) != 0;
  528.  
  529.         if (pLod && !bLodCompound)
  530.         {
  531.                 // Check if low lod decrease amount of used materials.
  532.                 int nPrevLodMatIds = m_nRenderMatIds;
  533.                 int nPrevLodTris = m_nLoadedTrisCount;
  534.                 if (nLod > 1 && m_pLODs && m_pLODs[nLod - 1])
  535.                 {
  536.                         nPrevLodMatIds = m_pLODs[nLod - 1]->m_nRenderMatIds;
  537.                         nPrevLodTris = m_pLODs[nLod - 1]->m_nLoadedTrisCount;
  538.                 }
  539.  
  540.                 if (GetCVars()->e_LodsForceUse)
  541.                 {
  542.                         if ((int)m_nMaxUsableLod < nLod)
  543.                                 m_nMaxUsableLod = nLod;
  544.                 }
  545.                 else
  546.                 {
  547.                         int min_tris = GetCVars()->e_LodMinTtris;
  548.                         if (((pLod->m_nLoadedTrisCount >= min_tris || nPrevLodTris >= (3 * min_tris) / 2)
  549.                              || pLod->m_nRenderMatIds < nPrevLodMatIds) && nLod > (int)m_nMaxUsableLod)
  550.                         {
  551.                                 m_nMaxUsableLod = nLod;
  552.                         }
  553.                 }
  554.  
  555.                 if (m_pParentObject && (m_pParentObject->m_nMaxUsableLod < m_nMaxUsableLod))
  556.                         m_pParentObject->m_nMaxUsableLod = m_nMaxUsableLod;
  557.  
  558.                 pLod->m_pLod0 = this;
  559.                 pLod->m_pMaterial = m_pMaterial; // Lod must use same material as parent.
  560.  
  561.                 if (pLod->m_nLoadedTrisCount > MAX_TRIS_IN_LOD_0)
  562.                 {
  563.                         if ((strstr(pLod->GetProperties(), "lowspeclod0") != 0) && !m_bLowSpecLod0Set)
  564.                         {
  565.                                 m_bLowSpecLod0Set = true;
  566.                                 m_nMaxUsableLod0 = nLod;
  567.                         }
  568.                         if (!m_bLowSpecLod0Set)
  569.                                 m_nMaxUsableLod0 = nLod;
  570.                 }
  571.                 if (nLod + 1 > (int)m_nLoadedLodsNum)
  572.                         m_nLoadedLodsNum = nLod + 1;
  573.  
  574.                 // When assigning lod to child object.
  575.                 if (m_pParentObject)
  576.                 {
  577.                         if (nLod + 1 > (int)m_pParentObject->m_nLoadedLodsNum)
  578.                                 m_pParentObject->m_nLoadedLodsNum = nLod + 1;
  579.                 }
  580.         }
  581.  
  582.         if (pLod && bLodCompound)
  583.         {
  584.                 m_nMaxUsableLod = nLod;
  585.                 pLod->m_bUnmergable = m_bUnmergable;
  586.         }
  587.  
  588.         if (!m_pLODs && pLod)
  589.                 m_pLODs = new _smart_ptr<CStatObj>[MAX_STATOBJ_LODS_NUM];
  590.  
  591.         if (m_pLODs)
  592.                 m_pLODs[nLod] = pLod;
  593. }
  594.  
  595. //////////////////////////////////////////////////////////////////////////
  596. IStatObj* CStatObj::GetLodObject(int nLodLevel, bool bReturnNearest)
  597. {
  598.         if (nLodLevel < 1)
  599.         {
  600.                 return this;
  601.         }
  602.  
  603.         if (!m_pLODs)
  604.         {
  605.                 if (bReturnNearest || nLodLevel == 0)
  606.                         return this;
  607.                 else
  608.                         return NULL;
  609.         }
  610.  
  611.         if (bReturnNearest)
  612.                 nLodLevel = CLAMP(nLodLevel, 0, MAX_STATOBJ_LODS_NUM - 1);
  613.  
  614.         CStatObj* pLod = 0;
  615.         if (nLodLevel < MAX_STATOBJ_LODS_NUM)
  616.         {
  617.                 pLod = m_pLODs[nLodLevel];
  618.  
  619.                 // Look up
  620.                 if (bReturnNearest && !pLod)
  621.                 {
  622.                         // Find highest existing lod looking up.
  623.                         int lod = nLodLevel;
  624.                         while (lod > 0 && m_pLODs[lod] == 0)
  625.                                 lod--;
  626.                         if (lod > 0)
  627.                         {
  628.                                 pLod = m_pLODs[lod];
  629.                         }
  630.                         else
  631.                         {
  632.                                 pLod = this;
  633.                         }
  634.                 }
  635.                 // Look down
  636.                 if (bReturnNearest && !pLod)
  637.                 {
  638.                         // Find highest existing lod looking down.
  639.                         for (int lod = nLodLevel + 1; lod < MAX_STATOBJ_LODS_NUM; lod++)
  640.                         {
  641.                                 if (m_pLODs[lod])
  642.                                 {
  643.                                         pLod = m_pLODs[lod];
  644.                                         break;
  645.                                 }
  646.                         }
  647.                 }
  648.         }
  649.  
  650.         return pLod;
  651. }
  652.  
  653. bool CStatObj::IsPhysicsExist() const
  654. {
  655.         return m_arrPhysGeomInfo.GetGeomCount() > 0;
  656. }
  657.  
  658. bool CStatObj::IsSphereOverlap(const Sphere& sSphere)
  659. {
  660.         if (m_pRenderMesh && Overlap::Sphere_AABB(sSphere, m_AABB))
  661.         {
  662.                 // if inside bbox
  663.                 int nPosStride = 0;
  664.                 int nInds = m_pRenderMesh->GetIndicesCount();
  665.                 const byte* pPos = m_pRenderMesh->GetPosPtr(nPosStride, FSL_READ);
  666.                 vtx_idx* pInds = m_pRenderMesh->GetIndexPtr(FSL_READ);
  667.  
  668.                 if (pInds && pPos)
  669.                         for (int i = 0; (i + 2) < nInds; i += 3)
  670.                         {
  671.                                 // test all triangles of water surface strip
  672.                                 Vec3 v0 = (*(Vec3*)&pPos[nPosStride * pInds[i + 0]]);
  673.                                 Vec3 v1 = (*(Vec3*)&pPos[nPosStride * pInds[i + 1]]);
  674.                                 Vec3 v2 = (*(Vec3*)&pPos[nPosStride * pInds[i + 2]]);
  675.                                 Vec3 vBoxMin = v0;
  676.                                 vBoxMin.CheckMin(v1);
  677.                                 vBoxMin.CheckMin(v2);
  678.                                 Vec3 vBoxMax = v0;
  679.                                 vBoxMax.CheckMax(v1);
  680.                                 vBoxMax.CheckMax(v2);
  681.  
  682.                                 if (Overlap::Sphere_AABB(sSphere, AABB(vBoxMin, vBoxMax)))
  683.                                         return true;
  684.                         }
  685.         }
  686.  
  687.         return false;
  688. }
  689.  
  690. //////////////////////////////////////////////////////////////////////////
  691. void CStatObj::Invalidate(bool bPhysics, float tolerance)
  692. {
  693.         if (m_pIndexedMesh)
  694.         {
  695.                 m_pIndexedMesh->CalcBBox();
  696.  
  697.                 m_AABB = m_pIndexedMesh->m_bbox;
  698.  
  699.                 MakeRenderMesh();
  700.                 m_nLoadedVertexCount = m_pIndexedMesh->GetVertexCount();
  701.                 m_nLoadedTrisCount = m_pIndexedMesh->GetFaceCount();
  702.                 if (!m_nLoadedTrisCount)
  703.                 {
  704.                         m_nLoadedTrisCount = m_pIndexedMesh->GetIndexCount() / 3;
  705.                 }
  706.                 CalcRadiuses();
  707.  
  708.                 if (bPhysics)
  709.                 {
  710.                         PhysicalizeGeomType(PHYS_GEOM_TYPE_DEFAULT, *m_pIndexedMesh->GetMesh(), tolerance, 0);
  711.                 }
  712.  
  713.                 ReleaseIndexedMesh(true);
  714.         }
  715.  
  716.         //////////////////////////////////////////////////////////////////////////
  717.         // Iterate through sub objects and update hide mask and sub obj mesh count.
  718.         //////////////////////////////////////////////////////////////////////////
  719.         m_nSubObjectMeshCount = 0;
  720.         for (size_t i = 0, numsub = m_subObjects.size(); i < numsub; i++)
  721.         {
  722.                 SSubObject& subObj = m_subObjects[i];
  723.                 if (subObj.pStatObj && subObj.nType == STATIC_SUB_OBJECT_MESH)
  724.                 {
  725.                         m_nSubObjectMeshCount++;
  726.                 }
  727.         }
  728.  
  729.         UnMergeSubObjectsRenderMeshes();
  730. }
  731.  
  732. //////////////////////////////////////////////////////////////////////////
  733. IStatObj* CStatObj::Clone(bool bCloneGeometry, bool bCloneChildren, bool bMeshesOnly)
  734. {
  735.         if (m_bDefaultObject)
  736.                 return this;
  737.  
  738.         CStatObj* pNewObj = new CStatObj;
  739.  
  740.         pNewObj->m_pClonedSourceObject = m_pClonedSourceObject ? m_pClonedSourceObject : this;
  741.         pNewObj->m_pClonedSourceObject->AddRef(); // Cloned object will keep a reference to this.
  742.  
  743.         pNewObj->m_nLoadedTrisCount = m_nLoadedTrisCount;
  744.         pNewObj->m_nLoadedVertexCount = m_nLoadedVertexCount;
  745.         pNewObj->m_nRenderTrisCount = m_nRenderTrisCount;
  746.  
  747.         if (bCloneGeometry)
  748.         {
  749.                 if (m_bMerged)
  750.                 {
  751.                         UnMergeSubObjectsRenderMeshes();
  752.                 }
  753.                 if (m_pIndexedMesh && !m_bMerged)
  754.                 {
  755.                         pNewObj->m_pIndexedMesh = new CIndexedMesh;
  756.                         pNewObj->m_pIndexedMesh->CopyFrom(*m_pIndexedMesh->GetMesh());
  757.                 }
  758.                 if (m_pRenderMesh && !m_bMerged)
  759.                 {
  760.                         _smart_ptr<IRenderMesh> pRenderMesh = GetRenderer()->CreateRenderMesh(
  761.                           "StatObj_Cloned",
  762.                           pNewObj->GetFilePath(),
  763.                           NULL,
  764.                           ((GetFlags() & STATIC_OBJECT_DYNAMIC) ? eRMT_Dynamic : eRMT_Static));
  765.  
  766.                         m_pRenderMesh->CopyTo(pRenderMesh);
  767.                         pNewObj->SetRenderMesh(pRenderMesh);
  768.                 }
  769.         }
  770.         else
  771.         {
  772.                 if (m_pRenderMesh)
  773.                         if (m_pMergedRenderMesh != m_pRenderMesh)
  774.                                 pNewObj->SetRenderMesh(m_pRenderMesh);
  775.                         else
  776.                                 pNewObj->m_pRenderMesh = m_pRenderMesh;
  777.                 pNewObj->m_pMergedRenderMesh = m_pMergedRenderMesh;
  778.                 pNewObj->m_bMerged = m_pMergedRenderMesh != NULL;
  779.         }
  780.  
  781.         pNewObj->m_szFileName = m_szFileName;
  782.         pNewObj->m_szGeomName = m_szGeomName;
  783.  
  784.         // Default material.
  785.         pNewObj->m_pMaterial = m_pMaterial;
  786.  
  787.         for (int i = 0; i < m_arrPhysGeomInfo.GetGeomCount(); i++)
  788.         {
  789.                 pNewObj->m_arrPhysGeomInfo.SetPhysGeom(m_arrPhysGeomInfo[i], i, m_arrPhysGeomInfo.GetGeomType(i));
  790.                 if (pNewObj->m_arrPhysGeomInfo[i])
  791.                         GetPhysicalWorld()->GetGeomManager()->AddRefGeometry(pNewObj->m_arrPhysGeomInfo[i]);
  792.         }
  793.         pNewObj->m_phys_mass = m_phys_mass;
  794.         pNewObj->m_phys_density = m_phys_density;
  795.         pNewObj->m_AABB = m_AABB;
  796.         pNewObj->m_vVegCenter = m_vVegCenter;
  797.  
  798.         pNewObj->m_fRadiusHors = m_fRadiusHors;
  799.         pNewObj->m_fRadiusVert = m_fRadiusVert;
  800.  
  801.         pNewObj->m_nFlags = m_nFlags | STATIC_OBJECT_CLONE;
  802.  
  803.         pNewObj->m_fGeometricMeanFaceArea = m_fGeometricMeanFaceArea;
  804.         pNewObj->m_fLodDistance = m_fLodDistance;
  805.         pNewObj->m_depthSortOffset = m_depthSortOffset;
  806.  
  807.         //////////////////////////////////////////////////////////////////////////
  808.         // Internal Flags.
  809.         //////////////////////////////////////////////////////////////////////////
  810.         pNewObj->m_bCanUnload = false;
  811.         pNewObj->m_bDefaultObject = m_bDefaultObject;
  812.         pNewObj->m_bOpenEdgesTested = m_bOpenEdgesTested;
  813.         pNewObj->m_bSubObject = false; // [anton] since parent is not copied anyway
  814.         pNewObj->m_bVehicleOnlyPhysics = m_bVehicleOnlyPhysics;
  815.         pNewObj->m_idmatBreakable = m_idmatBreakable;
  816.         pNewObj->m_bBreakableByGame = m_bBreakableByGame;
  817.         pNewObj->m_bHasDeformationMorphs = m_bHasDeformationMorphs;
  818.         pNewObj->m_bTmpIndexedMesh = m_bTmpIndexedMesh;
  819.         pNewObj->m_bHaveOcclusionProxy = m_bHaveOcclusionProxy;
  820.         pNewObj->m_bHasStreamOnlyCGF = m_bHasStreamOnlyCGF;
  821.         pNewObj->m_eStreamingStatus = m_eStreamingStatus;
  822.         //////////////////////////////////////////////////////////////////////////
  823.  
  824.         int numSubObj = (int)m_subObjects.size();
  825.         if (bMeshesOnly)
  826.         {
  827.                 numSubObj = 0;
  828.                 for (size_t i = 0; i < m_subObjects.size(); i++)
  829.                 {
  830.                         if (m_subObjects[i].nType == STATIC_SUB_OBJECT_MESH)
  831.                                 numSubObj++;
  832.                         else
  833.                                 break;
  834.                 }
  835.         }
  836.         pNewObj->m_subObjects.reserve(numSubObj);
  837.         for (int i = 0; i < numSubObj; i++)
  838.         {
  839.                 pNewObj->m_subObjects.push_back(m_subObjects[i]);
  840.                 pNewObj->m_subObjects[i].pFoliage = 0;
  841.                 if (m_subObjects[i].pStatObj)
  842.                 {
  843.                         if (bCloneChildren)
  844.                         {
  845.                                 pNewObj->m_subObjects[i].pStatObj = m_subObjects[i].pStatObj->Clone(bCloneGeometry, bCloneChildren, bMeshesOnly);
  846.                                 pNewObj->m_subObjects[i].pStatObj->AddRef();
  847.                                 ((CStatObj*)(pNewObj->m_subObjects[i].pStatObj))->m_pParentObject = this;
  848.                         }
  849.                         else
  850.                         {
  851.                                 m_subObjects[i].pStatObj->AddRef();
  852.                                 ((CStatObj*)(m_subObjects[i].pStatObj))->m_nFlags |= STATIC_OBJECT_MULTIPLE_PARENTS;
  853.                         }
  854.                 }
  855.         }
  856.         pNewObj->m_nSubObjectMeshCount = m_nSubObjectMeshCount;
  857.         if (!bCloneChildren)
  858.                 pNewObj->m_bSharesChildren = true;
  859.  
  860.         if (pNewObj->m_hasClothTangentsData = m_hasClothTangentsData)
  861.                 pNewObj->m_pClothTangentsData = m_pClothTangentsData;
  862.         if (pNewObj->m_hasSkinInfo = m_hasSkinInfo)
  863.                 pNewObj->m_pSkinInfo = m_pSkinInfo;
  864.  
  865.         return pNewObj;
  866. }
  867. //////////////////////////////////////////////////////////////////////////
  868.  
  869. IIndexedMesh* CStatObj::GetIndexedMesh(bool bCreateIfNone)
  870. {
  871.         WriteLock lock(m_lockIdxMesh);
  872.         if (m_pIndexedMesh)
  873.                 return m_pIndexedMesh;
  874.         else if (m_pRenderMesh && bCreateIfNone)
  875.         {
  876.  
  877.                 if (m_pRenderMesh->GetIndexedMesh(m_pIndexedMesh = new CIndexedMesh) == NULL)
  878.                 {
  879.                         // GetIndexMesh will free the IndexedMesh object if an allocation failed
  880.                         m_pIndexedMesh = NULL;
  881.                         return NULL;
  882.                 }
  883.  
  884.                 CMesh* pMesh = m_pIndexedMesh->GetMesh();
  885.                 if (!pMesh || pMesh->m_subsets.size() <= 0)
  886.                 {
  887.                         m_pIndexedMesh->Release();
  888.                         m_pIndexedMesh = 0;
  889.                         return 0;
  890.                 }
  891.                 m_bTmpIndexedMesh = true;
  892.  
  893.                 int i, j, i0 = pMesh->m_subsets[0].nFirstVertId + pMesh->m_subsets[0].nNumVerts;
  894.                 for (i = j = 1; i < pMesh->m_subsets.size(); i++)
  895.                         if (pMesh->m_subsets[i].nFirstVertId - i0 < pMesh->m_subsets[j].nFirstVertId - i0)
  896.                                 j = i;
  897.                 if (j < pMesh->m_subsets.size() && pMesh->m_subsets[0].nPhysicalizeType == PHYS_GEOM_TYPE_DEFAULT &&
  898.                     pMesh->m_subsets[j].nPhysicalizeType != PHYS_GEOM_TYPE_DEFAULT && pMesh->m_subsets[j].nFirstVertId > i0)
  899.                 {
  900.                         pMesh->m_subsets[j].nNumVerts += pMesh->m_subsets[j].nFirstVertId - i0;
  901.                         pMesh->m_subsets[j].nFirstVertId = i0;
  902.                 }
  903.                 return m_pIndexedMesh;
  904.         }
  905.         return 0;
  906. }
  907.  
  908. IIndexedMesh* CStatObj::CreateIndexedMesh()
  909. {
  910.         if (!m_pIndexedMesh)
  911.                 m_pIndexedMesh = new CIndexedMesh();
  912.  
  913.         return m_pIndexedMesh;
  914. }
  915.  
  916. void CStatObj::ReleaseIndexedMesh(bool bRenderMeshUpdated)
  917. {
  918.         WriteLock lock(m_lockIdxMesh);
  919.         if (m_bTmpIndexedMesh && m_pIndexedMesh)
  920.         {
  921.                 int istart, iend;
  922.                 CMesh* pMesh = m_pIndexedMesh->GetMesh();
  923.                 if (m_pRenderMesh && !bRenderMeshUpdated)
  924.                 {
  925.                         TRenderChunkArray& Chunks = m_pRenderMesh->GetChunks();
  926.                         for (int i = 0; i < pMesh->m_subsets.size(); i++)
  927.                                 Chunks[i].m_nMatFlags |= pMesh->m_subsets[i].nMatFlags & 1 << 30;
  928.                 }
  929.                 if (bRenderMeshUpdated && m_pBoneMapping)
  930.                 {
  931.                         for (int i = iend = 0; i < (int)pMesh->m_subsets.size(); i++)
  932.                                 if ((pMesh->m_subsets[i].nMatFlags & (MTL_FLAG_NOPHYSICALIZE | MTL_FLAG_NODRAW)) == MTL_FLAG_NOPHYSICALIZE)
  933.                                 {
  934.                                         for (istart = iend++; iend < (int)m_chunkBoneIds.size() && m_chunkBoneIds[iend]; iend++)
  935.                                                 ;
  936.                                         if (!pMesh->m_subsets[i].nNumIndices)
  937.                                         {
  938.                                                 m_chunkBoneIds.erase(m_chunkBoneIds.begin() + istart, m_chunkBoneIds.begin() + iend);
  939.                                                 iend = istart;
  940.                                         }
  941.                                 }
  942.                 }
  943.                 m_pIndexedMesh->Release();
  944.                 m_pIndexedMesh = 0;
  945.                 m_bTmpIndexedMesh = false;
  946.         }
  947. }
  948.  
  949. //////////////////////////////////////////////////////////////////////////
  950. static bool SubObjectsOfCompoundHaveLOD(const CStatObj* pStatObj, int nLod)
  951. {
  952.         int numSubObjects = pStatObj->GetSubObjectCount();
  953.         for (int i = 0; i < numSubObjects; ++i)
  954.         {
  955.                 const IStatObj::SSubObject* pSubObject = const_cast<CStatObj*>(pStatObj)->GetSubObject(i);
  956.                 if (!pSubObject)
  957.                         continue;
  958.                 const CStatObj* pChildObj = (const CStatObj*)pSubObject->pStatObj;
  959.                 if (!pChildObj)
  960.                         continue;
  961.                 if (!pChildObj->m_pLODs)
  962.                         continue;
  963.                 const CStatObj* pLod = pChildObj->m_pLODs[nLod];
  964.                 if (pLod)
  965.                         return true;
  966.         }
  967.         return false;
  968. }
  969.  
  970. //////////////////////////////////////////////////////////////////////////
  971. void CStatObj::TryMergeSubObjects(bool bFromStreaming)
  972. {
  973.         // sub meshes merging
  974.         if (GetCVars()->e_StatObjMerge)
  975.         {
  976.                 if (!m_bUnmergable && !IsDeformable())
  977.                 {
  978.                         MergeSubObjectsRenderMeshes(bFromStreaming, this, 0);
  979.  
  980.                         if (!bFromStreaming && !m_pLODs && m_nFlags & STATIC_OBJECT_COMPOUND)
  981.                         {
  982.                                 // Check if LODs were not split (production mode)
  983.                                 for (int i = 1; i < MAX_STATOBJ_LODS_NUM; ++i)
  984.                                 {
  985.                                         if (!SubObjectsOfCompoundHaveLOD(this, i))
  986.                                                 continue;
  987.  
  988.                                         CStatObj* pStatObj = new CStatObj();
  989.                                         pStatObj->m_szFileName = m_szFileName;
  990.                                         char lodName[32];
  991.                                         cry_strcpy(lodName, "-mlod");
  992.                                         ltoa(i, lodName + 5, 10);
  993.                                         pStatObj->m_szFileName.append(lodName);
  994.                                         pStatObj->m_szGeomName = m_szGeomName;
  995.                                         pStatObj->m_bSubObject = true;
  996.  
  997.                                         SetLodObject(i, pStatObj);
  998.                                         m_bMergedLODs = true;
  999.                                 }
  1000.                         }
  1001.  
  1002.                         if (m_pLODs)
  1003.                         {
  1004.                                 for (int i = 1; i < MAX_STATOBJ_LODS_NUM; i++)
  1005.                                 {
  1006.                                         if (m_pLODs[i])
  1007.                                         {
  1008.                                                 m_pLODs[i]->MergeSubObjectsRenderMeshes(bFromStreaming, this, i);
  1009.                                         }
  1010.                                 }
  1011.                         }
  1012.                 }
  1013.         }
  1014. }
  1015.  
  1016. //////////////////////////////////////////////////////////////////////////
  1017. void CStatObj::MergeSubObjectsRenderMeshes(bool bFromStreaming, CStatObj* pLod0, int nLod)
  1018. {
  1019.         if (m_bUnmergable)
  1020.                 return;
  1021.  
  1022.         MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Other, 0, "Merged StatObj");
  1023.         FUNCTION_PROFILER_3DENGINE;
  1024.  
  1025.         m_bMerged = false;
  1026.         m_pMergedRenderMesh = 0;
  1027.  
  1028.         int nSubObjCount = (int)pLod0->m_subObjects.size();
  1029.  
  1030.         std::vector<SRenderMeshInfoInput> lstRMI;
  1031.  
  1032.         SRenderMeshInfoInput rmi;
  1033.  
  1034.         rmi.pMat = m_pMaterial;
  1035.         rmi.mat.SetIdentity();
  1036.         rmi.pMesh = 0;
  1037.         rmi.pSrcRndNode = 0;
  1038.  
  1039.         for (int s = 0; s < nSubObjCount; s++)
  1040.         {
  1041.                 CStatObj::SSubObject* pSubObj = &pLod0->m_subObjects[s];
  1042.                 if (pSubObj->pStatObj && pSubObj->nType == STATIC_SUB_OBJECT_MESH)
  1043.                 {
  1044.                         CStatObj* pStatObj = (CStatObj*)pSubObj->pStatObj->GetLodObject(nLod, true); // Get lod, if not exist get lowest existing.
  1045.                         if (pStatObj)
  1046.                         {
  1047.                                 CryAutoCriticalSection lock(pStatObj->m_streamingMeshLock);
  1048.                                 if (pStatObj->m_pRenderMesh || pStatObj->m_pStreamedRenderMesh)
  1049.                                 {
  1050.                                         rmi.pMesh = pStatObj->m_pRenderMesh ? pStatObj->m_pRenderMesh : pStatObj->m_pStreamedRenderMesh;
  1051.                                         rmi.mat = pSubObj->tm;
  1052.                                         rmi.bIdentityMatrix = pSubObj->bIdentityMatrix;
  1053.                                         rmi.nSubObjectIndex = s;
  1054.                                         lstRMI.push_back(rmi);
  1055.                                 }
  1056.                         }
  1057.                 }
  1058.         }
  1059.  
  1060.         _smart_ptr<IRenderMesh> pMergedMesh = 0;
  1061.         if (lstRMI.size() == 1 && lstRMI[0].bIdentityMatrix)
  1062.         {
  1063.                 // If identity matrix and only mesh-subobject use it as a merged render mesh.
  1064.                 pMergedMesh = rmi.pMesh;
  1065.         }
  1066.         else if (!lstRMI.empty())
  1067.         {
  1068.                 SMergeInfo info;
  1069.                 info.sMeshName = GetFilePath();
  1070.                 info.sMeshType = "StatObj_Merged";
  1071.                 info.bMergeToOneRenderMesh = true;
  1072.                 info.pUseMaterial = m_pMaterial;
  1073.                 pMergedMesh = GetSharedRenderMeshMerger()->MergeRenderMeshes(&lstRMI[0], lstRMI.size(), info);
  1074.         }
  1075.  
  1076.         if (pMergedMesh)
  1077.         {
  1078.                 if (bFromStreaming)
  1079.                 {
  1080.                         CryAutoCriticalSection lock(m_streamingMeshLock);
  1081.                         m_pMergedRenderMesh = pMergedMesh;
  1082.                         m_pStreamedRenderMesh = pMergedMesh;
  1083.                 }
  1084.                 else
  1085.                 {
  1086.                         m_pMergedRenderMesh = pMergedMesh;
  1087.                         SetRenderMesh(pMergedMesh);
  1088.                 }
  1089.  
  1090.                 m_bMerged = true;
  1091.                 if (m_pLod0)
  1092.                 {
  1093.                         // Make sure upmost lod is also marked to be merged.
  1094.                         m_pLod0->m_bMerged = true;
  1095.                 }
  1096.         }
  1097. }
  1098.  
  1099. bool CStatObj::IsMatIDReferencedByObj(uint16 matID)
  1100. {
  1101.         //Check root obj
  1102.         if (IRenderMesh* pRenderMesh = GetRenderMesh())
  1103.         {
  1104.                 TRenderChunkArray& Chunks = pRenderMesh->GetChunks();
  1105.  
  1106.                 for (int nChunkId = 0; nChunkId < Chunks.size(); nChunkId++)
  1107.                 {
  1108.                         if (Chunks[nChunkId].m_nMatID == matID)
  1109.                         {
  1110.                                 return true;
  1111.                         }
  1112.                 }
  1113.         }
  1114.  
  1115.         //check children
  1116.         int nSubObjCount = (int)m_subObjects.size();
  1117.         for (int s = 0; s < nSubObjCount; s++)
  1118.         {
  1119.                 CStatObj::SSubObject* pSubObj = &m_subObjects[s];
  1120.  
  1121.                 if (pSubObj->pStatObj)
  1122.                 {
  1123.                         CStatObj* pSubStatObj = (CStatObj*)pSubObj->pStatObj;
  1124.  
  1125.                         if (IRenderMesh* pSubRenderMesh = pSubStatObj->GetRenderMesh())
  1126.                         {
  1127.                                 TRenderChunkArray& Chunks = pSubRenderMesh->GetChunks();
  1128.  
  1129.                                 for (int nChunkId = 0; nChunkId < Chunks.size(); nChunkId++)
  1130.                                 {
  1131.                                         if (Chunks[nChunkId].m_nMatID == matID)
  1132.                                         {
  1133.                                                 return true;
  1134.                                         }
  1135.                                 }
  1136.                         }
  1137.                 }
  1138.         }
  1139.  
  1140.         return false;
  1141. }
  1142.  
  1143. //////////////////////////////////////////////////////////////////////////
  1144. bool CStatObj::CanMergeSubObjects()
  1145. {
  1146.         if (gEnv->IsDedicated())
  1147.                 return false;
  1148.  
  1149.         int nSubMeshes = 0;
  1150.         int nTotalVertexCount = 0;
  1151.         int nTotalTriCount = 0;
  1152.         int nTotalRenderChunksCount = 0;
  1153.  
  1154.         int nSubObjCount = (int)m_subObjects.size();
  1155.         for (int s = 0; s < nSubObjCount; s++)
  1156.         {
  1157.                 CStatObj::SSubObject* pSubObj = &m_subObjects[s];
  1158.                 if (pSubObj->pStatObj && pSubObj->nType == STATIC_SUB_OBJECT_MESH && !pSubObj->bHidden)
  1159.                 {
  1160.                         CStatObj* pStatObj = (CStatObj*)pSubObj->pStatObj;
  1161.                         if (pStatObj->m_pMaterial != m_pMaterial || pStatObj->m_nSpines) // All materials must be same, and no bendable foliage
  1162.                         {
  1163.                                 return false;
  1164.                         }
  1165.                         nSubMeshes++;
  1166.                         nTotalVertexCount += pStatObj->m_nLoadedVertexCount;
  1167.                         nTotalTriCount += pStatObj->m_nLoadedTrisCount;
  1168.                         nTotalRenderChunksCount += pStatObj->m_nRenderMatIds;
  1169.                 }
  1170.         }
  1171.  
  1172.         // Check for mat_breakable surface type in material
  1173.         if (m_pMaterial)
  1174.         {
  1175.                 int nSubMtls = m_pMaterial->GetSubMtlCount();
  1176.                 if (nSubMtls > 0)
  1177.                 {
  1178.                         for (int i = 0; i < nSubMtls; ++i)
  1179.                         {
  1180.                                 IMaterial* pSubMtl = m_pMaterial->GetSafeSubMtl(i);
  1181.                                 if (pSubMtl)
  1182.                                 {
  1183.                                         ISurfaceType* pSFType = pSubMtl->GetSurfaceType();
  1184.  
  1185.                                         // This is breakable glass.
  1186.                                         // Do not merge meshes that have procedural physics breakability in them.
  1187.                                         if (pSFType && pSFType->GetBreakability() != 0)
  1188.                                         {
  1189.                                                 //if mesh is streamed, we must assume the material is referenced
  1190.                                                 if (m_bMeshStrippedCGF)
  1191.                                                 {
  1192.                                                         return false;
  1193.                                                 }
  1194.                                                 else if (IsMatIDReferencedByObj((uint16)i))
  1195.                                                 {
  1196.                                                         return false;
  1197.                                                 }
  1198.                                         }
  1199.                                 }
  1200.                         }
  1201.                 }
  1202.                 else // nSubMtls==0
  1203.                 {
  1204.                         ISurfaceType* pSFType = m_pMaterial->GetSurfaceType();
  1205.  
  1206.                         // This is breakable glass.
  1207.                         // Do not merge meshes that have procedural physics breakability in them.
  1208.                         if (pSFType && pSFType->GetBreakability() != 0)
  1209.                         {
  1210.                                 return false;
  1211.                         }
  1212.                 }
  1213.         }
  1214.  
  1215.         if (nTotalVertexCount > MAX_VERTICES_MERGABLE || nSubMeshes <= 1 || nTotalRenderChunksCount <= 1)
  1216.         {
  1217.                 return false;
  1218.         }
  1219.         if ((nTotalTriCount / nTotalRenderChunksCount) > GetCVars()->e_StatObjMergeMaxTrisPerDrawCall)
  1220.         {
  1221.                 return false; // tris to draw calls ratio is already not so bad
  1222.         }
  1223.         return true;
  1224. }
  1225.  
  1226. //////////////////////////////////////////////////////////////////////////
  1227. void CStatObj::UnMergeSubObjectsRenderMeshes()
  1228. {
  1229.         if (m_bMerged)
  1230.         {
  1231.                 m_bMerged = false;
  1232.                 m_pMergedRenderMesh = 0;
  1233.                 SetRenderMesh(0);
  1234.         }
  1235.         if (m_bMergedLODs)
  1236.         {
  1237.                 delete[] m_pLODs;
  1238.                 m_pLODs = 0;
  1239.         }
  1240. }
  1241.  
  1242. //------------------------------------------------------------------------------
  1243. // This function is recovered from previous FindSubObject function which was then
  1244. // changed and creating many CGA model issues (some joints never move).
  1245. CStatObj::SSubObject* CStatObj::FindSubObject_CGA(const char* sNodeName)
  1246. {
  1247.         uint32 numSubObjects = m_subObjects.size();
  1248.         for (uint32 i = 0; i < numSubObjects; i++)
  1249.         {
  1250.                 if (stricmp(m_subObjects[i].name.c_str(), sNodeName) == 0)
  1251.                 {
  1252.                         return &m_subObjects[i];
  1253.                 }
  1254.         }
  1255.         return 0;
  1256. }
  1257.  
  1258. //////////////////////////////////////////////////////////////////////////
  1259. CStatObj::SSubObject* CStatObj::FindSubObject(const char* sNodeName)
  1260. {
  1261.         uint32 numSubObjects = m_subObjects.size();
  1262.         int len = 1; // some objects has ' ' in the beginning
  1263.         for (; sNodeName[len] > ' ' && sNodeName[len] != ',' && sNodeName[len] != ';'; len++)
  1264.                 ;
  1265.         for (uint32 i = 0; i < numSubObjects; i++)
  1266.         {
  1267.                 if (strnicmp(m_subObjects[i].name.c_str(), sNodeName, len) == 0 && m_subObjects[i].name[len] == 0)
  1268.                 {
  1269.                         return &m_subObjects[i];
  1270.                 }
  1271.         }
  1272.         return 0;
  1273. }
  1274.  
  1275. //////////////////////////////////////////////////////////////////////////
  1276. CStatObj::SSubObject* CStatObj::FindSubObject_StrStr(const char* sNodeName)
  1277. {
  1278.         uint32 numSubObjects = m_subObjects.size();
  1279.         for (uint32 i = 0; i < numSubObjects; i++)
  1280.         {
  1281.                 if (stristr(m_subObjects[i].name.c_str(), sNodeName))
  1282.                 {
  1283.                         return &m_subObjects[i];
  1284.                 }
  1285.         }
  1286.         return 0;
  1287. }
  1288.  
  1289. //////////////////////////////////////////////////////////////////////////
  1290. IStatObj::SSubObject& CStatObj::AddSubObject(IStatObj* pSubObj)
  1291. {
  1292.         assert(pSubObj);
  1293.         SetSubObjectCount(m_subObjects.size() + 1);
  1294.         InitializeSubObject(m_subObjects[m_subObjects.size() - 1]);
  1295.         m_subObjects[m_subObjects.size() - 1].pStatObj = pSubObj;
  1296.         pSubObj->AddRef();
  1297.         return m_subObjects[m_subObjects.size() - 1];
  1298. }
  1299.  
  1300. //////////////////////////////////////////////////////////////////////////
  1301. bool CStatObj::RemoveSubObject(int nIndex)
  1302. {
  1303.         if (nIndex >= 0 && nIndex < (int)m_subObjects.size())
  1304.         {
  1305.                 SSubObject* pSubObj = &m_subObjects[nIndex];
  1306.                 CStatObj* pChildObj = (CStatObj*)pSubObj->pStatObj;
  1307.                 if (pChildObj)
  1308.                 {
  1309.                         if (!m_bSharesChildren)
  1310.                                 pChildObj->m_pParentObject = NULL;
  1311.                         pChildObj->Release();
  1312.                 }
  1313.                 m_subObjects.erase(m_subObjects.begin() + nIndex);
  1314.                 Invalidate(true);
  1315.                 return true;
  1316.         }
  1317.         return false;
  1318. }
  1319.  
  1320. //////////////////////////////////////////////////////////////////////////
  1321. void CStatObj::SetSubObjectCount(int nCount)
  1322. {
  1323.         // remove sub objects.
  1324.         while ((int)m_subObjects.size() > nCount)
  1325.         {
  1326.                 RemoveSubObject(m_subObjects.size() - 1);
  1327.         }
  1328.  
  1329.         SSubObject subobj;
  1330.         InitializeSubObject(subobj);
  1331.         m_subObjects.resize(nCount, subobj);
  1332.  
  1333.         if (nCount > 0)
  1334.         {
  1335.                 m_nFlags |= STATIC_OBJECT_COMPOUND;
  1336.         }
  1337.         else
  1338.         {
  1339.                 m_nFlags &= ~STATIC_OBJECT_COMPOUND;
  1340.         }
  1341.         Invalidate(true);
  1342.         UnMergeSubObjectsRenderMeshes();
  1343. }
  1344.  
  1345. //////////////////////////////////////////////////////////////////////////
  1346. bool CStatObj::CopySubObject(int nToIndex, IStatObj* pFromObj, int nFromIndex)
  1347. {
  1348.         SSubObject* pSrcSubObj = pFromObj->GetSubObject(nFromIndex);
  1349.         if (!pSrcSubObj)
  1350.                 return false;
  1351.  
  1352.         if (nToIndex >= (int)m_subObjects.size())
  1353.         {
  1354.                 SetSubObjectCount(nToIndex + 1);
  1355.                 if (pFromObj == this)
  1356.                         pSrcSubObj = pFromObj->GetSubObject(nFromIndex);
  1357.         }
  1358.  
  1359.         m_subObjects[nToIndex] = *pSrcSubObj;
  1360.         if (pSrcSubObj->pStatObj)
  1361.                 pSrcSubObj->pStatObj->AddRef();
  1362.         m_subObjects[nToIndex].pFoliage = 0;
  1363.  
  1364.         Invalidate(true);
  1365.  
  1366.         return true;
  1367. }
  1368.  
  1369. //////////////////////////////////////////////////////////////////////////
  1370. bool CStatObj::GetPhysicalProperties(float& mass, float& density)
  1371. {
  1372.         mass = m_phys_mass;
  1373.         density = m_phys_density;
  1374.         if (mass < 0 && density < 0)
  1375.                 return false;
  1376.         return true;
  1377. }
  1378.  
  1379. //////////////////////////////////////////////////////////////////////////
  1380. bool CStatObj::RayIntersection(SRayHitInfo& hitInfo, IMaterial* pCustomMtl)
  1381. {
  1382.         Vec3 vOut;
  1383.  
  1384.         bool bNonDirectionalTest = hitInfo.inRay.direction.IsZero();
  1385.  
  1386.         // First check if ray intersect objects bounding box.
  1387.         if (!bNonDirectionalTest && !Intersect::Ray_AABB(hitInfo.inRay, m_AABB, vOut))
  1388.                 return false;
  1389.  
  1390.         if (bNonDirectionalTest && !Overlap::AABB_AABB(
  1391.               AABB(hitInfo.inRay.origin - Vec3(hitInfo.fMaxHitDistance), hitInfo.inRay.origin + Vec3(hitInfo.fMaxHitDistance)),
  1392.               m_AABB))
  1393.                 return false;
  1394.  
  1395.         IRenderMesh* pRenderMesh = m_pRenderMesh;
  1396.  
  1397.         // Sometimes, object has no base lod mesh. So need to hit test with low level mesh.
  1398.         // If the distance from camera is larger then a base lod distance, then base lod mesh is not loaded yet.
  1399.         assert(m_nMaxUsableLod < MAX_STATOBJ_LODS_NUM && (m_nMaxUsableLod == 0 || (m_pLODs && m_pLODs[m_nMaxUsableLod])));
  1400.         if (!pRenderMesh && m_nMaxUsableLod > 0 && m_pLODs && m_pLODs[m_nMaxUsableLod])
  1401.                 pRenderMesh = m_pLODs[m_nMaxUsableLod]->GetRenderMesh();
  1402.  
  1403.         if ((m_nFlags & STATIC_OBJECT_COMPOUND) && !m_bMerged)
  1404.         {
  1405.                 SRayHitInfo hitOut;
  1406.                 bool bAnyHit = false;
  1407.                 float fMinDistance = FLT_MAX;
  1408.                 for (int i = 0, num = m_subObjects.size(); i < num; i++)
  1409.                 {
  1410.                         if (m_subObjects[i].pStatObj && m_subObjects[i].nType == STATIC_SUB_OBJECT_MESH && !m_subObjects[i].bHidden)
  1411.                         {
  1412.                                 if (((CStatObj*)(m_subObjects[i].pStatObj))->m_nFlags & STATIC_OBJECT_HIDDEN)
  1413.                                         continue;
  1414.  
  1415.                                 Matrix34 invertedTM = m_subObjects[i].tm.GetInverted();
  1416.  
  1417.                                 SRayHitInfo hit = hitInfo;
  1418.  
  1419.                                 // Transform ray into sub-object local space.
  1420.                                 hit.inReferencePoint = invertedTM.TransformPoint(hit.inReferencePoint);
  1421.                                 hit.inRay.origin = invertedTM.TransformPoint(hit.inRay.origin);
  1422.                                 hit.inRay.direction = invertedTM.TransformVector(hit.inRay.direction);
  1423.  
  1424.                                 int nFirstTriangleId = hit.pHitTris ? hit.pHitTris->Count() : 0;
  1425.  
  1426.                                 if (((CStatObj*)m_subObjects[i].pStatObj)->RayIntersection(hit, pCustomMtl))
  1427.                                 {
  1428.                                         if (hit.fDistance < fMinDistance)
  1429.                                         {
  1430.                                                 hitInfo.pStatObj = m_subObjects[i].pStatObj;
  1431.                                                 bAnyHit = true;
  1432.                                                 hitOut = hit;
  1433.                                         }
  1434.                                 }
  1435.  
  1436.                                 // transform collected triangles from sub-object space into object space
  1437.                                 if (hit.pHitTris)
  1438.                                 {
  1439.                                         for (int t = nFirstTriangleId; t < hit.pHitTris->Count(); t++)
  1440.                                         {
  1441.                                                 SRayHitTriangle& ht = hit.pHitTris->GetAt(t);
  1442.                                                 for (int c = 0; c < 3; c++)
  1443.                                                         ht.v[c] = m_subObjects[i].tm.TransformPoint(ht.v[c]);
  1444.                                         }
  1445.                                 }
  1446.                         }
  1447.                 }
  1448.                 if (bAnyHit)
  1449.                 {
  1450.                         // Restore input ray/reference point.
  1451.                         hitOut.inReferencePoint = hitInfo.inReferencePoint;
  1452.                         hitOut.inRay = hitInfo.inRay;
  1453.  
  1454.                         hitInfo = hitOut;
  1455.                         return true;
  1456.                 }
  1457.         }
  1458.         else
  1459.         {
  1460.                 if (pRenderMesh)
  1461.                 {
  1462.                         bool bRes = CRenderMeshUtils::RayIntersection(pRenderMesh, hitInfo, pCustomMtl);
  1463.                         if (bRes)
  1464.                         {
  1465.                                 hitInfo.pStatObj = this;
  1466.                                 hitInfo.pRenderMesh = pRenderMesh;
  1467.                         }
  1468.                         return bRes;
  1469.                 }
  1470.         }
  1471.         return false;
  1472. }
  1473.  
  1474. bool CStatObj::LineSegIntersection(const Lineseg& lineSeg, Vec3& hitPos, int& surfaceTypeId)
  1475. {
  1476.         bool intersects = false;
  1477.         if (m_pRenderMesh)
  1478.         {
  1479.                 m_pRenderMesh->LockForThreadAccess();
  1480.                 int numIndices = m_pRenderMesh->GetIndicesCount();
  1481.                 int numVertices = m_pRenderMesh->GetVerticesCount();
  1482.                 if (numIndices && numVertices)
  1483.                 {
  1484.                         int posStride;
  1485.                         uint8* pPositions = (uint8*)m_pRenderMesh->GetPosPtr(posStride, FSL_READ);
  1486.                         vtx_idx* pIndices = m_pRenderMesh->GetIndexPtr(FSL_READ);
  1487.  
  1488.                         TRenderChunkArray& Chunks = m_pRenderMesh->GetChunks();
  1489.                         int nChunkCount = Chunks.size();
  1490.                         for (int nChunkId = 0; nChunkId < nChunkCount; nChunkId++)
  1491.                         {
  1492.                                 CRenderChunk* pChunk = &Chunks[nChunkId];
  1493.                                 if (!(pChunk->m_nMatFlags & MTL_FLAG_NODRAW))
  1494.                                 {
  1495.                                         int lastIndex = pChunk->nFirstIndexId + pChunk->nNumIndices;
  1496.                                         for (int i = pChunk->nFirstIndexId; i < lastIndex; )
  1497.                                         {
  1498.                                                 const Vec3& v0 = *(Vec3*)(pPositions + pIndices[i++] * posStride);
  1499.                                                 const Vec3& v1 = *(Vec3*)(pPositions + pIndices[i++] * posStride);
  1500.                                                 const Vec3& v2 = *(Vec3*)(pPositions + pIndices[i++] * posStride);
  1501.  
  1502.                                                 if (Intersect::Lineseg_Triangle(lineSeg, v0, v2, v1, hitPos) || // Front face
  1503.                                                     Intersect::Lineseg_Triangle(lineSeg, v0, v1, v2, hitPos))   // Back face
  1504.                                                 {
  1505.                                                         IMaterial* pMtl = m_pMaterial->GetSafeSubMtl(pChunk->m_nMatID);
  1506.                                                         surfaceTypeId = pMtl->GetSurfaceTypeId();
  1507.                                                         intersects = true;
  1508.                                                         break;
  1509.                                                 }
  1510.                                         }
  1511.                                 }
  1512.                         }
  1513.                 }
  1514.                 m_pRenderMesh->UnlockStream(VSF_GENERAL);
  1515.                 m_pRenderMesh->UnlockIndexStream();
  1516.                 m_pRenderMesh->UnLockForThreadAccess();
  1517.         }
  1518.         return intersects;
  1519. }
  1520.  
  1521. void CStatObj::SetRenderMesh(IRenderMesh* pRM)
  1522. {
  1523.         LOADING_TIME_PROFILE_SECTION;
  1524.  
  1525.         if (pRM == m_pRenderMesh)
  1526.                 return;
  1527.  
  1528.         {
  1529.                 CryAutoCriticalSection lock(m_streamingMeshLock);
  1530.                 m_pRenderMesh = pRM;
  1531.  
  1532.                 IncrementModificationId();
  1533.         }
  1534.  
  1535.         if (m_pRenderMesh)
  1536.         {
  1537.                 m_nRenderTrisCount = 0;
  1538.                 m_nRenderMatIds = 0;
  1539.  
  1540.                 TRenderChunkArray& Chunks = m_pRenderMesh->GetChunks();
  1541.                 for (int nChunkId = 0; nChunkId < Chunks.size(); nChunkId++)
  1542.                 {
  1543.                         CRenderChunk* pChunk = &Chunks[nChunkId];
  1544.                         if (pChunk->m_nMatFlags & MTL_FLAG_NODRAW || !pChunk->pRE)
  1545.                                 continue;
  1546.  
  1547.                         if (pChunk->nNumIndices > 0)
  1548.                         {
  1549.                                 m_nRenderMatIds++;
  1550.                                 m_nRenderTrisCount += pChunk->nNumIndices / 3;
  1551.                         }
  1552.                 }
  1553.                 m_nLoadedTrisCount = pRM->GetIndicesCount() / 3;
  1554.                 m_nLoadedVertexCount = pRM->GetVerticesCount();
  1555.         }
  1556.  
  1557.         // this will prepare all deformable object during loading instead when needed.
  1558.         // Thus is will prevent runtime stalls (300ms when shooting a taxi with 6000 vertices)
  1559.         // but will incrase memory since every deformable information needs to be loaded(500kb for the taxi)
  1560.         // So this is more a workaround, the real solution would precompute the data in the RC and load
  1561.         // the data only when needed into memory
  1562.         if (GetCVars()->e_PrepareDeformableObjectsAtLoadTime && m_pRenderMesh && m_pDelayedSkinParams)
  1563.         {
  1564.                 PrepareSkinData(m_pDelayedSkinParams->mtxSkelToMesh, m_pDelayedSkinParams->pPhysSkel, m_pDelayedSkinParams->r);
  1565.         }
  1566. }
  1567.  
  1568. //////////////////////////////////////////////////////////////////////////
  1569. int CStatObj::CountChildReferences()
  1570. {
  1571.         // Check if it must be released.
  1572.         int nChildRefs = 0;
  1573.         int numChilds = (int)m_subObjects.size();
  1574.         for (int i = 0; i < numChilds; i++)
  1575.         {
  1576.                 IStatObj::SSubObject& so = m_subObjects[i];
  1577.                 CStatObj* pChildStatObj = (CStatObj*)so.pStatObj;
  1578.                 if (!pChildStatObj) // All stat objects must be at the begining of the array//
  1579.                         break;
  1580.  
  1581.                 // if I'm the real parent of this child, check that no-one else is referencing it, otherwise it doesn't matter if I get deleted
  1582.                 if (pChildStatObj->m_pParentObject == this)
  1583.                 {
  1584.                         bool bIgnoreSharedStatObj = false;
  1585.                         for (int k = 0; k < i; k++)
  1586.                         {
  1587.                                 if (pChildStatObj == m_subObjects[k].pStatObj)
  1588.                                 {
  1589.                                         // If we share pointer to this stat obj then do not count it again.
  1590.                                         bIgnoreSharedStatObj = true;
  1591.                                         nChildRefs -= 1; // 1 reference from current object should be ignored.
  1592.                                         break;
  1593.                                 }
  1594.                         }
  1595.                         if (!bIgnoreSharedStatObj)
  1596.                         {
  1597.                                 nChildRefs += pChildStatObj->m_nUsers - 1; // 1 reference from parent should be ignored.
  1598.                         }
  1599.                 }
  1600.         }
  1601.         assert(nChildRefs >= 0);
  1602.         return nChildRefs;
  1603. }
  1604.  
  1605. IStatObj* CStatObj::GetLowestLod()
  1606. {
  1607.         if (int nLowestLod = CStatObj::GetMinUsableLod())
  1608.                 return m_pLODs ? (CStatObj*)m_pLODs[CStatObj::GetMinUsableLod()] : (CStatObj*)NULL;
  1609.         return this;
  1610. }
  1611.  
  1612. //////////////////////////////////////////////////////////////////////////
  1613. int CStatObj::FindHighestLOD(int nBias)
  1614. {
  1615.         int nLowestLod = CStatObj::GetMinUsableLod();
  1616.  
  1617.         // if requested lod is not ready - find nearest ready one
  1618.         int nLod = CLAMP((int)m_nMaxUsableLod + nBias, nLowestLod, (int)m_nMaxUsableLod);
  1619.  
  1620.         while (nLod && nLod >= nLowestLod && (!m_pLODs || !m_pLODs[nLod] || !m_pLODs[nLod]->GetRenderMesh()))
  1621.                 nLod--;
  1622.  
  1623.         if (nLod == 0 && !GetRenderMesh())
  1624.                 nLod = -1;
  1625.  
  1626.         return nLod;
  1627. }
  1628.  
  1629. //////////////////////////////////////////////////////////////////////////
  1630. void CStatObj::GetStatisticsNonRecursive(SStatistics& si)
  1631. {
  1632.         CStatObj* pStatObj = this;
  1633.  
  1634.         for (int lod = 0; lod < MAX_STATOBJ_LODS_NUM; lod++)
  1635.         {
  1636.                 CStatObj* pLod = (CStatObj*)pStatObj->GetLodObject(lod);
  1637.                 if (pLod)
  1638.                 {
  1639.                         //if (!pLod0 && pLod->GetRenderMesh())
  1640.                         //pLod0 = pLod;
  1641.  
  1642.                         if (lod > 0 && lod + 1 > si.nLods) // Assign last existing lod.
  1643.                                 si.nLods = lod + 1;
  1644.  
  1645.                         si.nVerticesPerLod[lod] += pLod->m_nLoadedVertexCount;
  1646.                         si.nIndicesPerLod[lod] += pLod->m_nLoadedTrisCount * 3;
  1647.                         si.nMeshSize += pLod->m_nRenderMeshMemoryUsage;
  1648.  
  1649.                         IRenderMesh* pRenderMesh = pLod->GetRenderMesh();
  1650.                         if (pRenderMesh)
  1651.                         {
  1652.                                 si.nMeshSizeLoaded += pRenderMesh->GetMemoryUsage(0, IRenderMesh::MEM_USAGE_ONLY_STREAMS);
  1653.                                 //if (si.pTextureSizer)
  1654.                                 //pRenderMesh->GetTextureMemoryUsage(0,si.pTextureSizer);
  1655.                                 //if (si.pTextureSizer2)
  1656.                                 //pRenderMesh->GetTextureMemoryUsage(0,si.pTextureSizer2);
  1657.                         }
  1658.                 }
  1659.         }
  1660.  
  1661.         si.nIndices += m_nLoadedTrisCount * 3;
  1662.         si.nVertices += m_nLoadedVertexCount;
  1663.  
  1664.         for (int j = 0; j < pStatObj->m_arrPhysGeomInfo.GetGeomCount(); j++)
  1665.         {
  1666.                 if (pStatObj->GetPhysGeom(j))
  1667.                 {
  1668.                         ICrySizer* pPhysSizer = GetISystem()->CreateSizer();
  1669.                         pStatObj->GetPhysGeom(j)->pGeom->GetMemoryStatistics(pPhysSizer);
  1670.                         int sz = pPhysSizer->GetTotalSize();
  1671.                         si.nPhysProxySize += sz;
  1672.                         si.nPhysProxySizeMax = max(si.nPhysProxySizeMax, sz);
  1673.                         si.nPhysPrimitives += pStatObj->GetPhysGeom(j)->pGeom->GetPrimitiveCount();
  1674.                         pPhysSizer->Release();
  1675.                 }
  1676.         }
  1677. }
  1678.  
  1679. //////////////////////////////////////////////////////////////////////////
  1680. void CStatObj::GetStatistics(SStatistics& si)
  1681. {
  1682.         si.bSplitLods = m_bLodsAreLoadedFromSeparateFile;
  1683.  
  1684.         bool bMultiSubObj = (GetFlags() & STATIC_OBJECT_COMPOUND) != 0;
  1685.         if (!bMultiSubObj)
  1686.         {
  1687.                 GetStatisticsNonRecursive(si);
  1688.                 si.nSubMeshCount = 0;
  1689.                 si.nNumRefs = GetRefCount();
  1690.                 si.nDrawCalls = m_nRenderMatIds;
  1691.         }
  1692.         else
  1693.         {
  1694.                 si.nNumRefs = GetRefCount();
  1695.  
  1696.                 std::vector<void*> addedObjects;
  1697.                 for (int k = 0; k < GetSubObjectCount(); k++)
  1698.                 {
  1699.                         if (!GetSubObject(k))
  1700.                                 continue;
  1701.                         CStatObj* pSubObj = (CStatObj*)GetSubObject(k)->pStatObj;
  1702.  
  1703.                         int nSubObjectType = GetSubObject(k)->nType;
  1704.                         if (nSubObjectType != STATIC_SUB_OBJECT_MESH && nSubObjectType != STATIC_SUB_OBJECT_HELPER_MESH)
  1705.                                 continue;
  1706.  
  1707.                         if (stl::find(addedObjects, pSubObj))
  1708.                                 continue;
  1709.                         addedObjects.push_back(pSubObj);
  1710.  
  1711.                         if (pSubObj)
  1712.                         {
  1713.                                 pSubObj->GetStatisticsNonRecursive(si);
  1714.                                 si.nSubMeshCount++;
  1715.  
  1716.                                 if (nSubObjectType == STATIC_SUB_OBJECT_MESH)
  1717.                                 {
  1718.                                         si.nDrawCalls += pSubObj->m_nRenderMatIds;
  1719.                                 }
  1720.  
  1721.                                 if (pSubObj->GetRefCount() > si.nNumRefs)
  1722.                                         si.nNumRefs = pSubObj->GetRefCount();
  1723.                         }
  1724.                 }
  1725.         }
  1726.  
  1727.         // Only do rough estimation based on the material
  1728.         // This is more consistent when streaming is enabled and render mesh may no exist
  1729.         if (m_pMaterial)
  1730.         {
  1731.                 if (si.pTextureSizer)
  1732.                         m_pMaterial->GetTextureMemoryUsage(si.pTextureSizer);
  1733.                 if (si.pTextureSizer2)
  1734.                         m_pMaterial->GetTextureMemoryUsage(si.pTextureSizer2);
  1735.         }
  1736. }
  1737.  
downloadStatObjConstr.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top