Browse Source

Merge branch 'master' into M3DasciiByDefault

Kim Kulling 4 years ago
parent
commit
b70f195805
76 changed files with 561 additions and 533 deletions
  1. 8 7
      CMakeLists.txt
  2. 1 1
      code/AssetLib/3DS/3DSConverter.cpp
  3. 3 2
      code/AssetLib/3DS/3DSExporter.cpp
  4. 3 13
      code/AssetLib/3DS/3DSHelper.h
  5. 10 4
      code/AssetLib/3DS/3DSLoader.cpp
  6. 53 50
      code/AssetLib/3MF/3MFXmlTags.h
  7. 26 11
      code/AssetLib/3MF/D3MFExporter.cpp
  8. 107 99
      code/AssetLib/3MF/D3MFImporter.cpp
  9. 1 1
      code/AssetLib/3MF/D3MFImporter.h
  10. 3 3
      code/AssetLib/3MF/D3MFOpcPackage.cpp
  11. 3 6
      code/AssetLib/AMF/AMFImporter.cpp
  12. 0 1
      code/AssetLib/AMF/AMFImporter.hpp
  13. 2 2
      code/AssetLib/AMF/AMFImporter_Postprocess.cpp
  14. 6 0
      code/AssetLib/ASE/ASEParser.cpp
  15. 1 1
      code/AssetLib/Assbin/AssbinLoader.cpp
  16. 2 2
      code/AssetLib/BVH/BVHLoader.cpp
  17. 3 9
      code/AssetLib/Blender/BlenderLoader.cpp
  18. 0 1
      code/AssetLib/Blender/BlenderLoader.h
  19. 23 41
      code/AssetLib/C4D/C4DImporter.cpp
  20. 15 24
      code/AssetLib/C4D/C4DImporter.h
  21. 7 1
      code/AssetLib/COB/COBLoader.cpp
  22. 1 1
      code/AssetLib/Collada/ColladaLoader.cpp
  23. 1 1
      code/AssetLib/Collada/ColladaParser.cpp
  24. 3 3
      code/AssetLib/FBX/FBXExporter.cpp
  25. 1 1
      code/AssetLib/FBX/FBXMaterial.cpp
  26. 2 6
      code/AssetLib/HMP/HMPLoader.cpp
  27. 1 1
      code/AssetLib/IFC/IFCLoader.cpp
  28. 2 2
      code/AssetLib/Irr/IRRLoader.cpp
  29. 2 2
      code/AssetLib/Irr/IRRMeshLoader.cpp
  30. 1 1
      code/AssetLib/M3D/M3DImporter.cpp
  31. 21 23
      code/AssetLib/MD2/MD2Loader.cpp
  32. 1 1
      code/AssetLib/MD3/MD3Loader.cpp
  33. 10 10
      code/AssetLib/MDC/MDCLoader.cpp
  34. 4 3
      code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp
  35. 16 4
      code/AssetLib/MDL/MDLLoader.cpp
  36. 4 7
      code/AssetLib/MMD/MMDPmxParser.cpp
  37. 6 1
      code/AssetLib/MS3D/MS3DLoader.cpp
  38. 7 1
      code/AssetLib/NDO/NDOLoader.cpp
  39. 14 0
      code/AssetLib/OpenGEX/OpenGEXImporter.cpp
  40. 1 1
      code/AssetLib/Ply/PlyLoader.cpp
  41. 1 1
      code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp
  42. 8 2
      code/AssetLib/Q3D/Q3DLoader.cpp
  43. 10 4
      code/AssetLib/SIB/SIBImporter.cpp
  44. 2 2
      code/AssetLib/X/XFileImporter.cpp
  45. 2 2
      code/AssetLib/X/XFileParser.cpp
  46. 0 4
      code/AssetLib/X3D/X3DImporter.cpp
  47. 0 1
      code/AssetLib/X3D/X3DImporter.hpp
  48. 1 1
      code/AssetLib/XGL/XGLLoader.cpp
  49. 2 2
      code/CApi/CInterfaceIOWrapper.cpp
  50. 4 18
      code/Common/BaseImporter.cpp
  51. 15 2
      code/Common/ImporterRegistry.cpp
  52. 4 2
      code/Common/SceneCombiner.cpp
  53. 3 0
      code/PostProcessing/GenFaceNormalsProcess.cpp
  54. 1 0
      code/PostProcessing/GenFaceNormalsProcess.h
  55. 3 0
      code/PostProcessing/GenVertexNormalsProcess.cpp
  56. 1 0
      code/PostProcessing/GenVertexNormalsProcess.h
  57. 1 1
      code/PostProcessing/PretransformVertices.cpp
  58. 1 1
      contrib/draco/src/draco/io/parser_utils.cc
  59. 2 2
      contrib/draco/src/draco/io/ply_reader.cc
  60. 1 1
      contrib/gtest/include/gtest/internal/gtest-param-util.h
  61. 13 34
      contrib/openddlparser/code/OpenDDLParser.cpp
  62. 1 1
      contrib/zip/src/zip.c
  63. 1 0
      doc/Fileformats.md
  64. 2 37
      include/assimp/BaseImporter.h
  65. 1 1
      include/assimp/ParsingUtils.h
  66. 4 4
      include/assimp/StringComparison.h
  67. 31 4
      include/assimp/StringUtils.h
  68. 6 1
      include/assimp/XmlParser.h
  69. 3 2
      include/assimp/fast_atof.h
  70. 2 2
      port/PyAssimp/pyassimp/structs.py
  71. 41 42
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
  72. 1 3
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h
  73. BIN
      test/test.3mf
  74. 11 2
      test/unit/utStringUtils.cpp
  75. 5 4
      tools/assimp_cmd/ImageExtractor.cpp
  76. 2 2
      tools/assimp_view/Material.cpp

+ 8 - 7
CMakeLists.txt

@@ -527,12 +527,12 @@ ENDIF()
 MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
 
 SET ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER OFF CACHE BOOL
-  "Build the C4D importer, which relies on the non-free Melange SDK."
+  "Build the C4D importer, which relies on the non-free Cineware SDK."
 )
 
 IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
   IF ( MSVC )
-    SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes")
+    SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/includes")
 
     # pick the correct prebuilt library
     IF(MSVC15)
@@ -551,22 +551,23 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
       )
     ENDIF()
 
-    SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/libraries/win")
+    SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/libraries/win")
 
     SET(C4D_DEBUG_LIBRARIES
-      "${C4D_LIB_BASE_PATH}/melangelib${C4D_LIB_POSTFIX}/melangelib_debug.lib"
+      "${C4D_LIB_BASE_PATH}/cinewarelib${C4D_LIB_POSTFIX}/cinewarelib_debug.lib"
       "${C4D_LIB_BASE_PATH}/jpeglib${C4D_LIB_POSTFIX}/jpeglib_debug.lib"
     )
     SET(C4D_RELEASE_LIBRARIES
-      "${C4D_LIB_BASE_PATH}/melangelib${C4D_LIB_POSTFIX}/melangelib_release.lib"
+      "${C4D_LIB_BASE_PATH}/cinewarelib${C4D_LIB_POSTFIX}/cinewarelib_release.lib"
       "${C4D_LIB_BASE_PATH}/jpeglib${C4D_LIB_POSTFIX}/jpeglib_release.lib"
     )
 
-    # winsock and winmm are necessary dependencies of melange (this is undocumented, but true.)
+    # winsock and winmm are necessary (and undocumented) dependencies of Cineware SDK because
+    # it can be used to communicate with a running Cinema 4D instance
     SET(C4D_EXTRA_LIBRARIES WSock32.lib Winmm.lib)
   ELSE ()
     MESSAGE( FATAL_ERROR
-      "C4D is currently only available on Windows with melange SDK installed in contrib/Melange"
+      "C4D is currently only available on Windows with Cineware SDK installed in contrib/Cineware"
     )
   ENDIF ()
 ELSE ()

+ 1 - 1
code/AssetLib/3DS/3DSConverter.cpp

@@ -69,7 +69,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() {
     for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
         std::string s = mScene->mMaterials[i].mName;
         for (std::string::iterator it = s.begin(); it != s.end(); ++it) {
-            *it = static_cast<char>(::tolower(*it));
+            *it = static_cast<char>(::tolower(static_cast<unsigned char>(*it)));
         }
 
         if (std::string::npos == s.find("default")) continue;

+ 3 - 2
code/AssetLib/3DS/3DSExporter.cpp

@@ -102,13 +102,14 @@ private:
 // preserves the mesh's given name if it has one. |index| is the index
 // of the mesh in |aiScene::mMeshes|.
 std::string GetMeshName(const aiMesh &mesh, unsigned int index, const aiNode &node) {
-    static const std::string underscore = "_";
+    static const char underscore = '_';
     char postfix[10] = { 0 };
     ASSIMP_itoa10(postfix, index);
 
     std::string result = node.mName.C_Str();
     if (mesh.mName.length > 0) {
-        result += underscore + mesh.mName.C_Str();
+        result += underscore;
+        result += mesh.mName.C_Str();
     }
     return result + underscore + postfix;
 }

+ 3 - 13
code/AssetLib/3DS/3DSHelper.h

@@ -61,20 +61,10 @@ namespace D3DS {
 #include <assimp/Compiler/pushpack1.h>
 
 // ---------------------------------------------------------------------------
-/** Discreet3DS class: Helper class for loading 3ds files. Defines chunks
-*  and data structures.
+/** Defines chunks and data structures.
 */
-class Discreet3DS {
-private:
-    Discreet3DS() AI_NO_EXCEPT {
-        // empty
-    }
-
-    ~Discreet3DS() {
-        // empty
-    }
+namespace Discreet3DS {
 
-public:
     //! data structure for a single chunk in a .3ds file
     struct Chunk {
         uint16_t Flag;
@@ -314,7 +304,7 @@ public:
         // camera sub-chunks
         CHUNK_CAM_RANGES = 0x4720
     };
-};
+}
 
 // ---------------------------------------------------------------------------
 /** Helper structure representing a 3ds mesh face */

+ 10 - 4
code/AssetLib/3DS/3DSLoader.cpp

@@ -143,7 +143,13 @@ void Discreet3DSImporter::SetupProperties(const Importer * /*pImp*/) {
 // Imports the given file into the given scene structure.
 void Discreet3DSImporter::InternReadFile(const std::string &pFile,
         aiScene *pScene, IOSystem *pIOHandler) {
-    StreamReaderLE theStream(pIOHandler->Open(pFile, "rb"));
+
+    auto theFile = pIOHandler->Open(pFile, "rb");
+    if (!theFile) {
+        throw DeadlyImportError("3DS: Could not open ", pFile);
+    }
+
+    StreamReaderLE theStream(theFile);
 
     // We should have at least one chunk
     if (theStream.GetRemainingSize() < 16) {
@@ -981,9 +987,9 @@ void Discreet3DSImporter::ParseMeshChunk() {
         mMesh.mMat.a3 = stream->GetF4();
         mMesh.mMat.b3 = stream->GetF4();
         mMesh.mMat.c3 = stream->GetF4();
-        mMesh.mMat.d1 = stream->GetF4();
-        mMesh.mMat.d2 = stream->GetF4();
-        mMesh.mMat.d3 = stream->GetF4();
+        mMesh.mMat.a4 = stream->GetF4();
+        mMesh.mMat.b4 = stream->GetF4();
+        mMesh.mMat.c4 = stream->GetF4();
     } break;
 
     case Discreet3DS::CHUNK_MAPLIST: {

+ 53 - 50
code/AssetLib/3MF/3MFXmlTags.h

@@ -44,63 +44,66 @@ namespace Assimp {
 namespace D3MF {
 
 namespace XmlTag {
+    // Root tag
+    const char* const RootTag = "3MF";
+
     // Meta-data
-    static const std::string meta = "metadata";
-    static const std::string meta_name = "name";
+    const char* const meta = "metadata";
+    const char* const meta_name = "name";
 
     // Model-data specific tags
-    static const std::string model = "model";
-    static const std::string model_unit = "unit";
-    static const std::string metadata = "metadata";
-    static const std::string resources = "resources";
-    static const std::string object = "object";
-    static const std::string mesh = "mesh";
-    static const std::string components = "components";
-    static const std::string component = "component";
-    static const std::string vertices = "vertices";
-    static const std::string vertex = "vertex";
-    static const std::string triangles = "triangles";
-    static const std::string triangle = "triangle";
-    static const std::string x = "x";
-    static const std::string y = "y";
-    static const std::string z = "z";
-    static const std::string v1 = "v1";
-    static const std::string v2 = "v2";
-    static const std::string v3 = "v3";
-    static const std::string id = "id";
-    static const std::string pid = "pid";
-    static const std::string pindex = "pindex";
-    static const std::string p1 = "p1";
-    static const std::string name = "name";
-    static const std::string type = "type";
-    static const std::string build = "build";
-    static const std::string item = "item";
-    static const std::string objectid = "objectid";
-    static const std::string transform = "transform";
+    const char* const model = "model";
+    const char* const model_unit = "unit";
+    const char* const metadata = "metadata";
+    const char* const resources = "resources";
+    const char* const object = "object";
+    const char* const mesh = "mesh";
+    const char* const components = "components";
+    const char* const component = "component";
+    const char* const vertices = "vertices";
+    const char* const vertex = "vertex";
+    const char* const triangles = "triangles";
+    const char* const triangle = "triangle";
+    const char* const x = "x";
+    const char* const y = "y";
+    const char* const z = "z";
+    const char* const v1 = "v1";
+    const char* const v2 = "v2";
+    const char* const v3 = "v3";
+    const char* const id = "id";
+    const char* const pid = "pid";
+    const char* const pindex = "pindex";
+    const char* const p1 = "p1";
+    const char* const name = "name";
+    const char* const type = "type";
+    const char* const build = "build";
+    const char* const item = "item";
+    const char* const objectid = "objectid";
+    const char* const transform = "transform";
 
     // Material definitions
-    static const std::string basematerials = "basematerials";
-    static const std::string basematerials_id = "id";
-    static const std::string basematerials_base = "base";
-    static const std::string basematerials_name = "name";
-    static const std::string basematerials_displaycolor = "displaycolor";
+    const char* const basematerials = "basematerials";
+    const char* const basematerials_id = "id";
+    const char* const basematerials_base = "base";
+    const char* const basematerials_name = "name";
+    const char* const basematerials_displaycolor = "displaycolor";
 
     // Meta info tags
-    static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
-    static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
-    static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
-    static const std::string SCHEMA_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships";
-    static const std::string RELS_RELATIONSHIP_CONTAINER = "Relationships";
-    static const std::string RELS_RELATIONSHIP_NODE = "Relationship";
-    static const std::string RELS_ATTRIB_TARGET = "Target";
-    static const std::string RELS_ATTRIB_TYPE = "Type";
-    static const std::string RELS_ATTRIB_ID = "Id";
-    static const std::string PACKAGE_START_PART_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel";
-    static const std::string PACKAGE_PRINT_TICKET_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/printticket";
-    static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
-    static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
-    static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
-}
+    const char* const CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
+    const char* const ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
+    const char* const SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
+    const char* const SCHEMA_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships";
+    const char* const RELS_RELATIONSHIP_CONTAINER = "Relationships";
+    const char* const RELS_RELATIONSHIP_NODE = "Relationship";
+    const char* const RELS_ATTRIB_TARGET = "Target";
+    const char* const RELS_ATTRIB_TYPE = "Type";
+    const char* const RELS_ATTRIB_ID = "Id";
+    const char* const PACKAGE_START_PART_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel";
+    const char* const PACKAGE_PRINT_TICKET_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/printticket";
+    const char* const PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
+    const char* const PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
+    const char* const PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
+    }
 
 } // Namespace D3MF
 } // Namespace Assimp

+ 26 - 11
code/AssetLib/3MF/D3MFExporter.cpp

@@ -307,18 +307,26 @@ void D3MFExporter::writeMesh(aiMesh *mesh) {
         return;
     }
 
-    mModelOutput << "<" << XmlTag::mesh << ">" << std::endl;
-    mModelOutput << "<" << XmlTag::vertices << ">" << std::endl;
+    mModelOutput << "<"
+                 << XmlTag::mesh
+                 << ">" << "\n";
+    mModelOutput << "<"
+                 << XmlTag::vertices
+                 << ">" << "\n";
     for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
         writeVertex(mesh->mVertices[i]);
     }
-    mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
+    mModelOutput << "</"
+                 << XmlTag::vertices << ">"
+                 << "\n";
 
     const unsigned int matIdx(mesh->mMaterialIndex);
 
     writeFaces(mesh, matIdx);
 
-    mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
+    mModelOutput << "</"
+                 << XmlTag::mesh << ">"
+                 << "\n";
 }
 
 void D3MFExporter::writeVertex(const aiVector3D &pos) {
@@ -334,27 +342,34 @@ void D3MFExporter::writeFaces(aiMesh *mesh, unsigned int matIdx) {
     if (!mesh->HasFaces()) {
         return;
     }
-    mModelOutput << "<" << XmlTag::triangles << ">" << std::endl;
+    mModelOutput << "<"
+                 << XmlTag::triangles << ">"
+                 << "\n";
     for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
         aiFace &currentFace = mesh->mFaces[i];
         mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\""
                      << currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2]
                      << "\" pid=\"1\" p1=\"" + ai_to_string(matIdx) + "\" />";
-        mModelOutput << std::endl;
+        mModelOutput << "\n";
     }
-    mModelOutput << "</" << XmlTag::triangles << ">";
-    mModelOutput << std::endl;
+    mModelOutput << "</"
+                 << XmlTag::triangles
+                 << ">";
+    mModelOutput << "\n";
 }
 
 void D3MFExporter::writeBuild() {
-    mModelOutput << "<" << XmlTag::build << ">" << std::endl;
+    mModelOutput << "<"
+                 << XmlTag::build
+                 << ">"
+                 << "\n";
 
     for (size_t i = 0; i < mBuildItems.size(); ++i) {
         mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>";
-        mModelOutput << std::endl;
+        mModelOutput << "\n";
     }
     mModelOutput << "</" << XmlTag::build << ">";
-    mModelOutput << std::endl;
+    mModelOutput << "\n";
 }
 
 void D3MFExporter::zipContentType(const std::string &filename) {

+ 107 - 99
code/AssetLib/3MF/D3MFImporter.cpp

@@ -42,6 +42,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
 
 #include "D3MFImporter.h"
+#include "3MFXmlTags.h"
+#include "D3MFOpcPackage.h"
 
 #include <assimp/StringComparison.h>
 #include <assimp/StringUtils.h>
@@ -51,17 +53,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/IOSystem.hpp>
+#include <assimp/fast_atof.h>
+
 #include <cassert>
 #include <map>
 #include <memory>
 #include <string>
 #include <vector>
-
-#include "3MFXmlTags.h"
-#include "D3MFOpcPackage.h"
-#include <assimp/fast_atof.h>
-
 #include <iomanip>
+#include <string.h>
 
 namespace Assimp {
 namespace D3MF {
@@ -72,32 +72,39 @@ enum class ResourceType {
     RT_Unknown
 }; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...)
 
-class Resource
-{
+class Resource {
 public:
-    Resource(int id) :
-            mId(id) {}
+    int mId;
 
-    virtual ~Resource() {}
+    Resource(int id) :
+            mId(id) {
+        // empty
+    }
 
-    int mId;
+    virtual ~Resource() {
+        // empty
+    }
 
-    virtual ResourceType getType() {
+    virtual ResourceType getType() const {
         return ResourceType::RT_Unknown;
     }
 };
 
 class BaseMaterials : public Resource {
 public:
+    std::vector<aiMaterial *> mMaterials;
+    std::vector<unsigned int> mMaterialIndex;
+
     BaseMaterials(int id) :
             Resource(id),
             mMaterials(),
-            mMaterialIndex() {}
+            mMaterialIndex() {
+        // empty
+    }
 
-    std::vector<aiMaterial *> mMaterials;
-    std::vector<unsigned int> mMaterialIndex;
+    ~BaseMaterials() = default;
 
-    virtual ResourceType getType() {
+    ResourceType getType() const override {
         return ResourceType::RT_BaseMaterials;
     }
 };
@@ -109,24 +116,26 @@ struct Component {
 
 class Object : public Resource {
 public:
-    std::vector<aiMesh*> mMeshes;
+    std::vector<aiMesh *> mMeshes;
     std::vector<unsigned int> mMeshIndex;
     std::vector<Component> mComponents;
     std::string mName;
 
     Object(int id) :
             Resource(id),
-            mName(std::string("Object_") + ai_to_string(id)) {}
+            mName(std::string("Object_") + ai_to_string(id)) {
+        // empty
+    }
+
+    ~Object() = default;
 
-    virtual ResourceType getType() {
+    ResourceType getType() const override {
         return ResourceType::RT_Object;
     }
 };
 
-
 class XmlSerializer {
 public:
-
     XmlSerializer(XmlParser *xmlParser) :
             mResourcesDictionnary(),
             mMaterialCount(0),
@@ -136,7 +145,7 @@ public:
     }
 
     ~XmlSerializer() {
-        for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
+        for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it ) {
             delete it->second;
         }
     }
@@ -146,28 +155,28 @@ public:
             return;
         }
 
-        scene->mRootNode = new aiNode("3MF");
+        scene->mRootNode = new aiNode(XmlTag::RootTag);
 
-        XmlNode node = mXmlParser->getRootNode().child("model");
+        XmlNode node = mXmlParser->getRootNode().child(XmlTag::model);
         if (node.empty()) {
             return;
         }
-        XmlNode resNode = node.child("resources");
-        for (XmlNode currentNode = resNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
-            const std::string &currentNodeName = currentNode.name();
-            if (currentNodeName == D3MF::XmlTag::object) {
-                ReadObject(currentNode);;
-            } else if (currentNodeName == D3MF::XmlTag::basematerials) {
+        XmlNode resNode = node.child(XmlTag::resources);
+        for (auto &currentNode : resNode.children()) {
+            const std::string currentNodeName = currentNode.name();
+            if (currentNodeName == XmlTag::object) {
+                ReadObject(currentNode);
+            } else if (currentNodeName == XmlTag::basematerials) {
                 ReadBaseMaterials(currentNode);
-            } else if (currentNodeName == D3MF::XmlTag::meta) {
+            } else if (currentNodeName == XmlTag::meta) {
                 ReadMetadata(currentNode);
             }
         }
 
-        XmlNode buildNode = node.child("build");
-        for (XmlNode currentNode = buildNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
-            const std::string &currentNodeName = currentNode.name();
-            if (currentNodeName == D3MF::XmlTag::item) {
+        XmlNode buildNode = node.child(XmlTag::build);
+        for (auto &currentNode : buildNode.children()) {
+            const std::string currentNodeName = currentNode.name();
+            if (currentNodeName == XmlTag::item) {
                 int objectId = -1;
                 std::string transformationMatrixStr;
                 aiMatrix4x4 transformationMatrix;
@@ -186,10 +195,9 @@ public:
             }
         }
 
-
         // import the metadata
         if (!mMetaData.empty()) {
-            const size_t numMeta(mMetaData.size());
+            const size_t numMeta = mMetaData.size();
             scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
             for (size_t i = 0; i < numMeta; ++i) {
                 aiString val(mMetaData[i].value);
@@ -201,22 +209,22 @@ public:
         scene->mNumMeshes = static_cast<unsigned int>(mMeshCount);
         if (scene->mNumMeshes != 0) {
             scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
-            for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
+            for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it) {
                 if (it->second->getType() == ResourceType::RT_Object) {
-                    Object *obj = static_cast<Object*>(it->second);
+                    Object *obj = static_cast<Object *>(it->second);
+                    ai_assert(nullptr != obj);
                     for (unsigned int i = 0; i < obj->mMeshes.size(); ++i) {
                         scene->mMeshes[obj->mMeshIndex[i]] = obj->mMeshes[i];
                     }
                 }
             }
         }
-        
 
         // import the materials
-        scene->mNumMaterials = static_cast<unsigned int>(mMaterialCount);
+        scene->mNumMaterials = mMaterialCount;
         if (scene->mNumMaterials != 0) {
             scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
-            for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
+            for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it) {
                 if (it->second->getType() == ResourceType::RT_BaseMaterials) {
                     BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
                     for (unsigned int i = 0; i < baseMaterials->mMaterials.size(); ++i) {
@@ -228,35 +236,36 @@ public:
     }
 
 private:
+    void addObjectToNode(aiNode *parent, Object *obj, aiMatrix4x4 nodeTransform) {
+        ai_assert(nullptr != obj);
 
-    void addObjectToNode(aiNode* parent, Object* obj, aiMatrix4x4 nodeTransform) {
         aiNode *sceneNode = new aiNode(obj->mName);
         sceneNode->mNumMeshes = static_cast<unsigned int>(obj->mMeshes.size());
         sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes];
         std::copy(obj->mMeshIndex.begin(), obj->mMeshIndex.end(), sceneNode->mMeshes);
 
         sceneNode->mTransformation = nodeTransform;
-
-        parent->addChildren(1, &sceneNode);
+        if (nullptr != parent) {
+            parent->addChildren(1, &sceneNode);
+        }
 
         for (size_t i = 0; i < obj->mComponents.size(); ++i) {
             Component c = obj->mComponents[i];
             auto it = mResourcesDictionnary.find(c.mObjectId);
             if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
-                addObjectToNode(sceneNode, static_cast<Object*>(it->second), c.mTransformation);
+                addObjectToNode(sceneNode, static_cast<Object *>(it->second), c.mTransformation);
             }
-            
         }
     }
 
-    bool getNodeAttribute(const XmlNode& node, const std::string& attribute, std::string& value) {
+    bool getNodeAttribute(const XmlNode &node, const std::string &attribute, std::string &value) {
         pugi::xml_attribute objectAttribute = node.attribute(attribute.c_str());
         if (!objectAttribute.empty()) {
             value = objectAttribute.as_string();
             return true;
-        } else {
-            return false;
         }
+
+        return false;
     }
 
     bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &value) {
@@ -265,9 +274,9 @@ private:
         if (ret) {
             value = std::atoi(strValue.c_str());
             return true;
-        } else {
-            return false;
-        }
+        } 
+
+        return false;
     }
 
     aiMatrix4x4 parseTransformMatrix(std::string matrixStr) {
@@ -287,7 +296,7 @@ private:
             }
         }
         if (currentNumber.size() > 0) {
-            float f = std::stof(currentNumber);
+            const float f = std::stof(currentNumber);
             numbers.push_back(f);
         }
 
@@ -311,29 +320,26 @@ private:
         transformMatrix.b4 = numbers[10];
         transformMatrix.c4 = numbers[11];
         transformMatrix.d4 = 1;
+
         return transformMatrix;
     }
 
     void ReadObject(XmlNode &node) {
         int id = -1, pid = -1, pindex = -1;
-        bool hasId = getNodeAttribute(node, D3MF::XmlTag::id, id);
-        //bool hasType = getNodeAttribute(node, D3MF::XmlTag::type, type); not used currently
-        bool hasPid = getNodeAttribute(node, D3MF::XmlTag::pid, pid);
-        bool hasPindex = getNodeAttribute(node, D3MF::XmlTag::pindex, pindex);
-
-        std::string idStr = ai_to_string(id);
-
+        bool hasId = getNodeAttribute(node, XmlTag::id, id);
+        bool hasPid = getNodeAttribute(node, XmlTag::pid, pid);
+        bool hasPindex = getNodeAttribute(node, XmlTag::pindex, pindex);
         if (!hasId) {
             return;
         }
 
         Object *obj = new Object(id);
 
-        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+        for (XmlNode &currentNode : node.children()) {
             const std::string &currentName = currentNode.name();
             if (currentName == D3MF::XmlTag::mesh) {
                 auto mesh = ReadMesh(currentNode);
-                mesh->mName.Set(idStr);
+                mesh->mName.Set(ai_to_string(id));
 
                 if (hasPid) {
                     auto it = mResourcesDictionnary.find(pid);
@@ -347,8 +353,9 @@ private:
                 obj->mMeshIndex.push_back(mMeshCount);
                 mMeshCount++;
             } else if (currentName == D3MF::XmlTag::components) {
-                for (XmlNode currentSubNode = currentNode.first_child(); currentSubNode; currentSubNode = currentSubNode.next_sibling()) {
-                    if (currentSubNode.name() == D3MF::XmlTag::component) {
+                for (XmlNode &currentSubNode : currentNode.children()) {
+                    const std::string subNodeName = currentSubNode.name();
+                    if (subNodeName == D3MF::XmlTag::component) {
                         int objectId = -1;
                         std::string componentTransformStr;
                         aiMatrix4x4 componentTransform;
@@ -356,8 +363,9 @@ private:
                             componentTransform = parseTransformMatrix(componentTransformStr);
                         }
 
-                        if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId))
+                        if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId)) {
                             obj->mComponents.push_back({ objectId, componentTransform });
+                        }
                     }
                 }
             }
@@ -369,21 +377,20 @@ private:
     aiMesh *ReadMesh(XmlNode &node) {
         aiMesh *mesh = new aiMesh();
 
-        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
-            const std::string &currentName = currentNode.name();
-            if (currentName == D3MF::XmlTag::vertices) {
+        for (XmlNode &currentNode : node.children()) {
+            const std::string currentName = currentNode.name();
+            if (currentName == XmlTag::vertices) {
                 ImportVertices(currentNode, mesh);
-            } else if (currentName == D3MF::XmlTag::triangles) {
+            } else if (currentName == XmlTag::triangles) {
                 ImportTriangles(currentNode, mesh);
             }
-
         }
 
         return mesh;
     }
 
     void ReadMetadata(XmlNode &node) {
-        pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name.c_str());
+        pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name);
         const std::string name = attribute.as_string();
         const std::string value = node.value();
         if (name.empty()) {
@@ -398,9 +405,9 @@ private:
 
     void ImportVertices(XmlNode &node, aiMesh *mesh) {
         std::vector<aiVector3D> vertices;
-        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
-            const std::string &currentName = currentNode.name();
-            if (currentName == D3MF::XmlTag::vertex) {
+        for (XmlNode &currentNode : node.children()) {
+            const std::string currentName = currentNode.name();
+            if (currentName == XmlTag::vertex) {
                 vertices.push_back(ReadVertex(currentNode));
             }
         }
@@ -412,29 +419,28 @@ private:
 
     aiVector3D ReadVertex(XmlNode &node) {
         aiVector3D vertex;
-        vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::x.c_str()).as_string(), nullptr);
-        vertex.y = ai_strtof(node.attribute(D3MF::XmlTag::y.c_str()).as_string(), nullptr);
-        vertex.z = ai_strtof(node.attribute(D3MF::XmlTag::z.c_str()).as_string(), nullptr);
+        vertex.x = ai_strtof(node.attribute(XmlTag::x).as_string(), nullptr);
+        vertex.y = ai_strtof(node.attribute(XmlTag::y).as_string(), nullptr);
+        vertex.z = ai_strtof(node.attribute(XmlTag::z).as_string(), nullptr);
 
         return vertex;
     }
 
     void ImportTriangles(XmlNode &node, aiMesh *mesh) {
         std::vector<aiFace> faces;
-        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
-            const std::string &currentName = currentNode.name();
-            if (currentName == D3MF::XmlTag::triangle) {
+        for (XmlNode &currentNode : node.children()) {
+            const std::string currentName = currentNode.name();
+            if (currentName == XmlTag::triangle) {
                 aiFace face = ReadTriangle(currentNode);
                 faces.push_back(face);
 
-                int pid = 0, p1;
+                int pid = 0, p1 = 0;
                 bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
                 bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
 
                 if (hasPid && hasP1) {
                     auto it = mResourcesDictionnary.find(pid);
-                    if (it != mResourcesDictionnary.end())
-                    {
+                    if (it != mResourcesDictionnary.end()) {
                         if (it->second->getType() == ResourceType::RT_BaseMaterials) {
                             BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
                             mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
@@ -457,9 +463,9 @@ private:
 
         face.mNumIndices = 3;
         face.mIndices = new unsigned int[face.mNumIndices];
-        face.mIndices[0] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v1.c_str()).as_string()));
-        face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v2.c_str()).as_string()));
-        face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v3.c_str()).as_string()));
+        face.mIndices[0] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v1).as_string()));
+        face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v2).as_string()));
+        face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v3).as_string()));
 
         return face;
     }
@@ -467,14 +473,14 @@ private:
     void ReadBaseMaterials(XmlNode &node) {
         int id = -1;
         if (getNodeAttribute(node, D3MF::XmlTag::basematerials_id, id)) {
-            BaseMaterials* baseMaterials = new BaseMaterials(id);
+            BaseMaterials *baseMaterials = new BaseMaterials(id);
 
-            for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling())
-            {
-                if (currentNode.name() == D3MF::XmlTag::basematerials_base) {
+            for (XmlNode &currentNode : node.children()) {
+                const std::string currentName = currentNode.name();
+                if (currentName == XmlTag::basematerials_base) {
                     baseMaterials->mMaterialIndex.push_back(mMaterialCount);
                     baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id));
-                    mMaterialCount++;
+                    ++mMaterialCount;
                 }
             }
 
@@ -488,7 +494,7 @@ private:
         }
 
         //format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
-        const size_t len(strlen(color));
+        const size_t len = strlen(color);
         if (9 != len && 7 != len) {
             return false;
         }
@@ -517,7 +523,7 @@ private:
     }
 
     void assignDiffuseColor(XmlNode &node, aiMaterial *mat) {
-        const char *color = node.attribute(D3MF::XmlTag::basematerials_displaycolor.c_str()).as_string();
+        const char *color = node.attribute(XmlTag::basematerials_displaycolor).as_string();
         aiColor4D diffuse;
         if (parseColor(color, diffuse)) {
             mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
@@ -531,7 +537,7 @@ private:
         bool hasName = getNodeAttribute(node, D3MF::XmlTag::basematerials_name, name);
 
         std::string stdMaterialName;
-        std::string strId(ai_to_string(basematerialsId));
+        const std::string strId(ai_to_string(basematerialsId));
         stdMaterialName += "id";
         stdMaterialName += strId;
         stdMaterialName += "_";
@@ -556,13 +562,15 @@ private:
         std::string value;
     };
     std::vector<MetaEntry> mMetaData;
-    std::map<unsigned int, Resource*> mResourcesDictionnary;
+    std::map<unsigned int, Resource *> mResourcesDictionnary;
     unsigned int mMaterialCount, mMeshCount;
     XmlParser *mXmlParser;
 };
 
 } //namespace D3MF
 
+using namespace D3MF;
+
 static const aiImporterDesc desc = {
     "3mf Importer",
     "",
@@ -596,7 +604,7 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo
         if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
             return false;
         }
-        D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
+        D3MFOpcPackage opcPackage(pIOHandler, filename);
         return opcPackage.validate();
     }
 
@@ -612,11 +620,11 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
 }
 
 void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
-    D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
+    D3MFOpcPackage opcPackage(pIOHandler, filename);
 
     XmlParser xmlParser;
     if (xmlParser.parse(opcPackage.RootStream())) {
-        D3MF::XmlSerializer xmlSerializer(&xmlParser);
+        XmlSerializer xmlSerializer(&xmlParser);
         xmlSerializer.ImportXml(pScene);
     }
 }

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

@@ -47,9 +47,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp {
 
+/// @brief  The 3MF-importer class.
 class D3MFImporter : public BaseImporter {
 public:
-    // BaseImporter interface
     D3MFImporter();
     ~D3MFImporter();
     bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;

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

@@ -103,9 +103,9 @@ public:
             std::string name = currentNode.name();
             if (name == "Relationship") {
                 OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
-                relPtr->id = currentNode.attribute(XmlTag::RELS_ATTRIB_ID.c_str()).as_string();
-                relPtr->type = currentNode.attribute(XmlTag::RELS_ATTRIB_TYPE.c_str()).as_string();
-                relPtr->target = currentNode.attribute(XmlTag::RELS_ATTRIB_TARGET.c_str()).as_string();
+                relPtr->id = currentNode.attribute(XmlTag::RELS_ATTRIB_ID).as_string();
+                relPtr->type = currentNode.attribute(XmlTag::RELS_ATTRIB_TYPE).as_string();
+                relPtr->target = currentNode.attribute(XmlTag::RELS_ATTRIB_TARGET).as_string();
                 if (validateRels(relPtr)) {
                     m_relationShips.push_back(relPtr);
                 }

+ 3 - 6
code/AssetLib/AMF/AMFImporter.cpp

@@ -205,7 +205,7 @@ void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::s
 }
 
 static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) {
-    return (isalnum(pChar) || (pChar == '+') || (pChar == '/'));
+    return (isalnum((unsigned char)pChar) || (pChar == '+') || (pChar == '/'));
 }
 
 void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<uint8_t> &pOutputData) const {
@@ -268,7 +268,8 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
     mXmlParser = new XmlParser();
     if (!mXmlParser->parse(file.get())) {
         delete mXmlParser;
-        throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
+        mXmlParser = nullptr;
+        throw DeadlyImportError("Failed to create XML reader for file ", pFile, ".");
     }
 
     // Start reading, search for root tag <amf>
@@ -517,10 +518,6 @@ bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool p
     return false;
 }
 
-void AMFImporter::GetExtensionList(std::set<std::string> &pExtensionList) {
-    pExtensionList.insert("amf");
-}
-
 const aiImporterDesc *AMFImporter::GetInfo() const {
     return &Description;
 }

+ 0 - 1
code/AssetLib/AMF/AMFImporter.hpp

@@ -277,7 +277,6 @@ public:
     void ParseHelper_Node_Enter(AMFNodeElementBase *child);
     void ParseHelper_Node_Exit();
     bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const;
-    void GetExtensionList(std::set<std::string> &pExtensionList);
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
     const aiImporterDesc *GetInfo() const;
     bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const;

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

@@ -428,10 +428,10 @@ void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const st
 
                     if (pBiggerThan != nullptr) {
                         bool found = false;
-
+                        const size_t biggerThan = *pBiggerThan;
                         for (const SComplexFace &face : pFaceList) {
                             for (size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++) {
-                                if (face.Face.mIndices[idx_vert] > *pBiggerThan) {
+                                if (face.Face.mIndices[idx_vert] > biggerThan) {
                                     rv = face.Face.mIndices[idx_vert];
                                     found = true;
                                     break;

+ 6 - 0
code/AssetLib/ASE/ASEParser.cpp

@@ -498,6 +498,12 @@ void Parser::ParseLV1MaterialListBlock() {
                 ParseLV2MaterialBlock(sMat);
                 continue;
             }
+            if( iDepth == 1 ){
+                // CRUDE HACK: support missing brace after "Ascii Scene Exporter v2.51"
+                LogWarning("Missing closing brace in material list");
+                --filePtr;
+                return;
+            }
         }
         AI_ASE_HANDLE_TOP_LEVEL_SECTION();
     }

+ 1 - 1
code/AssetLib/Assbin/AssbinLoader.cpp

@@ -671,7 +671,7 @@ void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
 void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
     IOStream *stream = pIOHandler->Open(pFile, "rb");
     if (nullptr == stream) {
-        return;
+        throw DeadlyImportError("ASSBIN: Could not open ", pFile);
     }
 
     // signature

+ 2 - 2
code/AssetLib/BVH/BVHLoader.cpp

@@ -359,7 +359,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
 std::string BVHLoader::GetNextToken() {
     // skip any preceding whitespace
     while (mReader != mBuffer.end()) {
-        if (!isspace(*mReader))
+        if (!isspace((unsigned char)*mReader))
             break;
 
         // count lines
@@ -372,7 +372,7 @@ std::string BVHLoader::GetNextToken() {
     // collect all chars till the next whitespace. BVH is easy in respect to that.
     std::string token;
     while (mReader != mBuffer.end()) {
-        if (isspace(*mReader))
+        if (isspace((unsigned char)*mReader))
             break;
 
         token.push_back(*mReader);

+ 3 - 9
code/AssetLib/Blender/BlenderLoader.cpp

@@ -132,12 +132,6 @@ bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bo
     return false;
 }
 
-// ------------------------------------------------------------------------------------------------
-// List all extensions handled by this loader
-void BlenderImporter::GetExtensionList(std::set<std::string> &app) {
-    app.insert("blend");
-}
-
 // ------------------------------------------------------------------------------------------------
 // Loader registry entry
 const aiImporterDesc *BlenderImporter::GetInfo() const {
@@ -426,9 +420,9 @@ void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const M
             --s;
         }
 
-        curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower(s[1]);
-        curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower(s[2]);
-        curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower(s[3]);
+        curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower((unsigned char)s[1]);
+        curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower((unsigned char)s[2]);
+        curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower((unsigned char)s[3]);
         curTex->achFormatHint[3] = '\0';
 
         // tex->mHeight = 0;

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

@@ -110,7 +110,6 @@ public:
 
 protected:
     const aiImporterDesc* GetInfo () const;
-    void GetExtensionList(std::set<std::string>& app);
     void SetupProperties(const Importer* pImp);
     void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
     void ParseBlendFile(Blender::FileDatabase& out, std::shared_ptr<IOStream> stream);

+ 23 - 41
code/AssetLib/C4D/C4DImporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2021, assimp team
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -51,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endif
 
 #include "C4DImporter.h"
-#include <assimp/TinyFormatter.h>
 #include <memory>
 #include <assimp/IOSystem.hpp>
 #include <assimp/scene.h>
@@ -65,7 +64,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "c4d_file.h"
 #include "default_alien_overloads.h"
 
-using namespace melange;
+namespace {
+
+aiString aiStringFrom(cineware::String const & cinestring) {
+    aiString result;
+    cinestring.GetCString(result.data, MAXLEN-1);
+    result.length = static_cast<ai_uint32>(cinestring.GetLength());
+    return result;
+}
+
+}
+
+using namespace Assimp;
+using namespace cineware;
 
 // overload this function and fill in your own unique data
 void GetWriterInfo(int &id, String &appname) {
@@ -73,9 +84,6 @@ void GetWriterInfo(int &id, String &appname) {
     appname = "Open Asset Import Library";
 }
 
-using namespace Assimp;
-using namespace Assimp::Formatter;
-
 namespace Assimp {
     template<> const char* LogFunctions<C4DImporter>::Prefix() {
         static auto prefix = "C4D: ";
@@ -97,17 +105,6 @@ static const aiImporterDesc desc = {
 };
 
 
-// ------------------------------------------------------------------------------------------------
-C4DImporter::C4DImporter()
-: BaseImporter() {
-    // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-C4DImporter::~C4DImporter() {
-    // empty
-}
-
 // ------------------------------------------------------------------------------------------------
 bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
     const std::string& extension = GetExtension(pFile);
@@ -125,11 +122,6 @@ const aiImporterDesc* C4DImporter::GetInfo () const {
     return &desc;
 }
 
-// ------------------------------------------------------------------------------------------------
-void C4DImporter::SetupProperties(const Importer* /*pImp*/) {
-    // nothing to be done for the moment
-}
-
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
@@ -199,8 +191,8 @@ void C4DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
 
 
 // ------------------------------------------------------------------------------------------------
-bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) {
-    // based on Melange sample code (C4DImportExport.cpp)
+bool C4DImporter::ReadShader(aiMaterial* out, BaseShader* shader) {
+    // based on Cineware sample code (C4DImportExport.cpp)
     while(shader) {
         if(shader->GetType() == Xlayer) {
             BaseContainer* container = shader->GetDataInstance();
@@ -242,9 +234,7 @@ bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) {
                 lsl = lsl->GetNext();
             }
         } else if ( shader->GetType() == Xbitmap ) {
-            aiString path;
-            shader->GetFileName().GetString().GetCString(path.data, MAXLEN-1);
-            path.length = ::strlen(path.data);
+            auto const path = aiStringFrom(shader->GetFileName().GetString());
             out->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
             return true;
         } else {
@@ -257,18 +247,15 @@ bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) {
 }
 
 // ------------------------------------------------------------------------------------------------
-void C4DImporter::ReadMaterials(melange::BaseMaterial* mat) {
-    // based on Melange sample code
+void C4DImporter::ReadMaterials(BaseMaterial* mat) {
+    // based on Cineware sample code
     while (mat) {
-        const String& name = mat->GetName();
         if (mat->GetType() == Mmaterial) {
             aiMaterial* out = new aiMaterial();
             material_mapping[mat] = static_cast<unsigned int>(materials.size());
             materials.push_back(out);
 
-            aiString ai_name;
-            name.GetCString(ai_name.data, MAXLEN-1);
-            ai_name.length = ::strlen(ai_name.data);
+            auto const ai_name = aiStringFrom(mat->GetName());
             out->AddProperty(&ai_name, AI_MATKEY_NAME);
 
             Material& m = dynamic_cast<Material&>(*mat);
@@ -305,19 +292,15 @@ void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) {
     ai_assert(parent != nullptr );
     std::vector<aiNode*> nodes;
 
-    // based on Melange sample code
+    // based on Cineware sample code
     while (object) {
-        const String& name = object->GetName();
         const LONG type = object->GetType();
         const Matrix& ml = object->GetMl();
 
-        aiString string;
-        name.GetCString(string.data, MAXLEN-1);
-        string.length = ::strlen(string.data);
         aiNode* const nd = new aiNode();
 
         nd->mParent = parent;
-        nd->mName = string;
+        nd->mName = aiStringFrom(object->GetName());
 
         nd->mTransformation.a1 = ml.v1.x;
         nd->mTransformation.b1 = ml.v1.y;
@@ -370,7 +353,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) {
     ai_assert(object != nullptr);
     ai_assert( object->GetType() == Opolygon );
 
-    // based on Melange sample code
+    // based on Cineware sample code
     PolygonObject* const polyObject = dynamic_cast<PolygonObject*>(object);
     ai_assert(polyObject != nullptr);
 
@@ -618,4 +601,3 @@ unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj) {
 }
 
 #endif // ASSIMP_BUILD_NO_C4D_IMPORTER
-

+ 15 - 24
code/AssetLib/C4D/C4DImporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2021, assimp team
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -56,8 +56,8 @@ struct aiMaterial;
 
 struct aiImporterDesc;
 
-namespace melange {
-    class BaseObject; // c4d_file.h
+namespace cineware {
+    class BaseObject;
     class PolygonObject;
     class BaseMaterial;
     class BaseShader;
@@ -71,43 +71,34 @@ namespace Assimp  {
     }
 
 // -------------------------------------------------------------------------------------------
-/** Importer class to load Cinema4D files using the Melange library to be obtained from
- *  www.plugincafe.com
+/** Importer class to load Cinema4D files using the Cineware library to be obtained from
+ *  https://developers.maxon.net
  *
- *  Note that Melange is not free software. */
+ *  Note that Cineware is not free software. */
 // -------------------------------------------------------------------------------------------
 class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter> {
 public:
-    C4DImporter();
-    ~C4DImporter();
-    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-        bool checkSig) const;
+    bool CanRead( const std::string& pFile, IOSystem*, bool checkSig) const override;
 
 protected:
 
-    // --------------------
-    const aiImporterDesc* GetInfo () const;
+    const aiImporterDesc* GetInfo () const override;
 
-    // --------------------
-    void SetupProperties(const Importer* pImp);
-
-    // --------------------
-    void InternReadFile( const std::string& pFile, aiScene* pScene,
-        IOSystem* pIOHandler);
+    void InternReadFile( const std::string& pFile, aiScene*, IOSystem* ) override;
 
 private:
 
-    void ReadMaterials(melange::BaseMaterial* mat);
-    void RecurseHierarchy(melange::BaseObject* object, aiNode* parent);
-    aiMesh* ReadMesh(melange::BaseObject* object);
-    unsigned int ResolveMaterial(melange::PolygonObject* obj);
+    void ReadMaterials(cineware::BaseMaterial* mat);
+    void RecurseHierarchy(cineware::BaseObject* object, aiNode* parent);
+    aiMesh* ReadMesh(cineware::BaseObject* object);
+    unsigned int ResolveMaterial(cineware::PolygonObject* obj);
 
-    bool ReadShader(aiMaterial* out, melange::BaseShader* shader);
+    bool ReadShader(aiMaterial* out, cineware::BaseShader* shader);
 
     std::vector<aiMesh*> meshes;
     std::vector<aiMaterial*> materials;
 
-    typedef std::map<melange::BaseMaterial*, unsigned int> MaterialMap;
+    typedef std::map<cineware::BaseMaterial*, unsigned int> MaterialMap;
     MaterialMap material_mapping;
 
 }; // !class C4DImporter

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

@@ -137,7 +137,13 @@ void COBImporter::SetupProperties(const Importer * /*pImp*/) {
 // Imports the given file into the given scene structure.
 void COBImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
     COB::Scene scene;
-    std::unique_ptr<StreamReaderLE> stream(new StreamReaderLE(pIOHandler->Open(pFile, "rb")));
+
+    auto file = pIOHandler->Open(pFile, "rb");
+    if (!file) {
+        ThrowException("Could not open " + pFile);
+    }
+
+    std::unique_ptr<StreamReaderLE> stream(new StreamReaderLE(file));
 
     // check header
     char head[32];

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

@@ -75,7 +75,7 @@ static const aiImporterDesc desc = {
     3,
     1,
     5,
-    "dae zae"
+    "dae xml zae"
 };
 
 static const float kMillisecondsFromSeconds = 1000.f;

+ 1 - 1
code/AssetLib/Collada/ColladaParser.cpp

@@ -234,7 +234,7 @@ void ColladaParser::UriDecodePath(aiString &ss) {
 #if defined(_MSC_VER)
     if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
 #else
-    if (ss.data[0] == '/' && isalpha(ss.data[1]) && ss.data[2] == ':') {
+    if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
 #endif
         --ss.length;
         ::memmove(ss.data, ss.data + 1, ss.length);

+ 3 - 3
code/AssetLib/FBX/FBXExporter.cpp

@@ -1789,13 +1789,13 @@ void FBXExporter::WriteObjects ()
             blendchannel_uid, blendshape_name + FBX::SEPARATOR + "SubDeformer", "BlendShapeChannel"
         );
         sdnode.AddChild("Version", int32_t(100));
-        sdnode.AddChild("DeformPercent", int32_t(100));
+        sdnode.AddChild("DeformPercent", float_t(0.0));
         FBX::Node p("Properties70");
-        p.AddP70numberA("DeformPercent", 100.);
+        p.AddP70numberA("DeformPercent", 0.0);
         sdnode.AddChild(p);
         // TODO: Normally just one weight per channel, adding stub for later development
         std::vector<float>fFullWeights;
-        fFullWeights.push_back(0.);
+        fFullWeights.push_back(100.);
         sdnode.AddChild("FullWeights", fFullWeights);
         sdnode.Dump(outstream, binary, indent);
 

+ 1 - 1
code/AssetLib/FBX/FBXMaterial.cpp

@@ -82,7 +82,7 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
 
     // lower-case shading because Blender (for example) writes "Phong"
     for (size_t i = 0; i < shading.length(); ++i) {
-        shading[i] = static_cast<char>(tolower(shading[i]));
+        shading[i] = static_cast<char>(tolower(static_cast<unsigned char>(shading[i])));
     }
     std::string templateName;
     if(shading == "phong") {

+ 2 - 6
code/AssetLib/HMP/HMPLoader.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AssetLib/HMP/HMPLoader.h"
 #include "AssetLib/MD2/MD2FileData.h"
 
+#include <assimp/StringUtils.h>
 #include <assimp/importerdesc.h>
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
@@ -151,12 +152,7 @@ void HMPImporter::InternReadFile(const std::string &pFile,
         InternReadFile_HMP7();
     } else {
         // Print the magic word to the logger
-        char szBuffer[5];
-        szBuffer[0] = ((char *)&iMagic)[0];
-        szBuffer[1] = ((char *)&iMagic)[1];
-        szBuffer[2] = ((char *)&iMagic)[2];
-        szBuffer[3] = ((char *)&iMagic)[3];
-        szBuffer[4] = '\0';
+        std::string szBuffer = ai_str_toprintable((const char *)&iMagic, sizeof(iMagic));
     
         delete[] mBuffer;
         mBuffer = nullptr;

+ 1 - 1
code/AssetLib/IFC/IFCLoader.cpp

@@ -115,7 +115,7 @@ static const aiImporterDesc desc = {
     0,
     0,
     0,
-    "ifc ifczip stp"
+    "ifc ifczip step stp"
 };
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 2
code/AssetLib/Irr/IRRLoader.cpp

@@ -859,13 +859,13 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 
 	// Check whether we can read from the file
 	if (file.get() == nullptr) {
-		throw DeadlyImportError("Failed to open IRR file " + pFile);
+        throw DeadlyImportError("Failed to open IRR file ", pFile);
 	}
 
 	// Construct the irrXML parser
 	XmlParser st;
     if (!st.parse( file.get() )) {
-        return;
+        throw DeadlyImportError("XML parse error while loading IRR file ", pFile);
     }
     pugi::xml_node rootElement = st.getRootNode();
 

+ 2 - 2
code/AssetLib/Irr/IRRMeshLoader.cpp

@@ -135,12 +135,12 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
 
 	// Check whether we can read from the file
 	if (file.get() == NULL)
-		throw DeadlyImportError("Failed to open IRRMESH file " + pFile);
+        throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
 
 	// Construct the irrXML parser
 	XmlParser parser;
     if (!parser.parse( file.get() )) {
-        return;
+        throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
     }
     XmlNode root = parser.getRootNode();
 

+ 1 - 1
code/AssetLib/M3D/M3DImporter.cpp

@@ -131,7 +131,7 @@ bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool c
         */
         std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
         unsigned char data[4];
-        if (4 != pStream->Read(data, 1, 4)) {
+        if (!pStream || 4 != pStream->Read(data, 1, 4)) {
             return false;
         }
         return !memcmp(data, "3DMO", 4) /* bin */

+ 21 - 23
code/AssetLib/MD2/MD2Loader.cpp

@@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOSystem.hpp>
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
+#include <assimp/StringUtils.h>
 
 #include <memory>
 
@@ -148,46 +149,39 @@ void MD2Importer::ValidateHeader( )
     if (m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_BE &&
         m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_LE)
     {
-        char szBuffer[5];
-        szBuffer[0] = ((char*)&m_pcHeader->magic)[0];
-        szBuffer[1] = ((char*)&m_pcHeader->magic)[1];
-        szBuffer[2] = ((char*)&m_pcHeader->magic)[2];
-        szBuffer[3] = ((char*)&m_pcHeader->magic)[3];
-        szBuffer[4] = '\0';
-
-        throw DeadlyImportError("Invalid MD2 magic word: should be IDP2, the "
-            "magic word found is " + std::string(szBuffer));
+        throw DeadlyImportError("Invalid MD2 magic word: expected IDP2, found ",
+                                ai_str_toprintable((char *)&m_pcHeader->magic, 4));
     }
 
     // check file format version
     if (m_pcHeader->version != 8)
-        ASSIMP_LOG_WARN( "Unsupported md2 file version. Continuing happily ...");
+        ASSIMP_LOG_WARN( "Unsupported MD2 file version. Continuing happily ...");
 
     // check some values whether they are valid
     if (0 == m_pcHeader->numFrames)
-        throw DeadlyImportError( "Invalid md2 file: NUM_FRAMES is 0");
+        throw DeadlyImportError( "Invalid MD2 file: NUM_FRAMES is 0");
 
     if (m_pcHeader->offsetEnd > (uint32_t)fileSize)
-        throw DeadlyImportError( "Invalid md2 file: File is too small");
+        throw DeadlyImportError( "Invalid MD2 file: File is too small");
 
     if (m_pcHeader->numSkins > AI_MAX_ALLOC(MD2::Skin)) {
-        throw DeadlyImportError("Invalid MD2 header: too many skins, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many skins, would overflow");
     }
 
     if (m_pcHeader->numVertices > AI_MAX_ALLOC(MD2::Vertex)) {
-        throw DeadlyImportError("Invalid MD2 header: too many vertices, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many vertices, would overflow");
     }
 
     if (m_pcHeader->numTexCoords > AI_MAX_ALLOC(MD2::TexCoord)) {
-        throw DeadlyImportError("Invalid MD2 header: too many texcoords, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many texcoords, would overflow");
     }
 
     if (m_pcHeader->numTriangles > AI_MAX_ALLOC(MD2::Triangle)) {
-        throw DeadlyImportError("Invalid MD2 header: too many triangles, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many triangles, would overflow");
     }
 
     if (m_pcHeader->numFrames > AI_MAX_ALLOC(MD2::Frame)) {
-        throw DeadlyImportError("Invalid MD2 header: too many frames, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many frames, would overflow");
     }
 
     // -1 because Frame already contains one
@@ -199,7 +193,7 @@ void MD2Importer::ValidateHeader( )
         m_pcHeader->offsetFrames    + m_pcHeader->numFrames * frameSize                 >= fileSize ||
         m_pcHeader->offsetEnd           > fileSize)
     {
-        throw DeadlyImportError("Invalid MD2 header: some offsets are outside the file");
+        throw DeadlyImportError("Invalid MD2 header: Some offsets are outside the file");
     }
 
     if (m_pcHeader->numSkins > AI_MD2_MAX_SKINS)
@@ -210,7 +204,7 @@ void MD2Importer::ValidateHeader( )
         ASSIMP_LOG_WARN("The model contains more vertices than Quake 2 supports");
 
     if (m_pcHeader->numFrames <= configFrameID )
-        throw DeadlyImportError("The requested frame is not existing the file");
+        throw DeadlyImportError("MD2: The requested frame (", configFrameID, ") does not exist in the file");
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -433,10 +427,6 @@ void MD2Importer::InternReadFile( const std::string& pFile,
             aiVector3D& vNormal = pcMesh->mNormals[iCurrent];
             LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal);
 
-            // flip z and y to become right-handed
-            std::swap((float&)vNormal.z,(float&)vNormal.y);
-            std::swap((float&)vec.z,(float&)vec.y);
-
             if (m_pcHeader->numTexCoords)   {
                 // validate texture coordinates
                 iIndex = pcTriangles[i].textureIndices[c];
@@ -454,7 +444,15 @@ void MD2Importer::InternReadFile( const std::string& pFile,
             }
             pScene->mMeshes[0]->mFaces[i].mIndices[c] = iCurrent;
         }
+        // flip the face order
+        std::swap( pScene->mMeshes[0]->mFaces[i].mIndices[0], pScene->mMeshes[0]->mFaces[i].mIndices[2] );
     }
+    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
+    pScene->mRootNode->mTransformation = aiMatrix4x4(
+            1.f, 0.f, 0.f, 0.f,
+            0.f, 0.f, 1.f, 0.f,
+            0.f, -1.f, 0.f, 0.f,
+            0.f, 0.f, 0.f, 1.f);
 }
 
 #endif // !! ASSIMP_BUILD_NO_MD2_IMPORTER

+ 1 - 1
code/AssetLib/MD3/MD3Loader.cpp

@@ -702,7 +702,7 @@ void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
     }
     filename = mFile.substr(s), path = mFile.substr(0, s);
     for (std::string::iterator it = filename.begin(); it != filename.end(); ++it) {
-        *it = static_cast<char>(tolower(*it));
+        *it = static_cast<char>(tolower(static_cast<unsigned char>(*it)));
     }
 
     // Load multi-part model file, if necessary

+ 10 - 10
code/AssetLib/MDC/MDCLoader.cpp

@@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Importer.hpp>
+#include <assimp/StringUtils.h>
 
 #include <memory>
 
@@ -143,16 +144,8 @@ void MDCImporter::ValidateHeader() {
 
     if (pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_BE &&
             pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_LE) {
-        char szBuffer[5];
-        szBuffer[0] = ((char *)&pcHeader->ulIdent)[0];
-        szBuffer[1] = ((char *)&pcHeader->ulIdent)[1];
-        szBuffer[2] = ((char *)&pcHeader->ulIdent)[2];
-        szBuffer[3] = ((char *)&pcHeader->ulIdent)[3];
-        szBuffer[4] = '\0';
-
-        throw DeadlyImportError("Invalid MDC magic word: should be IDPC, the "
-                                "magic word found is " +
-                                std::string(szBuffer));
+        throw DeadlyImportError("Invalid MDC magic word: expected IDPC, found ",
+                                ai_str_toprintable((char *)&pcHeader->ulIdent, 4));
     }
 
     if (pcHeader->ulVersion != AI_MDC_VERSION) {
@@ -465,6 +458,13 @@ void MDCImporter::InternReadFile(
             pcMat->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
         }
     }
+
+    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
+    pScene->mRootNode->mTransformation = aiMatrix4x4(
+            1.f, 0.f, 0.f, 0.f,
+            0.f, 0.f, 1.f, 0.f,
+            0.f, -1.f, 0.f, 0.f,
+            0.f, 0.f, 0.f, 1.f);
 }
 
 #endif // !! ASSIMP_BUILD_NO_MDC_IMPORTER

+ 4 - 3
code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp

@@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <iomanip>
 #include <sstream>
+#include <map>
 
 #ifdef MDL_HALFLIFE_LOG_WARN_HEADER
 #undef MDL_HALFLIFE_LOG_WARN_HEADER
@@ -868,7 +869,7 @@ void HL1MDLLoader::read_meshes() {
                         scene_mesh->mNormals[v] = bind_pose_normals[pTrivert->normindex];
                         scene_mesh->mTextureCoords[0][v] = aiVector3D(
                                 pTrivert->s * texcoords_s_scale,
-                                pTrivert->t * texcoords_t_scale, 0);
+                                pTrivert->t * -texcoords_t_scale, 0);
                     }
 
                     // Add face and indices.
@@ -879,9 +880,9 @@ void HL1MDLLoader::read_meshes() {
                         aiFace *face = &scene_mesh->mFaces[f];
                         face->mNumIndices = 3;
                         face->mIndices = new unsigned int[3];
-                        face->mIndices[0] = mesh_faces[f].v0;
+                        face->mIndices[0] = mesh_faces[f].v2;
                         face->mIndices[1] = mesh_faces[f].v1;
-                        face->mIndices[2] = mesh_faces[f].v2;
+                        face->mIndices[2] = mesh_faces[f].v0;
                     }
 
                     // Add mesh bones.

+ 16 - 4
code/AssetLib/MDL/MDLLoader.cpp

@@ -199,6 +199,7 @@ void MDLImporter::InternReadFile(const std::string &pFile,
         const uint32_t iMagicWord = *((uint32_t *)mBuffer);
 
         // Determine the file subtype and call the appropriate member function
+        bool is_half_life = false;
 
         // Original Quake1 format
         if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) {
@@ -240,6 +241,7 @@ void MDLImporter::InternReadFile(const std::string &pFile,
         else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
                  AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord) {
             iGSFileVersion = 0;
+            is_half_life = true;
 
             HalfLife::HalfLifeMDLBaseHeader *pHeader = (HalfLife::HalfLifeMDLBaseHeader *)mBuffer;
             if (pHeader->version == AI_MDL_HL1_VERSION) {
@@ -252,12 +254,22 @@ void MDLImporter::InternReadFile(const std::string &pFile,
         } else {
             // print the magic word to the log file
             throw DeadlyImportError("Unknown MDL subformat ", pFile,
-                                    ". Magic word (", std::string((char *)&iMagicWord, 4), ") is not known");
+                                    ". Magic word (", ai_str_toprintable((const char *)&iMagicWord, sizeof(iMagicWord)), ") is not known");
         }
 
-        // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
-        pScene->mRootNode->mTransformation = aiMatrix4x4(1.f, 0.f, 0.f, 0.f,
-                0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
+        if (is_half_life){
+            // Now rotate the whole scene 90 degrees around the z and x axes to convert to internal coordinate system
+            pScene->mRootNode->mTransformation = aiMatrix4x4(
+                    0.f, -1.f, 0.f, 0.f,
+                    0.f, 0.f, 1.f, 0.f,
+                    -1.f, 0.f, 0.f, 0.f,
+                    0.f, 0.f, 0.f, 1.f);
+        }
+        else {
+            // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
+            pScene->mRootNode->mTransformation = aiMatrix4x4(1.f, 0.f, 0.f, 0.f,
+                    0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
+        }
 
         DeleteBufferAndCleanup();
     } catch (...) {

+ 4 - 7
code/AssetLib/MMD/MMDPmxParser.cpp

@@ -478,8 +478,7 @@ namespace pmx
 
     void PmxSoftBody::Read(std::istream * /*stream*/, PmxSetting * /*setting*/)
 	{
-		std::cerr << "Not Implemented Exception" << std::endl;
-        throw DeadlyImportError("MMD: Not Implemented Exception");
+        throw DeadlyImportError("MMD: Soft Body support is not implemented.");
     }
 
 	void PmxModel::Init()
@@ -516,15 +515,13 @@ namespace pmx
 		char magic[4];
 		stream->read((char*) magic, sizeof(char) * 4);
 		if (magic[0] != 0x50 || magic[1] != 0x4d || magic[2] != 0x58 || magic[3] != 0x20)
-		{
-			std::cerr << "invalid magic number." << std::endl;
-      throw DeadlyImportError("MMD: invalid magic number.");
+        {
+      throw DeadlyImportError("MMD: Invalid magic number.");
     }
 		stream->read((char*) &version, sizeof(float));
 		if (version != 2.0f && version != 2.1f)
 		{
-			std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl;
-            throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but ", ai_to_string(version));
+            throw DeadlyImportError("MMD: Unsupported version (must be 2.0 or 2.1): ", ai_to_string(version));
     }
 		this->setting.Read(stream);
 

+ 6 - 1
code/AssetLib/MS3D/MS3DLoader.cpp

@@ -215,7 +215,12 @@ void MS3DImporter :: CollectChildJoints(const std::vector<TempJoint>& joints, ai
 void MS3DImporter::InternReadFile( const std::string& pFile,
     aiScene* pScene, IOSystem* pIOHandler)
 {
-    StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
+
+    auto file = pIOHandler->Open(pFile, "rb");
+    if (!file)
+        throw DeadlyImportError("MS3D: Could not open ", pFile);
+
+    StreamReaderLE stream(file);
 
     // CanRead() should have done this already
     char head[10];

+ 7 - 1
code/AssetLib/NDO/NDOLoader.cpp

@@ -116,7 +116,13 @@ void NDOImporter::SetupProperties(const Importer* /*pImp*/)
 void NDOImporter::InternReadFile( const std::string& pFile,
     aiScene* pScene, IOSystem* pIOHandler)
 {
-    StreamReaderBE reader(pIOHandler->Open( pFile, "rb"));
+
+    auto file = pIOHandler->Open( pFile, "rb");
+    if (!file) {
+        throw DeadlyImportError("Nendo: Could not open ", pFile);
+    }
+
+    StreamReaderBE reader(file);
 
     // first 9 bytes are nendo file format ("nendo 1.n")
     const char* head = (const char*)reader.GetPtr();

+ 14 - 0
code/AssetLib/OpenGEX/OpenGEXImporter.cpp

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <assimp/DefaultIOSystem.h>
 #include <assimp/StringComparison.h>
+#include <assimp/StringUtils.h>
 #include <assimp/DefaultLogger.hpp>
 
 #include <assimp/ai_assert.h>
@@ -223,6 +224,18 @@ static void propId2StdString(Property *prop, std::string &name, std::string &key
     }
 }
 
+//------------------------------------------------------------------------------------------------
+static void logDDLParserMessage (LogSeverity severity, const std::string &rawmsg) {
+    std::string msg = ai_str_toprintable(rawmsg);
+    switch (severity) {
+    case ddl_debug_msg: ASSIMP_LOG_DEBUG(msg);         break;
+    case ddl_info_msg:  ASSIMP_LOG_INFO(msg);          break;
+    case ddl_warn_msg:  ASSIMP_LOG_WARN(msg);          break;
+    case ddl_error_msg: ASSIMP_LOG_ERROR(msg);         break;
+    default:            ASSIMP_LOG_VERBOSE_DEBUG(msg); break;
+    }
+}
+
 //------------------------------------------------------------------------------------------------
 OpenGEXImporter::VertexContainer::VertexContainer() :
         m_numColors(0), m_colors(nullptr), m_numUVComps(), m_textureCoords() {
@@ -306,6 +319,7 @@ void OpenGEXImporter::InternReadFile(const std::string &filename, aiScene *pScen
     pIOHandler->Close(file);
 
     OpenDDLParser myParser;
+    myParser.setLogCallback(&logDDLParserMessage);
     myParser.setBuffer(&buffer[0], buffer.size());
     bool success(myParser.parse());
     if (success) {

+ 1 - 1
code/AssetLib/Ply/PlyLoader.cpp

@@ -172,7 +172,7 @@ void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
             (headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
             (headerCheck[2] != 'Y' && headerCheck[2] != 'y')) {
         streamedBuffer.close();
-        throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
+        throw DeadlyImportError("Invalid .ply file: Incorrect magic number (expected 'ply' or 'PLY').");
     }
 
     std::vector<char> mBuffer2;

+ 1 - 1
code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp

@@ -75,7 +75,7 @@ static const aiImporterDesc desc = {
     0,
     0,
     0,
-    "pk3"
+    "bsp pk3"
 };
 
 namespace Assimp {

+ 8 - 2
code/AssetLib/Q3D/Q3DLoader.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "Q3DLoader.h"
+#include <assimp/StringUtils.h>
 #include <assimp/StreamReader.h>
 #include <assimp/fast_atof.h>
 #include <assimp/importerdesc.h>
@@ -106,7 +107,12 @@ const aiImporterDesc *Q3DImporter::GetInfo() const {
 // Imports the given file into the given scene structure.
 void Q3DImporter::InternReadFile(const std::string &pFile,
         aiScene *pScene, IOSystem *pIOHandler) {
-    StreamReaderLE stream(pIOHandler->Open(pFile, "rb"));
+
+    auto file = pIOHandler->Open(pFile, "rb");
+    if (!file)
+        throw DeadlyImportError("Quick3D: Could not open ", pFile);
+
+    StreamReaderLE stream(file);
 
     // The header is 22 bytes large
     if (stream.GetRemainingSize() < 22)
@@ -115,7 +121,7 @@ void Q3DImporter::InternReadFile(const std::string &pFile,
     // Check the file's signature
     if (ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Do", 8) &&
             ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Ds", 8)) {
-        throw DeadlyImportError("Not a Quick3D file. Signature string is: ", std::string((const char *)stream.GetPtr(), 8));
+        throw DeadlyImportError("Not a Quick3D file. Signature string is: ", ai_str_toprintable((const char *)stream.GetPtr(), 8));
     }
 
     // Print the file format version

+ 10 - 4
code/AssetLib/SIB/SIBImporter.cpp

@@ -68,6 +68,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/IOSystem.hpp>
+#include <assimp/StringUtils.h>
 
 #include <map>
 
@@ -166,14 +167,14 @@ static aiColor3D ReadColor(StreamReaderLE *stream) {
 }
 
 static void UnknownChunk(StreamReaderLE * /*stream*/, const SIBChunk &chunk) {
-    char temp[5] = {
+    char temp[4] = {
         static_cast<char>((chunk.Tag >> 24) & 0xff),
         static_cast<char>((chunk.Tag >> 16) & 0xff),
         static_cast<char>((chunk.Tag >> 8) & 0xff),
-        static_cast<char>(chunk.Tag & 0xff), '\0'
+        static_cast<char>(chunk.Tag & 0xff)
     };
 
-    ASSIMP_LOG_WARN((Formatter::format(), "SIB: Skipping unknown '", temp, "' chunk."));
+    ASSIMP_LOG_WARN((Formatter::format(), "SIB: Skipping unknown '", ai_str_toprintable(temp, 4), "' chunk."));
 }
 
 // Reads a UTF-16LE string and returns it at UTF-8.
@@ -804,7 +805,12 @@ static void ReadScene(SIB *sib, StreamReaderLE *stream) {
 // Imports the given file into the given scene structure.
 void SIBImporter::InternReadFile(const std::string &pFile,
         aiScene *pScene, IOSystem *pIOHandler) {
-    StreamReaderLE stream(pIOHandler->Open(pFile, "rb"));
+
+    auto file = pIOHandler->Open(pFile, "rb");
+    if (!file)
+        throw DeadlyImportError("SIB: Could not open ", pFile);
+
+    StreamReaderLE stream(file);
 
     // We should have at least one chunk
     if (stream.GetRemainingSize() < 16)

+ 2 - 2
code/AssetLib/X/XFileImporter.cpp

@@ -667,8 +667,8 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
 
                 // convert to lower case for easier comparison
                 for ( unsigned int c = 0; c < sz.length(); ++c ) {
-                    if ( isalpha( sz[ c ] ) ) {
-                        sz[ c ] = (char) tolower( sz[ c ] );
+                    if ( isalpha( (unsigned char) sz[ c ] ) ) {
+                        sz[ c ] = (char) tolower( (unsigned char) sz[ c ] );
                     }
                 }
 

+ 2 - 2
code/AssetLib/X/XFileParser.cpp

@@ -1245,13 +1245,13 @@ unsigned int XFileParser::ReadInt() {
         }
 
         // at least one digit expected
-        if (!isdigit(*mP))
+        if (!isdigit((unsigned char)*mP))
             ThrowException("Number expected.");
 
         // read digits
         unsigned int number = 0;
         while (mP < mEnd) {
-            if (!isdigit(*mP))
+            if (!isdigit((unsigned char)*mP))
                 break;
             number = number * 10 + (*mP - 48);
             mP++;

+ 0 - 4
code/AssetLib/X3D/X3DImporter.cpp

@@ -167,10 +167,6 @@ bool X3DImporter::CanRead( const std::string &pFile, IOSystem * /*pIOHandler*/,
     return false;
 }
 
-void X3DImporter::GetExtensionList( std::set<std::string> &extensionList ) {
-    extensionList.insert("x3d");
-}
-
 void X3DImporter::InternReadFile( const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler ) {
     std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
     if (!stream) {

+ 0 - 1
code/AssetLib/X3D/X3DImporter.hpp

@@ -307,7 +307,6 @@ public:
     /// \param [in] pIOHandler - pointer to IO helper object.
     void ParseFile(const std::string &pFile, IOSystem *pIOHandler);
     bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const;
-    void GetExtensionList(std::set<std::string> &pExtensionList);
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
     const aiImporterDesc *GetInfo() const;
     void Clear();

+ 1 - 1
code/AssetLib/XGL/XGLLoader.cpp

@@ -200,7 +200,7 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 	// parse the XML file
     mXmlParser = new XmlParser;
     if (!mXmlParser->parse(stream.get())) {
-		return;
+        throw DeadlyImportError("XML parse error while loading XGL file ", pFile);
 	}
 
 	TempScope scope;

+ 2 - 2
code/CApi/CInterfaceIOWrapper.cpp

@@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp {
 
-CIOStreamWrapper::~CIOStreamWrapper(void) {
+CIOStreamWrapper::~CIOStreamWrapper() {
     /* Various places depend on this destructor to close the file */
     if (mFile) {
         mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile);
@@ -78,7 +78,7 @@ aiReturn CIOStreamWrapper::Seek(size_t pOffset,
 }
 
 // ...................................................................
-size_t CIOStreamWrapper::Tell(void) const {
+size_t CIOStreamWrapper::Tell() const {
     return mFile->TellProc(mFile);
 }
 

+ 4 - 18
code/Common/BaseImporter.cpp

@@ -65,20 +65,6 @@ using namespace Assimp;
 // Constructor to be privately used by Importer
 BaseImporter::BaseImporter() AI_NO_EXCEPT
         : m_progress() {
-    /**
-    * Assimp Importer
-    * unit conversions available
-    * if you need another measurment unit add it below.
-    * it's currently defined in assimp that we prefer meters.
-    *
-    * NOTE: Initialised here rather than in the header file
-    * to workaround a VS2013 bug with brace initialisers
-    * */
-    importerUnits[ImporterUnits::M] = 1.0;
-    importerUnits[ImporterUnits::CM] = 0.01;
-    importerUnits[ImporterUnits::MM] = 0.001;
-    importerUnits[ImporterUnits::INCHES] = 0.0254;
-    importerUnits[ImporterUnits::FEET] = 0.3048;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -97,7 +83,7 @@ void BaseImporter::UpdateImporterScale(Importer *pImp) {
     // Set active scaling
     pImp->SetPropertyFloat(AI_CONFIG_APP_SCALE_KEY, static_cast<float>(activeScale));
 
-    ASSIMP_LOG_DEBUG_F("UpdateImporterScale scale set: %f", activeScale);
+    ASSIMP_LOG_DEBUG_F("UpdateImporterScale scale set: ", activeScale);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -193,7 +179,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
         }
 
         for (size_t i = 0; i < read; ++i) {
-            buffer[i] = static_cast<char>(::tolower(buffer[i]));
+            buffer[i] = static_cast<char>(::tolower((unsigned char)buffer[i]));
         }
 
         // It is not a proper handling of unicode files here ...
@@ -214,7 +200,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
             token.clear();
             const char *ptr(tokens[i]);
             for (size_t tokIdx = 0; tokIdx < len; ++tokIdx) {
-                token.push_back(static_cast<char>(tolower(*ptr)));
+                token.push_back(static_cast<char>(tolower(static_cast<unsigned char>(*ptr))));
                 ++ptr;
             }
             const char *r = strstr(buffer, token.c_str());
@@ -223,7 +209,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
             }
             // We need to make sure that we didn't accidentially identify the end of another token as our token,
             // e.g. in a previous version the "gltf " present in some gltf files was detected as "f "
-            if (noAlphaBeforeTokens && (r != buffer && isalpha(r[-1]))) {
+            if (noAlphaBeforeTokens && (r != buffer && isalpha(static_cast<unsigned char>(r[-1])))) {
                 continue;
             }
             // We got a match, either we don't care where it is, or it happens to

+ 15 - 2
code/Common/ImporterRegistry.cpp

@@ -48,6 +48,7 @@ corresponding preprocessor flag to selectively disable formats.
 
 #include <assimp/BaseImporter.h>
 #include <vector>
+#include <cstdlib>
 
 // ------------------------------------------------------------------------------------------------
 // Importers
@@ -204,7 +205,17 @@ corresponding preprocessor flag to selectively disable formats.
 namespace Assimp {
 
 // ------------------------------------------------------------------------------------------------
-void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
+void GetImporterInstanceList(std::vector<BaseImporter *> &out) {    
+    
+    // Some importers may be unimplemented or otherwise unsuitable for general use
+    // in their current state. Devs can set ASSIMP_ENABLE_DEV_IMPORTERS in their
+    // local environment to enable them, otherwise they're left out of the registry.
+    const char *envStr = std::getenv("ASSIMP_ENABLE_DEV_IMPORTERS");
+    bool devImportersEnabled = envStr && strcmp(envStr, "0");
+
+    // Ensure no unused var warnings if all uses are #ifndef'd away below:
+    (void)devImportersEnabled;
+
     // ----------------------------------------------------------------------------
     // Add an instance of each worker class here
     // (register_new_importers_here)
@@ -354,7 +365,9 @@ void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
     out.push_back(new D3MFImporter());
 #endif
 #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
-    out.push_back(new X3DImporter());
+    if (devImportersEnabled) { // https://github.com/assimp/assimp/issues/3647
+        out.push_back(new X3DImporter());
+    }
 #endif
 #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
     out.push_back(new MMDImporter());

+ 4 - 2
code/Common/SceneCombiner.cpp

@@ -45,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // possible as new fields are added to assimp structures.
 
 // ----------------------------------------------------------------------------
-/** 
+/**
   * @file Implements Assimp::SceneCombiner. This is a smart utility
   *       class that combines multiple scenes, meshes, ... into one. Currently
   *       these utilities are used by the IRR and LWS loaders and the
@@ -359,7 +359,7 @@ void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vector<At
 
     // generate the output texture list + an offset table for all texture indices
     if (dest->mNumTextures) {
-        aiTexture **pip = dest->mTextures = new aiTexture *[dest->mNumMaterials];
+        aiTexture **pip = dest->mTextures = new aiTexture *[dest->mNumTextures];
         cnt = 0;
         for (unsigned int n = 0; n < src.size(); ++n) {
             SceneHelper *cur = &src[n];
@@ -638,6 +638,8 @@ void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vector<At
         deleteMe->mMaterials = nullptr;
         delete[] deleteMe->mAnimations;
         deleteMe->mAnimations = nullptr;
+        delete[] deleteMe->mTextures;
+        deleteMe->mTextures = nullptr;
 
         deleteMe->mRootNode = nullptr;
 

+ 3 - 0
code/PostProcessing/GenFaceNormalsProcess.cpp

@@ -70,6 +70,7 @@ GenFaceNormalsProcess::~GenFaceNormalsProcess() {
 // Returns whether the processing step is present in the given flag field.
 bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const {
     force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
+    flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
     return (pFlags & aiProcess_GenNormals) != 0;
 }
 
@@ -134,6 +135,8 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) {
         const aiVector3D *pV1 = &pMesh->mVertices[face.mIndices[0]];
         const aiVector3D *pV2 = &pMesh->mVertices[face.mIndices[1]];
         const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]];
+        if (flippedWindingOrder_)
+            std::swap( pV2, pV3 );
         const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
 
         for (unsigned int i = 0; i < face.mNumIndices; ++i) {

+ 1 - 0
code/PostProcessing/GenFaceNormalsProcess.h

@@ -80,6 +80,7 @@ public:
 private:
     bool GenMeshFaceNormals(aiMesh* pcMesh);
     mutable bool force_ = false;
+    mutable bool flippedWindingOrder_ = false;
 };
 
 } // end of namespace Assimp

+ 3 - 0
code/PostProcessing/GenVertexNormalsProcess.cpp

@@ -70,6 +70,7 @@ GenVertexNormalsProcess::~GenVertexNormalsProcess() {
 // Returns whether the processing step is present in the given flag field.
 bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const {
     force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
+    flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
     return (pFlags & aiProcess_GenSmoothNormals) != 0;
 }
 
@@ -142,6 +143,8 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int m
         const aiVector3D *pV1 = &pMesh->mVertices[face.mIndices[0]];
         const aiVector3D *pV2 = &pMesh->mVertices[face.mIndices[1]];
         const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]];
+        if (flippedWindingOrder_)
+            std::swap( pV2, pV3 );
         const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
 
         for (unsigned int i = 0; i < face.mNumIndices; ++i) {

+ 1 - 0
code/PostProcessing/GenVertexNormalsProcess.h

@@ -104,6 +104,7 @@ private:
     /** Configuration option: maximum smoothing angle, in radians*/
     ai_real configMaxAngle;
     mutable bool force_ = false;
+    mutable bool flippedWindingOrder_ = false;
 };
 
 } // end of namespace Assimp

+ 1 - 1
code/PostProcessing/PretransformVertices.cpp

@@ -429,7 +429,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
 	const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
 
 	if (configTransform) {
-		pScene->mRootNode->mTransformation = configTransformation;
+		pScene->mRootNode->mTransformation = configTransformation * pScene->mRootNode->mTransformation;
 	}
 
 	// first compute absolute transformation matrices for all nodes

+ 1 - 1
contrib/draco/src/draco/io/parser_utils.cc

@@ -252,7 +252,7 @@ DecoderBuffer ParseLineIntoDecoderBuffer(DecoderBuffer *buffer) {
 
 std::string ToLower(const std::string &str) {
   std::string out;
-  std::transform(str.begin(), str.end(), std::back_inserter(out), tolower);
+  std::transform(str.begin(), str.end(), std::back_inserter(out), [](unsigned char c){return tolower(c);});
   return out;
 }
 

+ 2 - 2
contrib/draco/src/draco/io/ply_reader.cc

@@ -268,14 +268,14 @@ std::vector<std::string> PlyReader::SplitWords(const std::string &line) {
   while ((end = line.find_first_of(" \t\n\v\f\r", start)) !=
          std::string::npos) {
     const std::string word(line.substr(start, end - start));
-    if (!std::all_of(word.begin(), word.end(), isspace)) {
+    if (!std::all_of(word.begin(), word.end(), [](unsigned char c){return isspace(c);})) {
       output.push_back(word);
     }
     start = end + 1;
   }
 
   const std::string last_word(line.substr(start));
-  if (!std::all_of(last_word.begin(), last_word.end(), isspace)) {
+  if (!std::all_of(last_word.begin(), last_word.end(), [](unsigned char c){return isspace(c);})) {
     output.push_back(last_word);
   }
   return output;

+ 1 - 1
contrib/gtest/include/gtest/internal/gtest-param-util.h

@@ -644,7 +644,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
 
     // Check for invalid characters
     for (std::string::size_type index = 0; index < name.size(); ++index) {
-      if (!isalnum(name[index]) && name[index] != '_')
+      if (!IsAlNum(name[index]) && name[index] != '_')
         return false;
     }
 

+ 13 - 34
contrib/openddlparser/code/OpenDDLParser.cpp

@@ -72,13 +72,15 @@ const char *getTypeToken(Value::ValueType type) {
 }
 
 static void logInvalidTokenError(char *in, const std::string &exp, OpenDDLParser::logCallback callback) {
-    std::stringstream stream;
-    stream << "Invalid token \"" << *in << "\""
-           << " expected \"" << exp << "\"" << std::endl;
-    std::string full(in);
-    std::string part(full.substr(0, 50));
-    stream << part;
-    callback(ddl_error_msg, stream.str());
+    if (callback) {
+        std::string full(in);
+        std::string part(full.substr(0, 50));
+        std::stringstream stream;
+        stream << "Invalid token \"" << *in << "\" "
+               << "(expected \"" << exp << "\") "
+               << "in: \"" << part << "\"";
+        callback(ddl_error_msg, stream.str());
+    }
 }
 
 static bool isIntegerType(Value::ValueType integerType) {
@@ -111,26 +113,8 @@ static DDLNode *createDDLNode(Text *id, OpenDDLParser *parser) {
     return node;
 }
 
-static void logMessage(LogSeverity severity, const std::string &msg) {
-    std::string log;
-    if (ddl_debug_msg == severity) {
-        log += "Debug:";
-    } else if (ddl_info_msg == severity) {
-        log += "Info :";
-    } else if (ddl_warn_msg == severity) {
-        log += "Warn :";
-    } else if (ddl_error_msg == severity) {
-        log += "Error:";
-    } else {
-        log += "None :";
-    }
-
-    log += msg;
-    std::cout << log;
-}
-
 OpenDDLParser::OpenDDLParser() :
-        m_logCallback(logMessage),
+        m_logCallback(nullptr),
         m_buffer(),
         m_stack(),
         m_context(nullptr) {
@@ -138,7 +122,7 @@ OpenDDLParser::OpenDDLParser() :
 }
 
 OpenDDLParser::OpenDDLParser(const char *buffer, size_t len) :
-        m_logCallback(&logMessage), m_buffer(), m_context(nullptr) {
+        m_logCallback(nullptr), m_buffer(), m_context(nullptr) {
     if (0 != len) {
         setBuffer(buffer, len);
     }
@@ -149,13 +133,8 @@ OpenDDLParser::~OpenDDLParser() {
 }
 
 void OpenDDLParser::setLogCallback(logCallback callback) {
-    if (nullptr != callback) {
-        // install user-specific log callback
-        m_logCallback = callback;
-    } else {
-        // install default log callback
-        m_logCallback = &logMessage;
-    }
+    // install user-specific log callback; null = no log callback
+    m_logCallback = callback;
 }
 
 OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const {

+ 1 - 1
contrib/zip/src/zip.c

@@ -44,7 +44,7 @@
 
 #ifdef _MSC_VER
 #include <io.h>
-#pragma warning(disable : 4706)
+#pragma warning(disable : 4706 4244 4028)
 
 #define ftruncate(fd, sz) (-(_chsize_s((fd), (sz)) != 0))
 #define fileno _fileno

+ 1 - 0
doc/Fileformats.md

@@ -81,6 +81,7 @@ __Exporters__:
 - JSON (for WebGl, via https://github.com/acgessler/assimp2json)
 - ASSBIN
 - STEP
+- [PBRTv4](https://github.com/mmp/pbrt-v4)
 - glTF 1.0 (partial)
 - glTF 2.0 (partial)
 - 3MF ( experimental )

+ 2 - 37
include/assimp/BaseImporter.h

@@ -51,10 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "Exceptional.h"
 
-#include <assimp/ai_assert.h>
 #include <assimp/types.h>
 #include <assimp/ProgressHandler.hpp>
-#include <map>
 #include <set>
 #include <vector>
 #include <memory>
@@ -179,42 +177,10 @@ public:
     /**
      * Will be called only by scale process when scaling is requested.
      */
-    virtual void SetFileScale(double scale) {
+    void SetFileScale(double scale) {
         fileScale = scale;
     }
 
-    virtual double GetFileScale() const {
-        return fileScale;
-    }
-
-    enum ImporterUnits {
-        M,
-        MM,
-        CM,
-        INCHES,
-        FEET
-    };
-
-    /**
-     * Assimp Importer
-     * unit conversions available 
-     * NOTE: Valid options are initialised in the
-     * constructor in the implementation file to
-     * work around a VS2013 compiler bug if support
-     * for that compiler is dropped in the future
-     * initialisation can be moved back here
-     * */
-    std::map<ImporterUnits, double> importerUnits;
-
-    virtual void SetApplicationUnits(const ImporterUnits &unit) {
-        importerScale = importerUnits[unit];
-        applicationUnits = unit;
-    }
-
-    virtual const ImporterUnits &GetApplicationUnits() {
-        return applicationUnits;
-    }
-
     // -------------------------------------------------------------------
     /** Called by #Importer::GetExtensionList for each loaded importer.
      *  Take the extension list contained in the structure returned by
@@ -223,7 +189,6 @@ public:
     void GetExtensionList(std::set<std::string> &extensions);
 
 protected:
-    ImporterUnits applicationUnits = ImporterUnits::M;
     double importerScale = 1.0;
     double fileScale = 1.0;
 
@@ -420,7 +385,7 @@ public: // static utilities
 
 private:
     /* Pushes state into importer for the importer scale */
-    virtual void UpdateImporterScale(Importer *pImp);
+    void UpdateImporterScale(Importer *pImp);
 
 protected:
     /// Error description in case there was one.

+ 1 - 1
include/assimp/ParsingUtils.h

@@ -262,7 +262,7 @@ AI_FORCE_INLINE unsigned int tokenize(const string_type &str, std::vector<string
 inline std::string ai_stdStrToLower(const std::string &str) {
     std::string out(str);
     for (size_t i = 0; i < str.size(); ++i) {
-        out[i] = (char) tolower(out[i]);
+        out[i] = (char) tolower((unsigned char)out[i]);
     }
     return out;
 }

+ 4 - 4
include/assimp/StringComparison.h

@@ -146,8 +146,8 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2) {
 #else
     char c1, c2;
     do {
-        c1 = tolower(*s1++);
-        c2 = tolower(*s2++);
+        c1 = tolower((unsigned char)*(s1++));
+        c2 = tolower((unsigned char)*(s2++));
     } while (c1 && (c1 == c2));
     return c1 - c2;
 #endif
@@ -197,8 +197,8 @@ inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n) {
     unsigned int p = 0;
     do {
         if (p++ >= n) return 0;
-        c1 = tolower(*s1++);
-        c2 = tolower(*s2++);
+        c1 = tolower((unsigned char)*(s1++));
+        c2 = tolower((unsigned char)*(s2++));
     } while (c1 && (c1 == c2));
 
     return c1 - c2;

+ 31 - 4
include/assimp/StringUtils.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2021, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -55,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <cstdlib>
 #include <locale>
 #include <sstream>
+#include <iomanip>
 
 #ifdef _MSC_VER
 #define AI_SIZEFMT "%Iu"
@@ -157,7 +157,7 @@ AI_FORCE_INLINE std::string ai_decimal_to_hexa(T toConvert) {
     ss >> result;
 
     for (size_t i = 0; i < result.size(); ++i) {
-        result[i] = (char)toupper(result[i]);
+        result[i] = (char)toupper((unsigned char)result[i]);
     }
 
     return result;
@@ -177,7 +177,7 @@ AI_FORCE_INLINE std::string ai_rgba2hex(int r, int g, int b, int a, bool with_he
     if (with_head) {
         ss << "#";
     }
-    ss << std::hex << (r << 24 | g << 16 | b << 8 | a);
+    ss << std::hex << std::setfill('0') << std::setw(8) << (r << 24 | g << 16 | b << 8 | a);
 
     return ss.str();
 }
@@ -249,4 +249,31 @@ AI_FORCE_INLINE std::string ai_str_toupper(const std::string &in) {
     return out;
 }
 
-#endif
+// ---------------------------------------------------------------------------------
+/// @brief  Make a string printable by replacing all non-printable characters with
+///         the specified placeholder character.
+/// @param  in  The incoming string.
+/// @param  placeholder  Placeholder character, default is a question mark.
+/// @return The string, with all non-printable characters replaced.
+AI_FORCE_INLINE std::string ai_str_toprintable(const std::string &in, char placeholder = '?') {
+    std::string out(in);
+    std::transform(out.begin(), out.end(), out.begin(), [placeholder] (unsigned char c) {
+        return isprint(c) ? (char)c :  placeholder;
+    });
+    return out;
+}
+
+// ---------------------------------------------------------------------------------
+/// @brief  Make a string printable by replacing all non-printable characters with
+///         the specified placeholder character.
+/// @param  in  The incoming string.
+/// @param  len The length of the incoming string.
+/// @param  placeholder  Placeholder character, default is a question mark.
+/// @return The string, with all non-printable characters replaced. Will return an
+///         empty string if in is null or len is <= 0.
+AI_FORCE_INLINE std::string ai_str_toprintable(const char *in, int len, char placeholder = '?') {
+    return (in && len > 0) ? ai_str_toprintable(std::string(in, len), placeholder) : std::string();
+}
+
+
+#endif // INCLUDED_AI_STRINGUTILS_H

+ 6 - 1
include/assimp/XmlParser.h

@@ -43,8 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_IRRXML_WRAPPER
 
 #include <assimp/DefaultLogger.hpp>
+#include <assimp/ai_assert.h>
+
 #include "BaseImporter.h"
 #include "IOStream.hpp"
+
 #include <pugixml.hpp>
 #include <vector>
 
@@ -136,7 +139,9 @@ public:
         if (parse_result.status == pugi::status_ok) {
             return true;
         } else {
-            ASSIMP_LOG_DEBUG("Error while parse xml.");
+            std::ostringstream oss;
+            oss << "Error while parsing XML: " << parse_result.description() << " @ " << parse_result.offset;
+            ASSIMP_LOG_DEBUG(oss.str());
             return false;
         }
     }

+ 3 - 2
include/assimp/fast_atof.h

@@ -29,6 +29,7 @@
 #include "StringComparison.h"
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Exceptional.h>
+#include <assimp/StringUtils.h>
 
 #ifdef _MSC_VER
 #  include <stdint.h>
@@ -193,7 +194,7 @@ uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_ino
 
     if ( *in < '0' || *in > '9' ) {
         // The string is known to be bad, so don't risk printing the whole thing.
-        throw ExceptionType("The string \"", std::string(in).substr(0, 100), "\" cannot be converted into a value." );
+        throw ExceptionType("The string \"", ai_str_toprintable(in, 30), "\" cannot be converted into a value." );
     }
 
     for ( ;; ) {
@@ -293,7 +294,7 @@ const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
     if (!(c[0] >= '0' && c[0] <= '9') &&
             !((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')) {
         // The string is known to be bad, so don't risk printing the whole thing.
-        throw ExceptionType("Cannot parse string \"", std::string(c).substr(0, 100), 
+        throw ExceptionType("Cannot parse string \"", ai_str_toprintable(c, 30),
                                     "\" as a real number: does not start with digit "
                                     "or decimal point followed by digit.");
     }

+ 2 - 2
port/PyAssimp/pyassimp/structs.py

@@ -1,6 +1,6 @@
 #-*- coding: utf-8 -*-
 
-from ctypes import POINTER, c_void_p, c_uint, c_char, c_float, Structure, c_char_p, c_double, c_ubyte, c_size_t, c_uint32
+from ctypes import POINTER, c_void_p, c_uint, c_char, c_float, Structure, c_double, c_ubyte, c_size_t, c_uint32
 
 
 class Vector2D(Structure):
@@ -1121,7 +1121,7 @@ class Scene(Structure):
             ("mMetadata", POINTER(Metadata)),
 
             # Internal data, do not touch
-            ("mPrivate", c_char_p),
+            ("mPrivate", POINTER(c_char)),
         ]
 
 assimp_structs_as_tuple = (Matrix4x4,

+ 41 - 42
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp

@@ -42,22 +42,12 @@ void ModelLoader::Draw(ID3D11DeviceContext * devcon) {
 	}
 }
 
-std::string textype;
-
 Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) {
 	// Data to fill
 	std::vector<VERTEX> vertices;
 	std::vector<UINT> indices;
 	std::vector<Texture> textures;
 
-	if (mesh->mMaterialIndex >= 0) {
-		aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
-
-		if (textype.empty()) {
-            textype = determineTextureType(scene, mat);
-        }
-	}
-
 	// Walk through each of the mesh's vertices
 	for (UINT i = 0; i < mesh->mNumVertices; i++) {
 		VERTEX vertex;
@@ -108,9 +98,10 @@ std::vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextu
 		if (!skip) {   // If texture hasn't been loaded already, load it
 			HRESULT hr;
 			Texture texture;
-			if (textype == "embedded compressed texture") {
-				int textureindex = getTextureIndex(&str);
-				texture.texture = getTextureFromModel(scene, textureindex);
+
+			const aiTexture* embeddedTexture = scene->GetEmbeddedTexture(str.C_Str());
+			if (embeddedTexture != nullptr) {
+				texture.texture = loadEmbeddedTexture(embeddedTexture);
 			} else {
 				std::string filename = std::string(str.C_Str());
 				filename = directory_ + '/' + filename;
@@ -148,38 +139,46 @@ void ModelLoader::processNode(aiNode * node, const aiScene * scene) {
 	}
 }
 
-std::string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat) {
-	aiString textypeStr;
-	mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr);
-	std::string textypeteststr = textypeStr.C_Str();
-	if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5") {
-		if (scene->mTextures[0]->mHeight == 0) {
-			return "embedded compressed texture";
-		} else {
-			return "embedded non-compressed texture";
-		}
-	}
-	if (textypeteststr.find('.') != std::string::npos) {
-		return "textures are on disk";
-	}
-
-    return ".";
-}
-
-int ModelLoader::getTextureIndex(aiString * str) {
-	std::string tistr;
-	tistr = str->C_Str();
-	tistr = tistr.substr(1);
-	return stoi(tistr);
-}
-
-ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex) {
+ID3D11ShaderResourceView * ModelLoader::loadEmbeddedTexture(const aiTexture* embeddedTexture) {
 	HRESULT hr;
-	ID3D11ShaderResourceView *texture;
+	ID3D11ShaderResourceView *texture = nullptr;
+
+	if (embeddedTexture->mHeight != 0) {
+		// Load an uncompressed ARGB8888 embedded texture
+		D3D11_TEXTURE2D_DESC desc;
+		desc.Width = embeddedTexture->mWidth;
+		desc.Height = embeddedTexture->mHeight;
+		desc.MipLevels = 1;
+		desc.ArraySize = 1;
+		desc.SampleDesc.Count = 1;
+		desc.SampleDesc.Quality = 0;
+		desc.Usage = D3D11_USAGE_DEFAULT;
+		desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+		desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+		desc.CPUAccessFlags = 0;
+		desc.MiscFlags = 0;
+
+		D3D11_SUBRESOURCE_DATA subresourceData;
+		subresourceData.pSysMem = embeddedTexture->pcData;
+		subresourceData.SysMemPitch = embeddedTexture->mWidth * 4;
+		subresourceData.SysMemSlicePitch = embeddedTexture->mWidth * embeddedTexture->mHeight * 4;
+
+		ID3D11Texture2D *texture2D = nullptr;
+		hr = dev_->CreateTexture2D(&desc, &subresourceData, &texture2D);
+		if (FAILED(hr))
+			MessageBox(hwnd_, "CreateTexture2D failed!", "Error!", MB_ICONERROR | MB_OK);
+
+		hr = dev_->CreateShaderResourceView(texture2D, nullptr, &texture);
+		if (FAILED(hr))
+			MessageBox(hwnd_, "CreateShaderResourceView failed!", "Error!", MB_ICONERROR | MB_OK);
+
+		return texture;
+	}
 
-	int* size = reinterpret_cast<int*>(&scene->mTextures[textureindex]->mWidth);
+	// mHeight is 0, so try to load a compressed texture of mWidth bytes
+	const size_t size = embeddedTexture->mWidth;
 
-	hr = CreateWICTextureFromMemory(dev_, devcon_, reinterpret_cast<unsigned char*>(scene->mTextures[textureindex]->pcData), *size, nullptr, &texture);
+	hr = CreateWICTextureFromMemory(dev_, devcon_, reinterpret_cast<const unsigned char*>(embeddedTexture->pcData), size, nullptr, &texture);
 	if (FAILED(hr))
 		MessageBox(hwnd_, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK);
 

+ 1 - 3
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h

@@ -35,9 +35,7 @@ private:
 	void processNode(aiNode* node, const aiScene* scene);
 	Mesh processMesh(aiMesh* mesh, const aiScene* scene);
 	std::vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName, const aiScene* scene);
-	std::string determineTextureType(const aiScene* scene, aiMaterial* mat);
-	int getTextureIndex(aiString* str);
-	ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex);
+	ID3D11ShaderResourceView* loadEmbeddedTexture(const aiTexture* embeddedTexture);
 };
 
 #endif // !MODEL_LOADER_H

BIN
test/test.3mf


+ 11 - 2
test/unit/utStringUtils.cpp

@@ -42,9 +42,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/StringUtils.h>
 
 class utStringUtils : public ::testing::Test {
+    // empty
 };
 
-TEST_F( utStringUtils, to_string_Test ) {
+TEST_F(utStringUtils, to_string_Test ) {
     std::string res = ai_to_string( 1 );
     EXPECT_EQ( res, "1" );
 
@@ -52,7 +53,7 @@ TEST_F( utStringUtils, to_string_Test ) {
     EXPECT_EQ( res, "1" );
 }
 
-TEST_F( utStringUtils, ai_strtofTest ) {
+TEST_F(utStringUtils, ai_strtofTest ) {
     float res = ai_strtof( nullptr, nullptr );
     EXPECT_FLOAT_EQ( res, 0.0f );
 
@@ -66,3 +67,11 @@ TEST_F( utStringUtils, ai_strtofTest ) {
     res = ai_strtof( begin, end );
     EXPECT_FLOAT_EQ( res, 200.0f );
 }
+
+TEST_F(utStringUtils, ai_rgba2hexTest) {
+    std::string result;
+    result = ai_rgba2hex(255, 255, 255, 255, true);
+    EXPECT_EQ(result, "#ffffffff");
+    result = ai_rgba2hex(0, 0, 0, 0, false);
+    EXPECT_EQ(result, "00000000");
+}

+ 5 - 4
tools/assimp_cmd/ImageExtractor.cpp

@@ -130,8 +130,9 @@ int SaveAsBMP(FILE *file, const aiTexel *data, unsigned int width, unsigned int
             s[0] = t->b;
             s[1] = t->g;
             s[2] = t->r;
-            if (4 == numc)
+            if (4 == numc) {
                 s[3] = t->a;
+            }
         }
     }
 
@@ -296,7 +297,7 @@ int Assimp_Extract(const char *const *params, unsigned int num) {
 
         // check whether the requested texture is existing
         if (texIdx >= scene->mNumTextures) {
-            ::printf("assimp extract: Texture %i requested, but there are just %i textures\n",
+            ::printf("assimp extract: Texture %u requested, but there are just %i textures\n",
                     texIdx, scene->mNumTextures);
             return AssimpCmdExtractError::TextureIndexIsOutOfRange;
         }
@@ -325,7 +326,7 @@ int Assimp_Extract(const char *const *params, unsigned int num) {
         // if the texture is a compressed one, we'll export
         // it to its native file format
         if (!tex->mHeight) {
-            printf("assimp extract: Texture %i is compressed (%s). Writing native file format.\n",
+            printf("assimp extract: Texture %u is compressed (%s). Writing native file format.\n",
                     i, tex->achFormatHint);
 
             // modify file extension
@@ -350,7 +351,7 @@ int Assimp_Extract(const char *const *params, unsigned int num) {
         }
         ::fclose(p);
 
-        printf("assimp extract: Wrote texture %i to %s\n", i, out_cpy.c_str());
+        printf("assimp extract: Wrote texture %u to %s\n", i, out_cpy.c_str());
         if (texIdx != 0xffffffff) {
             return m;
         }

+ 2 - 2
tools/assimp_view/Material.cpp

@@ -272,7 +272,7 @@ bool CMaterialManager::TryLongerPath(char* szTemp,aiString* p_szString)
                             szExtFound - 1 - info.cFileName);
 
                         for (unsigned int i = 0; i < iSizeFound;++i)
-                            info.cFileName[i] = (CHAR)tolower(info.cFileName[i]);
+                            info.cFileName[i] = (CHAR)tolower((unsigned char)info.cFileName[i]);
 
                         if (0 == memcmp(info.cFileName,szFile2, std::min(iSizeFound,iSize)))
                         {
@@ -354,7 +354,7 @@ int CMaterialManager::FindValidPath(aiString* p_szString)
             for (unsigned int i = 0;;++i)
             {
                 if ('\0' == szTemp[i])break;
-                szTemp[i] = (char)tolower(szTemp[i]);
+                szTemp[i] = (char)tolower((unsigned char)szTemp[i]);
             }
 
             if(TryLongerPath(szTemp,p_szString))return 1;