BVB Source Codes

CRYENGINE Show MeshCompiler.cpp Source code

Return Download CRYENGINE: download MeshCompiler.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:   MeshCompiler.cpp
  5. //  Version:     v1.00
  6. //  Created:     5/11/2004 by Timur.
  7. //  Compilers:   Visual Studio.NET 2003
  8. //  Description:
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15. #include "MeshCompiler.h"
  16. #include "TangentSpaceCalculation.h"
  17. #if CRY_PLATFORM_WINDOWS
  18.         #include "ForsythFaceReorderer.h"
  19. #endif
  20.  
  21. #include <cstring>    // memset()
  22.  
  23. namespace mesh_compiler
  24. {
  25.  
  26. //////////////////////////////////////////////////////////////////////////
  27. CMeshCompiler::CMeshCompiler()
  28.         : m_pVertexMap(0)
  29.         , m_pIndexMap(0)
  30. {
  31. }
  32.  
  33. //////////////////////////////////////////////////////////////////////////
  34. CMeshCompiler::~CMeshCompiler()
  35. {
  36. }
  37.  
  38. #if CRY_PLATFORM_WINDOWS
  39.  
  40. namespace
  41. {
  42.  
  43. struct VertexLess
  44. {
  45.         const CMesh& mesh;
  46.  
  47.         VertexLess(const CMesh& a_mesh)
  48.                 : mesh(a_mesh)
  49.         {
  50.                 assert(mesh.m_pPositionsF16 == 0);
  51.         }
  52.  
  53.         bool operator()(int a, int b) const
  54.         {
  55.                 if (mesh.m_pTopologyIds && mesh.m_pTopologyIds[a] != mesh.m_pTopologyIds[b])
  56.                 {
  57.                         return mesh.m_pTopologyIds[a] < mesh.m_pTopologyIds[b];
  58.                 }
  59.  
  60.                 int res = memcmp(&mesh.m_pPositions[a], &mesh.m_pPositions[b], sizeof(mesh.m_pPositions[a]));
  61.                 if (res)
  62.                 {
  63.                         return res < 0;
  64.                 }
  65.  
  66.                 if ((mesh.m_pNorms && (res = memcmp(&mesh.m_pNorms[a], &mesh.m_pNorms[b], sizeof(mesh.m_pNorms[a])))) ||
  67.                     (mesh.m_pTexCoord && (res = memcmp(&mesh.m_pTexCoord[a], &mesh.m_pTexCoord[b], sizeof(mesh.m_pTexCoord[a])))) ||
  68.                     (mesh.m_pColor0 && (res = memcmp(&mesh.m_pColor0[a], &mesh.m_pColor0[b], sizeof(mesh.m_pColor0[a])))) ||
  69.                     (mesh.m_pColor1 && (res = memcmp(&mesh.m_pColor1[a], &mesh.m_pColor1[b], sizeof(mesh.m_pColor1[a])))) ||
  70.                     (mesh.m_pVertMats && (res = memcmp(&mesh.m_pVertMats[a], &mesh.m_pVertMats[b], sizeof(mesh.m_pVertMats[a])))) ||
  71.                     (mesh.m_pTangents && (res = memcmp(&mesh.m_pTangents[a], &mesh.m_pTangents[b], sizeof(mesh.m_pTangents[a])))))
  72.                 {
  73.                         return res < 0;
  74.                 }
  75.  
  76.                 return false;
  77.         }
  78. };
  79.  
  80. // Copies a vertex from old to new mesh
  81. inline void CopyMeshVertex(CMesh& newMesh, int newVertex, const CMesh& oldMesh, int oldVertex)
  82. {
  83.         assert(newVertex < newMesh.GetVertexCount());
  84.         assert(newMesh.m_pPositionsF16 == 0);
  85.         assert(oldMesh.m_pPositionsF16 == 0);
  86.  
  87.         newMesh.m_pPositions[newVertex] = oldMesh.m_pPositions[oldVertex];
  88.         if (oldMesh.m_pNorms)
  89.                 newMesh.m_pNorms[newVertex] = oldMesh.m_pNorms[oldVertex];
  90.         if (oldMesh.m_pTopologyIds)
  91.                 newMesh.m_pTopologyIds[newVertex] = oldMesh.m_pTopologyIds[oldVertex];
  92.         if (oldMesh.m_pTexCoord)
  93.                 newMesh.m_pTexCoord[newVertex] = oldMesh.m_pTexCoord[oldVertex];
  94.         if (oldMesh.m_pColor0)
  95.                 newMesh.m_pColor0[newVertex] = oldMesh.m_pColor0[oldVertex];
  96.         if (oldMesh.m_pColor1)
  97.                 newMesh.m_pColor1[newVertex] = oldMesh.m_pColor1[oldVertex];
  98.         if (oldMesh.m_pVertMats)
  99.                 newMesh.m_pVertMats[newVertex] = oldMesh.m_pVertMats[oldVertex];
  100.         if (oldMesh.m_pTangents)
  101.                 newMesh.m_pTangents[newVertex] = oldMesh.m_pTangents[oldVertex];
  102. }
  103.  
  104. // Modified version of MeshUtils::Mesh::ComputeVertexRemapping()
  105. // Computes vertexOldToNew and vertexNewToOld by detecting duplicate vertices
  106. void ComputeVertexRemapping(const CMesh& mesh, std::vector<int>& vertexOldToNew, std::vector<int>& vertexNewToOld)
  107. {
  108.         const size_t nVerts = mesh.GetVertexCount();
  109.  
  110.         vertexNewToOld.resize(nVerts);
  111.         for (size_t i = 0; i < nVerts; ++i)
  112.         {
  113.                 vertexNewToOld[i] = i;
  114.         }
  115.  
  116.         VertexLess less(mesh);
  117.         std::sort(vertexNewToOld.begin(), vertexNewToOld.end(), less);
  118.  
  119.         vertexOldToNew.resize(nVerts);
  120.  
  121.         int nVertsNew = 0;
  122.         for (size_t i = 0; i < nVerts; ++i)
  123.         {
  124.                 if (i == 0 || less(vertexNewToOld[i - 1], vertexNewToOld[i]))
  125.                 {
  126.                         vertexNewToOld[nVertsNew++] = vertexNewToOld[i];
  127.                 }
  128.                 vertexOldToNew[vertexNewToOld[i]] = nVertsNew - 1;
  129.         }
  130.         vertexNewToOld.resize(nVertsNew);
  131. }
  132.  
  133. } // namespace
  134.  
  135. //////////////////////////////////////////////////////////////////////////
  136.  
  137. namespace
  138. {
  139. class CMeshInputProxy
  140.         : public ITriangleInputProxy
  141. {
  142.         struct Index
  143.         {
  144.                 int index;
  145.                 int origPos;
  146.         };
  147.  
  148.         template<class TComparator>
  149.         void prepareUniqueIndices(std::vector<int>& outIndices, std::vector<Index>& tmp, const TComparator& comparator)
  150.         {
  151.                 const int faceCount = m_mesh.GetFaceCount();
  152.  
  153.                 tmp.resize(faceCount * 3);
  154.                 outIndices.resize(faceCount * 3, -1);
  155.  
  156.                 for (int i = 0; i < faceCount; ++i)
  157.                 {
  158.                         for (int j = 0; j < 3; ++j)
  159.                         {
  160.                                 tmp[i * 3 + j].index = m_mesh.m_pFaces[i].v[j];
  161.                                 tmp[i * 3 + j].origPos = i * 3 + j;
  162.                         }
  163.                 }
  164.  
  165.                 std::sort(tmp.begin(), tmp.end(), comparator);
  166.  
  167.                 int curIndex = -1;
  168.                 for (int i = 0, n = faceCount * 3; i < n; ++i)
  169.                 {
  170.                         if (curIndex < 0 || comparator(tmp[i - 1], tmp[i]))
  171.                         {
  172.                                 curIndex = tmp[i].index;
  173.                         }
  174.                         outIndices[tmp[i].origPos] = curIndex;
  175.                 }
  176.         }
  177.  
  178.         const char* ValidateMesh() const
  179.         {
  180.                 if (m_mesh.m_pPositionsF16)
  181.                 {
  182.                         return "the mesh has 16-bit positions";
  183.                 }
  184.                 if (!m_mesh.m_pFaces)
  185.                 {
  186.                         return "the mesh has no stream with faces";
  187.                 }
  188.                 if (!m_mesh.m_pPositions)
  189.                 {
  190.                         return "the mesh has no stream with positions";
  191.                 }
  192.                 if (!m_mesh.m_pNorms)
  193.                 {
  194.                         return "the mesh has no stream with normals";
  195.                 }
  196.                 if (!m_mesh.m_pTexCoord)
  197.                 {
  198.                         return "the mesh has no stream with texture coordinates";
  199.                 }
  200.  
  201.                 const int faceCount = m_mesh.GetFaceCount();
  202.                 const int vertexCount = m_mesh.GetVertexCount();
  203.                 const int texCoordCount = m_mesh.GetTexCoordCount();
  204.                 if (faceCount <= 0)
  205.                 {
  206.                         return "face count in the mesh is 0";
  207.                 }
  208.                 if (vertexCount <= 0)
  209.                 {
  210.                         return "vertex count in the mesh is 0";
  211.                 }
  212.                 if (texCoordCount <= 0)
  213.                 {
  214.                         return "texture coordinate count in the mesh is 0";
  215.                 }
  216.                 if (vertexCount != texCoordCount)
  217.                 {
  218.                         return "mismatch in number of positions and texture coordinates in the mesh";
  219.                 }
  220.  
  221.                 for (int i = 0; i < faceCount; ++i)
  222.                 {
  223.                         for (int j = 0; j < 3; ++j)
  224.                         {
  225.                                 const int vIdx = m_mesh.m_pFaces[i].v[j];
  226.                                 if (vIdx < 0 || vIdx >= vertexCount)
  227.                                 {
  228.                                         return "a face in the mesh has vertex index that is out of range";
  229.                                 }
  230.                         }
  231.                 }
  232.  
  233.                 // Trying to trigger a crash if a stream size is not correct
  234.                 {
  235.                         Vec3 v(0.0f, 0.0f, 0.0f);
  236.                         SMeshNormal n(v);
  237.                         SMeshTexCoord uv(0, 0);
  238.  
  239.                         v = m_mesh.m_pPositions[0];  // cppcheck-suppress redundantAssignment
  240.                         v = m_mesh.m_pPositions[vertexCount - 1];
  241.                         n = m_mesh.m_pNorms[0];  // cppcheck-suppress redundantAssignment
  242.                         n = m_mesh.m_pNorms[vertexCount - 1];
  243.                         uv = m_mesh.m_pTexCoord[0]; // cppcheck-suppress redundantAssignment
  244.                         uv = m_mesh.m_pTexCoord[vertexCount - 1];
  245.                 }
  246.  
  247.                 return 0;
  248.         }
  249.  
  250. public:
  251.         CMeshInputProxy(const CMesh& inMesh)
  252.                 : m_mesh(inMesh)
  253.         {
  254.                 m_pErrorText = ValidateMesh();
  255.                 if (m_pErrorText)
  256.                 {
  257.                         return;
  258.                 }
  259.  
  260.                 assert(m_mesh.m_pPositionsF16 == 0);
  261.  
  262.                 struct PositionComparator
  263.                 {
  264.                         const Vec3* const pPositions;
  265.                         const int* const  pTopologyIds;
  266.  
  267.                         PositionComparator(const Vec3* const a_pPositions, const int* const a_pTopologyIds)
  268.                                 : pPositions(a_pPositions)
  269.                                 , pTopologyIds(a_pTopologyIds)
  270.                         {
  271.                         }
  272.  
  273.                         bool operator()(const Index& v0, const Index& v1) const
  274.                         {
  275.                                 if (pTopologyIds)
  276.                                 {
  277.                                         const int a = pTopologyIds[v0.index];
  278.                                         const int b = pTopologyIds[v1.index];
  279.                                         if (a != b)
  280.                                         {
  281.                                                 return a < b;
  282.                                         }
  283.                                 }
  284.                                 const Vec3& a = pPositions[v0.index];
  285.                                 const Vec3& b = pPositions[v1.index];
  286.                                 if (a.x != b.x)
  287.                                 {
  288.                                         return a.x < b.x;
  289.                                 }
  290.                                 if (a.y != b.y)
  291.                                 {
  292.                                         return a.y < b.y;
  293.                                 }
  294.                                 return a.z < b.z;
  295.                         }
  296.                 };
  297.  
  298.                 struct NormalComparator
  299.                 {
  300.                         const SMeshNormal* const pNormals;
  301.  
  302.                         NormalComparator(const SMeshNormal* const a_pNormals)
  303.                                 : pNormals(a_pNormals)
  304.                         {
  305.                         }
  306.  
  307.                         bool operator()(const Index& v0, const Index& v1) const
  308.                         {
  309.                                 const SMeshNormal& a = pNormals[v0.index];
  310.                                 const SMeshNormal& b = pNormals[v1.index];
  311.  
  312.                                 return a < b;
  313.                         }
  314.                 };
  315.  
  316.                 struct TexCoordComparator
  317.                 {
  318.                         const SMeshTexCoord* const pTexCoords;
  319.  
  320.                         TexCoordComparator(const SMeshTexCoord* const a_pTexCoords)
  321.                                 : pTexCoords(a_pTexCoords)
  322.                         {
  323.                         }
  324.  
  325.                         bool operator()(const Index& v0, const Index& v1) const
  326.                         {
  327.                                 const SMeshTexCoord& a = pTexCoords[v0.index];
  328.                                 const SMeshTexCoord& b = pTexCoords[v1.index];
  329.  
  330.                                 return a < b;
  331.                         }
  332.                 };
  333.  
  334.                 std::vector<Index> tmp;
  335.                 prepareUniqueIndices(m_posIndx, tmp, PositionComparator(m_mesh.m_pPositions, m_mesh.m_pTopologyIds));
  336.                 prepareUniqueIndices(m_normIndx, tmp, NormalComparator(m_mesh.m_pNorms));
  337.                 prepareUniqueIndices(m_texCoordIndx, tmp, TexCoordComparator(m_mesh.m_pTexCoord));
  338.         }
  339.  
  340.         const char* GetErrorText() const
  341.         {
  342.                 return m_pErrorText;
  343.         }
  344.  
  345.         // interface ITriangleInputProxy ----------------------------------------------
  346.  
  347.         //! /return 0..
  348.         uint32 GetTriangleCount() const
  349.         {
  350.                 return m_mesh.GetFaceCount();
  351.         }
  352.  
  353.         //! /param indwTriNo 0..
  354.         //! /param outdwPos
  355.         //! /param outdwNorm
  356.         //! /param outdwUV
  357.         void GetTriangleIndices(const uint32 indwTriNo, uint32 outdwPos[3], uint32 outdwNorm[3], uint32 outdwUV[3]) const
  358.         {
  359.                 const int* const pPosInds = &m_posIndx[indwTriNo * 3];
  360.                 const int* const pNormInds = &m_normIndx[indwTriNo * 3];
  361.                 const int* const pTexCoordInds = &m_texCoordIndx[indwTriNo * 3];
  362.  
  363.                 for (int j = 0; j < 3; ++j)
  364.                 {
  365.                         outdwPos[j] = pPosInds[j];
  366.                         outdwUV[j] = pTexCoordInds[j];
  367.                         outdwNorm[j] = pNormInds[j];
  368.                 }
  369.         }
  370.  
  371.         //! /param indwPos 0..
  372.         //! /param outfPos
  373.         void GetPos(const uint32 indwPos, Vec3& outfPos) const
  374.         {
  375.                 assert(!m_pErrorText);
  376.                 assert((int)indwPos < m_mesh.GetVertexCount());
  377.                 outfPos = m_mesh.m_pPositions[indwPos];
  378.         }
  379.  
  380.         //! /param indwPos 0..
  381.         //! /param outfUV
  382.         void GetUV(const uint32 indwPos, Vec2& outfUV) const
  383.         {
  384.                 assert(!m_pErrorText);
  385.                 assert((int)indwPos < m_mesh.GetTexCoordCount());
  386.                 outfUV = m_mesh.m_pTexCoord[indwPos].GetUV();
  387.         }
  388.  
  389.         //! /param indwTriNo 0..
  390.         //! /param indwVertNo 0..
  391.         //! /param outfNorm
  392.         void GetNorm(const uint32 indwTriNo, const uint32 indwVertNo, Vec3& outfNorm) const
  393.         {
  394.                 assert(!m_pErrorText);
  395.                 assert((int)indwTriNo < m_mesh.GetFaceCount());
  396.                 assert((int)indwVertNo < 3);
  397.                 const int vIdx = m_mesh.m_pFaces[indwTriNo].v[indwVertNo];
  398.                 assert(vIdx < m_mesh.GetVertexCount());
  399.                 outfNorm = m_mesh.m_pNorms[vIdx].GetN();
  400.         }
  401.         //-----------------------------------------------------------------------------
  402.  
  403. private:
  404.         const CMesh&     m_mesh;
  405.         const char*      m_pErrorText;
  406.         std::vector<int> m_posIndx;       // indices of unique positions (in mesh.m_pPositions) for each corner of each triangle
  407.         std::vector<int> m_normIndx;      // indices of unique normals (in mesh.m_pNorms) for each corner of each triangle
  408.         std::vector<int> m_texCoordIndx;  // indices of unique texture coordinates normals (in mesh.m_pTexCoord) for each corner of each triangle
  409. };
  410. }
  411.  
  412. //do not use vec3 lib to keep it the fallback as it was
  413. inline static Vec3 CrossProd(const Vec3& a, const Vec3& b)
  414. {
  415.         Vec3 ret;
  416.         ret.x = a.y * b.z - a.z * b.y;
  417.         ret.y = a.z * b.x - a.x * b.z;
  418.         ret.z = a.x * b.y - a.y * b.x;
  419.         return ret;
  420. }
  421.  
  422. inline static void GetOtherBaseVec(const Vec3& s, Vec3& a, Vec3& b)
  423. {
  424.         if (fabsf(s.z) > 0.5f)
  425.         {
  426.                 a.x = s.z;
  427.                 a.y = s.y;
  428.                 a.z = -s.x;
  429.         }
  430.         else
  431.         {
  432.                 a.x = s.y;
  433.                 a.y = -s.x;
  434.                 a.z = s.z;
  435.         }
  436.  
  437.         b = CrossProd(s, a).normalize();
  438.         a = CrossProd(b, s).normalize();
  439. }
  440.  
  441. //check packed tangent space and ensure some useful values, fix always according to normal
  442. static void VerifyTangentSpace(SMeshTangents& rTangents, const SMeshNormal& rNormal)
  443. {
  444.         Vec3 normal = rNormal.GetN();
  445.  
  446.         if (normal.GetLengthSquared() < 0.1f)
  447.                 normal = Vec3(0, 0, 1);
  448.         else if (normal.GetLengthSquared() < 0.9f)
  449.                 normal.Normalize();
  450.  
  451.         //unpack first(necessary since the quantization can introduce errors whereas the original float data were different)
  452.         Vec3 tangent, bitangent;
  453.         rTangents.GetTB(tangent, bitangent);
  454.  
  455.         //check if they are equal
  456.         const bool cIsEqual = (tangent == bitangent);
  457.         //check if they are zero
  458.         const bool cTangentIsZero = (tangent.GetLengthSquared() < 0.01f);
  459.         const bool cBitangentIsZero = (bitangent.GetLengthSquared() < 0.01f);
  460.         const bool cbHasBeenChanged = (cIsEqual || cTangentIsZero || cBitangentIsZero);
  461.  
  462.         if (cIsEqual)
  463.         {
  464.                 //fix case where both vec's are equal
  465.                 GetOtherBaseVec(normal, tangent, bitangent);
  466.         }
  467.         else if (cTangentIsZero)
  468.         {
  469.                 //fix case where tangent is zero
  470.                 bitangent.Normalize();//just to make sure
  471.                 if (abs(bitangent * normal) > 0.9f)//if angle between both vecs is to low, calc new one for both
  472.                         GetOtherBaseVec(normal, tangent, bitangent);
  473.                 else
  474.                         tangent = CrossProd(normal, bitangent);
  475.         }
  476.         else if (cBitangentIsZero)
  477.         {
  478.                 //fix case where bitangent is zero
  479.                 tangent.Normalize();//just to make sure
  480.                 if (abs(tangent * normal) > 0.9f)//if angle between both vecs is to low, calc new one for both
  481.                         GetOtherBaseVec(normal, tangent, bitangent);
  482.                 else
  483.                         bitangent = CrossProd(tangent, normal);
  484.         }
  485.  
  486.         //pack altered tangent vecs
  487.         if (cbHasBeenChanged)
  488.         {
  489.                 rTangents = SMeshTangents(tangent, bitangent, normal);
  490.         }
  491. }
  492.  
  493. static void debugDumpMesh(CMesh& mesh, const char* filename)
  494. {
  495.         FILE* f;
  496.         f = fopen(filename, "wb");
  497.         if (!f)
  498.         {
  499.                 return;
  500.         }
  501.  
  502.         fprintf(f, "[Pos]\n");
  503.         for (int i = 0; i < mesh.GetVertexCount(); ++i)
  504.         {
  505.                 fprintf(f, "\t%g %g %g\n", mesh.m_pPositions[i].x, mesh.m_pPositions[i].y, mesh.m_pPositions[i].z);
  506.         }
  507.  
  508.         fprintf(f, "[Nor]\n");
  509.         for (int i = 0; i < mesh.GetVertexCount(); ++i)
  510.         {
  511.                 const Vec3 n = mesh.m_pNorms[i].GetN();
  512.                 fprintf(f, "\t%g %g %g\n", n.x, n.y, n.z);
  513.         }
  514.  
  515.         if (mesh.m_pTexCoord)
  516.         {
  517.                 fprintf(f, "[TexCoord]\n");
  518.                 for (int i = 0; i < mesh.GetTexCoordCount(); ++i)
  519.                 {
  520.                         const Vec2 uv = mesh.m_pTexCoord[i].GetUV();
  521.                         fprintf(f, "\t%g %g\n", uv.x, uv.y);
  522.                 }
  523.         }
  524.  
  525.         fprintf(f, "[Faces]\n");
  526.         for (int i = 0; i < mesh.GetIndexCount(); i += 3)
  527.         {
  528.                 fprintf(f, "\t%u %u %u\n", (uint)mesh.m_pIndices[i + 0], (uint)mesh.m_pIndices[i + 1], (uint)mesh.m_pIndices[i + 2]);
  529.         }
  530.  
  531.         fclose(f);
  532. }
  533.  
  534. //////////////////////////////////////////////////////////////////////////
  535. // Optimizes CMesh.
  536. // IMPLEMENTATION:
  537. // . Sort|Group faces by materials
  538. // . Create vertex buffer with sequence of (possibly non-unique) vertices, 3 verts per face
  539. // . For each (non-unique) vertex calculate the tangent base
  540. // . Index the mesh (Compact Vertices): detect and delete duplicate vertices
  541. // . Remove degenerated triangles in the generated mesh (GetIndices())
  542. // . Sort vertices and indices for GPU cache
  543. bool CMeshCompiler::Compile(CMesh& mesh, int flags)
  544. {
  545.         assert(mesh.m_pPositionsF16 == 0);
  546.  
  547.         if (mesh.GetFaceCount() == 0)
  548.         {
  549.                 // the mesh is either empty or already compiled
  550.  
  551.                 const int cVertexCount = mesh.GetVertexCount();
  552.                 if (cVertexCount == 0)
  553.                 {
  554.                         // the mesh is empty, nothing to do
  555.                         return true;
  556.                 }
  557.  
  558.                 // the mesh is already compiled, likely to have a refresh here: just verify and correct tangent space
  559.                 if (mesh.m_pTangents && mesh.m_pNorms)
  560.                 {
  561.                         for (int i = 0; i < cVertexCount; ++i)
  562.                         {
  563.                                 VerifyTangentSpace(mesh.m_pTangents[i], mesh.m_pNorms[i]);
  564.                         }
  565.                 }
  566.  
  567.                 return true;
  568.         }
  569.  
  570.         // the mesh has faces - it means that it's a non-compiled mesh. let's compile it.
  571.  
  572.         // Check input data
  573.         {
  574.                 if (mesh.GetIndexCount() > 0)
  575.                 {
  576.                         m_LastError.Format(
  577.                           "Mesh compilation failed - input mesh has both indices and faces. Contact an RC programmer.");
  578.                         return false;
  579.                 }
  580.  
  581.                 const int vertexCount = mesh.GetVertexCount();
  582.                 const int faceCount = mesh.GetFaceCount();
  583.  
  584.                 for (int i = 0; i < faceCount; ++i)
  585.                 {
  586.                         const SMeshFace& face = mesh.m_pFaces[i];
  587.                         if (face.nSubset < 0 || face.nSubset >= MAX_SUB_MATERIALS)
  588.                         {
  589.                                 m_LastError.Format(
  590.                                   "Mesh compilation failed - face %d has bad subset index %d (allowed range is [0;%d]). Contact an RC programmer.",
  591.                                   i, (int)face.nSubset, MAX_SUB_MATERIALS - 1);
  592.                                 return false;
  593.                         }
  594.                         for (int j = 0; j < 3; ++j)
  595.                         {
  596.                                 const int vIdx = mesh.m_pFaces[i].v[j];
  597.                                 if (vIdx < 0 || vIdx >= vertexCount)
  598.                                 {
  599.                                         m_LastError.Format(
  600.                                           "Mesh compilation failed - face %d has bad vertex index %d (allowed range is [0;%d]). Contact an RC programmer.",
  601.                                           i, vIdx, vertexCount - 1);
  602.                                         return false;
  603.                                 }
  604.                         }
  605.                 }
  606.         }
  607.  
  608.         //////////////////////////////////////////////////////////////////////////
  609.         // Calculate Tangent Space.
  610.         // Results will be stored in bases[] and m_thash_table[]
  611.         //////////////////////////////////////////////////////////////////////////
  612.  
  613.         std::vector<SMeshTangents> bases;
  614.  
  615.         // m_thash_table[] contains a std::vector<SBasisFace> per subset.
  616.         // Vector contains faces belonging to the subset.
  617.         // Face contains three indices of elements in bases[].
  618.         static_assert(CRY_ARRAY_COUNT(m_thash_table) == MAX_SUB_MATERIALS, "Invalid array size!");
  619.         for (int i = 0; i < MAX_SUB_MATERIALS; ++i)
  620.         {
  621.                 m_thash_table[i].clear();
  622.         }
  623.  
  624.         if (flags & MESH_COMPILE_TANGENTS)
  625.         {
  626.                 // Generate tangent basis vectors before indexing per-material
  627.  
  628.                 CMeshInputProxy Input(mesh);
  629.                 if (Input.GetErrorText())
  630.                 {
  631.                         m_LastError.Format("Mesh compilation failed - %s. Contact an RC or Editor programmer.", Input.GetErrorText());
  632.                         return false;
  633.                 }
  634.  
  635.                 CTangentSpaceCalculation tangents;
  636.                 string errorMessage;
  637.  
  638.                 // calculate the base matrices
  639.                 const bool bUseCustomNormals = (flags & MESH_COMPILE_USE_CUSTOM_NORMALS) != 0;
  640.                 const bool bIgnoreSomeErrors = (flags & MESH_COMPILE_IGNORE_TANGENT_SPACE_ERRORS) != 0;
  641.                 const eCalculateTangentSpaceErrorCode nErrorCode = tangents.CalculateTangentSpace(Input, bUseCustomNormals, bIgnoreSomeErrors, errorMessage);
  642.  
  643.                 if (nErrorCode != CALCULATE_TANGENT_SPACE_NO_ERRORS)
  644.                 {
  645.                         const char* errorCodeMessage;
  646.  
  647.                         switch (nErrorCode)
  648.                         {
  649.                         case VERTICES_SHARING_COORDINATES:
  650.                                 errorCodeMessage = "\nReason: two vertices of a face share the same coordinate. Run the Select Degenerate Faces Script and fix any highlighted vertices.\n";
  651.                                 break;
  652.                         case ALL_VERTICES_ON_THE_SAME_VECTOR:
  653.                                 errorCodeMessage = "\nReason: three vertices of a face lie on the same line. Run the Select Degenerate Faces Script and fix any highlighted vertices.\n";
  654.                                 break;
  655.                         case BROKEN_TEXTURE_COORDINATES:
  656.                                 errorCodeMessage = "\nReason: texture coordinates are not valid. Double check that the UV's have space on the UV map.\n";
  657.                                 break;
  658.                         case MEMORY_ALLOCATION_FAILED:
  659.                                 errorCodeMessage = "\nReason: failed to allocate memory for Mikkelsen's Tangent Basis algorithm.";
  660.                                 break;
  661.                         default:
  662.                                 errorCodeMessage = "\nInternal error.\n";
  663.                                 break;
  664.                         }
  665.  
  666.                         m_LastError.Format(" CalculateTangentSpace() failed, fix model.\n\nErrorCode:%d\n\n%s%s", nErrorCode, errorMessage.c_str(), errorCodeMessage);
  667.                         return false;
  668.                 }
  669.  
  670.                 const uint32 dwCnt = tangents.GetBaseCount();
  671.                 const uint32 dwTris = Input.GetTriangleCount();
  672.  
  673.                 bases.resize(dwCnt);
  674.  
  675.                 std::vector<int> basisIndices;
  676.                 basisIndices.resize(dwTris * 3);
  677.  
  678.                 for (uint32 dwTri = 0; dwTri < dwTris; dwTri++)
  679.                 {
  680.                         uint32 dwBaseIndx[3];
  681.  
  682.                         tangents.GetTriangleBaseIndices(dwTri, dwBaseIndx);
  683.  
  684.                         // for every corner of the triangle
  685.                         for (uint32 i = 0; i < 3; i++)
  686.                         {
  687.                                 assert(dwBaseIndx[i] < dwCnt);
  688.                                 basisIndices[dwTri * 3 + i] = dwBaseIndx[i];  // set the base vector
  689.                         }
  690.                 }
  691.  
  692.                 for (uint32 i = 0; i < dwCnt; i++)
  693.                 {
  694.                         Vec3 Tangent, Bitangent, Normal;
  695.  
  696.                         tangents.GetBase(i, (float*)&Tangent, (float*)&Bitangent, (float*)&Normal);
  697.  
  698.                         bases[i] = SMeshTangents(Tangent, Bitangent, Normal);
  699.  
  700.                         VerifyTangentSpace(bases[i], SMeshNormal(Normal));
  701.                 }
  702.  
  703.                 const int faceCount = mesh.GetFaceCount();
  704.                 for (int i = 0; i < faceCount; i++)
  705.                 {
  706.                         SBasisFace fc;
  707.  
  708.                         fc.v[0] = basisIndices[i * 3 + 0];
  709.                         fc.v[1] = basisIndices[i * 3 + 1];
  710.                         fc.v[2] = basisIndices[i * 3 + 2];
  711.  
  712.                         const SMeshFace& face = mesh.m_pFaces[i];
  713.                         m_thash_table[face.nSubset].push_back(fc);
  714.                 }
  715.         }
  716.         //////////////////////////////////////////////////////////////////////////
  717.  
  718.         // Create new mesh that will store non-unique vertices, 3 vertices per face
  719.  
  720.         const int max_vert_num = mesh.GetFaceCount() * 3;
  721.  
  722.         CMesh outMesh;
  723.         outMesh.CopyFrom(mesh);
  724.         outMesh.SetVertexCount(max_vert_num);
  725.         outMesh.ReallocStream(CMesh::VERT_MATS, max_vert_num);
  726.         if (mesh.m_pTopologyIds)
  727.                 outMesh.ReallocStream(CMesh::TOPOLOGY_IDS, max_vert_num);
  728.         if (mesh.m_pTexCoord)
  729.                 outMesh.ReallocStream(CMesh::TEXCOORDS, max_vert_num);
  730.         if (flags & MESH_COMPILE_TANGENTS)
  731.                 outMesh.ReallocStream(CMesh::TANGENTS, max_vert_num);
  732.         if (mesh.m_pColor0)
  733.                 outMesh.ReallocStream(CMesh::COLORS_0, max_vert_num);
  734.         if (mesh.m_pColor1)
  735.                 outMesh.ReallocStream(CMesh::COLORS_1, max_vert_num);
  736.  
  737.         // temporarily store original subset index in subset's nNumVerts
  738.         {
  739.                 const uint32 nSubsets = outMesh.GetSubSetCount();
  740.                 assert(nSubsets <= MAX_SUB_MATERIALS);
  741.                 for (uint32 i = 0; i < nSubsets; i++)
  742.                 {
  743.                         outMesh.m_subsets[i].nNumVerts = i;
  744.                 }
  745.         }
  746.  
  747.         // Sort subsets depending on their physicalization type (don't do it for character meshes (with mapping)).
  748.         if (!m_pVertexMap)
  749.         {
  750.                 // move normal physicalize subsets to the beginning (needed for breakable objects)
  751.                 for (uint32 i = 0; i < (uint32)outMesh.m_subsets.size(); i++)
  752.                 {
  753.                         const SMeshSubset& outSubset = outMesh.m_subsets[i];
  754.                         if (outSubset.nPhysicalizeType == PHYS_GEOM_TYPE_DEFAULT)
  755.                         {
  756.                                 const SMeshSubset tmp = outSubset;
  757.                                 outMesh.m_subsets.erase(outMesh.m_subsets.begin() + i);
  758.                                 outMesh.m_subsets.insert(outMesh.m_subsets.begin(), tmp);
  759.                         }
  760.                 }
  761.                 // move physicalize proxy subsets to the end
  762.                 for (int nSubset = (int)outMesh.m_subsets.size() - 1; nSubset >= 0; --nSubset)
  763.                 {
  764.                         const SMeshSubset& outSubset = outMesh.m_subsets[nSubset];
  765.                         if (outSubset.nPhysicalizeType != PHYS_GEOM_TYPE_NONE && outSubset.nPhysicalizeType != PHYS_GEOM_TYPE_DEFAULT)
  766.                         {
  767.                                 const SMeshSubset tmp = outSubset;
  768.                                 outMesh.m_subsets.erase(outMesh.m_subsets.begin() + nSubset);
  769.                                 outMesh.m_subsets.push_back(tmp);
  770.                         }
  771.                 }
  772.         }
  773.  
  774.         // m_vhash_table[] contains a std::vector<SMeshFace> per subset.
  775.         // Vector contains faces belonging to the subset.
  776.         // Face contains three indices of elements in mesh.m_pVertices[].
  777.         static_assert(CRY_ARRAY_COUNT(m_vhash_table) == MAX_SUB_MATERIALS, "Invalid array size!");
  778.         for (int i = 0; i < MAX_SUB_MATERIALS; ++i)
  779.         {
  780.                 m_vhash_table[i].clear();
  781.         }
  782.         for (int i = 0, n = mesh.GetFaceCount(); i < n; ++i)
  783.         {
  784.                 const SMeshFace& face = mesh.m_pFaces[i];
  785.                 assert(face.nSubset < MAX_SUB_MATERIALS);
  786.                 m_vhash_table[face.nSubset].push_back(&face);
  787.         }
  788.  
  789.         // Fill the new mesh with vertices
  790.         {
  791.                 int buff_vert_count = 0;
  792.  
  793.                 for (int t = 0; t < outMesh.GetSubSetCount(); t++)
  794.                 {
  795.                         SMeshSubset& subset = outMesh.m_subsets[t];
  796.                         // memorize the starting index of this material's face range
  797.                         subset.nFirstIndexId = buff_vert_count;
  798.  
  799.                         // scan through all the faces using the shader #t.
  800.                         // note: subset's nNumVerts contains original subset index
  801.                         const size_t nNumFacesInSubset = m_vhash_table[subset.nNumVerts].size();
  802.                         for (size_t i = 0; i < nNumFacesInSubset; ++i)
  803.                         {
  804.                                 const SMeshFace* const pFace = m_vhash_table[subset.nNumVerts][i];
  805.  
  806.                                 for (int v = 0; v < 3; ++v)
  807.                                 {
  808.                                         CopyMeshVertex(outMesh, buff_vert_count, mesh, pFace->v[v]);
  809.  
  810.                                         if (!bases.empty())
  811.                                         {
  812.                                                 const SBasisFace& tFace = m_thash_table[subset.nNumVerts][i];
  813.                                                 outMesh.m_pTangents[buff_vert_count] = bases[tFace.v[v]];
  814.                                         }
  815.  
  816.                                         // store subset id to prevent vertex sharing between materials during re-compacting
  817.                                         outMesh.m_pVertMats[buff_vert_count] = pFace->nSubset;
  818.  
  819.                                         ++buff_vert_count;
  820.                                 }
  821.                         }
  822.  
  823.                         subset.nNumIndices = buff_vert_count - subset.nFirstIndexId;
  824.                 }
  825.  
  826.                 if (buff_vert_count != max_vert_num)
  827.                 {
  828.                         m_LastError.Format("Mesh compilation failed - internal error in handling vertices (real#:%d, expected#:%d). Contact an RC programmer.", buff_vert_count, max_vert_num);
  829.                         return false;
  830.                 }
  831.         }
  832.  
  833.         if (!CreateIndicesAndDeleteDuplicateVertices(outMesh))
  834.         {
  835.                 return false;
  836.         }
  837.  
  838.         bool bFoundDegenerateFaces = false;
  839.         if (flags & MESH_COMPILE_VALIDATE)
  840.         {
  841.                 bFoundDegenerateFaces = CheckForDegenerateFaces(outMesh);
  842.         }
  843.  
  844.         if (flags & MESH_COMPILE_OPTIMIZE)
  845.         {
  846.                 const bool bOk = StripifyMesh_Forsyth(outMesh);
  847.                 if (!bOk)
  848.                 {
  849.                         m_LastError.Format("Mesh compilation failed - stripifier failed. Contact an RC programmer.");
  850.                         return false;
  851.                 }
  852.         }
  853.         else
  854.         {
  855.                 if (m_pIndexMap || m_pVertexMap)
  856.                 {
  857.                         m_LastError.Format("Mesh compilation failed - face and/or index maps cannot be requested without OPTIMIZE. Contact an RC programmer.");
  858.                         return false;
  859.                 }
  860.         }
  861.  
  862.         FindVertexRanges(outMesh);
  863.  
  864.         // Copy modified mesh back to original one.
  865.         mesh.CopyFrom(outMesh);
  866.  
  867.         // Calculate bounding box.
  868.         mesh.m_bbox.Reset();
  869.         for (int i = 0, n = mesh.GetVertexCount(); i < n; ++i)
  870.         {
  871.                 mesh.m_bbox.Add(mesh.m_pPositions[i]);
  872.         }
  873.  
  874.         if (flags & MESH_COMPILE_VALIDATE)
  875.         {
  876.                 if (bFoundDegenerateFaces)
  877.                 {
  878.                         m_LastError.Format("Mesh contains degenerate faces.");
  879.                         return false;
  880.                 }
  881.  
  882.                 const char* pErrorDescription = 0;
  883.                 if (!mesh.Validate(&pErrorDescription))
  884.                 {
  885.                         m_LastError.Format("Internal error in mesh compiling (%s). Contact an RC programmer.", pErrorDescription);
  886.                         return false;
  887.                 }
  888.         }
  889.  
  890.         return true;
  891. }
  892.  
  893. bool CMeshCompiler::StripifyMesh_Forsyth(CMesh& mesh)
  894. {
  895.         if (mesh.GetFaceCount() > 0)
  896.         {
  897.                 // We don't support stripifying of meshes with explicit faces, we support meshes with index array only
  898.                 return false;
  899.         }
  900.  
  901.         enum { kCACHESIZE_GEFORCE3 = 24 };
  902.         const size_t cacheSize = kCACHESIZE_GEFORCE3;
  903.         enum { kVerticesPerFace = 3 };
  904.  
  905.         // Prepare mapping buffers
  906.         if (m_pIndexMap)
  907.         {
  908.                 const int n = mesh.GetIndexCount();
  909.                 m_pIndexMap->resize(n);
  910.                 for (int i = 0; i < n; ++i)
  911.                 {
  912.                         (*m_pIndexMap)[i] = mesh.m_pIndices[i];
  913.                 }
  914.         }
  915.         if (m_pVertexMap)
  916.         {
  917.                 const int n = mesh.GetVertexCount();
  918.                 m_pVertexMap->resize(n, -1);
  919.         }
  920.  
  921.         CMesh newMesh;
  922.         newMesh.CopyFrom(mesh);
  923.  
  924.         // TODO: make those variables members of CMeshCompiler so we don't need to allocate memory every time
  925.         ForsythFaceReorderer ffr;
  926.         std::vector<uint32> buffer0;
  927.         std::vector<uint32> buffer1;
  928.  
  929.         // Reserve space
  930.         //
  931.         // We will use buffer0 for both subset's indices and for mapping from old vertex indices
  932.         // to new vertex indices (number of vertices decreases in case some vertices are not
  933.         // referenced from indices). In the latter case having size of buffer0 equal to number of
  934.         // indices is not enough if indices refer vertices in a spare fashion. Unfortunately,
  935.         // to compute range of referenced vertices we need to scan all indices in all subsets
  936.         // which is not fast.
  937.         {
  938.                 int maxIndexCountInSubset = 0;
  939.                 int maxVertexCountInSubset = 0;
  940.  
  941.                 for (int i = 0; i < newMesh.GetSubSetCount(); i++)
  942.                 {
  943.                         const SMeshSubset& subset = mesh.m_subsets[i];
  944.  
  945.                         if (subset.nNumIndices == 0)
  946.                         {
  947.                                 continue;
  948.                         }
  949.                         if (subset.nNumIndices < 0)
  950.                         {
  951.                                 assert(0);
  952.                                 return false;
  953.                         }
  954.                         if (subset.nNumIndices % kVerticesPerFace != 0)
  955.                         {
  956.                                 assert(0);
  957.                                 return false;
  958.                         }
  959.                         if (subset.nFirstIndexId % kVerticesPerFace != 0)
  960.                         {
  961.                                 assert(0);
  962.                                 return false;
  963.                         }
  964.  
  965.                         if (maxIndexCountInSubset < subset.nNumIndices)
  966.                         {
  967.                                 maxIndexCountInSubset = subset.nNumIndices;
  968.                         }
  969.  
  970.                         int subsetMinIndex = mesh.m_pIndices[subset.nFirstIndexId];
  971.                         int subsetMaxIndex = subsetMinIndex;
  972.                         for (int j = 1; j < subset.nNumIndices; ++j)
  973.                         {
  974.                                 const int idx = mesh.m_pIndices[subset.nFirstIndexId + j];
  975.                                 if (idx < subsetMinIndex)
  976.                                 {
  977.                                         subsetMinIndex = idx;
  978.                                 }
  979.                                 else if (idx > subsetMaxIndex)
  980.                                 {
  981.                                         subsetMaxIndex = idx;
  982.                                 }
  983.                         }
  984.  
  985.                         if (maxVertexCountInSubset < subsetMaxIndex - subsetMinIndex + 1)
  986.                         {
  987.                                 maxVertexCountInSubset = subsetMaxIndex - subsetMinIndex + 1;
  988.                         }
  989.                 }
  990.  
  991.                 buffer0.resize(max(maxIndexCountInSubset, maxVertexCountInSubset));
  992.                 buffer1.resize(maxIndexCountInSubset);
  993.         }
  994.  
  995.         int newVertexCount = 0;
  996.  
  997.         for (int i = 0; i < newMesh.GetSubSetCount(); i++)
  998.         {
  999.                 const SMeshSubset& subset = mesh.m_subsets[i];
  1000.  
  1001.                 if (subset.nNumIndices == 0)
  1002.                 {
  1003.                         continue;
  1004.                 }
  1005.  
  1006.                 int subsetMinIndex = mesh.m_pIndices[subset.nFirstIndexId];
  1007.                 int subsetMaxIndex = subsetMinIndex;
  1008.                 for (int j = 1; j < subset.nNumIndices; ++j)
  1009.                 {
  1010.                         const int idx = mesh.m_pIndices[subset.nFirstIndexId + j];
  1011.                         if (idx < subsetMinIndex)
  1012.                         {
  1013.                                 subsetMinIndex = idx;
  1014.                         }
  1015.                         else if (idx > subsetMaxIndex)
  1016.                         {
  1017.                                 subsetMaxIndex = idx;
  1018.                         }
  1019.                 }
  1020.  
  1021.                 for (int j = 0; j < subset.nNumIndices; ++j)
  1022.                 {
  1023.                         buffer0[j] = mesh.m_pIndices[subset.nFirstIndexId + j] - subsetMinIndex;
  1024.                 }
  1025.  
  1026.                 const bool bOk = ffr.reorderFaces(
  1027.                   cacheSize,
  1028.                   kVerticesPerFace,
  1029.                   subset.nNumIndices,
  1030.                   &buffer0[0],  // inVertexIndices
  1031.                   &buffer1[0],  // outVertexIndices
  1032.                   0);           // faceToOldFace[] - we don't need it
  1033.  
  1034.                 if (!bOk)
  1035.                 {
  1036.                         return false;
  1037.                 }
  1038.  
  1039.                 // Reorder vertices
  1040.  
  1041.                 SMeshSubset& newSubset = newMesh.m_subsets[i];
  1042.                 newSubset.nFirstVertId = newVertexCount;
  1043.                 newSubset.nNumVerts = 0;
  1044.                 newSubset.nFirstIndexId = subset.nFirstIndexId;
  1045.                 newSubset.nNumIndices = subset.nNumIndices;
  1046.  
  1047.                 const int oldSubsetVertexCount = (int)subsetMaxIndex - (int)subsetMinIndex + 1;
  1048.  
  1049.                 assert(buffer0.size() >= (size_t)oldSubsetVertexCount);
  1050.                 memset(&buffer0[0], -1, sizeof(buffer0[0]) * oldSubsetVertexCount);
  1051.  
  1052.                 for (int j = 0; j < subset.nNumIndices; ++j)
  1053.                 {
  1054.                         const uint32 idx = buffer1[j];
  1055.                         const int oldVertexIndex = subsetMinIndex + idx;
  1056.                         if (buffer0[idx] == -1)
  1057.                         {
  1058.                                 if (m_pVertexMap)
  1059.                                 {
  1060.                                         (*m_pVertexMap)[oldVertexIndex] = newVertexCount;
  1061.                                 }
  1062.                                 buffer0[idx] = newVertexCount;
  1063.                                 //copy from old -> new vertex buffer
  1064.                                 CopyMeshVertex(newMesh, newVertexCount, mesh, oldVertexIndex);
  1065.                                 ++newVertexCount;
  1066.                                 ++newSubset.nNumVerts;
  1067.                         }
  1068.                         newMesh.m_pIndices[subset.nFirstIndexId + j] = buffer0[idx];
  1069.                 }
  1070.         }
  1071.  
  1072.         newMesh.SetVertexCount(newVertexCount);
  1073.  
  1074.         mesh.CopyFrom(newMesh);
  1075.  
  1076.         return true;
  1077. }
  1078.  
  1079. //////////////////////////////////////////////////////////////////////////
  1080. //
  1081. // Input:
  1082. //   mesh contains mesh.GetVertexCount() vertices (vertex data are stored in
  1083. //   m_pPositions[] m_pNorms[] and in other data streams).
  1084. //   Face and index streams are ignored.
  1085. // Output:
  1086. //   1) mesh contains unique vertices only.
  1087. //   2) data stream mesh.m_pIndices has "inputMesh.GetVertexCount()"
  1088. //      indices (one output index per each input vertex).
  1089. //      note that an output index points to an *unique* vertex in the
  1090. //      output mesh.
  1091. //   3) data stream mesh.m_pFaces is empty.
  1092. //
  1093. // For example vertices [A, B, B, C, A, D] will be transformed to
  1094. // [A, B, C, D], and index array created will be [0, 1, 1, 2, 0, 3].
  1095. //
  1096. // Note that mesh.subsets[] is neither used nor changed.
  1097. //
  1098. bool CMeshCompiler::CreateIndicesAndDeleteDuplicateVertices(CMesh& mesh)
  1099. {
  1100.         assert(mesh.m_pPositionsF16 == 0);
  1101.  
  1102.         const int oldVertexCount = mesh.GetVertexCount();
  1103.         if (oldVertexCount <= 0)
  1104.         {
  1105.                 return true;
  1106.         }
  1107.  
  1108.         CMesh oldMesh;
  1109.         oldMesh.CopyFrom(mesh);
  1110.  
  1111.         std::vector<int> vertexOldToNew;
  1112.         std::vector<int> vertexNewToOld;
  1113.         ComputeVertexRemapping(oldMesh, vertexOldToNew, vertexNewToOld);
  1114.  
  1115.         const int newVertexCount = (int)vertexNewToOld.size();
  1116.  
  1117.         assert(vertexOldToNew.size() == oldVertexCount);
  1118.         const uint maxVertexCount = (sizeof(vtx_idx) == 2 ? 0xffff : 0x7fffffff);
  1119.         if (newVertexCount > maxVertexCount)
  1120.         {
  1121.                 m_LastError.Format("Too many vertices in mesh after compilation: %u (limit is %u).", (uint)newVertexCount, (uint)maxVertexCount);
  1122.                 return false;
  1123.         }
  1124.  
  1125.         for (int i = 0; i < newVertexCount; ++i)
  1126.         {
  1127.                 CopyMeshVertex(mesh, i, oldMesh, vertexNewToOld[i]);
  1128.         }
  1129.  
  1130.         mesh.SetVertexCount(newVertexCount);
  1131.         if (mesh.m_pNorms)
  1132.                 mesh.ReallocStream(CMesh::NORMALS, newVertexCount);
  1133.         if (mesh.m_pTexCoord)
  1134.                 mesh.ReallocStream(CMesh::TEXCOORDS, newVertexCount);
  1135.         if (mesh.m_pColor0)
  1136.                 mesh.ReallocStream(CMesh::COLORS_0, newVertexCount);
  1137.         if (mesh.m_pColor1)
  1138.                 mesh.ReallocStream(CMesh::COLORS_1, newVertexCount);
  1139.         if (mesh.m_pTangents)
  1140.                 mesh.ReallocStream(CMesh::TANGENTS, newVertexCount);
  1141.         mesh.ReallocStream(CMesh::TOPOLOGY_IDS, 0);
  1142.         mesh.ReallocStream(CMesh::VERT_MATS, 0);
  1143.         mesh.SetFaceCount(0);
  1144.         mesh.SetIndexCount(oldVertexCount);
  1145.         for (int i = 0; i < oldVertexCount; ++i)
  1146.         {
  1147.                 mesh.m_pIndices[i] = vertexOldToNew[i];
  1148.         }
  1149.  
  1150.         return true;
  1151. }
  1152.  
  1153. //////////////////////////////////////////////////////////////////////////
  1154. bool CMeshCompiler::CheckForDegenerateFaces(const CMesh& mesh)
  1155. {
  1156.         for (int i = 0; i < mesh.GetSubSetCount(); i++)
  1157.         {
  1158.                 const SMeshSubset& subset = mesh.m_subsets[i];
  1159.                 for (int j = subset.nFirstIndexId; j < subset.nFirstIndexId + subset.nNumIndices; j += 3)
  1160.                 {
  1161.                         if (mesh.m_pIndices[j + 0] == mesh.m_pIndices[j + 1] ||
  1162.                             mesh.m_pIndices[j + 1] == mesh.m_pIndices[j + 2] ||
  1163.                             mesh.m_pIndices[j + 2] == mesh.m_pIndices[j + 0])
  1164.                         {
  1165.                                 return true;
  1166.                         }
  1167.                 }
  1168.         }
  1169.         return false;
  1170. }
  1171.  
  1172. //////////////////////////////////////////////////////////////////////////
  1173. void CMeshCompiler::FindVertexRanges(CMesh& mesh)
  1174. {
  1175.         assert(mesh.m_pPositionsF16 == 0);
  1176.  
  1177.         const int nNumIndices = mesh.GetIndexCount();
  1178.  
  1179.         // Find vertex range (both index and spacial ranges) for each material (needed for rendering)
  1180.         for (int i = 0; i < mesh.GetSubSetCount(); i++)
  1181.         {
  1182.                 SMeshSubset& subset = mesh.m_subsets[i];
  1183.  
  1184.                 if (subset.nNumIndices == 0)
  1185.                 {
  1186.                         subset.nNumVerts = 0;
  1187.                         continue;
  1188.                 }
  1189.  
  1190.                 if (subset.nNumIndices + subset.nFirstIndexId > nNumIndices)
  1191.                 {
  1192.                         assert(0);
  1193.                         continue;
  1194.                 }
  1195.  
  1196.                 int nMin = INT_MAX;
  1197.                 int nMax = INT_MIN;
  1198.                 Vec3 vMin = SetMaxBB();
  1199.                 Vec3 vMax = SetMinBB();
  1200.  
  1201.                 for (int j = subset.nFirstIndexId; j < subset.nNumIndices + subset.nFirstIndexId; j++)
  1202.                 {
  1203.                         int index = mesh.m_pIndices[j];
  1204.                         Vec3 v = mesh.m_pPositions[index];
  1205.                         vMin.CheckMin(v);
  1206.                         vMax.CheckMax(v);
  1207.                         nMin = min(nMin, index);
  1208.                         nMax = max(nMax, index);
  1209.                 }
  1210.                 subset.vCenter = (vMin + vMax) * 0.5f;
  1211.                 subset.fRadius = (vMin - subset.vCenter).GetLength();
  1212.                 subset.nFirstVertId = nMin;
  1213.                 subset.nNumVerts = nMax - nMin + 1;
  1214.         }
  1215. }
  1216.  
  1217. #endif   // #if CRY_PLATFORM_WINDOWS
  1218.  
  1219. //////////////////////////////////////////////////////////////////////////
  1220. bool CMeshCompiler::CompareMeshes(const CMesh& mesh1, const CMesh& mesh2)
  1221. {
  1222.         if (mesh1.m_subsets.size() != mesh2.m_subsets.size())
  1223.                 return false;
  1224.  
  1225.         if (mesh1.GetFaceCount() != mesh2.GetFaceCount())
  1226.                 return false;
  1227.         if (mesh1.GetVertexCount() != mesh2.GetVertexCount())
  1228.                 return false;
  1229.         if (mesh1.GetTexCoordCount() != mesh2.GetTexCoordCount())
  1230.                 return false;
  1231.         if (mesh1.GetIndexCount() != mesh2.GetIndexCount())
  1232.                 return false;
  1233.  
  1234.         if (!mesh1.CompareStreams(mesh2))
  1235.                 return false;
  1236.  
  1237.         return true;
  1238. }
  1239.  
  1240. } // namespace mesh_compiler
  1241.  
downloadMeshCompiler.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