BVB Source Codes

CRYENGINE Show CGFSaver.cpp Source code

Return Download CRYENGINE: download CGFSaver.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4.  
  5. #if defined(RESOURCE_COMPILER) || defined(INCLUDE_SAVECGF)
  6.  
  7.         #include "CGFSaver.h"
  8.         #include "ChunkData.h"
  9.         #include "ChunkFile.h"
  10.         #include <CryMath/QTangent.h>
  11.         #include "VClothSaver.h"
  12.  
  13.         #if defined(RESOURCE_COMPILER)
  14.  
  15.                 #include "../../../Tools/RC/ResourceCompilerPC/CGF/LoaderCAF.h"
  16.                 #include "../../../Tools/RC/ResourceCompilerPC/CGF/AnimSaver.h"
  17.  
  18.         #endif
  19.  
  20.         #define SCALE_TO_CGF 100.0f
  21.  
  22. //////////////////////////////////////////////////////////////////////////
  23. CSaverCGF::CSaverCGF(CChunkFile& chunkFile)
  24. {
  25.         assert(&chunkFile);
  26.         m_pChunkFile = &chunkFile;
  27.         m_bDoNotSaveMeshData = false;
  28.         m_bDoNotSaveNonMeshData = false;
  29.         m_bSavePhysicsMeshes = true;
  30.         m_bCompactVertexStreams = false;
  31.         m_bComputeSubsetTexelDensity = false;
  32.         m_pCGF = 0;
  33. }
  34.  
  35. //////////////////////////////////////////////////////////////////////////
  36. void CSaverCGF::SetMeshDataSaving(bool bEnable)
  37. {
  38.         m_bDoNotSaveMeshData = !bEnable;
  39. }
  40.  
  41. void CSaverCGF::SetNonMeshDataSaving(bool bEnable)
  42. {
  43.         m_bDoNotSaveNonMeshData = !bEnable;
  44. }
  45.  
  46. void CSaverCGF::SetSavePhysicsMeshes(bool bEnable)
  47. {
  48.         m_bSavePhysicsMeshes = bEnable;
  49. }
  50.  
  51. void CSaverCGF::SetVertexStreamCompacting(bool bEnable)
  52. {
  53.         m_bCompactVertexStreams = bEnable;
  54. }
  55.  
  56. void CSaverCGF::SetSubsetTexelDensityComputing(bool bEnable)
  57. {
  58.         m_bComputeSubsetTexelDensity = bEnable;
  59. }
  60.  
  61. //////////////////////////////////////////////////////////////////////////
  62. void CSaverCGF::SaveContent(
  63.   CContentCGF* pCGF,
  64.   bool bSwapEndian,
  65.   bool bStorePositionsAsF16,
  66.   bool bUseQtangents,
  67.   bool bStoreIndicesAsU16)
  68. {
  69.         SetContent(pCGF);
  70.  
  71.         SaveExportFlags(bSwapEndian);
  72.         SaveMaterials(bSwapEndian);
  73.         #if defined(RESOURCE_COMPILER)
  74.         SaveNodes(bSwapEndian, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16, 0);
  75.         #else
  76.         SaveNodes(bSwapEndian, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16);
  77.         #endif
  78.         SaveBreakablePhysics(bSwapEndian);
  79.         SaveFoliage();
  80. }
  81.  
  82. //////////////////////////////////////////////////////////////////////////
  83. void CSaverCGF::SetContent(CContentCGF* pCGF)
  84. {
  85.         m_pCGF = pCGF;
  86. }
  87.  
  88. //////////////////////////////////////////////////////////////////////////
  89. int CSaverCGF::SaveCompiledBones(bool bSwapEndian, void* pData, int nSize, int version)
  90. {
  91.         COMPILED_BONE_CHUNK_DESC_0800 chunk;
  92.         ZeroStruct(chunk);
  93.         SwapEndian(chunk, bSwapEndian);
  94.  
  95.         CChunkData chunkData;
  96.         chunkData.Add(chunk);
  97.         chunkData.AddData(pData, nSize);
  98.  
  99.         return m_pChunkFile->AddChunk(
  100.           ChunkType_CompiledBones,
  101.           version,
  102.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  103.           chunkData.GetData(), chunkData.GetSize());
  104. }
  105.  
  106. //////////////////////////////////////////////////////////////////////////
  107. int CSaverCGF::SaveCompiledPhysicalBones(bool bSwapEndian, void* pData, int nSize, int version)
  108. {
  109.         COMPILED_PHYSICALBONE_CHUNK_DESC_0800 chunk;
  110.         ZeroStruct(chunk);
  111.         SwapEndian(chunk, bSwapEndian);
  112.  
  113.         CChunkData chunkData;
  114.         chunkData.Add(chunk);
  115.         chunkData.AddData(pData, nSize);
  116.  
  117.         return m_pChunkFile->AddChunk(
  118.           ChunkType_CompiledPhysicalBones,
  119.           version,
  120.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  121.           chunkData.GetData(), chunkData.GetSize());
  122. }
  123.  
  124. //////////////////////////////////////////////////////////////////////////
  125. int CSaverCGF::SaveCompiledPhysicalProxis(bool bSwapEndian, void* pData, int nSize, uint32 numPhysicalProxies, int version)
  126. {
  127.         COMPILED_PHYSICALPROXY_CHUNK_DESC_0800 chunk;
  128.         ZeroStruct(chunk);
  129.         chunk.numPhysicalProxies = numPhysicalProxies;
  130.         SwapEndian(chunk, bSwapEndian);
  131.  
  132.         CChunkData chunkData;
  133.         chunkData.Add(chunk);
  134.         chunkData.AddData(pData, nSize);
  135.  
  136.         return m_pChunkFile->AddChunk(
  137.           ChunkType_CompiledPhysicalProxies,
  138.           version,
  139.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  140.           chunkData.GetData(), chunkData.GetSize());
  141. }
  142.  
  143. //////////////////////////////////////////////////////////////////////////
  144. int CSaverCGF::SaveCompiledMorphTargets(bool bSwapEndian, void* pData, int nSize, uint32 numMorphTargets, int version)
  145. {
  146.         COMPILED_MORPHTARGETS_CHUNK_DESC_0800 chunk;
  147.         ZeroStruct(chunk);
  148.         chunk.numMorphTargets = numMorphTargets;
  149.         SwapEndian(chunk, bSwapEndian);
  150.  
  151.         CChunkData chunkData;
  152.         chunkData.Add(chunk);
  153.         chunkData.AddData(pData, nSize);
  154.  
  155.         return m_pChunkFile->AddChunk(
  156.           ChunkType_CompiledMorphTargets,
  157.           version,
  158.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  159.           chunkData.GetData(), chunkData.GetSize());
  160. }
  161.  
  162. //////////////////////////////////////////////////////////////////////////
  163. int CSaverCGF::SaveCompiledIntSkinVertices(bool bSwapEndian, void* pData, int nSize, int version)
  164. {
  165.         COMPILED_INTSKINVERTICES_CHUNK_DESC_0800 chunk;
  166.         ZeroStruct(chunk);
  167.         SwapEndian(chunk, bSwapEndian);
  168.  
  169.         CChunkData chunkData;
  170.         chunkData.Add(chunk);
  171.         chunkData.AddData(pData, nSize);
  172.  
  173.         return m_pChunkFile->AddChunk(
  174.           ChunkType_CompiledIntSkinVertices,
  175.           version,
  176.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  177.           chunkData.GetData(), chunkData.GetSize());
  178. }
  179.  
  180. //////////////////////////////////////////////////////////////////////////
  181. int CSaverCGF::SaveCompiledIntFaces(bool bSwapEndian, void* pData, int nSize, int version)
  182. {
  183.         CChunkData chunkData;
  184.         chunkData.AddData(pData, nSize);
  185.  
  186.         return m_pChunkFile->AddChunk(
  187.           ChunkType_CompiledIntFaces,
  188.           version,
  189.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  190.           chunkData.GetData(), chunkData.GetSize());
  191. }
  192.  
  193. //////////////////////////////////////////////////////////////////////////
  194. int CSaverCGF::SaveCompiledBoneBox(bool bSwapEndian, void* pData, int nSize, int version)
  195. {
  196.         CChunkData chunkData;
  197.         chunkData.AddData(pData, nSize);
  198.  
  199.         return m_pChunkFile->AddChunk(
  200.           ChunkType_BonesBoxes,
  201.           version,
  202.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  203.           chunkData.GetData(), chunkData.GetSize());
  204. }
  205.  
  206. //////////////////////////////////////////////////////////////////////////
  207. int CSaverCGF::SaveCompiledExt2IntMap(bool bSwapEndian, void* pData, int nSize, int version)
  208. {
  209.         CChunkData chunkData;
  210.         chunkData.AddData(pData, nSize);
  211.  
  212.         return m_pChunkFile->AddChunk(
  213.           ChunkType_CompiledExt2IntMap,
  214.           version,
  215.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  216.           chunkData.GetData(), chunkData.GetSize());
  217. }
  218.  
  219. //////////////////////////////////////////////////////////////////////////
  220. int CSaverCGF::SaveBones(bool bSwapEndian, void* pData, int numBones, int nSize)
  221. {
  222.         BONEANIM_CHUNK_DESC_0290 chunk;
  223.         ZeroStruct(chunk);
  224.         chunk.nBones = numBones;
  225.         SwapEndian(chunk, bSwapEndian);
  226.  
  227.         CChunkData chunkData;
  228.         chunkData.Add(chunk);
  229.         chunkData.AddData(pData, nSize);
  230.  
  231.         return m_pChunkFile->AddChunk(
  232.           ChunkType_BoneAnim,
  233.           BONEANIM_CHUNK_DESC_0290::VERSION,
  234.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  235.           chunkData.GetData(), chunkData.GetSize());
  236. }
  237.  
  238. //////////////////////////////////////////////////////////////////////////
  239. int CSaverCGF::SaveBoneNames(bool bSwapEndian, char* boneList, int numBones, int listSize)
  240. {
  241.         BONENAMELIST_CHUNK_DESC_0745 chunk;
  242.         ZeroStruct(chunk);
  243.         chunk.numEntities = numBones;
  244.         SwapEndian(chunk, bSwapEndian);
  245.  
  246.         CChunkData chunkData;
  247.         chunkData.Add(chunk);
  248.         chunkData.AddData(boneList, listSize);
  249.  
  250.         return m_pChunkFile->AddChunk(
  251.           ChunkType_BoneNameList,
  252.           BONENAMELIST_CHUNK_DESC_0745::VERSION,
  253.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  254.           chunkData.GetData(), chunkData.GetSize());
  255. }
  256.  
  257. //////////////////////////////////////////////////////////////////////////
  258. int CSaverCGF::SaveBoneInitialMatrices(bool bSwapEndian, SBoneInitPosMatrix* matrices, int numBones, int nSize)
  259. {
  260.         BONEINITIALPOS_CHUNK_DESC_0001 chunk;
  261.         ZeroStruct(chunk);
  262.         chunk.numBones = numBones;
  263.         SwapEndian(chunk, bSwapEndian);
  264.  
  265.         CChunkData chunkData;
  266.         chunkData.Add(chunk);
  267.         chunkData.AddData(matrices, nSize);
  268.  
  269.         return m_pChunkFile->AddChunk(
  270.           ChunkType_BoneInitialPos,
  271.           BONEINITIALPOS_CHUNK_DESC_0001::VERSION,
  272.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  273.           chunkData.GetData(), chunkData.GetSize());
  274. }
  275.  
  276. //////////////////////////////////////////////////////////////////////////
  277. int CSaverCGF::SaveBoneMesh(bool bSwapEndian, const PhysicalProxy& proxy)
  278. {
  279.         // uncompiled mesh chunk
  280.         MESH_CHUNK_DESC_0745 chunk;
  281.         ZeroStruct(chunk);
  282.  
  283.         int numVertices = proxy.m_arrPoints.size();
  284.         int numFaces = proxy.m_arrMaterials.size();
  285.  
  286.         chunk.nFaces = numFaces;
  287.         chunk.nTVerts = 0;
  288.         chunk.nVerts = numVertices;
  289.         chunk.VertAnimID = -1;
  290.  
  291.         // add chunk members
  292.         CChunkData chunkData;
  293.         chunkData.Add(chunk);
  294.  
  295.         // copy positions and vertices to a CryVertex array -----------------------------------
  296.         CryVertex* vertices = new CryVertex[numVertices];
  297.         for (int i = 0; i < numVertices; i++)
  298.         {
  299.                 vertices[i].p = proxy.m_arrPoints[i] * 100.0f;
  300.                 vertices[i].n = Vec3(ZERO);
  301.         }
  302.         chunkData.AddData(vertices, numVertices * sizeof(CryVertex));
  303.         SAFE_DELETE_ARRAY(vertices);
  304.  
  305.         // copy faces to a CryFace array ------------------------------------------------------
  306.         CryFace* faces = new CryFace[numFaces];
  307.         for (int i = 0; i < numFaces; i++)
  308.         {
  309.                 faces[i].v0 = proxy.m_arrIndices[i * 3 + 0];
  310.                 faces[i].v1 = proxy.m_arrIndices[i * 3 + 1];
  311.                 faces[i].v2 = proxy.m_arrIndices[i * 3 + 2];
  312.                 faces[i].MatID = proxy.m_arrMaterials[i];
  313.         }
  314.         chunkData.AddData(faces, numFaces * sizeof(CryFace));
  315.         SAFE_DELETE_ARRAY(faces);
  316.  
  317.         int nMeshChunkId = m_pChunkFile->AddChunk(
  318.           ChunkType_BoneMesh,
  319.           MESH_CHUNK_DESC_0745::VERSION,
  320.           eEndianness_Native,
  321.           chunkData.GetData(), chunkData.GetSize());
  322.  
  323.         return nMeshChunkId;
  324. }
  325.  
  326. //////////////////////////////////////////////////////////////////////////
  327. void CSaverCGF::SaveNodes(
  328.   bool bSwapEndian,
  329.   bool bStorePositionsAsF16,
  330.   bool bUseQtangents,
  331.   bool bStoreIndicesAsU16
  332.         #if defined(RESOURCE_COMPILER)
  333.   , CInternalSkinningInfo* pSkinningInfo
  334.         #endif
  335.   )
  336. {
  337.         m_savedNodes.clear();
  338.         int numNodes = m_pCGF->GetNodeCount();
  339.         for (int i = 0; i < numNodes; i++)
  340.         {
  341.                 CNodeCGF* pNode = m_pCGF->GetNode(i);
  342.                 const char* pNodeName = pNode->name;
  343.  
  344.                 // Check if not yet saved.
  345.                 uint32 numSavedNodes = m_savedNodes.size();
  346.                 //      if (m_savedNodes.find(pNode) == m_savedNodes.end())
  347.         #if defined(RESOURCE_COMPILER)
  348.                 SaveNode(pNode, bSwapEndian, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16, pSkinningInfo);
  349.         #else
  350.                 SaveNode(pNode, bSwapEndian, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16);
  351.         #endif
  352.         }
  353. }
  354.  
  355. //////////////////////////////////////////////////////////////////////////
  356.         #if defined(RESOURCE_COMPILER)
  357. void CSaverCGF::SaveUncompiledNodes()
  358. {
  359.         m_savedNodes.clear();
  360.         int numNodes = m_pCGF->GetNodeCount();
  361.         for (int i = 0; i < numNodes; i++)
  362.         {
  363.                 CNodeCGF* pNode = m_pCGF->GetNode(i);
  364.                 SaveUncompiledNode(pNode);
  365.         }
  366. }
  367.         #endif
  368.  
  369. //////////////////////////////////////////////////////////////////////////
  370. int CSaverCGF::SaveNode(
  371.   CNodeCGF* const pNode,
  372.   const bool bSwapEndian,
  373.   const bool bStorePositionsAsF16,
  374.   const bool bUseQtangents,
  375.   const bool bStoreIndicesAsU16
  376.         #if defined(RESOURCE_COMPILER)
  377.   , CInternalSkinningInfo* const pSkinningInfo
  378.         #endif
  379.   )
  380. {
  381.         if (m_savedNodes.find(pNode) != m_savedNodes.end())
  382.         {
  383.                 return pNode->nChunkId;
  384.         }
  385.  
  386.         if (m_bDoNotSaveNonMeshData && (pNode->bPhysicsProxy || !pNode->pMesh))
  387.         {
  388.                 return -1;
  389.         }
  390.  
  391.         m_savedNodes.insert(pNode);
  392.  
  393.         NODE_CHUNK_DESC_0824 chunk;
  394.         ZeroStruct(chunk);
  395.  
  396.         for (int i = 0; i < m_pCGF->GetNodeCount(); ++i)
  397.         {
  398.                 CNodeCGF* const pOtherNode = m_pCGF->GetNode(i);
  399.                 if (pOtherNode->pParent == pNode)
  400.                 {
  401.                         chunk.nChildren++;
  402.                 }
  403.         }
  404.  
  405.         cry_strcpy(chunk.name, pNode->name);
  406.  
  407.         // Set matrix to node chunk.
  408.         float* pMat = (float*)&chunk.tm;
  409.         pMat[0] = pNode->localTM(0, 0);
  410.         pMat[1] = pNode->localTM(1, 0);
  411.         pMat[2] = pNode->localTM(2, 0);
  412.         pMat[4] = pNode->localTM(0, 1);
  413.         pMat[5] = pNode->localTM(1, 1);
  414.         pMat[6] = pNode->localTM(2, 1);
  415.         pMat[8] = pNode->localTM(0, 2);
  416.         pMat[9] = pNode->localTM(1, 2);
  417.         pMat[10] = pNode->localTM(2, 2);
  418.         pMat[12] = pNode->localTM.GetTranslation().x * SCALE_TO_CGF;
  419.         pMat[13] = pNode->localTM.GetTranslation().y * SCALE_TO_CGF;
  420.         pMat[14] = pNode->localTM.GetTranslation().z * SCALE_TO_CGF;
  421.  
  422.         if (pNode->pMaterial)
  423.         {
  424.                 chunk.MatID = pNode->pMaterial->nChunkId;
  425.         }
  426.  
  427.         chunk.ObjectID = -1;
  428.         chunk.ParentID = -1;
  429.  
  430.         if (pNode->pParent)
  431.         {
  432.         #if defined(RESOURCE_COMPILER)
  433.                 pNode->nParentChunkId = SaveNode(pNode->pParent, bSwapEndian, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16, pSkinningInfo);
  434.         #else
  435.                 pNode->nParentChunkId = SaveNode(pNode->pParent, bSwapEndian, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16);
  436.         #endif
  437.                 chunk.ParentID = pNode->nParentChunkId;
  438.         }
  439.  
  440.         if (pNode->type == CNodeCGF::NODE_MESH ||
  441.             (pNode->type == CNodeCGF::NODE_HELPER && pNode->helperType == HP_GEOMETRY))
  442.         {
  443.                 pNode->nObjectChunkId = SaveNodeMesh(pNode, bSwapEndian, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16);
  444.         }
  445.         else if (pNode->type == CNodeCGF::NODE_HELPER)
  446.         {
  447.                 pNode->nObjectChunkId = SaveHelperChunk(pNode, bSwapEndian);
  448.         }
  449.  
  450.         int nextChunk = m_pChunkFile->NumChunks();
  451.  
  452.         int positionIndex = pNode->pos_cont_id;
  453.         int rotationIndex = pNode->rot_cont_id;
  454.         int scaleIndex = pNode->scl_cont_id;
  455.  
  456.         #if defined(RESOURCE_COMPILER)
  457.         int controllerIndex = -1;
  458.         if (pSkinningInfo)
  459.         {
  460.                 // Get the node index.
  461.                 for (int i = 0; i < m_pCGF->GetNodeCount(); ++i)
  462.                 {
  463.                         CNodeCGF* const pOtherNode = m_pCGF->GetNode(i);
  464.                         if (pOtherNode == pNode)
  465.                         {
  466.                                 controllerIndex = 3 * i;
  467.                                 break;
  468.                         }
  469.                 }
  470.  
  471.                 assert(controllerIndex > -1);
  472.  
  473.                 if (pSkinningInfo->m_arrControllers[controllerIndex].m_controllertype == 0x55)
  474.                 {
  475.                         positionIndex = ++nextChunk;
  476.                 }
  477.  
  478.                 if (pSkinningInfo->m_arrControllers[controllerIndex + 1].m_controllertype == 0xaa)
  479.                 {
  480.                         rotationIndex = ++nextChunk;
  481.                 }
  482.  
  483.                 if (pSkinningInfo->m_arrControllers[controllerIndex + 2].m_controllertype == 0x55)
  484.                 {
  485.                         scaleIndex = ++nextChunk;
  486.                 }
  487.         }
  488.         #endif
  489.  
  490.         chunk.pos_cont_id = positionIndex;
  491.         chunk.rot_cont_id = rotationIndex;
  492.         chunk.scl_cont_id = scaleIndex;
  493.  
  494.         chunk.ObjectID = pNode->nObjectChunkId;
  495.         chunk.PropStrLen = pNode->properties.length();
  496.  
  497.         const int PropLen = chunk.PropStrLen;
  498.  
  499.         SwapEndian(chunk, bSwapEndian);
  500.  
  501.         CChunkData chunkData;
  502.         chunkData.Add(chunk);
  503.         // Copy property string
  504.         chunkData.AddData(pNode->properties.c_str(), PropLen);
  505.  
  506.         pNode->nChunkId = m_pChunkFile->AddChunk(
  507.           ChunkType_Node,
  508.           NODE_CHUNK_DESC_0824::VERSION,
  509.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  510.           chunkData.GetData(), chunkData.GetSize());
  511.  
  512.         #if defined(RESOURCE_COMPILER)
  513.         if (pSkinningInfo)
  514.         {
  515.                 if (positionIndex != -1)
  516.                 {
  517.                         SaveTCB3Track(pSkinningInfo, pSkinningInfo->m_arrControllers[controllerIndex].m_index);
  518.                 }
  519.                 if (rotationIndex != -1)
  520.                 {
  521.                         SaveTCBQTrack(pSkinningInfo, pSkinningInfo->m_arrControllers[controllerIndex + 1].m_index);
  522.                 }
  523.                 if (scaleIndex != -1)
  524.                 {
  525.                         SaveTCB3Track(pSkinningInfo, pSkinningInfo->m_arrControllers[controllerIndex + 2].m_index);
  526.                 }
  527.         }
  528.         #endif
  529.  
  530.         return pNode->nChunkId;
  531. }
  532.  
  533. //////////////////////////////////////////////////////////////////////////
  534.         #if defined(RESOURCE_COMPILER)
  535. int CSaverCGF::SaveUncompiledNode(CNodeCGF* pNode)
  536. {
  537.         if (m_savedNodes.find(pNode) != m_savedNodes.end())
  538.         {
  539.                 return pNode->nChunkId;
  540.         }
  541.  
  542.         m_savedNodes.insert(pNode);
  543.  
  544.         NODE_CHUNK_DESC_0824 chunk;
  545.         ZeroStruct(chunk);
  546.  
  547.         for (int i = 0; i < m_pCGF->GetNodeCount(); i++)
  548.         {
  549.                 CNodeCGF* pOtherNode = m_pCGF->GetNode(i);
  550.                 if (pOtherNode->pParent == pNode)
  551.                         chunk.nChildren++;
  552.         }
  553.  
  554.         cry_strcpy(chunk.name, pNode->name);
  555.  
  556.         chunk.pos_cont_id = pNode->pos_cont_id;
  557.         chunk.rot_cont_id = pNode->rot_cont_id;
  558.         chunk.scl_cont_id = pNode->scl_cont_id;
  559.  
  560.         // Set matrix to node chunk.
  561.         float* pMat = (float*)&chunk.tm;
  562.         pMat[0] = pNode->localTM(0, 0);
  563.         pMat[1] = pNode->localTM(1, 0);
  564.         pMat[2] = pNode->localTM(2, 0);
  565.         pMat[4] = pNode->localTM(0, 1);
  566.         pMat[5] = pNode->localTM(1, 1);
  567.         pMat[6] = pNode->localTM(2, 1);
  568.         pMat[8] = pNode->localTM(0, 2);
  569.         pMat[9] = pNode->localTM(1, 2);
  570.         pMat[10] = pNode->localTM(2, 2);
  571.         pMat[12] = pNode->localTM.GetTranslation().x * SCALE_TO_CGF;
  572.         pMat[13] = pNode->localTM.GetTranslation().y * SCALE_TO_CGF;
  573.         pMat[14] = pNode->localTM.GetTranslation().z * SCALE_TO_CGF;
  574.  
  575.         if (pNode->pMaterial)
  576.         {
  577.                 chunk.MatID = pNode->pMaterial->nChunkId;
  578.         }
  579.  
  580.         chunk.ObjectID = -1;
  581.         chunk.ParentID = -1;
  582.         if (pNode->pParent)
  583.         {
  584.                 pNode->nParentChunkId = SaveUncompiledNode(pNode->pParent);
  585.                 chunk.ParentID = pNode->nParentChunkId;
  586.         }
  587.         if (pNode->type == CNodeCGF::NODE_MESH && pNode->pMesh && pNode->pMesh->GetFaceCount() > 0)
  588.         {
  589.                 pNode->nObjectChunkId = SaveUncompiledNodeMesh(pNode);
  590.         }
  591.         if (pNode->type == CNodeCGF::NODE_HELPER && pNode->helperType == HP_GEOMETRY && pNode->pMesh)
  592.         {
  593.                 pNode->nObjectChunkId = SaveUncompiledNodeMesh(pNode);
  594.         }
  595.         else if (pNode->type == CNodeCGF::NODE_HELPER)
  596.         {
  597.                 pNode->nObjectChunkId = SaveUncompiledHelperChunk(pNode);
  598.         }
  599.         else if (pNode->type == CNodeCGF::NODE_LIGHT)
  600.         {
  601.                 // Save Light chunk
  602.         }
  603.  
  604.         chunk.ObjectID = pNode->nObjectChunkId;
  605.         chunk.PropStrLen = pNode->properties.length();
  606.  
  607.         CChunkData chunkData;
  608.         chunkData.Add(chunk);
  609.         // Copy property string
  610.         chunkData.AddData(pNode->properties.c_str(), chunk.PropStrLen);
  611.  
  612.         pNode->nChunkId = m_pChunkFile->AddChunk(
  613.           ChunkType_Node,
  614.           NODE_CHUNK_DESC_0824::VERSION,
  615.           eEndianness_Native,
  616.           chunkData.GetData(), chunkData.GetSize());
  617.  
  618.         return pNode->nChunkId;
  619. }
  620.         #endif
  621.  
  622. //////////////////////////////////////////////////////////////////////////
  623.         #if defined(RESOURCE_COMPILER)
  624. void CSaverCGF::SaveUncompiledMorphTargets()
  625. {
  626.         assert(m_pCGF);
  627.         CSkinningInfo* const skinningInfo = m_pCGF->GetSkinningInfo();
  628.         for (int morphIndex = 0, morphCount = skinningInfo ? int(skinningInfo->m_arrMorphTargets.size()) : 0; morphIndex < morphCount; ++morphIndex)
  629.         {
  630.                 assert(skinningInfo);        // Loop invariant prevents skinningInfo from being nullptr here
  631.                 MorphTargets* morph = skinningInfo->m_arrMorphTargets[morphIndex];
  632.                 assert(morph);
  633.  
  634.                 MESHMORPHTARGET_CHUNK_DESC_0001 chunk;
  635.                 ZeroStruct(chunk);
  636.                 chunk.nChunkIdMesh = -1;     // TODO: Save this properly!
  637.                 chunk.numMorphVertices = int(morph->m_arrIntMorph.size());
  638.  
  639.                 CChunkData chunkData;
  640.                 chunkData.Add(chunk);
  641.                 if (morph->m_arrIntMorph.size())
  642.                         chunkData.AddData(&morph->m_arrIntMorph[0], int(morph->m_arrIntMorph.size() * sizeof(SMeshMorphTargetVertex)));
  643.                 chunkData.AddData(morph->m_strName.c_str(), int(morph->m_strName.size() + 1));
  644.  
  645.                 m_pChunkFile->AddChunk(
  646.                   ChunkType_MeshMorphTarget,
  647.                   MESHMORPHTARGET_CHUNK_DESC_0001::VERSION,
  648.                   eEndianness_Native,
  649.                   chunkData.GetData(), chunkData.GetSize());
  650.         }
  651. }
  652.         #endif
  653.  
  654. //////////////////////////////////////////////////////////////////////////
  655. int CSaverCGF::SaveNodeMesh(
  656.   CNodeCGF* pNode,
  657.   bool bSwapEndian,
  658.   bool bStorePositionsAsF16,
  659.   bool bUseQTangents,
  660.   bool bStoreIndicesAsU16)
  661. {
  662.         if (pNode->pMesh)
  663.         {
  664.                 if (m_mapMeshToChunk.find(pNode->pMesh) != m_mapMeshToChunk.end())
  665.                 {
  666.                         // This mesh already saved.
  667.                         return m_mapMeshToChunk.find(pNode->pMesh)->second;
  668.                 }
  669.         }
  670.  
  671.         MESH_CHUNK_DESC_0801 chunk;
  672.         ZeroStruct(chunk);
  673.  
  674.         if (pNode->pMesh)
  675.         {
  676.                 const CMesh& mesh = *pNode->pMesh;
  677.  
  678.                 const int nVerts = mesh.GetVertexCount();
  679.                 const int nIndices = mesh.GetIndexCount();
  680.  
  681.                 chunk.nVerts = nVerts;
  682.                 chunk.nIndices = nIndices;
  683.                 chunk.nSubsets = mesh.GetSubSetCount();
  684.                 chunk.bboxMin = mesh.m_bbox.min;
  685.                 chunk.bboxMax = mesh.m_bbox.max;
  686.         }
  687.         else
  688.         {
  689.                 chunk.nVerts = pNode->meshInfo.nVerts;
  690.                 chunk.nIndices = pNode->meshInfo.nIndices;
  691.                 chunk.nSubsets = pNode->meshInfo.nSubsets;
  692.                 chunk.bboxMax = pNode->meshInfo.bboxMin;
  693.                 chunk.bboxMax = pNode->meshInfo.bboxMax;
  694.         }
  695.  
  696.         const bool bEmptyMesh = m_bDoNotSaveMeshData || pNode->bPhysicsProxy || !pNode->pMesh;
  697.  
  698.         if (bEmptyMesh)
  699.         {
  700.                 chunk.nFlags |= MESH_CHUNK_DESC_0801::MESH_IS_EMPTY;
  701.         }
  702.         chunk.nFlags2 = pNode->nPhysicalizeFlags;
  703.  
  704.         if (m_bSavePhysicsMeshes)
  705.         {
  706.                 for (int i = 0; i < 4; ++i)
  707.                 {
  708.                         if (!pNode->physicalGeomData[i].empty())
  709.                         {
  710.                                 chunk.nPhysicsDataChunkId[i] = SavePhysicalDataChunk(&pNode->physicalGeomData[i][0], pNode->physicalGeomData[i].size(), bSwapEndian);
  711.                         }
  712.                 }
  713.         }
  714.  
  715.         if (!bEmptyMesh)
  716.         {
  717.                 CMesh& mesh = *pNode->pMesh;
  718.  
  719.                 mesh.RecomputeTexMappingDensity();
  720.                 chunk.texMappingDensity = mesh.m_texMappingDensity;
  721.                 chunk.nFlags |= MESH_CHUNK_DESC_0801::HAS_TEX_MAPPING_DENSITY;
  722.  
  723.                 chunk.nSubsetsChunkId = SaveMeshSubsetsChunk(mesh, bSwapEndian);
  724.  
  725.                 const int vertexCount = mesh.GetVertexCount();
  726.                 bool bInterleaved = false;
  727.  
  728.                 if (m_bCompactVertexStreams && mesh.m_pPositions && mesh.m_pColor0 && mesh.m_pTexCoord)
  729.                 {
  730.                         std::vector<SVF_P3S_C4B_T2S> interleavedVertices(vertexCount);
  731.                         memset(&interleavedVertices[0], 0, sizeof(interleavedVertices[0]) * interleavedVertices.size());
  732.  
  733.                         const Vec3* const pPositions = mesh.m_pPositions;
  734.                         const SMeshColor* const pColors = mesh.m_pColor0;
  735.                         const SMeshTexCoord* const pTexCoords = mesh.m_pTexCoord;
  736.  
  737.                         for (int vi = 0; vi < vertexCount; ++vi)
  738.                         {
  739.                                 SVF_P3S_C4B_T2S& vert = interleavedVertices[vi];
  740.                                 const ColorB clr = pColors[vi].GetRGBA();
  741.                                 const Vec2 uv = pTexCoords[vi].GetUV();
  742.  
  743.                                 vert.xyz = Vec3f16(pPositions[vi].x, pPositions[vi].y, pPositions[vi].z);
  744.                                 vert.color.dcolor = clr.pack_abgr8888();
  745.                                 vert.st = Vec2f16(uv.x, uv.y);
  746.  
  747.                                 SwapEndian(vert.xyz, bSwapEndian);
  748.                                 SwapEndian(vert.color.dcolor, bSwapEndian);
  749.                                 SwapEndian(vert.st, bSwapEndian);
  750.                         }
  751.  
  752.                         chunk.nStreamChunkID[CGF_STREAM_P3S_C4B_T2S] = SaveStreamDataChunk(&interleavedVertices[0], CGF_STREAM_P3S_C4B_T2S, vertexCount, sizeof(interleavedVertices[0]), bSwapEndian);
  753.  
  754.                         bInterleaved = true;
  755.                 }
  756.  
  757.                 // We don't support writing m_pPositionsF16 (although we can)
  758.                 if (mesh.m_pPositionsF16)
  759.                 {
  760.                         assert(0);
  761.                 }
  762.  
  763.                 if (mesh.m_pPositions && !bInterleaved)
  764.                 {
  765.                         static_assert(sizeof(mesh.m_pPositions[0]) == sizeof(Vec3), "Invalid type size!");
  766.                         if (bStorePositionsAsF16)
  767.                         {
  768.                                 const Vec3* pRealData = mesh.m_pPositions;
  769.                                 std::vector<Vec3f16> tmpVec(vertexCount);
  770.                                 for (int i = 0; i < vertexCount; ++i, ++pRealData)
  771.                                 {
  772.                                         tmpVec[i] = Vec3f16(pRealData->x, pRealData->y, pRealData->z);
  773.                                         SwapEndian(tmpVec[i], bSwapEndian);
  774.                                 }
  775.                                 chunk.nStreamChunkID[CGF_STREAM_POSITIONS] = SaveStreamDataChunk(&tmpVec[0], CGF_STREAM_POSITIONS, vertexCount, sizeof(tmpVec[0]), bSwapEndian);
  776.                         }
  777.                         else
  778.                         {
  779.                                 SwapEndian(mesh.m_pPositions, vertexCount, bSwapEndian);
  780.                                 chunk.nStreamChunkID[CGF_STREAM_POSITIONS] = SaveStreamDataChunk(mesh.m_pPositions, CGF_STREAM_POSITIONS, vertexCount, sizeof(mesh.m_pPositions[0]), bSwapEndian);
  781.                                 SwapEndian(mesh.m_pPositions, vertexCount, bSwapEndian);
  782.                         }
  783.                 }
  784.  
  785.                 if (mesh.m_pNorms && !m_bCompactVertexStreams)
  786.                 {
  787.                         SwapEndian(mesh.m_pNorms, vertexCount, bSwapEndian);
  788.                         chunk.nStreamChunkID[CGF_STREAM_NORMALS] = SaveStreamDataChunk(mesh.m_pNorms, CGF_STREAM_NORMALS, vertexCount, sizeof(Vec3), bSwapEndian);
  789.                         SwapEndian(mesh.m_pNorms, vertexCount, bSwapEndian);
  790.                 }
  791.  
  792.                 if (mesh.m_pTexCoord && !bInterleaved)
  793.                 {
  794.                         SwapEndian(mesh.m_pTexCoord, mesh.GetTexCoordCount(), bSwapEndian);
  795.                         chunk.nStreamChunkID[CGF_STREAM_TEXCOORDS] = SaveStreamDataChunk(mesh.m_pTexCoord, CGF_STREAM_TEXCOORDS, mesh.GetTexCoordCount(), sizeof(CryUV), bSwapEndian);
  796.                         SwapEndian(mesh.m_pTexCoord, mesh.GetTexCoordCount(), bSwapEndian);
  797.                 }
  798.  
  799.                 if (mesh.m_pColor0 && !bInterleaved)
  800.                 {
  801.                         SwapEndian(mesh.m_pColor0, vertexCount, bSwapEndian);
  802.                         chunk.nStreamChunkID[CGF_STREAM_COLORS] = SaveStreamDataChunk(mesh.m_pColor0, CGF_STREAM_COLORS, vertexCount, sizeof(SMeshColor), bSwapEndian);
  803.                         SwapEndian(mesh.m_pColor0, vertexCount, bSwapEndian);
  804.                 }
  805.  
  806.                 if (mesh.m_pColor1)
  807.                 {
  808.                         SwapEndian(mesh.m_pColor1, vertexCount, bSwapEndian);
  809.                         chunk.nStreamChunkID[CGF_STREAM_COLORS2] = SaveStreamDataChunk(mesh.m_pColor1, CGF_STREAM_COLORS2, vertexCount, sizeof(SMeshColor), bSwapEndian);
  810.                         SwapEndian(mesh.m_pColor1, vertexCount, bSwapEndian);
  811.                 }
  812.  
  813.                 if (mesh.m_pVertMats)
  814.                 {
  815.                         SwapEndian(mesh.m_pVertMats, vertexCount, bSwapEndian);
  816.                         chunk.nStreamChunkID[CGF_STREAM_VERT_MATS] = SaveStreamDataChunk(mesh.m_pVertMats, CGF_STREAM_VERT_MATS, vertexCount, sizeof(mesh.m_pVertMats[0]), bSwapEndian);
  817.                         SwapEndian(mesh.m_pVertMats, vertexCount, bSwapEndian);
  818.                 }
  819.  
  820.                 if (mesh.m_pIndices)
  821.                 {
  822.                         const int indexCount = mesh.GetIndexCount();
  823.  
  824.                         static_assert(sizeof(mesh.m_pIndices[0]) == sizeof(vtx_idx), "Invalid type size!");
  825.                         static_assert(sizeof(vtx_idx) == 2 || sizeof(vtx_idx) == 4, "Invalid type size!");
  826.  
  827.                         if (sizeof(mesh.m_pIndices[0]) == (bStoreIndicesAsU16 ? 2 : 4))
  828.                         {
  829.                                 SwapEndian(mesh.m_pIndices, indexCount, bSwapEndian);
  830.                                 chunk.nStreamChunkID[CGF_STREAM_INDICES] = SaveStreamDataChunk(mesh.m_pIndices, CGF_STREAM_INDICES, indexCount, sizeof(mesh.m_pIndices[0]), bSwapEndian);
  831.                                 SwapEndian(mesh.m_pIndices, indexCount, bSwapEndian);
  832.                         }
  833.                         else if (bStoreIndicesAsU16)
  834.                         {
  835.                                 if (vertexCount > 0xffff)
  836.                                 {
  837.                                         // 0xffff is used instead of 0x10000 to reserve index 0xffff for special cases
  838.         #if defined(RESOURCE_COMPILER)
  839.                                         RCLogError("Saving mesh with 16-bit vertex indices is impossible - 16-bit indices cannot address %i vertices", vertexCount);
  840.         #endif
  841.                                         return -1;
  842.                                 }
  843.                                 std::vector<uint16> tmp(indexCount);
  844.                                 for (int i = 0; i < indexCount; ++i)
  845.                                 {
  846.                                         tmp[i] = (uint16)mesh.m_pIndices[i];
  847.                                         SwapEndian(tmp[i], bSwapEndian);
  848.                                 }
  849.                                 chunk.nStreamChunkID[CGF_STREAM_INDICES] = SaveStreamDataChunk(&tmp[0], CGF_STREAM_INDICES, indexCount, sizeof(uint16), bSwapEndian);
  850.                         }
  851.                         else
  852.                         {
  853.                                 std::vector<uint32> tmp(indexCount);
  854.                                 for (int i = 0; i < indexCount; ++i)
  855.                                 {
  856.                                         tmp[i] = mesh.m_pIndices[i];
  857.                                         SwapEndian(tmp[i], bSwapEndian);
  858.                                 }
  859.                                 chunk.nStreamChunkID[CGF_STREAM_INDICES] = SaveStreamDataChunk(&tmp[0], CGF_STREAM_INDICES, indexCount, sizeof(uint32), bSwapEndian);
  860.                         }
  861.                 }
  862.  
  863.                 if (mesh.m_pTangents)
  864.                 {
  865.                         if (bUseQTangents)
  866.                         {
  867.                                 std::vector<SMeshQTangents> qTangents(vertexCount);
  868.                                 MeshTangentsFrameToQTangents(
  869.                                   &mesh.m_pTangents[0], sizeof(mesh.m_pTangents[0]), vertexCount,
  870.                                   &qTangents[0], sizeof(qTangents[0]));
  871.                                 SwapEndian(&qTangents[0], vertexCount, bSwapEndian);
  872.                                 chunk.nStreamChunkID[CGF_STREAM_QTANGENTS] = SaveStreamDataChunk(&qTangents[0], CGF_STREAM_QTANGENTS, vertexCount, sizeof(SMeshQTangents), bSwapEndian);
  873.                         }
  874.                         else
  875.                         {
  876.                                 SwapEndian(mesh.m_pTangents, vertexCount, bSwapEndian);
  877.                                 chunk.nStreamChunkID[CGF_STREAM_TANGENTS] = SaveStreamDataChunk(mesh.m_pTangents, CGF_STREAM_TANGENTS, vertexCount, sizeof(SMeshTangents), bSwapEndian);
  878.                                 SwapEndian(mesh.m_pTangents, vertexCount, bSwapEndian);
  879.                         }
  880.                 }
  881.  
  882.                 if (mesh.m_pBoneMapping)
  883.                 {
  884.                         if (mesh.m_pExtraBoneMapping)
  885.                         {
  886.                                 chunk.nFlags |= MESH_CHUNK_DESC_0801::HAS_EXTRA_WEIGHTS;
  887.  
  888.                                 std::vector<SMeshBoneMapping_uint16> tempBoneMapping;
  889.                                 static_assert(sizeof(tempBoneMapping[0]) == sizeof(mesh.m_pBoneMapping[0]), "Invalid type size!");
  890.                                 tempBoneMapping.resize(vertexCount * 2);
  891.                                 memcpy(&tempBoneMapping[0], mesh.m_pBoneMapping, sizeof(tempBoneMapping[0]) * vertexCount);
  892.                                 memcpy(&tempBoneMapping[vertexCount], mesh.m_pExtraBoneMapping, sizeof(tempBoneMapping[0]) * vertexCount);
  893.                                 SwapEndian(&tempBoneMapping[0], vertexCount * 2, bSwapEndian);
  894.                                 chunk.nStreamChunkID[CGF_STREAM_BONEMAPPING] = SaveStreamDataChunk(&tempBoneMapping[0], CGF_STREAM_BONEMAPPING, vertexCount * 2, sizeof(tempBoneMapping[0]), bSwapEndian);
  895.                         }
  896.                         else
  897.                         {
  898.                                 SwapEndian(mesh.m_pBoneMapping, vertexCount, bSwapEndian);
  899.                                 chunk.nStreamChunkID[CGF_STREAM_BONEMAPPING] = SaveStreamDataChunk(mesh.m_pBoneMapping, CGF_STREAM_BONEMAPPING, vertexCount, sizeof(mesh.m_pBoneMapping[0]), bSwapEndian);
  900.                                 SwapEndian(mesh.m_pBoneMapping, vertexCount, bSwapEndian);
  901.                         }
  902.                 }
  903.  
  904.                 if (pNode->pSkinInfo)
  905.                 {
  906.                         SwapEndian(pNode->pSkinInfo, vertexCount + 1, bSwapEndian);
  907.                         chunk.nStreamChunkID[CGF_STREAM_SKINDATA] = SaveStreamDataChunk(pNode->pSkinInfo, CGF_STREAM_SKINDATA, vertexCount + 1, sizeof(pNode->pSkinInfo[0]), bSwapEndian);
  908.                         SwapEndian(pNode->pSkinInfo, vertexCount + 1, bSwapEndian);
  909.                 }
  910.         }
  911.  
  912.         SwapEndian(chunk, bSwapEndian);
  913.  
  914.         const int nMeshChunkId = m_pChunkFile->AddChunk(
  915.           ChunkType_Mesh,
  916.           MESH_CHUNK_DESC_0801::VERSION,
  917.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  918.           &chunk, sizeof(chunk));
  919.  
  920.         m_mapMeshToChunk[pNode->pMesh] = nMeshChunkId;
  921.  
  922.         return nMeshChunkId;
  923. }
  924.  
  925. //////////////////////////////////////////////////////////////////////////
  926.         #if defined(RESOURCE_COMPILER)
  927. int CSaverCGF::SaveUncompiledNodeMesh(CNodeCGF* pNode)
  928. {
  929.         if (m_mapMeshToChunk.find(pNode->pMesh) != m_mapMeshToChunk.end())
  930.         {
  931.                 // This mesh already saved.
  932.                 return m_mapMeshToChunk.find(pNode->pMesh)->second;
  933.         }
  934.  
  935.         const CMesh* const mesh = pNode->pMesh;
  936.  
  937.         const bool HasBoneInfo = (mesh->m_pBoneMapping != 0);
  938.         const bool HasVertexColors = (mesh->m_pColor0 != 0);
  939.         const bool HasVertexAlphas = HasVertexColors;
  940.         const bool WriteVCol = true;
  941.  
  942.         // uncompiled mesh chunk
  943.         MESH_CHUNK_DESC_0745 chunk;
  944.         ZeroStruct(chunk);
  945.  
  946.         const int numVertices = mesh->GetVertexCount();
  947.         const int numFaces = mesh->GetFaceCount();
  948.         const int numUVs = mesh->GetTexCoordCount();
  949.  
  950.         if (numUVs != 0 && numUVs != numVertices)
  951.         {
  952.                 RCLogError("Mesh for node \"%s\" has mismatching number of vertices and texture coordinates", pNode->name);
  953.                 return -1;
  954.         }
  955.  
  956.         if (!mesh->m_pTopologyIds)
  957.         {
  958.                 RCLogError("Mesh for node \"%s\" has no topology info. Contact an RC programmer.", pNode->name);
  959.                 return -1;
  960.         }
  961.  
  962.         assert(mesh->m_pPositions);
  963.         assert(mesh->m_pNorms);
  964.         assert(mesh->m_pFaces);
  965.  
  966.         chunk.flags1 = 0;
  967.         chunk.flags2 = MESH_CHUNK_DESC_0745::FLAG2_HAS_TOPOLOGY_IDS;
  968.         chunk.flags1 |= HasBoneInfo ? MESH_CHUNK_DESC_0745::FLAG1_BONE_INFO : 0;
  969.         chunk.flags2 |= (WriteVCol && HasVertexColors) ? MESH_CHUNK_DESC_0745::FLAG2_HAS_VERTEX_COLOR : 0;
  970.         chunk.flags2 |= (WriteVCol && HasVertexAlphas) ? MESH_CHUNK_DESC_0745::FLAG2_HAS_VERTEX_ALPHA : 0;
  971.         chunk.nFaces = numFaces;
  972.         chunk.nTVerts = numUVs;
  973.         chunk.nVerts = numVertices;
  974.         chunk.VertAnimID = -1;         // nVertexAnimChunkID;
  975.  
  976.         // add chunk members
  977.         CChunkData chunkData;
  978.         chunkData.Add(chunk);
  979.  
  980.         // copy positions and vertices to a CryVertex array -----------------------------------
  981.         {
  982.                 CryVertex* vertices = new CryVertex[numVertices];
  983.                 for (int i = 0; i < numVertices; i++)
  984.                 {
  985.                         vertices[i].p = mesh->m_pPositions[i];
  986.                         vertices[i].n = mesh->m_pNorms[i].GetN();
  987.                 }
  988.                 chunkData.AddData(vertices, numVertices * sizeof(CryVertex));
  989.                 SAFE_DELETE_ARRAY(vertices);
  990.         }
  991.  
  992.         // copy faces to a CryFace array ------------------------------------------------------
  993.         {
  994.                 CryFace* faces = new CryFace[numFaces];
  995.                 for (int i = 0; i < numFaces; i++)
  996.                 {
  997.                         faces[i].v0 = mesh->m_pFaces[i].v[0];
  998.                         faces[i].v1 = mesh->m_pFaces[i].v[1];
  999.                         faces[i].v2 = mesh->m_pFaces[i].v[2];
  1000.                         faces[i].MatID = mesh->m_subsets[mesh->m_pFaces[i].nSubset].nMatID;
  1001.                 }
  1002.                 chunkData.AddData(faces, numFaces * sizeof(CryFace));
  1003.                 SAFE_DELETE_ARRAY(faces);
  1004.         }
  1005.  
  1006.         // topology info ----------------------------------------------------------------------
  1007.         {
  1008.                 chunkData.AddData(mesh->m_pTopologyIds, numVertices * sizeof(mesh->m_pTopologyIds[0]));
  1009.         }
  1010.  
  1011.         // copy texture coordinates to a CryUV array ------------------------------------------
  1012.         if (numUVs)
  1013.         {
  1014.                 assert(numUVs == numVertices);
  1015.  
  1016.                 CryUV* uvs = new CryUV[numUVs];
  1017.                 for (int i = 0; i < numUVs; i++)
  1018.                 {
  1019.                         mesh->m_pTexCoord[i].ExportTo(uvs[i].u, uvs[i].v);
  1020.                 }
  1021.                 chunkData.AddData(uvs, numUVs * sizeof(CryUV));
  1022.                 SAFE_DELETE_ARRAY(uvs);
  1023.         }
  1024.  
  1025.         if (HasBoneInfo)
  1026.         {
  1027.                 CSkinningInfo* skinningInfo = m_pCGF->GetSkinningInfo();
  1028.                 Matrix34 objectTransform = pNode->worldTM;
  1029.  
  1030.                 typedef std::map<int, std::set<int>> BadBoneIDs;
  1031.                 BadBoneIDs badBoneIDs;
  1032.  
  1033.                 std::vector<CryLink> arrLinks;
  1034.  
  1035.                 for (int k = 0; k < numVertices; k++)
  1036.                 {
  1037.                         Vec3 point = mesh->m_pPositions[k];
  1038.                         Vec3 worldVertex = objectTransform.TransformPoint(point);
  1039.  
  1040.                         arrLinks.clear();
  1041.  
  1042.                         float totalweight = 0.0f;
  1043.  
  1044.                         for (int j = 0; j < 8; j++)
  1045.                         {
  1046.                                 int boneID = -1;
  1047.                                 float blending = 0.0f;
  1048.  
  1049.                                 if (j < 4)
  1050.                                 {
  1051.                                         boneID = mesh->m_pBoneMapping[k].boneIds[j];
  1052.                                         blending = (float)(mesh->m_pBoneMapping[k].weights[j]) / 255.0f;
  1053.                                 }
  1054.                                 else if (mesh->m_pExtraBoneMapping)
  1055.                                 {
  1056.                                         boneID = mesh->m_pExtraBoneMapping[k].boneIds[j - 4];
  1057.                                         blending = (float)(mesh->m_pExtraBoneMapping[k].weights[j - 4]) / 255.0f;
  1058.                                 }
  1059.  
  1060.                                 if (blending < 0.01f)
  1061.                                 {
  1062.                                         continue;
  1063.                                 }
  1064.  
  1065.                                 if (boneID >= skinningInfo->m_arrBonesDesc.size())
  1066.                                 {
  1067.                                         badBoneIDs[boneID].insert(k);
  1068.                                         continue;
  1069.                                 }
  1070.  
  1071.                                 totalweight += blending;
  1072.  
  1073.                                 const Matrix34& boneTransform = skinningInfo->m_arrBonesDesc[boneID].m_DefaultW2B;
  1074.                                 const Vec3 offset = boneTransform.TransformPoint(worldVertex);
  1075.  
  1076.                                 static float const metersToCentimeters = 100.0f;
  1077.  
  1078.                                 CryLink link;
  1079.                                 link.BoneID = boneID;
  1080.                                 link.Blending = blending;
  1081.                                 link.offset = offset * metersToCentimeters;
  1082.  
  1083.                                 arrLinks.push_back(link);
  1084.                         }
  1085.  
  1086.                         const int nLinks = arrLinks.size();
  1087.  
  1088.                         for (int j = 0; j < nLinks; j++)
  1089.                         {
  1090.                                 arrLinks[j].Blending /= totalweight;
  1091.                         }
  1092.  
  1093.                         chunkData.AddData(&nLinks, sizeof(int));
  1094.                         chunkData.AddData(&arrLinks[0], nLinks * sizeof(CryLink));
  1095.                 }
  1096.  
  1097.                 if (!badBoneIDs.empty())
  1098.                 {
  1099.                         RCLogError("Skinned mesh for node \"%s\" contains references to missing bones:", pNode->name);
  1100.                         BadBoneIDs::iterator it;
  1101.                         string message;
  1102.                         string vertexStr;
  1103.                         for (it = badBoneIDs.begin(); it != badBoneIDs.end(); ++it)
  1104.                         {
  1105.                                 const std::set<int>& vertexIndices = it->second;
  1106.                                 message.Format("  Bone %i, vertices:", it->first);
  1107.                                 for (std::set<int>::const_iterator vit = vertexIndices.begin(); vit != vertexIndices.end(); ++vit)
  1108.                                 {
  1109.                                         vertexStr.Format(" %i", *vit);
  1110.                                         message += vertexStr;
  1111.                                 }
  1112.                                 RCLogError("%s", message.c_str());
  1113.                         }
  1114.                 }
  1115.         }
  1116.  
  1117.         if (WriteVCol)
  1118.         {
  1119.                 if (HasVertexColors)
  1120.                 {
  1121.                         CryIRGB* vertexcolors = new CryIRGB[numVertices];
  1122.                         for (int i = 0; i < numVertices; i++)
  1123.                         {
  1124.                                 const ColorB clr = mesh->m_pColor0[i].GetRGBA();
  1125.  
  1126.                                 vertexcolors[i].r = clr.r;
  1127.                                 vertexcolors[i].g = clr.g;
  1128.                                 vertexcolors[i].b = clr.b;
  1129.                         }
  1130.                         chunkData.AddData(vertexcolors, numVertices * sizeof(CryIRGB));
  1131.                         SAFE_DELETE_ARRAY(vertexcolors);
  1132.                 }
  1133.  
  1134.                 if (HasVertexAlphas)
  1135.                 {
  1136.                         unsigned char* vertexalphas = new unsigned char[numVertices];
  1137.                         for (int i = 0; i < numVertices; i++)
  1138.                         {
  1139.                                 const ColorB clr = mesh->m_pColor0[i].GetRGBA();
  1140.  
  1141.                                 vertexalphas[i] = clr.a;
  1142.                         }
  1143.                         chunkData.AddData(vertexalphas, numVertices * sizeof(unsigned char));
  1144.                         SAFE_DELETE_ARRAY(vertexalphas);
  1145.                 }
  1146.         }
  1147.  
  1148.         if (0)     // save morph targets - the loader load this?
  1149.         {}
  1150.  
  1151.         if (0)     // save bone initial pose - the loader load this?
  1152.         {}
  1153.  
  1154.         int nMeshChunkId = m_pChunkFile->AddChunk(
  1155.           ChunkType_Mesh,
  1156.           MESH_CHUNK_DESC_0745::VERSION,
  1157.           eEndianness_Native,
  1158.           chunkData.GetData(), chunkData.GetSize());
  1159.  
  1160.         m_mapMeshToChunk[pNode->pMesh] = nMeshChunkId;
  1161.  
  1162.         return nMeshChunkId;
  1163. }
  1164.         #endif
  1165.  
  1166. //////////////////////////////////////////////////////////////////////////
  1167. int CSaverCGF::SaveHelperChunk(CNodeCGF* pNode, bool bSwapEndian)
  1168. {
  1169.         HELPER_CHUNK_DESC chunk;
  1170.         ZeroStruct(chunk);
  1171.  
  1172.         chunk.type = pNode->helperType;
  1173.         chunk.size = pNode->helperSize;
  1174.  
  1175.         SwapEndian(chunk, bSwapEndian);
  1176.  
  1177.         return m_pChunkFile->AddChunk(
  1178.           ChunkType_Helper,
  1179.           HELPER_CHUNK_DESC::VERSION,
  1180.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1181.           &chunk, sizeof(chunk));
  1182. }
  1183.  
  1184. //////////////////////////////////////////////////////////////////////////
  1185.         #if defined(RESOURCE_COMPILER)
  1186. int CSaverCGF::SaveUncompiledHelperChunk(CNodeCGF* pNode)
  1187. {
  1188.         HELPER_CHUNK_DESC chunk;
  1189.         ZeroStruct(chunk);
  1190.  
  1191.         chunk.type = pNode->helperType;
  1192.         chunk.size = pNode->helperSize;
  1193.  
  1194.         return m_pChunkFile->AddChunk(
  1195.           ChunkType_Helper,
  1196.           HELPER_CHUNK_DESC::VERSION,
  1197.           eEndianness_Native,
  1198.           &chunk, sizeof(chunk));
  1199. }
  1200.         #endif
  1201.  
  1202. //////////////////////////////////////////////////////////////////////////
  1203. // TODO:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1204.  
  1205. int CSaverCGF::SaveBreakablePhysics(bool bSwapEndian)
  1206. {
  1207.         const CPhysicalizeInfoCGF* const pPi = m_pCGF->GetPhysicalizeInfo();
  1208.  
  1209.         if (!pPi || pPi->nGranularity == -1)
  1210.         {
  1211.                 return 0;
  1212.         }
  1213.  
  1214.         BREAKABLE_PHYSICS_CHUNK_DESC chunk;
  1215.         ZeroStruct(chunk);
  1216.  
  1217.         chunk.granularity = pPi->nGranularity;
  1218.         chunk.nMode = pPi->nMode;
  1219.         chunk.nRetVtx = pPi->nRetVtx;
  1220.         chunk.nRetTets = pPi->nRetTets;
  1221.  
  1222.         CChunkData chunkData;
  1223.         chunkData.Add(chunk);
  1224.         if (pPi->pRetVtx)
  1225.         {
  1226.                 chunkData.AddData(pPi->pRetVtx, pPi->nRetVtx * sizeof(Vec3));
  1227.         }
  1228.         if (pPi->pRetTets)
  1229.         {
  1230.                 chunkData.AddData(pPi->pRetTets, pPi->nRetTets * sizeof(int) * 4);
  1231.         }
  1232.  
  1233.         SwapEndian(chunk, bSwapEndian);
  1234.  
  1235.         return m_pChunkFile->AddChunk(
  1236.           ChunkType_BreakablePhysics,
  1237.           BREAKABLE_PHYSICS_CHUNK_DESC::VERSION,
  1238.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1239.           chunkData.GetData(), chunkData.GetSize());
  1240. }
  1241.  
  1242. //////////////////////////////////////////////////////////////////////////
  1243. int CSaverCGF::SaveMeshSubsetsChunk(CMesh& mesh, bool bSwapEndian)
  1244. {
  1245.         MESH_SUBSETS_CHUNK_DESC_0800 chunk;
  1246.         ZeroStruct(chunk);
  1247.  
  1248.         chunk.nCount = mesh.GetSubSetCount();
  1249.  
  1250.         if (m_bComputeSubsetTexelDensity)
  1251.         {
  1252.                 chunk.nFlags |= MESH_SUBSETS_CHUNK_DESC_0800::HAS_SUBSET_TEXEL_DENSITY;
  1253.         }
  1254.  
  1255.         SwapEndian(chunk, bSwapEndian);
  1256.  
  1257.         CChunkData chunkData;
  1258.         chunkData.Add(chunk);
  1259.  
  1260.         for (int i = 0; i < mesh.GetSubSetCount(); i++)
  1261.         {
  1262.                 const SMeshSubset& srcSubset = mesh.m_subsets[i];
  1263.  
  1264.                 MESH_SUBSETS_CHUNK_DESC_0800::MeshSubset subset;
  1265.                 memset(&subset, 0, sizeof(subset));
  1266.                 subset.nFirstIndexId = srcSubset.nFirstIndexId;
  1267.                 subset.nNumIndices = srcSubset.nNumIndices;
  1268.                 subset.nFirstVertId = srcSubset.nFirstVertId;
  1269.                 subset.nNumVerts = srcSubset.nNumVerts;
  1270.                 subset.nMatID = srcSubset.nMatID;
  1271.                 subset.fRadius = srcSubset.fRadius;
  1272.                 subset.vCenter = srcSubset.vCenter;
  1273.                 SwapEndian(subset, bSwapEndian);
  1274.                 chunkData.Add(subset);
  1275.         }
  1276.  
  1277.         // add subset texel densities
  1278.         if (m_bComputeSubsetTexelDensity)
  1279.         {
  1280.                 for (int i = 0; i < mesh.GetSubSetCount(); ++i)
  1281.                 {
  1282.                         MESH_SUBSETS_CHUNK_DESC_0800::MeshSubsetTexelDensity subset;
  1283.  
  1284.                         const char* err;
  1285.                         float posArea, texArea;
  1286.                         if (!mesh.ComputeSubsetTexMappingAreas((size_t)i, posArea, texArea, err))
  1287.                         {
  1288.         #if defined(RESOURCE_COMPILER)
  1289.                                 RCLog("ComputeSubsetTexMappingAreas: %s", err);
  1290.         #endif
  1291.                                 subset.texelDensity = 0.0f;
  1292.                         }
  1293.                         else
  1294.                         {
  1295.                                 subset.texelDensity = texArea / posArea;
  1296.                         }
  1297.  
  1298.                         SwapEndian(subset, bSwapEndian);
  1299.                         chunkData.AddData(&subset, sizeof(subset));
  1300.                 }
  1301.         }
  1302.  
  1303.         return m_pChunkFile->AddChunk(
  1304.           ChunkType_MeshSubsets,
  1305.           MESH_SUBSETS_CHUNK_DESC_0800::VERSION,
  1306.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1307.           chunkData.GetData(), chunkData.GetSize());
  1308. }
  1309.  
  1310. //////////////////////////////////////////////////////////////////////////
  1311. int CSaverCGF::SaveStreamDataChunk(const void* pStreamData, int nStreamType, int nCount, int nElemSize, bool bSwapEndian)
  1312. {
  1313.         STREAM_DATA_CHUNK_DESC_0800 chunk;
  1314.         ZeroStruct(chunk);
  1315.  
  1316.         chunk.nStreamType = nStreamType;
  1317.         chunk.nCount = nCount;
  1318.         chunk.nElementSize = nElemSize;
  1319.  
  1320.         SwapEndian(chunk, bSwapEndian);
  1321.  
  1322.         CChunkData chunkData;
  1323.         chunkData.Add(chunk);
  1324.         chunkData.AddData(pStreamData, nCount * nElemSize);
  1325.  
  1326.         return m_pChunkFile->AddChunk(
  1327.           ChunkType_DataStream,
  1328.           STREAM_DATA_CHUNK_DESC_0800::VERSION,
  1329.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1330.           chunkData.GetData(), chunkData.GetSize());
  1331. }
  1332.  
  1333. //////////////////////////////////////////////////////////////////////////
  1334. int CSaverCGF::SavePhysicalDataChunk(const void* pData, int nSize, bool bSwapEndian)
  1335. {
  1336.         MESH_PHYSICS_DATA_CHUNK_DESC_0800 chunk;
  1337.         ZeroStruct(chunk);
  1338.  
  1339.         chunk.nDataSize = nSize;
  1340.  
  1341.         SwapEndian(chunk, bSwapEndian);
  1342.  
  1343.         CChunkData chunkData;
  1344.         chunkData.Add(chunk);
  1345.         chunkData.AddData(pData, nSize);
  1346.  
  1347.         return m_pChunkFile->AddChunk(
  1348.           ChunkType_MeshPhysicsData,
  1349.           MESH_PHYSICS_DATA_CHUNK_DESC_0800::VERSION,
  1350.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1351.           chunkData.GetData(), chunkData.GetSize());
  1352. }
  1353.  
  1354. //////////////////////////////////////////////////////////////////////////
  1355. int CSaverCGF::SaveExportFlags(bool bSwapEndian)
  1356. {
  1357.         if (m_bDoNotSaveNonMeshData)
  1358.         {
  1359.                 return -1;
  1360.         }
  1361.  
  1362.         EXPORT_FLAGS_CHUNK_DESC chunk;
  1363.         ZeroStruct(chunk);
  1364.  
  1365.         CExportInfoCGF* pExpInfo = m_pCGF->GetExportInfo();
  1366.         if (pExpInfo->bMergeAllNodes)
  1367.         {
  1368.                 chunk.flags |= EXPORT_FLAGS_CHUNK_DESC::MERGE_ALL_NODES;
  1369.         }
  1370.         if (pExpInfo->bUseCustomNormals)
  1371.         {
  1372.                 chunk.flags |= EXPORT_FLAGS_CHUNK_DESC::USE_CUSTOM_NORMALS;
  1373.         }
  1374.         if (pExpInfo->bHaveAutoLods)
  1375.         {
  1376.                 chunk.flags |= EXPORT_FLAGS_CHUNK_DESC::HAVE_AUTO_LODS;
  1377.         }
  1378.         if (pExpInfo->bWantF32Vertices)
  1379.         {
  1380.                 chunk.flags |= EXPORT_FLAGS_CHUNK_DESC::WANT_F32_VERTICES;
  1381.         }
  1382.         if (pExpInfo->b8WeightsPerVertex)
  1383.         {
  1384.                 chunk.flags |= EXPORT_FLAGS_CHUNK_DESC::EIGHT_WEIGHTS_PER_VERTEX;
  1385.         }
  1386.         if (pExpInfo->bMakeVCloth)
  1387.         {
  1388.                 chunk.flags |= EXPORT_FLAGS_CHUNK_DESC::MAKE_VCLOTH;
  1389.         }
  1390.  
  1391.         if (pExpInfo->bFromColladaXSI)
  1392.         {
  1393.                 chunk.assetAuthorTool |= EXPORT_FLAGS_CHUNK_DESC::FROM_COLLADA_XSI;
  1394.         }
  1395.         if (pExpInfo->bFromColladaMAX)
  1396.         {
  1397.                 chunk.assetAuthorTool |= EXPORT_FLAGS_CHUNK_DESC::FROM_COLLADA_MAX;
  1398.         }
  1399.         if (pExpInfo->bFromColladaMAYA)
  1400.         {
  1401.                 chunk.assetAuthorTool |= EXPORT_FLAGS_CHUNK_DESC::FROM_COLLADA_MAYA;
  1402.         }
  1403.  
  1404.         chunk.authorToolVersion = pExpInfo->authorToolVersion;
  1405.  
  1406.         static_assert(sizeof(chunk.rc_version) == sizeof(pExpInfo->rc_version), "Invalid type size!");
  1407.         memcpy(&chunk.rc_version[0], &pExpInfo->rc_version[0], sizeof(pExpInfo->rc_version));
  1408.  
  1409.         cry_strcpy(chunk.rc_version_string, pExpInfo->rc_version_string);
  1410.  
  1411.         SwapEndian(chunk, bSwapEndian);
  1412.  
  1413.         return m_pChunkFile->AddChunk(
  1414.           ChunkType_ExportFlags,
  1415.           EXPORT_FLAGS_CHUNK_DESC::VERSION,
  1416.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1417.           &chunk, sizeof(chunk));
  1418. }
  1419.  
  1420. //////////////////////////////////////////////////////////////////////////
  1421. void CSaverCGF::SaveMaterials(bool bSwapEndian)
  1422. {
  1423.         for (int i = 0; i < m_pCGF->GetNodeCount(); ++i)
  1424.         {
  1425.                 CMaterialCGF* const pMaterialCGF = m_pCGF->GetNode(i)->pMaterial;
  1426.                 if (pMaterialCGF)
  1427.                 {
  1428.                         SaveMaterial(pMaterialCGF, bSwapEndian);
  1429.                 }
  1430.         }
  1431. }
  1432.  
  1433. //////////////////////////////////////////////////////////////////////////
  1434. int CSaverCGF::SaveMaterial(CMaterialCGF* pMtl, bool bSwapEndian)
  1435. {
  1436.         // Check whether the material has already been saved.
  1437.         if (m_savedMaterials.find(pMtl) != m_savedMaterials.end())
  1438.         {
  1439.                 return pMtl->nChunkId;
  1440.         }
  1441.  
  1442.         m_savedMaterials.insert(pMtl);
  1443.  
  1444.         MTL_NAME_CHUNK_DESC_0802 chunk;
  1445.         ZeroStruct(chunk);
  1446.  
  1447.         cry_strcpy(chunk.name, pMtl->name);
  1448.  
  1449.         DynArray<int32> nPhysicalizeTypeArray;
  1450.         DynArray<char> names;
  1451.  
  1452.         int nSubMaterials = int(pMtl->subMaterials.size());
  1453.  
  1454.         if (nSubMaterials == 0)
  1455.         {
  1456.                 nPhysicalizeTypeArray.push_back(pMtl->nPhysicalizeType);
  1457.         }
  1458.         else
  1459.         {
  1460.                 if (nSubMaterials > MAX_SUB_MATERIALS)
  1461.                 {
  1462.         #if defined(RESOURCE_COMPILER)
  1463.                         RCLogError(
  1464.                           "Material %s uses %d sub-materials but maximum allowed is %d.", pMtl->name, nSubMaterials, MAX_SUB_MATERIALS);
  1465.         #else
  1466.                         CryWarning(
  1467.                           VALIDATOR_MODULE_3DENGINE, VALIDATOR_ERROR,
  1468.                           "Material %s uses %d sub-materials but maximum allowed is %d.", pMtl->name, nSubMaterials, MAX_SUB_MATERIALS);
  1469.         #endif
  1470.                         nSubMaterials = MAX_SUB_MATERIALS;
  1471.                 }
  1472.                 nPhysicalizeTypeArray.resize(nSubMaterials, PHYS_GEOM_TYPE_DEFAULT);
  1473.  
  1474.                 for (int childIndex = 0; childIndex < nSubMaterials; ++childIndex)
  1475.                 {
  1476.                         CMaterialCGF* childMaterial = pMtl->subMaterials[childIndex];
  1477.                         if (childMaterial)
  1478.                         {
  1479.                                 nPhysicalizeTypeArray[childIndex] = childMaterial->nPhysicalizeType;
  1480.                                 for (int i = 0; childMaterial->name[i] != 0; ++i)
  1481.                                 {
  1482.                                         names.push_back(childMaterial->name[i]);
  1483.                                 }
  1484.                         }
  1485.                         names.push_back(0);
  1486.                 }
  1487.         }
  1488.  
  1489.         chunk.nSubMaterials = nSubMaterials;
  1490.  
  1491.         SwapEndian(chunk, bSwapEndian);
  1492.         SwapEndian(&nPhysicalizeTypeArray[0], nPhysicalizeTypeArray.size(), bSwapEndian);
  1493.  
  1494.         CChunkData chunkData;
  1495.         chunkData.Add(chunk);
  1496.         chunkData.AddData(&nPhysicalizeTypeArray[0], nPhysicalizeTypeArray.size() * sizeof(nPhysicalizeTypeArray[0]));
  1497.         if (!names.empty())
  1498.         {
  1499.                 chunkData.AddData(&names[0], names.size() * sizeof(names[0]));
  1500.         }
  1501.  
  1502.         pMtl->nChunkId = m_pChunkFile->AddChunk(
  1503.           ChunkType_MtlName,
  1504.           MTL_NAME_CHUNK_DESC_0802::VERSION,
  1505.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1506.           chunkData.GetData(), chunkData.GetSize());
  1507.  
  1508.         return pMtl->nChunkId;
  1509. }
  1510.  
  1511. int CSaverCGF::SaveController829(bool bSwapEndian, const CONTROLLER_CHUNK_DESC_0829& ctrlChunk, void* pData, int nSize)
  1512. {
  1513.         CChunkData chunkData;
  1514.         chunkData.Add(ctrlChunk);
  1515.         chunkData.AddData(pData, nSize);
  1516.  
  1517.         return m_pChunkFile->AddChunk(
  1518.           ChunkType_Controller,
  1519.           CONTROLLER_CHUNK_DESC_0829::VERSION,
  1520.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1521.           chunkData.GetData(), chunkData.GetSize());
  1522. }
  1523.  
  1524. int CSaverCGF::SaveController832(bool bSwapEndian, const CONTROLLER_CHUNK_DESC_0832& ctrlChunk, void* pData, int nSize)
  1525. {
  1526.         CChunkData chunkData;
  1527.         chunkData.Add(ctrlChunk);
  1528.         chunkData.AddData(pData, nSize);
  1529.  
  1530.         return m_pChunkFile->AddChunk(
  1531.           ChunkType_Controller,
  1532.           CONTROLLER_CHUNK_DESC_0832::VERSION,
  1533.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1534.           chunkData.GetData(), chunkData.GetSize());
  1535. }
  1536.  
  1537. int CSaverCGF::SaveControllerDB905(bool bSwapEndian, const CONTROLLER_CHUNK_DESC_0905& ctrlChunk, void* pData, int nSize)
  1538. {
  1539.         CChunkData chunkData;
  1540.         chunkData.Add(ctrlChunk);
  1541.         chunkData.AddData(pData, nSize);
  1542.  
  1543.         return m_pChunkFile->AddChunk(
  1544.           ChunkType_Controller,
  1545.           CONTROLLER_CHUNK_DESC_0905::VERSION,
  1546.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1547.           chunkData.GetData(), chunkData.GetSize());
  1548. }
  1549.  
  1550. //////////////////////////////////////////////////////////////////////////
  1551. int CSaverCGF::SaveFoliage()
  1552. {
  1553.         FOLIAGE_INFO_CHUNK_DESC chunk;
  1554.         ZeroStruct(chunk);
  1555.  
  1556.         SFoliageInfoCGF& fi = *m_pCGF->GetFoliageInfo();
  1557.  
  1558.         if (fi.nSpines > 0)
  1559.         {
  1560.                 int i, j;
  1561.                 chunk.nSpines = fi.nSpines;
  1562.                 chunk.nSkinnedVtx = fi.nSkinnedVtx;
  1563.                 chunk.nBoneIds = fi.chunkBoneIds.size();
  1564.                 chunk.nSpineVtx = 0;
  1565.  
  1566.                 for (i = 0; i < fi.nSpines; i++)
  1567.                 {
  1568.                         chunk.nSpineVtx += fi.pSpines[i].nVtx;
  1569.                 }
  1570.  
  1571.                 FOLIAGE_SPINE_SUB_CHUNK* const pSpineBuf = new FOLIAGE_SPINE_SUB_CHUNK[fi.nSpines];
  1572.                 Vec3* const pSpineVtx = new Vec3[chunk.nSpineVtx];
  1573.                 Vec4* const pSpineSegDim = new Vec4[chunk.nSpineVtx];
  1574.  
  1575.                 memset(pSpineBuf, 0, sizeof(pSpineBuf[0]) * fi.nSpines);
  1576.  
  1577.                 for (i = j = 0; i < fi.nSpines; j += fi.pSpines[i++].nVtx)
  1578.                 {
  1579.                         pSpineBuf[i].nVtx = fi.pSpines[i].nVtx;
  1580.                         pSpineBuf[i].len = fi.pSpines[i].len;
  1581.                         pSpineBuf[i].navg = fi.pSpines[i].navg;
  1582.                         pSpineBuf[i].iAttachSpine = fi.pSpines[i].iAttachSpine + 1;
  1583.                         pSpineBuf[i].iAttachSeg = fi.pSpines[i].iAttachSeg + 1;
  1584.                         memcpy(pSpineVtx + j, fi.pSpines[i].pVtx, fi.pSpines[i].nVtx * sizeof(Vec3));
  1585.                         memcpy(pSpineSegDim + j, fi.pSpines[i].pSegDim, fi.pSpines[i].nVtx * sizeof(Vec4));
  1586.                 }
  1587.  
  1588.                 CChunkData chunkData;
  1589.                 chunkData.Add(chunk);
  1590.                 chunkData.AddData(pSpineBuf, sizeof(pSpineBuf[0]) * fi.nSpines);
  1591.                 chunkData.AddData(pSpineVtx, sizeof(pSpineVtx[0]) * chunk.nSpineVtx);
  1592.                 chunkData.AddData(pSpineSegDim, sizeof(pSpineSegDim[0]) * chunk.nSpineVtx);
  1593.                 chunkData.AddData(fi.pBoneMapping, sizeof(fi.pBoneMapping[0]) * fi.nSkinnedVtx);
  1594.                 chunkData.AddData(&fi.chunkBoneIds[0], sizeof(fi.chunkBoneIds[0]) * fi.chunkBoneIds.size());
  1595.  
  1596.                 delete[] pSpineSegDim;
  1597.                 delete[] pSpineVtx;
  1598.                 delete[] pSpineBuf;
  1599.  
  1600.                 return m_pChunkFile->AddChunk(
  1601.                   ChunkType_FoliageInfo,
  1602.                   FOLIAGE_INFO_CHUNK_DESC::VERSION,
  1603.                   eEndianness_Native,
  1604.                   chunkData.GetData(), chunkData.GetSize());
  1605.         }
  1606.         else
  1607.         {
  1608.                 return 0;
  1609.         }
  1610. }
  1611.  
  1612. //////////////////////////////////////////////////////////////////////////
  1613.  
  1614. int CSaverCGF::SaveVCloth(bool bSwapEndian)
  1615. {
  1616.         const SVClothInfoCGF* const pVClothInfo = m_pCGF->GetVClothInfo();
  1617.         CChunkData chunkData;
  1618.  
  1619.         CSaverVCloth saver(chunkData, pVClothInfo, bSwapEndian);
  1620.         saver.WriteChunkHeader();
  1621.         saver.WriteChunkVertices();
  1622.         saver.WriteTriangleData();
  1623.         saver.WriteLraNotAttachedOrdered();
  1624.         saver.WriteLinks();
  1625.  
  1626.         return m_pChunkFile->AddChunk(
  1627.           ChunkType_VCloth,
  1628.           VCLOTH_CHUNK::VERSION,
  1629.           (bSwapEndian ? eEndianness_NonNative : eEndianness_Native),
  1630.           chunkData.GetData(), chunkData.GetSize());
  1631. }
  1632.  
  1633.         #if defined(RESOURCE_COMPILER)
  1634.  
  1635. int CSaverCGF::SaveTCB3Track(CInternalSkinningInfo* pSkinningInfo, int trackIndex)
  1636. {
  1637.         return CSaverAnim::SaveTCB3Track(m_pChunkFile, pSkinningInfo, trackIndex);
  1638. }
  1639.  
  1640. int CSaverCGF::SaveTCBQTrack(CInternalSkinningInfo* pSkinningInfo, int trackIndex)
  1641. {
  1642.         return CSaverAnim::SaveTCBQTrack(m_pChunkFile, pSkinningInfo, trackIndex);
  1643. }
  1644.  
  1645. int CSaverCGF::SaveTiming(CInternalSkinningInfo* pSkinningInfo)
  1646. {
  1647.         return CSaverAnim::SaveTiming(m_pChunkFile, pSkinningInfo->m_nStart, pSkinningInfo->m_nEnd);
  1648. }
  1649.  
  1650.         #endif
  1651.  
  1652. #endif
  1653.  
downloadCGFSaver.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top