Prechádzať zdrojové kódy

Refactoring: Reuse code from GeometryUtils

Kim Kulling 2 rokov pred
rodič
commit
d58201a579

+ 8 - 0
code/Geometry/GeometryUtils.cpp

@@ -89,4 +89,12 @@ bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
     return true;
 }
 
+// ------------------------------------------------------------------------------------------------
+void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, 
+        size_t numVectors) {
+    for (size_t i=0; i<numVectors; ++i) {
+		    vectorArrayOut[i] = vectorArrayIn[i].Normalize();
+	  }
+}
+
 } // namespace Assimp

+ 13 - 1
code/Geometry/GeometryUtils.h

@@ -47,7 +47,7 @@ namespace Assimp {
 // ---------------------------------------------------------------------------
 /// @brief This helper class supports some basic geometry algorithms.
 // ---------------------------------------------------------------------------
-class GeometryUtils {
+class ASSIMP_API GeometryUtils {
 public:
     static ai_real heron( ai_real a, ai_real b, ai_real c );
     
@@ -63,7 +63,19 @@ public:
     /// @return The area.
     static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh );
 
+    /// @brief 
+    /// @param ray 
+    /// @param planePos 
+    /// @param planeNormal 
+    /// @param pos 
+    /// @return 
     static bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, const aiVector3D& planeNormal, aiVector3D& pos);
+
+    /// @brief 
+    /// @param vectorArrayIn 
+    /// @param vectorArrayOut 
+    /// @param numVectors 
+    static void normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors);
 };
 
 } // namespace Assimp

+ 129 - 160
code/PostProcessing/ComputeUVMappingProcess.cpp

@@ -42,30 +42,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /** @file GenUVCoords step */
 
 #include "ComputeUVMappingProcess.h"
+#include "Geometry/GeometryUtils.h"
 #include "ProcessHelper.h"
 #include <assimp/Exceptional.h>
-#include "Geometry/GeometryUtils.h"
 
 using namespace Assimp;
 
 namespace {
 
-    const static aiVector3D base_axis_y(0.0,1.0,0.0);
-    const static aiVector3D base_axis_x(1.0,0.0,0.0);
-    const static aiVector3D base_axis_z(0.0,0.0,1.0);
-    const static ai_real angle_epsilon = ai_real( 0.95 );
-}
+const static aiVector3D base_axis_y(0.0, 1.0, 0.0);
+const static aiVector3D base_axis_x(1.0, 0.0, 0.0);
+const static aiVector3D base_axis_z(0.0, 0.0, 1.0);
+const static ai_real angle_epsilon = ai_real(0.95);
+} // namespace
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const {
-    return  (pFlags & aiProcess_GenUVCoords) != 0;
+bool ComputeUVMappingProcess::IsActive(unsigned int pFlags) const {
+    return (pFlags & aiProcess_GenUVCoords) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Find the first empty UV channel in a mesh
-inline unsigned int FindEmptyUVChannel (aiMesh* mesh) {
-    for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
+inline unsigned int FindEmptyUVChannel(aiMesh *mesh) {
+    for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++m)
         if (!mesh->mTextureCoords[m]) {
             return m;
         }
@@ -76,19 +76,19 @@ inline unsigned int FindEmptyUVChannel (aiMesh* mesh) {
 
 // ------------------------------------------------------------------------------------------------
 // Try to remove UV seams
-void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
+void RemoveUVSeams(aiMesh *mesh, aiVector3D *out) {
     // TODO: just a very rough algorithm. I think it could be done
     // much easier, but I don't know how and am currently too tired to
     // to think about a better solution.
 
-    const static ai_real LOWER_LIMIT = ai_real( 0.1 );
-    const static ai_real UPPER_LIMIT = ai_real( 0.9 );
+    const static ai_real LOWER_LIMIT = ai_real(0.1);
+    const static ai_real UPPER_LIMIT = ai_real(0.9);
 
-    const static ai_real LOWER_EPSILON = ai_real( 10e-3 );
-    const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 );
+    const static ai_real LOWER_EPSILON = ai_real(10e-3);
+    const static ai_real UPPER_EPSILON = ai_real(1.0 - 10e-3);
 
-    for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) {
-        const aiFace& face = mesh->mFaces[fidx];
+    for (unsigned int fidx = 0; fidx < mesh->mNumFaces; ++fidx) {
+        const aiFace &face = mesh->mFaces[fidx];
         if (face.mNumIndices < 3) {
             continue; // triangles and polygons only, please
         }
@@ -100,20 +100,18 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
         // but the assumption that a face with at least one very small
         // on the one side and one very large U coord on the other side
         // lies on a UV seam should work for most cases.
-        for (unsigned int n = 0; n < face.mNumIndices;++n)
-        {
-            if (out[face.mIndices[n]].x < LOWER_LIMIT)
-            {
+        for (unsigned int n = 0; n < face.mNumIndices; ++n) {
+            if (out[face.mIndices[n]].x < LOWER_LIMIT) {
                 smallV = n;
 
                 // If we have a U value very close to 0 we can't
                 // round the others to 0, too.
                 if (out[face.mIndices[n]].x <= LOWER_EPSILON)
                     zero = true;
-                else round_to_zero = true;
+                else
+                    round_to_zero = true;
             }
-            if (out[face.mIndices[n]].x > UPPER_LIMIT)
-            {
+            if (out[face.mIndices[n]].x > UPPER_LIMIT) {
                 large = n;
 
                 // If we have a U value very close to 1 we can't
@@ -122,10 +120,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
                     one = true;
             }
         }
-        if (smallV != face.mNumIndices && large != face.mNumIndices)
-        {
-            for (unsigned int n = 0; n < face.mNumIndices;++n)
-            {
+        if (smallV != face.mNumIndices && large != face.mNumIndices) {
+            for (unsigned int n = 0; n < face.mNumIndices; ++n) {
                 // If the u value is over the upper limit and no other u
                 // value of that face is 0, round it to 0
                 if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
@@ -141,9 +137,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
                 // Due to numerical inaccuracies one U coord becomes 0, the
                 // other 1. But we do still have a third UV coord to determine
                 // to which side we must round to.
-                else if (one && zero)
-                {
-                    if (round_to_zero && out[face.mIndices[n]].x >=  UPPER_EPSILON)
+                else if (one && zero) {
+                    if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
                         out[face.mIndices[n]].x = 0.0;
                     else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
                         out[face.mIndices[n]].x = 1.0;
@@ -154,8 +149,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
 }
 
 // ------------------------------------------------------------------------------------------------
-void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
-{
+void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
     aiVector3D center, min, max;
     FindMeshCenter(mesh, center, min, max);
 
@@ -163,7 +157,7 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
     // currently the mapping axis will always be one of x,y,z, except if the
     // PretransformVertices step is used (it transforms the meshes into worldspace,
     // thus changing the mapping axis)
-    if (axis * base_axis_x >= angle_epsilon)    {
+    if (axis * base_axis_x >= angle_epsilon) {
 
         // For each point get a normalized projection vector in the sphere,
         // get its longitude and latitude and map them to their respective
@@ -177,58 +171,54 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
         // Thus we can derive:
         // lat  = arcsin (z)
         // lon  = arctan (y/x)
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
-            out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
-                (std::asin  (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
+            out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
+                    (std::asin(diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
         }
-    }
-    else if (axis * base_axis_y >= angle_epsilon)   {
+    } else if (axis * base_axis_y >= angle_epsilon) {
         // ... just the same again
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
-            out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
-                (std::asin  (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
+            out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
+                    (std::asin(diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
         }
-    }
-    else if (axis * base_axis_z >= angle_epsilon)   {
+    } else if (axis * base_axis_z >= angle_epsilon) {
         // ... just the same again
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
-            out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
-                (std::asin  (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
+            out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
+                    (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
         }
     }
     // slower code path in case the mapping axis is not one of the coordinate system axes
-    else    {
+    else {
         aiMatrix4x4 mTrafo;
-        aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
+        aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
 
         // again the same, except we're applying a transformation now
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize();
-            out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
-                (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D diff = ((mTrafo * mesh->mVertices[pnt]) - center).Normalize();
+            out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
+                    (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
         }
     }
 
-
     // Now find and remove UV seams. A seam occurs if a face has a tcoord
     // close to zero on the one side, and a tcoord close to one on the
     // other side.
-    RemoveUVSeams(mesh,out);
+    RemoveUVSeams(mesh, out);
 }
 
 // ------------------------------------------------------------------------------------------------
-void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
-{
+void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
     aiVector3D center, min, max;
 
     // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
     // currently the mapping axis will always be one of x,y,z, except if the
     // PretransformVertices step is used (it transforms the meshes into worldspace,
     // thus changing the mapping axis)
-    if (axis * base_axis_x >= angle_epsilon)    {
+    if (axis * base_axis_x >= angle_epsilon) {
         FindMeshCenter(mesh, center, min, max);
         const ai_real diff = max.x - min.x;
 
@@ -236,116 +226,110 @@ void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector
         // directly to the texture V axis. The other axis is derived from
         // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
         // 'c' is the center point of the mesh.
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D& pos = mesh->mVertices[pnt];
-            aiVector3D& uv  = out[pnt];
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D &pos = mesh->mVertices[pnt];
+            aiVector3D &uv = out[pnt];
 
             uv.y = (pos.x - min.x) / diff;
-            uv.x = (std::atan2( pos.z - center.z, pos.y - center.y) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
+            uv.x = (std::atan2(pos.z - center.z, pos.y - center.y) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
         }
-    }
-    else if (axis * base_axis_y >= angle_epsilon)   {
+    } else if (axis * base_axis_y >= angle_epsilon) {
         FindMeshCenter(mesh, center, min, max);
         const ai_real diff = max.y - min.y;
 
         // just the same ...
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D& pos = mesh->mVertices[pnt];
-            aiVector3D& uv  = out[pnt];
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D &pos = mesh->mVertices[pnt];
+            aiVector3D &uv = out[pnt];
 
             uv.y = (pos.y - min.y) / diff;
-            uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
+            uv.x = (std::atan2(pos.x - center.x, pos.z - center.z) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
         }
-    }
-    else if (axis * base_axis_z >= angle_epsilon)   {
+    } else if (axis * base_axis_z >= angle_epsilon) {
         FindMeshCenter(mesh, center, min, max);
         const ai_real diff = max.z - min.z;
 
         // just the same ...
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D& pos = mesh->mVertices[pnt];
-            aiVector3D& uv  = out[pnt];
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D &pos = mesh->mVertices[pnt];
+            aiVector3D &uv = out[pnt];
 
             uv.y = (pos.z - min.z) / diff;
-            uv.x = (std::atan2( pos.y - center.y, pos.x - center.x) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
+            uv.x = (std::atan2(pos.y - center.y, pos.x - center.x) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
         }
     }
     // slower code path in case the mapping axis is not one of the coordinate system axes
     else {
         aiMatrix4x4 mTrafo;
-        aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
-        FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
+        aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
+        FindMeshCenterTransformed(mesh, center, min, max, mTrafo);
         const ai_real diff = max.y - min.y;
 
         // again the same, except we're applying a transformation now
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){
-            const aiVector3D pos = mTrafo* mesh->mVertices[pnt];
-            aiVector3D& uv  = out[pnt];
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
+            aiVector3D &uv = out[pnt];
 
             uv.y = (pos.y - min.y) / diff;
-            uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
+            uv.x = (std::atan2(pos.x - center.x, pos.z - center.z) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
         }
     }
 
     // Now find and remove UV seams. A seam occurs if a face has a tcoord
     // close to zero on the one side, and a tcoord close to one on the
     // other side.
-    RemoveUVSeams(mesh,out);
+    RemoveUVSeams(mesh, out);
 }
 
 // ------------------------------------------------------------------------------------------------
-void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
-{
-    ai_real diffu,diffv;
+void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
+    ai_real diffu, diffv;
     aiVector3D center, min, max;
 
     // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
     // currently the mapping axis will always be one of x,y,z, except if the
     // PretransformVertices step is used (it transforms the meshes into worldspace,
     // thus changing the mapping axis)
-    if (axis * base_axis_x >= angle_epsilon)    {
+    if (axis * base_axis_x >= angle_epsilon) {
         FindMeshCenter(mesh, center, min, max);
         diffu = max.z - min.z;
         diffv = max.y - min.y;
 
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D& pos = mesh->mVertices[pnt];
-            out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.0);
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D &pos = mesh->mVertices[pnt];
+            out[pnt].Set((pos.z - min.z) / diffu, (pos.y - min.y) / diffv, 0.0);
         }
-    }
-    else if (axis * base_axis_y >= angle_epsilon)   {
+    } else if (axis * base_axis_y >= angle_epsilon) {
         FindMeshCenter(mesh, center, min, max);
         diffu = max.x - min.x;
         diffv = max.z - min.z;
 
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D& pos = mesh->mVertices[pnt];
-            out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0);
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D &pos = mesh->mVertices[pnt];
+            out[pnt].Set((pos.x - min.x) / diffu, (pos.z - min.z) / diffv, 0.0);
         }
-    }
-    else if (axis * base_axis_z >= angle_epsilon)   {
+    } else if (axis * base_axis_z >= angle_epsilon) {
         FindMeshCenter(mesh, center, min, max);
         diffu = max.x - min.x;
         diffv = max.y - min.y;
 
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
-            const aiVector3D& pos = mesh->mVertices[pnt];
-            out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0);
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
+            const aiVector3D &pos = mesh->mVertices[pnt];
+            out[pnt].Set((pos.x - min.x) / diffu, (pos.y - min.y) / diffv, 0.0);
         }
     }
     // slower code path in case the mapping axis is not one of the coordinate system axes
-    else
-    {
+    else {
         aiMatrix4x4 mTrafo;
-        aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
-        FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
+        aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
+        FindMeshCenterTransformed(mesh, center, min, max, mTrafo);
         diffu = max.x - min.x;
         diffv = max.z - min.z;
 
         // again the same, except we're applying a transformation now
-        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
             const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
-            out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0);
+            out[pnt].Set((pos.x - min.x) / diffu, (pos.z - min.z) / diffv, 0.0);
         }
     }
 
@@ -353,14 +337,12 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
 }
 
 // ------------------------------------------------------------------------------------------------
-void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* )
-{
+void ComputeUVMappingProcess::ComputeBoxMapping(aiMesh *, aiVector3D *) {
     ASSIMP_LOG_ERROR("Mapping type currently not implemented");
 }
 
 // ------------------------------------------------------------------------------------------------
-void ComputeUVMappingProcess::Execute( aiScene* pScene)
-{
+void ComputeUVMappingProcess::Execute(aiScene *pScene) {
     ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
     char buffer[1024];
 
@@ -371,23 +353,18 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
 
     /*  Iterate through all materials and search for non-UV mapped textures
      */
-    for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
-    {
+    for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
         mappingStack.clear();
-        aiMaterial* mat = pScene->mMaterials[i];
-        for (unsigned int a = 0; a < mat->mNumProperties;++a)
-        {
-            aiMaterialProperty* prop = mat->mProperties[a];
-            if (!::strcmp( prop->mKey.data, "$tex.mapping"))
-            {
-                aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
-                if (aiTextureMapping_UV != mapping)
-                {
-                    if (!DefaultLogger::isNullLogger())
-                    {
+        aiMaterial *mat = pScene->mMaterials[i];
+        for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
+            aiMaterialProperty *prop = mat->mProperties[a];
+            if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
+                aiTextureMapping &mapping = *((aiTextureMapping *)prop->mData);
+                if (aiTextureMapping_UV != mapping) {
+                    if (!DefaultLogger::isNullLogger()) {
                         ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
-                            aiTextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
-                            MappingTypeToString(mapping));
+                                aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex,
+                                MappingTypeToString(mapping));
 
                         ASSIMP_LOG_INFO(buffer);
                     }
@@ -395,70 +372,62 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
                     if (aiTextureMapping_OTHER == mapping)
                         continue;
 
-                    MappingInfo info (mapping);
+                    MappingInfo info(mapping);
 
                     // Get further properties - currently only the major axis
-                    for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
-                    {
-                        aiMaterialProperty* prop2 = mat->mProperties[a2];
+                    for (unsigned int a2 = 0; a2 < mat->mNumProperties; ++a2) {
+                        aiMaterialProperty *prop2 = mat->mProperties[a2];
                         if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
                             continue;
 
-                        if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis"))  {
-                            info.axis = *((aiVector3D*)prop2->mData);
+                        if (!::strcmp(prop2->mKey.data, "$tex.mapaxis")) {
+                            info.axis = *((aiVector3D *)prop2->mData);
                             break;
                         }
                     }
 
-                    unsigned int idx( 99999999 );
+                    unsigned int idx(99999999);
 
                     // Check whether we have this mapping mode already
-                    std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
-                    if (mappingStack.end() != it)
-                    {
+                    std::list<MappingInfo>::iterator it = std::find(mappingStack.begin(), mappingStack.end(), info);
+                    if (mappingStack.end() != it) {
                         idx = (*it).uv;
-                    }
-                    else
-                    {
+                    } else {
                         /*  We have found a non-UV mapped texture. Now
-                        *   we need to find all meshes using this material
-                        *   that we can compute UV channels for them.
-                        */
-                        for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
-                        {
-                            aiMesh* mesh = pScene->mMeshes[m];
+                         *   we need to find all meshes using this material
+                         *   that we can compute UV channels for them.
+                         */
+                        for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
+                            aiMesh *mesh = pScene->mMeshes[m];
                             unsigned int outIdx = 0;
-                            if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
-                                !mesh->mNumVertices)
-                            {
+                            if (mesh->mMaterialIndex != i || (outIdx = FindEmptyUVChannel(mesh)) == UINT_MAX ||
+                                    !mesh->mNumVertices) {
                                 continue;
                             }
 
                             // Allocate output storage
-                            aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
+                            aiVector3D *p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
 
-                            switch (mapping)
-                            {
+                            switch (mapping) {
                             case aiTextureMapping_SPHERE:
-                                ComputeSphereMapping(mesh,info.axis,p);
+                                ComputeSphereMapping(mesh, info.axis, p);
                                 break;
                             case aiTextureMapping_CYLINDER:
-                                ComputeCylinderMapping(mesh,info.axis,p);
+                                ComputeCylinderMapping(mesh, info.axis, p);
                                 break;
                             case aiTextureMapping_PLANE:
-                                ComputePlaneMapping(mesh,info.axis,p);
+                                ComputePlaneMapping(mesh, info.axis, p);
                                 break;
                             case aiTextureMapping_BOX:
-                                ComputeBoxMapping(mesh,p);
+                                ComputeBoxMapping(mesh, p);
                                 break;
                             default:
                                 ai_assert(false);
                             }
-                            if (m && idx != outIdx)
-                            {
+                            if (m && idx != outIdx) {
                                 ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
-                                    "this material have equal numbers of UV channels. The UV index stored in  "
-                                    "the material structure does therefore not apply for all meshes. ");
+                                                "this material have equal numbers of UV channels. The UV index stored in  "
+                                                "the material structure does therefore not apply for all meshes. ");
                             }
                             idx = outIdx;
                         }
@@ -468,7 +437,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
 
                     // Update the material property list
                     mapping = aiTextureMapping_UV;
-                    ((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
+                    ((aiMaterial *)mat)->AddProperty(&idx, 1, AI_MATKEY_UVWSRC(prop->mSemantic, prop->mIndex));
                 }
             }
         }

+ 12 - 13
code/PostProcessing/DropFaceNormalsProcess.cpp

@@ -42,27 +42,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 /** @file Implementation of the post processing step to drop face
-* normals for all imported faces.
-*/
-
+ * normals for all imported faces.
+ */
 
 #include "DropFaceNormalsProcess.h"
+#include <assimp/Exceptional.h>
 #include <assimp/postprocess.h>
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
-#include <assimp/Exceptional.h>
 
 using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const {
-    return  (pFlags & aiProcess_DropNormals) != 0;
+bool DropFaceNormalsProcess::IsActive(unsigned int pFlags) const {
+    return (pFlags & aiProcess_DropNormals) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void DropFaceNormalsProcess::Execute( aiScene* pScene) {
+void DropFaceNormalsProcess::Execute(aiScene *pScene) {
     ASSIMP_LOG_DEBUG("DropFaceNormalsProcess begin");
 
     if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
@@ -70,21 +69,21 @@ void DropFaceNormalsProcess::Execute( aiScene* pScene) {
     }
 
     bool bHas = false;
-    for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
-        bHas |= this->DropMeshFaceNormals( pScene->mMeshes[a]);
+    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
+        bHas |= this->DropMeshFaceNormals(pScene->mMeshes[a]);
     }
-    if (bHas)   {
+    if (bHas) {
         ASSIMP_LOG_INFO("DropFaceNormalsProcess finished. "
-            "Face normals have been removed");
+                        "Face normals have been removed");
     } else {
         ASSIMP_LOG_DEBUG("DropFaceNormalsProcess finished. "
-            "No normals were present");
+                         "No normals were present");
     }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-bool DropFaceNormalsProcess::DropMeshFaceNormals (aiMesh* mesh) {
+bool DropFaceNormalsProcess::DropMeshFaceNormals(aiMesh *mesh) {
     ai_assert(nullptr != mesh);
 
     if (nullptr == mesh->mNormals) {

+ 39 - 41
code/PostProcessing/FindDegenerates.cpp

@@ -41,11 +41,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 /** @file  FindDegenerates.cpp
  *  @brief Implementation of the FindDegenerates post-process step.
-*/
+ */
 
-#include "ProcessHelper.h"
 #include "FindDegenerates.h"
 #include "Geometry/GeometryUtils.h"
+#include "ProcessHelper.h"
 
 #include <assimp/Exceptional.h>
 
@@ -54,35 +54,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 // Correct node indices to meshes and remove references to deleted mesh
-static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap);
+static void updateSceneGraph(aiNode *pNode, const std::unordered_map<unsigned int, unsigned int> &meshMap);
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 FindDegeneratesProcess::FindDegeneratesProcess() :
-        mConfigRemoveDegenerates( false ),
-        mConfigCheckAreaOfTriangle( false ){
+        mConfigRemoveDegenerates(false),
+        mConfigCheckAreaOfTriangle(false) {
     // empty
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const {
+bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const {
     return 0 != (pFlags & aiProcess_FindDegenerates);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup import configuration
-void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
+void FindDegeneratesProcess::SetupProperties(const Importer *pImp) {
     // Get the current value of AI_CONFIG_PP_FD_REMOVE
-    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
-    mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) );
+    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0));
+    mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA));
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void FindDegeneratesProcess::Execute( aiScene* pScene) {
+void FindDegeneratesProcess::Execute(aiScene *pScene) {
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
-    if ( nullptr == pScene) {
+    if (nullptr == pScene) {
         return;
     }
 
@@ -112,7 +112,7 @@ void FindDegeneratesProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
 }
 
-static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap) {
+static void updateSceneGraph(aiNode *pNode, const std::unordered_map<unsigned int, unsigned int> &meshMap) {
     unsigned int targetIndex = 0;
     for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
         const unsigned int sourceMeshIndex = pNode->mMeshes[i];
@@ -123,7 +123,7 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned in
         }
     }
     pNode->mNumMeshes = targetIndex;
-    //recurse to all children
+    // recurse to all children
     for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
         updateSceneGraph(pNode->mChildren[i], meshMap);
     }
@@ -131,17 +131,17 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned in
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported mesh
-bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
+bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
     mesh->mPrimitiveTypes = 0;
 
     std::vector<bool> remove_me;
     if (mConfigRemoveDegenerates) {
-        remove_me.resize( mesh->mNumFaces, false );
+        remove_me.resize(mesh->mNumFaces, false);
     }
 
     unsigned int deg = 0, limit;
-    for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) {
-        aiFace& face = mesh->mFaces[a];
+    for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
+        aiFace &face = mesh->mFaces[a];
         bool first = true;
 
         // check whether the face contains degenerated entries
@@ -151,43 +151,43 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
             // double points may not come directly after another.
             limit = face.mNumIndices;
             if (face.mNumIndices > 4) {
-                limit = std::min( limit, i+2 );
+                limit = std::min(limit, i + 2);
             }
 
-            for (unsigned int t = i+1; t < limit; ++t) {
-                if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) {
+            for (unsigned int t = i + 1; t < limit; ++t) {
+                if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) {
                     // we have found a matching vertex position
                     // remove the corresponding index from the array
                     --face.mNumIndices;
                     --limit;
                     for (unsigned int m = t; m < face.mNumIndices; ++m) {
-                        face.mIndices[ m ] = face.mIndices[ m+1 ];
+                        face.mIndices[m] = face.mIndices[m + 1];
                     }
                     --t;
 
                     // NOTE: we set the removed vertex index to an unique value
                     // to make sure the developer gets notified when his
                     // application attempts to access this data.
-                    face.mIndices[ face.mNumIndices ] = 0xdeadbeef;
+                    face.mIndices[face.mNumIndices] = 0xdeadbeef;
 
-                    if(first) {
+                    if (first) {
                         ++deg;
                         first = false;
                     }
 
-                    if ( mConfigRemoveDegenerates ) {
-                        remove_me[ a ] = true;
+                    if (mConfigRemoveDegenerates) {
+                        remove_me[a] = true;
                         goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
                     }
                 }
             }
 
-            if ( mConfigCheckAreaOfTriangle ) {
-                if ( face.mNumIndices == 3 ) {
-                    ai_real area = GeometryUtils::calculateAreaOfTriangle( face, mesh );
+            if (mConfigCheckAreaOfTriangle) {
+                if (face.mNumIndices == 3) {
+                    ai_real area = GeometryUtils::calculateAreaOfTriangle(face, mesh);
                     if (area < ai_epsilon) {
-                        if ( mConfigRemoveDegenerates ) {
-                            remove_me[ a ] = true;
+                        if (mConfigRemoveDegenerates) {
+                            remove_me[a] = true;
                             ++deg;
                             goto evil_jump_outside;
                         }
@@ -199,8 +199,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
         }
 
         // We need to update the primitive flags array of the mesh.
-        switch (face.mNumIndices)
-        {
+        switch (face.mNumIndices) {
         case 1u:
             mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
             break;
@@ -214,22 +213,21 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
             mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
             break;
         };
-evil_jump_outside:
+    evil_jump_outside:
         continue;
     }
 
     // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
     if (mConfigRemoveDegenerates && deg) {
         unsigned int n = 0;
-        for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
-        {
-            aiFace& face_src = mesh->mFaces[a];
+        for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
+            aiFace &face_src = mesh->mFaces[a];
             if (!remove_me[a]) {
-                aiFace& face_dest = mesh->mFaces[n++];
+                aiFace &face_dest = mesh->mFaces[n++];
 
                 // Do a manual copy, keep the index array
                 face_dest.mNumIndices = face_src.mNumIndices;
-                face_dest.mIndices    = face_src.mIndices;
+                face_dest.mIndices = face_src.mIndices;
 
                 if (&face_src != &face_dest) {
                     // clear source
@@ -246,15 +244,15 @@ evil_jump_outside:
         // Just leave the rest of the array unreferenced, we don't care for now
         mesh->mNumFaces = n;
         if (!mesh->mNumFaces) {
-            //The whole mesh consists of degenerated faces
-            //signal upward, that this mesh should be deleted.
+            // The whole mesh consists of degenerated faces
+            // signal upward, that this mesh should be deleted.
             ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
             return true;
         }
     }
 
     if (deg && !DefaultLogger::isNullLogger()) {
-        ASSIMP_LOG_WARN( "Found ", deg, " degenerated primitives");
+        ASSIMP_LOG_WARN("Found ", deg, " degenerated primitives");
     }
     return false;
 }

+ 151 - 140
code/PostProcessing/PretransformVertices.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -41,9 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 
-/** @file PretransformVertices.cpp
- *  @brief Implementation of the "PretransformVertices" post processing step
-*/
+/// @file  PretransformVertices.cpp
+/// @brief Implementation of the "PretransformVertices" post processing step
 
 #include "PretransformVertices.h"
 #include "ConvertToLHProcess.h"
@@ -57,16 +54,44 @@ using namespace Assimp;
 #define AI_PTVS_VERTEX 0x0
 #define AI_PTVS_FACE 0x1
 
+namespace {
+
+// Get a bitwise combination identifying the vertex format of a mesh
+static unsigned int GetMeshVFormat(aiMesh *pcMesh)  {
+	// the vertex format is stored in aiMesh::mBones for later retrieval.
+	// there isn't a good reason to compute it a few hundred times
+	// from scratch. The pointer is unused as animations are lost
+	// during PretransformVertices.
+	if (pcMesh->mBones)
+		return (unsigned int)(uint64_t)pcMesh->mBones;
+
+	const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
+
+	// store the value for later use
+	pcMesh->mBones = (aiBone **)(uint64_t)iRet;
+	return iRet;
+}
+
+// Get a list of all vertex formats that occur for a given material index
+// The output list contains duplicate elements
+static void GetVFormatList(const aiScene *pcScene, unsigned int iMat, std::list<unsigned int> &aiOut)  {
+	for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
+		aiMesh *pcMesh = pcScene->mMeshes[i];
+		if (iMat == pcMesh->mMaterialIndex) {
+			aiOut.push_back(GetMeshVFormat(pcMesh));
+		}
+	}
+}
+
+}
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 PretransformVertices::PretransformVertices() :
-		configKeepHierarchy(false),
-		configNormalize(false),
-		configTransform(false),
-		configTransformation(),
-		mConfigPointCloud(false) {
-	// empty
-}
+		mConfigKeepHierarchy(false),
+		mConfigNormalize(false),
+		mConfigTransform(false),
+		mConfigTransformation(),
+		mConfigPointCloud(false) {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
@@ -79,11 +104,11 @@ bool PretransformVertices::IsActive(unsigned int pFlags) const {
 void PretransformVertices::SetupProperties(const Importer *pImp) {
 	// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE,
 	// AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION
-	configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0));
-	configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0));
-	configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0));
+	mConfigKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0));
+	mConfigNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0));
+	mConfigTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0));
 
-	configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
+	mConfigTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
 
 	mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
 }
@@ -99,25 +124,7 @@ unsigned int PretransformVertices::CountNodes(const aiNode *pcNode) const {
 }
 
 // ------------------------------------------------------------------------------------------------
-// Get a bitwise combination identifying the vertex format of a mesh
-unsigned int PretransformVertices::GetMeshVFormat(aiMesh *pcMesh) const {
-	// the vertex format is stored in aiMesh::mBones for later retrieval.
-	// there isn't a good reason to compute it a few hundred times
-	// from scratch. The pointer is unused as animations are lost
-	// during PretransformVertices.
-	if (pcMesh->mBones)
-		return (unsigned int)(uint64_t)pcMesh->mBones;
-
-	const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
-
-	// store the value for later use
-	pcMesh->mBones = (aiBone **)(uint64_t)iRet;
-	return iRet;
-}
-
-// ------------------------------------------------------------------------------------------------
-// Count the number of vertices in the whole scene and a given
-// material index
+// Count the number of vertices in the whole scene and a given material index
 void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
 		unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const {
 	for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) {
@@ -128,8 +135,7 @@ void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const a
 		}
 	}
 	for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
-		CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat,
-				iVFormat, piFaces, piVertices);
+		CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, iVFormat, piFaces, piVertices);
 	}
 }
 
@@ -272,19 +278,6 @@ void PretransformVertices::CollectData(const aiScene *pcScene, const aiNode *pcN
 	}
 }
 
-// ------------------------------------------------------------------------------------------------
-// Get a list of all vertex formats that occur for a given material index
-// The output list contains duplicate elements
-void PretransformVertices::GetVFormatList(const aiScene *pcScene, unsigned int iMat,
-		std::list<unsigned int> &aiOut) const {
-	for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
-		aiMesh *pcMesh = pcScene->mMeshes[i];
-		if (iMat == pcMesh->mMaterialIndex) {
-			aiOut.push_back(GetMeshVFormat(pcMesh));
-		}
-	}
-}
-
 // ------------------------------------------------------------------------------------------------
 // Compute the absolute transformation matrices of each node
 void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
@@ -297,39 +290,44 @@ void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
 	}
 }
 
+static void normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors) {
+	for (size_t i=0; i<numVectors; ++i) {
+		vectorArrayOut[i] = vectorArrayIn[i].Normalize();
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // Apply the node transformation to a mesh
 void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const {
 	// Check whether we need to transform the coordinates at all
-	if (!mat.IsIdentity()) {
+	if (mat.IsIdentity()) {
+		return;
+	}
 
-		// Check for odd negative scale (mirror)
-		if (mesh->HasFaces() && mat.Determinant() < 0) {
-			// Reverse the mesh face winding order
-			FlipWindingOrderProcess::ProcessMesh(mesh);
-		}
+	// Check for odd negative scale (mirror)
+	if (mesh->HasFaces() && mat.Determinant() < 0) {
+		// Reverse the mesh face winding order
+		FlipWindingOrderProcess::ProcessMesh(mesh);
+	}
 
-		// Update positions
-		if (mesh->HasPositions()) {
-			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-				mesh->mVertices[i] = mat * mesh->mVertices[i];
-			}
+	// Update positions
+	if (mesh->HasPositions()) {
+		for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+			mesh->mVertices[i] = mat * mesh->mVertices[i];
 		}
+	}
 
-		// Update normals and tangents
-		if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
-			const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose();
+	// Update normals and tangents
+	if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
+		const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose();
 
-			if (mesh->HasNormals()) {
-				for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-					mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
-				}
-			}
-			if (mesh->HasTangentsAndBitangents()) {
-				for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-					mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
-					mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
-				}
+		if (mesh->HasNormals()) {
+			normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices);
+		}
+		if (mesh->HasTangentsAndBitangents()) {
+			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+				mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
+				mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
 			}
 		}
 	}
@@ -352,40 +350,41 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **i
 			// yes, we can.
 			mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
 			mesh->mNumBones = UINT_MAX;
-		} else {
+			continue;
+		} 
 
-			// try to find us in the list of newly created meshes
-			for (unsigned int n = 0; n < out.size(); ++n) {
-				aiMesh *ctz = out[n];
-				if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4 *>(ctz->mBones) == node->mTransformation) {
+		// try to find us in the list of newly created meshes
+		for (unsigned int n = 0; n < out.size(); ++n) {
+			aiMesh *ctz = out[n];
+			if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4 *>(ctz->mBones) == node->mTransformation) {
 
-					// ok, use this one. Update node mesh index
-					node->mMeshes[i] = numIn + n;
-				}
+				// ok, use this one. Update node mesh index
+				node->mMeshes[i] = numIn + n;
 			}
-			if (node->mMeshes[i] < numIn) {
-				// Worst case. Need to operate on a full copy of the mesh
-				ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms");
-				aiMesh *ntz;
+		}
+		if (node->mMeshes[i] < numIn) {
+			// Worst case. Need to operate on a full copy of the mesh
+			ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms");
+			aiMesh *ntz;
 
-				const unsigned int tmp = mesh->mNumBones; //
-				mesh->mNumBones = 0;
-				SceneCombiner::Copy(&ntz, mesh);
-				mesh->mNumBones = tmp;
+			const unsigned int cacheNumBones = mesh->mNumBones; //
+			mesh->mNumBones = 0;
+			SceneCombiner::Copy(&ntz, mesh);
+			mesh->mNumBones = cacheNumBones;
 
-				ntz->mNumBones = node->mMeshes[i];
-				ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
+			ntz->mNumBones = node->mMeshes[i];
+			ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
 
-				out.push_back(ntz);
+			out.push_back(ntz);
 
-				node->mMeshes[i] = static_cast<unsigned int>(numIn + out.size() - 1);
-			}
+			node->mMeshes[i] = static_cast<unsigned int>(numIn + out.size() - 1);
 		}
 	}
 
 	// call children
-	for (unsigned int i = 0; i < node->mNumChildren; ++i)
+	for (unsigned int i = 0; i < node->mNumChildren; ++i) {
 		BuildWCSMeshes(out, in, numIn, node->mChildren[i]);
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -394,8 +393,9 @@ void PretransformVertices::MakeIdentityTransform(aiNode *nd) const {
 	nd->mTransformation = aiMatrix4x4();
 
 	// call children
-	for (unsigned int i = 0; i < nd->mNumChildren; ++i)
+	for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
 		MakeIdentityTransform(nd->mChildren[i]);
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -405,8 +405,27 @@ void PretransformVertices::BuildMeshRefCountArray(const aiNode *nd, unsigned int
 		refs[nd->mMeshes[i]]++;
 
 	// call children
-	for (unsigned int i = 0; i < nd->mNumChildren; ++i)
+	for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
 		BuildMeshRefCountArray(nd->mChildren[i], refs);
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+static void appendNewMeshesToScene(aiScene *pScene, std::vector<aiMesh*> &apcOutMeshes) {
+	ai_assert(pScene != nullptr);
+
+	if (apcOutMeshes.empty()) {
+		return;
+	}
+
+	aiMesh **npp = new aiMesh *[pScene->mNumMeshes + apcOutMeshes.size()];
+
+	::memcpy(npp, pScene->mMeshes, sizeof(aiMesh *) * pScene->mNumMeshes);
+	::memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * apcOutMeshes.size());
+
+	pScene->mNumMeshes += static_cast<unsigned int>(apcOutMeshes.size());
+	delete[] pScene->mMeshes;
+	pScene->mMeshes = npp;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -418,12 +437,12 @@ void PretransformVertices::Execute(aiScene *pScene) {
 	if (!pScene->mNumMeshes)
 		return;
 
-	const unsigned int iOldMeshes = pScene->mNumMeshes;
-	const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
-	const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
+	const unsigned int oldMeshes = pScene->mNumMeshes;
+	const unsigned int oldAnimationChannels = pScene->mNumAnimations;
+	const unsigned int oldNodes = CountNodes(pScene->mRootNode);
 
-	if (configTransform) {
-		pScene->mRootNode->mTransformation = configTransformation * pScene->mRootNode->mTransformation;
+	if (mConfigTransform) {
+		pScene->mRootNode->mTransformation = mConfigTransformation * pScene->mRootNode->mTransformation;
 	}
 
 	// first compute absolute transformation matrices for all nodes
@@ -449,22 +468,13 @@ void PretransformVertices::Execute(aiScene *pScene) {
 	// we go on and transform all meshes, if one is referenced by nodes
 	// with different absolute transformations a depth copy of the mesh
 	// is required.
-	if (configKeepHierarchy) {
+	if (mConfigKeepHierarchy) {
 
 		// Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
 		BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode);
 
 		// ... if new meshes have been generated, append them to the end of the scene
-		if (apcOutMeshes.size() > 0) {
-			aiMesh **npp = new aiMesh *[pScene->mNumMeshes + apcOutMeshes.size()];
-
-			memcpy(npp, pScene->mMeshes, sizeof(aiMesh *) * pScene->mNumMeshes);
-			memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * apcOutMeshes.size());
-
-			pScene->mNumMeshes += static_cast<unsigned int>(apcOutMeshes.size());
-			delete[] pScene->mMeshes;
-			pScene->mMeshes = npp;
-		}
+		appendNewMeshesToScene(pScene, apcOutMeshes);
 
 		// now iterate through all meshes and transform them to world-space
 		for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
@@ -488,34 +498,35 @@ void PretransformVertices::Execute(aiScene *pScene) {
 			aiVFormats.sort();
 			aiVFormats.unique();
 			for (std::list<unsigned int>::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) {
-				unsigned int iVertices = 0;
-				unsigned int iFaces = 0;
-				CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices);
-				if (0 != iFaces && 0 != iVertices) {
+				unsigned int numVertices = 0u;
+				unsigned int numFaces = 0u;
+				CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &numFaces, &numVertices);
+				if (0 != numFaces && 0 != numVertices) {
 					apcOutMeshes.push_back(new aiMesh());
 					aiMesh *pcMesh = apcOutMeshes.back();
-					pcMesh->mNumFaces = iFaces;
-					pcMesh->mNumVertices = iVertices;
-					pcMesh->mFaces = new aiFace[iFaces];
-					pcMesh->mVertices = new aiVector3D[iVertices];
+					pcMesh->mNumFaces = numFaces;
+					pcMesh->mNumVertices = numVertices;
+					pcMesh->mFaces = new aiFace[numFaces];
+					pcMesh->mVertices = new aiVector3D[numVertices];
 					pcMesh->mMaterialIndex = i;
-					if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices];
+					if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[numVertices];
 					if ((*j) & 0x4) {
-						pcMesh->mTangents = new aiVector3D[iVertices];
-						pcMesh->mBitangents = new aiVector3D[iVertices];
+						pcMesh->mTangents = new aiVector3D[numVertices];
+						pcMesh->mBitangents = new aiVector3D[numVertices];
 					}
-					iFaces = 0;
-					while ((*j) & (0x100 << iFaces)) {
-						pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices];
-						if ((*j) & (0x10000 << iFaces))
-							pcMesh->mNumUVComponents[iFaces] = 3;
-						else
-							pcMesh->mNumUVComponents[iFaces] = 2;
-						iFaces++;
+					numFaces = 0;
+					while ((*j) & (0x100 << numFaces)) {
+						pcMesh->mTextureCoords[numFaces] = new aiVector3D[numVertices];
+						if ((*j) & (0x10000 << numFaces)) {
+							pcMesh->mNumUVComponents[numFaces] = 3;
+						} else {
+							pcMesh->mNumUVComponents[numFaces] = 2;
+						}
+						++numFaces;
 					}
-					iFaces = 0;
-					while ((*j) & (0x1000000 << iFaces))
-						pcMesh->mColors[iFaces++] = new aiColor4D[iVertices];
+					numFaces = 0;
+					while ((*j) & (0x1000000 << numFaces))
+						pcMesh->mColors[numFaces++] = new aiColor4D[numVertices];
 
 					// fill the mesh ...
 					unsigned int aiTemp[2] = { 0, 0 };
@@ -593,7 +604,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
 		l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp;
 	}
 
-	if (!configKeepHierarchy) {
+	if (!mConfigKeepHierarchy) {
 
 		// now delete all nodes in the scene and build a new
 		// flat node graph with a root node and some level 1 children
@@ -644,7 +655,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
 		MakeIdentityTransform(pScene->mRootNode);
 	}
 
-	if (configNormalize) {
+	if (mConfigNormalize) {
 		// compute the boundary of all meshes
 		aiVector3D min, max;
 		MinMaxChooser<aiVector3D>()(min, max);
@@ -674,9 +685,9 @@ void PretransformVertices::Execute(aiScene *pScene) {
 	if (!DefaultLogger::isNullLogger()) {
 		ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished");
 
-		ASSIMP_LOG_INFO("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (",
+		ASSIMP_LOG_INFO("Removed ", oldNodes, " nodes and ", oldAnimationChannels, " animation channels (",
 				CountNodes(pScene->mRootNode), " output nodes)");
 		ASSIMP_LOG_INFO("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras.");
-		ASSIMP_LOG_INFO("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")");
+		ASSIMP_LOG_INFO("Moved ", oldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")");
 	}
 }

+ 9 - 9
code/PostProcessing/PretransformVertices.h

@@ -90,7 +90,7 @@ public:
      *  @param keep    true for keep configuration.
      */
 	void KeepHierarchy(bool keep) {
-		configKeepHierarchy = keep;
+		mConfigKeepHierarchy = keep;
 	}
 
 	// -------------------------------------------------------------------
@@ -98,7 +98,7 @@ public:
      *  @return ...
      */
 	bool IsHierarchyKept() const {
-		return configKeepHierarchy;
+		return mConfigKeepHierarchy;
 	}
 
 private:
@@ -108,7 +108,7 @@ private:
 
 	// -------------------------------------------------------------------
 	// Get a bitwise combination identifying the vertex format of a mesh
-	unsigned int GetMeshVFormat(aiMesh *pcMesh) const;
+	//unsigned int GetMeshVFormat(aiMesh *pcMesh) const;
 
 	// -------------------------------------------------------------------
 	// Count the number of vertices in the whole scene and a given
@@ -131,8 +131,8 @@ private:
 	// -------------------------------------------------------------------
 	// Get a list of all vertex formats that occur for a given material
 	// The output list contains duplicate elements
-	void GetVFormatList(const aiScene *pcScene, unsigned int iMat,
-			std::list<unsigned int> &aiOut) const;
+	/*void GetVFormatList(const aiScene *pcScene, unsigned int iMat,
+			std::list<unsigned int> &aiOut) const;*/
 
 	// -------------------------------------------------------------------
 	// Compute the absolute transformation matrices of each node
@@ -156,10 +156,10 @@ private:
 	void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const;
 
 	//! Configuration option: keep scene hierarchy as long as possible
-	bool configKeepHierarchy;
-	bool configNormalize;
-	bool configTransform;
-	aiMatrix4x4 configTransformation;
+	bool mConfigKeepHierarchy;
+	bool mConfigNormalize;
+	bool mConfigTransform;
+	aiMatrix4x4 mConfigTransformation;
 	bool mConfigPointCloud;
 };
 

+ 3 - 4
code/PostProcessing/ProcessHelper.cpp

@@ -175,10 +175,9 @@ unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh) {
     // tangents and bitangents
     if (pcMesh->HasTangentsAndBitangents()) iRet |= 0x4;
 
-#ifdef BOOST_STATIC_ASSERT
-    BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
-    BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
-#endif
+
+    static_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
+    static_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
 
     // texture coordinates
     unsigned int p = 0;

+ 9 - 24
code/PostProcessing/RemoveRedundantMaterials.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -45,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 // internal headers
-
 #include "RemoveRedundantMaterials.h"
 #include <assimp/ParsingUtils.h>
 #include "ProcessHelper.h"
@@ -57,35 +54,28 @@ using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-RemoveRedundantMatsProcess::RemoveRedundantMatsProcess()
-: mConfigFixedMaterials() {
-    // nothing to do here
-}
+RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() : mConfigFixedMaterials() {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const
-{
+bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const {
     return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup import properties
-void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp)
-{
+void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) {
     // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST
     mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,"");
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
-{
+void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
 
     unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
-    if (pScene->mNumMaterials)
-    {
+    if (pScene->mNumMaterials) {
         // Find out which materials are referenced by meshes
         std::vector<bool> abReferenced(pScene->mNumMaterials,false);
         for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
@@ -134,8 +124,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
         // we do already have a specific hash. This allows us to
         // determine which materials are identical.
         uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];;
-        for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
-        {
+        for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
             // No mesh is referencing this material, remove it.
             if (!abReferenced[i]) {
                 ++unreferencedRemoved;
@@ -147,8 +136,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
             // Check all previously mapped materials for a matching hash.
             // On a match we can delete this material and just make it ref to the same index.
             uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
-            for (unsigned int a = 0; a < i;++a)
-            {
+            for (unsigned int a = 0; a < i;++a) {
                 if (abReferenced[a] && me == aiHashes[a]) {
                     ++redundantRemoved;
                     me = 0;
@@ -205,12 +193,9 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
         delete[] aiHashes;
         delete[] aiMappingTable;
     }
-    if (redundantRemoved == 0 && unreferencedRemoved == 0)
-    {
+    if (redundantRemoved == 0 && unreferencedRemoved == 0) {
         ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
-    }
-    else
-    {
+    } else {
         ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
             unreferencedRemoved, " unused materials.");
     }

+ 0 - 1
code/PostProcessing/ScaleProcess.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,

+ 2 - 1
code/PostProcessing/SortByPTypeProcess.cpp

@@ -99,8 +99,9 @@ void UpdateNodes(const std::vector<unsigned int> &replaceMeshIndex, aiNode *node
     }
 
     // call all subnodes recursively
-    for (unsigned int m = 0; m < node->mNumChildren; ++m)
+    for (unsigned int m = 0; m < node->mNumChildren; ++m) {
         UpdateNodes(replaceMeshIndex, node->mChildren[m]);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------

+ 1 - 3
code/PostProcessing/SplitByBoneCountProcess.cpp

@@ -57,9 +57,7 @@ using namespace Assimp::Formatter;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor
-SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {
-    // empty
-}
+SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag.

+ 15 - 19
code/PostProcessing/SplitLargeMeshes.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -40,9 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
-/**
- *  @file Implementation of the SplitLargeMeshes postprocessing step
- */
+ ///  @file Implementation of the SplitLargeMeshes postprocessing step
 
 // internal headers of the post-processing framework
 #include "SplitLargeMeshes.h"
@@ -75,22 +72,22 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) {
         this->SplitMesh(a, pScene->mMeshes[a],avList);
     }
 
-    if (avList.size() != pScene->mNumMeshes) {
-        // it seems something has been split. rebuild the mesh list
-        delete[] pScene->mMeshes;
-        pScene->mNumMeshes = (unsigned int)avList.size();
-        pScene->mMeshes = new aiMesh*[avList.size()];
+    if (avList.size() == pScene->mNumMeshes) {
+        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
+    }
 
-        for (unsigned int i = 0; i < avList.size();++i) {
-            pScene->mMeshes[i] = avList[i].first;
-        }
+    // it seems something has been split. rebuild the mesh list
+    delete[] pScene->mMeshes;
+    pScene->mNumMeshes = (unsigned int)avList.size();
+    pScene->mMeshes = new aiMesh*[avList.size()];
 
-        // now we need to update all nodes
-        this->UpdateNode(pScene->mRootNode,avList);
-        ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
-    } else {
-        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
+    for (unsigned int i = 0; i < avList.size();++i) {
+        pScene->mMeshes[i] = avList[i].first;
     }
+
+    // now we need to update all nodes
+    this->UpdateNode(pScene->mRootNode,avList);
+    ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -102,8 +99,7 @@ void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) {
 
 // ------------------------------------------------------------------------------------------------
 // Update a node after some meshes have been split
-void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode,
-        const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
+void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
     // for every index in out list build a new entry
     std::vector<unsigned int> aiEntries;
     aiEntries.reserve(pcNode->mNumMeshes + 1);

+ 2 - 4
code/PostProcessing/TextureTransform.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -42,8 +41,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 /** @file A helper class that processes texture transformations */
 
-
-
 #include <assimp/Importer.hpp>
 #include <assimp/postprocess.h>
 #include <assimp/DefaultLogger.hpp>
@@ -494,8 +491,9 @@ void TextureTransformStep::Execute( aiScene* pScene) {
             ai_assert(nullptr != src);
 
             // Copy the data to the destination array
-            if (dest != src)
+            if (dest != src) {
                 ::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices);
+            }
 
             end = dest + mesh->mNumVertices;
 

+ 4 - 41
code/PostProcessing/TriangulateProcess.cpp

@@ -158,15 +158,13 @@ namespace {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool TriangulateProcess::IsActive( unsigned int pFlags) const
-{
+bool TriangulateProcess::IsActive( unsigned int pFlags) const {
     return (pFlags & aiProcess_Triangulate) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void TriangulateProcess::Execute( aiScene* pScene)
-{
+void TriangulateProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("TriangulateProcess begin");
 
     bool bHas = false;
@@ -187,8 +185,7 @@ void TriangulateProcess::Execute( aiScene* pScene)
 
 // ------------------------------------------------------------------------------------------------
 // Triangulates the given mesh.
-bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
-{
+bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) {
     // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
     if (!pMesh->mPrimitiveTypes)    {
         bool bNeed = false;
@@ -218,8 +215,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
         if( face.mNumIndices <= 3) {
             numOut++;
 
-        }
-        else {
+        } else {
             numOut += face.mNumIndices-2;
             max_out = std::max(max_out,face.mNumIndices);
         }
@@ -511,22 +507,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
 #endif
                     num = 0;
                     break;
-
-                    /*curOut -= (max-num); // undo all previous work
-                    for (tmp = 0; tmp < max-2; ++tmp) {
-                        aiFace& nface = *curOut++;
-
-                        nface.mNumIndices = 3;
-                        if (!nface.mIndices)
-                            nface.mIndices = new unsigned int[3];
-
-                        nface.mIndices[0] = 0;
-                        nface.mIndices[1] = tmp+1;
-                        nface.mIndices[2] = tmp+2;
-
-                    }
-                    num = 0;
-                    break;*/
                 }
 
                 aiFace& nface = *curOut++;
@@ -580,23 +560,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
         for(aiFace* f = last_face; f != curOut; ) {
             unsigned int* i = f->mIndices;
 
-            //  drop dumb 0-area triangles - deactivated for now:
-            //FindDegenerates post processing step can do the same thing
-            //if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
-            //    ASSIMP_LOG_VERBOSE_DEBUG("Dropping triangle with area 0");
-            //    --curOut;
-
-            //    delete[] f->mIndices;
-            //    f->mIndices = nullptr;
-
-            //    for(aiFace* ff = f; ff != curOut; ++ff) {
-            //        ff->mNumIndices = (ff+1)->mNumIndices;
-            //        ff->mIndices = (ff+1)->mIndices;
-            //        (ff+1)->mIndices = nullptr;
-            //    }
-            //    continue;
-            //}
-
             i[0] = idx[i[0]];
             i[1] = idx[i[1]];
             i[2] = idx[i[2]];

+ 37 - 50
code/PostProcessing/ValidateDataStructure.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -110,18 +108,21 @@ inline int HasNameMatch(const aiString &in, aiNode *node) {
 template <typename T>
 inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
     // validate all entries
-    if (size) {
-        if (!parray) {
-            ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
-                    firstName, secondName, size);
-        }
-        for (unsigned int i = 0; i < size; ++i) {
-            if (!parray[i]) {
-                ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
-                        firstName, i, secondName, size);
-            }
-            Validate(parray[i]);
+    if (size == 0) {
+        return;
+    }
+
+    if (!parray) {
+        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
+                firstName, secondName, size);
+    }
+
+    for (unsigned int i = 0; i < size; ++i) {
+        if (!parray[i]) {
+            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
+                    firstName, i, secondName, size);
         }
+        Validate(parray[i]);
     }
 }
 
@@ -130,25 +131,27 @@ template <typename T>
 inline void ValidateDSProcess::DoValidationEx(T **parray, unsigned int size,
         const char *firstName, const char *secondName) {
     // validate all entries
-    if (size) {
-        if (!parray) {
-            ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
-                    firstName, secondName, size);
-        }
-        for (unsigned int i = 0; i < size; ++i) {
-            if (!parray[i]) {
-                ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
-                        firstName, i, secondName, size);
-            }
-            Validate(parray[i]);
-
-            // check whether there are duplicate names
-            for (unsigned int a = i + 1; a < size; ++a) {
-                if (parray[i]->mName == parray[a]->mName) {
-                    ReportError("aiScene::%s[%u] has the same name as "
-                                "aiScene::%s[%u]",
-                            firstName, i, secondName, a);
-                }
+    if (size == 0) {
+        return;
+    }
+        
+    if (!parray) {
+        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
+                firstName, secondName, size);
+    }
+    for (unsigned int i = 0; i < size; ++i) {
+        if (!parray[i]) {
+            ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
+                    firstName, i, secondName, size);
+        }
+        Validate(parray[i]);
+
+        // check whether there are duplicate names
+        for (unsigned int a = i + 1; a < size; ++a) {
+            if (parray[i]->mName == parray[a]->mName) {
+                ReportError("aiScene::%s[%u] has the same name as "
+                            "aiScene::%s[%u]",
+                        firstName, i, secondName, a);
             }
         }
     }
@@ -229,12 +232,6 @@ void ValidateDSProcess::Execute(aiScene *pScene) {
     if (pScene->mNumMaterials) {
         DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials");
     }
-#if 0
-    // NOTE: ScenePreprocessor generates a default material if none is there
-    else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
-        ReportError("aiScene::mNumMaterials is 0. At least one material must be there");
-    }
-#endif
     else if (pScene->mMaterials) {
         ReportError("aiScene::mMaterials is non-null although there are no materials");
     }
@@ -267,8 +264,7 @@ void ValidateDSProcess::Validate(const aiCamera *pCamera) {
     if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear)
         ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear");
 
-    // FIX: there are many 3ds files with invalid FOVs. No reason to
-    // reject them at all ... a warning is appropriate.
+    // There are many 3ds files with invalid FOVs. No reason to reject them at all ... a warning is appropriate.
     if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI)
         ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV);
 }
@@ -362,15 +358,6 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh) {
             if (face.mIndices[a] >= pMesh->mNumVertices) {
                 ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a);
             }
-            // the MSB flag is temporarily used by the extra verbose
-            // mode to tell us that the JoinVerticesProcess might have
-            // been executed already.
-            /*if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && !(this->mScene->mFlags & AI_SCENE_FLAGS_ALLOW_SHARED) &&
-				abRefList[face.mIndices[a]])
-            {
-                ReportError("aiMesh::mVertices[%i] is referenced twice - second "
-                    "time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a);
-            }*/
             abRefList[face.mIndices[a]] = true;
         }
     }
@@ -466,7 +453,7 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh, const aiBone *pBone, float
     this->Validate(&pBone->mName);
 
     if (!pBone->mNumWeights) {
-        //ReportError("aiBone::mNumWeights is zero");
+        ReportWarning("aiBone::mNumWeights is zero");
     }
 
     // check whether all vertices affected by this bone are valid

+ 1 - 4
include/assimp/StreamWriter.h

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -68,8 +66,7 @@ namespace Assimp {
  */
 // --------------------------------------------------------------------------------------------
 template <bool SwapEndianess = false, bool RuntimeSwitch = false>
-class StreamWriter
-{
+class StreamWriter {
     enum {
         INITIAL_CAPACITY = 1024
     };

+ 11 - 14
include/assimp/Vertex.h

@@ -97,14 +97,20 @@ namespace Assimp    {
  *  to *all* vertex components equally. This is useful for stuff like interpolation
  *  or subdivision, but won't work if special handling is required for some vertex components. */
 // ------------------------------------------------------------------------------------------------
-class Vertex {
+struct Vertex {
     friend Vertex operator + (const Vertex&,const Vertex&);
     friend Vertex operator - (const Vertex&,const Vertex&);
     friend Vertex operator * (const Vertex&,ai_real);
     friend Vertex operator / (const Vertex&,ai_real);
     friend Vertex operator * (ai_real, const Vertex&);
 
-public:
+    aiVector3D position;
+    aiVector3D normal;
+    aiVector3D tangent, bitangent;
+
+    aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+    aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
+
     Vertex() = default;
 
     // ----------------------------------------------------------------------------
@@ -178,7 +184,7 @@ public:
     }
 
     // ----------------------------------------------------------------------------
-    /** Convert back to non-interleaved storage */
+    /// Convert back to non-interleaved storage
     void SortBack(aiMesh* out, unsigned int idx) const {
         ai_assert(idx<out->mNumVertices);
         out->mVertices[idx] = position;
@@ -204,7 +210,7 @@ public:
 private:
 
     // ----------------------------------------------------------------------------
-    /** Construct from two operands and a binary operation to combine them */
+    /// Construct from two operands and a binary operation to combine them
     template <template <typename t> class op> static Vertex BinaryOp(const Vertex& v0, const Vertex& v1) {
         // this is a heavy task for the compiler to optimize ... *pray*
 
@@ -224,7 +230,7 @@ private:
     }
 
     // ----------------------------------------------------------------------------
-    /** This time binary arithmetic of v0 with a floating-point number */
+    /// This time binary arithmetic of v0 with a floating-point number
     template <template <typename, typename, typename> class op> static Vertex BinaryOp(const Vertex& v0, ai_real f) {
         // this is a heavy task for the compiler to optimize ... *pray*
 
@@ -262,15 +268,6 @@ private:
         }
         return res;
     }
-
-public:
-
-    aiVector3D position;
-    aiVector3D normal;
-    aiVector3D tangent, bitangent;
-
-    aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
-    aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
 };
 
 // ------------------------------------------------------------------------------------------------

+ 12 - 6
test/CMakeLists.txt

@@ -102,6 +102,10 @@ SET( COMMON
   unit/Common/utBaseProcess.cpp
 )
 
+SET(Geometry 
+    unit/Geometry/utGeometryUtils.cpp
+)
+
 SET( IMPORTERS
   unit/ImportExport/Assxml/utAssxmlImportExport.cpp
   unit/utLWSImportExport.cpp
@@ -200,12 +204,13 @@ SET( POST_PROCESSES
   unit/utGenBoundingBoxesProcess.cpp
 )
 
-SOURCE_GROUP( UnitTests\\Compiler     FILES  unit/CCompilerTest.c )
-SOURCE_GROUP( UnitTests\\Common       FILES  ${COMMON} )
-SOURCE_GROUP( UnitTests\\ImportExport FILES  ${IMPORTERS} )
-SOURCE_GROUP( UnitTests\\Material     FILES  ${MATERIAL} )
-SOURCE_GROUP( UnitTests\\Math         FILES  ${MATH} )
-SOURCE_GROUP( UnitTests\\PostProcess  FILES  ${POST_PROCESSES})
+SOURCE_GROUP( UnitTests\\Compiler      FILES unit/CCompilerTest.c )
+SOURCE_GROUP( UnitTests\\Common        FILES ${COMMON} )
+SOURCE_GROUP( UnitTests\\GeometryTools FILES ${Geometry} )
+SOURCE_GROUP( UnitTests\\ImportExport  FILES ${IMPORTERS} )
+SOURCE_GROUP( UnitTests\\Material      FILES ${MATERIAL} )
+SOURCE_GROUP( UnitTests\\Math          FILES ${MATH} )
+SOURCE_GROUP( UnitTests\\PostProcess   FILES ${POST_PROCESSES})
 
 add_executable( unit
     unit/CCompilerTest.c
@@ -213,6 +218,7 @@ add_executable( unit
     ../code/Common/Version.cpp
 	../code/Common/Base64.cpp
 	${COMMON}
+  ${Geometry}
 	${IMPORTERS}
 	${MATERIAL}
 	${MATH}

+ 68 - 0
test/unit/Geometry/utGeometryUtils.cpp

@@ -0,0 +1,68 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#include "UnitTestPCH.h"
+#include "Geometry/GeometryUtils.h"
+
+using namespace Assimp;
+
+class utGeometryUtils : public ::testing::Test {
+protected:
+
+    void SetUp() override {
+    }
+
+    void TearDown() override {
+    }
+};
+static constexpr size_t NumVectors =  100;
+TEST_F(utGeometryUtils, normalizeVectorArrayTest) {
+    aiVector3D *inNormals = new aiVector3D[NumVectors];
+    for (uint32_t i=0; i<NumVectors; ++i){
+        inNormals[i].x = static_cast<ai_real>(i);
+        inNormals[i].y = static_cast<ai_real>(i);
+        inNormals[i].z = static_cast<ai_real>(i);
+    }
+    aiVector3D *outNormals = new aiVector3D[NumVectors];
+    GeometryUtils::normalizeVectorArray(inNormals, outNormals, NumVectors);
+    delete[] outNormals;
+    delete[] inNormals;
+}