Browse Source

Merge branch 'stb-image-updated' of https://github.com/krishty/assimp into stb-image-updated

Krishty 4 years ago
parent
commit
ab43f3fefd
34 changed files with 151 additions and 162 deletions
  1. 1 1
      code/AssetLib/3DS/3DSConverter.cpp
  2. 33 26
      code/AssetLib/3MF/D3MFImporter.cpp
  3. 1 1
      code/AssetLib/3MF/D3MFImporter.h
  4. 1 1
      code/AssetLib/AMF/AMFImporter.cpp
  5. 2 2
      code/AssetLib/BVH/BVHLoader.cpp
  6. 3 3
      code/AssetLib/Blender/BlenderLoader.cpp
  7. 1 1
      code/AssetLib/Collada/ColladaParser.cpp
  8. 1 1
      code/AssetLib/FBX/FBXMaterial.cpp
  9. 1 1
      code/AssetLib/IFC/IFCLoader.cpp
  10. 1 1
      code/AssetLib/M3D/M3DImporter.cpp
  11. 1 1
      code/AssetLib/MD3/MD3Loader.cpp
  12. 1 0
      code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp
  13. 2 2
      code/AssetLib/X/XFileImporter.cpp
  14. 2 2
      code/AssetLib/X/XFileParser.cpp
  15. 3 17
      code/Common/BaseImporter.cpp
  16. 15 2
      code/Common/ImporterRegistry.cpp
  17. 3 0
      code/PostProcessing/GenFaceNormalsProcess.cpp
  18. 1 0
      code/PostProcessing/GenFaceNormalsProcess.h
  19. 3 0
      code/PostProcessing/GenVertexNormalsProcess.cpp
  20. 1 0
      code/PostProcessing/GenVertexNormalsProcess.h
  21. 1 1
      code/PostProcessing/PretransformVertices.cpp
  22. 1 1
      contrib/draco/src/draco/io/parser_utils.cc
  23. 2 2
      contrib/draco/src/draco/io/ply_reader.cc
  24. 1 1
      contrib/gtest/include/gtest/internal/gtest-param-util.h
  25. 2 37
      include/assimp/BaseImporter.h
  26. 1 1
      include/assimp/ParsingUtils.h
  27. 4 4
      include/assimp/StringComparison.h
  28. 4 4
      include/assimp/StringUtils.h
  29. 3 0
      include/assimp/XmlParser.h
  30. 41 42
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
  31. 1 3
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h
  32. BIN
      test/test.3mf
  33. 11 2
      test/unit/utStringUtils.cpp
  34. 2 2
      tools/assimp_view/Material.cpp

+ 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;

+ 33 - 26
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 {
@@ -163,7 +163,7 @@ public:
         }
         XmlNode resNode = node.child(XmlTag::resources);
         for (auto &currentNode : resNode.children()) {
-            const std::string &currentNodeName = currentNode.name();
+            const std::string currentNodeName = currentNode.name();
             if (currentNodeName == XmlTag::object) {
                 ReadObject(currentNode);
             } else if (currentNodeName == XmlTag::basematerials) {
@@ -173,8 +173,9 @@ public:
             }
         }
 
-        for (auto &currentNode : resNode.children()) {
-            const std::string &currentNodeName = currentNode.name();
+        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;
@@ -196,7 +197,7 @@ 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);
@@ -211,6 +212,7 @@ public:
             for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it) {
                 if (it->second->getType() == ResourceType::RT_Object) {
                     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];
                     }
@@ -352,7 +354,8 @@ private:
                 mMeshCount++;
             } else if (currentName == D3MF::XmlTag::components) {
                 for (XmlNode &currentSubNode : currentNode.children()) {
-                    if (currentSubNode.name() == D3MF::XmlTag::component) {
+                    const std::string subNodeName = currentSubNode.name();
+                    if (subNodeName == D3MF::XmlTag::component) {
                         int objectId = -1;
                         std::string componentTransformStr;
                         aiMatrix4x4 componentTransform;
@@ -360,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 });
+                        }
                     }
                 }
             }
@@ -374,7 +378,7 @@ private:
         aiMesh *mesh = new aiMesh();
 
         for (XmlNode &currentNode : node.children()) {
-            const std::string &currentName = currentNode.name();
+            const std::string currentName = currentNode.name();
             if (currentName == XmlTag::vertices) {
                 ImportVertices(currentNode, mesh);
             } else if (currentName == XmlTag::triangles) {
@@ -402,8 +406,8 @@ private:
     void ImportVertices(XmlNode &node, aiMesh *mesh) {
         std::vector<aiVector3D> vertices;
         for (XmlNode &currentNode : node.children()) {
-            const std::string &currentName = currentNode.name();
-            if (currentName == D3MF::XmlTag::vertex) {
+            const std::string currentName = currentNode.name();
+            if (currentName == XmlTag::vertex) {
                 vertices.push_back(ReadVertex(currentNode));
             }
         }
@@ -415,22 +419,22 @@ private:
 
     aiVector3D ReadVertex(XmlNode &node) {
         aiVector3D vertex;
-        vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::x).as_string(), nullptr);
-        vertex.y = ai_strtof(node.attribute(D3MF::XmlTag::y).as_string(), nullptr);
-        vertex.z = ai_strtof(node.attribute(D3MF::XmlTag::z).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);
 
@@ -472,10 +476,11 @@ private:
             BaseMaterials *baseMaterials = new BaseMaterials(id);
 
             for (XmlNode &currentNode : node.children()) {
-                if (currentNode.name() == XmlTag::basematerials_base) {
+                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;
                 }
             }
 
@@ -564,6 +569,8 @@ private:
 
 } //namespace D3MF
 
+using namespace D3MF;
+
 static const aiImporterDesc desc = {
     "3mf Importer",
     "",
@@ -597,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();
     }
 
@@ -613,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;

+ 1 - 1
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 {

+ 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 - 3
code/AssetLib/Blender/BlenderLoader.cpp

@@ -420,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;

+ 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);

+ 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") {

+ 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"
 };
 
 // ------------------------------------------------------------------------------------------------

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

@@ -136,7 +136,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 */

+ 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

+ 1 - 0
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

+ 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++;

+ 3 - 17
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;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -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());

+ 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;
     }
 

+ 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;

+ 4 - 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,4 @@ AI_FORCE_INLINE std::string ai_str_toupper(const std::string &in) {
     return out;
 }
 
-#endif
+#endif // INCLUDED_AI_STRINGUTILS_H

+ 3 - 0
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>
 

+ 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");
+}

+ 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;