BVB Source Codes

CRYENGINE Show StatObjLoad.cpp Source code

Return Download CRYENGINE: download StatObjLoad.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: loading
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15.  
  16. #include "StatObj.h"
  17. #include "IndexedMesh.h"
  18. #include "MatMan.h"
  19.  
  20. #include "CGF/CGFLoader.h"
  21. #include "CGF/CGFSaver.h"
  22. #include "CGF/ReadOnlyChunkFile.h"
  23.  
  24. #include <CryMemory/CryMemoryManager.h>
  25.  
  26. #define GEOM_INFO_FILE_EXT      "ginfo"
  27. #define MESH_NAME_FOR_MAIN      "main"
  28. #define PHYSICS_BREAKABLE_JOINT "$joint"
  29. #define PHYSICS_COMPILED_JOINTS "$compiled_joints"
  30.  
  31. void CStatObj::Refresh(int nFlags)
  32. {
  33.         if (nFlags & FRO_GEOMETRY)
  34.         {
  35.                 if (nFlags & FRO_FORCERELOAD)
  36.                 {
  37.                         m_bLodsLoaded = false;
  38.                 }
  39.  
  40.                 if (m_bCheckGarbage)
  41.                 {
  42.                         GetObjManager()->UnregisterForGarbage(this);
  43.                 }
  44.  
  45.                 const int oldModificationId = m_nModificationId;
  46.  
  47.                 ShutDown();
  48.                 Init();
  49.                 bool bRes = LoadCGF(m_szFileName, false, 0, 0, 0);
  50.  
  51.                 // Shutdown/Init sequence might produce same modification id as before, so we make sure to store a different value.
  52.                 m_nModificationId = oldModificationId + 1;
  53.  
  54.                 LoadLowLODs(false, 0);
  55.                 TryMergeSubObjects(false);
  56.  
  57.                 if (!bRes)
  58.                 {
  59.                         // load default in case of error
  60.                         ShutDown();
  61.                         Init();
  62.                         LoadCGF("objects/default.cgf", 0, 0, 0, 0);
  63.                         m_bDefaultObject = true;
  64.                 }
  65.  
  66.                 return;
  67.         }
  68. }
  69.  
  70. void CStatObj::LoadLowLODs(bool bUseStreaming, unsigned long nLoadingFlags)
  71. {
  72.         if (!LoadLowLODS_Prep(bUseStreaming, nLoadingFlags))
  73.                 return;
  74.  
  75.         int nLoadedLods = 1;
  76.         CStatObj* loadedLods[MAX_STATOBJ_LODS_NUM];
  77.         for (int nLodLevel = 0; nLodLevel < MAX_STATOBJ_LODS_NUM; nLodLevel++)
  78.                 loadedLods[nLodLevel] = 0;
  79.  
  80.         for (int nLodLevel = 1; nLodLevel < MAX_STATOBJ_LODS_NUM; nLodLevel++)
  81.         {
  82.                 CStatObj* pLodStatObj = LoadLowLODS_Load(nLodLevel, bUseStreaming, nLoadingFlags, NULL, 0);
  83.                 if (!pLodStatObj)
  84.                         break;
  85.                 nLoadedLods++;
  86.  
  87.                 loadedLods[nLodLevel] = pLodStatObj;
  88.         }
  89.  
  90.         LoadLowLODS_Finalize(nLoadedLods, loadedLods);
  91. }
  92.  
  93. bool CStatObj::LoadLowLODS_Prep(bool bUseStreaming, unsigned long nLoadingFlags)
  94. {
  95.         m_bLodsLoaded = true;
  96.  
  97.         if (nLoadingFlags & ELoadingFlagsIgnoreLoDs)
  98.         {
  99.                 return false;
  100.         }
  101.  
  102.         const char* sFileExt = PathUtil::GetExt(m_szFileName);
  103.  
  104.         if (m_nLoadedLodsNum > 1 && GetFlags() & STATIC_OBJECT_COMPOUND)
  105.         {
  106.                 for (int nLodLevel = 1; nLodLevel < MAX_STATOBJ_LODS_NUM; nLodLevel++)
  107.                 {
  108.                         // make lod file name
  109.                         char sLodFileName[512];
  110.                         char sLodNum[8];
  111.                         cry_strcpy(sLodFileName, m_szFileName);
  112.                         char* sPointSeparator = strchr(sLodFileName, '.');
  113.                         if (sPointSeparator)
  114.                                 *sPointSeparator = '\0'; // Terminate at the dot
  115.                         cry_strcat(sLodFileName, "_lod");
  116.                         ltoa(nLodLevel, sLodNum, 10);
  117.                         cry_strcat(sLodFileName, sLodNum);
  118.                         cry_strcat(sLodFileName, ".");
  119.                         cry_strcat(sLodFileName, sFileExt);
  120.  
  121.                         if (IsValidFile(sLodFileName))
  122.                         {
  123.                                 m_nLoadedLodsNum = 1;
  124.                                 break;
  125.                         }
  126.                 }
  127.         }
  128.  
  129.         if (m_nLoadedLodsNum > 1)
  130.                 return false;
  131.  
  132.         m_nLoadedLodsNum = 1;
  133.  
  134.         if (!GetCVars()->e_Lods)
  135.                 return false;
  136.  
  137.         if (m_bSubObject) // Never do this for sub objects.
  138.                 return false;
  139.  
  140.         return true;
  141. }
  142.  
  143. CStatObj* CStatObj::LoadLowLODS_Load(int nLodLevel, bool bUseStreaming, unsigned long nLoadingFlags, const void* pData, int nDataLen)
  144. {
  145.         const char* sFileExt = PathUtil::GetExt(m_szFileName);
  146.  
  147.         // make lod file name
  148.         char sLodFileName[512];
  149.         char sLodNum[8];
  150.         cry_strcpy(sLodFileName, m_szFileName);
  151.         char* sPointSeparator = strchr(sLodFileName, '.');
  152.         if (sPointSeparator)
  153.                 *sPointSeparator = '\0'; // Terminate at the dot
  154.         cry_strcat(sLodFileName, "_lod");
  155.         ltoa(nLodLevel, sLodNum, 10);
  156.         cry_strcat(sLodFileName, sLodNum);
  157.         cry_strcat(sLodFileName, ".");
  158.         cry_strcat(sLodFileName, sFileExt);
  159.  
  160.         CStatObj* pLodStatObj = m_pLODs ? (CStatObj*)m_pLODs[nLodLevel] : (CStatObj*)NULL;
  161.  
  162.         // try to load
  163.         bool bRes = false;
  164.  
  165.         pLodStatObj = stl::find_in_map(m_pObjManager->m_nameToObjectMap, CONST_TEMP_STRING(sLodFileName), NULL);
  166.  
  167.         if (pLodStatObj)
  168.         {
  169.                 pLodStatObj->m_pLod0 = this; // Must be here.
  170.                 bRes = true;
  171.  
  172.                 typedef std::set<CStatObj*> LoadedObjects;
  173.                 LoadedObjects::iterator it = m_pObjManager->m_lstLoadedObjects.find(pLodStatObj);
  174.                 if (it != m_pObjManager->m_lstLoadedObjects.end())
  175.                 {
  176.                         m_pObjManager->m_lstLoadedObjects.erase(it);
  177.                         m_pObjManager->m_nameToObjectMap.erase(CONST_TEMP_STRING(sLodFileName));
  178.                 }
  179.         }
  180.         else if (pData || IsValidFile(sLodFileName))
  181.         {
  182.                 if (!pLodStatObj)
  183.                 {
  184.                         pLodStatObj = new CStatObj();
  185.                         pLodStatObj->m_pLod0 = this; // Must be here.
  186.                 }
  187.  
  188.                 if (bUseStreaming && GetCVars()->e_StreamCgf)
  189.                         pLodStatObj->m_bCanUnload = true;
  190.  
  191.                 bRes = pLodStatObj->LoadCGF(sLodFileName, true, nLoadingFlags, pData, nDataLen);
  192.         }
  193.  
  194.         if (!bRes)
  195.         {
  196.                 if ((m_pLODs ? (CStatObj*)m_pLODs[nLodLevel] : (CStatObj*)NULL) != pLodStatObj)
  197.                 {
  198.                         SAFE_RELEASE(pLodStatObj);
  199.                 }
  200.                 SetLodObject(nLodLevel, 0);
  201.                 return NULL;
  202.         }
  203.  
  204.         bool bLodCompound = (pLodStatObj->GetFlags() & STATIC_OBJECT_COMPOUND) != 0;
  205.         bool bLod0Compund = (GetFlags() & STATIC_OBJECT_COMPOUND) != 0;
  206.  
  207.         SetLodObject(nLodLevel, pLodStatObj);
  208.  
  209.         if (bLodCompound != bLod0Compund)
  210.         {
  211.                 // LOD0 and LOD differ.
  212.                 FileWarning(0, sLodFileName, "Invalid LOD%d, LOD%d have different merging property from LOD0", nLodLevel, nLodLevel);
  213.         }
  214.  
  215.         return pLodStatObj;
  216. }
  217.  
  218. void CStatObj::LoadLowLODS_Finalize(int nLoadedLods, CStatObj* loadedLods[MAX_STATOBJ_LODS_NUM])
  219. {
  220.         //////////////////////////////////////////////////////////////////////////
  221.         // Put LODs into the sub objects.
  222.         //////////////////////////////////////////////////////////////////////////
  223.         if (nLoadedLods > 1)
  224.         {
  225.                 m_bLodsAreLoadedFromSeparateFile = true;
  226.  
  227.                 for (int i = 0; i < (int)m_subObjects.size(); i++)
  228.                 {
  229.                         SSubObject* pSubObject = &m_subObjects[i];
  230.                         if (!pSubObject->pStatObj || pSubObject->nType != STATIC_SUB_OBJECT_MESH)
  231.                                 continue;
  232.  
  233.                         CStatObj* pSubStatObj = (CStatObj*)pSubObject->pStatObj;
  234.  
  235.                         //                      int nLoadedTrisCount = ((CStatObj*)pSubObject->pStatObj)->m_nLoadedTrisCount;
  236.  
  237.                         for (int nLodLevel = 1; nLodLevel < nLoadedLods; nLodLevel++)
  238.                         {
  239.                                 if (loadedLods[nLodLevel] != 0 && loadedLods[nLodLevel]->m_nSubObjectMeshCount > 0)
  240.                                 {
  241.                                         SSubObject* pLodSubObject = loadedLods[nLodLevel]->FindSubObject(pSubObject->name);
  242.                                         if (pLodSubObject && pLodSubObject->pStatObj && pLodSubObject->nType == STATIC_SUB_OBJECT_MESH)
  243.                                         {
  244.                                                 pSubStatObj->SetLodObject(nLodLevel, (CStatObj*)pLodSubObject->pStatObj);
  245.                                         }
  246.                                 }
  247.                         }
  248.                         if (pSubStatObj)
  249.                                 pSubStatObj->CleanUnusedLods();
  250.                 }
  251.         }
  252.  
  253.         CleanUnusedLods();
  254.  
  255.         for (int nLodLevel = 0; nLodLevel < MAX_STATOBJ_LODS_NUM; nLodLevel++)
  256.         {
  257.                 if (loadedLods[nLodLevel])
  258.                 {
  259.                         GetObjManager()->CheckForGarbage(loadedLods[nLodLevel]);
  260.                 }
  261.         }
  262. }
  263.  
  264. //////////////////////////////////////////////////////////////////////////
  265. void CStatObj::CleanUnusedLods()
  266. {
  267.         //////////////////////////////////////////////////////////////////////////
  268.         // Free render resources for unused upper LODs.
  269.         //////////////////////////////////////////////////////////////////////////
  270.         if (m_nLoadedLodsNum > 1)
  271.         {
  272.                 int nMinLod = GetMinUsableLod();
  273.                 nMinLod = clamp_tpl(nMinLod, 0, (int)m_nLoadedLodsNum - 1);
  274.                 for (int i = 0; i < nMinLod; i++)
  275.                 {
  276.                         CStatObj* pStatObj = (CStatObj*)GetLodObject(i);
  277.                         if (!pStatObj)
  278.                                 continue;
  279.  
  280.                         if (pStatObj->m_pRenderMesh)
  281.                         {
  282.                                 pStatObj->SetRenderMesh(0);
  283.                         }
  284.                 }
  285.         }
  286.         //////////////////////////////////////////////////////////////////////////
  287. }
  288.  
  289. void TransformMesh(CMesh& mesh, Matrix34 tm)
  290. {
  291.         const int nVerts = mesh.GetVertexCount();
  292.         if (mesh.m_pPositions)
  293.         {
  294.                 for (int i = 0; i < nVerts; i++)
  295.                 {
  296.                         mesh.m_pPositions[i] = tm.TransformPoint(mesh.m_pPositions[i]);
  297.                 }
  298.         }
  299.         else if (mesh.m_pPositionsF16)
  300.         {
  301.                 for (int i = 0; i < nVerts; i++)
  302.                 {
  303.                         mesh.m_pPositionsF16[i] = tm.TransformPoint(mesh.m_pPositionsF16[i].ToVec3());
  304.                 }
  305.         }
  306. }
  307.  
  308. #if INCLUDE_MEMSTAT_CONTEXTS
  309. static string FindCGFSourceFilename(const char* filename)
  310. {
  311.         CChunkFile infoChunkFile;
  312.         if (!infoChunkFile.Read(filename))
  313.         {
  314.                 return string();
  315.         }
  316.  
  317.         for (int i = 0, n = infoChunkFile.NumChunks(); i < n; ++i)
  318.         {
  319.                 const IChunkFile::ChunkDesc* const pChunkDesc = infoChunkFile.GetChunk(i);
  320.                 if (pChunkDesc->chunkType == ChunkType_SourceInfo)
  321.                 {
  322.                         return (const char*)pChunkDesc->data;
  323.                 }
  324.         }
  325.  
  326.         return string();
  327. }
  328. #endif //INCLUDE_MEMSTAT_CONTEXTS
  329.  
  330. //////////////////////////////////////////////////////////////////////////
  331. bool CStatObj::LoadStreamRenderMeshes(const char* filename, const void* pData, const int nDataSize, bool bLod)
  332. {
  333.         MEMSTAT_CONTEXT_FMT(EMemStatContextTypes::MSC_CGF, EMemStatContextFlags::MSF_Instance, "%s", m_szFileName.c_str());
  334.         LOADING_TIME_PROFILE_SECTION;
  335.  
  336.         CLoaderCGF cgfLoader(util::pool_allocate, util::pool_free, GetCVars()->e_StatObjTessellationMode != 2 || bLod);
  337.         CStackContainer<CContentCGF> contentContainer(InplaceFactory(m_szFileName));
  338.         CContentCGF* pCGF = contentContainer.get();
  339.  
  340.         bool bMeshAssigned = false;
  341.  
  342.         //////////////////////////////////////////////////////////////////////////
  343.         // Load CGF.
  344.         //////////////////////////////////////////////////////////////////////////
  345.         class Listener : public ILoaderCGFListener
  346.         {
  347.         public:
  348.                 virtual void Warning(const char* format) {}
  349.                 virtual void Error(const char* format)   {}
  350.                 virtual bool IsValidationEnabled()       { return false; }
  351.         };
  352.  
  353.         bool bLoaded = false;
  354.         bool bLoadedChunks = false;
  355.  
  356.         Listener listener;
  357.         CReadOnlyChunkFile chunkFile(false, true);  // Chunk file must exist until CGF is completely loaded, and if loading from file do not make a copy of it.
  358.  
  359.         if (filename && filename[0])
  360.                 bLoadedChunks = chunkFile.Read(filename);
  361.         else
  362.                 bLoadedChunks = chunkFile.ReadFromMemory(pData, nDataSize);
  363.  
  364.         if (bLoadedChunks)
  365.                 bLoaded = cgfLoader.LoadCGF(contentContainer.get(), m_szFileName, chunkFile, &listener, 0);
  366.  
  367.         if (!bLoaded)
  368.         {
  369.                 FileWarning(0, m_szFileName, "CGF Streaming Failed: %s", cgfLoader.GetLastError());
  370.                 return false;
  371.         }
  372.  
  373.         //////////////////////////////////////////////////////////////////////////
  374.  
  375.         int nSubObjCount = (int)m_subObjects.size();
  376.  
  377.         bool bBreakNodeLoop = false;
  378.  
  379.         for (int i = 0; i < pCGF->GetNodeCount() && !bBreakNodeLoop; i++)
  380.         {
  381.                 CNodeCGF* pNode = pCGF->GetNode(i);
  382.                 if (!pNode->pMesh)
  383.                         continue;
  384.  
  385.                 bool bNodeIsValidMesh = (pNode->type == CNodeCGF::NODE_MESH || (pNode->type == CNodeCGF::NODE_HELPER && pNode->helperType == HP_GEOMETRY));
  386.                 if (!bNodeIsValidMesh)
  387.                         continue;
  388.  
  389.                 CStatObj* pStatObj = 0;
  390.                 for (int s = 0; s < nSubObjCount && !pStatObj; s++)
  391.                 {
  392.                         CStatObj* pSubStatObj = (CStatObj*)m_subObjects[s].pStatObj;
  393.                         if (!pSubStatObj)
  394.                                 continue;
  395.                         for (int nLod = 0; nLod < MAX_STATOBJ_LODS_NUM; nLod++)
  396.                         {
  397.                                 CStatObj* pSubLod = (CStatObj*)pSubStatObj->GetLodObject(nLod);
  398.                                 if (!pSubLod)
  399.                                         continue;
  400.                                 if (0 == strcmp(pSubLod->m_cgfNodeName.c_str(), pNode->name))
  401.                                 {
  402.                                         pStatObj = pSubLod;
  403.                                         break;
  404.                                 }
  405.                         }
  406.                 }
  407.  
  408.                 if (!pStatObj && m_nSubObjectMeshCount <= 1)
  409.                 {
  410.                         // If we do not have sub objects, assign the root StatObj to be used, and then not check anymore other nodes.
  411.                         for (int nLod = 0; nLod < MAX_STATOBJ_LODS_NUM && !pStatObj; nLod++)
  412.                         {
  413.                                 CStatObj* pLod = (CStatObj*)GetLodObject(nLod);
  414.                                 if (!pLod)
  415.                                         continue;
  416.                                 if (0 == strcmp(pLod->m_cgfNodeName.c_str(), pNode->name))
  417.                                 {
  418.                                         pStatObj = pLod;
  419.                                         break;
  420.                                 }
  421.                         }
  422.                 }
  423.                 if (pStatObj)
  424.                 {
  425.                         // add mesh to sync setup queue
  426.                         pStatObj->m_pStreamedRenderMesh = pStatObj->MakeRenderMesh(pNode->pMesh, true);
  427.                         if (pStatObj->m_pStreamedRenderMesh)
  428.                         {
  429.                                 bMeshAssigned = true;
  430.  
  431.                                 //////////////////////////////////////////////////////////////////////////
  432.                                 // FIXME: Qtangents not generated for foliage in RC, we must do that here.
  433.                                 //////////////////////////////////////////////////////////////////////////
  434.                                 if (pStatObj->m_nSpines && pStatObj->m_pSpines) // foliage
  435.                                         pStatObj->m_pStreamedRenderMesh->GenerateQTangents();
  436.                         }
  437.                 }
  438.         }
  439.         if (!bMeshAssigned)
  440.         {
  441.                 Warning("RenderMesh not assigned %s", m_szFileName.c_str());
  442.         }
  443.  
  444.         //////////////////////////////////////////////////////////////////////////
  445.         // Merge sub-objects for the new lod.
  446.         if (GetCVars()->e_StatObjMerge)
  447.         {
  448.                 CStatObj* pLod0 = (m_pLod0 != 0) ? (CStatObj*)m_pLod0 : this;
  449.                 pLod0->TryMergeSubObjects(true);
  450.         }
  451.         //////////////////////////////////////////////////////////////////////////
  452.  
  453.         return true;
  454. }
  455.  
  456. //////////////////////////////////////////////////////////////////////////
  457. void CStatObj::CommitStreamRenderMeshes()
  458. {
  459.         if (m_pStreamedRenderMesh)
  460.         {
  461.                 CryAutoCriticalSection lock(m_streamingMeshLock);
  462.                 SetRenderMesh(m_pStreamedRenderMesh);
  463.                 m_pStreamedRenderMesh = 0;
  464.         }
  465.         if (m_pLODs)
  466.         {
  467.                 for (int nLod = 0; nLod < MAX_STATOBJ_LODS_NUM; nLod++)
  468.                 {
  469.                         CStatObj* pLodObj = m_pLODs[nLod];
  470.                         if (pLodObj && pLodObj->m_pStreamedRenderMesh)
  471.                         {
  472.                                 CryAutoCriticalSection lock(pLodObj->m_streamingMeshLock);
  473.  
  474.                                 pLodObj->SetRenderMesh(pLodObj->m_pStreamedRenderMesh);
  475.                                 pLodObj->m_pStreamedRenderMesh = 0;
  476.                         }
  477.                 }
  478.         }
  479.  
  480.         for (size_t i = 0, num = m_subObjects.size(); i < num; ++i)
  481.         {
  482.                 CStatObj* pSubObj = (CStatObj*)m_subObjects[i].pStatObj;
  483.                 if (pSubObj)
  484.                 {
  485.                         pSubObj->CommitStreamRenderMeshes();
  486.                 }
  487.         }
  488. }
  489.  
  490. bool CStatObj::IsDeformable()
  491. {
  492.         if (Cry3DEngineBase::GetCVars()->e_MergedMeshes == 0)
  493.                 return false;
  494.  
  495.         // Create deformable subobject is present
  496.         if (m_isDeformable)
  497.         {
  498.                 return true;
  499.         }
  500.         else
  501.                 for (int i = 0, n = GetSubObjectCount(); i < n; ++i)
  502.                 {
  503.                         IStatObj::SSubObject* subObject = GetSubObject(i);
  504.                         if (!subObject)
  505.                                 continue;
  506.                         if (CStatObj* pChild = static_cast<CStatObj*>(GetSubObject(i)->pStatObj))
  507.                         {
  508.                                 if (pChild->m_isDeformable)
  509.                                         return true;
  510.                         }
  511.                 }
  512.  
  513.         return false;
  514. }
  515.  
  516. //////////////////////////////////////////////////////////////////////////
  517. bool CStatObj::LoadCGF(const char* filename, bool bLod, unsigned long nLoadingFlags, const void* pData, const int nDataSize)
  518. {
  519.         FUNCTION_PROFILER_3DENGINE;
  520.  
  521.         CRY_DEFINE_ASSET_SCOPE("CGF", filename);
  522.  
  523.         if (m_bSubObject) // Never execute this on the sub objects.
  524.                 return true;
  525.  
  526. #if INCLUDE_MEMSTAT_CONTEXTS
  527.         MEMSTAT_CONTEXT_FMT(EMemStatContextTypes::MSC_CGF, EMemStatContextFlags::MSF_Instance, "%s", filename);
  528. #endif
  529.  
  530.         PrintComment("Loading %s", filename);
  531.         if (!bLod)
  532.                 GetConsole()->TickProgressBar();
  533.  
  534.         m_nRenderTrisCount = m_nLoadedTrisCount = 0;
  535.         m_nLoadedVertexCount = 0;
  536.         m_szFileName = filename;
  537.         m_szFileName.replace('\\', '/');
  538.  
  539.         // Determine if stream only cgf is available
  540.         stack_string streamPath;
  541.         GetStreamFilePath(streamPath);
  542.         m_bHasStreamOnlyCGF = gEnv->pCryPak->IsFileExist(streamPath.c_str());
  543.  
  544.         if (!m_bCanUnload)
  545.         {
  546.                 if (m_bHasStreamOnlyCGF)
  547.                 {
  548.                         if (!LoadCGF_Int(filename, bLod, nLoadingFlags, pData, nDataSize))
  549.                                 return false;
  550.                         return LoadStreamRenderMeshes(streamPath.c_str(), 0, 0, bLod);
  551.                 }
  552.         }
  553.  
  554.         return LoadCGF_Int(filename, bLod, nLoadingFlags, pData, nDataSize);
  555. }
  556.  
  557. //////////////////////////////////////////////////////////////////////////
  558. static _smart_ptr<IMaterial> LoadCGFMaterial(CMatMan* pMatMan, const char* szMaterialName, const char* szCgfFilename, unsigned long nLoadingFlags)
  559. {
  560.         _smart_ptr<IMaterial> pMaterial = pMatMan->LoadCGFMaterial(szMaterialName, szCgfFilename, nLoadingFlags);
  561.         if (pMaterial->IsDefault())
  562.         {
  563.                 // If the material file is not found then let's try to use material file
  564.                 // with the name that is the same as the name of the .cgf file.
  565.                 const string cgfBasedMaterialName = PathUtil::GetFileName(szCgfFilename);
  566.                 pMaterial = pMatMan->LoadCGFMaterial(cgfBasedMaterialName.c_str(), szCgfFilename, nLoadingFlags);
  567.                 if (pMaterial->IsDefault())
  568.                 {
  569.                         pMatMan->FileWarning(0, szCgfFilename, "CGF is unable to load its material, see XML reader error above for material info.");
  570.                 }
  571.                 else
  572.                 {
  573.                         CryLog("Loaded material \"%s\" instead of missing \"%s\" (file \"%s\")", cgfBasedMaterialName.c_str(), szMaterialName, szCgfFilename);
  574.                 }
  575.         }
  576.  
  577. #if defined(FEATURE_SVO_GI)
  578.         if ((Cry3DEngineBase::GetCVars()->e_svoTI_Active >= 0) && (gEnv->IsEditor() || Cry3DEngineBase::GetCVars()->e_svoTI_Apply))
  579.                 pMaterial->SetKeepLowResSysCopyForDiffTex();
  580. #endif
  581.  
  582.         return pMaterial;
  583. }
  584.  
  585. bool CStatObj::LoadCGF_Int(const char* filename, bool bLod, unsigned long nLoadingFlags, const void* pData, const int nDataSize)
  586. {
  587.         CLoaderCGF cgfLoader(util::pool_allocate, util::pool_free, GetCVars()->e_StatObjTessellationMode != 2 || bLod);
  588.         CStackContainer<CContentCGF> contentContainer(InplaceFactory(filename));
  589.         CContentCGF* pCGF = contentContainer.get();
  590.  
  591.         //////////////////////////////////////////////////////////////////////////
  592.         // Load CGF.
  593.         //////////////////////////////////////////////////////////////////////////
  594.         class Listener : public ILoaderCGFListener
  595.         {
  596.         public:
  597.                 virtual void Warning(const char* format) { Cry3DEngineBase::Warning("%s", format); }
  598.                 virtual void Error(const char* format)   { Cry3DEngineBase::Error("%s", format); }
  599.                 virtual bool IsValidationEnabled()       { return Cry3DEngineBase::GetCVars()->e_StatObjValidate != 0; }
  600.         };
  601.  
  602. #if !defined(_RELEASE)
  603.         if (GetCVars()->e_CGFMaxFileSize >= 0 && !stristr(filename, DEFAULT_CGF_NAME))
  604.         {
  605.                 size_t fileSize = gEnv->pCryPak->FGetSize(filename, true);
  606.                 if (fileSize > (size_t)GetCVars()->e_CGFMaxFileSize << 10)
  607.                 {
  608.                         FileWarning(0, filename, "CGF Loading Failed: file '%s' (size %3.3f kb) exceeds size limit (max %3.3f kb)",
  609.                                     filename, fileSize / 1024.f, (GetCVars()->e_CGFMaxFileSize << 10) / 1024.f);
  610.                         return false;
  611.                 }
  612.         }
  613. #endif
  614.  
  615.         Listener listener;
  616.         CReadOnlyChunkFile chunkFile(false, bLod);  // Chunk file must exist until CGF is completely loaded, and if loading from file do not make a copy of it.
  617.  
  618.         bool bLoaded = false;
  619.         if (nDataSize)
  620.         {
  621.                 if (chunkFile.ReadFromMemory(pData, nDataSize))
  622.                         bLoaded = cgfLoader.LoadCGF(contentContainer.get(), filename, chunkFile, &listener, nLoadingFlags);
  623.         }
  624.         else
  625.         {
  626.                 bLoaded = cgfLoader.LoadCGF(contentContainer.get(), filename, chunkFile, &listener, nLoadingFlags);
  627.         }
  628.         if (!bLoaded)
  629.         {
  630.                 FileWarning(0, filename, "CGF Loading Failed: %s", cgfLoader.GetLastError());
  631.                 return false;
  632.         }
  633.         //////////////////////////////////////////////////////////////////////////
  634.  
  635.         INDENT_LOG_DURING_SCOPE(true, "While loading static object geometry '%s'", filename);
  636.  
  637.         CExportInfoCGF* pExportInfo = pCGF->GetExportInfo();
  638.         CNodeCGF* pFirstMeshNode = NULL;
  639.         CMesh* pFirstMesh = NULL;
  640.         m_nSubObjectMeshCount = 0;
  641.  
  642.         if (!pExportInfo->bCompiledCGF)
  643.         {
  644.                 FileWarning(0, m_szFileName, "CGF is not compiled, use RC");
  645.                 return false;
  646.         }
  647.  
  648.         m_bMeshStrippedCGF = pExportInfo->bNoMesh;
  649.  
  650.         bool bHasJoints = false;
  651.         if (nLoadingFlags & ELoadingFlagsForceBreakable)
  652.                 m_nFlags |= STATIC_OBJECT_DYNAMIC;
  653.  
  654.         m_nNodeCount = pCGF->GetNodeCount();
  655.  
  656.         //////////////////////////////////////////////////////////////////////////
  657.         // Find out number of meshes, and get pointer to the first found mesh.
  658.         //////////////////////////////////////////////////////////////////////////
  659.         for (int i = 0; i < pCGF->GetNodeCount(); i++)
  660.         {
  661.                 CNodeCGF* pNode = pCGF->GetNode(i);
  662.                 if (pNode->type == CNodeCGF::NODE_MESH)
  663.                 {
  664.                         if (m_szProperties.empty())
  665.                         {
  666.                                 m_szProperties = pNode->properties; // Take properties from the first mesh node.
  667.                                 m_szProperties.MakeLower();
  668.                         }
  669.                         m_nSubObjectMeshCount++;
  670.                         if (!pFirstMeshNode)
  671.                         {
  672.                                 pFirstMeshNode = pNode;
  673.                                 pFirstMesh = pNode->pMesh;
  674.                         }
  675.                 }
  676.                 else if (!strncmp(pNode->name, PHYSICS_BREAKABLE_JOINT, strlen(PHYSICS_BREAKABLE_JOINT)) || !strcmp(pNode->name, PHYSICS_COMPILED_JOINTS))
  677.                         bHasJoints = true;
  678.         }
  679.  
  680.         bool bIsLod0Merged = false;
  681.         if (bLod && m_pLod0)
  682.         {
  683.                 // This is a log object, check if parent was merged or not.
  684.                 bIsLod0Merged = m_pLod0->m_nSubObjectMeshCount == 0;
  685.         }
  686.  
  687.         if (pExportInfo->bMergeAllNodes || (m_nSubObjectMeshCount <= 1 && !bHasJoints && (!bLod || bIsLod0Merged)))
  688.         {
  689.                 // If we merging all nodes, ignore sub object meshes.
  690.                 m_nSubObjectMeshCount = 0;
  691.  
  692.                 if (pCGF->GetCommonMaterial())
  693.                 {
  694.                         if (nLoadingFlags & ELoadingFlagsPreviewMode)
  695.                         {
  696.                                 m_pMaterial = GetMatMan()->GetDefaultMaterial();
  697.                                 m_pMaterial->AddRef();
  698.                         }
  699.                         else
  700.                         {
  701.                                 m_pMaterial = ::LoadCGFMaterial(GetMatMan(), pCGF->GetCommonMaterial()->name, m_szFileName.c_str(), nLoadingFlags);
  702.                         }
  703.                 }
  704.         }
  705.  
  706.         // Fail if mesh was not complied by RC
  707.         if (pFirstMesh && pFirstMesh->GetFaceCount() > 0)
  708.         {
  709.                 FileWarning(0, filename, "CGF is not compiled");
  710.                 return false;
  711.         }
  712.  
  713.         if (GetCVars()->e_StatObjValidate)
  714.         {
  715.                 const char* pErrorDescription = 0;
  716.                 if (pFirstMesh && (!pFirstMesh->Validate(&pErrorDescription)))
  717.                 {
  718.                         FileWarning(0, filename, "CGF has invalid merged mesh (%s)", pErrorDescription);
  719.                         assert(!"CGF has invalid merged mesh");
  720.                         return false;
  721.                 }
  722.                 if (!pCGF->ValidateMeshes(&pErrorDescription))
  723.                 {
  724.                         FileWarning(0, filename, "CGF has invalid meshes (%s)", pErrorDescription);
  725.                         assert(!"CGF has invalid meshes");
  726.                         return false;
  727.                 }
  728.         }
  729.  
  730.         // Common of all sub nodes bbox.
  731.         AABB commonBBox;
  732.         commonBBox.Reset();
  733.  
  734.         bool bHaveMeshNamedMain = false;
  735.         bool bHasBreakableJoints = false;
  736.         bool bHasCompiledJoints = false;
  737.         bool bRenderMeshLoaded = false; // even if streaming is disabled we may load now from stripped cgf so meshes will fail to load - in this case we will stream it later
  738.  
  739.         //////////////////////////////////////////////////////////////////////////
  740.         // Create StatObj from Mesh.
  741.         //////////////////////////////////////////////////////////////////////////
  742.  
  743.         _smart_ptr<IRenderMesh> pMainMesh;
  744.  
  745.         if (pExportInfo->bMergeAllNodes || m_nSubObjectMeshCount == 0)
  746.         {
  747.                 if (pFirstMeshNode)
  748.                 {
  749.                         m_AABB.min = pFirstMeshNode->meshInfo.bboxMin;
  750.                         m_AABB.max = pFirstMeshNode->meshInfo.bboxMax;
  751.                         m_fGeometricMeanFaceArea = pFirstMeshNode->meshInfo.fGeometricMean;
  752.                         commonBBox = m_AABB;
  753.                         m_nRenderTrisCount = m_nLoadedTrisCount = pFirstMeshNode->meshInfo.nIndices / 3;
  754.                         m_nLoadedVertexCount = pFirstMeshNode->meshInfo.nVerts;
  755.                         m_cgfNodeName = pFirstMeshNode->name;
  756.                         CalcRadiuses();
  757.  
  758.                         if (pFirstMesh)
  759.                         {
  760.                                 // Assign mesh to this static object.
  761.                                 _smart_ptr<IRenderMesh> pRenderMesh = MakeRenderMesh(pFirstMesh, !m_bCanUnload);
  762.                                 SetRenderMesh(pRenderMesh);
  763.                                 pMainMesh = m_pRenderMesh;
  764.                                 bRenderMeshLoaded |= (m_pRenderMesh != 0);
  765.                         }
  766.                         else
  767.                         {
  768.                                 // If mesh not known now try to estimate its memory usage.
  769.                                 m_nRenderMeshMemoryUsage = CMesh::ApproximateRenderMeshMemoryUsage(pFirstMeshNode->meshInfo.nVerts, pFirstMeshNode->meshInfo.nIndices);
  770.                                 CalcRadiuses();
  771.                         }
  772.  
  773.                         //////////////////////////////////////////////////////////////////////////
  774.                         // Physicalize merged geometry.
  775.                         //////////////////////////////////////////////////////////////////////////
  776.                         if (!bLod)
  777.                         {
  778.                                 PhysicalizeCompiled(pFirstMeshNode);
  779.                         }
  780.                 }
  781.         }
  782.         //////////////////////////////////////////////////////////////////////////
  783.  
  784.         scratch_vector<CNodeCGF*> nodes;
  785.         static const size_t lodNamePrefixLength = strlen(CGF_NODE_NAME_LOD_PREFIX);
  786.  
  787.         //////////////////////////////////////////////////////////////////////////
  788.         // Create SubObjects.
  789.         //////////////////////////////////////////////////////////////////////////
  790.         if (pCGF->GetNodeCount() > 1 || m_nSubObjectMeshCount > 0)
  791.         {
  792.                 nodes.reserve(pCGF->GetNodeCount());
  793.  
  794.                 scratch_vector<std::pair<CNodeCGF*, CStatObj*>> meshToObject;
  795.                 meshToObject.reserve(pCGF->GetNodeCount());
  796.  
  797.                 //////////////////////////////////////////////
  798.                 // Count required subobjects and reserve space
  799.                 //////////////////////////////////////////////
  800.                 size_t nSubObjects = 0;
  801.                 for (int ii = 0; ii < pCGF->GetNodeCount(); ii++)
  802.                 {
  803.                         CNodeCGF* pNode = pCGF->GetNode(ii);
  804.  
  805.                         if (pNode->bPhysicsProxy)
  806.                                 continue;
  807.  
  808.                         if (pNode->type == CNodeCGF::NODE_MESH)
  809.                         {
  810.                                 if (pExportInfo->bMergeAllNodes || m_nSubObjectMeshCount == 0) // Only add helpers, ignore meshes.
  811.                                         continue;
  812.                         }
  813.                         else if (pNode->type == CNodeCGF::NODE_HELPER)
  814.                         {
  815.                                 switch (pNode->helperType)
  816.                                 {
  817.                                 case HP_GEOMETRY:
  818.                                         {
  819.                                                 if (strnicmp(pNode->name, CGF_NODE_NAME_LOD_PREFIX, lodNamePrefixLength) == 0)
  820.                                                         continue;
  821.                                         }
  822.                                         break;
  823.                                 }
  824.                         }
  825.  
  826.                         ++nSubObjects;
  827.                 }
  828.                 m_subObjects.reserve(nSubObjects);
  829.                 //////////////////////////////////////////////
  830.  
  831.                 int nNumMeshes = 0;
  832.                 for (int ii = 0; ii < pCGF->GetNodeCount(); ii++)
  833.                 {
  834.                         CNodeCGF* pNode = pCGF->GetNode(ii);
  835.  
  836.                         if (pNode->bPhysicsProxy)
  837.                                 continue;
  838.  
  839.                         SSubObject subObject;
  840.                         subObject.pStatObj = 0;
  841.                         subObject.bIdentityMatrix = pNode->bIdentityMatrix;
  842.                         subObject.bHidden = false;
  843.                         subObject.tm = pNode->worldTM;
  844.                         subObject.localTM = pNode->localTM;
  845.                         subObject.name = pNode->name;
  846.                         subObject.properties = pNode->properties;
  847.                         subObject.nParent = -1;
  848.                         subObject.pWeights = 0;
  849.                         subObject.pFoliage = 0;
  850.                         subObject.helperSize.Set(0, 0, 0);
  851.  
  852.                         if (pNode->type == CNodeCGF::NODE_MESH)
  853.                         {
  854.                                 if (pExportInfo->bMergeAllNodes || m_nSubObjectMeshCount == 0) // Only add helpers, ignore meshes.
  855.                                         continue;
  856.  
  857.                                 nNumMeshes++;
  858.                                 subObject.nType = STATIC_SUB_OBJECT_MESH;
  859.  
  860.                                 if (stristr(pNode->name, "shadowproxy") != 0)
  861.                                         subObject.bShadowProxy = true;
  862.  
  863.                                 if (stricmp(pNode->name, MESH_NAME_FOR_MAIN) == 0)
  864.                                         bHaveMeshNamedMain = true;
  865.                         }
  866.                         else if (pNode->type == CNodeCGF::NODE_LIGHT)
  867.                                 subObject.nType = STATIC_SUB_OBJECT_LIGHT;
  868.                         else if (pNode->type == CNodeCGF::NODE_HELPER)
  869.                         {
  870.                                 if (!bHasBreakableJoints && !strncmp(pNode->name, PHYSICS_BREAKABLE_JOINT, strlen(PHYSICS_BREAKABLE_JOINT)))
  871.                                         bHasBreakableJoints = true;
  872.                                 if (!bHasCompiledJoints && !strcmp(pNode->name, PHYSICS_COMPILED_JOINTS))
  873.                                         bHasBreakableJoints = bHasCompiledJoints = true;
  874.  
  875.                                 switch (pNode->helperType)
  876.                                 {
  877.                                 case HP_POINT:
  878.                                         subObject.nType = STATIC_SUB_OBJECT_POINT;
  879.                                         break;
  880.                                 case HP_DUMMY:
  881.                                         subObject.nType = STATIC_SUB_OBJECT_DUMMY;
  882.                                         subObject.helperSize = (pNode->helperSize * 0.01f);
  883.                                         break;
  884.                                 case HP_XREF:
  885.                                         subObject.nType = STATIC_SUB_OBJECT_XREF;
  886.                                         break;
  887.                                 case HP_CAMERA:
  888.                                         subObject.nType = STATIC_SUB_OBJECT_CAMERA;
  889.                                         break;
  890.                                 case HP_GEOMETRY:
  891.                                         {
  892.                                                 subObject.nType = STATIC_SUB_OBJECT_HELPER_MESH;
  893.                                                 subObject.bHidden = true; // Helpers are not rendered.
  894.                                         }
  895.                                         break;
  896.                                 default:
  897.                                         assert(0); // unknown type.
  898.                                 }
  899.                         }
  900.  
  901.                         // Only when multiple meshes inside.
  902.                         // If only 1 mesh inside, Do not create a separate CStatObj for it.
  903.                         if ((m_nSubObjectMeshCount > 0 && pNode->type == CNodeCGF::NODE_MESH) ||
  904.                             (subObject.nType == STATIC_SUB_OBJECT_HELPER_MESH))
  905.                         {
  906.                                 if (pNode->pSharedMesh)
  907.                                 {
  908.                                         // Try to find already create StatObj for a shred mesh node
  909.                                         for (int k = 0, num = (int)meshToObject.size(); k < num; k++)
  910.                                         {
  911.                                                 if (pNode->pSharedMesh == meshToObject[k].first)
  912.                                                 {
  913.                                                         subObject.pStatObj = meshToObject[k].second;
  914.                                                         break;
  915.                                                 }
  916.                                         }
  917.                                 }
  918.  
  919.                                 if (!subObject.pStatObj)
  920.                                 {
  921.                                         // Create a StatObj from the CGF node.
  922.                                         subObject.pStatObj = MakeStatObjFromCgfNode(pCGF, pNode, bLod, nLoadingFlags, commonBBox);
  923.                                         if (pNode->pSharedMesh)
  924.                                                 meshToObject.push_back(std::make_pair(pNode->pSharedMesh, static_cast<CStatObj*>(subObject.pStatObj)));
  925.                                         else
  926.                                                 meshToObject.push_back(std::make_pair(pNode, static_cast<CStatObj*>(subObject.pStatObj)));
  927.                                         bRenderMeshLoaded |= (((CStatObj*)subObject.pStatObj)->m_pRenderMesh != 0);
  928.                                 }
  929.                         }
  930.  
  931.                         //////////////////////////////////////////////////////////////////////////
  932.                         // Check if helper object is a LOD
  933.                         //////////////////////////////////////////////////////////////////////////
  934.                         if ((subObject.nType == STATIC_SUB_OBJECT_HELPER_MESH) &&
  935.                             (strnicmp(pNode->name, CGF_NODE_NAME_LOD_PREFIX, lodNamePrefixLength) == 0))
  936.                         {
  937.                                 // Check if helper object is a LOD
  938.  
  939.                                 if (!subObject.pStatObj)
  940.                                 {
  941.                                         continue;
  942.                                 }
  943.  
  944.                                 CStatObj* pLodStatObj = (CStatObj*)subObject.pStatObj;
  945.                                 CStatObj* pStatObjParent = this;
  946.                                 if (!pExportInfo->bMergeAllNodes && m_nSubObjectMeshCount > 0 && pNode->pParent)
  947.                                 {
  948.                                         // We are attached to some object, find it.
  949.                                         for (int i = 0, num = nodes.size(); i < num; i++)
  950.                                         {
  951.                                                 if (nodes[i] == pNode->pParent)
  952.                                                 {
  953.                                                         pStatObjParent = (CStatObj*)m_subObjects[i].pStatObj;
  954.                                                         break;
  955.                                                 }
  956.                                         }
  957.                                 }
  958.                                 if (!pStatObjParent)
  959.                                 {
  960.                                         continue;
  961.                                 }
  962.  
  963.                                 const int nLodLevel = atoi(pNode->name + lodNamePrefixLength);
  964.                                 if ((nLodLevel >= 1) && (nLodLevel < MAX_STATOBJ_LODS_NUM))
  965.                                 {
  966.                                         if (!pStatObjParent->m_pLODs || !pStatObjParent->m_pLODs[nLodLevel])
  967.                                         {
  968.                                                 pStatObjParent->SetLodObject(nLodLevel, pLodStatObj);
  969.                                         }
  970.                                         else
  971.                                         {
  972.                                                 const char* existingGeoName = pStatObjParent->m_pLODs[nLodLevel]->GetGeoName();
  973.                                                 FileWarning(0, m_szFileName.c_str(), "Duplicated LOD helper %s (%s). Existing geometry name: %s", pNode->name, m_szFileName.c_str(), existingGeoName);
  974.                                         }
  975.                                 }
  976.  
  977.                                 continue;
  978.                         }
  979.                         //////////////////////////////////////////////////////////////////////////
  980.  
  981.                         if (subObject.pStatObj)
  982.                         {
  983.                                 subObject.pStatObj->AddRef();
  984.                         }
  985.  
  986.                         m_subObjects.push_back(subObject);
  987.                         nodes.push_back(pNode);
  988.                 }
  989.  
  990.                 // Delete not assigned stat objects.
  991.                 for (int k = 0, num = (int)meshToObject.size(); k < num; k++)
  992.                 {
  993.                         if (meshToObject[k].second->m_nUsers == 0)
  994.                         {
  995.                                 delete meshToObject[k].second;
  996.                         }
  997.                 }
  998.  
  999.                 // Assign SubObject parent pointers.
  1000.                 int nNumCgfNodes = (int)nodes.size();
  1001.                 if (nNumCgfNodes > 0)
  1002.                 {
  1003.                         CNodeCGF** pNodes = &nodes[0];
  1004.  
  1005.                         //////////////////////////////////////////////////////////////////////////
  1006.                         // Move meshes to beginning, Sort sub-objects so that meshes are first.
  1007.                         for (int i = 0; i < nNumCgfNodes; i++)
  1008.                         {
  1009.                                 if (pNodes[i]->type != CNodeCGF::NODE_MESH)
  1010.                                 {
  1011.                                         // check if any more meshes exist.
  1012.                                         if (i < nNumMeshes)
  1013.                                         {
  1014.                                                 // Try to find next mesh and place it here.
  1015.                                                 for (int j = i + 1; j < nNumCgfNodes; j++)
  1016.                                                 {
  1017.                                                         if (pNodes[j]->type == CNodeCGF::NODE_MESH)
  1018.                                                         {
  1019.                                                                 // Swap objects at j to i.
  1020.                                                                 std::swap(pNodes[i], pNodes[j]);
  1021.                                                                 std::swap(m_subObjects[i], m_subObjects[j]);
  1022.                                                                 break;
  1023.                                                         }
  1024.                                                 }
  1025.                                         }
  1026.                                 }
  1027.                         }
  1028.                         //////////////////////////////////////////////////////////////////////////
  1029.  
  1030.                         // Assign Parent nodes.
  1031.                         for (int i = 0; i < nNumCgfNodes; i++)
  1032.                         {
  1033.                                 CNodeCGF* pParentNode = pNodes[i]->pParent;
  1034.                                 if (pParentNode)
  1035.                                 {
  1036.                                         for (int j = 0; j < nNumCgfNodes; j++)
  1037.                                         {
  1038.                                                 if (pNodes[j] == pParentNode)
  1039.                                                 {
  1040.                                                         m_subObjects[i].nParent = j;
  1041.                                                         break;
  1042.                                                 }
  1043.                                         }
  1044.                                 }
  1045.                         }
  1046.  
  1047.                         //////////////////////////////////////////////////////////////////////////
  1048.                         // Handle Main/Remain meshes used for Destroyable Objects.
  1049.                         //////////////////////////////////////////////////////////////////////////
  1050.                         if (bHaveMeshNamedMain)
  1051.                         {
  1052.                                 // If have mesh named main, then mark all sub object hidden except the one called "Main".
  1053.                                 for (int i = 0, n = m_subObjects.size(); i < n; i++)
  1054.                                 {
  1055.                                         if (m_subObjects[i].nType == STATIC_SUB_OBJECT_MESH)
  1056.                                         {
  1057.                                                 if (stricmp(m_subObjects[i].name, MESH_NAME_FOR_MAIN) == 0)
  1058.                                                         m_subObjects[i].bHidden = false;
  1059.                                                 else
  1060.                                                         m_subObjects[i].bHidden = true;
  1061.                                         }
  1062.                                 }
  1063.                         }
  1064.                         //////////////////////////////////////////////////////////////////////////
  1065.                 }
  1066.         }
  1067.  
  1068.         if (m_nSubObjectMeshCount > 0)
  1069.         {
  1070.                 m_AABB = commonBBox;
  1071.                 CalcRadiuses();
  1072.         }
  1073.  
  1074.         //////////////////////////////////////////////////////////////////////////
  1075.         // Physicalize physics proxy nodes.
  1076.         //////////////////////////////////////////////////////////////////////////
  1077.         if (!bLod)
  1078.         {
  1079.                 for (int i = 0, numNodes = pCGF->GetNodeCount(); i < numNodes; i++)
  1080.                 {
  1081.                         CNodeCGF* pNode = pCGF->GetNode(i);
  1082.                         if (pNode->bPhysicsProxy)
  1083.                         {
  1084.                                 CStatObj* pStatObjParent = this;
  1085.                                 if (pNode->pParent)
  1086.                                         for (int j = nodes.size() - 1; j >= 0; j--)
  1087.                                                 if (nodes[j] == pNode->pParent && m_subObjects[j].pStatObj)
  1088.                                                 {
  1089.                                                         pStatObjParent = (CStatObj*)m_subObjects[j].pStatObj;
  1090.                                                         break;
  1091.                                                 }
  1092.                                 pStatObjParent->PhysicalizeCompiled(pNode, 1);
  1093.                         }
  1094.                 }
  1095.         }
  1096.  
  1097.         //////////////////////////////////////////////////////////////////////////
  1098.         // Analyze foliage info.
  1099.         //////////////////////////////////////////////////////////////////////////
  1100.         if (!bLod && (pExportInfo->bMergeAllNodes || m_nSubObjectMeshCount == 0))
  1101.         {
  1102.                 AnalyzeFoliage(pMainMesh, pCGF);
  1103.         }
  1104.         //////////////////////////////////////////////////////////////////////////
  1105.  
  1106.         for (int i = 0; i < pCGF->GetNodeCount(); i++)
  1107.                 if (strstr(pCGF->GetNode(i)->properties, "deformable"))
  1108.                         m_nFlags |= STATIC_OBJECT_DEFORMABLE;
  1109.  
  1110.         if (m_nSubObjectMeshCount > 0)
  1111.                 m_nFlags |= STATIC_OBJECT_COMPOUND;
  1112.         else
  1113.                 m_nFlags &= ~STATIC_OBJECT_COMPOUND;
  1114.  
  1115.         if (!bLod && !m_szProperties.empty())
  1116.         {
  1117.                 ParseProperties();
  1118.         }
  1119.  
  1120.         if (!bLod)
  1121.         {
  1122.                 CPhysicalizeInfoCGF* pPi = pCGF->GetPhysicalizeInfo();
  1123.                 if (pPi->nRetTets)
  1124.                 {
  1125.                         m_pLattice = GetPhysicalWorld()->GetGeomManager()->CreateTetrLattice(pPi->pRetVtx, pPi->nRetVtx, pPi->pRetTets, pPi->nRetTets);
  1126.                 }
  1127.         }
  1128.  
  1129.         if (m_bHasDeformationMorphs)
  1130.         {
  1131.                 int i, j;
  1132.                 for (i = GetSubObjectCount() - 1; i >= 0; i--)
  1133.                         if ((j = SubobjHasDeformMorph(i)) >= 0)
  1134.                                 GetSubObject(i)->pStatObj->SetDeformationMorphTarget(GetSubObject(j)->pStatObj);
  1135.                 m_bUnmergable = 1;
  1136.         }
  1137.  
  1138.         // Only objects with breakable physics joints can be merged.
  1139.         if (!bHasBreakableJoints)
  1140.         {
  1141.                 m_bUnmergable = true;
  1142.         }
  1143.  
  1144.         // sub meshes merging
  1145.         if (GetCVars()->e_StatObjMerge)
  1146.         {
  1147.                 if (!m_bUnmergable)
  1148.                 {
  1149.                         if (!CanMergeSubObjects())
  1150.                         {
  1151.                                 m_bUnmergable = true;
  1152.                         }
  1153.                 }
  1154.         }
  1155.  
  1156.         // Merging always produces 16 bit meshes, so disable for 32 bit meshes for now
  1157.         if (pFirstMesh && pFirstMesh->m_pPositions && !bHasCompiledJoints)
  1158.         {
  1159.                 m_bUnmergable = true;
  1160.         }
  1161.  
  1162.         if (!m_bCanUnload && bRenderMeshLoaded)
  1163.                 m_eStreamingStatus = ecss_Ready;
  1164.  
  1165.         const std::vector<CStatObj*> allObjects = GatherAllObjects();
  1166.         for (CStatObj* obj : allObjects)
  1167.         {
  1168.                 // Determine if the cgf is deformable
  1169.                 if (stristr(obj->m_szGeomName.c_str(), "bendable") && stristr(obj->m_szProperties.c_str(), "mergedmesh_deform"))
  1170.                 {
  1171.                         obj->m_isDeformable = 1;
  1172.                         obj->DisableStreaming();
  1173.                 }
  1174.  
  1175.                 // Read the depth sort offset
  1176.                 Vec3 depthSortOffset;
  1177.                 if (std::sscanf(obj->m_szProperties.c_str(), "depthoffset(x:%f,y:%f,z:%f)", &depthSortOffset.x, &depthSortOffset.y, &depthSortOffset.z) == 3)
  1178.                 {
  1179.                         obj->m_depthSortOffset = depthSortOffset;
  1180.                 }
  1181.         }
  1182.  
  1183.         // Recursive computation of m_fLODDistance for compound- and sub-objects
  1184.         ComputeAndStoreLodDistances();
  1185.  
  1186.         return true;
  1187. }
  1188.  
  1189. //////////////////////////////////////////////////////////////////////////
  1190. std::vector<CStatObj*> CStatObj::GatherAllObjects()
  1191. {
  1192.         const int subObjectsCount = GetSubObjectCount();
  1193.  
  1194.         std::vector<CStatObj*> allObjects;
  1195.         allObjects.reserve(subObjectsCount + 1);
  1196.  
  1197.         allObjects.push_back(this);
  1198.  
  1199.         for (int i = 0; i < subObjectsCount; ++i)
  1200.         {
  1201.                 IStatObj::SSubObject* subObject = GetSubObject(i);
  1202.                 if (subObject && subObject->pStatObj)
  1203.                 {
  1204.                         allObjects.push_back(static_cast<CStatObj*>(subObject->pStatObj));
  1205.                 }
  1206.         }
  1207.  
  1208.         return allObjects;
  1209. }
  1210.  
  1211. //////////////////////////////////////////////////////////////////////////
  1212. CStatObj* CStatObj::MakeStatObjFromCgfNode(CContentCGF* pCGF, CNodeCGF* pNode, bool bLod, int nLoadingFlags, AABB& commonBBox)
  1213. {
  1214.         CNodeCGF* pTMNode = pNode;
  1215.         if (pNode->pSharedMesh)
  1216.         {
  1217.                 pNode = pNode->pSharedMesh;
  1218.         }
  1219.  
  1220.         // Calc bbox.
  1221.         if (pNode->type == CNodeCGF::NODE_MESH)
  1222.         {
  1223.                 AABB box(pNode->meshInfo.bboxMin, pNode->meshInfo.bboxMax);
  1224.                 box.SetTransformedAABB(pTMNode->worldTM, box);
  1225.                 commonBBox.Add(box.min);
  1226.                 commonBBox.Add(box.max);
  1227.         }
  1228.  
  1229.         CStatObj* pStatObj = new CStatObj;
  1230.  
  1231.         pStatObj->m_szFileName = m_szFileName;
  1232.         pStatObj->m_szGeomName = pNode->name;
  1233.         pStatObj->m_bSubObject = true;
  1234.  
  1235.         if (pNode->type == CNodeCGF::NODE_MESH)
  1236.         {
  1237.                 pStatObj->m_pParentObject = this;
  1238.         }
  1239.  
  1240.         pStatObj->m_szProperties = pNode->properties;
  1241.         pStatObj->m_szProperties.MakeLower();
  1242.         if (!bLod && !pStatObj->m_szProperties.empty())
  1243.         {
  1244.                 pStatObj->ParseProperties();
  1245.         }
  1246.  
  1247.         if (pNode->pMaterial)
  1248.         {
  1249.                 if (nLoadingFlags & ELoadingFlagsPreviewMode)
  1250.                 {
  1251.                         pStatObj->m_pMaterial = GetMatMan()->GetDefaultMaterial();
  1252.                         pStatObj->m_pMaterial->AddRef();
  1253.                 }
  1254.                 else
  1255.                 {
  1256.                         pStatObj->m_pMaterial = ::LoadCGFMaterial(GetMatMan(), pNode->pMaterial->name, m_szFileName.c_str(), nLoadingFlags);
  1257.                 }
  1258.                 if (!m_pMaterial || m_pMaterial->IsDefault())
  1259.                         m_pMaterial = pStatObj->m_pMaterial; // take it as a general stat obj material.
  1260.         }
  1261.         if (!pStatObj->m_pMaterial)
  1262.                 pStatObj->m_pMaterial = m_pMaterial;
  1263.  
  1264.         pStatObj->m_AABB.min = pNode->meshInfo.bboxMin;
  1265.         pStatObj->m_AABB.max = pNode->meshInfo.bboxMax;
  1266.         pStatObj->m_nRenderMatIds = pNode->meshInfo.nSubsets;
  1267.         pStatObj->m_nRenderTrisCount = pStatObj->m_nLoadedTrisCount = pNode->meshInfo.nIndices / 3;
  1268.         pStatObj->m_nLoadedVertexCount = pNode->meshInfo.nVerts;
  1269.         pStatObj->m_fGeometricMeanFaceArea = pNode->meshInfo.fGeometricMean;
  1270.         pStatObj->CalcRadiuses();
  1271.  
  1272.         if (nLoadingFlags & ELoadingFlagsForceBreakable)
  1273.                 pStatObj->m_nFlags |= STATIC_OBJECT_DYNAMIC;
  1274.  
  1275.         if (pNode->pMesh)
  1276.         {
  1277.                 _smart_ptr<IRenderMesh> pRenderMesh = pStatObj->MakeRenderMesh(pNode->pMesh, !m_bCanUnload);
  1278.                 pStatObj->SetRenderMesh(pRenderMesh);
  1279.         }
  1280.         else
  1281.         {
  1282.                 // If mesh not known now try to estimate its memory usage.
  1283.                 pStatObj->m_nRenderMeshMemoryUsage = CMesh::ApproximateRenderMeshMemoryUsage(pNode->meshInfo.nVerts, pNode->meshInfo.nIndices);
  1284.         }
  1285.         pStatObj->m_cgfNodeName = pNode->name;
  1286.  
  1287.         if (!bLod)
  1288.         {
  1289.                 pStatObj->PhysicalizeCompiled(pNode);
  1290.                 pStatObj->AnalyzeFoliage(pStatObj->m_pRenderMesh, pCGF);
  1291.         }
  1292.         if (pNode->pSkinInfo)
  1293.         {
  1294.                 pStatObj->m_pSkinInfo = (SSkinVtx*)pNode->pSkinInfo;
  1295.                 pStatObj->m_hasSkinInfo = 1;
  1296.                 pNode->pSkinInfo = 0;
  1297.         }
  1298.  
  1299.         return pStatObj;
  1300. }
  1301.  
  1302. //////////////////////////////////////////////////////////////////////////
  1303. _smart_ptr<IRenderMesh> CStatObj::MakeRenderMesh(CMesh* pMesh, bool bDoRenderMesh)
  1304. {
  1305.         FUNCTION_PROFILER_3DENGINE;
  1306.  
  1307.         if (!pMesh)
  1308.                 return 0;
  1309.  
  1310.         m_AABB = pMesh->m_bbox;
  1311.         m_fGeometricMeanFaceArea = pMesh->m_geometricMeanFaceArea;
  1312.  
  1313.         CalcRadiuses();
  1314.  
  1315.         m_nLoadedTrisCount = pMesh->GetIndexCount() / 3;
  1316.         m_nLoadedVertexCount = pMesh->GetVertexCount();
  1317.         if (!m_nLoadedTrisCount)
  1318.                 return 0;
  1319.  
  1320.         m_nRenderTrisCount = 0;
  1321.         m_nRenderMatIds = 0;
  1322.         //////////////////////////////////////////////////////////////////////////
  1323.         // Initialize Mesh subset material flags.
  1324.         //////////////////////////////////////////////////////////////////////////
  1325.         for (int i = 0; i < pMesh->GetSubSetCount(); i++)
  1326.         {
  1327.                 SMeshSubset& subset = pMesh->m_subsets[i];
  1328.                 IMaterial* pMtl = m_pMaterial->GetSafeSubMtl(subset.nMatID);
  1329.                 subset.nMatFlags = pMtl->GetFlags();
  1330.                 if (subset.nPhysicalizeType == PHYS_GEOM_TYPE_NONE && pMtl->GetSurfaceType()->GetPhyscalParams().pierceability >= 10)
  1331.                         subset.nMatFlags |= MTL_FLAG_NOPHYSICALIZE;
  1332.                 if (!(subset.nMatFlags & MTL_FLAG_NODRAW) && (subset.nNumIndices > 0))
  1333.                 {
  1334.                         m_nRenderMatIds++;
  1335.                         m_nRenderTrisCount += subset.nNumIndices / 3;
  1336.                 }
  1337.         }
  1338.         //////////////////////////////////////////////////////////////////////////
  1339.  
  1340.         if (!m_nRenderTrisCount)
  1341.                 return 0;
  1342.  
  1343.         _smart_ptr<IRenderMesh> pOutRenderMesh;
  1344.  
  1345.         // Create renderable mesh.
  1346.         if (gEnv->pRenderer)
  1347.         {
  1348.                 if (!pMesh)
  1349.                         return 0;
  1350.                 if (pMesh->GetSubSetCount() == 0)
  1351.                         return 0;
  1352.  
  1353.                 size_t nRenderMeshSize = ~0U;
  1354.                 if (bDoRenderMesh)
  1355.                 {
  1356.                         pOutRenderMesh = GetRenderer()->CreateRenderMesh("StatObj", m_szFileName.c_str());
  1357.  
  1358.                         if (m_idmatBreakable >= 0 || m_bBreakableByGame)
  1359.                         {
  1360.                                 // need to keep mesh data in system memory for breakable meshes
  1361.                                 pOutRenderMesh->KeepSysMesh(true);
  1362.                         }
  1363.  
  1364.                         // we cannot use FSM_CREATE_DEVICE_MESH flag since we can have an async call to the renderer!
  1365.                         {
  1366.                                 uint32 nFlags = 0;
  1367.                                 nFlags |= GetCVars()->e_StreamCgf ? 0 : FSM_CREATE_DEVICE_MESH;
  1368.                                 nFlags |= (!GetCVars()->e_StreamCgf && Get3DEngine()->m_bInLoad) ? FSM_SETMESH_ASYNC : 0;
  1369. #ifdef MESH_TESSELLATION_ENGINE
  1370.                                 nFlags |= FSM_ENABLE_NORMALSTREAM;
  1371. #endif
  1372.                                 nRenderMeshSize = pOutRenderMesh->SetMesh(*pMesh, 0, nFlags, NULL, true);
  1373.                                 if (nRenderMeshSize == ~0U)
  1374.                                         return 0;
  1375.                         }
  1376.  
  1377.                         bool arrMaterialSupportsTeselation[32];
  1378.                         ZeroStruct(arrMaterialSupportsTeselation);
  1379.                 }
  1380.  
  1381.                 m_nRenderMeshMemoryUsage = (nRenderMeshSize == ~0U) ? pMesh->EstimateRenderMeshMemoryUsage() : nRenderMeshSize;
  1382.                 //m_nRenderMeshMemoryUsage = pMesh->EstimateRenderMeshMemoryUsage();
  1383.         }
  1384.  
  1385.         return pOutRenderMesh;
  1386. }
  1387.  
  1388. static inline CNodeCGF* CreateNodeCGF(CContentCGF* pCGF, CStatObj* pStatObj, const char* name, CNodeCGF* pParent, CMaterialCGF* pMaterial, const Matrix34& localTM = Matrix34(IDENTITY), const char* properties = 0)
  1389. {
  1390.         CNodeCGF* pNode = NULL;
  1391.  
  1392.         // Add single node for merged mesh.
  1393.         pNode = new CNodeCGF;
  1394.  
  1395.         if (!pNode)
  1396.         {
  1397.                 CryLog("SaveToCgf: failed to allocate CNodeCGF aborting");
  1398.                 return 0;
  1399.         }
  1400.  
  1401.         cry_sprintf(pNode->name, "%s", name);
  1402.         pNode->properties = properties;
  1403.         pNode->localTM = localTM;
  1404.         pNode->worldTM = pParent ? pParent->worldTM * localTM : localTM;
  1405.         pNode->bIdentityMatrix = localTM.IsIdentity();
  1406.         pNode->pParent = pParent;
  1407.         pNode->pMaterial = pMaterial;
  1408.         pNode->nPhysicalizeFlags = 0;
  1409.  
  1410.         if (pStatObj && pStatObj->GetIndexedMesh())
  1411.         {
  1412.                 pNode->pMesh = new CMesh;
  1413.                 pNode->pMesh->CopyFrom(*(pStatObj->GetIndexedMesh()->GetMesh()));
  1414.                 pNode->pMesh->m_bbox = pStatObj->GetAABB();
  1415.                 pNode->type = CNodeCGF::NODE_MESH;
  1416.         }
  1417.         else
  1418.                 pNode->type = CNodeCGF::NODE_HELPER;
  1419.  
  1420.         if (pStatObj)
  1421.                 pStatObj->SavePhysicalizeData(pNode);
  1422.         pCGF->AddNode(pNode);
  1423.  
  1424.         const int subobjCount = pStatObj ? pStatObj->GetSubObjectCount() : 0;
  1425.         std::vector<CNodeCGF*> nodes;
  1426.         nodes.resize(subobjCount);
  1427.         for (int subidx = 0; subidx < subobjCount; ++subidx)
  1428.                 nodes[subidx] = pNode;
  1429.         for (int subidx = 0; subidx < subobjCount; ++subidx)
  1430.         {
  1431.                 IStatObj::SSubObject* pSubObj = pStatObj->GetSubObject(subidx);
  1432.                 if (!(nodes[subidx] = CreateNodeCGF(pCGF, (CStatObj*)pSubObj->pStatObj, pSubObj->pStatObj ? pSubObj->pStatObj->GetGeoName() : pSubObj->name.c_str(),
  1433.                                                     pSubObj->nParent >= 0 ? nodes[pSubObj->nParent] : pNode, pMaterial, pSubObj->localTM, pSubObj->properties)))
  1434.                         pNode = 0;
  1435.         }
  1436.         return pNode;
  1437. }
  1438.  
  1439. //////////////////////////////////////////////////////////////////////////
  1440. // Save statobj to the CGF file.
  1441. bool CStatObj::SaveToCGF(const char* sFilename, IChunkFile** pOutChunkFile, bool bHavePhiscalProxy)
  1442. {
  1443. #if defined(INCLUDE_SAVECGF)
  1444.         CContentCGF* pCGF = new CContentCGF(sFilename);
  1445.  
  1446.         pCGF->GetExportInfo()->bCompiledCGF = true;
  1447.         pCGF->GetExportInfo()->bMergeAllNodes = (GetSubObjectCount() <= 0);
  1448.         pCGF->GetExportInfo()->bHavePhysicsProxy = bHavePhiscalProxy;
  1449.         cry_strcpy(pCGF->GetExportInfo()->rc_version_string, "From Sandbox");
  1450.  
  1451.         CChunkFile* pChunkFile = new CChunkFile();
  1452.         if (pOutChunkFile)
  1453.                 *pOutChunkFile = pChunkFile;
  1454.  
  1455.         CMaterialCGF* pMaterialCGF = new CMaterialCGF;
  1456.         if (m_pMaterial)
  1457.                 cry_strcpy(pMaterialCGF->name, m_pMaterial->GetName());
  1458.         else
  1459.                 pMaterialCGF->name[0] = 0;
  1460.         pMaterialCGF->nPhysicalizeType = PHYS_GEOM_TYPE_DEFAULT;
  1461.         pMaterialCGF->bOldMaterial = false;
  1462.         pMaterialCGF->nChunkId = 0;
  1463.  
  1464.         // Array of sub materials.
  1465.         //std::vector<CMaterialCGF*> subMaterials;
  1466.  
  1467.         bool bResult = false;
  1468.         if (CreateNodeCGF(pCGF, this, GetGeoName() ? GetGeoName() : "Merged", NULL, pMaterialCGF))
  1469.         {
  1470.                 CSaverCGF cgfSaver(*pChunkFile);
  1471.  
  1472.                 const bool bNeedEndianSwap = false;
  1473.                 const bool bUseQtangents = false;
  1474.                 const bool bStorePositionsAsF16 = false;
  1475.                 const bool bStoreIndicesAsU16 = (sizeof(vtx_idx) == sizeof(uint16));
  1476.  
  1477.                 cgfSaver.SaveContent(pCGF, bNeedEndianSwap, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16);
  1478.  
  1479.                 bResult = true;
  1480.         }
  1481.  
  1482.         if (!pOutChunkFile && bResult)
  1483.         {
  1484.                 bResult = pChunkFile->Write(sFilename);
  1485.                 pChunkFile->Release();
  1486.         }
  1487.  
  1488.         delete pCGF;
  1489.  
  1490.         return bResult;
  1491. #else // #if defined(INCLUDE_SAVECGF)
  1492.         #if !defined(_RELEASE)
  1493.         __debugbreak();
  1494.         #endif
  1495.         return false;
  1496. #endif
  1497. }
  1498.  
  1499. //////////////////////////////////////////////////////////////////////////
  1500. inline char* trim_whitespaces(char* str, char* strEnd)
  1501. {
  1502.         char* first = str;
  1503.         while (first < strEnd && (*first == ' ' || *first == '\t'))
  1504.                 first++;
  1505.         char* s = strEnd - 1;
  1506.         while (s >= first && (*s == ' ' || *s == '\t'))
  1507.                 *s-- = 0;
  1508.         return first;
  1509. }
  1510.  
  1511. //////////////////////////////////////////////////////////////////////////
  1512. void CStatObj::ParseProperties()
  1513. {
  1514.         FUNCTION_PROFILER_3DENGINE;
  1515.  
  1516.         int nLen = m_szProperties.size();
  1517.         if (nLen >= 4090)
  1518.         {
  1519.                 Warning("CGF '%s' have longer then 4K geometry info file", m_szFileName.c_str());
  1520.                 nLen = 4090;
  1521.         }
  1522.  
  1523.         char properties[4096];
  1524.         memcpy(properties, m_szProperties.c_str(), nLen);
  1525.         properties[nLen] = 0;
  1526.  
  1527.         char* str = properties;
  1528.         char* strEnd = str + nLen;
  1529.         while (str < strEnd)
  1530.         {
  1531.                 char* line = str;
  1532.                 while (str < strEnd && *str != '\n' && *str != '\r')
  1533.                         str++;
  1534.                 char* lineEnd = str;
  1535.                 *lineEnd = 0;
  1536.                 str++;
  1537.                 while (str < strEnd && (*str == '\n' || *str == '\r')) // Skip all \r\n at end.
  1538.                         str++;
  1539.  
  1540.                 if (*line == '/' || *line == '#') // skip comments
  1541.                 {
  1542.                         continue;
  1543.                 }
  1544.  
  1545.                 if (line < lineEnd)
  1546.                 {
  1547.                         // Parse line.
  1548.                         char* l = line;
  1549.                         while (l < lineEnd && *l != '=')
  1550.                                 l++;
  1551.                         if (l < lineEnd)
  1552.                         {
  1553.                                 *l = 0;
  1554.                                 char* left = line;
  1555.                                 char* right = l + 1;
  1556.  
  1557.                                 // remove white spaces from left and right.
  1558.                                 left = trim_whitespaces(left, l);
  1559.                                 right = trim_whitespaces(right, lineEnd);
  1560.  
  1561.                                 //////////////////////////////////////////////////////////////////////////
  1562.                                 if (0 == strcmp(left, "mass"))
  1563.                                 {
  1564.                                         m_phys_mass = (float)atof(right);
  1565.                                 }
  1566.                                 else if (0 == strcmp(left, "density"))
  1567.                                 {
  1568.                                         m_phys_density = (float)atof(right);
  1569.                                 }
  1570.                                 //////////////////////////////////////////////////////////////////////////
  1571.  
  1572.                         }
  1573.                         else
  1574.                         {
  1575.                                 // There`s no = on the line, must be a flag.
  1576.                                 //////////////////////////////////////////////////////////////////////////
  1577.                                 if (0 == strcmp(line, "entity"))
  1578.                                 {
  1579.                                         // pickable
  1580.                                         m_nFlags |= STATIC_OBJECT_SPAWN_ENTITY;
  1581.                                 }
  1582.                                 else if (0 == strcmp(line, "no_player_collide"))
  1583.                                 {
  1584.                                         m_nFlags |= STATIC_OBJECT_NO_PLAYER_COLLIDE;
  1585.                                 }
  1586.                                 else if (0 == strcmp(line, "pickable"))
  1587.                                 {
  1588.                                         m_nFlags |= STATIC_OBJECT_PICKABLE;
  1589.                                 }
  1590.                                 else if (0 == strcmp(line, "no_auto_hidepoints"))
  1591.                                 {
  1592.                                         m_nFlags |= STATIC_OBJECT_NO_AUTO_HIDEPOINTS;
  1593.                                 }
  1594.                                 else if (0 == strcmp(line, "dynamic"))
  1595.                                 {
  1596.                                         m_nFlags |= STATIC_OBJECT_DYNAMIC;
  1597.                                 }
  1598.                                 else if (0 == strcmp(line, "no_hit_refinement"))
  1599.                                 {
  1600.                                         m_bNoHitRefinement = true;
  1601.                                         for (int i = m_arrPhysGeomInfo.GetGeomCount() - 1; i >= 0; i--)
  1602.                                                 m_arrPhysGeomInfo[i]->pGeom->SetForeignData(0, 0);
  1603.                                 }
  1604.                                 else if (0 == strcmp(line, "no_explosion_occlusion"))
  1605.                                 {
  1606.                                         m_bDontOccludeExplosions = true;
  1607.                                 }
  1608.                                 //////////////////////////////////////////////////////////////////////////
  1609.                         }
  1610.                 }
  1611.         }
  1612. }
  1613.  
downloadStatObjLoad.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