Browse Source

Bugfix/cosmetic code cleanup (#5947)

* Refactorings: Code cleanups

* More cosmetic changes

---------

Co-authored-by: Kim Kulling <[email protected]>
Kim Kulling 7 tháng trước cách đây
mục cha
commit
5fa7b8ceb9
52 tập tin đã thay đổi với 608 bổ sung649 xóa
  1. 1 2
      code/AssetLib/3DS/3DSExporter.h
  2. 1 2
      code/AssetLib/3DS/3DSLoader.h
  3. 1 1
      code/AssetLib/3MF/D3MFImporter.cpp
  4. 3 3
      code/AssetLib/3MF/XmlSerializer.cpp
  5. 3 3
      code/AssetLib/3MF/XmlSerializer.h
  6. 6 7
      code/AssetLib/AC/ACLoader.cpp
  7. 2 2
      code/AssetLib/AC/ACLoader.h
  8. 1 1
      code/AssetLib/AMF/AMFImporter.cpp
  9. 7 6
      code/AssetLib/AMF/AMFImporter_Node.hpp
  10. 1 1
      code/AssetLib/AMF/AMFImporter_Postprocess.cpp
  11. 3 7
      code/AssetLib/BVH/BVHLoader.cpp
  12. 7 12
      code/AssetLib/BVH/BVHLoader.h
  13. 0 1
      code/AssetLib/Blender/BlenderDNA.h
  14. 3 1
      code/AssetLib/Blender/BlenderDNA.inl
  15. 0 1
      code/AssetLib/Blender/BlenderIntermediate.h
  16. 2 10
      code/AssetLib/C4D/C4DImporter.cpp
  17. 2 2
      code/AssetLib/C4D/C4DImporter.h
  18. 1 1
      code/AssetLib/COB/COBLoader.cpp
  19. 4 8
      code/AssetLib/CSM/CSMLoader.cpp
  20. 310 252
      code/AssetLib/Collada/ColladaExporter.cpp
  21. 0 1
      code/AssetLib/Collada/ColladaExporter.h
  22. 1 0
      code/AssetLib/Collada/ColladaLoader.cpp
  23. 21 18
      code/AssetLib/Collada/ColladaLoader.h
  24. 8 19
      code/AssetLib/DXF/DXFHelper.h
  25. 22 20
      code/AssetLib/FBX/FBXAnimation.cpp
  26. 9 52
      code/AssetLib/FBX/FBXBinaryTokenizer.cpp
  27. 2 1
      code/AssetLib/FBX/FBXCommon.h
  28. 7 7
      code/AssetLib/FBX/FBXConverter.cpp
  29. 1 2
      code/AssetLib/FBX/FBXConverter.h
  30. 5 18
      code/AssetLib/FBX/FBXDeformer.cpp
  31. 8 0
      code/AssetLib/FBX/FBXDocument.cpp
  32. 7 7
      code/AssetLib/FBX/FBXDocument.h
  33. 10 15
      code/AssetLib/FBX/FBXDocumentUtil.cpp
  34. 1 1
      code/AssetLib/FBX/FBXDocumentUtil.h
  35. 13 20
      code/AssetLib/FBX/FBXExportNode.cpp
  36. 26 35
      code/AssetLib/FBX/FBXExportNode.h
  37. 14 36
      code/AssetLib/FBX/FBXExporter.cpp
  38. 0 1
      code/AssetLib/FBX/FBXExporter.h
  39. 0 4
      code/AssetLib/FBX/FBXMaterial.cpp
  40. 1 2
      code/AssetLib/FBX/FBXParser.h
  41. 4 16
      code/AssetLib/FBX/FBXProperties.cpp
  42. 20 25
      code/AssetLib/FBX/FBXProperties.h
  43. 0 5
      code/AssetLib/FBX/FBXUtil.h
  44. 0 1
      code/AssetLib/NFF/NFFLoader.h
  45. 1 1
      code/AssetLib/Obj/ObjExporter.cpp
  46. 2 2
      code/AssetLib/Obj/ObjExporter.h
  47. 1 1
      code/AssetLib/Obj/ObjFileImporter.h
  48. 1 5
      code/AssetLib/Obj/ObjFileMtlImporter.cpp
  49. 2 5
      code/AssetLib/Obj/ObjFileMtlImporter.h
  50. 2 2
      code/AssetLib/Obj/ObjFileParser.cpp
  51. 7 4
      code/AssetLib/Obj/ObjFileParser.h
  52. 54 0
      include/assimp/scene.h

+ 1 - 2
code/AssetLib/3DS/3DSExporter.h

@@ -63,7 +63,7 @@ namespace Assimp {
  *  @brief  Helper class to export a given scene to a 3DS file.
  *  @brief  Helper class to export a given scene to a 3DS file.
  */
  */
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-class Discreet3DSExporter {
+class Discreet3DSExporter final {
 public:
 public:
     Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* pScene);
     Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* pScene);
     ~Discreet3DSExporter() = default;
     ~Discreet3DSExporter() = default;
@@ -88,7 +88,6 @@ private:
 
 
     using MeshesByNodeMap = std::multimap<const aiNode*, unsigned int>;
     using MeshesByNodeMap = std::multimap<const aiNode*, unsigned int>;
     MeshesByNodeMap meshes;
     MeshesByNodeMap meshes;
-
 };
 };
 
 
 } // Namespace Assimp
 } // Namespace Assimp

+ 1 - 2
code/AssetLib/3DS/3DSLoader.h

@@ -5,7 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -64,7 +63,7 @@ using namespace D3DS;
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 /** Importer class for 3D Studio r3 and r4 3DS files
 /** Importer class for 3D Studio r3 and r4 3DS files
  */
  */
-class Discreet3DSImporter : public BaseImporter {
+class Discreet3DSImporter final : public BaseImporter {
 public:
 public:
     Discreet3DSImporter();
     Discreet3DSImporter();
     ~Discreet3DSImporter() override = default;
     ~Discreet3DSImporter() override = default;

+ 1 - 1
code/AssetLib/3MF/D3MFImporter.cpp

@@ -107,7 +107,7 @@ void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene,
 
 
     XmlParser xmlParser;
     XmlParser xmlParser;
     if (xmlParser.parse(opcPackage.RootStream())) {
     if (xmlParser.parse(opcPackage.RootStream())) {
-        XmlSerializer xmlSerializer(&xmlParser);
+        XmlSerializer xmlSerializer(xmlParser);
         xmlSerializer.ImportXml(pScene);
         xmlSerializer.ImportXml(pScene);
 
 
         const std::vector<aiTexture*> &tex =  opcPackage.GetEmbeddedTextures();
         const std::vector<aiTexture*> &tex =  opcPackage.GetEmbeddedTextures();

+ 3 - 3
code/AssetLib/3MF/XmlSerializer.cpp

@@ -199,11 +199,11 @@ void assignDiffuseColor(XmlNode &node, aiMaterial *mat) {
 
 
 } // namespace
 } // namespace
 
 
-XmlSerializer::XmlSerializer(XmlParser *xmlParser) :
+XmlSerializer::XmlSerializer(XmlParser &xmlParser) :
         mResourcesDictionnary(),
         mResourcesDictionnary(),
         mMeshCount(0),
         mMeshCount(0),
         mXmlParser(xmlParser) {
         mXmlParser(xmlParser) {
-    ai_assert(nullptr != xmlParser);
+    // empty
 }
 }
 
 
 XmlSerializer::~XmlSerializer() {
 XmlSerializer::~XmlSerializer() {
@@ -218,7 +218,7 @@ void XmlSerializer::ImportXml(aiScene *scene) {
     }
     }
 
 
     scene->mRootNode = new aiNode(XmlTag::RootTag);
     scene->mRootNode = new aiNode(XmlTag::RootTag);
-    XmlNode node = mXmlParser->getRootNode().child(XmlTag::model);
+    XmlNode node = mXmlParser.getRootNode().child(XmlTag::model);
     if (node.empty()) {
     if (node.empty()) {
         return;
         return;
     }
     }

+ 3 - 3
code/AssetLib/3MF/XmlSerializer.h

@@ -59,9 +59,9 @@ class Texture2DGroup;
 class EmbeddedTexture;
 class EmbeddedTexture;
 class ColorGroup;
 class ColorGroup;
 
 
-class XmlSerializer {
+class XmlSerializer final {
 public:
 public:
-    XmlSerializer(XmlParser *xmlParser);
+    XmlSerializer(XmlParser &xmlParser);
     ~XmlSerializer();
     ~XmlSerializer();
     void ImportXml(aiScene *scene);
     void ImportXml(aiScene *scene);
 
 
@@ -92,7 +92,7 @@ private:
     std::vector<aiMaterial *> mMaterials;
     std::vector<aiMaterial *> mMaterials;
     std::map<unsigned int, Resource *> mResourcesDictionnary;
     std::map<unsigned int, Resource *> mResourcesDictionnary;
     unsigned int mMeshCount;
     unsigned int mMeshCount;
-    XmlParser *mXmlParser;
+    XmlParser &mXmlParser;
 };
 };
 
 
 } // namespace D3MF
 } // namespace D3MF

+ 6 - 7
code/AssetLib/AC/ACLoader.cpp

@@ -144,10 +144,6 @@ AC3DImporter::AC3DImporter() :
     // nothing to be done here
     // nothing to be done here
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-AC3DImporter::~AC3DImporter() = default;
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
 bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
 bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
@@ -171,8 +167,9 @@ bool AC3DImporter::GetNextLine() {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Parse an object section in an AC file
 // Parse an object section in an AC file
 bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
 bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
-    if (!TokenMatch(mBuffer.data, "OBJECT", 6))
+    if (!TokenMatch(mBuffer.data, "OBJECT", 6)) {
         return false;
         return false;
+    }
 
 
     SkipSpaces(&mBuffer.data, mBuffer.end);
     SkipSpaces(&mBuffer.data, mBuffer.end);
 
 
@@ -192,7 +189,6 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
         light->mAttenuationConstant = 1.f;
         light->mAttenuationConstant = 1.f;
 
 
         // Generate a default name for both the light source and the node
         // Generate a default name for both the light source and the node
-        // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
         light->mName.length = ::ai_snprintf(light->mName.data, AI_MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
         light->mName.length = ::ai_snprintf(light->mName.data, AI_MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
         obj.name = std::string(light->mName.data);
         obj.name = std::string(light->mName.data);
 
 
@@ -202,8 +198,10 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
         obj.type = Object::Group;
         obj.type = Object::Group;
     } else if (!ASSIMP_strincmp(mBuffer.data, "world", 5)) {
     } else if (!ASSIMP_strincmp(mBuffer.data, "world", 5)) {
         obj.type = Object::World;
         obj.type = Object::World;
-    } else
+    } else {
         obj.type = Object::Poly;
         obj.type = Object::Poly;
+    }
+
     while (GetNextLine()) {
     while (GetNextLine()) {
         if (TokenMatch(mBuffer.data, "kids", 4)) {
         if (TokenMatch(mBuffer.data, "kids", 4)) {
             SkipSpaces(&mBuffer.data, mBuffer.end);
             SkipSpaces(&mBuffer.data, mBuffer.end);
@@ -344,6 +342,7 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
         }
         }
     }
     }
     ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: \'kids\' line was expected");
     ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: \'kids\' line was expected");
+
     return false;
     return false;
 }
 }
 
 

+ 2 - 2
code/AssetLib/AC/ACLoader.h

@@ -63,7 +63,7 @@ namespace Assimp {
 class AC3DImporter : public BaseImporter {
 class AC3DImporter : public BaseImporter {
 public:
 public:
     AC3DImporter();
     AC3DImporter();
-    ~AC3DImporter() override;
+    ~AC3DImporter() override = default;
 
 
     // Represents an AC3D material
     // Represents an AC3D material
     struct Material {
     struct Material {
@@ -103,7 +103,7 @@ public:
 
 
         unsigned int mat, flags;
         unsigned int mat, flags;
 
 
-        typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
+        using SurfaceEntry = std::pair<unsigned int, aiVector2D>;
         std::vector<SurfaceEntry> entries;
         std::vector<SurfaceEntry> entries;
 
 
         // Type is low nibble of flags
         // Type is low nibble of flags

+ 1 - 1
code/AssetLib/AMF/AMFImporter.cpp

@@ -474,7 +474,7 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) {
 
 
     // read attribute
     // read attribute
     ne = new AMFMetadata(mNodeElement_Cur);
     ne = new AMFMetadata(mNodeElement_Cur);
-    ((AMFMetadata *)ne)->Type = type;
+    ((AMFMetadata *)ne)->MetaType = type;
     ((AMFMetadata *)ne)->Value = value;
     ((AMFMetadata *)ne)->Value = value;
     mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
     mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.

+ 7 - 6
code/AssetLib/AMF/AMFImporter_Node.hpp

@@ -86,7 +86,8 @@ public:
 	AMFNodeElementBase *Parent; ///< Parent element. If nullptr then this node is root.
 	AMFNodeElementBase *Parent; ///< Parent element. If nullptr then this node is root.
 	std::list<AMFNodeElementBase *> Child; ///< Child elements.
 	std::list<AMFNodeElementBase *> Child; ///< Child elements.
 
 
-public: /// Destructor, virtual..
+public: 
+	/// Destructor, virtual..
 	virtual ~AMFNodeElementBase() = default;
 	virtual ~AMFNodeElementBase() = default;
 
 
 	/// Disabled copy constructor and co.
 	/// Disabled copy constructor and co.
@@ -97,10 +98,10 @@ public: /// Destructor, virtual..
 
 
 protected:
 protected:
 	/// In constructor inheritor must set element type.
 	/// In constructor inheritor must set element type.
-	/// \param [in] pType - element type.
+	/// \param [in] type - element type.
 	/// \param [in] pParent - parent element.
 	/// \param [in] pParent - parent element.
-	AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) :
-			Type(pType), Parent(pParent) {
+	AMFNodeElementBase(EType type, AMFNodeElementBase *pParent) :
+			Type(type), Parent(pParent) {
 		// empty
 		// empty
 	}
 	}
 }; // class IAMFImporter_NodeElement
 }; // class IAMFImporter_NodeElement
@@ -135,8 +136,8 @@ struct AMFInstance : public AMFNodeElementBase {
 /// Structure that define metadata node.
 /// Structure that define metadata node.
 struct AMFMetadata : public AMFNodeElementBase {
 struct AMFMetadata : public AMFNodeElementBase {
 
 
-	std::string Type; ///< Type of "Value".
-	std::string Value; ///< Value.
+	std::string MetaType; ///< Type of "Value".
+	std::string Value;    ///< Value.
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.

+ 1 - 1
code/AssetLib/AMF/AMFImporter_Postprocess.cpp

@@ -333,7 +333,7 @@ void AMFImporter::Postprocess_AddMetadata(const AMFMetaDataArray &metadataList,
     size_t meta_idx(0);
     size_t meta_idx(0);
 
 
     for (const AMFMetadata *metadata : metadataList) {
     for (const AMFMetadata *metadata : metadataList) {
-        sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata->Type, aiString(metadata->Value));
+        sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata->MetaType, aiString(metadata->Value));
     }
     }
 }
 }
 
 

+ 3 - 7
code/AssetLib/BVH/BVHLoader.cpp

@@ -6,8 +6,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -85,11 +83,9 @@ BVHLoader::BVHLoader() :
         mLine(),
         mLine(),
         mAnimTickDuration(),
         mAnimTickDuration(),
         mAnimNumFrames(),
         mAnimNumFrames(),
-        noSkeletonMesh() {}
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-BVHLoader::~BVHLoader() = default;
+        noSkeletonMesh() {
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.

+ 7 - 12
code/AssetLib/BVH/BVHLoader.h

@@ -80,32 +80,27 @@ class BVHLoader : public BaseImporter {
         std::vector<ChannelType> mChannels;
         std::vector<ChannelType> mChannels;
         std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
         std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
 
 
-        Node() :
-                mNode(nullptr) {}
-
-        explicit Node(const aiNode *pNode) :
-                mNode(pNode) {}
+        Node() : mNode(nullptr) {}
+        explicit Node(const aiNode *pNode) :mNode(pNode) {}
     };
     };
 
 
 public:
 public:
     BVHLoader();
     BVHLoader();
-    ~BVHLoader();
+    ~BVHLoader() override = default;
 
 
-public:
     /** Returns whether the class can handle the format of the given file.
     /** Returns whether the class can handle the format of the given file.
      * See BaseImporter::CanRead() for details. */
      * See BaseImporter::CanRead() for details. */
-    bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const;
+    bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const override;
 
 
-    void SetupProperties(const Importer *pImp);
-    const aiImporterDesc *GetInfo() const;
+    void SetupProperties(const Importer *pImp) override;
+    const aiImporterDesc *GetInfo() const override;
 
 
 protected:
 protected:
     /** Imports the given file into the given scene structure.
     /** Imports the given file into the given scene structure.
      * See BaseImporter::InternReadFile() for details
      * See BaseImporter::InternReadFile() for details
      */
      */
-    void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
+    void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
 
 
-protected:
     /** Reads the file */
     /** Reads the file */
     void ReadStructure(aiScene *pScene);
     void ReadStructure(aiScene *pScene);
 
 

+ 0 - 1
code/AssetLib/Blender/BlenderDNA.h

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

+ 3 - 1
code/AssetLib/Blender/BlenderDNA.inl

@@ -841,5 +841,7 @@ template <template <typename> class TOUT> template <typename T> void ObjectCache
 #endif
 #endif
 }
 }
 
 
-}}
+}
+}
+
 #endif
 #endif

+ 0 - 1
code/AssetLib/Blender/BlenderIntermediate.h

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

+ 2 - 10
code/AssetLib/C4D/C4DImporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2021, assimp team
+Copyright (c) 2006-2024, assimp team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -86,7 +86,7 @@ namespace Assimp {
     }
     }
 }
 }
 
 
-static const aiImporterDesc desc = {
+static constexpr aiImporterDesc desc = {
     "Cinema4D Importer",
     "Cinema4D Importer",
     "",
     "",
     "",
     "",
@@ -99,13 +99,6 @@ static const aiImporterDesc desc = {
     "c4d"
     "c4d"
 };
 };
 
 
-
-// ------------------------------------------------------------------------------------------------
-C4DImporter::C4DImporter() = default;
-
-// ------------------------------------------------------------------------------------------------
-C4DImporter::~C4DImporter() = default;
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
 bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
     const std::string& extension = GetExtension(pFile);
     const std::string& extension = GetExtension(pFile);
@@ -196,7 +189,6 @@ void C4DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
     std::copy(materials.begin(), materials.end(), pScene->mMaterials);
     std::copy(materials.begin(), materials.end(), pScene->mMaterials);
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 bool C4DImporter::ReadShader(aiMaterial* out, BaseShader* shader) {
 bool C4DImporter::ReadShader(aiMaterial* out, BaseShader* shader) {
     // based on Cineware sample code (C4DImportExport.cpp)
     // based on Cineware sample code (C4DImportExport.cpp)

+ 2 - 2
code/AssetLib/C4D/C4DImporter.h

@@ -78,8 +78,8 @@ namespace Assimp  {
 // -------------------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------------------
 class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter> {
 class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter> {
 public:
 public:
-    C4DImporter();
-    ~C4DImporter() override;
+    C4DImporter() = default;
+    ~C4DImporter() override = default;
     bool CanRead( const std::string& pFile, IOSystem*, bool checkSig) const override;
     bool CanRead( const std::string& pFile, IOSystem*, bool checkSig) const override;
 
 
 protected:
 protected:

+ 1 - 1
code/AssetLib/COB/COBLoader.cpp

@@ -228,7 +228,7 @@ aiNode *COBImporter::BuildNodes(const Node &root, const Scene &scin, aiScene *fi
         const Mesh &ndmesh = (const Mesh &)(root);
         const Mesh &ndmesh = (const Mesh &)(root);
         if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) {
         if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) {
 
 
-            typedef std::pair<const unsigned int, Mesh::FaceRefList> Entry;
+            using Entry = std::pair<const unsigned int, Mesh::FaceRefList>;
             for (const Entry &reflist : ndmesh.temp_map) {
             for (const Entry &reflist : ndmesh.temp_map) {
                 { // create mesh
                 { // create mesh
                     size_t n = 0;
                     size_t n = 0;

+ 4 - 8
code/AssetLib/CSM/CSMLoader.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -73,10 +71,9 @@ static constexpr aiImporterDesc desc = {
     "csm"
     "csm"
 };
 };
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
-CSMImporter::CSMImporter() : noSkeletonMesh(){
+CSMImporter::CSMImporter() : noSkeletonMesh() {
     // empty
     // empty
 }
 }
 
 
@@ -102,8 +99,7 @@ void CSMImporter::SetupProperties(const Importer* pImp) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 // Imports the given file into the given scene structure.
 void CSMImporter::InternReadFile( const std::string& pFile,
 void CSMImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
-{
+        aiScene* pScene, IOSystem* pIOHandler) {
     std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
     std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
@@ -127,11 +123,11 @@ void CSMImporter::InternReadFile( const std::string& pFile,
 
 
         if ('$'  == *buffer)    {
         if ('$'  == *buffer)    {
             ++buffer;
             ++buffer;
-            if (TokenMatchI(buffer,"firstframe",10))    {
+            if (TokenMatchI(buffer,"firstframe",10)) {
                 SkipSpaces(&buffer, end);
                 SkipSpaces(&buffer, end);
                 first = strtol10(buffer,&buffer);
                 first = strtol10(buffer,&buffer);
             }
             }
-            else if (TokenMatchI(buffer,"lastframe",9))     {
+            else if (TokenMatchI(buffer,"lastframe",9)) {
                 SkipSpaces(&buffer, end);
                 SkipSpaces(&buffer, end);
                 last = strtol10(buffer,&buffer);
                 last = strtol10(buffer,&buffer);
             }
             }

+ 310 - 252
code/AssetLib/Collada/ColladaExporter.cpp

@@ -62,6 +62,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 namespace Assimp {
 namespace Assimp {
 
 
+static const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) {
+    std::set<const aiNode *> topParentBoneNodes;
+    if (mesh && mesh->mNumBones > 0) {
+        for (unsigned int i = 0; i < mesh->mNumBones; ++i) {
+            aiBone *bone = mesh->mBones[i];
+
+            const aiNode *node = scene->mRootNode->findBoneNode(bone);
+            if (node) {
+                while (node->mParent && scene->findBone(node->mParent->mName) != nullptr) {
+                    node = node->mParent;
+                }
+                topParentBoneNodes.insert(node);
+            }
+        }
+    }
+
+    if (!topParentBoneNodes.empty()) {
+        const aiNode *parentBoneNode = *topParentBoneNodes.begin();
+        if (topParentBoneNodes.size() == 1) {
+            return parentBoneNode;
+        } else {
+            for (auto it : topParentBoneNodes) {
+                if (it->mParent) return it->mParent;
+            }
+            return parentBoneNode;
+        }
+    }
+
+    return nullptr;
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 void ExportSceneCollada(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
 void ExportSceneCollada(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
@@ -325,60 +356,68 @@ void ColladaExporter::WriteHeader() {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Write the embedded textures
 // Write the embedded textures
 void ColladaExporter::WriteTextures() {
 void ColladaExporter::WriteTextures() {
-    static const unsigned int buffer_size = 1024;
-    char str[buffer_size];
+    static constexpr unsigned int buffer_size = 1024;
+    char str[buffer_size] = {'\0'};
 
 
-    if (mScene->HasTextures()) {
-        for (unsigned int i = 0; i < mScene->mNumTextures; i++) {
-            // It would be great to be able to create a directory in portable standard C++, but it's not the case,
-            // so we just write the textures in the current directory.
-
-            aiTexture *texture = mScene->mTextures[i];
-            if (nullptr == texture) {
-                continue;
-            }
+    if (!mScene->HasTextures()) {
+        return;
+    }
 
 
-            ASSIMP_itoa10(str, buffer_size, i + 1);
+    for (unsigned int i = 0; i < mScene->mNumTextures; i++) {
+        // It would be great to be able to create a directory in portable standard C++, but it's not the case,
+        // so we just write the textures in the current directory.
 
 
-            std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char *)texture->achFormatHint);
+        aiTexture *texture = mScene->mTextures[i];
+        if (nullptr == texture) {
+            continue;
+        }
 
 
-            std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb"));
-            if (outfile == nullptr) {
-                throw DeadlyExportError("could not open output texture file: " + mPath + name);
-            }
+        ASSIMP_itoa10(str, buffer_size, i + 1);
 
 
-            if (texture->mHeight == 0) {
-                outfile->Write((void *)texture->pcData, texture->mWidth, 1);
-            } else {
-                Bitmap::Save(texture, outfile.get());
-            }
+        std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char *)texture->achFormatHint);
 
 
-            outfile->Flush();
+        std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb"));
+        if (outfile == nullptr) {
+            throw DeadlyExportError("could not open output texture file: " + mPath + name);
+        }
 
 
-            textures.insert(std::make_pair(i, name));
+        if (texture->mHeight == 0) {
+            outfile->Write((void *)texture->pcData, texture->mWidth, 1);
+        } else {
+            Bitmap::Save(texture, outfile.get());
         }
         }
+
+        outfile->Flush();
+
+        textures.insert(std::make_pair(i, name));
     }
     }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Write the embedded textures
 // Write the embedded textures
 void ColladaExporter::WriteCamerasLibrary() {
 void ColladaExporter::WriteCamerasLibrary() {
-    if (mScene->HasCameras()) {
-
-        mOutput << startstr << "<library_cameras>" << endstr;
-        PushTag();
+    if (!mScene->HasCameras()) {
+        return;
+    }
 
 
-        for (size_t a = 0; a < mScene->mNumCameras; ++a)
-            WriteCamera(a);
+    mOutput << startstr << "<library_cameras>" << endstr;
+    PushTag();
 
 
-        PopTag();
-        mOutput << startstr << "</library_cameras>" << endstr;
+    for (size_t a = 0; a < mScene->mNumCameras; ++a) {
+        WriteCamera(a);
     }
     }
+
+    PopTag();
+    mOutput << startstr << "</library_cameras>" << endstr;
 }
 }
 
 
 void ColladaExporter::WriteCamera(size_t pIndex) {
 void ColladaExporter::WriteCamera(size_t pIndex) {
 
 
     const aiCamera *cam = mScene->mCameras[pIndex];
     const aiCamera *cam = mScene->mCameras[pIndex];
+    if (cam == nullptr) {
+        return;
+    }
+
     const std::string cameraId = GetObjectUniqueId(AiObjectType::Camera, pIndex);
     const std::string cameraId = GetObjectUniqueId(AiObjectType::Camera, pIndex);
     const std::string cameraName = GetObjectName(AiObjectType::Camera, pIndex);
     const std::string cameraName = GetObjectName(AiObjectType::Camera, pIndex);
 
 
@@ -416,22 +455,27 @@ void ColladaExporter::WriteCamera(size_t pIndex) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Write the embedded textures
 // Write the embedded textures
 void ColladaExporter::WriteLightsLibrary() {
 void ColladaExporter::WriteLightsLibrary() {
-    if (mScene->HasLights()) {
-
-        mOutput << startstr << "<library_lights>" << endstr;
-        PushTag();
+    if (!mScene->HasLights()) {
+        return;
+    }
 
 
-        for (size_t a = 0; a < mScene->mNumLights; ++a)
-            WriteLight(a);
+    mOutput << startstr << "<library_lights>" << endstr;
+    PushTag();
 
 
-        PopTag();
-        mOutput << startstr << "</library_lights>" << endstr;
+    for (size_t a = 0; a < mScene->mNumLights; ++a) {
+        WriteLight(a);
     }
     }
+
+    PopTag();
+    mOutput << startstr << "</library_lights>" << endstr;
 }
 }
 
 
 void ColladaExporter::WriteLight(size_t pIndex) {
 void ColladaExporter::WriteLight(size_t pIndex) {
 
 
     const aiLight *light = mScene->mLights[pIndex];
     const aiLight *light = mScene->mLights[pIndex];
+    if (light == nullptr) {
+        return;
+    }
     const std::string lightId = GetObjectUniqueId(AiObjectType::Light, pIndex);
     const std::string lightId = GetObjectUniqueId(AiObjectType::Light, pIndex);
     const std::string lightName = GetObjectName(AiObjectType::Light, pIndex);
     const std::string lightName = GetObjectName(AiObjectType::Light, pIndex);
 
 
@@ -456,6 +500,7 @@ void ColladaExporter::WriteLight(size_t pIndex) {
     case aiLightSource_AREA:
     case aiLightSource_AREA:
     case aiLightSource_UNDEFINED:
     case aiLightSource_UNDEFINED:
     case _aiLightSource_Force32Bit:
     case _aiLightSource_Force32Bit:
+    default:
         break;
         break;
     }
     }
     PopTag();
     PopTag();
@@ -515,10 +560,6 @@ void ColladaExporter::WriteSpotLight(const aiLight *const light) {
     mOutput << startstr << "<quadratic_attenuation>"
     mOutput << startstr << "<quadratic_attenuation>"
             << light->mAttenuationQuadratic
             << light->mAttenuationQuadratic
             << "</quadratic_attenuation>" << endstr;
             << "</quadratic_attenuation>" << endstr;
-    /*
-    out->mAngleOuterCone = AI_DEG_TO_RAD (std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+
-                            srcLight->mFalloffAngle);
-    */
 
 
     const ai_real fallOffAngle = AI_RAD_TO_DEG(light->mAngleInnerCone);
     const ai_real fallOffAngle = AI_RAD_TO_DEG(light->mAngleInnerCone);
     mOutput << startstr << "<falloff_angle sid=\"fall_off_angle\">"
     mOutput << startstr << "<falloff_angle sid=\"fall_off_angle\">"
@@ -552,43 +593,44 @@ void ColladaExporter::WriteAmbientLight(const aiLight *const light) {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads a single surface entry from the given material keys
 // Reads a single surface entry from the given material keys
-bool ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture,
-        const char *pKey, size_t pType, size_t pIndex) {
-    if (pSrcMat.GetTextureCount(pTexture) > 0) {
-        aiString texfile;
-        unsigned int uvChannel = 0;
-        pSrcMat.GetTexture(pTexture, 0, &texfile, nullptr, &uvChannel);
+bool ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex) {
+    if (pSrcMat.GetTextureCount(pTexture) == 0) {
+        if (pKey)
+            poSurface.exist = pSrcMat.Get(pKey, static_cast<unsigned int>(pType), static_cast<unsigned int>(pIndex), poSurface.color) == aiReturn_SUCCESS;
+        return poSurface.exist;
+    }
 
 
-        std::string index_str(texfile.C_Str());
+    aiString texfile;
+    unsigned int uvChannel = 0;
+    pSrcMat.GetTexture(pTexture, 0, &texfile, nullptr, &uvChannel);
 
 
-        if (index_str.size() != 0 && index_str[0] == '*') {
-            unsigned int index;
+    std::string index_str(texfile.C_Str());
 
 
-            index_str = index_str.substr(1, std::string::npos);
+    if (index_str.size() != 0 && index_str[0] == '*') {
+        unsigned int index;
 
 
-            try {
-                index = (unsigned int)strtoul10_64<DeadlyExportError>(index_str.c_str());
-            } catch (std::exception &error) {
-                throw DeadlyExportError(error.what());
-            }
+        index_str = index_str.substr(1, std::string::npos);
 
 
-            std::map<unsigned int, std::string>::const_iterator name = textures.find(index);
+        try {
+            index = (unsigned int)strtoul10_64<DeadlyExportError>(index_str.c_str());
+        } catch (std::exception &error) {
+            throw DeadlyExportError(error.what());
+        }
 
 
-            if (name != textures.end()) {
-                poSurface.texture = name->second;
-            } else {
-                throw DeadlyExportError("could not find embedded texture at index " + index_str);
-            }
+        std::map<unsigned int, std::string>::const_iterator name = textures.find(index);
+
+        if (name != textures.end()) {
+            poSurface.texture = name->second;
         } else {
         } else {
-            poSurface.texture = texfile.C_Str();
+            throw DeadlyExportError("could not find embedded texture at index " + index_str);
         }
         }
-
-        poSurface.channel = uvChannel;
-        poSurface.exist = true;
     } else {
     } else {
-        if (pKey)
-            poSurface.exist = pSrcMat.Get(pKey, static_cast<unsigned int>(pType), static_cast<unsigned int>(pIndex), poSurface.color) == aiReturn_SUCCESS;
+        poSurface.texture = texfile.C_Str();
     }
     }
+
+    poSurface.channel = uvChannel;
+    poSurface.exist = true;
+
     return poSurface.exist;
     return poSurface.exist;
 }
 }
 
 
@@ -601,79 +643,87 @@ static bool isalnum_C(char c) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Writes an image entry for the given surface
 // Writes an image entry for the given surface
 void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string &imageId) {
 void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string &imageId) {
-    if (!pSurface.texture.empty()) {
-        mOutput << startstr << "<image id=\"" << imageId << "\">" << endstr;
-        PushTag();
-        mOutput << startstr << "<init_from>";
+    if (pSurface.texture.empty()) {
+        return;
+    }
 
 
-        // URL encode image file name first, then XML encode on top
-        std::stringstream imageUrlEncoded;
-        for (std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it) {
-            if (isalnum_C((unsigned char)*it) || *it == ':' || *it == '_' || *it == '-' || *it == '.' || *it == '/' || *it == '\\')
-                imageUrlEncoded << *it;
-            else
-                imageUrlEncoded << '%' << std::hex << size_t((unsigned char)*it) << std::dec;
-        }
-        mOutput << XMLEscape(imageUrlEncoded.str());
-        mOutput << "</init_from>" << endstr;
-        PopTag();
-        mOutput << startstr << "</image>" << endstr;
+    mOutput << startstr << "<image id=\"" << imageId << "\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<init_from>";
+
+    // URL encode image file name first, then XML encode on top
+    std::stringstream imageUrlEncoded;
+    for (std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it) {
+        if (isalnum_C((unsigned char)*it) || *it == ':' || *it == '_' || *it == '-' || *it == '.' || *it == '/' || *it == '\\')
+            imageUrlEncoded << *it;
+        else
+            imageUrlEncoded << '%' << std::hex << size_t((unsigned char)*it) << std::dec;
     }
     }
+    mOutput << XMLEscape(imageUrlEncoded.str());
+    mOutput << "</init_from>" << endstr;
+    PopTag();
+    mOutput << startstr << "</image>" << endstr;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Writes a color-or-texture entry into an effect definition
 // Writes a color-or-texture entry into an effect definition
 void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId) {
 void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId) {
-    if (pSurface.exist) {
-        mOutput << startstr << "<" << pTypeName << ">" << endstr;
-        PushTag();
-        if (pSurface.texture.empty()) {
-            mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
-        } else {
-            mOutput << startstr << "<texture texture=\"" << imageId << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
-        }
-        PopTag();
-        mOutput << startstr << "</" << pTypeName << ">" << endstr;
+    if (!pSurface.exist) {
+        return;
+    }
+
+    mOutput << startstr << "<" << pTypeName << ">" << endstr;
+    PushTag();
+    if (pSurface.texture.empty()) {
+        mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
+    } else {
+        mOutput << startstr << "<texture texture=\"" << imageId << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
     }
     }
+    PopTag();
+    mOutput << startstr << "</" << pTypeName << ">" << endstr;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Writes the two parameters necessary for referencing a texture in an effect entry
 // Writes the two parameters necessary for referencing a texture in an effect entry
 void ColladaExporter::WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId) {
 void ColladaExporter::WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId) {
     // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
     // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
-    if (!pSurface.texture.empty()) {
-        mOutput << startstr << "<newparam sid=\"" << materialId << "-" << pTypeName << "-surface\">" << endstr;
-        PushTag();
-        mOutput << startstr << "<surface type=\"2D\">" << endstr;
-        PushTag();
-        mOutput << startstr << "<init_from>" << materialId << "-" << pTypeName << "-image</init_from>" << endstr;
-        PopTag();
-        mOutput << startstr << "</surface>" << endstr;
-        PopTag();
-        mOutput << startstr << "</newparam>" << endstr;
-
-        mOutput << startstr << "<newparam sid=\"" << materialId << "-" << pTypeName << "-sampler\">" << endstr;
-        PushTag();
-        mOutput << startstr << "<sampler2D>" << endstr;
-        PushTag();
-        mOutput << startstr << "<source>" << materialId << "-" << pTypeName << "-surface</source>" << endstr;
-        PopTag();
-        mOutput << startstr << "</sampler2D>" << endstr;
-        PopTag();
-        mOutput << startstr << "</newparam>" << endstr;
+    if (pSurface.texture.empty()) {
+        return;
     }
     }
+
+    mOutput << startstr << "<newparam sid=\"" << materialId << "-" << pTypeName << "-surface\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<surface type=\"2D\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<init_from>" << materialId << "-" << pTypeName << "-image</init_from>" << endstr;
+    PopTag();
+    mOutput << startstr << "</surface>" << endstr;
+    PopTag();
+    mOutput << startstr << "</newparam>" << endstr;
+
+    mOutput << startstr << "<newparam sid=\"" << materialId << "-" << pTypeName << "-sampler\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<sampler2D>" << endstr;
+    PushTag();
+    mOutput << startstr << "<source>" << materialId << "-" << pTypeName << "-surface</source>" << endstr;
+    PopTag();
+    mOutput << startstr << "</sampler2D>" << endstr;
+    PopTag();
+    mOutput << startstr << "</newparam>" << endstr;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Writes a scalar property
 // Writes a scalar property
 void ColladaExporter::WriteFloatEntry(const Property &pProperty, const std::string &pTypeName) {
 void ColladaExporter::WriteFloatEntry(const Property &pProperty, const std::string &pTypeName) {
-    if (pProperty.exist) {
-        mOutput << startstr << "<" << pTypeName << ">" << endstr;
-        PushTag();
-        mOutput << startstr << "<float sid=\"" << pTypeName << "\">" << pProperty.value << "</float>" << endstr;
-        PopTag();
-        mOutput << startstr << "</" << pTypeName << ">" << endstr;
+    if (!pProperty.exist) {
+        return;
     }
     }
+
+    mOutput << startstr << "<" << pTypeName << ">" << endstr;
+    PushTag();
+    mOutput << startstr << "<float sid=\"" << pTypeName << "\">" << pProperty.value << "</float>" << endstr;
+    PopTag();
+    mOutput << startstr << "</" << pTypeName << ">" << endstr;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -827,8 +877,9 @@ void ColladaExporter::WriteControllerLibrary() {
 void ColladaExporter::WriteController(size_t pIndex) {
 void ColladaExporter::WriteController(size_t pIndex) {
     const aiMesh *mesh = mScene->mMeshes[pIndex];
     const aiMesh *mesh = mScene->mMeshes[pIndex];
     // Is there a skin controller?
     // Is there a skin controller?
-    if (mesh->mNumBones == 0 || mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
+    if (mesh->mNumBones == 0 || mesh->mNumFaces == 0 || mesh->mNumVertices == 0) {
         return;
         return;
+    }
 
 
     const std::string idstr = GetObjectUniqueId(AiObjectType::Mesh, pIndex);
     const std::string idstr = GetObjectUniqueId(AiObjectType::Mesh, pIndex);
     const std::string namestr = GetObjectName(AiObjectType::Mesh, pIndex);
     const std::string namestr = GetObjectName(AiObjectType::Mesh, pIndex);
@@ -859,8 +910,9 @@ void ColladaExporter::WriteController(size_t pIndex) {
 
 
     mOutput << startstr << "<Name_array id=\"" << idstr << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\">";
     mOutput << startstr << "<Name_array id=\"" << idstr << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\">";
 
 
-    for (size_t i = 0; i < mesh->mNumBones; ++i)
+    for (size_t i = 0; i < mesh->mNumBones; ++i) {
         mOutput << GetBoneUniqueId(mesh->mBones[i]) << ' ';
         mOutput << GetBoneUniqueId(mesh->mBones[i]) << ' ';
+    }
 
 
     mOutput << "</Name_array>" << endstr;
     mOutput << "</Name_array>" << endstr;
 
 
@@ -883,9 +935,11 @@ void ColladaExporter::WriteController(size_t pIndex) {
 
 
     std::vector<ai_real> bind_poses;
     std::vector<ai_real> bind_poses;
     bind_poses.reserve(mesh->mNumBones * 16);
     bind_poses.reserve(mesh->mNumBones * 16);
-    for (unsigned int i = 0; i < mesh->mNumBones; ++i)
-        for (unsigned int j = 0; j < 4; ++j)
+    for (unsigned int i = 0; i < mesh->mNumBones; ++i) {
+        for (unsigned int j = 0; j < 4; ++j) {
             bind_poses.insert(bind_poses.end(), mesh->mBones[i]->mOffsetMatrix[j], mesh->mBones[i]->mOffsetMatrix[j] + 4);
             bind_poses.insert(bind_poses.end(), mesh->mBones[i]->mOffsetMatrix[j], mesh->mBones[i]->mOffsetMatrix[j] + 4);
+        }
+    }
 
 
     WriteFloatArray(idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real *)bind_poses.data(), bind_poses.size() / 16);
     WriteFloatArray(idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real *)bind_poses.data(), bind_poses.size() / 16);
 
 
@@ -893,9 +947,11 @@ void ColladaExporter::WriteController(size_t pIndex) {
 
 
     std::vector<ai_real> skin_weights;
     std::vector<ai_real> skin_weights;
     skin_weights.reserve(mesh->mNumVertices * mesh->mNumBones);
     skin_weights.reserve(mesh->mNumVertices * mesh->mNumBones);
-    for (size_t i = 0; i < mesh->mNumBones; ++i)
-        for (size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j)
+    for (size_t i = 0; i < mesh->mNumBones; ++i) {
+        for (size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) {
             skin_weights.push_back(mesh->mBones[i]->mWeights[j].mWeight);
             skin_weights.push_back(mesh->mBones[i]->mWeights[j].mWeight);
+        }
+    }
 
 
     WriteFloatArray(idstr + "-skin-weights", FloatType_Weight, (const ai_real *)skin_weights.data(), skin_weights.size());
     WriteFloatArray(idstr + "-skin-weights", FloatType_Weight, (const ai_real *)skin_weights.data(), skin_weights.size());
 
 
@@ -919,12 +975,15 @@ void ColladaExporter::WriteController(size_t pIndex) {
     mOutput << startstr << "<vcount>";
     mOutput << startstr << "<vcount>";
 
 
     std::vector<ai_uint> num_influences(mesh->mNumVertices, (ai_uint)0);
     std::vector<ai_uint> num_influences(mesh->mNumVertices, (ai_uint)0);
-    for (size_t i = 0; i < mesh->mNumBones; ++i)
-        for (size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j)
+    for (size_t i = 0; i < mesh->mNumBones; ++i) {
+        for (size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) {
             ++num_influences[mesh->mBones[i]->mWeights[j].mVertexId];
             ++num_influences[mesh->mBones[i]->mWeights[j].mVertexId];
+        }
+    }
 
 
-    for (size_t i = 0; i < mesh->mNumVertices; ++i)
+    for (size_t i = 0; i < mesh->mNumVertices; ++i) {
         mOutput << num_influences[i] << " ";
         mOutput << num_influences[i] << " ";
+    }
 
 
     mOutput << "</vcount>" << endstr;
     mOutput << "</vcount>" << endstr;
 
 
@@ -940,7 +999,7 @@ void ColladaExporter::WriteController(size_t pIndex) {
 
 
     ai_uint weight_index = 0;
     ai_uint weight_index = 0;
     std::vector<ai_int> joint_weight_indices(2 * joint_weight_indices_length, (ai_int)-1);
     std::vector<ai_int> joint_weight_indices(2 * joint_weight_indices_length, (ai_int)-1);
-    for (unsigned int i = 0; i < mesh->mNumBones; ++i)
+    for (unsigned int i = 0; i < mesh->mNumBones; ++i) {
         for (unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j) {
         for (unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j) {
             unsigned int vId = mesh->mBones[i]->mWeights[j].mVertexId;
             unsigned int vId = mesh->mBones[i]->mWeights[j].mVertexId;
             for (ai_uint k = 0; k < num_influences[vId]; ++k) {
             for (ai_uint k = 0; k < num_influences[vId]; ++k) {
@@ -952,9 +1011,11 @@ void ColladaExporter::WriteController(size_t pIndex) {
             }
             }
             ++weight_index;
             ++weight_index;
         }
         }
+    }
 
 
-    for (size_t i = 0; i < joint_weight_indices.size(); ++i)
+    for (size_t i = 0; i < joint_weight_indices.size(); ++i) {
         mOutput << joint_weight_indices[i] << " ";
         mOutput << joint_weight_indices[i] << " ";
+    }
 
 
     num_influences.clear();
     num_influences.clear();
     accum_influences.clear();
     accum_influences.clear();
@@ -978,8 +1039,9 @@ void ColladaExporter::WriteGeometryLibrary() {
     mOutput << startstr << "<library_geometries>" << endstr;
     mOutput << startstr << "<library_geometries>" << endstr;
     PushTag();
     PushTag();
 
 
-    for (size_t a = 0; a < mScene->mNumMeshes; ++a)
+    for (size_t a = 0; a < mScene->mNumMeshes; ++a) {
         WriteGeometry(a);
         WriteGeometry(a);
+    }
 
 
     PopTag();
     PopTag();
     mOutput << startstr << "</library_geometries>" << endstr;
     mOutput << startstr << "</library_geometries>" << endstr;
@@ -992,8 +1054,9 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
     const std::string geometryId = GetObjectUniqueId(AiObjectType::Mesh, pIndex);
     const std::string geometryId = GetObjectUniqueId(AiObjectType::Mesh, pIndex);
     const std::string geometryName = GetObjectName(AiObjectType::Mesh, pIndex);
     const std::string geometryName = GetObjectName(AiObjectType::Mesh, pIndex);
 
 
-    if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
+    if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) {
         return;
         return;
+    }
 
 
     // opening tag
     // opening tag
     mOutput << startstr << "<geometry id=\"" << geometryId << "\" name=\"" << geometryName << "\" >" << endstr;
     mOutput << startstr << "<geometry id=\"" << geometryId << "\" name=\"" << geometryName << "\" >" << endstr;
@@ -1005,8 +1068,9 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
     // Positions
     // Positions
     WriteFloatArray(geometryId + "-positions", FloatType_Vector, (ai_real *)mesh->mVertices, mesh->mNumVertices);
     WriteFloatArray(geometryId + "-positions", FloatType_Vector, (ai_real *)mesh->mVertices, mesh->mNumVertices);
     // Normals, if any
     // Normals, if any
-    if (mesh->HasNormals())
+    if (mesh->HasNormals()) {
         WriteFloatArray(geometryId + "-normals", FloatType_Vector, (ai_real *)mesh->mNormals, mesh->mNumVertices);
         WriteFloatArray(geometryId + "-normals", FloatType_Vector, (ai_real *)mesh->mNormals, mesh->mNumVertices);
+    }
 
 
     // texture coords
     // texture coords
     for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
     for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
@@ -1035,10 +1099,11 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
     int countLines = 0;
     int countLines = 0;
     int countPoly = 0;
     int countPoly = 0;
     for (size_t a = 0; a < mesh->mNumFaces; ++a) {
     for (size_t a = 0; a < mesh->mNumFaces; ++a) {
-        if (mesh->mFaces[a].mNumIndices == 2)
+        if (mesh->mFaces[a].mNumIndices == 2) {
             countLines++;
             countLines++;
-        else if (mesh->mFaces[a].mNumIndices >= 3)
+        } else if (mesh->mFaces[a].mNumIndices >= 3) {
             countPoly++;
             countPoly++;
+        }
     }
     }
 
 
     // lines
     // lines
@@ -1046,13 +1111,18 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
         mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
         mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
         PushTag();
         PushTag();
         mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << geometryId << "-vertices\" />" << endstr;
         mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << geometryId << "-vertices\" />" << endstr;
-        if (mesh->HasNormals())
+        if (mesh->HasNormals()) {
             mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << geometryId << "-normals\" />" << endstr;
             mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << geometryId << "-normals\" />" << endstr;
+        }
         for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
         for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
-            if (mesh->HasTextureCoords(static_cast<unsigned int>(a)))
-                mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << geometryId << "-tex" << a << "\" "
+            if (mesh->HasTextureCoords(static_cast<unsigned int>(a))) {
+                mOutput << startstr 
+                        << "<input semantic=\"TEXCOORD\" source=\"#" 
+                        << geometryId 
+                        << "-tex" << a << "\" "
                         << "set=\"" << a << "\""
                         << "set=\"" << a << "\""
                         << " />" << endstr;
                         << " />" << endstr;
+            }
         }
         }
         for (size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
         for (size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
             if (mesh->HasVertexColors(static_cast<unsigned int>(a)))
             if (mesh->HasVertexColors(static_cast<unsigned int>(a)))
@@ -1065,8 +1135,9 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
         for (size_t a = 0; a < mesh->mNumFaces; ++a) {
         for (size_t a = 0; a < mesh->mNumFaces; ++a) {
             const aiFace &face = mesh->mFaces[a];
             const aiFace &face = mesh->mFaces[a];
             if (face.mNumIndices != 2) continue;
             if (face.mNumIndices != 2) continue;
-            for (size_t b = 0; b < face.mNumIndices; ++b)
+            for (size_t b = 0; b < face.mNumIndices; ++b) {
                 mOutput << face.mIndices[b] << " ";
                 mOutput << face.mIndices[b] << " ";
+            }
         }
         }
         mOutput << "</p>" << endstr;
         mOutput << "</p>" << endstr;
         PopTag();
         PopTag();
@@ -1080,8 +1151,9 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
         mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
         mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
         PushTag();
         PushTag();
         mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << geometryId << "-vertices\" />" << endstr;
         mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << geometryId << "-vertices\" />" << endstr;
-        if (mesh->HasNormals())
+        if (mesh->HasNormals()) {
             mOutput << startstr << "<input offset=\"0\" semantic=\"NORMAL\" source=\"#" << geometryId << "-normals\" />" << endstr;
             mOutput << startstr << "<input offset=\"0\" semantic=\"NORMAL\" source=\"#" << geometryId << "-normals\" />" << endstr;
+        }
         for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
         for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
             if (mesh->HasTextureCoords(static_cast<unsigned int>(a)))
             if (mesh->HasTextureCoords(static_cast<unsigned int>(a)))
                 mOutput << startstr << "<input offset=\"0\" semantic=\"TEXCOORD\" source=\"#" << geometryId << "-tex" << a << "\" "
                 mOutput << startstr << "<input offset=\"0\" semantic=\"TEXCOORD\" source=\"#" << geometryId << "-tex" << a << "\" "
@@ -1106,8 +1178,9 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
         for (size_t a = 0; a < mesh->mNumFaces; ++a) {
         for (size_t a = 0; a < mesh->mNumFaces; ++a) {
             const aiFace &face = mesh->mFaces[a];
             const aiFace &face = mesh->mFaces[a];
             if (face.mNumIndices < 3) continue;
             if (face.mNumIndices < 3) continue;
-            for (size_t b = 0; b < face.mNumIndices; ++b)
+            for (size_t b = 0; b < face.mNumIndices; ++b) {
                 mOutput << face.mIndices[b] << " ";
                 mOutput << face.mIndices[b] << " ";
+            }
         }
         }
         mOutput << "</p>" << endstr;
         mOutput << "</p>" << endstr;
         PopTag();
         PopTag();
@@ -1126,13 +1199,27 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
 void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount) {
 void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount) {
     size_t floatsPerElement = 0;
     size_t floatsPerElement = 0;
     switch (pType) {
     switch (pType) {
-    case FloatType_Vector: floatsPerElement = 3; break;
-    case FloatType_TexCoord2: floatsPerElement = 2; break;
-    case FloatType_TexCoord3: floatsPerElement = 3; break;
-    case FloatType_Color: floatsPerElement = 3; break;
-    case FloatType_Mat4x4: floatsPerElement = 16; break;
-    case FloatType_Weight: floatsPerElement = 1; break;
-    case FloatType_Time: floatsPerElement = 1; break;
+    case FloatType_Vector: 
+        floatsPerElement = 3; 
+        break;
+    case FloatType_TexCoord2: 
+        floatsPerElement = 2; 
+        break;
+    case FloatType_TexCoord3: 
+        floatsPerElement = 3; 
+        break;
+    case FloatType_Color: 
+        floatsPerElement = 3; 
+        break;
+    case FloatType_Mat4x4: 
+        floatsPerElement = 16; 
+        break;
+    case FloatType_Weight: 
+        floatsPerElement = 1; 
+        break;
+    case FloatType_Time: 
+        floatsPerElement = 1; 
+        break;
     default:
     default:
         return;
         return;
     }
     }
@@ -1158,8 +1245,9 @@ void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataTyp
             mOutput << pData[a * 4 + 2] << " ";
             mOutput << pData[a * 4 + 2] << " ";
         }
         }
     } else {
     } else {
-        for (size_t a = 0; a < pElementCount * floatsPerElement; ++a)
+        for (size_t a = 0; a < pElementCount * floatsPerElement; ++a) {
             mOutput << pData[a] << " ";
             mOutput << pData[a] << " ";
+        }
     }
     }
     mOutput << "</float_array>" << endstr;
     mOutput << "</float_array>" << endstr;
     PopTag();
     PopTag();
@@ -1251,9 +1339,13 @@ void ColladaExporter::WriteSceneLibrary() {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ColladaExporter::WriteAnimationLibrary(size_t pIndex) {
 void ColladaExporter::WriteAnimationLibrary(size_t pIndex) {
     const aiAnimation *anim = mScene->mAnimations[pIndex];
     const aiAnimation *anim = mScene->mAnimations[pIndex];
-
-    if (anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels == 0)
+    if (anim == nullptr) {
+        return;
+    }
+    
+    if (anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels == 0) {
         return;
         return;
+    }
 
 
     const std::string animationNameEscaped = GetObjectName(AiObjectType::Animation, pIndex);
     const std::string animationNameEscaped = GetObjectName(AiObjectType::Animation, pIndex);
     const std::string idstrEscaped = GetObjectUniqueId(AiObjectType::Animation, pIndex);
     const std::string idstrEscaped = GetObjectUniqueId(AiObjectType::Animation, pIndex);
@@ -1264,8 +1356,11 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) {
     std::string cur_node_idstr;
     std::string cur_node_idstr;
     for (size_t a = 0; a < anim->mNumChannels; ++a) {
     for (size_t a = 0; a < anim->mNumChannels; ++a) {
         const aiNodeAnim *nodeAnim = anim->mChannels[a];
         const aiNodeAnim *nodeAnim = anim->mChannels[a];
+        if (nodeAnim == nullptr) {
+            continue;
+        }
 
 
-        // sanity check
+        // sanity checks
         if (nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys) {
         if (nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys) {
             continue;
             continue;
         }
         }
@@ -1364,6 +1459,9 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) {
 
 
     for (size_t a = 0; a < anim->mNumChannels; ++a) {
     for (size_t a = 0; a < anim->mNumChannels; ++a) {
         const aiNodeAnim *nodeAnim = anim->mChannels[a];
         const aiNodeAnim *nodeAnim = anim->mChannels[a];
+        if (nodeAnim == nullptr) {
+            continue;
+        }
 
 
         {
         {
             // samplers
             // samplers
@@ -1382,97 +1480,42 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) {
 
 
     for (size_t a = 0; a < anim->mNumChannels; ++a) {
     for (size_t a = 0; a < anim->mNumChannels; ++a) {
         const aiNodeAnim *nodeAnim = anim->mChannels[a];
         const aiNodeAnim *nodeAnim = anim->mChannels[a];
+        if (nodeAnim == nullptr) {
+            continue;
+        }
 
 
         {
         {
             // channels
             // channels
-            mOutput << startstr << "<channel source=\"#" << XMLIDEncode(nodeAnim->mNodeName.data + std::string("_matrix-sampler")) << "\" target=\"" << XMLIDEncode(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr;
+            mOutput << startstr 
+                    << "<channel source=\"#" 
+                    << XMLIDEncode(nodeAnim->mNodeName.data + std::string("_matrix-sampler")) 
+                    << "\" target=\"" 
+                    << XMLIDEncode(nodeAnim->mNodeName.data) 
+                    << "/matrix\"/>" 
+                    << endstr;
         }
         }
     }
     }
 
 
     PopTag();
     PopTag();
     mOutput << startstr << "</animation>" << endstr;
     mOutput << startstr << "</animation>" << endstr;
 }
 }
-// ------------------------------------------------------------------------------------------------
-void ColladaExporter::WriteAnimationsLibrary() {
-    if (mScene->mNumAnimations > 0) {
-        mOutput << startstr << "<library_animations>" << endstr;
-        PushTag();
-
-        // start recursive write at the root node
-        for (size_t a = 0; a < mScene->mNumAnimations; ++a)
-            WriteAnimationLibrary(a);
-
-        PopTag();
-        mOutput << startstr << "</library_animations>" << endstr;
-    }
-}
-// ------------------------------------------------------------------------------------------------
-// Helper to find a bone by name in the scene
-aiBone *findBone(const aiScene *scene, const aiString &name) {
-    for (size_t m = 0; m < scene->mNumMeshes; m++) {
-        aiMesh *mesh = scene->mMeshes[m];
-        for (size_t b = 0; b < mesh->mNumBones; b++) {
-            aiBone *bone = mesh->mBones[b];
-            if (name == bone->mName) {
-                return bone;
-            }
-        }
-    }
-    return nullptr;
-}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// Helper to find the node associated with a bone in the scene
-const aiNode *findBoneNode(const aiNode *aNode, const aiBone *bone) {
-    if (aNode && bone && aNode->mName == bone->mName) {
-        return aNode;
-    }
-
-    if (aNode && bone) {
-        for (unsigned int i = 0; i < aNode->mNumChildren; ++i) {
-            aiNode *aChild = aNode->mChildren[i];
-            const aiNode *foundFromChild = nullptr;
-            if (aChild) {
-                foundFromChild = findBoneNode(aChild, bone);
-                if (foundFromChild) {
-                    return foundFromChild;
-                }
-            }
-        }
-    }
-
-    return nullptr;
-}
-
-const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) {
-    std::set<const aiNode *> topParentBoneNodes;
-    if (mesh && mesh->mNumBones > 0) {
-        for (unsigned int i = 0; i < mesh->mNumBones; ++i) {
-            aiBone *bone = mesh->mBones[i];
-
-            const aiNode *node = findBoneNode(scene->mRootNode, bone);
-            if (node) {
-                while (node->mParent && findBone(scene, node->mParent->mName) != nullptr) {
-                    node = node->mParent;
-                }
-                topParentBoneNodes.insert(node);
-            }
-        }
+void ColladaExporter::WriteAnimationsLibrary() {
+    if (mScene->mNumAnimations == 0) {
+        return;
     }
     }
+    
+    mOutput << startstr << "<library_animations>" << endstr;
+    PushTag();
 
 
-    if (!topParentBoneNodes.empty()) {
-        const aiNode *parentBoneNode = *topParentBoneNodes.begin();
-        if (topParentBoneNodes.size() == 1) {
-            return parentBoneNode;
-        } else {
-            for (auto it : topParentBoneNodes) {
-                if (it->mParent) return it->mParent;
-            }
-            return parentBoneNode;
-        }
+    // start recursive write at the root node
+    for (size_t a = 0; a < mScene->mNumAnimations; ++a) {
+        WriteAnimationLibrary(a);
     }
     }
 
 
-    return nullptr;
+    PopTag();
+    mOutput << startstr << "</library_animations>" << endstr;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -1483,13 +1526,13 @@ void ColladaExporter::WriteNode(const aiNode *pNode) {
     // Assimp-specific: nodes with no name cannot be associated with bones
     // Assimp-specific: nodes with no name cannot be associated with bones
     const char *node_type;
     const char *node_type;
     bool is_joint, is_skeleton_root = false;
     bool is_joint, is_skeleton_root = false;
-    if (pNode->mName.length == 0 || nullptr == findBone(mScene, pNode->mName)) {
+    if (pNode->mName.length == 0 || nullptr == mScene->findBone(pNode->mName)) {
         node_type = "NODE";
         node_type = "NODE";
         is_joint = false;
         is_joint = false;
     } else {
     } else {
         node_type = "JOINT";
         node_type = "JOINT";
         is_joint = true;
         is_joint = true;
-        if (!pNode->mParent || nullptr == findBone(mScene, pNode->mParent->mName)) {
+        if (!pNode->mParent || nullptr == mScene->findBone(pNode->mParent->mName)) {
             is_skeleton_root = true;
             is_skeleton_root = true;
         }
         }
     }
     }
@@ -1527,7 +1570,6 @@ void ColladaExporter::WriteNode(const aiNode *pNode) {
     }
     }
 
 
     // customized, sid should be 'matrix' to match with loader code.
     // customized, sid should be 'matrix' to match with loader code.
-    //mOutput << startstr << "<matrix sid=\"transform\">";
     mOutput << startstr << "<matrix sid=\"matrix\">";
     mOutput << startstr << "<matrix sid=\"matrix\">";
 
 
     mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
     mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
@@ -1551,7 +1593,6 @@ void ColladaExporter::WriteNode(const aiNode *pNode) {
                 break;
                 break;
             }
             }
         }
         }
-
     } else
     } else
         // instance every geometry
         // instance every geometry
         for (size_t a = 0; a < pNode->mNumMeshes; ++a) {
         for (size_t a = 0; a < pNode->mNumMeshes; ++a) {
@@ -1607,8 +1648,9 @@ void ColladaExporter::WriteNode(const aiNode *pNode) {
         }
         }
 
 
     // recurse into subnodes
     // recurse into subnodes
-    for (size_t a = 0; a < pNode->mNumChildren; ++a)
+    for (size_t a = 0; a < pNode->mNumChildren; ++a) {
         WriteNode(pNode->mChildren[a]);
         WriteNode(pNode->mChildren[a]);
+    }
 
 
     PopTag();
     PopTag();
     mOutput << startstr << "</node>" << endstr;
     mOutput << startstr << "</node>" << endstr;
@@ -1623,8 +1665,9 @@ void ColladaExporter::CreateNodeIds(const aiNode *node) {
 std::string ColladaExporter::GetNodeUniqueId(const aiNode *node) {
 std::string ColladaExporter::GetNodeUniqueId(const aiNode *node) {
     // Use the pointer as the key. This is safe because the scene is immutable.
     // Use the pointer as the key. This is safe because the scene is immutable.
     auto idIt = mNodeIdMap.find(node);
     auto idIt = mNodeIdMap.find(node);
-    if (idIt != mNodeIdMap.cend())
+    if (idIt != mNodeIdMap.cend()) {
         return idIt->second;
         return idIt->second;
+    }
 
 
     // Prefer the requested Collada Id if extant
     // Prefer the requested Collada Id if extant
     std::string idStr;
     std::string idStr;
@@ -1635,36 +1678,42 @@ std::string ColladaExporter::GetNodeUniqueId(const aiNode *node) {
         idStr = node->mName.C_Str();
         idStr = node->mName.C_Str();
     }
     }
     // Make sure the requested id is valid
     // Make sure the requested id is valid
-    if (idStr.empty())
+    if (idStr.empty()) {
         idStr = "node";
         idStr = "node";
-    else
+    } else {
         idStr = XMLIDEncode(idStr);
         idStr = XMLIDEncode(idStr);
+    }
 
 
     // Ensure it's unique
     // Ensure it's unique
     idStr = MakeUniqueId(mUniqueIds, idStr, std::string());
     idStr = MakeUniqueId(mUniqueIds, idStr, std::string());
     mUniqueIds.insert(idStr);
     mUniqueIds.insert(idStr);
     mNodeIdMap.insert(std::make_pair(node, idStr));
     mNodeIdMap.insert(std::make_pair(node, idStr));
+    
     return idStr;
     return idStr;
 }
 }
 
 
 std::string ColladaExporter::GetNodeName(const aiNode *node) {
 std::string ColladaExporter::GetNodeName(const aiNode *node) {
-
+    if (node == nullptr) {
+        return std::string();
+    }
     return XMLEscape(node->mName.C_Str());
     return XMLEscape(node->mName.C_Str());
 }
 }
 
 
 std::string ColladaExporter::GetBoneUniqueId(const aiBone *bone) {
 std::string ColladaExporter::GetBoneUniqueId(const aiBone *bone) {
     // Find the Node that is this Bone
     // Find the Node that is this Bone
-    const aiNode *boneNode = findBoneNode(mScene->mRootNode, bone);
-    if (boneNode == nullptr)
+    const aiNode *boneNode = mScene->mRootNode->findBoneNode(bone);
+    if (boneNode == nullptr) {
         return std::string();
         return std::string();
+    }
 
 
     return GetNodeUniqueId(boneNode);
     return GetNodeUniqueId(boneNode);
 }
 }
 
 
 std::string ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex) {
 std::string ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex) {
     auto idIt = GetObjectIdMap(type).find(pIndex);
     auto idIt = GetObjectIdMap(type).find(pIndex);
-    if (idIt != GetObjectIdMap(type).cend())
+    if (idIt != GetObjectIdMap(type).cend()) {
         return idIt->second;
         return idIt->second;
+    }
 
 
     // Not seen this object before, create and add
     // Not seen this object before, create and add
     NameIdPair result = AddObjectIndexToMaps(type, pIndex);
     NameIdPair result = AddObjectIndexToMaps(type, pIndex);
@@ -1673,8 +1722,9 @@ std::string ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex)
 
 
 std::string ColladaExporter::GetObjectName(AiObjectType type, size_t pIndex) {
 std::string ColladaExporter::GetObjectName(AiObjectType type, size_t pIndex) {
     auto objectName = GetObjectNameMap(type).find(pIndex);
     auto objectName = GetObjectNameMap(type).find(pIndex);
-    if (objectName != GetObjectNameMap(type).cend())
+    if (objectName != GetObjectNameMap(type).cend()) {
         return objectName->second;
         return objectName->second;
+    }
 
 
     // Not seen this object before, create and add
     // Not seen this object before, create and add
     NameIdPair result = AddObjectIndexToMaps(type, pIndex);
     NameIdPair result = AddObjectIndexToMaps(type, pIndex);
@@ -1694,9 +1744,15 @@ ColladaExporter::NameIdPair ColladaExporter::AddObjectIndexToMaps(AiObjectType t
 
 
     // Get the name and id postfix
     // Get the name and id postfix
     switch (type) {
     switch (type) {
-    case AiObjectType::Mesh: name = mScene->mMeshes[index]->mName.C_Str(); break;
-    case AiObjectType::Material: name = mScene->mMaterials[index]->GetName().C_Str(); break;
-    case AiObjectType::Animation: name = mScene->mAnimations[index]->mName.C_Str(); break;
+    case AiObjectType::Mesh: 
+        name = mScene->mMeshes[index]->mName.C_Str(); 
+        break;
+    case AiObjectType::Material: 
+        name = mScene->mMaterials[index]->GetName().C_Str(); 
+        break;
+    case AiObjectType::Animation: 
+        name = mScene->mAnimations[index]->mName.C_Str(); 
+        break;
     case AiObjectType::Light:
     case AiObjectType::Light:
         name = mScene->mLights[index]->mName.C_Str();
         name = mScene->mLights[index]->mName.C_Str();
         idPostfix = "-light";
         idPostfix = "-light";
@@ -1705,7 +1761,8 @@ ColladaExporter::NameIdPair ColladaExporter::AddObjectIndexToMaps(AiObjectType t
         name = mScene->mCameras[index]->mName.C_Str();
         name = mScene->mCameras[index]->mName.C_Str();
         idPostfix = "-camera";
         idPostfix = "-camera";
         break;
         break;
-    case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type");
+    case AiObjectType::Count: 
+        throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type");
     }
     }
 
 
     if (name.empty()) {
     if (name.empty()) {
@@ -1723,8 +1780,9 @@ ColladaExporter::NameIdPair ColladaExporter::AddObjectIndexToMaps(AiObjectType t
         idStr = XMLIDEncode(name);
         idStr = XMLIDEncode(name);
     }
     }
 
 
-    if (!name.empty())
+    if (!name.empty()) {
         name = XMLEscape(name);
         name = XMLEscape(name);
+    }
 
 
     idStr = MakeUniqueId(mUniqueIds, idStr, idPostfix);
     idStr = MakeUniqueId(mUniqueIds, idStr, idPostfix);
 
 
@@ -1738,5 +1796,5 @@ ColladaExporter::NameIdPair ColladaExporter::AddObjectIndexToMaps(AiObjectType t
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp
 
 
-#endif
-#endif
+#endif // ASSIMP_BUILD_NO_COLLADA_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 0 - 1
code/AssetLib/Collada/ColladaExporter.h

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

+ 1 - 0
code/AssetLib/Collada/ColladaLoader.cpp

@@ -1077,6 +1077,7 @@ static float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key,
             return mKey.mWeight;
             return mKey.mWeight;
         }
         }
     }
     }
+    
     // no value at key found, try to interpolate if present at other keys. if not, return zero
     // no value at key found, try to interpolate if present at other keys. if not, return zero
     // TODO: interpolation
     // TODO: interpolation
     return 0.0f;
     return 0.0f;

+ 21 - 18
code/AssetLib/Collada/ColladaLoader.h

@@ -6,7 +6,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -77,8 +76,11 @@ struct ColladaMeshIndex {
     }
     }
 };
 };
 
 
-/** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing
- * more useless stuff, so I limited the data to what I think is useful for games.
+/** 
+ * @brief Loader class to read Collada scenes. 
+ *
+ * Collada is over-engineered to death, with every new iteration bringing  more useless stuff, 
+ * so I limited the data to what I think is useful for games.
 */
 */
 class ColladaLoader : public BaseImporter {
 class ColladaLoader : public BaseImporter {
 public:
 public:
@@ -102,50 +104,51 @@ protected:
     /// See #BaseImporter::InternReadFile for the details
     /// See #BaseImporter::InternReadFile for the details
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
 
 
-    /** Recursively constructs a scene node for the given parser node and returns it. */
+    /// Recursively constructs a scene node for the given parser node and returns it.
     aiNode *BuildHierarchy(const ColladaParser &pParser, const Collada::Node *pNode);
     aiNode *BuildHierarchy(const ColladaParser &pParser, const Collada::Node *pNode);
 
 
-    /** Resolve node instances */
+    /// Resolve node instances
     void ResolveNodeInstances(const ColladaParser &pParser, const Collada::Node *pNode,
     void ResolveNodeInstances(const ColladaParser &pParser, const Collada::Node *pNode,
             std::vector<const Collada::Node *> &resolved);
             std::vector<const Collada::Node *> &resolved);
 
 
-    /** Builds meshes for the given node and references them */
+    /// Builds meshes for the given node and references them 
     void BuildMeshesForNode(const ColladaParser &pParser, const Collada::Node *pNode,
     void BuildMeshesForNode(const ColladaParser &pParser, const Collada::Node *pNode,
             aiNode *pTarget);
             aiNode *pTarget);
 
 
+    /// Lookup for meshes by their name
     aiMesh *findMesh(const std::string &meshid);
     aiMesh *findMesh(const std::string &meshid);
 
 
-    /** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
+    /// Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
     aiMesh *CreateMesh(const ColladaParser &pParser, const Collada::Mesh *pSrcMesh, const Collada::SubMesh &pSubMesh,
     aiMesh *CreateMesh(const ColladaParser &pParser, const Collada::Mesh *pSrcMesh, const Collada::SubMesh &pSubMesh,
             const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace);
             const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace);
 
 
-    /** Builds cameras for the given node and references them */
+    /// Builds cameras for the given node and references them
     void BuildCamerasForNode(const ColladaParser &pParser, const Collada::Node *pNode,
     void BuildCamerasForNode(const ColladaParser &pParser, const Collada::Node *pNode,
             aiNode *pTarget);
             aiNode *pTarget);
 
 
-    /** Builds lights for the given node and references them */
+    /// Builds lights for the given node and references them
     void BuildLightsForNode(const ColladaParser &pParser, const Collada::Node *pNode,
     void BuildLightsForNode(const ColladaParser &pParser, const Collada::Node *pNode,
             aiNode *pTarget);
             aiNode *pTarget);
 
 
-    /** Stores all meshes in the given scene */
+    /// Stores all meshes in the given scene
     void StoreSceneMeshes(aiScene *pScene);
     void StoreSceneMeshes(aiScene *pScene);
 
 
-    /** Stores all materials in the given scene */
+    /// Stores all materials in the given scene
     void StoreSceneMaterials(aiScene *pScene);
     void StoreSceneMaterials(aiScene *pScene);
 
 
-    /** Stores all lights in the given scene */
+    /// Stores all lights in the given scene
     void StoreSceneLights(aiScene *pScene);
     void StoreSceneLights(aiScene *pScene);
 
 
-    /** Stores all cameras in the given scene */
+    /// Stores all cameras in the given scene
     void StoreSceneCameras(aiScene *pScene);
     void StoreSceneCameras(aiScene *pScene);
 
 
-    /** Stores all textures in the given scene */
+    /// Stores all textures in the given scene
     void StoreSceneTextures(aiScene *pScene);
     void StoreSceneTextures(aiScene *pScene);
 
 
-    /** Stores all animations
-     * @param pScene target scene to store the anims
-     */
-    void StoreAnimations(aiScene *pScene, const ColladaParser &pParser);
+    /// Stores all animations
+    /// @param pScene   Target scene to store the anims
+    /// @param parser   The collada parser
+    void StoreAnimations(aiScene *pScene, const ColladaParser &parser);
 
 
     /** Stores all animations for the given source anim and its nested child animations
     /** Stores all animations for the given source anim and its nested child animations
      * @param pScene target scene to store the anims
      * @param pScene target scene to store the anims

+ 8 - 19
code/AssetLib/DXF/DXFHelper.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -62,10 +61,7 @@ namespace DXF {
 // do NOT skip empty lines. In DXF files, they count as valid data.
 // do NOT skip empty lines. In DXF files, they count as valid data.
 class LineReader {
 class LineReader {
 public:
 public:
-    LineReader(StreamReaderLE& reader)
-    : splitter(reader,false,true)
-    , groupcode( 0 )
-    , end() {
+    LineReader(StreamReaderLE& reader) : splitter(reader,false,true), groupcode( 0 ), end() {
         // empty
         // empty
     }
     }
 
 
@@ -165,8 +161,7 @@ private:
 
 
 // represents a POLYLINE or a LWPOLYLINE. or even a 3DFACE The data is converted as needed.
 // represents a POLYLINE or a LWPOLYLINE. or even a 3DFACE The data is converted as needed.
 struct PolyLine {
 struct PolyLine {
-    PolyLine()
-    : flags() {
+    PolyLine() : flags() {
         // empty
         // empty
     }
     }
 
 
@@ -182,10 +177,7 @@ struct PolyLine {
 
 
 // reference to a BLOCK. Specifies its own coordinate system.
 // reference to a BLOCK. Specifies its own coordinate system.
 struct InsertBlock {
 struct InsertBlock {
-    InsertBlock()
-    : pos()
-    , scale(1.f,1.f,1.f)
-    , angle() {
+    InsertBlock() : pos(0.f, 0.f, 0.f), scale(1.f,1.f,1.f), angle(0.0f) {
         // empty
         // empty
     }
     }
 
 
@@ -198,8 +190,7 @@ struct InsertBlock {
 
 
 
 
 // keeps track of all geometry in a single BLOCK.
 // keeps track of all geometry in a single BLOCK.
-struct Block
-{
+struct Block {
     std::vector< std::shared_ptr<PolyLine> > lines;
     std::vector< std::shared_ptr<PolyLine> > lines;
     std::vector<InsertBlock> insertions;
     std::vector<InsertBlock> insertions;
 
 
@@ -207,14 +198,12 @@ struct Block
     aiVector3D base;
     aiVector3D base;
 };
 };
 
 
-
-struct FileData
-{
+struct FileData {
     // note: the LAST block always contains the stuff from ENTITIES.
     // note: the LAST block always contains the stuff from ENTITIES.
     std::vector<Block> blocks;
     std::vector<Block> blocks;
 };
 };
 
 
-}
-} // Namespace Assimp
+} // namespace DXF
+} // namespace Assimp
 
 
-#endif
+#endif // INCLUDED_DXFHELPER_H

+ 22 - 20
code/AssetLib/FBX/FBXAnimation.cpp

@@ -143,31 +143,33 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, cons
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 const AnimationCurveMap &AnimationCurveNode::Curves() const {
 const AnimationCurveMap &AnimationCurveNode::Curves() const {
-    if (curves.empty()) {
-        // resolve attached animation curves
-        const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
-
-        for (const Connection *con : conns) {
+    if (!curves.empty()) {
+        return curves;
+    }
+        
+    // resolve attached animation curves
+    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
 
 
-            // link should go for a property
-            if (!con->PropertyName().length()) {
-                continue;
-            }
+    for (const Connection *con : conns) {
 
 
-            const Object *const ob = con->SourceObject();
-            if (nullptr == ob) {
-                DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring", &element);
-                continue;
-            }
+        // link should go for a property
+        if (!con->PropertyName().length()) {
+            continue;
+        }
 
 
-            const AnimationCurve *const anim = dynamic_cast<const AnimationCurve *>(ob);
-            if (nullptr == anim) {
-                DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element);
-                continue;
-            }
+        const Object *const ob = con->SourceObject();
+        if (nullptr == ob) {
+            DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring", &element);
+            continue;
+        }
 
 
-            curves[con->PropertyName()] = anim;
+        const AnimationCurve *const anim = dynamic_cast<const AnimationCurve *>(ob);
+        if (nullptr == anim) {
+            DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element);
+            continue;
         }
         }
+
+        curves[con->PropertyName()] = anim;
     }
     }
 
 
     return curves;
     return curves;

+ 9 - 52
code/AssetLib/FBX/FBXBinaryTokenizer.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -60,58 +59,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {
 
 
-//enum Flag
-//{
-//   e_unknown_0 = 1 << 0,
-//   e_unknown_1 = 1 << 1,
-//   e_unknown_2 = 1 << 2,
-//   e_unknown_3 = 1 << 3,
-//   e_unknown_4 = 1 << 4,
-//   e_unknown_5 = 1 << 5,
-//   e_unknown_6 = 1 << 6,
-//   e_unknown_7 = 1 << 7,
-//   e_unknown_8 = 1 << 8,
-//   e_unknown_9 = 1 << 9,
-//   e_unknown_10 = 1 << 10,
-//   e_unknown_11 = 1 << 11,
-//   e_unknown_12 = 1 << 12,
-//   e_unknown_13 = 1 << 13,
-//   e_unknown_14 = 1 << 14,
-//   e_unknown_15 = 1 << 15,
-//   e_unknown_16 = 1 << 16,
-//   e_unknown_17 = 1 << 17,
-//   e_unknown_18 = 1 << 18,
-//   e_unknown_19 = 1 << 19,
-//   e_unknown_20 = 1 << 20,
-//   e_unknown_21 = 1 << 21,
-//   e_unknown_22 = 1 << 22,
-//   e_unknown_23 = 1 << 23,
-//   e_flag_field_size_64_bit = 1 << 24, // Not sure what is
-//   e_unknown_25 = 1 << 25,
-//   e_unknown_26 = 1 << 26,
-//   e_unknown_27 = 1 << 27,
-//   e_unknown_28 = 1 << 28,
-//   e_unknown_29 = 1 << 29,
-//   e_unknown_30 = 1 << 30,
-//   e_unknown_31 = 1 << 31
-//};
-//
-//bool check_flag(uint32_t flags, Flag to_check)
-//{
-//	return (flags & to_check) != 0;
-//}
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset)
-    :
-    #ifdef DEBUG
-    contents(sbegin, static_cast<size_t>(send-sbegin)),
-    #endif
-    sbegin(sbegin)
-    , send(send)
-    , type(type)
-    , line(offset)
-    , column(BINARY_MARKER)
-{
+Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset) :
+        #ifdef DEBUG
+        contents(sbegin, static_cast<size_t>(send-sbegin)),
+        #endif
+        sbegin(sbegin),
+        send(send),
+        type(type),
+        line(offset),
+        column(BINARY_MARKER) {
     ai_assert(sbegin);
     ai_assert(sbegin);
     ai_assert(send);
     ai_assert(send);
 
 

+ 2 - 1
code/AssetLib/FBX/FBXCommon.h

@@ -51,7 +51,8 @@ namespace Assimp {
 namespace FBX {
 namespace FBX {
 
 
 static constexpr size_t NumNullRecords = 25;
 static constexpr size_t NumNullRecords = 25;
-const char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
+
+constexpr char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
     '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
     '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
     '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
     '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
 }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)
 }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)

+ 7 - 7
code/AssetLib/FBX/FBXConverter.cpp

@@ -438,7 +438,8 @@ void FBXConverter::ConvertLight(const Light &light, const std::string &orig_name
             out_light->mType = aiLightSource_UNDEFINED;
             out_light->mType = aiLightSource_UNDEFINED;
             break;
             break;
         default:
         default:
-            ai_assert(false);
+            FBXImporter::LogError("Not handled light type: ", light.LightType());
+            break;
     }
     }
 
 
     float decay = light.DecayStart();
     float decay = light.DecayStart();
@@ -463,7 +464,7 @@ void FBXConverter::ConvertLight(const Light &light, const std::string &orig_name
             out_light->mAttenuationQuadratic = 1.0f;
             out_light->mAttenuationQuadratic = 1.0f;
             break;
             break;
         default:
         default:
-            ai_assert(false);
+            FBXImporter::LogError("Not handled light decay type: ", light.DecayType());
             break;
             break;
     }
     }
 }
 }
@@ -601,7 +602,7 @@ const char *FBXConverter::NameTransformationCompProperty(TransformationComp comp
             return "GeometricRotationInverse";
             return "GeometricRotationInverse";
         case TransformationComp_GeometricTranslationInverse:
         case TransformationComp_GeometricTranslationInverse:
             return "GeometricTranslationInverse";
             return "GeometricTranslationInverse";
-        case TransformationComp_MAXIMUM: // this is to silence compiler warnings
+        case TransformationComp_MAXIMUM:
             break;
             break;
     }
     }
 
 
@@ -3415,7 +3416,7 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std::
     KeyFrameListList inputs;
     KeyFrameListList inputs;
     inputs.reserve(nodes.size() * 3);
     inputs.reserve(nodes.size() * 3);
 
 
-    //give some breathing room for rounding errors
+    // give some breathing room for rounding errors
     const int64_t adj_start = start - 10000;
     const int64_t adj_start = start - 10000;
     const int64_t adj_stop = stop + 10000;
     const int64_t adj_stop = stop + 10000;
 
 
@@ -3441,7 +3442,7 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std::
             ai_assert(curve->GetKeys().size() == curve->GetValues().size());
             ai_assert(curve->GetKeys().size() == curve->GetValues().size());
             ai_assert(curve->GetKeys().size());
             ai_assert(curve->GetKeys().size());
 
 
-            //get values within the start/stop time window
+            // get values within the start/stop time window
             std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
             std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
             std::shared_ptr<KeyValueList> Values(new KeyValueList());
             std::shared_ptr<KeyValueList> Values(new KeyValueList());
             const size_t count = curve->GetKeys().size();
             const size_t count = curve->GetKeys().size();
@@ -3461,8 +3462,7 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std::
                         if (tnew >= adj_start && tnew <= adj_stop) {
                         if (tnew >= adj_start && tnew <= adj_stop) {
                             Keys->push_back(tnew);
                             Keys->push_back(tnew);
                             Values->push_back(vnew);
                             Values->push_back(vnew);
-                        }
-                        else {
+                        } else {
                             // Something broke
                             // Something broke
                             break;
                             break;
                         }
                         }

+ 1 - 2
code/AssetLib/FBX/FBXConverter.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -70,7 +69,7 @@ struct morphKeyData {
     std::vector<unsigned int> values;
     std::vector<unsigned int> values;
     std::vector<float> weights;
     std::vector<float> weights;
 };
 };
-typedef std::map<int64_t, morphKeyData*> morphAnimData;
+using morphAnimData = std::map<int64_t, morphKeyData*> ;
 
 
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {

+ 5 - 18
code/AssetLib/FBX/FBXDeformer.cpp

@@ -65,9 +65,6 @@ Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, con
     props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
     props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-Deformer::~Deformer() = default;
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 : Deformer(id,element,doc,name)
 : Deformer(id,element,doc,name)
@@ -113,10 +110,6 @@ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const
     }
     }
 }
 }
 
 
-
-// ------------------------------------------------------------------------------------------------
-Cluster::~Cluster() = default;
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 : Deformer(id,element,doc,name)
 : Deformer(id,element,doc,name)
@@ -142,9 +135,6 @@ Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::
     }
     }
 }
 }
 
 
-
-// ------------------------------------------------------------------------------------------------
-Skin::~Skin() = default;
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name)
     : Deformer(id, element, doc, name)
     : Deformer(id, element, doc, name)
@@ -161,8 +151,7 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc,
         }
         }
     }
     }
 }
 }
-// ------------------------------------------------------------------------------------------------
-BlendShape::~BlendShape() = default;
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name)
     : Deformer(id, element, doc, name)
     : Deformer(id, element, doc, name)
@@ -188,10 +177,8 @@ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const
         }
         }
     }
     }
 }
 }
-// ------------------------------------------------------------------------------------------------
-BlendShapeChannel::~BlendShapeChannel() = default;
-// ------------------------------------------------------------------------------------------------
-}
-}
-#endif
 
 
+} // namespace FBX
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_FBX_IMPORTER

+ 8 - 0
code/AssetLib/FBX/FBXDocument.cpp

@@ -663,6 +663,10 @@ LazyObject& Connection::LazyDestinationObject() const {
 const Object* Connection::SourceObject() const {
 const Object* Connection::SourceObject() const {
     LazyObject* const lazy = doc.GetObject(src);
     LazyObject* const lazy = doc.GetObject(src);
     ai_assert(lazy);
     ai_assert(lazy);
+    if (lazy == nullptr) {
+        return nullptr;
+    }
+
     return lazy->Get();
     return lazy->Get();
 }
 }
 
 
@@ -670,6 +674,10 @@ const Object* Connection::SourceObject() const {
 const Object* Connection::DestinationObject() const {
 const Object* Connection::DestinationObject() const {
     LazyObject* const lazy = doc.GetObject(dest);
     LazyObject* const lazy = doc.GetObject(dest);
     ai_assert(lazy);
     ai_assert(lazy);
+    if (lazy == nullptr) {
+        return nullptr;
+    }
+
     return lazy->Get();
     return lazy->Get();
 }
 }
 
 

+ 7 - 7
code/AssetLib/FBX/FBXDocument.h

@@ -657,11 +657,11 @@ private:
 };
 };
 
 
 /** DOM class for generic FBX materials */
 /** DOM class for generic FBX materials */
-class Material : public Object {
+class Material final : public Object {
 public:
 public:
     Material(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     Material(uint64_t id, const Element& element, const Document& doc, const std::string& name);
 
 
-    virtual ~Material();
+    ~Material() override = default;
 
 
     const std::string& GetShadingModel() const {
     const std::string& GetShadingModel() const {
         return shading;
         return shading;
@@ -835,7 +835,7 @@ private:
 class Deformer : public Object {
 class Deformer : public Object {
 public:
 public:
     Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-    virtual ~Deformer();
+    virtual ~Deformer() = default;
 
 
     const PropertyTable& Props() const {
     const PropertyTable& Props() const {
         ai_assert(props.get());
         ai_assert(props.get());
@@ -855,7 +855,7 @@ class BlendShapeChannel : public Deformer {
 public:
 public:
     BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name);
 
 
-    virtual ~BlendShapeChannel();
+    virtual ~BlendShapeChannel() = default;
 
 
     float DeformPercent() const {
     float DeformPercent() const {
         return percent;
         return percent;
@@ -880,7 +880,7 @@ class BlendShape : public Deformer {
 public:
 public:
     BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name);
 
 
-    virtual ~BlendShape();
+    virtual ~BlendShape() = default;
 
 
     const std::unordered_set<const BlendShapeChannel*>& BlendShapeChannels() const {
     const std::unordered_set<const BlendShapeChannel*>& BlendShapeChannels() const {
         return blendShapeChannels;
         return blendShapeChannels;
@@ -895,7 +895,7 @@ class Cluster : public Deformer {
 public:
 public:
     Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name);
 
 
-    virtual ~Cluster();
+    virtual ~Cluster() = default;
 
 
     /** get the list of deformer weights associated with this cluster.
     /** get the list of deformer weights associated with this cluster.
      *  Use #GetIndices() to get the associated vertices. Both arrays
      *  Use #GetIndices() to get the associated vertices. Both arrays
@@ -939,7 +939,7 @@ class Skin : public Deformer {
 public:
 public:
     Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name);
 
 
-    virtual ~Skin();
+    virtual ~Skin() = default;
 
 
     float DeformAccuracy() const {
     float DeformAccuracy() const {
         return accuracy;
         return accuracy;

+ 10 - 15
code/AssetLib/FBX/FBXDocumentUtil.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -36,7 +35,6 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
@@ -81,8 +79,7 @@ void DOMWarning(const std::string& message, const Token& token) {
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void DOMWarning(const std::string& message, const Element* element /*= nullptr*/)
-{
+void DOMWarning(const std::string& message, const Element* element /*= nullptr*/) {
     if(element) {
     if(element) {
         DOMWarning(message,element->KeyToken());
         DOMWarning(message,element->KeyToken());
         return;
         return;
@@ -92,41 +89,39 @@ void DOMWarning(const std::string& message, const Element* element /*= nullptr*/
     }
     }
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // fetch a property table and the corresponding property template
 // fetch a property table and the corresponding property template
 std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
 std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
-    const std::string& templateName,
-    const Element &element,
-    const Scope& sc,
-    bool no_warn /*= false*/)
-{
+        const std::string& templateName,
+        const Element &element,
+        const Scope& sc,
+        bool no_warn /*= false*/) {
     const Element* const Properties70 = sc["Properties70"];
     const Element* const Properties70 = sc["Properties70"];
     std::shared_ptr<const PropertyTable> templateProps = std::shared_ptr<const PropertyTable>(
     std::shared_ptr<const PropertyTable> templateProps = std::shared_ptr<const PropertyTable>(
             static_cast<const PropertyTable *>(nullptr));
             static_cast<const PropertyTable *>(nullptr));
 
 
-    if(templateName.length()) {
+    if (templateName.length()) {
         PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
         PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
         if(it != doc.Templates().end()) {
         if(it != doc.Templates().end()) {
             templateProps = (*it).second;
             templateProps = (*it).second;
         }
         }
     }
     }
 
 
-    if(!Properties70 || !Properties70->Compound()) {
+    if (!Properties70 || !Properties70->Compound()) {
         if(!no_warn) {
         if(!no_warn) {
             DOMWarning("property table (Properties70) not found",&element);
             DOMWarning("property table (Properties70) not found",&element);
         }
         }
         if(templateProps) {
         if(templateProps) {
             return templateProps;
             return templateProps;
-        }
-        else {
+        } else {
             return std::make_shared<const PropertyTable>();
             return std::make_shared<const PropertyTable>();
         }
         }
     }
     }
     return std::make_shared<const PropertyTable>(*Properties70,templateProps);
     return std::make_shared<const PropertyTable>(*Properties70,templateProps);
 }
 }
+
 } // !Util
 } // !Util
 } // !FBX
 } // !FBX
 } // !Assimp
 } // !Assimp
 
 
-#endif
+#endif // ASSIMP_BUILD_NO_FBX_IMPORTER

+ 1 - 1
code/AssetLib/FBX/FBXDocumentUtil.h

@@ -114,4 +114,4 @@ inline const T* ProcessSimpleConnection(const Connection& con,
 } //!FBX
 } //!FBX
 } //!Assimp
 } //!Assimp
 
 
-#endif
+#endif // ASSIMP_BUILD_NO_FBX_IMPORTER

+ 13 - 20
code/AssetLib/FBX/FBXExportNode.cpp

@@ -35,7 +35,6 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_EXPORT
@@ -55,37 +54,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory> // shared_ptr
 #include <memory> // shared_ptr
 
 
 namespace Assimp {
 namespace Assimp {
+
 // AddP70<type> helpers... there's no usable pattern here,
 // AddP70<type> helpers... there's no usable pattern here,
 // so all are defined as separate functions.
 // so all are defined as separate functions.
 // Even "animatable" properties are often completely different
 // Even "animatable" properties are often completely different
 // from the standard (nonanimated) property definition,
 // from the standard (nonanimated) property definition,
 // so they are specified with an 'A' suffix.
 // so they are specified with an 'A' suffix.
 
 
-void FBX::Node::AddP70int(
-    const std::string& cur_name, int32_t value
-) {
+void FBX::Node::AddP70int(const std::string& cur_name, int32_t value) {
     FBX::Node n("P");
     FBX::Node n("P");
     n.AddProperties(cur_name, "int", "Integer", "", value);
     n.AddProperties(cur_name, "int", "Integer", "", value);
     AddChild(n);
     AddChild(n);
 }
 }
 
 
-void FBX::Node::AddP70bool(
-    const std::string& cur_name, bool value
-) {
+void FBX::Node::AddP70bool(const std::string& cur_name, bool value) {
     FBX::Node n("P");
     FBX::Node n("P");
     n.AddProperties(cur_name, "bool", "", "", int32_t(value));
     n.AddProperties(cur_name, "bool", "", "", int32_t(value));
     AddChild(n);
     AddChild(n);
 }
 }
 
 
-void FBX::Node::AddP70double(
-        const std::string &cur_name, double value) {
-    FBX::Node n("P");
+void FBX::Node::AddP70double(const std::string &cur_name, double value) {    FBX::Node n("P");
     n.AddProperties(cur_name, "double", "Number", "", value);
     n.AddProperties(cur_name, "double", "Number", "", value);
     AddChild(n);
     AddChild(n);
 }
 }
 
 
-void FBX::Node::AddP70numberA(
-        const std::string &cur_name, double value) {
+void FBX::Node::AddP70numberA(const std::string &cur_name, double value) {
     FBX::Node n("P");
     FBX::Node n("P");
     n.AddProperties(cur_name, "Number", "", "A", value);
     n.AddProperties(cur_name, "Number", "", "A", value);
     AddChild(n);
     AddChild(n);
@@ -405,8 +398,7 @@ void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent)
     }
     }
 }
 }
 
 
-void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children)
-{
+void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children) {
     if (!has_children) { return; } // nothing to do
     if (!has_children) { return; } // nothing to do
     s << '\n';
     s << '\n';
     for (int i = 0; i < indent; ++i) { s << '\t'; }
     for (int i = 0; i < indent; ++i) { s << '\t'; }
@@ -417,11 +409,10 @@ void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children)
 
 
 // ascii property node from vector of doubles
 // ascii property node from vector of doubles
 void FBX::Node::WritePropertyNodeAscii(
 void FBX::Node::WritePropertyNodeAscii(
-    const std::string& name,
-    const std::vector<double>& v,
-    Assimp::StreamWriterLE& s,
-    int indent
-){
+        const std::string& name,
+        const std::vector<double>& v,
+        Assimp::StreamWriterLE& s,
+        int indent){
     char buffer[32];
     char buffer[32];
     FBX::Node node(name);
     FBX::Node node(name);
     node.Begin(s, false, indent);
     node.Begin(s, false, indent);
@@ -556,6 +547,8 @@ void FBX::Node::WritePropertyNode(
         FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
         FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
     }
     }
 }
 }
-}
+
+} // namespace Assimp
+
 #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 #endif // ASSIMP_BUILD_NO_EXPORT
 #endif // ASSIMP_BUILD_NO_EXPORT

+ 26 - 35
code/AssetLib/FBX/FBXExportNode.h

@@ -35,7 +35,6 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
@@ -70,7 +69,6 @@ public:
     // some nodes always pretend they have children...
     // some nodes always pretend they have children...
     bool force_has_children = false;
     bool force_has_children = false;
 
 
-public: // constructors
     /// The default class constructor.
     /// The default class constructor.
     Node() = default;
     Node() = default;
 
 
@@ -89,7 +87,6 @@ public: // constructors
         AddProperties(std::forward<More>(more)...);
         AddProperties(std::forward<More>(more)...);
     }
     }
 
 
-public: // functions to add properties or children
     // add a single property to the node
     // add a single property to the node
     template <typename T>
     template <typename T>
     void AddProperty(T&& value) {
     void AddProperty(T&& value) {
@@ -118,8 +115,6 @@ public: // functions to add properties or children
         children.push_back(std::move(c));
         children.push_back(std::move(c));
     }
     }
 
 
-public: // support specifically for dealing with Properties70 nodes
-
     // it really is simpler to make these all separate functions.
     // it really is simpler to make these all separate functions.
     // the versions with 'A' suffixes are for animatable properties.
     // the versions with 'A' suffixes are for animatable properties.
     // those often follow a completely different format internally in FBX.
     // those often follow a completely different format internally in FBX.
@@ -150,8 +145,6 @@ public: // support specifically for dealing with Properties70 nodes
         AddChild(n);
         AddChild(n);
     }
     }
 
 
-public: // member functions for writing data to a file or stream
-
     // write the full node to the given file or stream
     // write the full node to the given file or stream
     void Dump(
     void Dump(
             const std::shared_ptr<Assimp::IOStream> &outfile,
             const std::shared_ptr<Assimp::IOStream> &outfile,
@@ -175,31 +168,6 @@ public: // member functions for writing data to a file or stream
         bool has_children
         bool has_children
     );
     );
 
 
-private: // internal functions used for writing
-
-    void DumpBinary(Assimp::StreamWriterLE &s);
-    void DumpAscii(Assimp::StreamWriterLE &s, int indent);
-    void DumpAscii(std::ostream &s, int indent);
-
-    void BeginBinary(Assimp::StreamWriterLE &s);
-    void DumpPropertiesBinary(Assimp::StreamWriterLE& s);
-    void EndPropertiesBinary(Assimp::StreamWriterLE &s);
-    void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties);
-    void DumpChildrenBinary(Assimp::StreamWriterLE& s);
-    void EndBinary(Assimp::StreamWriterLE &s, bool has_children);
-
-    void BeginAscii(std::ostream &s, int indent);
-    void DumpPropertiesAscii(std::ostream &s, int indent);
-    void BeginChildrenAscii(std::ostream &s, int indent);
-    void DumpChildrenAscii(std::ostream &s, int indent);
-    void EndAscii(std::ostream &s, int indent, bool has_children);
-
-private: // data used for binary dumps
-    size_t start_pos; // starting position in stream
-    size_t end_pos; // ending position in stream
-    size_t property_start; // starting position of property section
-
-public: // static member functions
 
 
     // convenience function to create a node with a single property,
     // convenience function to create a node with a single property,
     // and write it to the stream.
     // and write it to the stream.
@@ -235,7 +203,26 @@ public: // static member functions
         bool binary, int indent
         bool binary, int indent
     );
     );
 
 
-private: // static helper functions
+private: // internal functions used for writing
+
+    void DumpBinary(Assimp::StreamWriterLE &s);
+    void DumpAscii(Assimp::StreamWriterLE &s, int indent);
+    void DumpAscii(std::ostream &s, int indent);
+
+    void BeginBinary(Assimp::StreamWriterLE &s);
+    void DumpPropertiesBinary(Assimp::StreamWriterLE& s);
+    void EndPropertiesBinary(Assimp::StreamWriterLE &s);
+    void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties);
+    void DumpChildrenBinary(Assimp::StreamWriterLE& s);
+    void EndBinary(Assimp::StreamWriterLE &s, bool has_children);
+
+    void BeginAscii(std::ostream &s, int indent);
+    void DumpPropertiesAscii(std::ostream &s, int indent);
+    void BeginChildrenAscii(std::ostream &s, int indent);
+    void DumpChildrenAscii(std::ostream &s, int indent);
+    void EndAscii(std::ostream &s, int indent, bool has_children);
+    
+    // static helper functions
     static void WritePropertyNodeAscii(
     static void WritePropertyNodeAscii(
         const std::string& name,
         const std::string& name,
         const std::vector<double>& v,
         const std::vector<double>& v,
@@ -259,9 +246,13 @@ private: // static helper functions
         Assimp::StreamWriterLE& s
         Assimp::StreamWriterLE& s
     );
     );
 
 
+private: // data used for binary dumps
+    size_t start_pos; // starting position in stream
+    size_t end_pos; // ending position in stream
+    size_t property_start; // starting position of property section
 };
 };
-}
 
 
-#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
+} // Namespace Assimp
 
 
+#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 #endif // AI_FBXEXPORTNODE_H_INC
 #endif // AI_FBXEXPORTNODE_H_INC

+ 14 - 36
code/AssetLib/FBX/FBXExporter.cpp

@@ -370,12 +370,6 @@ void FBXExporter::WriteHeaderExtension ()
         "Creator", creator.str(), outstream, binary, indent
         "Creator", creator.str(), outstream, binary, indent
     );
     );
 
 
-    //FBX::Node sceneinfo("SceneInfo");
-    //sceneinfo.AddProperty("GlobalInfo" + FBX::SEPARATOR + "SceneInfo");
-    // not sure if any of this is actually needed,
-    // so just write an empty node for now.
-    //sceneinfo.Dump(outstream, binary, indent);
-
     indent = 0;
     indent = 0;
 
 
     // finish node
     // finish node
@@ -459,11 +453,7 @@ void WritePropString(const aiScene* scene, FBX::Node& p, const std::string& key,
     }
     }
 }
 }
 
 
-void FBXExporter::WriteGlobalSettings ()
-{
-    if (!binary) {
-        // no title, follows directly from the header extension
-    }
+void FBXExporter::WriteGlobalSettings () {
     FBX::Node gs("GlobalSettings");
     FBX::Node gs("GlobalSettings");
     gs.AddChild("Version", int32_t(1000));
     gs.AddChild("Version", int32_t(1000));
 
 
@@ -493,8 +483,7 @@ void FBXExporter::WriteGlobalSettings ()
     gs.Dump(outfile, binary, 0);
     gs.Dump(outfile, binary, 0);
 }
 }
 
 
-void FBXExporter::WriteDocuments ()
-{
+void FBXExporter::WriteDocuments() {
     if (!binary) {
     if (!binary) {
         WriteAsciiSectionHeader("Documents Description");
         WriteAsciiSectionHeader("Documents Description");
     }
     }
@@ -523,8 +512,7 @@ void FBXExporter::WriteDocuments ()
     docs.Dump(outfile, binary, 0);
     docs.Dump(outfile, binary, 0);
 }
 }
 
 
-void FBXExporter::WriteReferences ()
-{
+void FBXExporter::WriteReferences() {
     if (!binary) {
     if (!binary) {
         WriteAsciiSectionHeader("Document References");
         WriteAsciiSectionHeader("Document References");
     }
     }
@@ -540,7 +528,6 @@ void FBXExporter::WriteReferences ()
 // some internal helper functions used for writing the definitions
 // some internal helper functions used for writing the definitions
 // (before any actual data is written)
 // (before any actual data is written)
 // ---------------------------------------------------------------
 // ---------------------------------------------------------------
-
 size_t count_nodes(const aiNode* n, const aiNode* root) {
 size_t count_nodes(const aiNode* n, const aiNode* root) {
     size_t count;
     size_t count;
     if (n == root) {
     if (n == root) {
@@ -556,8 +543,7 @@ size_t count_nodes(const aiNode* n, const aiNode* root) {
     return count;
     return count;
 }
 }
 
 
-bool has_phong_mat(const aiScene* scene)
-{
+static bool has_phong_mat(const aiScene* scene) {
     // just search for any material with a shininess exponent
     // just search for any material with a shininess exponent
     for (size_t i = 0; i < scene->mNumMaterials; ++i) {
     for (size_t i = 0; i < scene->mNumMaterials; ++i) {
         aiMaterial* mat = scene->mMaterials[i];
         aiMaterial* mat = scene->mMaterials[i];
@@ -570,16 +556,12 @@ bool has_phong_mat(const aiScene* scene)
     return false;
     return false;
 }
 }
 
 
-size_t count_images(const aiScene* scene) {
+static size_t count_images(const aiScene* scene) {
     std::unordered_set<std::string> images;
     std::unordered_set<std::string> images;
     aiString texpath;
     aiString texpath;
     for (size_t i = 0; i < scene->mNumMaterials; ++i) {
     for (size_t i = 0; i < scene->mNumMaterials; ++i) {
-        aiMaterial* mat = scene->mMaterials[i];
-        for (
-            size_t tt = aiTextureType_DIFFUSE;
-            tt < aiTextureType_UNKNOWN;
-            ++tt
-        ){
+        aiMaterial *mat = scene->mMaterials[i];
+        for (size_t tt = aiTextureType_DIFFUSE; tt < aiTextureType_UNKNOWN; ++tt) {
             const aiTextureType textype = static_cast<aiTextureType>(tt);
             const aiTextureType textype = static_cast<aiTextureType>(tt);
             const size_t texcount = mat->GetTextureCount(textype);
             const size_t texcount = mat->GetTextureCount(textype);
             for (unsigned int j = 0; j < texcount; ++j) {
             for (unsigned int j = 0; j < texcount; ++j) {
@@ -588,10 +570,11 @@ size_t count_images(const aiScene* scene) {
             }
             }
         }
         }
     }
     }
+
     return images.size();
     return images.size();
 }
 }
 
 
-size_t count_textures(const aiScene* scene) {
+static size_t count_textures(const aiScene* scene) {
     size_t count = 0;
     size_t count = 0;
     for (size_t i = 0; i < scene->mNumMaterials; ++i) {
     for (size_t i = 0; i < scene->mNumMaterials; ++i) {
         aiMaterial* mat = scene->mMaterials[i];
         aiMaterial* mat = scene->mMaterials[i];
@@ -609,7 +592,7 @@ size_t count_textures(const aiScene* scene) {
     return count;
     return count;
 }
 }
 
 
-size_t count_deformers(const aiScene* scene) {
+static size_t count_deformers(const aiScene* scene) {
     size_t count = 0;
     size_t count = 0;
     for (size_t i = 0; i < scene->mNumMeshes; ++i) {
     for (size_t i = 0; i < scene->mNumMeshes; ++i) {
         const size_t n = scene->mMeshes[i]->mNumBones;
         const size_t n = scene->mMeshes[i]->mNumBones;
@@ -621,8 +604,7 @@ size_t count_deformers(const aiScene* scene) {
     return count;
     return count;
 }
 }
 
 
-void FBXExporter::WriteDefinitions ()
-{
+void FBXExporter::WriteDefinitions () {
     // basically this is just bookkeeping:
     // basically this is just bookkeeping:
     // determining how many of each type of object there are
     // determining how many of each type of object there are
     // and specifying the base properties to use when otherwise unspecified.
     // and specifying the base properties to use when otherwise unspecified.
@@ -1033,9 +1015,7 @@ void FBXExporter::WriteDefinitions ()
 // some internal helper functions used for writing the objects section
 // some internal helper functions used for writing the objects section
 // (which holds the actual data)
 // (which holds the actual data)
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
-
-aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node)
-{
+static aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node) {
     for (size_t i = 0; i < node->mNumMeshes; ++i) {
     for (size_t i = 0; i < node->mNumMeshes; ++i) {
         if (node->mMeshes[i] == meshIndex) {
         if (node->mMeshes[i] == meshIndex) {
             return node;
             return node;
@@ -1048,8 +1028,7 @@ aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node)
     return nullptr;
     return nullptr;
 }
 }
 
 
-aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene)
-{
+aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) {
     std::vector<const aiNode*> node_chain;
     std::vector<const aiNode*> node_chain;
     while (node != scene->mRootNode && node != nullptr) {
     while (node != scene->mRootNode && node != nullptr) {
         node_chain.push_back(node);
         node_chain.push_back(node);
@@ -1073,8 +1052,7 @@ inline int64_t to_ktime(double time) {
     return (static_cast<int64_t>(time * FBX::SECOND));
     return (static_cast<int64_t>(time * FBX::SECOND));
 }
 }
 
 
-void FBXExporter::WriteObjects ()
-{
+void FBXExporter::WriteObjects () {
     if (!binary) {
     if (!binary) {
         WriteAsciiSectionHeader("Object properties");
         WriteAsciiSectionHeader("Object properties");
     }
     }

+ 0 - 1
code/AssetLib/FBX/FBXExporter.h

@@ -51,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXCommon.h" // FBX::TransformInheritance
 #include "FBXCommon.h" // FBX::TransformInheritance
 
 
 #include <assimp/types.h>
 #include <assimp/types.h>
-//#include <assimp/material.h>
 #include <assimp/StreamWriter.h> // StreamWriterLE
 #include <assimp/StreamWriter.h> // StreamWriterLE
 #include <assimp/Exceptional.h> // DeadlyExportError
 #include <assimp/Exceptional.h> // DeadlyExportError
 
 

+ 0 - 4
code/AssetLib/FBX/FBXMaterial.cpp

@@ -134,10 +134,6 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
     }
     }
 }
 }
 
 
-
-// ------------------------------------------------------------------------------------------------
-Material::~Material() = default;
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
 Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
         Object(id,element,name),
         Object(id,element,name),

+ 1 - 2
code/AssetLib/FBX/FBXParser.h

@@ -84,8 +84,7 @@ using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const
  *  As can be seen in this sample, elements can contain nested #Scope
  *  As can be seen in this sample, elements can contain nested #Scope
  *  as their trailing member.  
  *  as their trailing member.  
 **/
 **/
-class Element
-{
+class Element {
 public:
 public:
     Element(const Token& key_token, Parser& parser);
     Element(const Token& key_token, Parser& parser);
     ~Element();
     ~Element();

+ 4 - 16
code/AssetLib/FBX/FBXProperties.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -57,15 +56,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {
 
 
-    using namespace Util;
+using namespace Util;
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-    Property::Property() = default;
-
-    // ------------------------------------------------------------------------------------------------
-    Property::~Property() = default;
 
 
-    namespace {
+namespace {
 
 
     void checkTokenCount(const TokenList &tok, unsigned int expectedCount) {
     void checkTokenCount(const TokenList &tok, unsigned int expectedCount) {
         ai_assert(expectedCount >= 2);
         ai_assert(expectedCount >= 2);
@@ -146,9 +141,9 @@ Property* ReadTypedProperty(const Element& element)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // peek into an element and check if it contains a FBX property, if so return its name.
 // peek into an element and check if it contains a FBX property, if so return its name.
-std::string PeekPropertyName(const Element& element)
-{
+std::string PeekPropertyName(const Element& element) {
     ai_assert(element.KeyToken().StringContents() == "P");
     ai_assert(element.KeyToken().StringContents() == "P");
+
     const TokenList& tok = element.Tokens();
     const TokenList& tok = element.Tokens();
     if(tok.size() < 4) {
     if(tok.size() < 4) {
         return std::string();
         return std::string();
@@ -160,13 +155,6 @@ std::string PeekPropertyName(const Element& element)
 } //! anon
 } //! anon
 
 
 
 
-// ------------------------------------------------------------------------------------------------
-PropertyTable::PropertyTable()
-: templateProps()
-, element()
-{
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 PropertyTable::PropertyTable(const Element &element, std::shared_ptr<const PropertyTable> templateProps) :
 PropertyTable::PropertyTable(const Element &element, std::shared_ptr<const PropertyTable> templateProps) :
         templateProps(std::move(templateProps)), element(&element) {
         templateProps(std::move(templateProps)), element(&element) {

+ 20 - 25
code/AssetLib/FBX/FBXProperties.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -56,34 +55,33 @@ namespace FBX {
 // Forward declarations
 // Forward declarations
 class Element;
 class Element;
 
 
-/** Represents a dynamic property. Type info added by deriving classes,
- *  see #TypedProperty.
- Example:
- @verbatim
-   P: "ShininessExponent", "double", "Number", "",0.5
- @endvebatim
-*/
+/**
+ * Represents a dynamic property. Type info added by deriving classes,
+ * see #TypedProperty.
+ * Example:
+ *
+ * @verbatim
+ *  P: "ShininessExponent", "double", "Number", "",0.5
+ * @endvebatim
+ */
 class Property {
 class Property {
-protected:
-    Property();
 
 
 public:
 public:
-    virtual ~Property();
+    virtual ~Property() = default;
 
 
-public:
     template <typename T>
     template <typename T>
     const T* As() const {
     const T* As() const {
         return dynamic_cast<const T*>(this);
         return dynamic_cast<const T*>(this);
     }
     }
+
+protected:
+    Property() = default;
 };
 };
 
 
 template<typename T>
 template<typename T>
 class TypedProperty : public Property {
 class TypedProperty : public Property {
 public:
 public:
-    explicit TypedProperty(const T& value)
-    : value(value) {
-        // empty
-    }
+    explicit TypedProperty(const T& value) : value(value) {}
 
 
     const T& Value() const {
     const T& Value() const {
         return value;
         return value;
@@ -93,10 +91,9 @@ private:
     T value;
     T value;
 };
 };
 
 
-
-typedef std::fbx_unordered_map<std::string,std::shared_ptr<Property> > DirectPropertyMap;
-typedef std::fbx_unordered_map<std::string,const Property*>            PropertyMap;
-typedef std::fbx_unordered_map<std::string,const Element*>             LazyPropertyMap;
+using DirectPropertyMap = std::fbx_unordered_map<std::string,std::shared_ptr<Property> >;
+using PropertyMap = std::fbx_unordered_map<std::string,const Property*>;
+using LazyPropertyMap = std::fbx_unordered_map<std::string,const Element*>;
 
 
 /**
 /**
  *  Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
  *  Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
@@ -104,7 +101,7 @@ typedef std::fbx_unordered_map<std::string,const Element*>             LazyPrope
 class PropertyTable {
 class PropertyTable {
 public:
 public:
     // in-memory property table with no source element
     // in-memory property table with no source element
-    PropertyTable();
+    PropertyTable() : element() {}
     PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps);
     PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps);
     ~PropertyTable();
     ~PropertyTable();
 
 
@@ -130,8 +127,7 @@ private:
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 template <typename T>
-inline
-T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
+inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
     const Property* const prop = in.Get(name);
     const Property* const prop = in.Get(name);
     if( nullptr == prop) {
     if( nullptr == prop) {
         return defaultValue;
         return defaultValue;
@@ -148,8 +144,7 @@ T PropertyGet(const PropertyTable& in, const std::string& name, const T& default
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 template <typename T>
-inline
-T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
+inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
     const Property* prop = in.Get(name);
     const Property* prop = in.Get(name);
     if( nullptr == prop) {
     if( nullptr == prop) {
         if ( ! useTemplate ) {
         if ( ! useTemplate ) {

+ 0 - 5
code/AssetLib/FBX/FBXUtil.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2024, assimp team
 Copyright (c) 2006-2024, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -53,10 +52,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {
 
 
-
 namespace Util {
 namespace Util {
 
 
-
 /** helper for std::for_each to delete all heap-allocated items in a container */
 /** helper for std::for_each to delete all heap-allocated items in a container */
 template<typename T>
 template<typename T>
 struct delete_fun
 struct delete_fun
@@ -88,7 +85,6 @@ const char* TokenTypeString(TokenType t);
  *  @return A string of the following format: " (offset 0x{offset}) "*/
  *  @return A string of the following format: " (offset 0x{offset}) "*/
 std::string GetOffsetText(size_t offset);
 std::string GetOffsetText(size_t offset);
 
 
-
 /** Format log/error messages using a given line location in the source file.
 /** Format log/error messages using a given line location in the source file.
  *
  *
  *  @param line Line index, 1-based
  *  @param line Line index, 1-based
@@ -96,7 +92,6 @@ std::string GetOffsetText(size_t offset);
  *  @return A string of the following format: " (line {line}, col {column}) "*/
  *  @return A string of the following format: " (line {line}, col {column}) "*/
 std::string GetLineAndColumnText(unsigned int line, unsigned int column);
 std::string GetLineAndColumnText(unsigned int line, unsigned int column);
 
 
-
 /** Format log/error messages using a given cursor token.
 /** Format log/error messages using a given cursor token.
  *
  *
  *  @param tok Token where parsing/processing stopped
  *  @param tok Token where parsing/processing stopped

+ 0 - 1
code/AssetLib/NFF/NFFLoader.h

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

+ 1 - 1
code/AssetLib/Obj/ObjExporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2024, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 2 - 2
code/AssetLib/Obj/ObjExporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2024, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.
@@ -62,7 +62,7 @@ namespace Assimp {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 /** Helper class to export a given scene to an OBJ file. */
 /** Helper class to export a given scene to an OBJ file. */
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-class ObjExporter {
+class ObjExporter final {
 public:
 public:
     /// Constructor for a specific scene to export
     /// Constructor for a specific scene to export
     ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false, const ExportProperties* props = nullptr);
     ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false, const ExportProperties* props = nullptr);

+ 1 - 1
code/AssetLib/Obj/ObjFileImporter.h

@@ -61,7 +61,7 @@ struct Model;
 /// \class  ObjFileImporter
 /// \class  ObjFileImporter
 /// \brief  Imports a waveform obj file
 /// \brief  Imports a waveform obj file
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-class ObjFileImporter : public BaseImporter {
+class ObjFileImporter final : public BaseImporter {
 public:
 public:
     /// \brief  Default constructor
     /// \brief  Default constructor
     ObjFileImporter();
     ObjFileImporter();

+ 1 - 5
code/AssetLib/Obj/ObjFileMtlImporter.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2024, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -106,10 +106,6 @@ ObjFileMtlImporter::ObjFileMtlImporter(std::vector<char> &buffer,
     load();
     load();
 }
 }
 
 
-// -------------------------------------------------------------------
-//  Destructor
-ObjFileMtlImporter::~ObjFileMtlImporter() = default;
-
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
 //  Loads the material description
 //  Loads the material description
 void ObjFileMtlImporter::load() {
 void ObjFileMtlImporter::load() {

+ 2 - 5
code/AssetLib/Obj/ObjFileMtlImporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2024, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -71,13 +71,12 @@ public:
             ObjFile::Model *pModel);
             ObjFile::Model *pModel);
 
 
     //! \brief  The class destructor
     //! \brief  The class destructor
-    ~ObjFileMtlImporter();
+    ~ObjFileMtlImporter() = default;
 
 
     ObjFileMtlImporter(const ObjFileMtlImporter &rOther) = delete;
     ObjFileMtlImporter(const ObjFileMtlImporter &rOther) = delete;
     ObjFileMtlImporter &operator=(const ObjFileMtlImporter &rOther) = delete;
     ObjFileMtlImporter &operator=(const ObjFileMtlImporter &rOther) = delete;
 
 
 private:
 private:
-    /// Copy constructor, empty.
     /// Load the whole material description
     /// Load the whole material description
     void load();
     void load();
     /// Get color data.
     /// Get color data.
@@ -109,8 +108,6 @@ private:
     std::vector<char> m_buffer;
     std::vector<char> m_buffer;
 };
 };
 
 
-// ------------------------------------------------------------------------------------------------
-
 } // Namespace Assimp
 } // Namespace Assimp
 
 
 #endif // OBJFILEMTLIMPORTER_H_INC
 #endif // OBJFILEMTLIMPORTER_H_INC

+ 2 - 2
code/AssetLib/Obj/ObjFileParser.cpp

@@ -111,8 +111,8 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
     //const unsigned int updateProgressEveryBytes = 100 * 1024;
     //const unsigned int updateProgressEveryBytes = 100 * 1024;
     const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
     const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
     const unsigned int progressTotal = bytesToProcess;
     const unsigned int progressTotal = bytesToProcess;
-    unsigned int processed = 0;
-    size_t lastFilePos(0);
+    unsigned int processed = 0u;
+    size_t lastFilePos = 0u;
 
 
     bool insideCstype = false;
     bool insideCstype = false;
     std::vector<char> buffer;
     std::vector<char> buffer;

+ 7 - 4
code/AssetLib/Obj/ObjFileParser.h

@@ -55,18 +55,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 namespace Assimp {
 namespace Assimp {
 
 
+// Forward declarations
 class ObjFileImporter;
 class ObjFileImporter;
 class IOSystem;
 class IOSystem;
 class ProgressHandler;
 class ProgressHandler;
 
 
+// ------------------------------------------------------------------------------------------------
 /// \class  ObjFileParser
 /// \class  ObjFileParser
 /// \brief  Parser for a obj waveform file
 /// \brief  Parser for a obj waveform file
+// ------------------------------------------------------------------------------------------------
 class ASSIMP_API ObjFileParser {
 class ASSIMP_API ObjFileParser {
 public:
 public:
-    static const size_t Buffersize = 4096;
-    typedef std::vector<char> DataArray;
-    typedef std::vector<char>::iterator DataArrayIt;
-    typedef std::vector<char>::const_iterator ConstDataArrayIt;
+    static constexpr size_t Buffersize = 4096;
+    using DataArray = std::vector<char>;
+    using DataArrayIt = std::vector<char>::iterator;
+    using ConstDataArrayIt = std::vector<char>::const_iterator;
 
 
     /// @brief  The default constructor.
     /// @brief  The default constructor.
     ObjFileParser();
     ObjFileParser();

+ 54 - 0
include/assimp/scene.h

@@ -165,6 +165,33 @@ struct ASSIMP_API aiNode {
     const aiNode* FindNode(const char* name) const;
     const aiNode* FindNode(const char* name) const;
     aiNode* FindNode(const char* name);
     aiNode* FindNode(const char* name);
 
 
+    // ------------------------------------------------------------------------------------------------
+    // Helper to find the node associated with a bone in the scene
+    const aiNode *findBoneNode(const aiBone *bone) const {
+        if (bone == nullptr) {
+            return nullptr;
+        }
+
+        if (mName == bone->mName) {
+            return this;
+        }
+
+        for (unsigned int i = 0; i < mNumChildren; ++i) {
+            aiNode *aChild = mChildren[i];
+            if (aChild == nullptr) {
+                continue;
+            }
+
+            const aiNode *foundFromChild = nullptr;
+            foundFromChild = aChild->findBoneNode(bone);
+            if (foundFromChild) {
+                return foundFromChild;
+            }
+        }
+
+        return nullptr;
+    }
+
     /**
     /**
      * @brief   Will add new children.
      * @brief   Will add new children.
      * @param   numChildren  Number of children to add.
      * @param   numChildren  Number of children to add.
@@ -441,6 +468,33 @@ struct ASSIMP_API aiScene {
         }
         }
         return std::make_pair(nullptr, -1);
         return std::make_pair(nullptr, -1);
     }
     }
+
+        /**
+     * @brief Will try to locate a bone described by its name.
+     * 
+     * @param name  The name to look for.
+     * @return The bone as a pointer.
+     */
+    inline aiBone *findBone(const aiString &name) const {
+        for (size_t m = 0; m < mNumMeshes; m++) {
+            aiMesh *mesh = mMeshes[m];
+            if (mesh == nullptr) {
+                continue;
+            }
+
+            for (size_t b = 0; b < mesh->mNumBones; b++) {
+                aiBone *bone = mesh->mBones[b];
+                if (bone == nullptr) {
+                    continue;
+                }
+                if (name == bone->mName) {
+                    return bone;
+                }
+            }
+        }
+        return nullptr;
+    }
+
 #endif // __cplusplus
 #endif // __cplusplus
 
 
     /**  Internal data, do not touch */
     /**  Internal data, do not touch */