BVB Source Codes

CRYENGINE Show CGFLoader.cpp Source code

Return Download CRYENGINE: download CGFLoader.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:   CGFLoader.cpp
  5. //  Version:     v1.00
  6. //  Created:     6/11/2004 by Timur.
  7. //  Compilers:   Visual Studio.NET
  8. //  Description:
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15. #include "CGFLoader.h"
  16. #include <CryCore/TypeInfo_impl.h>
  17. #include <CryCore/Common_TypeInfo2.h>
  18. #include <CryString/StringUtils.h>
  19. #include <CrySystem/InplaceFactory.h>
  20. #include <CryString/CryPath.h>
  21. #include "ReadOnlyChunkFile.h"
  22. #include <CryCore/CryCustomTypes.h>
  23.  
  24. #include <Cry3DEngine/IStatObj.h>
  25.  
  26. // #define DEBUG_DUMP_RBATCHES
  27. #define VERTEX_SCALE 0.01f
  28. enum { MAX_NUMBER_OF_BONES = 65534 };
  29.  
  30. #if !defined(FUNCTION_PROFILER_3DENGINE)
  31.         #define FUNCTION_PROFILER_3DENGINE
  32. #endif
  33.  
  34. namespace
  35. {
  36. // Templated construct helper function using an inplace factory
  37. //
  38. // Called from the templated New<T, Expr> function below. Returns a typed
  39. // pointer to the inplace constructed object.
  40. template<typename T, typename InPlaceFactory>
  41. T* Construct(
  42.   const InPlaceFactory& factory,
  43.   void* (*pAllocFnc)(size_t))
  44. {
  45.         return reinterpret_cast<T*>(factory.template apply<T>(pAllocFnc(sizeof(T))));
  46. }
  47.  
  48. // Templated construct helper function using an inplace factory
  49. //
  50. // Called from the templated New<T, Expr> function below. Returns a typed
  51. // pointer to the inplace constructed object.
  52. template<typename T>
  53. T* Construct(void* (*pAllocFnc)(size_t))
  54. {
  55.         return new(pAllocFnc(sizeof(T)))T;
  56. }
  57.  
  58. // Templated destruct helper function
  59. //
  60. // Calls the object's destructor and returns a void pointer to the storage
  61. template<typename T>
  62. void Destruct(T* obj, void (* pDestructFnc)(void*))
  63. {
  64.         obj->~T();
  65.         pDestructFnc(reinterpret_cast<void*>(obj));
  66. }
  67. }
  68.  
  69. //////////////////////////////////////////////////////////////////////////
  70. CLoaderCGF::CLoaderCGF(
  71.   AllocFncPtr pAllocFnc,
  72.   DestructFncPtr pDestructFnc,
  73.   bool bAllowStreamSharing)
  74.         : m_pAllocFnc(pAllocFnc)
  75.         , m_pDestructFnc(pDestructFnc)
  76. {
  77.         m_pChunkFile = NULL;
  78.  
  79.         //////////////////////////////////////////////////////////////////////////
  80.         // To find really used materials
  81.         memset(MatIdToSubset, 0, sizeof(MatIdToSubset));
  82.         nMaterialsUsed = 0;
  83.         //////////////////////////////////////////////////////////////////////////
  84.  
  85.         m_bUseReadOnlyMesh = false;
  86.  
  87.         m_bAllowStreamSharing = bAllowStreamSharing;
  88.  
  89.         m_pCompiledCGF = 0;
  90.  
  91.         m_maxWeightsPerVertex = 4;
  92. }
  93.  
  94. //////////////////////////////////////////////////////////////////////////
  95. CLoaderCGF::~CLoaderCGF()
  96. {
  97. }
  98.  
  99. //////////////////////////////////////////////////////////////////////////
  100. CContentCGF* CLoaderCGF::LoadCGF(const char* filename, IChunkFile& chunkFile, ILoaderCGFListener* pListener, unsigned long nLoadingFlags)
  101. {
  102.         CContentCGF* const pContentCGF = new CContentCGF(filename);
  103.         if (!pContentCGF)
  104.         {
  105.                 return NULL;
  106.         }
  107.         if (!LoadCGF(pContentCGF, filename, chunkFile, pListener, nLoadingFlags))
  108.         {
  109.                 delete pContentCGF;
  110.                 return NULL;
  111.         }
  112.         return pContentCGF;
  113. }
  114.  
  115. //////////////////////////////////////////////////////////////////////////
  116. bool CLoaderCGF::LoadCGF(CContentCGF* pContentCGF, const char* filename, IChunkFile& chunkFile, ILoaderCGFListener* pListener, unsigned long nLoadingFlags)
  117. {
  118.         FUNCTION_PROFILER_3DENGINE;
  119.  
  120.         if (!chunkFile.IsLoaded())
  121.         {
  122.                 if (!chunkFile.Read(filename))
  123.                 {
  124.                         m_LastError = chunkFile.GetLastError();
  125.                         return false;
  126.                 }
  127.         }
  128.  
  129.         if (gEnv)
  130.         {
  131.                 //Update loading screen and important tick functions
  132.                 SYNCHRONOUS_LOADING_TICK();
  133.         }
  134.  
  135.         return LoadCGF_Int(pContentCGF, filename, chunkFile, pListener, nLoadingFlags);
  136. }
  137.  
  138. bool CLoaderCGF::LoadCGFFromMem(CContentCGF* pContentCGF, const void* pData, size_t nDataLen, IChunkFile& chunkFile, ILoaderCGFListener* pListener, unsigned long nLoadingFlags)
  139. {
  140.         FUNCTION_PROFILER_3DENGINE;
  141.  
  142.         if (!chunkFile.IsLoaded())
  143.         {
  144.                 if (!chunkFile.ReadFromMemory(pData, (int)nDataLen))
  145.                 {
  146.                         m_LastError = chunkFile.GetLastError();
  147.                         return false;
  148.                 }
  149.         }
  150.  
  151.         if (gEnv)
  152.         {
  153.                 //Update loading screen and important tick functions
  154.                 SYNCHRONOUS_LOADING_TICK();
  155.         }
  156.  
  157.         return LoadCGF_Int(pContentCGF, pContentCGF->GetFilename(), chunkFile, pListener, nLoadingFlags);
  158. }
  159.  
  160. bool CLoaderCGF::LoadCGF_Int(CContentCGF* pContentCGF, const char* filename, IChunkFile& chunkFile, ILoaderCGFListener* pListener, unsigned long nLoadingFlags)
  161. {
  162.         m_pListener = pListener;
  163.         m_bUseReadOnlyMesh = chunkFile.IsReadOnly();
  164.  
  165.         cry_strcpy(m_filename, filename);
  166.         m_pChunkFile = &chunkFile;
  167.  
  168.         // Load mesh from chunk file.
  169.  
  170.         if (!pContentCGF)
  171.         {
  172.                 m_LastError.Format("no valid CContentCGF instance for cgf file: %s", m_filename);
  173.                 return false;
  174.         }
  175.         m_pCGF = pContentCGF;
  176.  
  177.         {
  178.                 const char* const pExt = PathUtil::GetExt(filename);
  179.                 m_IsCHR =
  180.                   !stricmp(pExt, "chr") ||
  181.                   !stricmp(pExt, "chrp") ||
  182.                   !stricmp(pExt, "chrm") ||
  183.                   !stricmp(pExt, "skin") ||
  184.                   !stricmp(pExt, "skinp") ||
  185.                   !stricmp(pExt, "skinm") ||
  186.                   !stricmp(pExt, "skel");
  187.         }
  188.  
  189.         const bool bJustGeometry = (nLoadingFlags& IStatObj::ELoadingFlagsJustGeometry) != 0;
  190.  
  191.         if (!LoadChunks(bJustGeometry))
  192.         {
  193.                 return false;
  194.         }
  195.  
  196.         for (int i = 0; i < m_pChunkFile->NumChunks(); ++i)
  197.         {
  198.                 if (m_pChunkFile->GetChunk(i)->bSwapEndian)
  199.                 {
  200.                         m_pCGF->m_bConsoleFormat = true;
  201.                         break;
  202.                 }
  203.         }
  204.  
  205.         if (!bJustGeometry)
  206.         {
  207.                 if (m_pCGF->GetMaterialCount() > 0)
  208.                 {
  209.                         m_pCGF->SetCommonMaterial(m_pCGF->GetMaterial(0));
  210.                 }
  211.         }
  212.  
  213.         // Set node parents.
  214.         for (int i = 0; i < m_pCGF->GetNodeCount(); ++i)
  215.         {
  216.                 if (m_pCGF->GetNode(i)->nParentChunkId > 0)
  217.                 {
  218.                         for (int j = 0; j < m_pCGF->GetNodeCount(); ++j)
  219.                         {
  220.                                 if (m_pCGF->GetNode(i)->nParentChunkId == m_pCGF->GetNode(j)->nChunkId)
  221.                                 {
  222.                                         m_pCGF->GetNode(i)->pParent = m_pCGF->GetNode(j);
  223.                                         break;
  224.                                 }
  225.                         }
  226.                 }
  227.         }
  228.  
  229.         // Calculate node *world* matrices.
  230.         for (int i = 0; i < m_pCGF->GetNodeCount(); ++i)
  231.         {
  232.                 CNodeCGF* const pNode = m_pCGF->GetNode(i);
  233.                 Matrix34 tm = pNode->localTM;
  234.                 for (CNodeCGF* pCurNode = pNode->pParent; pCurNode; pCurNode = pCurNode->pParent)
  235.                 {
  236.                         tm = pCurNode->localTM * tm;
  237.                 }
  238.                 pNode->worldTM = tm;
  239.                 pNode->bIdentityMatrix = pNode->worldTM.IsIdentity();
  240.         }
  241.  
  242.         // Setup mesh subsets.
  243.         for (int i = 0; i < m_pCGF->GetNodeCount(); ++i)
  244.         {
  245.                 CNodeCGF* const pNode = m_pCGF->GetNode(i);
  246.                 if (pNode->pMesh)
  247.                 {
  248.                         SetupMeshSubsets(*pNode->pMesh, pNode->pMaterial);
  249.                 }
  250.         }
  251.  
  252.         if (gEnv)
  253.         {
  254.                 SYNCHRONOUS_LOADING_TICK();
  255.         }
  256.  
  257.         if (!bJustGeometry)
  258.         {
  259.                 if (!ProcessSkinning())
  260.                 {
  261.                         return false;
  262.                 }
  263.         }
  264.  
  265.         if (pListener && pListener->IsValidationEnabled())
  266.         {
  267.                 const char* pErrorDescription = 0;
  268.                 if (!m_pCGF->ValidateMeshes(&pErrorDescription))
  269.                 {
  270.                         Warning(
  271.                           "!Invalid meshes (%s) found in file: %s\n"
  272.                           "The file is corrupt (possibly generated with old/buggy RC) -- please re-export it with newest RC",
  273.                           pErrorDescription, m_filename);
  274.                 }
  275.         }
  276.  
  277.         m_pListener = 0;
  278.  
  279.         return true;
  280. }
  281.  
  282. //////////////////////////////////////////////////////////////////////////
  283. bool CLoaderCGF::LoadChunks(bool bJustGeometry)
  284. {
  285.         FUNCTION_PROFILER_3DENGINE;
  286.  
  287.         m_CompiledBones = false;
  288.         m_CompiledMesh = 0;
  289.         m_CompiledBonesBoxes = false;
  290.  
  291.         m_numBonenameList = 0;
  292.         m_numBoneInitialPos = 0;
  293.         m_numMorphTargets = 0;
  294.         m_numBoneHierarchy = 0;
  295.  
  296.         // Load Nodes.
  297.         const uint32 numChunk = m_pChunkFile->NumChunks();
  298.         m_pCGF->GetSkinningInfo()->m_arrPhyBoneMeshes.clear();
  299.         m_pCGF->GetSkinningInfo()->m_numChunks = numChunk;
  300.  
  301.         for (uint32 i = 0; i < numChunk; i++)
  302.         {
  303.                 IChunkFile::ChunkDesc* const pChunkDesc = m_pChunkFile->GetChunk(i);
  304.  
  305.                 if (!bJustGeometry)
  306.                 {
  307.                         if (m_IsCHR)
  308.                         {
  309.                                 switch (pChunkDesc->chunkType)
  310.                                 {
  311.  
  312.                                 case ChunkType_BoneNameList:
  313.                                         m_numBonenameList++;
  314.                                         if (!ReadBoneNameList(pChunkDesc))
  315.                                                 return false;
  316.                                         break;
  317.  
  318.                                 case ChunkType_BoneInitialPos:
  319.                                         m_numBoneInitialPos++;
  320.                                         if (!ReadBoneInitialPos(pChunkDesc))
  321.                                                 return false;
  322.                                         break;
  323.  
  324.                                 case ChunkType_BoneAnim:
  325.                                         m_numBoneHierarchy++;
  326.                                         if (!ReadBoneHierarchy(pChunkDesc))
  327.                                                 return false;
  328.                                         break;
  329.  
  330.                                 case ChunkType_BoneMesh:
  331.                                         if (!ReadBoneMesh(pChunkDesc))
  332.                                                 return false;
  333.                                         break;
  334.  
  335.                                 case ChunkType_MeshMorphTarget:
  336.                                         m_numMorphTargets++;
  337.                                         if (!ReadMorphTargets(pChunkDesc))
  338.                                                 return false;
  339.                                         break;
  340.  
  341.                                 //---------------------------------------------------------
  342.                                 //---       chunks for compiled characters             ----
  343.                                 //---------------------------------------------------------
  344.  
  345.                                 case ChunkType_CompiledBones:
  346.                                         if (!ReadCompiledBones(pChunkDesc))
  347.                                                 return false;
  348.                                         break;
  349.  
  350.                                 case ChunkType_CompiledPhysicalBones:
  351.                                         if (!ReadCompiledPhysicalBones(pChunkDesc))
  352.                                                 return false;
  353.                                         break;
  354.  
  355.                                 case ChunkType_CompiledPhysicalProxies:
  356.                                         if (!ReadCompiledPhysicalProxies(pChunkDesc))
  357.                                                 return false;
  358.                                         break;
  359.  
  360.                                 case ChunkType_CompiledMorphTargets:
  361.                                         if (!ReadCompiledMorphTargets(pChunkDesc))
  362.                                                 return false;
  363.                                         break;
  364.  
  365.                                 case ChunkType_CompiledIntFaces:
  366.                                         if (!ReadCompiledIntFaces(pChunkDesc))
  367.                                                 return false;
  368.                                         break;
  369.  
  370.                                 case ChunkType_CompiledIntSkinVertices:
  371.                                         if (!ReadCompiledIntSkinVertice(pChunkDesc))
  372.                                                 return false;
  373.                                         break;
  374.  
  375.                                 case ChunkType_CompiledExt2IntMap:
  376.                                         if (!ReadCompiledExt2IntMap(pChunkDesc))
  377.                                                 return false;
  378.                                         break;
  379.  
  380.                                 case ChunkType_BonesBoxes:
  381.                                         if (!ReadCompiledBonesBoxes(pChunkDesc))
  382.                                                 return false;
  383.                                         break;
  384.  
  385.                                 }
  386.                         }
  387.  
  388.                         switch (pChunkDesc->chunkType)
  389.                         {
  390.                         //---------------------------------------------------------
  391.                         //---       chunks for CGA-objects  -----------------------
  392.                         //---------------------------------------------------------
  393.  
  394.                         case ChunkType_ExportFlags:
  395.                                 if (!LoadExportFlagsChunk(pChunkDesc))
  396.                                         return false;
  397.                                 break;
  398.  
  399.                         case ChunkType_Node:
  400.                                 if (!LoadNodeChunk(pChunkDesc, false))
  401.                                         return false;
  402.                                 break;
  403.  
  404.                         case ChunkType_MtlName:
  405.                                 if (!LoadMaterialFromChunk(pChunkDesc->chunkId))
  406.                                         return false;
  407.                                 break;
  408.  
  409.                         case ChunkType_BreakablePhysics:
  410.                                 if (!ReadCompiledBreakablePhysics(pChunkDesc))
  411.                                         return false;
  412.                                 break;
  413.  
  414.                         case ChunkType_FoliageInfo:
  415.                                 if (!LoadFoliageInfoChunk(pChunkDesc))
  416.                                         return false;
  417.                                 break;
  418.  
  419.                         case ChunkType_VCloth:
  420.                                 if (!LoadVClothChunk(pChunkDesc))
  421.                                         return false;
  422.                                 break;
  423.                         }
  424.                 }
  425.                 else
  426.                 {
  427.                         switch (pChunkDesc->chunkType)
  428.                         {
  429.                         case ChunkType_Node:
  430.                                 if (!LoadNodeChunk(pChunkDesc, true))
  431.                                         return false;
  432.                                 break;
  433.                         }
  434.                 }
  435.         }
  436.  
  437.         return true;
  438. }
  439.  
  440. bool CLoaderCGF::ReadBoneInitialPos(IChunkFile::ChunkDesc* pChunkDesc)
  441. {
  442.         FUNCTION_PROFILER_3DENGINE;
  443.  
  444.         if (pChunkDesc->chunkVersion != BONEINITIALPOS_CHUNK_DESC_0001::VERSION)
  445.         {
  446.                 m_LastError.Format("BoneInitialPos chunk is of unknown version %d", pChunkDesc->chunkVersion);
  447.                 return false;
  448.         }
  449.  
  450.         BONEINITIALPOS_CHUNK_DESC_0001* const pBIPChunk = (BONEINITIALPOS_CHUNK_DESC_0001*)pChunkDesc->data;
  451.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  452.         SwapEndian(*pBIPChunk, bSwapEndianness);
  453.         pChunkDesc->bSwapEndian = false;
  454.  
  455.         const uint32 numBones = pBIPChunk->numBones;
  456.  
  457.         SBoneInitPosMatrix* const pDefMatrix = (SBoneInitPosMatrix*)(pBIPChunk + 1);
  458.         SwapEndian(pDefMatrix, numBones, bSwapEndianness);
  459.  
  460.         m_arrInitPose34.resize(numBones, IDENTITY);
  461.         for (uint32 nBone = 0; nBone < numBones; ++nBone)
  462.         {
  463.                 m_arrInitPose34[nBone].m00 = pDefMatrix[nBone].mx[0][0];
  464.                 m_arrInitPose34[nBone].m01 = pDefMatrix[nBone].mx[1][0];
  465.                 m_arrInitPose34[nBone].m02 = pDefMatrix[nBone].mx[2][0];
  466.                 m_arrInitPose34[nBone].m03 = pDefMatrix[nBone].mx[3][0] * VERTEX_SCALE;
  467.                 m_arrInitPose34[nBone].m10 = pDefMatrix[nBone].mx[0][1];
  468.                 m_arrInitPose34[nBone].m11 = pDefMatrix[nBone].mx[1][1];
  469.                 m_arrInitPose34[nBone].m12 = pDefMatrix[nBone].mx[2][1];
  470.                 m_arrInitPose34[nBone].m13 = pDefMatrix[nBone].mx[3][1] * VERTEX_SCALE;
  471.                 m_arrInitPose34[nBone].m20 = pDefMatrix[nBone].mx[0][2];
  472.                 m_arrInitPose34[nBone].m21 = pDefMatrix[nBone].mx[1][2];
  473.                 m_arrInitPose34[nBone].m22 = pDefMatrix[nBone].mx[2][2];
  474.                 m_arrInitPose34[nBone].m23 = pDefMatrix[nBone].mx[3][2] * VERTEX_SCALE;
  475.                 m_arrInitPose34[nBone].OrthonormalizeFast(); // for some reason Max supplies unnormalized matrices.
  476.         }
  477.  
  478.         return true;
  479. }
  480.  
  481. //////////////////////////////////////////////////////////////////////////
  482.  
  483. bool CLoaderCGF::ReadMorphTargets(IChunkFile::ChunkDesc* pChunkDesc)
  484. {
  485.         FUNCTION_PROFILER_3DENGINE;
  486.  
  487. #if !defined(RESOURCE_COMPILER)
  488.         m_LastError.Format("%s tried to load a noncompiled MeshMorphTarget chunk %i", __FUNCTION__, (int)pChunkDesc->chunkId);
  489.         return false;
  490. #else
  491.         if (pChunkDesc->chunkVersion != MESHMORPHTARGET_CHUNK_DESC_0001::VERSION)
  492.         {
  493.                 m_LastError.Format("MeshMorphTarget chunk %i is of unknown version %i", (int)pChunkDesc->chunkId, (int)pChunkDesc->chunkVersion);
  494.                 return false;
  495.         }
  496.  
  497.         // the chunk must at least contain its header and the name (min 2 bytes)
  498.         if (pChunkDesc->size <= sizeof(MESHMORPHTARGET_CHUNK_DESC_0001))
  499.         {
  500.                 m_LastError.Format("MeshMorphTarget chunk %i: Bad size: %i", (int)pChunkDesc->chunkId, (int)pChunkDesc->size);
  501.                 return false;
  502.         }
  503.  
  504.         if (m_vertexOldToNew.empty())
  505.         {
  506.                 m_LastError.Format("MeshMorphTarget chunk %i: main mesh was not loaded yet or its type is not Skin.", (int)pChunkDesc->chunkId);
  507.                 return false;
  508.         }
  509.  
  510.         MESHMORPHTARGET_CHUNK_DESC_0001* const pMeshMorphTarget = (MESHMORPHTARGET_CHUNK_DESC_0001*)pChunkDesc->data;
  511.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  512.         SwapEndian(*pMeshMorphTarget, bSwapEndianness);
  513.         pChunkDesc->bSwapEndian = false;
  514.  
  515.         const uint32 oldVertexCount = pMeshMorphTarget->numMorphVertices;
  516.         if (oldVertexCount <= 0)
  517.         {
  518.                 m_LastError.Format("MeshMorphTarget chunk %i: Bad # of vertices: %i", (int)pChunkDesc->chunkId, (int)oldVertexCount);
  519.                 return false;
  520.         }
  521.  
  522.         SMeshMorphTargetVertex* const pSrcVertices = (SMeshMorphTargetVertex*)(pMeshMorphTarget + 1);
  523.         SwapEndian(pSrcVertices, (size_t)oldVertexCount, bSwapEndianness);
  524.  
  525.         // Remap stored vertex indices to match main mesh's remapping. We also delete entries that
  526.         // reference vertices which do not exist (were removed) in main mesh.
  527.  
  528.         uint32 newVertexCount = 0;
  529.  
  530.         for (uint32 i = 0; i < oldVertexCount; ++i)
  531.         {
  532.                 const unsigned oldIdx = pSrcVertices[i].nVertexId;
  533.                 if (oldIdx >= m_vertexOldToNew.size())
  534.                 {
  535.                         m_LastError.Format("MeshMorphTarget chunk %i: bad vertex index (%u) at element %u", (int)pChunkDesc->chunkId, oldIdx, (unsigned)i);
  536.                         return false;
  537.                 }
  538.  
  539.                 const int newIdx = m_vertexOldToNew[oldIdx];
  540.                 // Negative index means that the vertex was not used and so it was removed from the main mesh
  541.                 if (newIdx >= 0)
  542.                 {
  543.                         pSrcVertices[i].nVertexId = (unsigned)newIdx;
  544.                         pSrcVertices[newVertexCount++] = pSrcVertices[i];
  545.                 }
  546.         }
  547.  
  548.         // Get rid of duplicate entries (referencing same main mesh vertex), and also sort entries
  549.         // in ascending order of vertex indices
  550.         {
  551.                 struct CompareByVertexIndex
  552.                 {
  553.                         static bool less(const SMeshMorphTargetVertex& left, const SMeshMorphTargetVertex& right)
  554.                         {
  555.                                 return left.nVertexId < right.nVertexId;
  556.                         }
  557.                 };
  558.  
  559.                 std::sort(&pSrcVertices[0], &pSrcVertices[newVertexCount], CompareByVertexIndex::less);
  560.  
  561.                 const uint32 n = newVertexCount;
  562.                 newVertexCount = 0;
  563.                 for (uint32 i = 0; i < n; ++i)
  564.                 {
  565.                         if (i == 0 || CompareByVertexIndex::less(pSrcVertices[i - 1], pSrcVertices[i]))
  566.                         {
  567.                                 pSrcVertices[newVertexCount++] = pSrcVertices[i];
  568.                         }
  569.                 }
  570.         }
  571.  
  572.         // Form results
  573.  
  574.         MorphTargets* const pMT = new MorphTargets;
  575.  
  576.         // Store the mesh ID
  577.         pMT->MeshID = pMeshMorphTarget->nChunkIdMesh;
  578.         // Store the name of morph-target
  579.         const char* const pName = (const char*)(pSrcVertices + oldVertexCount);
  580.         pMT->m_strName = "#" + string(pName);
  581.         // Store the vertices of morph-target
  582.         pMT->m_arrIntMorph.resize(newVertexCount);
  583.         memcpy(pMT->m_arrIntMorph.data(), pSrcVertices, sizeof(*pMT->m_arrIntMorph.data()) * newVertexCount);
  584.  
  585.         CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  586.         pSkinningInfo->m_arrMorphTargets.push_back(pMT);
  587.  
  588.         return true;
  589. #endif
  590. }
  591.  
  592. //////////////////////////////////////////////////////////////////////////
  593. bool CLoaderCGF::ReadBoneNameList(IChunkFile::ChunkDesc* pChunkDesc)
  594. {
  595.         FUNCTION_PROFILER_3DENGINE;
  596.  
  597.         if (pChunkDesc->chunkVersion != BONENAMELIST_CHUNK_DESC_0745::VERSION)
  598.         {
  599.                 m_LastError.Format("Unknown version of bone name list chunk");
  600.                 return false;
  601.         }
  602.  
  603.         // the chunk contains variable-length packed strings following tightly each other
  604.         BONENAMELIST_CHUNK_DESC_0745* pNameChunk = (BONENAMELIST_CHUNK_DESC_0745*)(pChunkDesc->data);
  605.         SwapEndian(*pNameChunk, pChunkDesc->bSwapEndian);
  606.         pChunkDesc->bSwapEndian = false;
  607.  
  608.         const uint32 nGeomBones = pNameChunk->numEntities;
  609.  
  610.         // we know how many strings there are there; note that the whole bunch
  611.         // of strings may be followed by padding zeros
  612.         m_arrBoneNameTable.resize(nGeomBones, "");
  613.  
  614.         // scan through all the strings (strings are zero-terminated)
  615.         const char* const pNameListEnd = ((const char*)pNameChunk) + pChunkDesc->size;
  616.         const char* pName = (const char*)(pNameChunk + 1);
  617.         uint32 numNames = 0;
  618.         while (*pName && pName < pNameListEnd && numNames < nGeomBones)
  619.         {
  620.                 m_arrBoneNameTable[numNames] = pName;
  621.                 pName += m_arrBoneNameTable[numNames].size() + 1;
  622.                 numNames++;
  623.         }
  624.         if (numNames < nGeomBones)
  625.         {
  626.                 m_LastError.Format("inconsistent bone name list chunk: only %d out of %d bone names have been read.", numNames, nGeomBones);
  627.                 return false;
  628.         }
  629.  
  630.         return true;
  631. }
  632.  
  633. /////////////////////////////////////////////////////////////////////////////////////
  634. // loads the root bone (and the hierarchy) and returns true if loaded successfully
  635. // this gets called only for LOD 0
  636. /////////////////////////////////////////////////////////////////////////////////////
  637. bool CLoaderCGF::ReadBoneHierarchy(IChunkFile::ChunkDesc* pChunkDesc)
  638. {
  639.         if (pChunkDesc->chunkVersion != BONEANIM_CHUNK_DESC_0290::VERSION)
  640.         {
  641.                 m_LastError.Format("Unknown version of bone hierarchy chunk");
  642.                 return false;
  643.         }
  644.  
  645.         CSkinningInfo* pSkinningInfo = m_pCGF->GetSkinningInfo();
  646.  
  647.         BONEANIM_CHUNK_DESC_0290* pChunk = (BONEANIM_CHUNK_DESC_0290*)(pChunkDesc->data);
  648.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  649.         SwapEndian(*pChunk, bSwapEndianness);
  650.         pChunkDesc->bSwapEndian = false;
  651.  
  652.         m_pBoneAnimRawData = 0;
  653.  
  654.         if (pChunk->nBones <= 0)
  655.         {
  656.                 m_LastError = "There must be at least one bone.";
  657.                 return false;
  658.         }
  659.  
  660.         if (pChunkDesc->size < sizeof(*pChunk) ||
  661.             pChunk->nBones != (pChunkDesc->size - sizeof(*pChunk)) / sizeof(BONE_ENTITY))
  662.         {
  663.                 m_LastError = "Corrupted bone hierarchy chunk data.";
  664.         }
  665.  
  666.         m_pBoneAnimRawData = pChunk + 1;
  667.         m_pBoneAnimRawDataEnd = ((const char*)pChunk) + pChunkDesc->size;
  668.  
  669.         BONE_ENTITY* const pBones = (BONE_ENTITY*)m_pBoneAnimRawData;
  670.  
  671.         for (int i = 0; i < pChunk->nBones; ++i)
  672.         {
  673.                 SwapEndian(pBones[i], bSwapEndianness);
  674.         }
  675.  
  676.         if (pBones[0].ParentID != -1)
  677.         {
  678.                 m_LastError = "The first bone in the hierarchy has a parent, but the first none expected to be the root bone.";
  679.                 return false;
  680.         }
  681.  
  682.         /*
  683.            for (int i = 1; i < pChunk->nBones; ++i)
  684.            {
  685.            if (pBones[i].ParentID == -1)
  686.            {
  687.            m_LastError = "The skeleton has multiple roots. Only single-rooted skeletons are supported in this version.");
  688.            return false;
  689.            }
  690.            }
  691.          */
  692.  
  693.         pSkinningInfo->m_arrBonesDesc.resize(pChunk->nBones);
  694.         CryBoneDescData zeroBone;
  695.         memset(&zeroBone, 0, sizeof(zeroBone));
  696.         std::fill(pSkinningInfo->m_arrBonesDesc.begin(), pSkinningInfo->m_arrBonesDesc.end(), zeroBone);
  697.         m_arrIndexToId.resize(pChunk->nBones, ~0);
  698.         m_arrIdToIndex.resize(pChunk->nBones, ~0);
  699.  
  700.         m_nNextBone = 1;
  701.         assert(m_nNextBone <= pChunk->nBones);
  702.  
  703.         m_numBones = 0;
  704.  
  705.         for (int i = 0; i < pChunk->nBones; ++i)
  706.         {
  707.                 if (pBones[i].ParentID == -1)
  708.                 {
  709.                         const int nRootBoneIndex = i;
  710.                         m_nNextBone = nRootBoneIndex + 1;
  711.                         RecursiveBoneLoader(nRootBoneIndex, nRootBoneIndex);
  712.                 }
  713.         }
  714.         assert(pChunk->nBones == m_numBones);
  715.  
  716.         //-----------------------------------------------------------------------------
  717.         //---                  read physical information                            ---
  718.         //-----------------------------------------------------------------------------
  719.         pSkinningInfo->m_arrBoneEntities.resize(pChunk->nBones);
  720.  
  721.         int32 test = 0;
  722.         for (int i = 0; i < pChunk->nBones; ++i)
  723.         {
  724.                 pSkinningInfo->m_arrBoneEntities[i] = pBones[i];
  725.                 test |= pBones[i].phys.nPhysGeom;
  726.         }
  727.         return true;
  728. }
  729.  
  730. // loads the whole hierarchy of bones, using the state machine
  731. // when this function is called, the bone is already allocated
  732. uint32 CLoaderCGF::RecursiveBoneLoader(int nBoneParentIndex, int nBoneIndex)
  733. {
  734.         m_numBones++;
  735.         CSkinningInfo* pSkinningInfo = m_pCGF->GetSkinningInfo();
  736.  
  737.         BONE_ENTITY* pEntity = (BONE_ENTITY*)m_pBoneAnimRawData;
  738.         SwapEndian(*pEntity);
  739.         m_pBoneAnimRawData = ((uint8*)m_pBoneAnimRawData) + sizeof(BONE_ENTITY);
  740.  
  741.         // initialize the next bone
  742.         CryBoneDescData& rBoneDesc = pSkinningInfo->m_arrBonesDesc[nBoneIndex];
  743.         //read  bone info
  744.  
  745.         CopyPhysInfo(rBoneDesc.m_PhysInfo[0], pEntity->phys);
  746.         int nFlags = 0;
  747.         if (pEntity->prop[0])
  748.         {
  749.                 nFlags = joint_no_gravity | joint_isolated_accelerations;
  750.         }
  751.         else
  752.         {
  753.                 if (!CryStringUtils::strnstr(pEntity->prop, "gravity", sizeof(pEntity->prop)))
  754.                         nFlags |= joint_no_gravity;
  755.                 if (!CryStringUtils::strnstr(pEntity->prop, "active_phys", sizeof(pEntity->prop)))
  756.                         nFlags |= joint_isolated_accelerations;
  757.         }
  758.         (rBoneDesc.m_PhysInfo[0].flags &= ~(joint_no_gravity | joint_isolated_accelerations)) |= nFlags;
  759.  
  760.         //get bone info
  761.         rBoneDesc.m_nControllerID = pEntity->ControllerID;
  762.  
  763.         // set the mapping entries
  764.         m_arrIndexToId[nBoneIndex] = pEntity->BoneID;
  765.         m_arrIdToIndex[pEntity->BoneID] = nBoneIndex;
  766.  
  767.         rBoneDesc.m_nOffsetParent = nBoneParentIndex - nBoneIndex;
  768.  
  769.         // load children
  770.         if (pEntity->nChildren)
  771.         {
  772.                 int nChildrenIndexBase = m_nNextBone;
  773.                 m_nNextBone += pEntity->nChildren;
  774.                 if (nChildrenIndexBase < 0)
  775.                         return 0;
  776.                 // load the children
  777.                 rBoneDesc.m_numChildren = pEntity->nChildren;
  778.                 rBoneDesc.m_nOffsetChildren = nChildrenIndexBase - nBoneIndex;
  779.                 for (int nChild = 0; nChild < pEntity->nChildren; ++nChild)
  780.                 {
  781.                         if (!RecursiveBoneLoader(nBoneIndex, nChildrenIndexBase + nChild))
  782.                                 return 0;
  783.                 }
  784.         }
  785.         else
  786.         {
  787.                 rBoneDesc.m_numChildren = 0;
  788.                 rBoneDesc.m_nOffsetChildren = 0;
  789.         }
  790.         return m_numBones;
  791. }
  792.  
  793. namespace
  794. {
  795. struct BoneVertex
  796. {
  797.         Vec3 pos;
  798.         int  matId;
  799.         int  faceIndex;
  800.         int  cornerIndex;
  801. };
  802.  
  803. struct BoneVertexComparator
  804. {
  805.         bool operator()(const BoneVertex& v0, const BoneVertex& v1) const
  806.         {
  807.                 int res = memcmp(&v0.pos, &v1.pos, sizeof(v0.pos));
  808.                 // The 'if' block below prevents sharing vertices between faces with different materials.
  809.                 // Note: you can comment the block out to enable sharing and decreases # of resulting
  810.                 // vertices in case of multi-material geometry.
  811.                 if (res == 0)
  812.                 {
  813.                         res = v0.matId - v1.matId;
  814.                 }
  815.                 return res < 0;
  816.         }
  817. };
  818. }
  819.  
  820. static bool CompactBoneVertices(
  821.   DynArray<Vec3>& outArrPositions,
  822.   DynArray<char>& outArrMaterials,
  823.   DynArray<uint16>& outArrIndices,
  824.   const int inVertexCount,
  825.   const CryVertex* const inVertices,
  826.   const int inFaceCount,
  827.   const CryFace* const inFaces)
  828. {
  829.         outArrPositions.clear();
  830.         outArrMaterials.clear();
  831.         outArrIndices.clear();
  832.  
  833.         DynArray<BoneVertex> verts;
  834.         verts.reserve(inFaceCount * 3);
  835.  
  836.         outArrMaterials.reserve(inFaceCount);
  837.  
  838.         for (int i = 0; i < inFaceCount; ++i)
  839.         {
  840.                 outArrMaterials.push_back(inFaces[i].MatID);
  841.  
  842.                 for (int j = 0; j < 3; ++j)
  843.                 {
  844.                         const int vIdx = inFaces[i][j];
  845.                         if (vIdx < 0 || vIdx >= inVertexCount)
  846.                         {
  847.                                 return false;
  848.                         }
  849.                         BoneVertex v;
  850.                         v.pos = inVertices[vIdx].p;
  851.                         v.matId = inFaces[i].MatID;
  852.                         v.faceIndex = i;
  853.                         v.cornerIndex = j;
  854.                         verts.push_back(v);
  855.                 }
  856.         }
  857.  
  858.         std::sort(verts.begin(), verts.end(), BoneVertexComparator());
  859.  
  860.         outArrPositions.reserve(inVertexCount);   // preallocating by using a good enough guess
  861.         outArrIndices.resize(3 * inFaceCount, -1);
  862.  
  863.         int outVertexCount = 0;
  864.         for (int i = 0; i < verts.size(); ++i)
  865.         {
  866.                 if (i == 0 || BoneVertexComparator()(verts[i - 1], verts[i]))
  867.                 {
  868.                         outArrPositions.push_back(verts[i].pos);
  869.                         ++outVertexCount;
  870.                         if (outVertexCount > (1 << 16))
  871.                         {
  872.                                 return false;
  873.                         }
  874.                 }
  875.                 outArrIndices[verts[i].faceIndex * 3 + verts[i].cornerIndex] = outVertexCount - 1;
  876.         }
  877.  
  878.         // Making sure that the code above has no bugs
  879.         for (int i = 0; i < outArrIndices.size(); ++i)
  880.         {
  881.                 if (outArrIndices[i] < 0)
  882.                 {
  883.                         return false;
  884.                 }
  885.         }
  886.  
  887.         return true;
  888. }
  889.  
  890. //////////////////////////////////////////////////////////////////////////
  891. bool CLoaderCGF::ReadBoneMesh(IChunkFile::ChunkDesc* pChunkDesc)
  892. {
  893.         if (pChunkDesc->chunkVersion != MESH_CHUNK_DESC_0745::VERSION &&
  894.             pChunkDesc->chunkVersion != MESH_CHUNK_DESC_0745::COMPATIBLE_OLD_VERSION)
  895.         {
  896.                 m_LastError.Format(
  897.                   "Unknown version (0x%x) of BoneMesh chunk. The only supported versions are 0x%x and 0x%x.",
  898.                   (uint)pChunkDesc->chunkVersion,
  899.                   (uint)MESH_CHUNK_DESC_0745::VERSION,
  900.                   (uint)MESH_CHUNK_DESC_0745::COMPATIBLE_OLD_VERSION);
  901.                 return false;
  902.         }
  903.  
  904.         if (pChunkDesc->size < sizeof(MESH_CHUNK_DESC_0745))
  905.         {
  906.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Bad chunk size");
  907.                 return false;
  908.         }
  909.  
  910.         MESH_CHUNK_DESC_0745* const pMeshChunk = (MESH_CHUNK_DESC_0745*)pChunkDesc->data;
  911.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  912.         SwapEndian(*pMeshChunk, bSwapEndianness);
  913.         pChunkDesc->bSwapEndian = false;
  914.  
  915.         if (pMeshChunk->nVerts <= 0)
  916.         {
  917.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Bad vertex count (%d)", pMeshChunk->nVerts);
  918.                 return false;
  919.         }
  920.         if (pMeshChunk->nFaces <= 0)
  921.         {
  922.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Bad face count (%d)", pMeshChunk->nFaces);
  923.                 return false;
  924.         }
  925.         if (pMeshChunk->nTVerts != 0)
  926.         {
  927.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Texture coordinates found (%d)", pMeshChunk->nTVerts);
  928.                 return false;
  929.         }
  930.         if (pMeshChunk->flags1 != 0 || pMeshChunk->flags2 != 0)
  931.         {
  932.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Flags are not 0 (0x%x, 0x%x)", (int)pMeshChunk->flags1, (int)pMeshChunk->flags2);
  933.                 return false;
  934.         }
  935.  
  936.         // prepare vertices
  937.         void* pRawData = pMeshChunk + 1;
  938.         CryVertex* const pSrcVertices = (CryVertex*)pRawData;
  939.         SwapEndian(pSrcVertices, pMeshChunk->nVerts, bSwapEndianness);
  940.         if ((const char*)(pSrcVertices + pMeshChunk->nVerts) > (const char*)pRawData + (pChunkDesc->size - sizeof(*pMeshChunk)))
  941.         {
  942.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Vertex data are truncated");
  943.                 return false;
  944.         }
  945.         pRawData = pSrcVertices + pMeshChunk->nVerts;
  946.  
  947.         // prepare indices and MatIDs
  948.         CryFace* const pSrcFaces = (CryFace*)pRawData;
  949.         SwapEndian(pSrcFaces, pMeshChunk->nFaces, bSwapEndianness);
  950.         if ((const char*)(pSrcFaces + pMeshChunk->nFaces) > (const char*)pRawData + (pChunkDesc->size - sizeof(*pMeshChunk)))
  951.         {
  952.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Vertex data are truncated");
  953.                 return false;
  954.         }
  955.  
  956.         PhysicalProxy pbm;
  957.  
  958.         pbm.ChunkID = pChunkDesc->chunkId;
  959.  
  960.         // Bone meshes may contain many vertices sharing positions, so we
  961.         // call CompactBoneVertices() to get vertices with unique positions only
  962.         if (!CompactBoneVertices(
  963.               pbm.m_arrPoints,
  964.               pbm.m_arrMaterials,
  965.               pbm.m_arrIndices,
  966.               pMeshChunk->nVerts,
  967.               pSrcVertices,
  968.               pMeshChunk->nFaces,
  969.               pSrcFaces))
  970.         {
  971.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Bad geometry (indices are out range or too many vertices in mesh)");
  972.                 return false;
  973.         }
  974.  
  975.         // SS: I have no idea why we used this magic number of vertices (60000). I just keep it as is.
  976.         if (pbm.m_arrPoints.size() > 60000)
  977.         {
  978.                 m_LastError.Format("CLoaderCGF::ReadBoneMesh: Bad vertex count (%d)", pbm.m_arrPoints.size());
  979.                 return false;
  980.         }
  981.  
  982.         for (int i = 0, n = pbm.m_arrPoints.size(); i < n; ++i)
  983.         {
  984.                 pbm.m_arrPoints[i] *= VERTEX_SCALE;
  985.         }
  986.  
  987.         CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  988.         pSkinningInfo->m_arrPhyBoneMeshes.push_back(pbm);
  989.  
  990.         return true;
  991. }
  992.  
  993. //////////////////////////////////////////////////////////////////////////
  994. bool CLoaderCGF::ReadCompiledBones(IChunkFile::ChunkDesc* pChunkDesc)
  995. {
  996.         FUNCTION_PROFILER_3DENGINE;
  997.  
  998.         COMPILED_BONE_CHUNK_DESC_0800* const pBIPChunk = (COMPILED_BONE_CHUNK_DESC_0800*)pChunkDesc->data;
  999.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1000.         SwapEndian(*pBIPChunk, bSwapEndianness);
  1001.         pChunkDesc->bSwapEndian = false;
  1002.  
  1003.         if (pChunkDesc->chunkVersion == pBIPChunk->VERSION)
  1004.         {
  1005.                 CryBoneDescData_Comp* const pSrcVertices = (CryBoneDescData_Comp*)(pBIPChunk + 1);
  1006.                 const uint32 nDataSize = pChunkDesc->size - sizeof(COMPILED_BONE_CHUNK_DESC_0800);
  1007.                 const uint32 numBones = nDataSize / sizeof(CryBoneDescData_Comp);
  1008.                 CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  1009.                 pSkinningInfo->m_arrBonesDesc.resize(numBones);
  1010.                 SwapEndian(pSrcVertices, (size_t)numBones, bSwapEndianness);
  1011.  
  1012.                 for (uint32 i = 0; i < numBones; i++)
  1013.                 {
  1014.                         pSkinningInfo->m_arrBonesDesc[i].m_nControllerID = pSrcVertices[i].m_nControllerID;
  1015.                         memcpy(
  1016.                           &pSkinningInfo->m_arrBonesDesc[i].m_fMass,
  1017.                           &pSrcVertices[i].m_fMass,
  1018.                           (INT_PTR)&pSrcVertices[i + 1] - (INT_PTR)&pSrcVertices[i].m_fMass);
  1019.                         for (uint32 j = 0; j < 2; j++)
  1020.                         {
  1021.                                 pSkinningInfo->m_arrBonesDesc[i].m_PhysInfo[j].pPhysGeom = (phys_geometry*)(INT_PTR)pSrcVertices[i].m_PhysInfo[j].nPhysGeom;
  1022.                                 memcpy(
  1023.                                   &pSkinningInfo->m_arrBonesDesc[i].m_PhysInfo[j].flags,
  1024.                                   &pSrcVertices[i].m_PhysInfo[j].flags,
  1025.                                   (INT_PTR)&pSrcVertices[i].m_PhysInfo[j + 1] - (INT_PTR)&pSrcVertices[i].m_PhysInfo[j].flags);
  1026.                         }
  1027.                 }
  1028.  
  1029.                 m_CompiledBones = true;
  1030.                 return true;
  1031.         }
  1032.  
  1033.         m_LastError.Format("Unknown version of compiled bone chunk");
  1034.         return false;
  1035. }
  1036.  
  1037. //////////////////////////////////////////////////////////////////////////
  1038. bool CLoaderCGF::ReadCompiledPhysicalBones(IChunkFile::ChunkDesc* pChunkDesc)
  1039. {
  1040.         FUNCTION_PROFILER_3DENGINE;
  1041.  
  1042.         COMPILED_PHYSICALBONE_CHUNK_DESC_0800* const pChunk = (COMPILED_PHYSICALBONE_CHUNK_DESC_0800*)pChunkDesc->data;
  1043.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1044.         SwapEndian(*pChunk, bSwapEndianness);
  1045.         pChunkDesc->bSwapEndian = false;
  1046.  
  1047.         if (pChunkDesc->chunkVersion == pChunk->VERSION)
  1048.         {
  1049.                 BONE_ENTITY* pSrcVertices = (BONE_ENTITY*)(pChunk + 1);
  1050.                 const uint32 nDataSize = pChunkDesc->size - sizeof(COMPILED_PHYSICALBONE_CHUNK_DESC_0800);
  1051.                 const uint32 numBones = nDataSize / sizeof(BONE_ENTITY);
  1052.                 CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  1053.                 pSkinningInfo->m_arrBoneEntities.resize(numBones);
  1054.                 SwapEndian(pSrcVertices, (size_t)numBones, bSwapEndianness);
  1055.                 for (uint32 i = 0; i < numBones; i++)
  1056.                 {
  1057.                         pSkinningInfo->m_arrBoneEntities[i] = pSrcVertices[i];
  1058.                 }
  1059.  
  1060.                 m_CompiledBones = true;
  1061.                 return true;
  1062.         }
  1063.  
  1064.         m_LastError.Format("Unknown version of compiled physical bone chunk");
  1065.         return false;
  1066. }
  1067.  
  1068. //////////////////////////////////////////////////////////////////////////
  1069. bool CLoaderCGF::ReadCompiledPhysicalProxies(IChunkFile::ChunkDesc* pChunkDesc)
  1070. {
  1071.         FUNCTION_PROFILER_3DENGINE;
  1072.  
  1073.         // Note that this chunk type often contains non-aligned data. Because of that
  1074.         // we use chunk's data only after memcpy()'ing them.
  1075.  
  1076.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1077.  
  1078.         COMPILED_PHYSICALPROXY_CHUNK_DESC_0800 chunk;
  1079.         memcpy(&chunk, pChunkDesc->data, sizeof(chunk));
  1080.         SwapEndian(chunk, bSwapEndianness);
  1081.  
  1082.         // Fixing bug of an old format: numPhysicalProxies was stored in little-endian
  1083.         // format when chunk header had 'big-endian' flag set.
  1084.         if (chunk.numPhysicalProxies > 0xffff)
  1085.         {
  1086.                 SwapEndianBase(&chunk.numPhysicalProxies, 1);
  1087.         }
  1088.  
  1089.         if (pChunkDesc->chunkVersion == chunk.VERSION)
  1090.         {
  1091.                 const uint8* rawdata = ((const uint8*)pChunkDesc->data) + sizeof(chunk);
  1092.                 const uint32 numPhysicalProxies = chunk.numPhysicalProxies;
  1093.  
  1094.                 for (uint32 i = 0; i < numPhysicalProxies; ++i)
  1095.                 {
  1096.                         SMeshPhysicalProxyHeader header;
  1097.  
  1098.                         memcpy(&header, rawdata, sizeof(header));
  1099.                         SwapEndian(header, bSwapEndianness);
  1100.                         rawdata += sizeof(header);
  1101.  
  1102.                         if (header.ChunkID > 0xffff)
  1103.                         {
  1104.                                 SwapEndianBase(&header.ChunkID, 1);
  1105.                         }
  1106.  
  1107.                         PhysicalProxy sm;
  1108.  
  1109.                         sm.ChunkID = header.ChunkID;
  1110.  
  1111.                         //store the vertices
  1112.                         static_assert(sizeof(sm.m_arrPoints[0]) == sizeof(Vec3), "Invalid type size!");
  1113.                         sm.m_arrPoints.resize(header.numPoints);
  1114.                         size_t size = sizeof(sm.m_arrPoints[0]) * header.numPoints;
  1115.                         if (size > 0)
  1116.                         {
  1117.                                 memcpy(sm.m_arrPoints.begin(), rawdata, size);
  1118.                                 SwapEndian(sm.m_arrPoints.begin(), (size_t)header.numPoints, bSwapEndianness);
  1119.                                 rawdata += size;
  1120.                         }
  1121.  
  1122.                         //store the indices
  1123.                         static_assert(sizeof(sm.m_arrIndices[0]) == sizeof(uint16), "Invalid type size!");
  1124.                         sm.m_arrIndices.resize(header.numIndices);
  1125.                         size = sizeof(sm.m_arrIndices[0]) * header.numIndices;
  1126.                         if (size > 0)
  1127.                         {
  1128.                                 memcpy(sm.m_arrIndices.begin(), rawdata, size);
  1129.                                 SwapEndian(sm.m_arrIndices.begin(), (size_t)header.numIndices, bSwapEndianness);
  1130.                                 rawdata += size;
  1131.                         }
  1132.  
  1133.                         //store the materials
  1134.                         static_assert(sizeof(sm.m_arrMaterials[0]) == sizeof(uint8), "Invalid type size!");
  1135.                         sm.m_arrMaterials.resize(header.numMaterials);
  1136.                         size = sizeof(sm.m_arrMaterials[0]) * header.numMaterials;
  1137.                         if (size > 0)
  1138.                         {
  1139.                                 memcpy(sm.m_arrMaterials.begin(), rawdata, size);
  1140.                                 SwapEndian(sm.m_arrMaterials.begin(), (size_t)header.numMaterials, bSwapEndianness);
  1141.                                 rawdata += size;
  1142.                         }
  1143.  
  1144.                         m_pCGF->GetSkinningInfo()->m_arrPhyBoneMeshes.push_back(sm);
  1145.                 }
  1146.                 return true;
  1147.         }
  1148.  
  1149.         m_LastError.Format("Unknown version of compiled physical proxies chunk");
  1150.         return false;
  1151. }
  1152.  
  1153. //////////////////////////////////////////////////////////////////////////
  1154. bool CLoaderCGF::ReadCompiledMorphTargets(IChunkFile::ChunkDesc* pChunkDesc)
  1155. {
  1156.         FUNCTION_PROFILER_3DENGINE;
  1157.  
  1158.         // Note that this chunk type often contains non-aligned data. Because of that
  1159.         // we use chunk's data only after memcpy()'ing them.
  1160.  
  1161.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1162.  
  1163.         COMPILED_MORPHTARGETS_CHUNK_DESC_0800 chunk;
  1164.         memcpy(&chunk, pChunkDesc->data, sizeof(chunk));
  1165.         SwapEndian(chunk, bSwapEndianness);
  1166.  
  1167.         if (pChunkDesc->chunkVersion == chunk.VERSION || pChunkDesc->chunkVersion == chunk.VERSION1)
  1168.         {
  1169.                 const uint8* rawdata = ((const uint8*)pChunkDesc->data) + sizeof(chunk);
  1170.  
  1171.                 CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  1172.                 for (uint32 i = 0; i < chunk.numMorphTargets; ++i)
  1173.                 {
  1174.                         MorphTargetsPtr pSm = new MorphTargets;
  1175.  
  1176.                         SMeshMorphTargetHeader header;
  1177.  
  1178.                         memcpy(&header, rawdata, sizeof(header));
  1179.                         SwapEndian(header, bSwapEndianness);
  1180.                         rawdata += sizeof(header);
  1181.  
  1182.                         pSm->MeshID = header.MeshID;
  1183.  
  1184.                         pSm->m_strName = string((const char*)rawdata);
  1185.                         rawdata += header.NameLength;
  1186.  
  1187.                         // store the internal vertices&indices of morph-target
  1188.                         static_assert(sizeof(pSm->m_arrIntMorph[0]) == sizeof(SMeshMorphTargetVertex), "Invalid type size!");
  1189.                         pSm->m_arrIntMorph.resize(header.numIntVertices);
  1190.                         size_t size = sizeof(pSm->m_arrIntMorph[0]) * header.numIntVertices;
  1191.                         if (size > 0)
  1192.                         {
  1193.                                 memcpy(pSm->m_arrIntMorph.begin(), rawdata, size);
  1194.                                 SwapEndian(pSm->m_arrIntMorph.begin(), (size_t)header.numIntVertices, bSwapEndianness);
  1195.                                 rawdata += size;
  1196.                         }
  1197.  
  1198.                         // store the external vertices&indices of morph-target
  1199.                         static_assert(sizeof(pSm->m_arrExtMorph[0]) == sizeof(SMeshMorphTargetVertex), "Invalid type size!");
  1200.                         pSm->m_arrExtMorph.resize(header.numExtVertices);
  1201.                         size = sizeof(pSm->m_arrExtMorph[0]) * header.numExtVertices;
  1202.                         if (size > 0)
  1203.                         {
  1204.                                 memcpy(pSm->m_arrExtMorph.begin(), rawdata, size);
  1205.                                 SwapEndian(pSm->m_arrExtMorph.begin(), (size_t)header.numExtVertices, bSwapEndianness);
  1206.                                 rawdata += size;
  1207.                         }
  1208.  
  1209.                         pSkinningInfo->m_arrMorphTargets.push_back(pSm);
  1210.                 }
  1211.                 return true;
  1212.         }
  1213.  
  1214.         m_LastError.Format("Unknown version of compiled morph targets chunk");
  1215.         return false;
  1216. }
  1217.  
  1218. //////////////////////////////////////////////////////////////////////////
  1219. bool CLoaderCGF::ReadCompiledIntFaces(IChunkFile::ChunkDesc* pChunkDesc)
  1220. {
  1221.         FUNCTION_PROFILER_3DENGINE;
  1222.  
  1223.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1224.         pChunkDesc->bSwapEndian = false;
  1225.  
  1226.         if (pChunkDesc->chunkVersion == COMPILED_INTFACES_CHUNK_DESC_0800::VERSION)
  1227.         {
  1228.                 TFace* const pSrc = (TFace*)pChunkDesc->data;
  1229.                 const uint32 numIntFaces = pChunkDesc->size / sizeof(pSrc[0]);
  1230.                 CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  1231.                 pSkinningInfo->m_arrIntFaces.resize(numIntFaces);
  1232.                 SwapEndian(pSrc, (size_t)numIntFaces, bSwapEndianness);
  1233.                 for (uint32 i = 0; i < numIntFaces; ++i)
  1234.                 {
  1235.                         pSkinningInfo->m_arrIntFaces[i] = pSrc[i];
  1236.                 }
  1237.                 m_CompiledMesh |= 2;
  1238.                 return true;
  1239.         }
  1240.  
  1241.         m_LastError.Format("Unknown version of compiled int faces chunk");
  1242.         return false;
  1243. }
  1244.  
  1245. //////////////////////////////////////////////////////////////////////////
  1246. bool CLoaderCGF::ReadCompiledIntSkinVertice(IChunkFile::ChunkDesc* pChunkDesc)
  1247. {
  1248.         FUNCTION_PROFILER_3DENGINE;
  1249.  
  1250.         COMPILED_INTSKINVERTICES_CHUNK_DESC_0800* const pBIPChunk = (COMPILED_INTSKINVERTICES_CHUNK_DESC_0800*)pChunkDesc->data;
  1251.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1252.         SwapEndian(*pBIPChunk, bSwapEndianness);
  1253.         pChunkDesc->bSwapEndian = false;
  1254.  
  1255.         if (pChunkDesc->chunkVersion == pBIPChunk->VERSION)
  1256.         {
  1257.                 IntSkinVertex* const pSrcVertices = (IntSkinVertex*)(pBIPChunk + 1);
  1258.                 const uint32 nDataSize = pChunkDesc->size - sizeof(COMPILED_INTSKINVERTICES_CHUNK_DESC_0800);
  1259.                 const uint32 numIntVertices = nDataSize / sizeof(pSrcVertices[0]);
  1260.                 CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  1261.                 pSkinningInfo->m_arrIntVertices.resize(numIntVertices);
  1262.                 SwapEndian(pSrcVertices, (size_t)numIntVertices, bSwapEndianness);
  1263.                 for (uint32 i = 0; i < numIntVertices; ++i)
  1264.                 {
  1265.                         pSkinningInfo->m_arrIntVertices[i] = pSrcVertices[i];
  1266.                 }
  1267.                 m_CompiledMesh |= 1;
  1268.                 return true;
  1269.         }
  1270.  
  1271.         m_LastError.Format("Unknown version of compiled skin vertices chunk");
  1272.         return false;
  1273. }
  1274.  
  1275. //////////////////////////////////////////////////////////////////////////
  1276. bool CLoaderCGF::ReadCompiledBonesBoxes(IChunkFile::ChunkDesc* pChunkDesc)
  1277. {
  1278.         FUNCTION_PROFILER_3DENGINE;
  1279.  
  1280.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1281.         pChunkDesc->bSwapEndian = false;
  1282.  
  1283.         if (pChunkDesc->chunkVersion == COMPILED_BONEBOXES_CHUNK_DESC_0800::VERSION ||
  1284.             pChunkDesc->chunkVersion == COMPILED_BONEBOXES_CHUNK_DESC_0800::VERSION1)
  1285.         {
  1286.                 char* pSrc = (char*)pChunkDesc->data;
  1287.  
  1288.                 CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  1289.                 pSkinningInfo->m_arrCollisions.push_back(MeshCollisionInfo());
  1290.                 MeshCollisionInfo& info = pSkinningInfo->m_arrCollisions[pSkinningInfo->m_arrCollisions.size() - 1];
  1291.  
  1292.                 static_assert(sizeof(info.m_iBoneId) == sizeof(int32), "Invalid type size!");
  1293.                 SwapEndian((int32*)pSrc, 1, bSwapEndianness);
  1294.                 memcpy(&info.m_iBoneId, pSrc, sizeof(info.m_iBoneId));
  1295.                 pSrc += sizeof(info.m_iBoneId);
  1296.  
  1297.                 static_assert(sizeof(info.m_aABB) == sizeof(AABB), "Invalid type size!");
  1298.                 SwapEndian((AABB*)pSrc, 1, bSwapEndianness);
  1299.                 memcpy(&info.m_aABB, pSrc, sizeof(info.m_aABB));
  1300.                 pSrc += sizeof(info.m_aABB);
  1301.  
  1302.                 int32 size;
  1303.                 static_assert(sizeof(size) == sizeof(int32), "Invalid type size!");
  1304.                 SwapEndian((int32*)pSrc, 1, bSwapEndianness);
  1305.                 memcpy(&size, pSrc, sizeof(size));
  1306.                 pSrc += sizeof(size);
  1307.  
  1308.                 if (size > 0)
  1309.                 {
  1310.                         static_assert(sizeof(info.m_arrIndexes[0]) == sizeof(int16), "Invalid type size!");
  1311.                         SwapEndian((int16*)pSrc, size, bSwapEndianness);
  1312.                         info.m_arrIndexes.resize(size);
  1313.                         memcpy(info.m_arrIndexes.begin(), pSrc, size * sizeof(info.m_arrIndexes[0]));
  1314.                 }
  1315.  
  1316.                 m_CompiledBonesBoxes = true;
  1317.                 return true;
  1318.         }
  1319.  
  1320.         m_LastError.Format("Unknown version of compiled bone boxes chunk");
  1321.         return false;
  1322. }
  1323.  
  1324. //////////////////////////////////////////////////////////////////////////
  1325. bool CLoaderCGF::ReadCompiledExt2IntMap(IChunkFile::ChunkDesc* pChunkDesc)
  1326. {
  1327.         FUNCTION_PROFILER_3DENGINE;
  1328.  
  1329.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1330.         pChunkDesc->bSwapEndian = false;
  1331.  
  1332.         if (pChunkDesc->chunkVersion == COMPILED_EXT2INTMAP_CHUNK_DESC_0800::VERSION)
  1333.         {
  1334.                 uint16* const pSrc = (uint16*)pChunkDesc->data;
  1335.                 const uint32 numExtVertices = pChunkDesc->size / sizeof(pSrc[0]);
  1336.                 CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  1337.                 pSkinningInfo->m_arrExt2IntMap.resize(numExtVertices);
  1338.                 SwapEndian(pSrc, (size_t)numExtVertices, bSwapEndianness);
  1339.                 for (uint32 i = 0; i < numExtVertices; ++i)
  1340.                 {
  1341.                         assert(pSrc[i] != 0xffff);
  1342.                         pSkinningInfo->m_arrExt2IntMap[i] = pSrc[i];
  1343.                 }
  1344.                 m_CompiledMesh |= 4;
  1345.                 return true;
  1346.         }
  1347.         m_LastError.Format("Unknown version of compiled Ext2Int map chunk");
  1348.         return false;
  1349. }
  1350.  
  1351. //////////////////////////////////////////////////////////////////////////
  1352. bool CLoaderCGF::ReadCompiledBreakablePhysics(IChunkFile::ChunkDesc* pChunkDesc)
  1353. {
  1354.         FUNCTION_PROFILER_3DENGINE;
  1355.  
  1356.         if (pChunkDesc->chunkVersion != BREAKABLE_PHYSICS_CHUNK_DESC::VERSION)
  1357.         {
  1358.                 m_LastError.Format("Unknown version of breakable physics chunk");
  1359.                 return false;
  1360.         }
  1361.  
  1362.         BREAKABLE_PHYSICS_CHUNK_DESC* const pChunk = (BREAKABLE_PHYSICS_CHUNK_DESC*)pChunkDesc->data;
  1363.         const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  1364.         SwapEndian(*pChunk, bSwapEndianness);
  1365.         pChunkDesc->bSwapEndian = false;
  1366.  
  1367.         CPhysicalizeInfoCGF* const pPi = m_pCGF->GetPhysicalizeInfo();
  1368.  
  1369.         pPi->nGranularity = pChunk->granularity;
  1370.         pPi->nMode = pChunk->nMode;
  1371.         pPi->pRetVtx = new Vec3[pPi->nRetVtx = pChunk->nRetVtx];
  1372.         pPi->pRetTets = new int[(pPi->nRetTets = pChunk->nRetTets) * 4];
  1373.         if (pPi->nRetVtx > 0)
  1374.         {
  1375.                 char* pData = ((char*)pChunk) + sizeof(BREAKABLE_PHYSICS_CHUNK_DESC);
  1376.                 SwapEndian((Vec3*)pData, pPi->nRetVtx, bSwapEndianness);
  1377.                 memcpy(pPi->pRetVtx, pData, pPi->nRetVtx * sizeof(Vec3));
  1378.         }
  1379.         if (pPi->nRetTets > 0)
  1380.         {
  1381.                 char* pData = ((char*)pChunk) + sizeof(BREAKABLE_PHYSICS_CHUNK_DESC) + pPi->nRetVtx * sizeof(Vec3);
  1382.                 SwapEndian((int*)pData, pPi->nRetTets * 4, bSwapEndianness);
  1383.                 memcpy(pPi->pRetTets, pData, pPi->nRetTets * sizeof(int) * 4);
  1384.         }
  1385.         return true;
  1386. }
  1387.  
  1388. /////////////////////////////////////////////////////////////////////////////////////////
  1389. /////////////////////////////////////////////////////////////////////////////////////////
  1390. /////////////////////////////////////////////////////////////////////////////////////////
  1391. /////////////////////////////////////////////////////////////////////////////////////////
  1392.  
  1393. #if defined(RESOURCE_COMPILER)
  1394.  
  1395. namespace ProcessSkinningHelpers
  1396. {
  1397.  
  1398. struct RBatch
  1399. {
  1400.         uint32 startFace;
  1401.         uint32 numFaces;
  1402.         uint32 MaterialID;
  1403. };
  1404.  
  1405. bool SplitIntoRBatches(
  1406.   std::vector<SMeshSubset>& arrSubsets,
  1407.   std::vector<TFace>& arrExtFaces,
  1408.   string& lastError,
  1409.   const CMesh* const pMesh)
  1410. {
  1411.         arrSubsets.clear();
  1412.         arrExtFaces.clear();
  1413.  
  1414.         const int numSubsets = pMesh->m_subsets.size();
  1415.  
  1416.         //--------------------------------------------------------------------------
  1417.         //---         sort render-batches for hardware skinning                  ---
  1418.         //--------------------------------------------------------------------------
  1419.  
  1420.         std::vector<RBatch> arrBatches;
  1421.         for (uint32 m = 0; m < numSubsets; m++)
  1422.         {
  1423.                 const int numFacesTotal = pMesh->GetIndexCount() / 3;
  1424.                 const int firstFace = pMesh->m_subsets[m].nFirstIndexId / 3;
  1425.                 const int numFaces = pMesh->m_subsets[m].nNumIndices / 3;
  1426.                 if (firstFace >= numFacesTotal)
  1427.                 {
  1428.                         lastError.Format("Wrong first face id index (%i out of %i)", (int)firstFace, (int)numFacesTotal);
  1429.                         return false;
  1430.                 }
  1431.                 if (numFaces <= 0 || firstFace + numFaces > numFacesTotal)
  1432.                 {
  1433.                         lastError.Format("Bad # of faces (%i)", (int)numFaces);
  1434.                         return false;
  1435.                 }
  1436.  
  1437.                 {
  1438.                         RBatch rbatch;
  1439.                         rbatch.MaterialID = pMesh->m_subsets[m].nMatID;
  1440.                         rbatch.startFace = arrExtFaces.size();
  1441.                         rbatch.numFaces = numFaces;
  1442.  
  1443.                         arrBatches.push_back(rbatch);
  1444.                 }
  1445.  
  1446.                 vtx_idx* const pIndices = &pMesh->m_pIndices[firstFace * 3];
  1447.  
  1448.                 for (int i = 0; i < numFaces * 3; i += 3)
  1449.                 {
  1450.                         arrExtFaces.push_back(TFace(pIndices[i + 0], pIndices[i + 1], pIndices[i + 2]));
  1451.                 }
  1452.         }
  1453.  
  1454.         //-------------------------------------------------------------------------
  1455.         //---                 check if material batches overlap                 ---
  1456.         //-------------------------------------------------------------------------
  1457.         {
  1458.                 for (uint32 m = 0; m < numSubsets; m++)
  1459.                 {
  1460.                         uint32 vmin = 0xffffffff;
  1461.                         uint32 vmax = 0x00000000;
  1462.  
  1463.                         uint32 nFirstFaceId = pMesh->m_subsets[m].nFirstIndexId / 3;
  1464.                         uint32 numFaces = pMesh->m_subsets[m].nNumIndices / 3;
  1465.                         for (uint32 f = 0; f < numFaces; f++)
  1466.                         {
  1467.                                 uint32 i0 = arrExtFaces[nFirstFaceId + f].i0;
  1468.                                 uint32 i1 = arrExtFaces[nFirstFaceId + f].i1;
  1469.                                 uint32 i2 = arrExtFaces[nFirstFaceId + f].i2;
  1470.                                 if (vmin > i0) vmin = i0;
  1471.                                 if (vmin > i1) vmin = i1;
  1472.                                 if (vmin > i2) vmin = i2;
  1473.                                 if (vmax < i0) vmax = i0;
  1474.                                 if (vmax < i1) vmax = i1;
  1475.                                 if (vmax < i2) vmax = i2;
  1476.                         }
  1477.                         uint32 a = pMesh->m_subsets[m].nFirstVertId;
  1478.                         uint32 b = pMesh->m_subsets[m].nNumVerts;
  1479.                         if (pMesh->m_subsets[m].nFirstVertId != vmin ||
  1480.                             pMesh->m_subsets[m].nNumVerts != vmax - vmin + 1)
  1481.                         {
  1482.                                 lastError = "Overlapping material batches";
  1483.                                 return false;
  1484.                         }
  1485.                 }
  1486.  
  1487.                 for (uint32 a = 0; a < numSubsets; a++)
  1488.                 {
  1489.                         for (uint32 b = 0; b < numSubsets; b++)
  1490.                         {
  1491.                                 if (a == b) continue;
  1492.                                 uint32 amin = pMesh->m_subsets[a].nFirstVertId;
  1493.                                 uint32 amax = pMesh->m_subsets[a].nNumVerts + amin - 1;
  1494.                                 uint32 bmin = pMesh->m_subsets[b].nFirstVertId;
  1495.                                 uint32 bmax = pMesh->m_subsets[b].nNumVerts + bmin - 1;
  1496.                                 if (amax >= bmin && amin <= bmax)
  1497.                                 {
  1498.                                         lastError = "Overlapping material batches";
  1499.                                         return false;
  1500.                                 }
  1501.                         }
  1502.                 }
  1503.         }
  1504.  
  1505.         arrSubsets.resize(arrBatches.size());           //subsets of the mesh as they appear in video-mem
  1506.         for (uint32 m = 0; m < arrBatches.size(); m++)
  1507.         {
  1508.                 uint32 mat = arrBatches[m].MaterialID;
  1509.                 //      assert(mat<testcheck);
  1510.                 uint32 r = 0;
  1511.                 bool found = false;
  1512.                 const uint32 numSubsets = pMesh->m_subsets.size();
  1513.                 for (r = 0; r < numSubsets; r++)
  1514.                 {
  1515.                         if (mat == pMesh->m_subsets[r].nMatID)
  1516.                         {
  1517.                                 found = true;
  1518.                                 break;
  1519.                         }
  1520.                 }
  1521.  
  1522.                 if (!found)
  1523.                 {
  1524.                         lastError.Format("Mesh subset for material %i was not found.", (int)mat);
  1525.                         return false;
  1526.                 }
  1527.  
  1528.                 arrSubsets[m] = pMesh->m_subsets[r];
  1529.                 arrSubsets[m].nMatID = arrBatches[m].MaterialID;
  1530.                 arrSubsets[m].nFirstIndexId = arrBatches[m].startFace * 3;
  1531.                 arrSubsets[m].nNumIndices = arrBatches[m].numFaces * 3;
  1532.  
  1533.                 //Make sure the all vertices are in range if indices. This is important for ATI-kards
  1534.                 uint32 sml_index = 0xffffffff;
  1535.                 uint32 big_index = 0x00000000;
  1536.                 uint32 sface = arrBatches[m].startFace;
  1537.                 uint32 eface = arrBatches[m].numFaces + sface;
  1538.                 for (uint32 i = sface; i < eface; i++)
  1539.                 {
  1540.                         uint32 i0 = arrExtFaces[i].i0;
  1541.                         uint32 i1 = arrExtFaces[i].i1;
  1542.                         uint32 i2 = arrExtFaces[i].i2;
  1543.                         if (sml_index > i0) sml_index = i0;
  1544.                         if (sml_index > i1) sml_index = i1;
  1545.                         if (sml_index > i2) sml_index = i2;
  1546.                         if (big_index < i0) big_index = i0;
  1547.                         if (big_index < i1) big_index = i1;
  1548.                         if (big_index < i2) big_index = i2;
  1549.                 }
  1550.                 arrSubsets[m].nFirstVertId = sml_index;
  1551.                 arrSubsets[m].nNumVerts = big_index - sml_index + 1;
  1552.         }
  1553.  
  1554.         return true;
  1555. }
  1556.  
  1557. }
  1558. #endif
  1559.  
  1560. bool CLoaderCGF::ProcessSkinning()
  1561. {
  1562.         FUNCTION_PROFILER_3DENGINE;
  1563.  
  1564.         CSkinningInfo* const pSkinningInfo = m_pCGF->GetSkinningInfo();
  1565.  
  1566.         const uint32 numBones = pSkinningInfo->m_arrBonesDesc.size();
  1567.  
  1568.         //do we have an initialized skeleton?
  1569.         if (numBones == 0)
  1570.         {
  1571.                 return true;
  1572.         }
  1573.  
  1574.         if (numBones > MAX_NUMBER_OF_BONES)
  1575.         {
  1576.                 m_LastError.Format("Too many bones: %i. Reached limit of %i bones.", int(numBones), int(MAX_NUMBER_OF_BONES));
  1577.                 return false;
  1578.         }
  1579.  
  1580. #if !defined(RESOURCE_COMPILER)
  1581.  
  1582.         if (m_CompiledMesh != 7 && m_CompiledBones != 1)
  1583.         {
  1584.                 CryFatalError("%s tried to load a noncompiled mesh: %s", __FUNCTION__, m_filename);
  1585.                 m_LastError.Format("noncompiled mesh");
  1586.                 return false;
  1587.         }
  1588.         return true;
  1589.  
  1590. #else
  1591.         using namespace ProcessSkinningHelpers;
  1592.  
  1593.         if (m_CompiledBones == 0)
  1594.         {
  1595.                 //process raw bone-data
  1596.                 assert(m_numBonenameList < 2);
  1597.                 assert(m_numBoneInitialPos < 2);
  1598.                 assert(m_numBoneHierarchy < 2);
  1599.  
  1600.                 const uint32 numIPos = m_arrInitPose34.size();
  1601.                 if (numBones != numIPos)
  1602.                 {
  1603.                         m_LastError.Format("Skeleton-Initial-Positions are missing.");
  1604.                         return false;
  1605.                 }
  1606.  
  1607.                 const uint32 numBonenames = m_arrBoneNameTable.size();
  1608.                 if (numBones != numBonenames)
  1609.                 {
  1610.                         m_LastError.Format("Number of bones does not match in the bone hierarchy chunk (%d) and the bone name chunk (%d)", numBones, numBonenames);
  1611.                         return false;
  1612.                 }
  1613.  
  1614.                 //------------------------------------------------------------------------------------------
  1615.                 //----     use the old chunks to initialize the bone structure  ----------------------------
  1616.                 //------------------------------------------------------------------------------------------
  1617.                 static const char* const arrLimbNames[] =
  1618.                 {
  1619.                         "L UpperArm",
  1620.                         "R UpperArm",
  1621.                         "L Thigh",
  1622.                         "R Thigh"
  1623.                 };
  1624.                 static const int limbNamesCount = CRY_ARRAY_COUNT(arrLimbNames);
  1625.                 const uint32 numBonesDesc = pSkinningInfo->m_arrBonesDesc.size();
  1626.                 for (uint32 nBone = 0; nBone < numBonesDesc; ++nBone)
  1627.                 {
  1628.                         uint32 nBoneID = m_arrIndexToId[nBone];
  1629.                         if (nBoneID == ~0)
  1630.                                 continue;
  1631.  
  1632.                         pSkinningInfo->m_arrBonesDesc[nBone].m_DefaultW2B = m_arrInitPose34[nBoneID].GetInvertedFast();
  1633.                         pSkinningInfo->m_arrBonesDesc[nBone].m_DefaultB2W = m_arrInitPose34[nBoneID];
  1634.  
  1635.                         memset(pSkinningInfo->m_arrBonesDesc[nBone].m_arrBoneName, 0, sizeof(pSkinningInfo->m_arrBonesDesc[nBone].m_arrBoneName));
  1636.                         cry_strcpy(pSkinningInfo->m_arrBonesDesc[nBone].m_arrBoneName, m_arrBoneNameTable[nBoneID].c_str());
  1637.  
  1638.                         //fill in names of the bones and the limb IDs
  1639.                         uint32 nBoneId = m_arrIndexToId[nBone];
  1640.                         pSkinningInfo->m_arrBonesDesc[nBone].m_nLimbId = -1;
  1641.                         for (int j = 0; j < limbNamesCount; ++j)
  1642.                         {
  1643.                                 if (strstr(m_arrBoneNameTable[nBoneId], arrLimbNames[j]))
  1644.                                 {
  1645.                                         pSkinningInfo->m_arrBonesDesc[nBone].m_nLimbId = j;
  1646.                                         break;
  1647.                                 }
  1648.                         }
  1649.                 }
  1650.         }
  1651.  
  1652.         if (m_CompiledMesh != 0 && m_CompiledMesh != 7)
  1653.         {
  1654.                 m_LastError.Format("Found mix of new and old chunks");
  1655.                 return false;
  1656.         }
  1657.  
  1658.         if (m_CompiledMesh)
  1659.         {
  1660.                 return true;
  1661.         }
  1662.  
  1663.         //------------------------------------------------------------------------------------------
  1664.         //----     get the mesh    -----------------------------------------------------------------
  1665.         //------------------------------------------------------------------------------------------
  1666.  
  1667.         CNodeCGF* pNode = 0;
  1668.         for (int i = 0; i < m_pCGF->GetNodeCount(); ++i)
  1669.         {
  1670.                 if (m_pCGF->GetNode(i)->type == CNodeCGF::NODE_MESH && m_pCGF->GetNode(i)->pMesh)
  1671.                 {
  1672.                         pNode = m_pCGF->GetNode(i);
  1673.                         break;
  1674.                 }
  1675.         }
  1676.         if (!pNode)
  1677.         {
  1678.                 return true;
  1679.         }
  1680.  
  1681.         CMesh* const pMesh = pNode->pMesh;
  1682.  
  1683.         if (!pMesh)
  1684.         {
  1685.                 m_LastError = "No mesh found";
  1686.                 return false;
  1687.         }
  1688.  
  1689.         if (pMesh->m_pPositionsF16)
  1690.         {
  1691.                 m_LastError.Format("Unexpected format of vertex positions: f16");
  1692.                 return false;
  1693.         }
  1694.  
  1695.         const uint32 numIntVertices = pMesh->GetVertexCount();
  1696.  
  1697.         /* -----------------------------------------------------------------------------
  1698.            // NOTE: Related to commented out code below!
  1699.            // Color0 is copied into two distinct streams in the Engine:
  1700.            // as Color in the Base stream and as indices in the Shape
  1701.            // Deformation stream. The latter needs for the values to be
  1702.            // snapped while the former doesn't.
  1703.            // Snapping used to happen here at compiling/loading time, however
  1704.            // this will destroy the Color information that might be needed in
  1705.            // the Base stream.
  1706.            // We are now snapping the values when copying this data into the
  1707.            // Shape Deformation stream, while leaving the data copied in the
  1708.            // Base stream untouched. A properer solution would be to create an
  1709.            // additional chunk in the file and completely decouple the two
  1710.            // datasets.
  1711.  
  1712.            if (pMesh->m_pColor0)
  1713.            {
  1714.            //-----------------------------------------------------------------
  1715.            //--- do a color-snap on all vcolors and calculate index        ---
  1716.            //-----------------------------------------------------------------
  1717.            for (uint32 i=0; i<numIntVertices; ++i)
  1718.            {
  1719.            pMesh->m_pColor0[i].r = (pMesh->m_pColor0[i].r>0x80) ? 0xff : 0x00;
  1720.            pMesh->m_pColor0[i].g = (pMesh->m_pColor0[i].g>0x80) ? 0xff : 0x00;
  1721.            pMesh->m_pColor0[i].b = (pMesh->m_pColor0[i].b>0x80) ? 0xff : 0x00;
  1722.            pMesh->m_pColor0[i].a = 0;
  1723.            //calculate the index (this is the only value we need in the vertex-shader)
  1724.            if (pMesh->m_pColor0[i].r) pMesh->m_pColor0[i].a|=1;
  1725.            if (pMesh->m_pColor0[i].g) pMesh->m_pColor0[i].a|=2;
  1726.            if (pMesh->m_pColor0[i].b) pMesh->m_pColor0[i].a|=4;
  1727.            }
  1728.            }
  1729.            ----------------------------------------------------------------------------- */
  1730.  
  1731.         //--------------------------------------------------------------
  1732.         //---        copy the links into geometry info               ---
  1733.         //--------------------------------------------------------------
  1734.         {
  1735.                 const uint32 numLinks = m_arrLinksTmp.size();
  1736.                 if (numIntVertices != numLinks)
  1737.                 {
  1738.                         m_LastError.Format("Different number of vertices (%i) and vertex links (%i)", (int)numIntVertices, (int)numLinks);
  1739.                         return false;
  1740.                 }
  1741.                 assert(!m_arrIdToIndex.empty());
  1742.  
  1743.                 for (uint32 i = 0; i < numIntVertices; ++i)
  1744.                 {
  1745.                         MeshUtils::VertexLinks& links = m_arrLinksTmp[i];
  1746.  
  1747.                         for (int j = 0; j < (int)links.links.size(); ++j)
  1748.                         {
  1749.                                 MeshUtils::VertexLinks::Link& cl = links.links[j];
  1750.                                 if (cl.boneId >= 0 && cl.boneId < (int)m_arrIdToIndex.size())
  1751.                                 {
  1752.                                         cl.boneId = m_arrIdToIndex[cl.boneId];
  1753.                                 }
  1754.                                 else
  1755.                                 {
  1756.                                         // bone index is out of range
  1757.                                         // if you get this assert, most probably there is desynchronization between different LODs of the same model
  1758.                                         // - all of them must be exported with exactly the same skeletons.
  1759.                                         assert(0);
  1760.                                         cl.boneId = 0;
  1761.                                 }
  1762.                         }
  1763.  
  1764.                         const char* const err = links.Normalize(MeshUtils::VertexLinks::eSort_ByWeight, 0.0f, (int)links.links.size());
  1765.                         if (err)
  1766.                         {
  1767.                                 m_LastError.Format("Internal error in skin compiler: %s", err);
  1768.                                 return false;
  1769.                         }
  1770.  
  1771.                         // Paranoid checks
  1772.                         {
  1773.                                 float w = 0;
  1774.                                 for (int j = 0; j < (int)links.links.size(); ++j)
  1775.                                 {
  1776.                                         w += links.links[j].weight;
  1777.                                 }
  1778.                                 if (fabsf(w - 1.0f) > 0.005f)
  1779.                                 {
  1780.                                         m_LastError.Format("Internal error in skin compiler: %s", "sum of weights is not 1.0");
  1781.                                         return false;
  1782.                                 }
  1783.  
  1784.                                 for (int j = 1; j < (int)links.links.size(); ++j)
  1785.                                 {
  1786.                                         if (links.links[j - 1].weight < links.links[j].weight)
  1787.                                         {
  1788.                                                 m_LastError.Format("Internal error in skin compiler: %s", "links are not sorted by weight");
  1789.                                                 return false;
  1790.                                         }
  1791.                                 }
  1792.                         }
  1793.                 }
  1794.         }
  1795.  
  1796.         //---------------------------------------------------------------------
  1797.         // create internal SkinBuffer
  1798.         //---------------------------------------------------------------------
  1799.         bool bHasExtraBoneMappings = false;
  1800.         pSkinningInfo->m_arrIntVertices.resize(numIntVertices);
  1801.         for (uint32 nVert = 0; nVert < numIntVertices; ++nVert)
  1802.         {
  1803.                 const MeshUtils::VertexLinks& rLinks_base = m_arrLinksTmp[nVert];
  1804.  
  1805.                 const int numVertexLinks = (int)rLinks_base.links.size();
  1806.                 assert(numVertexLinks > 0 && numVertexLinks <= 8);
  1807.  
  1808.                 bHasExtraBoneMappings = bHasExtraBoneMappings || numVertexLinks > 4;
  1809.  
  1810.                 IntSkinVertex v;
  1811.  
  1812.                 if (pMesh->m_pColor0)
  1813.                 {
  1814.                         v.color = pMesh->m_pColor0[nVert].GetRGBA();
  1815.                 }
  1816.                 else
  1817.                 {
  1818.                         v.color = ColorB(0xff, 0xff, 0xff, 1 | 2 | 4);
  1819.                 }
  1820.  
  1821.                 v.__obsolete0 = Vec3(ZERO);
  1822.                 v.__obsolete2 = Vec3(ZERO);
  1823.  
  1824.                 const int n = std::min(numVertexLinks, (int)CRY_ARRAY_COUNT(v.weights));
  1825.                 for (int j = 0; j < n; ++j)
  1826.                 {
  1827.                         v.boneIDs[j] = rLinks_base.links[j].boneId;
  1828.                         v.weights[j] = rLinks_base.links[j].weight;
  1829.                 }
  1830.                 for (int j = n; j < CRY_ARRAY_COUNT(v.weights); ++j)
  1831.                 {
  1832.                         v.boneIDs[j] = 0;
  1833.                         v.weights[j] = 0;
  1834.                 }
  1835.  
  1836.                 // transform position from bone-space to world-space
  1837.                 v.pos = Vec3(ZERO);
  1838.                 for (int j = 0; j < numVertexLinks; ++j)
  1839.                 {
  1840.                         v.pos +=
  1841.                           pSkinningInfo->m_arrBonesDesc[rLinks_base.links[j].boneId].m_DefaultB2W *
  1842.                           rLinks_base.links[j].offset *
  1843.                           rLinks_base.links[j].weight;
  1844.                 }
  1845.  
  1846.                 pSkinningInfo->m_arrIntVertices[nVert] = v;
  1847.         }
  1848.  
  1849.         //--------------------------------------------------------------------------
  1850.         // sort faces by subsets
  1851.         //--------------------------------------------------------------------------
  1852.         // for each subset, construct an array of faces and keep the faces (in the original order) in there
  1853.         typedef std::map<uint8, std::vector<TFace>> SubsetFacesMap;
  1854.         SubsetFacesMap mapSubsetFaces;
  1855.  
  1856.         if (numIntVertices > (1 << 16))
  1857.         {
  1858.                 m_LastError.Format("Too many vertices in skin geometry: %i (max possible is %i)", numIntVertices, (1 << 16));
  1859.                 return false;
  1860.         }
  1861.  
  1862.         // put each face into its subset group;
  1863.         // the corresponding groups will be created by the map automatically
  1864.         // upon the first request of that group
  1865.         const uint32 numIntFaces = pMesh->GetFaceCount();
  1866.  
  1867.         for (uint32 i = 0; i < numIntFaces; ++i)
  1868.         {
  1869.                 const int subsetIdx = pMesh->m_pFaces[i].nSubset;
  1870.                 if (subsetIdx < 0 || subsetIdx > pMesh->m_subsets.size())
  1871.                 {
  1872.                         m_LastError.Format("Invalid subset index detected: %i (# of subsets: %i)", subsetIdx, (int)pMesh->m_subsets.size());
  1873.                         return false;
  1874.                 }
  1875.                 if (pMesh->m_subsets[subsetIdx].nMatID >= MAX_SUB_MATERIALS)
  1876.                 {
  1877.                         m_LastError.Format("Maximum number of submaterials reached (%i)", (int)MAX_SUB_MATERIALS);
  1878.                         return false;
  1879.                 }
  1880.  
  1881.                 int vIdx[3];
  1882.                 for (int j = 0; j < 3; ++j)
  1883.                 {
  1884.                         vIdx[j] = pMesh->m_pFaces[i].v[j];
  1885.                         if (vIdx[j] < 0)
  1886.                         {
  1887.                                 m_LastError.Format("Internal vertex index %i is negative (# of vertices is %i)", vIdx[j], numIntVertices);
  1888.                                 return false;
  1889.                         }
  1890.                         if (vIdx[j] >= numIntVertices)
  1891.                         {
  1892.                                 m_LastError.Format("Internal vertex index %i is out of range (# of vertices is %i)", vIdx[j], numIntVertices);
  1893.                                 return false;
  1894.                         }
  1895.                 }
  1896.                 mapSubsetFaces[subsetIdx].push_back(TFace(vIdx[0], vIdx[1], vIdx[2]));
  1897.         }
  1898.  
  1899.         if (pMesh->GetSubSetCount() != mapSubsetFaces.size())
  1900.         {
  1901.                 m_LastError.Format("Number of referenced subsets (%d) is not equal to number of stored subsets (%i)", (int)mapSubsetFaces.size(), pMesh->GetSubSetCount());
  1902.                 return false;
  1903.         }
  1904.  
  1905.         //--------------------------------------------------------------------------
  1906.         // create array with internal faces (sorted by subsets)
  1907.         //--------------------------------------------------------------------------
  1908.         {
  1909.                 pSkinningInfo->m_arrIntFaces.resize(numIntFaces);
  1910.  
  1911.                 int newFaceCount = 0;
  1912.                 for (SubsetFacesMap::iterator itMtl = mapSubsetFaces.begin(); itMtl != mapSubsetFaces.end(); ++itMtl)
  1913.                 {
  1914.                         const size_t faceCount = itMtl->second.size();
  1915.                         for (size_t f = 0; f < faceCount; ++f, ++newFaceCount)
  1916.                         {
  1917.                                 pSkinningInfo->m_arrIntFaces[newFaceCount] = itMtl->second[f];
  1918.                         }
  1919.                 }
  1920.                 assert(newFaceCount == numIntFaces);
  1921.         }
  1922.  
  1923.         // Compile contents.
  1924.         // These map from internal (original) to external (optimized) indices/vertices
  1925.         std::vector<int> arrVRemapping;
  1926.         std::vector<int> arrIRemapping;
  1927.  
  1928.         m_pCompiledCGF = MakeCompiledSkinCGF(m_pCGF, &arrVRemapping, &arrIRemapping);
  1929.         if (!m_pCompiledCGF)
  1930.         {
  1931.                 return false;
  1932.         }
  1933.         const uint32 numVRemapping = arrVRemapping.size();
  1934.         if (numVRemapping == 0)
  1935.         {
  1936.                 m_LastError = "Empty vertex remapping";
  1937.                 return false;
  1938.         }
  1939.         if (arrIRemapping.size() != numIntFaces * 3)
  1940.         {
  1941.                 m_LastError.Format("Wrong # of indices for remapping");
  1942.                 return false;
  1943.         }
  1944.  
  1945.         //allocates the external to internal map entries
  1946.         // (m_arrExt2IntMap[]: for each final vertex contains its index in initial vertex buffer)
  1947.         // TODO: in theory arrVRemapping.size() is not necessarily equals to the number of final vertices.
  1948.         // It could be bigger if a face is not referenced from any of the subsets.
  1949.         pSkinningInfo->m_arrExt2IntMap.resize(numVRemapping, ~0);
  1950.         for (uint32 i = 0; i < numIntFaces; ++i)
  1951.         {
  1952.                 const uint32 idx0 = arrVRemapping[arrIRemapping[i * 3 + 0]];
  1953.                 const uint32 idx1 = arrVRemapping[arrIRemapping[i * 3 + 1]];
  1954.                 const uint32 idx2 = arrVRemapping[arrIRemapping[i * 3 + 2]];
  1955.                 if (idx0 >= numVRemapping || idx1 >= numVRemapping || idx2 >= numVRemapping)
  1956.                 {
  1957.                         m_LastError.Format("Indices out of range");
  1958.                         return false;
  1959.                 }
  1960.                 pSkinningInfo->m_arrExt2IntMap[idx0] = pSkinningInfo->m_arrIntFaces[i].i0;
  1961.                 pSkinningInfo->m_arrExt2IntMap[idx1] = pSkinningInfo->m_arrIntFaces[i].i1;
  1962.                 pSkinningInfo->m_arrExt2IntMap[idx2] = pSkinningInfo->m_arrIntFaces[i].i2;
  1963.         }
  1964.  
  1965.         {
  1966.                 int brokenCount = 0;
  1967.                 for (uint32 i = 0; i < numVRemapping; i++)
  1968.                 {
  1969.                         if (pSkinningInfo->m_arrExt2IntMap[i] >= numIntVertices)
  1970.                         {
  1971.                                 ++brokenCount;
  1972.                                 // "Fixing" mapping allows us to comment out "return false" below (in case of an urgent need)
  1973.                                 pSkinningInfo->m_arrExt2IntMap[i] = 0;
  1974.                         }
  1975.                 }
  1976.                 if (brokenCount > 0)
  1977.                 {
  1978.                         m_LastError.Format("Remapping-table is broken. %i of %i vertices are not remapped", brokenCount, numVRemapping);
  1979.                         return false;
  1980.                 }
  1981.         }
  1982.  
  1983.         //-------------------------------------------------------------------------
  1984.  
  1985.         std::vector<SMeshSubset> arrSubsets;
  1986.         std::vector<TFace> arrExtFaces;
  1987.  
  1988.         if (!SplitIntoRBatches(arrSubsets, arrExtFaces, m_LastError, pMesh))
  1989.         {
  1990.                 return false;
  1991.         }
  1992.  
  1993.         //--------------------------------------------------------------------------
  1994.         //---              copy compiled-data back into CMesh                    ---
  1995.         //--------------------------------------------------------------------------
  1996.         for (size_t f = 0, n = arrExtFaces.size(); f < n; ++f)
  1997.         {
  1998.                 pMesh->m_pIndices[f * 3 + 0] = arrExtFaces[f].i0;
  1999.                 pMesh->m_pIndices[f * 3 + 1] = arrExtFaces[f].i1;
  2000.                 pMesh->m_pIndices[f * 3 + 2] = arrExtFaces[f].i2;
  2001.         }
  2002.  
  2003.         pMesh->m_subsets.clear();
  2004.         pMesh->m_subsets.reserve(arrSubsets.size());
  2005.         for (size_t i = 0; i < arrSubsets.size(); ++i)
  2006.         {
  2007.                 pMesh->m_subsets.push_back(arrSubsets[i]);
  2008.         }
  2009.  
  2010.         //////////////////////////////////////////////////////////////////////////
  2011.         // Create and fill bone-mapping streams.
  2012.         //////////////////////////////////////////////////////////////////////////
  2013.         {
  2014.                 pMesh->ReallocStream(CMesh::BONEMAPPING, numVRemapping);
  2015.                 if (bHasExtraBoneMappings)
  2016.                 {
  2017.                         pMesh->ReallocStream(CMesh::EXTRABONEMAPPING, numVRemapping);
  2018.                 }
  2019.  
  2020.                 for (uint32 i = 0; i < numVRemapping; ++i)
  2021.                 {
  2022.                         const uint32 index = pSkinningInfo->m_arrExt2IntMap[i];
  2023.                         const MeshUtils::VertexLinks& links = m_arrLinksTmp[index];
  2024.                         const int linkCount = (int)links.links.size();
  2025.  
  2026.                         // Convert floating point weights to integer [0;255] weights
  2027.                         int w[8];
  2028.                         {
  2029.                                 assert(linkCount <= 8);
  2030.  
  2031.                                 int wSum = 0;
  2032.                                 for (int j = 0; j < linkCount; ++j)
  2033.                                 {
  2034.                                         w[j] = (int)(links.links[j].weight * 255.0f + 0.5f);
  2035.                                         wSum += w[j];
  2036.                                 }
  2037.  
  2038.                                 // Ensure that the sum of weights is exactly 255.
  2039.                                 // Note that the code below preserves sorting by
  2040.                                 // weight in descending order.
  2041.                                 if (wSum < 255)
  2042.                                 {
  2043.                                         w[0] += 255 - wSum;
  2044.                                 }
  2045.                                 else if (wSum > 255)
  2046.                                 {
  2047.                                         for (int j = 0;; ++j)
  2048.                                         {
  2049.                                                 if (j >= linkCount - 1 || w[j] > w[j + 1])
  2050.                                                 {
  2051.                                                         --w[j];
  2052.                                                         if (--wSum == 255)
  2053.                                                         {
  2054.                                                                 break;
  2055.                                                         }
  2056.                                                         j = std::max(j - 1, 0) - 1;
  2057.                                                 }
  2058.                                         }
  2059.                                 }
  2060.  
  2061.                                 // TODO: quantization to integer values might produce zero weight links, so
  2062.                                 // it might be a good idea to delete such links. Warning: m_arrIntVertices[]
  2063.                                 // also stores (up to) four links, so we should delete matching zero-weight
  2064.                                 // links in m_arrIntVertices[] as well.
  2065.                         }
  2066.  
  2067.                         // Fill CMesh::BONEMAPPING stream
  2068.                         {
  2069.                                 const int n = std::min(linkCount, 4);
  2070.                                 for (int j = 0; j < n; ++j)
  2071.                                 {
  2072.                                         pMesh->m_pBoneMapping[i].boneIds[j] = links.links[j].boneId;
  2073.                                         pMesh->m_pBoneMapping[i].weights[j] = (uint8)w[j];
  2074.                                 }
  2075.                                 for (int j = n; j < 4; ++j)
  2076.                                 {
  2077.                                         pMesh->m_pBoneMapping[i].boneIds[j] = 0;
  2078.                                         pMesh->m_pBoneMapping[i].weights[j] = 0;
  2079.                                 }
  2080.                         }
  2081.  
  2082.                         // Fill CMesh::EXTRABONEMAPPING stream
  2083.                         if (bHasExtraBoneMappings)
  2084.                         {
  2085.                                 const int n = std::max(linkCount - 4, 0);
  2086.                                 for (int j = 0; j < n; ++j)
  2087.                                 {
  2088.                                         pMesh->m_pExtraBoneMapping[i].boneIds[j] = links.links[4 + j].boneId;
  2089.                                         pMesh->m_pExtraBoneMapping[i].weights[j] = (uint8)w[4 + j];
  2090.                                 }
  2091.                                 for (int j = n; j < 4; ++j)
  2092.                                 {
  2093.                                         pMesh->m_pExtraBoneMapping[i].boneIds[j] = 0;
  2094.                                         pMesh->m_pExtraBoneMapping[i].weights[j] = 0;
  2095.                                 }
  2096.                         }
  2097.                 }
  2098.         }
  2099.  
  2100.         // Keep original transform for morph targets
  2101.         Matrix34 mat34 = pNode->localTM * Diag33(VERTEX_SCALE, VERTEX_SCALE, VERTEX_SCALE);
  2102.  
  2103.         //////////////////////////////////////////////////////////////////////////
  2104.         // Copy shape-deformation and positions.
  2105.         //////////////////////////////////////////////////////////////////////////
  2106.         {
  2107.                 // Modify orientation, but keep translation.
  2108.                 // We need to keep translation to be able to use pivot of the node.
  2109.                 // It allows us to control coordinate origin for FP16 meshes.
  2110.                 // The translation is applied later before skinning.
  2111.                 const Matrix34 oldWorldTM = pNode->worldTM;
  2112.                 const Vec3 translation = oldWorldTM.GetTranslation();
  2113.                 pNode->worldTM = Matrix34(Matrix33(IDENTITY), translation);
  2114.  
  2115.                 // Reconstruct localTM out of new worldTM
  2116.                 if (pNode->pParent)
  2117.                 {
  2118.                         Matrix34 parentWorldInverted = pNode->pParent->worldTM;
  2119.                         parentWorldInverted.Invert();
  2120.                         pNode->localTM = parentWorldInverted * pNode->worldTM;
  2121.                 }
  2122.                 else
  2123.                 {
  2124.                         pNode->localTM = pNode->worldTM;
  2125.                 }
  2126.  
  2127.                 for (uint32 e = 0; e < numVRemapping; ++e)
  2128.                 {
  2129.                         const uint32 i = pSkinningInfo->m_arrExt2IntMap[e];
  2130.                         const IntSkinVertex& intVertex = pSkinningInfo->m_arrIntVertices[i];
  2131.                         pMesh->m_pPositions[e] = intVertex.pos - translation;
  2132.                 }
  2133.  
  2134.                 // The exporting pipeline is expected to produce pNode->worldTM
  2135.                 // with identity orientation only, but let's be paranoid and handle
  2136.                 // non-identity orientations properly as well.
  2137.  
  2138.                 const float eps = 0.001f;
  2139.                 const bool bIdentity =
  2140.                   oldWorldTM.GetColumn0().IsEquivalent(Vec3(1, 0, 0), eps) &&
  2141.                   oldWorldTM.GetColumn1().IsEquivalent(Vec3(0, 1, 0), eps) &&
  2142.                   oldWorldTM.GetColumn2().IsEquivalent(Vec3(0, 0, 1), eps);
  2143.  
  2144.                 if (!bIdentity)
  2145.                 {
  2146.                         for (uint32 e = 0; e < numVRemapping; ++e)
  2147.                         {
  2148.                                 const uint32 i = pSkinningInfo->m_arrExt2IntMap[e];
  2149.  
  2150.                                 pMesh->m_pNorms[e].RotateSafelyBy(oldWorldTM);
  2151.                                 pMesh->m_pTangents[i].RotateSafelyBy(oldWorldTM);
  2152.                         }
  2153.                 }
  2154.         }
  2155.  
  2156.         //--------------------------------------------------------------------------
  2157.         //---              prepare morph-targets                                 ---
  2158.         //--------------------------------------------------------------------------
  2159.         uint32 numMorphTargets = pSkinningInfo->m_arrMorphTargets.size();
  2160.         for (uint32 it = 0; it < numMorphTargets; ++it)
  2161.         {
  2162.                 //init internal morph-targets
  2163.                 MorphTargets* pMorphtarget = pSkinningInfo->m_arrMorphTargets[it];
  2164.                 uint32 numMorphVerts = pMorphtarget->m_arrIntMorph.size();
  2165.                 uint32 intVertexCount = pSkinningInfo->m_arrIntVertices.size();
  2166.                 for (uint32 i = 0; i < numMorphVerts; i++)
  2167.                 {
  2168.                         uint32 idx = pMorphtarget->m_arrIntMorph[i].nVertexId;
  2169.                         assert(idx < intVertexCount);
  2170.                         Vec3 mvertex = (mat34 * pMorphtarget->m_arrIntMorph[i].ptVertex) - pSkinningInfo->m_arrIntVertices[idx].pos;
  2171.                         pMorphtarget->m_arrIntMorph[i].ptVertex = mvertex;
  2172.                 }
  2173.  
  2174.                 //init external morph-targets
  2175.                 for (uint32 v = 0; v < numMorphVerts; v++)
  2176.                 {
  2177.                         uint32 idx = pMorphtarget->m_arrIntMorph[v].nVertexId;
  2178.                         Vec3 mvertex = pMorphtarget->m_arrIntMorph[v].ptVertex;
  2179.  
  2180.                         const uint16* pExtToIntMap = &pSkinningInfo->m_arrExt2IntMap[0];
  2181.                         uint32 numExtVertices = numVRemapping;
  2182.                         assert(numExtVertices);
  2183.                         for (uint32 i = 0; i < numExtVertices; ++i)
  2184.                         {
  2185.                                 uint32 index = pExtToIntMap[i];
  2186.                                 if (index == idx)
  2187.                                 {
  2188.                                         SMeshMorphTargetVertex mp;
  2189.                                         mp.nVertexId = i;
  2190.                                         mp.ptVertex = mvertex;
  2191.                                         pMorphtarget->m_arrExtMorph.push_back(mp);
  2192.                                 }
  2193.                         }
  2194.                 }
  2195.         }
  2196.  
  2197.         pMesh->m_bbox.Reset();
  2198.         for (size_t v = 0; v < numVRemapping; ++v)
  2199.         {
  2200.                 pMesh->m_bbox.Add(pMesh->m_pPositions[v]);
  2201.         }
  2202.  
  2203.         return true;
  2204. #endif
  2205. }
  2206.  
  2207. //------------------------------------------------------------------------------------------------------------------------
  2208. //------------------------------------------------------------------------------------------------------------------------
  2209. //------------------------------------------------------------------------------------------------------------------------
  2210.  
  2211. //////////////////////////////////////////////////////////////////////////
  2212. #if defined(RESOURCE_COMPILER)
  2213.  
  2214. CContentCGF* CLoaderCGF::MakeCompiledSkinCGF(
  2215.   CContentCGF* pCGF, std::vector<int>* pVertexRemapping, std::vector<int>* pIndexRemapping) PREFAST_SUPPRESS_WARNING(6262) //function uses > 32k stack space
  2216. {
  2217.         CContentCGF* const pCompiledCGF = new CContentCGF(pCGF->GetFilename());
  2218.         *pCompiledCGF->GetExportInfo() = *pCGF->GetExportInfo(); // Copy export info.
  2219.  
  2220.         // Compile mesh.
  2221.         // Note that this function cannot fill/return mapping arrays properly in case of
  2222.         // multiple meshes (because mapping is per-mesh), so we will treat multiple
  2223.         // meshes as error.
  2224.         bool bMeshFound = false;
  2225.         for (int i = 0; i < pCGF->GetNodeCount(); ++i)
  2226.         {
  2227.                 CNodeCGF* const pNodeCGF = pCGF->GetNode(i);
  2228.                 if (!pNodeCGF->pMesh || pNodeCGF->type != CNodeCGF::NODE_MESH || pNodeCGF->bPhysicsProxy)
  2229.                 {
  2230.                         continue;
  2231.                 }
  2232.  
  2233.                 if (bMeshFound)
  2234.                 {
  2235.                         m_LastError.Format("Failed to compile skinned geometry file %s - %s", pCGF->GetFilename(), "*multiple* mesh nodes aren't supported");
  2236.                         delete pCompiledCGF;
  2237.                         return 0;
  2238.                 }
  2239.  
  2240.                 bMeshFound = true;
  2241.  
  2242.                 mesh_compiler::CMeshCompiler meshCompiler;
  2243.  
  2244.                 meshCompiler.SetIndexRemapping(pIndexRemapping);
  2245.                 meshCompiler.SetVertexRemapping(pVertexRemapping);
  2246.  
  2247.                 int flags = mesh_compiler::MESH_COMPILE_TANGENTS | mesh_compiler::MESH_COMPILE_OPTIMIZE;
  2248.                 if (pCompiledCGF->GetExportInfo()->bUseCustomNormals)
  2249.                 {
  2250.                         flags |= mesh_compiler::MESH_COMPILE_USE_CUSTOM_NORMALS;
  2251.                 }
  2252.  
  2253.                 if (!meshCompiler.Compile(*pNodeCGF->pMesh, flags))
  2254.                 {
  2255.                         m_LastError.Format("Failed to compile skinned geometry file %s - %s", pCGF->GetFilename(), meshCompiler.GetLastError());
  2256.                         delete pCompiledCGF;
  2257.                         return 0;
  2258.                 }
  2259.  
  2260.                 pCompiledCGF->AddNode(pNodeCGF);
  2261.  
  2262.                 // We continue scanning just to detect if we have multiple mesh nodes (to throw an error)
  2263.         }
  2264.  
  2265.         // Compile physics proxy nodes.
  2266.         if (pCGF->GetExportInfo()->bHavePhysicsProxy)
  2267.         {
  2268.                 for (int i = 0; i < pCGF->GetNodeCount(); ++i)
  2269.                 {
  2270.                         CNodeCGF* pNodeCGF = pCGF->GetNode(i);
  2271.                         if (pNodeCGF->pMesh && pNodeCGF->bPhysicsProxy)
  2272.                         {
  2273.                                 // Compile physics proxy mesh.
  2274.                                 mesh_compiler::CMeshCompiler meshCompiler;
  2275.                                 if (!meshCompiler.Compile(*pNodeCGF->pMesh, mesh_compiler::MESH_COMPILE_OPTIMIZE))
  2276.                                 {
  2277.                                         m_LastError.Format("Failed to compile skinned geometry in node %s in file %s - %s", pNodeCGF->name, pCGF->GetFilename(), meshCompiler.GetLastError());
  2278.                                         delete pCompiledCGF;
  2279.                                         return 0;
  2280.                                 }
  2281.                         }
  2282.                         pCompiledCGF->AddNode(pNodeCGF);
  2283.                 }
  2284.         }
  2285.  
  2286.         return pCompiledCGF;
  2287. }
  2288.  
  2289. #endif
  2290.  
  2291. //////////////////////////////////////////////////////////////////////////
  2292. bool CLoaderCGF::LoadExportFlagsChunk(IChunkFile::ChunkDesc* pChunkDesc)
  2293. {
  2294.         if (pChunkDesc->chunkVersion != EXPORT_FLAGS_CHUNK_DESC::VERSION)
  2295.         {
  2296.                 m_LastError.Format("Unknown version of export flags chunk");
  2297.                 return false;
  2298.         }
  2299.  
  2300.         EXPORT_FLAGS_CHUNK_DESC& chunk = *(EXPORT_FLAGS_CHUNK_DESC*)pChunkDesc->data;
  2301.         SwapEndian(chunk, pChunkDesc->bSwapEndian);
  2302.         pChunkDesc->bSwapEndian = false;
  2303.  
  2304.         CExportInfoCGF* pExportInfo = m_pCGF->GetExportInfo();
  2305.         if (chunk.flags & EXPORT_FLAGS_CHUNK_DESC::MERGE_ALL_NODES)
  2306.                 pExportInfo->bMergeAllNodes = true;
  2307.         else
  2308.                 pExportInfo->bMergeAllNodes = false;
  2309.  
  2310.         if (chunk.flags & EXPORT_FLAGS_CHUNK_DESC::HAVE_AUTO_LODS)
  2311.                 pExportInfo->bHaveAutoLods = true;
  2312.         else
  2313.                 pExportInfo->bHaveAutoLods = false;
  2314.  
  2315.         if (chunk.flags & EXPORT_FLAGS_CHUNK_DESC::USE_CUSTOM_NORMALS)
  2316.                 pExportInfo->bUseCustomNormals = true;
  2317.         else
  2318.                 pExportInfo->bUseCustomNormals = false;
  2319.  
  2320.         if (chunk.flags & EXPORT_FLAGS_CHUNK_DESC::WANT_F32_VERTICES)
  2321.                 pExportInfo->bWantF32Vertices = true;
  2322.         else
  2323.                 pExportInfo->bWantF32Vertices = false;
  2324.  
  2325.         if (chunk.flags & EXPORT_FLAGS_CHUNK_DESC::EIGHT_WEIGHTS_PER_VERTEX)
  2326.                 pExportInfo->b8WeightsPerVertex = true;
  2327.         else
  2328.                 pExportInfo->b8WeightsPerVertex = false;
  2329.  
  2330.         if (chunk.flags & EXPORT_FLAGS_CHUNK_DESC::MAKE_VCLOTH)
  2331.                 pExportInfo->bMakeVCloth = true;
  2332.         else
  2333.                 pExportInfo->bMakeVCloth = false;
  2334.  
  2335.         return true;
  2336. }
  2337.  
  2338. inline const char* stristr2(const char* szString, const char* szSubstring)
  2339. {
  2340.         int nSuperstringLength = (int)strlen(szString);
  2341.         int nSubstringLength = (int)strlen(szSubstring);
  2342.  
  2343.         for (int nSubstringPos = 0; nSubstringPos <= nSuperstringLength - nSubstringLength; ++nSubstringPos)
  2344.         {
  2345.                 if (strnicmp(szString + nSubstringPos, szSubstring, nSubstringLength) == 0)
  2346.                         return szString + nSubstringPos;
  2347.         }
  2348.         return NULL;
  2349. }
  2350.  
  2351. //////////////////////////////////////////////////////////////////////////
  2352. bool CLoaderCGF::LoadNodeChunk(IChunkFile::ChunkDesc* pChunkDesc, bool bJustGeometry)
  2353. {
  2354.         if (pChunkDesc->chunkVersion != NODE_CHUNK_DESC_0824::VERSION &&
  2355.             pChunkDesc->chunkVersion != NODE_CHUNK_DESC_0824::COMPATIBLE_OLD_VERSION)
  2356.         {
  2357.                 m_LastError.Format(
  2358.                   "Unknown version (0x%x) of Node chunk. The only supported versions are 0x%x and 0x%x.",
  2359.                   (uint)pChunkDesc->chunkVersion,
  2360.                   (uint)NODE_CHUNK_DESC_0824::VERSION,
  2361.                   (uint)NODE_CHUNK_DESC_0824::COMPATIBLE_OLD_VERSION);
  2362.                 return false;
  2363.         }
  2364.  
  2365.         NODE_CHUNK_DESC_0824* nodeChunk = (NODE_CHUNK_DESC_0824*)pChunkDesc->data;
  2366.         assert(nodeChunk);
  2367.         SwapEndian(*nodeChunk, pChunkDesc->bSwapEndian);
  2368.         pChunkDesc->bSwapEndian = false;
  2369.  
  2370.         CNodeCGF* pNodeCGF = Construct<CNodeCGF>(InplaceFactory(m_pDestructFnc), m_pAllocFnc);
  2371.         m_pCGF->AddNode(pNodeCGF);
  2372.  
  2373.         cry_strcpy(pNodeCGF->name, nodeChunk->name);
  2374.  
  2375.         // Fill node object.
  2376.         pNodeCGF->nChunkId = pChunkDesc->chunkId;
  2377.         pNodeCGF->nParentChunkId = nodeChunk->ParentID;
  2378.         pNodeCGF->nObjectChunkId = nodeChunk->ObjectID;
  2379.         pNodeCGF->pParent = 0;
  2380.         pNodeCGF->pMesh = 0;
  2381.  
  2382.         pNodeCGF->pos_cont_id = nodeChunk->pos_cont_id;
  2383.         pNodeCGF->rot_cont_id = nodeChunk->rot_cont_id;
  2384.         pNodeCGF->scl_cont_id = nodeChunk->scl_cont_id;
  2385.  
  2386.         pNodeCGF->pMaterial = 0;
  2387.         if (nodeChunk->MatID > 0)
  2388.         {
  2389.                 pNodeCGF->pMaterial = LoadMaterialFromChunk(nodeChunk->MatID);
  2390.                 if (!pNodeCGF->pMaterial)
  2391.                 {
  2392.                         return false;
  2393.                 }
  2394.         }
  2395.  
  2396.         {
  2397.                 const float* const pMat = &nodeChunk->tm[0][0];
  2398.  
  2399.                 pNodeCGF->localTM.SetFromVectors(
  2400.                   Vec3(pMat[0], pMat[1], pMat[2]),
  2401.                   Vec3(pMat[4], pMat[5], pMat[6]),
  2402.                   Vec3(pMat[8], pMat[9], pMat[10]),
  2403.                   Vec3(pMat[12] * VERTEX_SCALE, pMat[13] * VERTEX_SCALE, pMat[14] * VERTEX_SCALE));
  2404.         }
  2405.  
  2406.         if (nodeChunk->PropStrLen > 0)
  2407.         {
  2408.                 pNodeCGF->properties.Format("%.*s", nodeChunk->PropStrLen, ((const char*)nodeChunk) + sizeof(*nodeChunk));
  2409.         }
  2410.  
  2411.         if (stristr2(nodeChunk->name, CGF_NODE_NAME_PHYSICS_PROXY0) ||
  2412.             stristr2(nodeChunk->name, CGF_NODE_NAME_PHYSICS_PROXY1) ||
  2413.             stristr2(nodeChunk->name, CGF_NODE_NAME_PHYSICS_PROXY2))
  2414.         {
  2415.                 pNodeCGF->type = CNodeCGF::NODE_HELPER;
  2416.                 pNodeCGF->bPhysicsProxy = true;
  2417.                 m_pCGF->GetExportInfo()->bHavePhysicsProxy = true;
  2418.         }
  2419.         else if (nodeChunk->name[0] == '$')
  2420.         {
  2421.                 pNodeCGF->type = CNodeCGF::NODE_HELPER;
  2422.                 pNodeCGF->bPhysicsProxy = false;
  2423.         }
  2424.         else
  2425.         {
  2426.                 pNodeCGF->type = CNodeCGF::NODE_MESH;
  2427.                 pNodeCGF->bPhysicsProxy = false;
  2428.         }
  2429.  
  2430.         // Check if valid object node.
  2431.         if (nodeChunk->ObjectID > 0)
  2432.         {
  2433.                 IChunkFile::ChunkDesc* const pObjChunkDesc = m_pChunkFile->FindChunkById(nodeChunk->ObjectID);
  2434.                 if (!pObjChunkDesc)
  2435.                 {
  2436.                         assert(pObjChunkDesc);
  2437.                         m_LastError.Format("Failed to find chunk with id %d", nodeChunk->ObjectID);
  2438.                         return false;
  2439.                 }
  2440.                 if (pObjChunkDesc->chunkType == ChunkType_Mesh)
  2441.                 {
  2442.                         if (pNodeCGF->type == CNodeCGF::NODE_HELPER)
  2443.                                 pNodeCGF->helperType = HP_GEOMETRY;
  2444.                         if (!LoadGeomChunk(pNodeCGF, pObjChunkDesc))
  2445.                                 return false;
  2446.                 }
  2447.                 else if (!bJustGeometry)
  2448.                 {
  2449.                         if (pObjChunkDesc->chunkType == ChunkType_Helper)
  2450.                         {
  2451.                                 pNodeCGF->type = CNodeCGF::NODE_HELPER;
  2452.                                 if (!LoadHelperChunk(pNodeCGF, pObjChunkDesc))
  2453.                                         return false;
  2454.                         }
  2455.                 }
  2456.         }
  2457.         else
  2458.         {
  2459.                 //      pNodeCGF->type = CNodeCGF::NODE_HELPER;
  2460.                 //      pNodeCGF->helperType = HP_POINT;
  2461.                 //      pNodeCGF->helperSize = Vec3(0.01f,0.01f,0.01f);
  2462.         }
  2463.         return true;
  2464. }
  2465.  
  2466. //////////////////////////////////////////////////////////////////////////
  2467. bool CLoaderCGF::LoadHelperChunk(CNodeCGF* pNode, IChunkFile::ChunkDesc* pChunkDesc)
  2468. {
  2469.         FUNCTION_PROFILER_3DENGINE;
  2470.  
  2471.         if (pChunkDesc->chunkVersion != HELPER_CHUNK_DESC::VERSION)
  2472.         {
  2473.                 m_LastError.Format("Unknown version of Helper chunk");
  2474.                 return false;
  2475.         }
  2476.  
  2477.         HELPER_CHUNK_DESC& chunk = *(HELPER_CHUNK_DESC*)pChunkDesc->data;
  2478.         assert(&chunk);
  2479.  
  2480.         SwapEndian(chunk, pChunkDesc->bSwapEndian);
  2481.         pChunkDesc->bSwapEndian = false;
  2482.  
  2483.         // Fill node object.
  2484.         pNode->helperType = chunk.type;
  2485.         pNode->helperSize = chunk.size;
  2486.         return true;
  2487. }
  2488.  
  2489. //////////////////////////////////////////////////////////////////////////
  2490. void CLoaderCGF::SetupMeshSubsets(CMesh& mesh, CMaterialCGF* pMaterialCGF)
  2491. {
  2492.         if (!m_pCGF->GetExportInfo()->bCompiledCGF && mesh.m_subsets.empty())
  2493.         {
  2494.                 const DynArray<int>& usedMaterialIds = m_pCGF->GetUsedMaterialIDs();
  2495.                 for (int i = 0; i < usedMaterialIds.size(); ++i)
  2496.                 {
  2497.                         SMeshSubset meshSubset;
  2498.                         meshSubset.nMatID = usedMaterialIds[i];
  2499.                         meshSubset.nPhysicalizeType = PHYS_GEOM_TYPE_NONE;
  2500.                         mesh.m_subsets.push_back(meshSubset);
  2501.                 }
  2502.         }
  2503.  
  2504.         // Copy physicalization type from material to subsets (and fix subsets' matId if needed)
  2505.         if (pMaterialCGF)
  2506.         {
  2507.                 for (int i = 0; i < mesh.m_subsets.size(); ++i)
  2508.                 {
  2509.                         SMeshSubset& meshSubset = mesh.m_subsets[i];
  2510.                         if (pMaterialCGF->subMaterials.size() > 0)
  2511.                         {
  2512.                                 int id = meshSubset.nMatID;
  2513.                                 if (id >= (int)pMaterialCGF->subMaterials.size())
  2514.                                 {
  2515.                                         // Let's use 3dsMax's approach of handling material ids out of range
  2516.                                         id %= (int)pMaterialCGF->subMaterials.size();
  2517.                                 }
  2518.  
  2519.                                 if (id >= 0 && pMaterialCGF->subMaterials[id] != nullptr)
  2520.                                 {
  2521.                                         meshSubset.nPhysicalizeType = pMaterialCGF->subMaterials[id]->nPhysicalizeType;
  2522.                                 }
  2523.                                 else
  2524.                                 {
  2525.                                         Warning("Submaterial %d is not available for subset %d in %s", meshSubset.nMatID, i, m_filename);
  2526.                                 }
  2527.                         }
  2528.                         else
  2529.                         {
  2530.                                 meshSubset.nPhysicalizeType = pMaterialCGF->nPhysicalizeType;
  2531.                         }
  2532.                 }
  2533.         }
  2534. }
  2535.  
  2536. //////////////////////////////////////////////////////////////////////////
  2537. bool CLoaderCGF::LoadGeomChunk(CNodeCGF* pNode, IChunkFile::ChunkDesc* pChunkDesc)
  2538. {
  2539.         FUNCTION_PROFILER_3DENGINE;
  2540.  
  2541.         // First check if this geometry chunk was already loaded by some node.
  2542.         int nNumNodes = m_pCGF->GetNodeCount();
  2543.         for (int i = 0; i < nNumNodes; i++)
  2544.         {
  2545.                 CNodeCGF* pOldNode = m_pCGF->GetNode(i);
  2546.                 if (pOldNode != pNode && pOldNode->nObjectChunkId == pChunkDesc->chunkId)
  2547.                 {
  2548.                         pNode->pMesh = pOldNode->pMesh;
  2549.                         pNode->pSharedMesh = pOldNode;
  2550.                         return true;
  2551.                 }
  2552.         }
  2553.  
  2554.         assert(pChunkDesc && pChunkDesc->chunkType == ChunkType_Mesh);
  2555.  
  2556.         if (pChunkDesc->chunkVersion == MESH_CHUNK_DESC_0801::VERSION ||
  2557.             pChunkDesc->chunkVersion == MESH_CHUNK_DESC_0801::COMPATIBLE_OLD_VERSION)
  2558.         {
  2559.                 m_pCGF->GetExportInfo()->bCompiledCGF = true;
  2560.                 return LoadCompiledMeshChunk(pNode, pChunkDesc);
  2561.         }
  2562.  
  2563.         // Uncompiled format
  2564.         if (pChunkDesc->chunkVersion == MESH_CHUNK_DESC_0745::VERSION ||
  2565.             pChunkDesc->chunkVersion == MESH_CHUNK_DESC_0745::COMPATIBLE_OLD_VERSION)
  2566.         {
  2567. #if !defined(RESOURCE_COMPILER)
  2568.                 m_LastError.Format("%s: non-compiled geometry chunk in %s", __FUNCTION__, m_filename);
  2569.                 return false;
  2570. #else
  2571.                 m_pCGF->GetExportInfo()->bCompiledCGF = false;
  2572.  
  2573.                 const int maxLinkCount =
  2574.                   m_pCGF->GetExportInfo()->b8WeightsPerVertex
  2575.                   ? 8
  2576.                   : ((m_maxWeightsPerVertex <= 8) ? m_maxWeightsPerVertex : 8);      // CMesh doesn't support more than 8 weights
  2577.  
  2578.                 const bool bSwapEndianness = pChunkDesc->bSwapEndian;
  2579.                 pChunkDesc->bSwapEndian = false;
  2580.  
  2581.                 uint8* pMeshChunkData = (uint8*)pChunkDesc->data;
  2582.  
  2583.                 MESH_CHUNK_DESC_0745* chunk;
  2584.                 StepData(chunk, pMeshChunkData, 1, bSwapEndianness);
  2585.  
  2586.                 if (!(chunk->flags2 & MESH_CHUNK_DESC_0745::FLAG2_HAS_TOPOLOGY_IDS))
  2587.                 {
  2588.                         m_LastError.Format("%s: obsolete non-compiled geometry chunk format in %s", __FUNCTION__, m_filename);
  2589.                         return false;
  2590.                 }
  2591.  
  2592.                 //////////////////////////////////////////////////////////////////////////
  2593.                 // Preparing source mesh data (may contain duplicate vertices)
  2594.                 //////////////////////////////////////////////////////////////////////////
  2595.  
  2596.                 MeshUtils::Mesh mesh;
  2597.                 const char* err = 0;
  2598.  
  2599.                 if (chunk->nVerts <= 0)
  2600.                 {
  2601.                         m_LastError.Format("%s: missing vertices in %s", __FUNCTION__, m_filename);
  2602.                         return false;
  2603.                 }
  2604.                 if (chunk->nFaces <= 0)
  2605.                 {
  2606.                         m_LastError.Format("%s: missing faces in %s", __FUNCTION__, m_filename);
  2607.                         return false;
  2608.                 }
  2609.                 if (chunk->nTVerts != 0 && chunk->nTVerts != chunk->nVerts)
  2610.                 {
  2611.                         m_LastError.Format("%s: Number of texture coordinates doesn't match number of vertices", __FUNCTION__);
  2612.                         return false;
  2613.                 }
  2614.  
  2615.                 // Preparing positions and normals
  2616.                 {
  2617.                         CryVertex* p;
  2618.                         StepData(p, pMeshChunkData, chunk->nVerts, bSwapEndianness);
  2619.  
  2620.                         err = mesh.SetPositions(&p->p.x, chunk->nVerts, sizeof(*p), VERTEX_SCALE);       // VERTEX_SCALE - to convert from centimeters to meters
  2621.                         if (!err)
  2622.                         {
  2623.                                 err = mesh.SetNormals(&p->n.x, chunk->nVerts, sizeof(*p));
  2624.                         }
  2625.  
  2626.                         if (err)
  2627.                         {
  2628.                                 m_LastError.Format("%s: Failed: %s", __FUNCTION__, err);
  2629.                                 return false;
  2630.                         }
  2631.                 }
  2632.  
  2633.                 // Preparing faces and face material IDs
  2634.                 {
  2635.                         CryFace* p;
  2636.                         StepData(p, pMeshChunkData, chunk->nFaces, bSwapEndianness);
  2637.                         err = mesh.SetFaces(&p->v0, chunk->nFaces, sizeof(*p));
  2638.                         if (!err)
  2639.                         {
  2640.                                 err = mesh.SetFaceMatIds(&p->MatID, chunk->nFaces, sizeof(*p), MAX_SUB_MATERIALS - 1);
  2641.                         }
  2642.                         if