فهرست منبع

Merge branch 'master' into master

Kim Kulling 2 سال پیش
والد
کامیت
2c3d52a5a1

+ 12 - 4
CMakeLists.txt

@@ -84,10 +84,6 @@ OPTION( ASSIMP_NO_EXPORT
   "Disable Assimp's export functionality."
   OFF
 )
-OPTION( ASSIMP_BUILD_ZLIB
-  "Build your own zlib"
-  OFF
-)
 OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
   "If the supplementary tools for Assimp are built in addition to the library."
   OFF
@@ -134,6 +130,18 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
    OFF
 )
 
+IF (WIN32)
+  OPTION( ASSIMP_BUILD_ZLIB
+    "Build your own zlib"
+    ON
+  )
+ELSE()
+  OPTION( ASSIMP_BUILD_ZLIB
+    "Build your own zlib"
+    OFF
+  )
+ENDIF()
+
 IF (WIN32)
   # Use subset of Windows.h
   ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )

+ 1 - 1
code/AssetLib/B3D/B3DImporter.cpp

@@ -150,7 +150,7 @@ AI_WONT_RETURN void B3DImporter::Fail(const string &str) {
 
 // ------------------------------------------------------------------------------------------------
 int B3DImporter::ReadByte() {
-    if (_pos > _buf.size()) {
+    if (_pos >= _buf.size()) {
         Fail("EOF");
     }
 

+ 1 - 1
code/AssetLib/MDL/MDLLoader.cpp

@@ -975,7 +975,7 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7 **apcOutBones)
                     }
 
                     // store the name of the bone
-                    pcOutBone->mName.length = (size_t)iMaxLen;
+                    pcOutBone->mName.length = static_cast<ai_uint32>(iMaxLen);
                     ::memcpy(pcOutBone->mName.data, pcBone->name, pcOutBone->mName.length);
                     pcOutBone->mName.data[pcOutBone->mName.length] = '\0';
                 }

+ 2 - 2
code/AssetLib/MS3D/MS3DLoader.cpp

@@ -486,7 +486,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
 
         for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) {
             aiFace& f = m->mFaces[j];
-            if (g.triangles[j]>triangles.size()) {
+            if (g.triangles[j] >= triangles.size()) {
                 throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed");
             }
 
@@ -494,7 +494,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
             f.mIndices = new unsigned int[f.mNumIndices=3];
 
             for (unsigned int k = 0; k < 3; ++k,++n) {
-                if (t.indices[k]>vertices.size()) {
+                if (t.indices[k] >= vertices.size()) {
                     throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed");
                 }
 

+ 1 - 1
code/AssetLib/SMD/SMDLoader.cpp

@@ -590,7 +590,7 @@ void SMDImporter::CreateOutputMaterials() {
         pScene->mMaterials[iMat] = pcMat;
 
         aiString szName;
-        szName.length = (size_t)ai_snprintf(szName.data,MAXLEN,"Texture_%u",iMat);
+        szName.length = static_cast<ai_uint32>(ai_snprintf(szName.data,MAXLEN,"Texture_%u",iMat));
         pcMat->AddProperty(&szName,AI_MATKEY_NAME);
 
         if (aszTextures[iMat].length())

+ 2 - 2
code/AssetLib/glTF2/glTF2AssetWriter.inl

@@ -836,7 +836,7 @@ namespace glTF2 {
             throw DeadlyExportError("Failed to write scene data!");
         }
 
-        uint32_t jsonChunkLength = (docBuffer.GetSize() + 3) & ~3; // Round up to next multiple of 4
+        uint32_t jsonChunkLength = static_cast<uint32_t>((docBuffer.GetSize() + 3) & ~3); // Round up to next multiple of 4
         auto paddingLength = jsonChunkLength - docBuffer.GetSize();
 
         GLB_Chunk jsonChunk;
@@ -862,7 +862,7 @@ namespace glTF2 {
         int GLB_Chunk_count = 1;
         uint32_t binaryChunkLength = 0;
         if (bodyBuffer->byteLength > 0) {
-            binaryChunkLength = (bodyBuffer->byteLength + 3) & ~3; // Round up to next multiple of 4
+            binaryChunkLength = static_cast<uint32_t>((bodyBuffer->byteLength + 3) & ~3); // Round up to next multiple of 4
 
             auto curPaddingLength = binaryChunkLength - bodyBuffer->byteLength;
             ++GLB_Chunk_count;

+ 32 - 26
code/Common/Importer.cpp

@@ -482,37 +482,43 @@ bool Importer::ValidateFlags(unsigned int pFlags) const {
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
-    size_t pLength,
-    unsigned int pFlags,
-    const char* pHint /*= ""*/) {
+const aiScene* Importer::ReadFileFromMemory(const void* pBuffer, size_t pLength, unsigned int pFlags, const char* pHint ) {
     ai_assert(nullptr != pimpl);
 
-    ASSIMP_BEGIN_EXCEPTION_REGION();
-    if (!pHint) {
-        pHint = "";
-    }
-
-    if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
-        pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
-        return nullptr;
-    }
-
-    // prevent deletion of the previous IOHandler
     IOSystem* io = pimpl->mIOHandler;
-    pimpl->mIOHandler = nullptr;
-
-    SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
-
-    // read the file and recover the previous IOSystem
-    static const size_t BufSize(Importer::MaxLenHint + 28);
-    char fbuff[BufSize];
-    ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
+    try {
+        if (pHint == nullptr) {
+            pHint = "";
+        }
+        if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
+            pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
+            return nullptr;
+        }
+        // prevent deletion of the previous IOHandler
+        pimpl->mIOHandler = nullptr;
+
+        SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
+
+        // read the file and recover the previous IOSystem
+        static const size_t BufSize(Importer::MaxLenHint + 28);
+        char fbuff[BufSize];
+        ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
+
+        ReadFile(fbuff,pFlags);
+        SetIOHandler(io);
+    } catch(const DeadlyImportError &e) {
+        pimpl->mErrorString = e.what();
+        pimpl->mException = std::current_exception();
+        SetIOHandler(io);
+        return ExceptionSwallower<const aiScene*>()();                                                                                                    \
+    } catch(...) {
+        pimpl->mErrorString = "Unknown exception";
+        pimpl->mException = std::current_exception();
+        SetIOHandler(io);
+        return ExceptionSwallower<const aiScene*>()();                                                                                                    \
 
-    ReadFile(fbuff,pFlags);
-    SetIOHandler(io);
+    }
 
-    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
     return pimpl->mScene;
 }
 

+ 2 - 2
contrib/zip/src/miniz.h

@@ -6092,8 +6092,8 @@ mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) {
   if (!pZip->m_file_offset_alignment)
     return 0;
   n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
-  return (pZip->m_file_offset_alignment - n) &
-         (pZip->m_file_offset_alignment - 1);
+  return (mz_uint)((pZip->m_file_offset_alignment - n) &
+                   (pZip->m_file_offset_alignment - 1));
 }
 
 static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip,

+ 1 - 1
doc/Fileformats.md

@@ -14,7 +14,7 @@ __Importers__:
 - B3D
 - [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format))
 - [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy)
-- CMS
+- CSM
 - COB
 - [DAE/Collada](https://en.wikipedia.org/wiki/COLLADA)
 - [DXF](https://en.wikipedia.org/wiki/AutoCAD_DXF)

+ 4 - 3
fuzz/assimp_fuzzer.cc

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2023, assimp team
 
 All rights reserved.
 
@@ -46,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize) {
-	aiLogStream stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
-	aiAttachLogStream(&stream);
+    aiLogStream stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
+    aiAttachLogStream(&stream);
 
     Importer importer;
     const aiScene *sc = importer.ReadFileFromMemory(data, dataSize,
@@ -57,3 +57,4 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize) {
 
     return 0;
 }
+

+ 33 - 42
include/assimp/MemoryIOWrapper.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -66,23 +65,21 @@ namespace Assimp    {
 // ----------------------------------------------------------------------------------
 class MemoryIOStream : public IOStream {
 public:
-    MemoryIOStream (const uint8_t* buff, size_t len, bool own = false)
-    : buffer (buff)
-    , length(len)
-    , pos((size_t)0)
-    , own(own) {
+    MemoryIOStream (const uint8_t* buff, size_t len, bool own = false) : 
+            buffer (buff), 
+            length(len),
+            pos(static_cast<size_t>(0)),
+            own(own) {
         // empty
     }
 
-    ~MemoryIOStream ()  {
+    ~MemoryIOStream() override  {
         if(own) {
             delete[] buffer;
         }
     }
 
-    // -------------------------------------------------------------------
-    // Read from stream
-    size_t Read(void* pvBuffer, size_t pSize, size_t pCount)    {
+    size_t Read(void* pvBuffer, size_t pSize, size_t pCount) override {
         ai_assert(nullptr != pvBuffer);
         ai_assert(0 != pSize);
 
@@ -95,16 +92,12 @@ public:
         return cnt;
     }
 
-    // -------------------------------------------------------------------
-    // Write to stream
-    size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/,size_t /*pCount*/)  {
+    size_t Write(const void*, size_t, size_t ) override {
         ai_assert(false); // won't be needed
         return 0;
     }
 
-    // -------------------------------------------------------------------
-    // Seek specific position
-    aiReturn Seek(size_t pOffset, aiOrigin pOrigin) {
+    aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override {
         if (aiOrigin_SET == pOrigin) {
             if (pOffset > length) {
                 return AI_FAILURE;
@@ -124,21 +117,15 @@ public:
         return AI_SUCCESS;
     }
 
-    // -------------------------------------------------------------------
-    // Get current seek position
-    size_t Tell() const {
+    size_t Tell() const override {
         return pos;
     }
 
-    // -------------------------------------------------------------------
-    // Get size of file
-    size_t FileSize() const {
+    size_t FileSize() const override {
         return length;
     }
 
-    // -------------------------------------------------------------------
-    // Flush file contents
-    void Flush() {
+    void Flush() override{
         ai_assert(false); // won't be needed
     }
 
@@ -149,24 +136,21 @@ private:
 };
 
 // ---------------------------------------------------------------------------
-/** Dummy IO system to read from a memory buffer */
+/// @brief Dummy IO system to read from a memory buffer.
 class MemoryIOSystem : public IOSystem {
 public:
-    /** Constructor. */
-    MemoryIOSystem(const uint8_t* buff, size_t len, IOSystem* io)
-    : buffer(buff)
-    , length(len)
-    , existing_io(io)
-    , created_streams() {
+    /// @brief Constructor.
+    MemoryIOSystem(const uint8_t* buff, size_t len, IOSystem* io) : buffer(buff), length(len), existing_io(io) {
         // empty
     }
 
-    /** Destructor. */
+    /// @brief Destructor.
     ~MemoryIOSystem() = default;
 
     // -------------------------------------------------------------------
-    /** Tests for the existence of a file at the given path. */
+    /// @brief Tests for the existence of a file at the given path.
     bool Exists(const char* pFile) const override {
+        printf("Exists\n");
         if (0 == strncmp( pFile, AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) ) {
             return true;
         }
@@ -174,24 +158,24 @@ public:
     }
 
     // -------------------------------------------------------------------
-    /** Returns the directory separator. */
+    /// @brief Returns the directory separator.
     char getOsSeparator() const override {
         return existing_io ? existing_io->getOsSeparator()
                            : '/';  // why not? it doesn't care
     }
 
     // -------------------------------------------------------------------
-    /** Open a new file with a given path. */
+    /// @brief Open a new file with a given path.
     IOStream* Open(const char* pFile, const char* pMode = "rb") override {
         if ( 0 == strncmp( pFile, AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) ) {
             created_streams.emplace_back(new MemoryIOStream(buffer, length));
             return created_streams.back();
         }
-        return existing_io ? existing_io->Open(pFile, pMode) : NULL;
+        return existing_io ? existing_io->Open(pFile, pMode) : nullptr;
     }
 
     // -------------------------------------------------------------------
-    /** Closes the given file and releases all resources associated with it. */
+    /// @brief Closes the given file and releases all resources associated with it.
     void Close( IOStream* pFile) override {
         auto it = std::find(created_streams.begin(), created_streams.end(), pFile);
         if (it != created_streams.end()) {
@@ -203,36 +187,43 @@ public:
     }
 
     // -------------------------------------------------------------------
-    /** Compare two paths */
+    /// @brief Compare two paths
     bool ComparePaths(const char* one, const char* second) const override {
         return existing_io ? existing_io->ComparePaths(one, second) : false;
     }
-
+    
+    /// @brief Will push the directory.
     bool PushDirectory( const std::string &path ) override {
         return existing_io ? existing_io->PushDirectory(path) : false;
     }
 
+    /// @brief Will return the current directory from the stack top.
     const std::string &CurrentDirectory() const override {
         static std::string empty;
         return existing_io ? existing_io->CurrentDirectory() : empty;
     }
 
+    /// @brief Returns the stack size.
     size_t StackSize() const override {
         return existing_io ? existing_io->StackSize() : 0;
     }
 
+    /// @brief Will pop the upper directory.
     bool PopDirectory() override {
         return existing_io ? existing_io->PopDirectory() : false;
     }
 
+    /// @brief Will create the directory.
     bool CreateDirectory( const std::string &path ) override {
         return existing_io ? existing_io->CreateDirectory(path) : false;
     }
-
+    
+    /// @brief Will change the directory.
     bool ChangeDirectory( const std::string &path ) override {
         return existing_io ? existing_io->ChangeDirectory(path) : false;
     }
 
+    /// @brief Will delete the file.
     bool DeleteFile( const std::string &file ) override {
         return existing_io ? existing_io->DeleteFile(file) : false;
     }
@@ -246,4 +237,4 @@ private:
 
 } // end namespace Assimp
 
-#endif
+#endif // AI_MEMORYIOSTREAM_H_INC

+ 337 - 226
include/assimp/mesh.h

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2022, assimp team
+Copyright (c) 2006-2023, assimp team
 
 All rights reserved.
 
@@ -111,7 +111,8 @@ extern "C" {
 #endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS
 
 // ---------------------------------------------------------------------------
-/** @brief A single face in a mesh, referring to multiple vertices.
+/**
+ * @brief A single face in a mesh, referring to multiple vertices.
  *
  * If mNumIndices is 3, we call the face 'triangle', for mNumIndices > 3
  * it's called 'polygon' (hey, that's just a definition!).
@@ -142,25 +143,25 @@ struct aiFace {
 
 #ifdef __cplusplus
 
-    //! Default constructor
+    //! @brief Default constructor.
     aiFace() AI_NO_EXCEPT
             : mNumIndices(0),
               mIndices(nullptr) {
         // empty
     }
 
-    //! Default destructor. Delete the index array
+    //! @brief Default destructor. Delete the index array
     ~aiFace() {
         delete[] mIndices;
     }
 
-    //! Copy constructor. Copy the index array
+    //! @brief Copy constructor. Copy the index array
     aiFace(const aiFace &o) :
             mNumIndices(0), mIndices(nullptr) {
         *this = o;
     }
 
-    //! Assignment operator. Copy the index array
+    //! @brief Assignment operator. Copy the index array
     aiFace &operator=(const aiFace &o) {
         if (&o == this) {
             return *this;
@@ -178,8 +179,7 @@ struct aiFace {
         return *this;
     }
 
-    //! Comparison operator. Checks whether the index array
-    //! of two faces is identical
+    //! @brief Comparison operator. Checks whether the index array of two faces is identical.
     bool operator==(const aiFace &o) const {
         if (mIndices == o.mIndices) {
             return true;
@@ -202,7 +202,7 @@ struct aiFace {
         return true;
     }
 
-    //! Inverse comparison operator. Checks whether the index
+    //! @brief Inverse comparison operator. Checks whether the index
     //! array of two faces is NOT identical
     bool operator!=(const aiFace &o) const {
         return !(*this == o);
@@ -223,14 +223,14 @@ struct aiVertexWeight {
 
 #ifdef __cplusplus
 
-    //! Default constructor
+    //! @brief Default constructor
     aiVertexWeight() AI_NO_EXCEPT
             : mVertexId(0),
               mWeight(0.0f) {
         // empty
     }
 
-    //! Initialization from a given index and vertex weight factor
+    //! @brief Initialization from a given index and vertex weight factor
     //! \param pID ID
     //! \param pWeight Vertex weight factor
     aiVertexWeight(unsigned int pID, float pWeight) :
@@ -261,27 +261,38 @@ struct aiNode;
  *  position of the bone at the time of binding.
  */
 struct aiBone {
-    //! The name of the bone.
+    /**
+     * The name of the bone.
+     */
     C_STRUCT aiString mName;
 
-    //! The number of vertices affected by this bone.
-    //! The maximum value for this member is #AI_MAX_BONE_WEIGHTS.
+    /**
+     * The number of vertices affected by this bone.
+     * The maximum value for this member is #AI_MAX_BONE_WEIGHTS.
+     */
     unsigned int mNumWeights;
 
 #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
-    /// The bone armature node - used for skeleton conversion
-    /// you must enable aiProcess_PopulateArmatureData to populate this
+    /**
+     * The bone armature node - used for skeleton conversion
+     * you must enable aiProcess_PopulateArmatureData to populate this
+     */
     C_STRUCT aiNode *mArmature;
 
-    /// The bone node in the scene - used for skeleton conversion
-    /// you must enable aiProcess_PopulateArmatureData to populate this
+    /**
+     * The bone node in the scene - used for skeleton conversion
+     * you must enable aiProcess_PopulateArmatureData to populate this
+     */
     C_STRUCT aiNode *mNode;
 
 #endif
-    //! The influence weights of this bone, by vertex index.
+    /**
+     * The influence weights of this bone, by vertex index.
+     */
     C_STRUCT aiVertexWeight *mWeights;
 
-    /** Matrix that transforms from mesh space to bone space in bind pose.
+    /**
+     * Matrix that transforms from mesh space to bone space in bind pose.
      *
      * This matrix describes the position of the mesh
      * in the local space of this bone when the skeleton was bound.
@@ -338,7 +349,7 @@ struct aiBone {
         ::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
     }
 
-    //! Assignment operator
+    //! @brief Assignment operator
     aiBone &operator = (const aiBone &other) {
         if (this == &other) {
             return *this;
@@ -352,6 +363,7 @@ struct aiBone {
         return *this;
     }
 
+    /// @brief Compare operator.
     bool operator==(const aiBone &rhs) const {
         if (mName != rhs.mName || mNumWeights != rhs.mNumWeights ) {
             return false;
@@ -365,7 +377,7 @@ struct aiBone {
 
         return true;
     }
-    //! Destructor - deletes the array of vertex weights
+    //! @brief Destructor - deletes the array of vertex weights
     ~aiBone() {
         delete[] mWeights;
     }
@@ -381,27 +393,31 @@ struct aiBone {
  *  @see AI_CONFIG_PP_SBP_REMOVE Removal of specific primitive types.
  */
 enum aiPrimitiveType {
-    /** A point primitive.
+    /**
+     * @brief A point primitive.
      *
      * This is just a single vertex in the virtual world,
      * #aiFace contains just one index for such a primitive.
      */
     aiPrimitiveType_POINT = 0x1,
 
-    /** A line primitive.
+    /**
+     * @brief A line primitive.
      *
      * This is a line defined through a start and an end position.
      * #aiFace contains exactly two indices for such a primitive.
      */
     aiPrimitiveType_LINE = 0x2,
 
-    /** A triangular primitive.
+    /**
+     * @brief A triangular primitive.
      *
      * A triangle consists of three indices.
      */
     aiPrimitiveType_TRIANGLE = 0x4,
 
-    /** A higher-level polygon with more than 3 edges.
+    /**
+     * @brief A higher-level polygon with more than 3 edges.
      *
      * A triangle is a polygon, but polygon in this context means
      * "all polygons that are not triangles". The "Triangulate"-Step
@@ -411,7 +427,7 @@ enum aiPrimitiveType {
     aiPrimitiveType_POLYGON = 0x8,
 
     /**
-     * A flag to determine whether this triangles only mesh is NGON encoded.
+     * @brief A flag to determine whether this triangles only mesh is NGON encoded.
      *
      * NGON encoding is a special encoding that tells whether 2 or more consecutive triangles
      * should be considered as a triangle fan. This is identified by looking at the first vertex index.
@@ -428,8 +444,9 @@ enum aiPrimitiveType {
      */
     aiPrimitiveType_NGONEncodingFlag = 0x10,
 
-/** This value is not used. It is just here to force the
-     *  compiler to map this enum to a 32 Bit integer.
+    /**
+     * This value is not used. It is just here to force the
+     * compiler to map this enum to a 32 Bit integer.
      */
 #ifndef SWIG
     _aiPrimitiveType_Force32Bit = INT_MAX
@@ -494,25 +511,20 @@ struct aiAnimMesh {
     float mWeight;
 
 #ifdef __cplusplus
-
-    aiAnimMesh() AI_NO_EXCEPT
-            : mVertices(nullptr),
-              mNormals(nullptr),
-              mTangents(nullptr),
-              mBitangents(nullptr),
-              mColors(),
-              mTextureCoords(),
-              mNumVertices(0),
-              mWeight(0.0f) {
-        // fixme consider moving this to the ctor initializer list as well
-        for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
-            mTextureCoords[a] = nullptr;
-        }
-        for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) {
-            mColors[a] = nullptr;
-        }
+    /// @brief  The class constructor.
+    aiAnimMesh() AI_NO_EXCEPT :
+            mVertices(nullptr),
+            mNormals(nullptr),
+            mTangents(nullptr),
+            mBitangents(nullptr),
+            mColors {nullptr},
+            mTextureCoords{nullptr},
+            mNumVertices(0),
+            mWeight(0.0f) {
+        // empty
     }
 
+    /// @brief The class destructor.
     ~aiAnimMesh() {
         delete[] mVertices;
         delete[] mNormals;
@@ -526,35 +538,51 @@ struct aiAnimMesh {
         }
     }
 
-    /** Check whether the anim mesh overrides the vertex positions
-     *  of its host mesh*/
+    /**
+     *  @brief Check whether the anim-mesh overrides the vertex positions
+     *         of its host mesh.
+     *  @return true if positions are stored, false if not.
+     */
     bool HasPositions() const {
         return mVertices != nullptr;
     }
 
-    /** Check whether the anim mesh overrides the vertex normals
-     *  of its host mesh*/
+    /**
+     *  @brief Check whether the anim-mesh overrides the vertex normals
+     *         of its host mesh
+     *  @return true if normals are stored, false if not.
+     */
     bool HasNormals() const {
         return mNormals != nullptr;
     }
 
-    /** Check whether the anim mesh overrides the vertex tangents
-     *  and bitangents of its host mesh. As for aiMesh,
-     *  tangents and bitangents always go together. */
+    /**
+     *  @brief Check whether the anim-mesh overrides the vertex tangents
+     *         and bitangents of its host mesh. As for aiMesh,
+     *         tangents and bitangents always go together.
+     *  @return true if tangents and bi-tangents are stored, false if not.
+     */
     bool HasTangentsAndBitangents() const {
         return mTangents != nullptr;
     }
 
-    /** Check whether the anim mesh overrides a particular
-     * set of vertex colors on his host mesh.
-     *  @param pIndex 0<index<AI_MAX_NUMBER_OF_COLOR_SETS */
+    /**
+     *  @brief Check whether the anim mesh overrides a particular
+     *         set of vertex colors on his host mesh.
+     *  @param pIndex 0<index<AI_MAX_NUMBER_OF_COLOR_SETS
+     *  @return true if vertex colors are stored, false if not.
+     */
+
     bool HasVertexColors(unsigned int pIndex) const {
         return pIndex >= AI_MAX_NUMBER_OF_COLOR_SETS ? false : mColors[pIndex] != nullptr;
     }
 
-    /** Check whether the anim mesh overrides a particular
-     * set of texture coordinates on his host mesh.
-     *  @param pIndex 0<index<AI_MAX_NUMBER_OF_TEXTURECOORDS */
+    /**
+     *  @brief Check whether the anim mesh overrides a particular
+     *        set of texture coordinates on his host mesh.
+     *  @param pIndex 0<index<AI_MAX_NUMBER_OF_TEXTURECOORDS
+     *  @return true if texture coordinates are stored, false if not.
+     */
     bool HasTextureCoords(unsigned int pIndex) const {
         return pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? false : mTextureCoords[pIndex] != nullptr;
     }
@@ -588,143 +616,167 @@ enum aiMorphingMethod {
 
 // ---------------------------------------------------------------------------
 /** @brief A mesh represents a geometry or model with a single material.
-*
-* It usually consists of a number of vertices and a series of primitives/faces
-* referencing the vertices. In addition there might be a series of bones, each
-* of them addressing a number of vertices with a certain weight. Vertex data
-* is presented in channels with each channel containing a single per-vertex
-* information such as a set of texture coordinates or a normal vector.
-* If a data pointer is non-null, the corresponding data stream is present.
-* From C++-programs you can also use the comfort functions Has*() to
-* test for the presence of various data streams.
-*
-* A Mesh uses only a single material which is referenced by a material ID.
-* @note The mPositions member is usually not optional. However, vertex positions
-* *could* be missing if the #AI_SCENE_FLAGS_INCOMPLETE flag is set in
-* @code
-* aiScene::mFlags
-* @endcode
-*/
+ *
+ * It usually consists of a number of vertices and a series of primitives/faces
+ * referencing the vertices. In addition there might be a series of bones, each
+ * of them addressing a number of vertices with a certain weight. Vertex data
+ * is presented in channels with each channel containing a single per-vertex
+ * information such as a set of texture coordinates or a normal vector.
+ * If a data pointer is non-null, the corresponding data stream is present.
+ * From C++-programs you can also use the comfort functions Has*() to
+ * test for the presence of various data streams.
+ *
+ * A Mesh uses only a single material which is referenced by a material ID.
+ * @note The mPositions member is usually not optional. However, vertex positions
+ * *could* be missing if the #AI_SCENE_FLAGS_INCOMPLETE flag is set in
+ * @code
+ * aiScene::mFlags
+ * @endcode
+ */
 struct aiMesh {
-    /** Bitwise combination of the members of the #aiPrimitiveType enum.
+    /**
+     * Bitwise combination of the members of the #aiPrimitiveType enum.
      * This specifies which types of primitives are present in the mesh.
      * The "SortByPrimitiveType"-Step can be used to make sure the
      * output meshes consist of one primitive type each.
      */
     unsigned int mPrimitiveTypes;
 
-    /** The number of vertices in this mesh.
-    * This is also the size of all of the per-vertex data arrays.
-    * The maximum value for this member is #AI_MAX_VERTICES.
-    */
+    /**
+     * The number of vertices in this mesh.
+     * This is also the size of all of the per-vertex data arrays.
+     * The maximum value for this member is #AI_MAX_VERTICES.
+     */
     unsigned int mNumVertices;
 
-    /** The number of primitives (triangles, polygons, lines) in this  mesh.
-    * This is also the size of the mFaces array.
-    * The maximum value for this member is #AI_MAX_FACES.
-    */
+    /**
+     * The number of primitives (triangles, polygons, lines) in this  mesh.
+     * This is also the size of the mFaces array.
+     * The maximum value for this member is #AI_MAX_FACES.
+     */
     unsigned int mNumFaces;
 
-    /** Vertex positions.
-    * This array is always present in a mesh. The array is
-    * mNumVertices in size.
-    */
+    /**
+     * @brief Vertex positions.
+     * 
+     * This array is always present in a mesh. The array is
+     * mNumVertices in size.
+     */
     C_STRUCT aiVector3D *mVertices;
 
-    /** Vertex normals.
-    * The array contains normalized vectors, nullptr if not present.
-    * The array is mNumVertices in size. Normals are undefined for
-    * point and line primitives. A mesh consisting of points and
-    * lines only may not have normal vectors. Meshes with mixed
-    * primitive types (i.e. lines and triangles) may have normals,
-    * but the normals for vertices that are only referenced by
-    * point or line primitives are undefined and set to QNaN (WARN:
-    * qNaN compares to inequal to *everything*, even to qNaN itself.
-    * Using code like this to check whether a field is qnan is:
-    * @code
-    * #define IS_QNAN(f) (f != f)
-    * @endcode
-    * still dangerous because even 1.f == 1.f could evaluate to false! (
-    * remember the subtleties of IEEE754 artithmetics). Use stuff like
-    * @c fpclassify instead.
-    * @note Normal vectors computed by Assimp are always unit-length.
-    * However, this needn't apply for normals that have been taken
-    *   directly from the model file.
-    */
+    /**
+     * @brief Vertex normals.
+     * 
+     * The array contains normalized vectors, nullptr if not present.
+     * The array is mNumVertices in size. Normals are undefined for
+     * point and line primitives. A mesh consisting of points and
+     * lines only may not have normal vectors. Meshes with mixed
+     * primitive types (i.e. lines and triangles) may have normals,
+     * but the normals for vertices that are only referenced by
+     * point or line primitives are undefined and set to QNaN (WARN:
+     * qNaN compares to inequal to *everything*, even to qNaN itself.
+     * Using code like this to check whether a field is qnan is:
+     * @code
+     * #define IS_QNAN(f) (f != f)
+     * @endcode
+     * still dangerous because even 1.f == 1.f could evaluate to false! (
+     * remember the subtleties of IEEE754 artithmetics). Use stuff like
+     * @c fpclassify instead.
+     * @note Normal vectors computed by Assimp are always unit-length.
+     * However, this needn't apply for normals that have been taken
+     * directly from the model file.
+     */
     C_STRUCT aiVector3D *mNormals;
 
-    /** Vertex tangents.
-    * The tangent of a vertex points in the direction of the positive
-    * X texture axis. The array contains normalized vectors, nullptr if
-    * not present. The array is mNumVertices in size. A mesh consisting
-    * of points and lines only may not have normal vectors. Meshes with
-    * mixed primitive types (i.e. lines and triangles) may have
-    * normals, but the normals for vertices that are only referenced by
-    * point or line primitives are undefined and set to qNaN.  See
-    * the #mNormals member for a detailed discussion of qNaNs.
-    * @note If the mesh contains tangents, it automatically also
-    * contains bitangents.
-    */
+    /**
+     * @brief Vertex tangents.
+     * 
+     * The tangent of a vertex points in the direction of the positive
+     * X texture axis. The array contains normalized vectors, nullptr if
+     * not present. The array is mNumVertices in size. A mesh consisting
+     * of points and lines only may not have normal vectors. Meshes with
+     * mixed primitive types (i.e. lines and triangles) may have
+     * normals, but the normals for vertices that are only referenced by
+     * point or line primitives are undefined and set to qNaN.  See
+     * the #mNormals member for a detailed discussion of qNaNs.
+     * @note If the mesh contains tangents, it automatically also
+     * contains bitangents.
+     */
     C_STRUCT aiVector3D *mTangents;
 
-    /** Vertex bitangents.
-    * The bitangent of a vertex points in the direction of the positive
-    * Y texture axis. The array contains normalized vectors, nullptr if not
-    * present. The array is mNumVertices in size.
-    * @note If the mesh contains tangents, it automatically also contains
-    * bitangents.
-    */
+    /**
+     * @brief Vertex bitangents.
+     * 
+     * The bitangent of a vertex points in the direction of the positive
+     * Y texture axis. The array contains normalized vectors, nullptr if not
+     * present. The array is mNumVertices in size.
+     * @note If the mesh contains tangents, it automatically also contains
+     * bitangents.
+     */
     C_STRUCT aiVector3D *mBitangents;
 
-    /** Vertex color sets.
-    * A mesh may contain 0 to #AI_MAX_NUMBER_OF_COLOR_SETS vertex
-    * colors per vertex. nullptr if not present. Each array is
-    * mNumVertices in size if present.
-    */
+    /**
+     * @brief Vertex color sets.
+     * 
+     * A mesh may contain 0 to #AI_MAX_NUMBER_OF_COLOR_SETS vertex
+     * colors per vertex. nullptr if not present. Each array is
+     * mNumVertices in size if present.
+     */
     C_STRUCT aiColor4D *mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
 
-    /** Vertex texture coordinates, also known as UV channels.
-    * A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS per
-    * vertex. nullptr if not present. The array is mNumVertices in size.
-    */
+    /**
+     * @brief Vertex texture coordinates, also known as UV channels.
+     * 
+     * A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS per
+     * vertex. nullptr if not present. The array is mNumVertices in size.
+     */
     C_STRUCT aiVector3D *mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 
-    /** Specifies the number of components for a given UV channel.
-    * Up to three channels are supported (UVW, for accessing volume
-    * or cube maps). If the value is 2 for a given channel n, the
-    * component p.z of mTextureCoords[n][p] is set to 0.0f.
-    * If the value is 1 for a given channel, p.y is set to 0.0f, too.
-    * @note 4D coordinates are not supported
-    */
+    /**
+     * @brief Specifies the number of components for a given UV channel.
+     * 
+     * Up to three channels are supported (UVW, for accessing volume
+     * or cube maps). If the value is 2 for a given channel n, the
+     * component p.z of mTextureCoords[n][p] is set to 0.0f.
+     * If the value is 1 for a given channel, p.y is set to 0.0f, too.
+     * @note 4D coordinates are not supported
+     */
     unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 
-    /** The faces the mesh is constructed from.
-    * Each face refers to a number of vertices by their indices.
-    * This array is always present in a mesh, its size is given
-    * in mNumFaces. If the #AI_SCENE_FLAGS_NON_VERBOSE_FORMAT
-    * is NOT set each face references an unique set of vertices.
-    */
+    /**
+     * @brief The faces the mesh is constructed from.
+     * 
+     * Each face refers to a number of vertices by their indices.
+     * This array is always present in a mesh, its size is given
+     *  in mNumFaces. If the #AI_SCENE_FLAGS_NON_VERBOSE_FORMAT
+     * is NOT set each face references an unique set of vertices.
+     */
     C_STRUCT aiFace *mFaces;
 
-    /** The number of bones this mesh contains.
-    * Can be 0, in which case the mBones array is nullptr.
+    /**
+    * The number of bones this mesh contains. Can be 0, in which case the mBones array is nullptr.
     */
     unsigned int mNumBones;
 
-    /** The bones of this mesh.
-    * A bone consists of a name by which it can be found in the
-    * frame hierarchy and a set of vertex weights.
-    */
+    /**
+     * @brief The bones of this mesh.
+     * 
+     * A bone consists of a name by which it can be found in the
+     * frame hierarchy and a set of vertex weights.
+     */
     C_STRUCT aiBone **mBones;
 
-    /** The material used by this mesh.
+    /**
+     * @brief The material used by this mesh.
+     * 
      * A mesh uses only a single material. If an imported model uses
      * multiple materials, the import splits up the mesh. Use this value
      * as index into the scene's material list.
      */
     unsigned int mMaterialIndex;
 
-    /** Name of the mesh. Meshes can be named, but this is not a
+    /**
+     *  Name of the mesh. Meshes can be named, but this is not a
      *  requirement and leaving this field empty is totally fine.
      *  There are mainly three uses for mesh names:
      *   - some formats name nodes and meshes independently.
@@ -734,22 +786,24 @@ struct aiMesh {
      *      aids the caller at recovering the original mesh
      *      partitioning.
      *   - Vertex animations refer to meshes by their names.
-     **/
+     */
     C_STRUCT aiString mName;
 
-    /** The number of attachment meshes.
-     *  Currently known to work with loaders:
-     *   - Collada
-     *   - gltf
+    /**
+     * The number of attachment meshes.
+     * Currently known to work with loaders:
+     * - Collada
+     * - gltf
      */
     unsigned int mNumAnimMeshes;
 
-    /** Attachment meshes for this mesh, for vertex-based animation.
-     *  Attachment meshes carry replacement data for some of the
-     *  mesh'es vertex components (usually positions, normals).
-     *  Currently known to work with loaders:
-     *   - Collada
-     *   - gltf
+    /**
+     * Attachment meshes for this mesh, for vertex-based animation.
+     * Attachment meshes carry replacement data for some of the
+     * mesh'es vertex components (usually positions, normals).
+     * Currently known to work with loaders:
+     * - Collada
+     * - gltf
      */
     C_STRUCT aiAnimMesh **mAnimMeshes;
 
@@ -764,13 +818,14 @@ struct aiMesh {
      */
     C_STRUCT aiAABB mAABB;
 
-    /** Vertex UV stream names. Pointer to array of size AI_MAX_NUMBER_OF_TEXTURECOORDS
+    /**
+     * Vertex UV stream names. Pointer to array of size AI_MAX_NUMBER_OF_TEXTURECOORDS
      */
     C_STRUCT aiString **mTextureCoordsNames;
 
 #ifdef __cplusplus
 
-    //! Default constructor. Initializes all members to 0
+    //! The default class constructor.
     aiMesh() AI_NO_EXCEPT
             : mPrimitiveTypes(0),
               mNumVertices(0),
@@ -779,9 +834,9 @@ struct aiMesh {
               mNormals(nullptr),
               mTangents(nullptr),
               mBitangents(nullptr),
-              mColors(),
-              mTextureCoords(),
-              mNumUVComponents(),
+              mColors{nullptr},
+              mTextureCoords{nullptr},
+              mNumUVComponents{0},
               mFaces(nullptr),
               mNumBones(0),
               mBones(nullptr),
@@ -791,17 +846,10 @@ struct aiMesh {
               mMethod(aiMorphingMethod_UNKNOWN),
               mAABB(),
               mTextureCoordsNames(nullptr) {
-        for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
-            mNumUVComponents[a] = 0;
-            mTextureCoords[a] = nullptr;
-        }
-
-        for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
-            mColors[a] = nullptr;
-        }
+        // empty
     }
 
-    //! Deletes all storage allocated for the mesh
+    //! @brief The class destructor.
     ~aiMesh() {
         delete[] mVertices;
         delete[] mNormals;
@@ -842,44 +890,58 @@ struct aiMesh {
         delete[] mFaces;
     }
 
-    //! Check whether the mesh contains positions. Provided no special
-    //! scene flags are set, this will always be true
-    bool HasPositions() const { return mVertices != nullptr && mNumVertices > 0; }
+    //! @brief Check whether the mesh contains positions. Provided no special
+    //!        scene flags are set, this will always be true
+    //! @return true, if positions are stored, false if not.
+    bool HasPositions() const {
+        return mVertices != nullptr && mNumVertices > 0;
+    }
 
-    //! Check whether the mesh contains faces. If no special scene flags
-    //! are set this should always return true
-    bool HasFaces() const { return mFaces != nullptr && mNumFaces > 0; }
+    //! @brief Check whether the mesh contains faces. If no special scene flags
+    //!        are set this should always return true
+    //! @return true, if faces are stored, false if not.
+    bool HasFaces() const {
+        return mFaces != nullptr && mNumFaces > 0;
+    }
 
-    //! Check whether the mesh contains normal vectors
-    bool HasNormals() const { return mNormals != nullptr && mNumVertices > 0; }
+    //! @brief Check whether the mesh contains normal vectors
+    //! @return true, if normals are stored, false if not.
+    bool HasNormals() const {
+        return mNormals != nullptr && mNumVertices > 0;
+    }
 
-    //! Check whether the mesh contains tangent and bitangent vectors
+    //! @brief Check whether the mesh contains tangent and bitangent vectors.
+    //! 
     //! It is not possible that it contains tangents and no bitangents
     //! (or the other way round). The existence of one of them
     //! implies that the second is there, too.
-    bool HasTangentsAndBitangents() const { return mTangents != nullptr && mBitangents != nullptr && mNumVertices > 0; }
+    //! @return true, if tangents and bi-tangents are stored, false if not.
+    bool HasTangentsAndBitangents() const {
+        return mTangents != nullptr && mBitangents != nullptr && mNumVertices > 0;
+    }
 
-    //! Check whether the mesh contains a vertex color set
-    //! \param pIndex Index of the vertex color set
-    bool HasVertexColors(unsigned int pIndex) const {
-        if (pIndex >= AI_MAX_NUMBER_OF_COLOR_SETS) {
+    //! @brief Check whether the mesh contains a vertex color set
+    //! @param index    Index of the vertex color set
+    //! @return true, if vertex colors are stored, false if not.
+    bool HasVertexColors(unsigned int index) const {
+        if (index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
             return false;
-        } else {
-            return mColors[pIndex] != nullptr && mNumVertices > 0;
         }
+        return mColors[index] != nullptr && mNumVertices > 0;        
     }
 
-    //! Check whether the mesh contains a texture coordinate set
-    //! \param pIndex Index of the texture coordinates set
-    bool HasTextureCoords(unsigned int pIndex) const {
-        if (pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
+    //! @brief Check whether the mesh contains a texture coordinate set
+    //! @param index    Index of the texture coordinates set
+    //! @return true, if texture coordinates are stored, false if not.
+    bool HasTextureCoords(unsigned int index) const {
+        if (index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
             return false;
-        } else {
-            return mTextureCoords[pIndex] != nullptr && mNumVertices > 0;
         }
+        return (mTextureCoords[index] != nullptr && mNumVertices > 0);
     }
 
-    //! Get the number of UV channels the mesh contains
+    //! @brief Get the number of UV channels the mesh contains.
+    //! @return the number of stored uv-channels.
     unsigned int GetNumUVChannels() const {
         unsigned int n(0);
         while (n < AI_MAX_NUMBER_OF_TEXTURECOORDS && mTextureCoords[n]) {
@@ -889,7 +951,8 @@ struct aiMesh {
         return n;
     }
 
-    //! Get the number of vertex color channels the mesh contains
+    //! @brief Get the number of vertex color channels the mesh contains.
+    //! @return The number of stored color channels.
     unsigned int GetNumColorChannels() const {
         unsigned int n(0);
         while (n < AI_MAX_NUMBER_OF_COLOR_SETS && mColors[n]) {
@@ -898,13 +961,15 @@ struct aiMesh {
         return n;
     }
 
-    //! Check whether the mesh contains bones
+    //! @brief Check whether the mesh contains bones.
+    //! @return true, if bones are stored.
     bool HasBones() const {
         return mBones != nullptr && mNumBones > 0;
     }
 
-    //! Check whether the mesh contains a texture coordinate set name
-    //! \param pIndex Index of the texture coordinates set
+    //! @brief  Check whether the mesh contains a texture coordinate set name
+    //! @param pIndex Index of the texture coordinates set
+    //! @return true, if texture coordinates for the index exists.
     bool HasTextureCoordsName(unsigned int pIndex) const {
         if (mTextureCoordsNames == nullptr || pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
             return false;
@@ -912,9 +977,9 @@ struct aiMesh {
         return mTextureCoordsNames[pIndex] != nullptr;
     }
 
-    //! Set a texture coordinate set name
-    //! \param pIndex Index of the texture coordinates set
-    //! \param texCoordsName name of the texture coordinate set
+    //! @brief  Set a texture coordinate set name
+    //! @param pIndex Index of the texture coordinates set
+    //! @param texCoordsName name of the texture coordinate set
     void SetTextureCoordsName(unsigned int pIndex, const aiString &texCoordsName) {
         if (pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
             return;
@@ -939,30 +1004,46 @@ struct aiMesh {
         *mTextureCoordsNames[pIndex] = texCoordsName;
     }
 
-    //! Get a texture coordinate set name
-    //! \param pIndex Index of the texture coordinates set
-    const aiString *GetTextureCoordsName(unsigned int pIndex) const {
-        if (mTextureCoordsNames == nullptr || pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
+    //! @brief  Get a texture coordinate set name
+    //! @param  pIndex Index of the texture coordinates set
+    //! @return The texture coordinate name.
+    const aiString *GetTextureCoordsName(unsigned int index) const {
+        if (mTextureCoordsNames == nullptr || index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
             return nullptr;
         }
 
-        return mTextureCoordsNames[pIndex];
+        return mTextureCoordsNames[index];
     }
 
 #endif // __cplusplus
 };
 
+/**
+ * @brief  A skeleton bone represents a single bone is a skeleton structure.
+ *
+ * Skeleton-Animations can be represented via a skeleton struct, which describes
+ * a hierarchical tree assembled from skeleton bones. A bone is linked to a mesh.
+ * The bone knows its parent bone. If there is no parent bone the parent id is
+ * marked with -1.
+ * The skeleton-bone stores a pointer to its used armature. If there is no
+ * armature this value if set to nullptr.
+ * A skeleton bone stores its offset-matrix, which is the absolute transformation
+ * for the bone. The bone stores the locale transformation to its parent as well.
+ * You can compute the offset matrix by multiplying the hierarchy like:
+ * Tree: s1 -> s2 -> s3
+ * Offset-Matrix s3 = locale-s3 * locale-s2 * locale-s1
+ */
 struct aiSkeletonBone {
     /// The parent bone index, is -1 one if this bone represents the root bone.
     int mParent;
 
 
 #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
-    /// The bone armature node - used for skeleton conversion
+    /// @brief The bone armature node - used for skeleton conversion
     /// you must enable aiProcess_PopulateArmatureData to populate this
     C_STRUCT aiNode *mArmature;
 
-    /// The bone node in the scene - used for skeleton conversion
+    /// @brief The bone node in the scene - used for skeleton conversion
     /// you must enable aiProcess_PopulateArmatureData to populate this
     C_STRUCT aiNode *mNode;
 
@@ -993,6 +1074,7 @@ struct aiSkeletonBone {
     C_STRUCT aiMatrix4x4 mLocalMatrix;
 
 #ifdef __cplusplus
+    ///	@brief The class constructor.
     aiSkeletonBone() :
             mParent(-1),
 #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
@@ -1007,6 +1089,22 @@ struct aiSkeletonBone {
         // empty
     }
 
+    /// @brief The class constructor with its parent
+    /// @param  parent      The parent node index.
+    aiSkeletonBone(unsigned int parent) :
+            mParent(parent),
+#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
+            mArmature(nullptr),
+            mNode(nullptr),
+#endif
+            mNumnWeights(0),
+            mMeshId(nullptr),
+            mWeights(nullptr),
+            mOffsetMatrix(),
+            mLocalMatrix() {
+        // empty
+    }
+    /// @brief The class destructor.
     ~aiSkeletonBone() {
         delete[] mWeights;
         mWeights = nullptr;
@@ -1014,34 +1112,45 @@ struct aiSkeletonBone {
 #endif // __cplusplus
 };
 /**
- *  @brief
+ * @brief A skeleton represents the bone hierarchy of an animation.
+ *
+ * Skeleton animations can be described as a tree of bones:
+ *                  root
+ *                    |
+ *                  node1
+ *                  /   \
+ *               node3  node4
+ * If you want to calculate the transformation of node three you need to compute the
+ * transformation hierarchy for the transformation chain of node3:
+ * root->node1->node3
+ * Each node is represented as a skeleton instance.
  */
 struct aiSkeleton {
     /**
-     *
+     *  @brief The name of the skeleton instance.
      */
     C_STRUCT aiString mName;
 
     /**
-     *
+     *  @brief  The number of bones in the skeleton.
      */
     unsigned int mNumBones;
 
     /**
-     *
+     *  @brief The bone instance in the skeleton.
      */
     C_STRUCT aiSkeletonBone **mBones;
 
 #ifdef __cplusplus
     /**
-     *
+     *  @brief The class constructor.
      */
     aiSkeleton() AI_NO_EXCEPT : mName(), mNumBones(0), mBones(nullptr) {
         // empty
     }
 
     /**
-     *
+     *  @brief  The class destructor.
      */
     ~aiSkeleton() {
         delete[] mBones;
@@ -1051,4 +1160,6 @@ struct aiSkeleton {
 #ifdef __cplusplus
 }
 #endif //! extern "C"
+
 #endif // AI_MESH_H_INC
+

+ 37 - 1
include/assimp/metadata.h

@@ -56,6 +56,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <stdint.h>
 #endif
 
+#include <assimp/quaternion.h>
+
 // -------------------------------------------------------------------------------
 /**
   * Enum used to distinguish data types
@@ -70,7 +72,9 @@ typedef enum aiMetadataType {
     AI_AISTRING = 5,
     AI_AIVECTOR3D = 6,
     AI_AIMETADATA = 7,
-    AI_META_MAX = 8,
+    AI_INT64 = 8,
+    AI_UINT32 = 9,
+    AI_META_MAX = 10,
 
 #ifndef SWIG
     FORCE_32BIT = INT_MAX
@@ -133,6 +137,12 @@ inline aiMetadataType GetAiType(const aiVector3D &) {
 inline aiMetadataType GetAiType(const aiMetadata &) {
     return AI_AIMETADATA;
 }
+inline aiMetadataType GetAiType(int64_t) {
+    return AI_INT64;
+}
+inline aiMetadataType GetAiType(uint32_t) {
+    return AI_UINT32;
+}
 
 #endif // __cplusplus
 
@@ -215,6 +225,16 @@ struct aiMetadata {
                 rhs.Get<aiMetadata>(static_cast<unsigned int>(i), v);
                 mValues[i].mData = new aiMetadata(v);
             } break;
+            case AI_INT64: {
+                int64_t v;
+                ::memcpy(&v, rhs.mValues[i].mData, sizeof(int64_t));
+                mValues[i].mData = new int64_t(v);
+            } break;
+            case AI_UINT32: {
+                uint32_t v;
+                ::memcpy(&v, rhs.mValues[i].mData, sizeof(uint32_t));
+                mValues[i].mData = new uint32_t(v);
+            } break;
 #ifndef SWIG
             case FORCE_32BIT:
 #endif
@@ -267,6 +287,12 @@ struct aiMetadata {
                 case AI_AIMETADATA:
                     delete static_cast<aiMetadata *>(data);
                     break;
+                case AI_INT64:
+                    delete static_cast<int64_t *>(data);
+                    break;
+                case AI_UINT32:
+                    delete static_cast<uint32_t *>(data);
+                    break;
 #ifndef SWIG
                 case FORCE_32BIT:
 #endif
@@ -510,6 +536,16 @@ struct aiMetadata {
                     return false;
                 }
             } break;
+            case AI_INT64: {
+                if (*static_cast<int64_t *>(lhs.mValues[i].mData) != *static_cast<int64_t *>(rhs.mValues[i].mData)) {
+                    return false;
+                }
+            } break;
+            case AI_UINT32: {
+                if (*static_cast<uint32_t *>(lhs.mValues[i].mData) != *static_cast<uint32_t *>(rhs.mValues[i].mData)) {
+                    return false;
+                }
+            } break;
 #ifndef SWIG
             case FORCE_32BIT:
 #endif

+ 1 - 1
port/PyAssimp/README.md

@@ -76,7 +76,7 @@ $ python setup.py install
 ```
 
 PyAssimp requires a assimp dynamic library (`DLL` on windows,
-`.so` on linux, `.dynlib` on macOS) in order to work. The default search directories are:
+`.so` on linux, `.dylib` on macOS) in order to work. The default search directories are:
   - the current directory
   - on linux additionally: `/usr/lib`, `/usr/local/lib`,
     `/usr/lib/x86_64-linux-gnu`

+ 1 - 1
port/PyAssimp/README.rst

@@ -81,7 +81,7 @@ Install ``pyassimp`` by running:
     $ python setup.py install
 
 PyAssimp requires a assimp dynamic library (``DLL`` on windows, ``.so``
-on linux, ``.dynlib`` on macOS) in order to work. The default search
+on linux, ``.dylib`` on macOS) in order to work. The default search
 directories are:
 
 -  the current directory

+ 30 - 6
test/unit/utMetadata.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -84,7 +82,7 @@ TEST_F( utMetadata, allocTest ) {
 }
 
 TEST_F( utMetadata, get_set_pod_Test ) {
-    m_data = aiMetadata::Alloc( 5 );
+    m_data = aiMetadata::Alloc( 7 );
 
     // int, 32 bit
     unsigned int index( 0 );
@@ -137,6 +135,28 @@ TEST_F( utMetadata, get_set_pod_Test ) {
     EXPECT_TRUE( success );
     EXPECT_DOUBLE_EQ( 3.0, result_double );
 
+    // int64_t
+    index++;
+    const std::string key_int64 = "test_int64";
+    int64_t val_int64 = 64;
+    success = m_data->Set(index, key_int64, val_int64);
+    EXPECT_TRUE(success);
+    int64_t result_int64(0);
+    success = m_data->Get(key_int64, result_int64);
+    EXPECT_TRUE(success);
+    EXPECT_EQ(result_int64, val_int64);
+
+    // uint32
+    index++;
+    const std::string key_uint32 = "test_uint32";
+    int64_t val_uint32 = 32;
+    success = m_data->Set(index, key_uint32, val_uint32);
+    EXPECT_TRUE(success);
+    int64_t result_uint32(0);
+    success = m_data->Get(key_uint32, result_uint32);
+    EXPECT_TRUE(success);
+    EXPECT_EQ(result_uint32, val_uint32);
+
     // error
     int result;
     success = m_data->Get( "bla", result );
@@ -181,6 +201,7 @@ TEST_F( utMetadata, get_set_aiVector3D_Test ) {
     EXPECT_TRUE( success );
 }
 
+
 TEST_F( utMetadata, copy_test ) {
     m_data = aiMetadata::Alloc( AI_META_MAX );
     bool bv = true;
@@ -199,9 +220,12 @@ TEST_F( utMetadata, copy_test ) {
     m_data->Set( 6, "aiVector3D", vecVal );
     aiMetadata metaVal;
     m_data->Set( 7, "aiMetadata", metaVal );
-
-    aiMetadata copy( *m_data );
-    EXPECT_EQ( 8u, copy.mNumProperties );
+    int64_t i64 = 64;
+    m_data->Set(8, "int64_t", i64);
+    uint32_t ui32 = 32;
+    m_data->Set(9, "uint32_t", ui32);
+    aiMetadata copy(*m_data);
+    EXPECT_EQ( 10u, copy.mNumProperties );
 
     // bool test
     {

+ 10 - 8
tools/assimp_cmd/Info.cpp

@@ -55,26 +55,28 @@ constexpr char AICMD_MSG_INFO_HELP_E[] =
         "\t-v,--verbose: Print verbose info such as node transform data\n"
         "\t-s, --silent: Print only minimal info\n";
 
-constexpr char TREE_BRANCH_ASCII[] = "|-";
-constexpr char TREE_BRANCH_UTF8[] = "\xe2\x94\x9c\xe2\x95\xb4";
-constexpr char TREE_STOP_ASCII[] = "'-";
-constexpr char TREE_STOP_UTF8[] = "\xe2\x94\x94\xe2\x95\xb4";
-constexpr char TREE_CONTINUE_ASCII[] = "| ";
-constexpr char TREE_CONTINUE_UTF8[] = "\xe2\x94\x82 ";
 
 // note: by default this is using utf-8 text.
 // this is well supported on pretty much any linux terminal.
 // if this causes problems on some platform,
 // put an #ifdef to use the ascii version for that platform.
 #ifdef _WIN32
+constexpr char TREE_BRANCH_ASCII[] = "|-";
+constexpr char TREE_STOP_ASCII[] = "'-";
+constexpr char TREE_CONTINUE_ASCII[] = "| ";
+
 const char *TREE_BRANCH = TREE_BRANCH_ASCII;
 const char *TREE_STOP = TREE_STOP_ASCII;
 const char *TREE_CONTINUE = TREE_CONTINUE_ASCII;
-#else
+#else  // _WIN32
+constexpr char TREE_BRANCH_UTF8[] = "\xe2\x94\x9c\xe2\x95\xb4";
+constexpr char TREE_STOP_UTF8[] = "\xe2\x94\x94\xe2\x95\xb4";
+constexpr char TREE_CONTINUE_UTF8[] = "\xe2\x94\x82 ";
+
 const char *TREE_BRANCH = TREE_BRANCH_UTF8;
 const char *TREE_STOP = TREE_STOP_UTF8;
 const char *TREE_CONTINUE = TREE_CONTINUE_UTF8;
-#endif
+#endif  // _WIN32
 
 // -----------------------------------------------------------------------------------
 unsigned int CountNodes(const aiNode *root) {