Kaynağa Gözat

Fix empty mesh handling

Kim Kulling 1 yıl önce
ebeveyn
işleme
0b0ec713f6

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

@@ -103,10 +103,6 @@ Discreet3DSImporter::Discreet3DSImporter() :
     // empty
 }
 
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-Discreet3DSImporter::~Discreet3DSImporter() = default;
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {

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

@@ -59,7 +59,6 @@ struct aiNode;
 
 namespace Assimp    {
 
-
 using namespace D3DS;
 
 // ---------------------------------------------------------------------------------
@@ -68,7 +67,7 @@ using namespace D3DS;
 class Discreet3DSImporter : public BaseImporter {
 public:
     Discreet3DSImporter();
-    ~Discreet3DSImporter() override;
+    ~Discreet3DSImporter() override = default;
 
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.

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

@@ -95,7 +95,7 @@ FBXImporter::FBXImporter() = default;
 // Returns whether the class can handle the format of the given file.
 bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const {
 	// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
-	static const char *tokens[] = { "fbx" };
+	static const char *tokens[] = { " \n\r\n " };
 	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 

+ 0 - 7
code/AssetLib/IQM/IQMImporter.cpp

@@ -100,13 +100,6 @@ bool IQMImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool c
         if (!pIOHandler) {
             return true;
         }
-        /*
-         * don't use CheckMagicToken because that checks with swapped bytes too, leading to false
-         * positives. This magic is not uint32_t, but char[4], so memcmp is the best way
-
-        const char* tokens[] = {"3DMO", "3dmo"};
-        return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
-        */
         std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
         unsigned char data[15];
         if (!pStream || 15 != pStream->Read(data, 1, 15)) {

+ 4 - 2
code/AssetLib/Obj/ObjFileImporter.cpp

@@ -78,7 +78,9 @@ using namespace std;
 ObjFileImporter::ObjFileImporter() :
         m_Buffer(),
         m_pRootObject(nullptr),
-        m_strAbsPath(std::string(1, DefaultIOSystem().getOsSeparator())) {}
+        m_strAbsPath(std::string(1, DefaultIOSystem().getOsSeparator())) {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 //  Destructor.
@@ -102,7 +104,7 @@ const aiImporterDesc *ObjFileImporter::GetInfo() const {
 //  Obj-file import implementation
 void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
     // Read file into memory
-    static const std::string mode = "rb";
+    static constexpr char mode[] = "rb";
     auto streamCloser = [&](IOStream *pStream) {
         pIOHandler->Close(pStream);
     };

+ 105 - 99
code/AssetLib/XGL/XGLLoader.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2022, assimp team
+Copyright (c) 2006-2023, assimp team
 
 All rights reserved.
 
@@ -56,62 +56,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <memory>
 #include <utility>
-//#include <cctype>
-//#include <memory>
 
-using namespace Assimp;
+namespace Assimp {
 
-namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp
+static constexpr uint32_t ErrorId = ~0u;
 
 template <>
 const char *LogFunctions<XGLImporter>::Prefix() {
 	return "XGL: ";
 }
 
-} // namespace Assimp
-
-static const aiImporterDesc desc = {
-	"XGL Importer",
-	"",
-	"",
-	"",
-	aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportCompressedFlavour,
-	0,
-	0,
-	0,
-	0,
-	"xgl zgl"
-};
+static constexpr aiImporterDesc desc = {
+	"XGL Importer", "", "",  "",
+    aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportCompressedFlavour,
+	0,	0,	0,	0,	"xgl zgl"};
 
 // ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by Importer
-XGLImporter::XGLImporter() :
-        mXmlParser(nullptr),
-        m_scene(nullptr) {
+XGLImporter::XGLImporter() : mXmlParser(nullptr), m_scene(nullptr) {
     // empty
 }
 
 // ------------------------------------------------------------------------------------------------
-// Destructor, private as well
 XGLImporter::~XGLImporter() {
 	delete mXmlParser;
 }
 
 // ------------------------------------------------------------------------------------------------
-// Returns whether the class can handle the format of the given file.
 bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
 	static const char *tokens[] = { "<world>", "<World>", "<WORLD>" };
 	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------
-// Get a list of all file extensions which are handled by this class
 const aiImporterDesc *XGLImporter::GetInfo() const {
 	return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
-// Imports the given file into the given scene structure.
 void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
 	std::vector<char> uncompressed;
@@ -159,7 +140,7 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 
 	std::vector<aiMesh *> &meshes = scope.meshes_linear;
 	std::vector<aiMaterial *> &materials = scope.materials_linear;
-	if (!meshes.size() || !materials.size()) {
+	if (meshes.empty() || materials.empty()) {
 		ThrowException("failed to extract data from XGL file, no meshes loaded");
 	}
 
@@ -199,9 +180,10 @@ void XGLImporter::ReadWorld(XmlNode &node, TempScope &scope) {
 	}
 
 	aiNode *const nd = ReadObject(node, scope);
-	if (!nd) {
+	if (nd == nullptr) {
 		ThrowException("failure reading <world>");
 	}
+
 	if (nd->mName.length == 0) {
 		nd->mName.Set("WORLD");
 	}
@@ -254,15 +236,19 @@ aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope) {
 			const std::string &s = ai_stdStrToLower(child.name());
 			if (s == "mesh") {
 				const size_t prev = scope.meshes_linear.size();
-                bool empty;
-				if (ReadMesh(child, scope, empty)) {
+				if (ReadMesh(child, scope)) {
 					const size_t newc = scope.meshes_linear.size();
 					for (size_t i = 0; i < newc - prev; ++i) {
 						meshes.push_back(static_cast<unsigned int>(i + prev));
 					}
+				} else {
+					printf("skipping empty mesh\n");
 				}
 			} else if (s == "mat") {
-				ReadMaterial(child, scope);
+				const uint32_t matId = ReadMaterial(child, scope);
+                if (matId == ErrorId) {
+                    ThrowException("Invalid material id detected.");
+                }
 			} else if (s == "object") {
 				children.push_back(ReadObject(child, scope));
 			} else if (s == "objectref") {
@@ -438,18 +424,25 @@ aiMesh *XGLImporter::ToOutputMesh(const TempMaterialMesh &m) {
     return mesh.release();
 }
 
+
 // ------------------------------------------------------------------------------------------------
-bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope, bool &empty) {
-	TempMesh t;
+inline static unsigned int generateMeshId(unsigned int meshId, bool nor, bool uv) {
+    unsigned int currentMeshId = meshId | ((nor ? 1 : 0) << 31) | ((uv ? 1 : 0) << 30);
+    return currentMeshId;
+}
 
+// ------------------------------------------------------------------------------------------------
+bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) {
+	TempMesh t;
+    uint32_t matId = 99999;
+    bool mesh_created = false;
 	std::map<unsigned int, TempMaterialMesh> bymat;
     const unsigned int mesh_id = ReadIDAttr(node);
-    bool empty_mesh = true;
 	for (XmlNode &child : node.children()) {
         const std::string &s = ai_stdStrToLower(child.name());
 
 		if (s == "mat") {
-			ReadMaterial(child, scope);
+			matId = ReadMaterial(child, scope);
 		} else if (s == "p") {
 			pugi::xml_attribute attr = child.attribute("ID");
 			if (attr.empty()) {
@@ -477,66 +470,41 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope, bool &empty) {
 		} else if (s == "f" || s == "l" || s == "p") {
 			const unsigned int vcount = s == "f" ? 3 : (s == "l" ? 2 : 1);
 
-			unsigned int mid = ~0u;
-			TempFace tf[3];
+			unsigned int meshId = ErrorId;
+            TempFace tempFace[3] = {};
 			bool has[3] = { false };
-			for (XmlNode &sub_child : child.children()) {
-                const std::string &scn = ai_stdStrToLower(sub_child.name());
-                if (scn == "fv1" || scn == "lv1" || scn == "pv1") {
-					ReadFaceVertex(sub_child, t, tf[0]);
-					has[0] = true;
-                } else if (scn == "fv2" || scn == "lv2") {
-					ReadFaceVertex(sub_child, t, tf[1]);
-					has[1] = true;
-                } else if (scn == "fv3") {
-					ReadFaceVertex(sub_child, t, tf[2]);
-					has[2] = true;
-                } else if (scn == "mat") {
-					if (mid != ~0u) {
-						LogWarn("only one material tag allowed per <f>");
-					}
-					mid = ResolveMaterialRef(sub_child, scope);
-                } else if (scn == "matref") {
-					if (mid != ~0u) {
-						LogWarn("only one material tag allowed per <f>");
-					}
-					mid = ResolveMaterialRef(sub_child, scope);
-				}
-			}
-            if (has[0] || has[1] || has[2]) {
-                empty_mesh = false;
-            }
-
-			if (mid == ~0u) {
+            meshId = ReadVertices(child, t, tempFace, has, meshId, scope);
+            if (meshId == ErrorId) {
 				ThrowException("missing material index");
 			}
 
-			bool nor = false;
-			bool uv = false;
+			bool nor = false, uv = false;
 			for (unsigned int i = 0; i < vcount; ++i) {
 				if (!has[i]) {
 					ThrowException("missing face vertex data");
 				}
 
-				nor = nor || tf[i].has_normal;
-				uv = uv || tf[i].has_uv;
+				nor = nor || tempFace[i].has_normal;
+				uv = uv || tempFace[i].has_uv;
 			}
 
-			if (mid >= (1 << 30)) {
+			if (meshId >= (1 << 30)) {
 				LogWarn("material indices exhausted, this may cause errors in the output");
 			}
-			unsigned int meshId = mid | ((nor ? 1 : 0) << 31) | ((uv ? 1 : 0) << 30);
+            const unsigned int currentMeshId = generateMeshId(meshId, nor, uv);
 
-			TempMaterialMesh &mesh = bymat[meshId];
-			mesh.matid = mid;
+            // Generate the temp mesh
+			TempMaterialMesh &mesh = bymat[currentMeshId];
+            mesh.matid = meshId;
+            mesh_created = true;
 
 			for (unsigned int i = 0; i < vcount; ++i) {
-				mesh.positions.push_back(tf[i].pos);
+				mesh.positions.push_back(tempFace[i].pos);
 				if (nor) {
-					mesh.normals.push_back(tf[i].normal);
+					mesh.normals.push_back(tempFace[i].normal);
 				}
 				if (uv) {
-					mesh.uvs.push_back(tf[i].uv);
+					mesh.uvs.push_back(tempFace[i].uv);
 				}
 
 				mesh.pflags |= 1 << (vcount - 1);
@@ -546,25 +514,59 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope, bool &empty) {
 		}
 	}
 
-	// finally extract output meshes and add them to the scope
-	using pairt = std::pair<const unsigned int, TempMaterialMesh>;
-	for (const pairt &p : bymat) {
-		aiMesh *const m = ToOutputMesh(p.second);
-		scope.meshes_linear.push_back(m);
-
-		// if this is a definition, keep it on the stack
-		if (mesh_id != ~0u) {
-			scope.meshes.insert(std::pair<unsigned int, aiMesh *>(mesh_id, m));
-		}
-	}
-    if (empty_mesh) {
-        LogWarn("Mesh is empty, skipping.");
-        empty = empty_mesh;
-        return false;
+    if (!mesh_created) {
+        TempMaterialMesh &mesh = bymat[mesh_id];
+        mesh.matid = matId;
     }
 
+	// finally extract output meshes and add them to the scope
+    AppendOutputMeshes(bymat, scope, mesh_id);
+
 	// no id == not a reference, insert this mesh right *here*
-	return mesh_id == ~0u;
+    return mesh_id == ErrorId;
+}
+
+// ----------------------------------------------------------------------------------------------
+void XGLImporter::AppendOutputMeshes(std::map<unsigned int, TempMaterialMesh> bymat, TempScope &scope,
+        const unsigned int mesh_id) {
+    using pairt = std::pair<const unsigned int, TempMaterialMesh>;
+    for (const pairt &p : bymat) {
+        aiMesh *const m = ToOutputMesh(p.second);
+        scope.meshes_linear.push_back(m);
+
+        // if this is a definition, keep it on the stack
+        if (mesh_id != ErrorId) {
+            scope.meshes.insert(std::pair<unsigned int, aiMesh *>(mesh_id, m));
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------------------------
+unsigned int XGLImporter::ReadVertices(XmlNode &child, TempMesh t, TempFace *tf, bool *has, unsigned int mid, TempScope &scope) {
+    for (XmlNode &sub_child : child.children()) {
+        const std::string &scn = ai_stdStrToLower(sub_child.name());
+        if (scn == "fv1" || scn == "lv1" || scn == "pv1") {
+            ReadFaceVertex(sub_child, t, tf[0]);
+            has[0] = true;
+        } else if (scn == "fv2" || scn == "lv2") {
+            ReadFaceVertex(sub_child, t, tf[1]);
+            has[1] = true;
+        } else if (scn == "fv3") {
+            ReadFaceVertex(sub_child, t, tf[2]);
+            has[2] = true;
+        } else if (scn == "mat") {
+            if (mid != ErrorId) {
+                LogWarn("only one material tag allowed per <f>");
+            }
+            mid = ResolveMaterialRef(sub_child, scope);
+        } else if (scn == "matref") {
+            if (mid != ErrorId) {
+                LogWarn("only one material tag allowed per <f>");
+            }
+            mid = ResolveMaterialRef(sub_child, scope);
+        }
+    }
+    return mid;
 }
 
 // ----------------------------------------------------------------------------------------------
@@ -598,10 +600,10 @@ unsigned int XGLImporter::ResolveMaterialRef(XmlNode &node, TempScope &scope) {
 }
 
 // ------------------------------------------------------------------------------------------------
-void XGLImporter::ReadMaterial(XmlNode &node, TempScope &scope) {
+unsigned int XGLImporter::ReadMaterial(XmlNode &node, TempScope &scope) {
     const unsigned int mat_id = ReadIDAttr(node);
 
-	auto *mat(new aiMaterial);
+	auto *mat = new aiMaterial;
 	for (XmlNode &child : node.children()) {
         const std::string &s = ai_stdStrToLower(child.name());
 		if (s == "amb") {
@@ -627,6 +629,8 @@ void XGLImporter::ReadMaterial(XmlNode &node, TempScope &scope) {
 
 	scope.materials[mat_id] = mat;
 	scope.materials_linear.push_back(mat);
+
+    return mat_id;
 }
 
 // ----------------------------------------------------------------------------------------------
@@ -683,7 +687,7 @@ unsigned int XGLImporter::ReadIDAttr(XmlNode &node) {
 		}
 	}
 
-	return ~0u;
+	return ErrorId;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -712,14 +716,14 @@ unsigned int XGLImporter::ReadIndexFromText(XmlNode &node) {
     const char *s = v.c_str();
 	if (!SkipSpaces(&s)) {
 		LogError("unexpected EOL, failed to parse index element");
-		return ~0u;
+        return ErrorId;
 	}
-	const char *se;
+	const char *se = nullptr;
 	const unsigned int t = strtoul10(s, &se);
 
 	if (se == s) {
 		LogError("failed to read index");
-		return ~0u;
+        return ErrorId;
 	}
 
 	return t;
@@ -786,4 +790,6 @@ aiColor3D XGLImporter::ReadCol3(XmlNode &node) {
 	return aiColor3D(v.x, v.y, v.z);
 }
 
+} // namespace Assimp
+
 #endif // ASSIMP_BUILD_NO_XGL_IMPORTER

+ 12 - 18
code/AssetLib/XGL/XGLLoader.h

@@ -69,12 +69,14 @@ namespace Assimp {
  */
 class XGLImporter : public BaseImporter, public LogFunctions<XGLImporter> {
 public:
+    /// @brief  The class constructor.
     XGLImporter();
+
+    /// @brief The class destructor.
     ~XGLImporter() override;
 
-    // -------------------------------------------------------------------
-    /** Returns whether the class can handle the format of the given file.
-     *  See BaseImporter::CanRead() for details.    */
+    /// @brief Returns whether the class can handle the format of the given file.
+    /// @see BaseImporter::CanRead() for details.    */
     bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
             bool checkSig) const override;
 
@@ -92,10 +94,7 @@ protected:
 
 private:
     struct TempScope {
-        TempScope() :
-                light() {
-            // empty
-        }
+        TempScope() : light() {}
 
         ~TempScope() {
             for (aiMesh *m : meshes_linear) {
@@ -145,9 +144,7 @@ private:
     };
 
     struct TempMaterialMesh {
-        TempMaterialMesh() :
-                pflags(),
-                matid() {
+        TempMaterialMesh() : pflags(), matid() {
             // empty
         }
 
@@ -160,9 +157,7 @@ private:
     };
 
     struct TempFace {
-        TempFace() :
-                has_uv(),
-                has_normal() {
+        TempFace() : has_uv(), has_normal() {
             // empty
         }
 
@@ -175,26 +170,25 @@ private:
 
 private:
     void Cleanup();
-
     std::string GetElementName();
     bool ReadElement();
     bool ReadElementUpToClosing(const char *closetag);
     bool SkipToText();
     unsigned int ReadIDAttr(XmlNode &node);
-
     void ReadWorld(XmlNode &node, TempScope &scope);
     void ReadLighting(XmlNode &node, TempScope &scope);
     aiLight *ReadDirectionalLight(XmlNode &node);
     aiNode *ReadObject(XmlNode &node, TempScope &scope);
-    bool ReadMesh(XmlNode &node, TempScope &scope, bool &empty);
-    void ReadMaterial(XmlNode &node, TempScope &scope);
+    bool ReadMesh(XmlNode &node, TempScope &scope);
+    void AppendOutputMeshes(std::map<unsigned int, TempMaterialMesh> bymat, TempScope &scope, const unsigned int mesh_id);
+    unsigned int ReadVertices(XmlNode &child, TempMesh t, TempFace *tf, bool *has, unsigned int mid, TempScope &scope);
+    unsigned int ReadMaterial(XmlNode &node, TempScope &scope);
     aiVector2D ReadVec2(XmlNode &node);
     aiVector3D ReadVec3(XmlNode &node);
     aiColor3D ReadCol3(XmlNode &node);
     aiMatrix4x4 ReadTrafo(XmlNode &node);
     unsigned int ReadIndexFromText(XmlNode &node);
     float ReadFloat(XmlNode &node);
-
     aiMesh *ToOutputMesh(const TempMaterialMesh &m);
     void ReadFaceVertex(XmlNode &node, const TempMesh &t, TempFace &out);
     unsigned int ResolveMaterialRef(XmlNode &node, TempScope &scope);

+ 5 - 1
code/Common/Compression.cpp

@@ -66,6 +66,10 @@ Compression::Compression() :
 Compression::~Compression() {
     ai_assert(mImpl != nullptr);
 
+    if (mImpl->mOpen) {
+        close();
+    }
+
     delete mImpl;
 }
 
@@ -124,7 +128,7 @@ static int getFlushMode(Compression::FlushMode flush) {
     return z_flush;
 }
 
-constexpr size_t MYBLOCK = 32786;
+static constexpr size_t MYBLOCK = 32786;
 
 size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
     ai_assert(mImpl != nullptr);

+ 16 - 3
contrib/zlib/zconf.h.included

@@ -40,6 +40,9 @@
 #  define crc32                 z_crc32
 #  define crc32_combine         z_crc32_combine
 #  define crc32_combine64       z_crc32_combine64
+#  define crc32_combine_gen     z_crc32_combine_gen
+#  define crc32_combine_gen64   z_crc32_combine_gen64
+#  define crc32_combine_op      z_crc32_combine_op
 #  define crc32_z               z_crc32_z
 #  define deflate               z_deflate
 #  define deflateBound          z_deflateBound
@@ -351,6 +354,9 @@
 #    ifdef FAR
 #      undef FAR
 #    endif
+#    ifndef WIN32_LEAN_AND_MEAN
+#      define WIN32_LEAN_AND_MEAN
+#    endif
 #    include <windows.h>
      /* No need for _export, use ZLIB.DEF instead. */
      /* For complete Windows compatibility, use WINAPI, not __stdcall. */
@@ -469,11 +475,18 @@ typedef uLong FAR uLongf;
 #  undef _LARGEFILE64_SOURCE
 #endif
 
-#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
-#  define Z_HAVE_UNISTD_H
+#ifndef Z_HAVE_UNISTD_H
+#  ifdef __WATCOMC__
+#    define Z_HAVE_UNISTD_H
+#  endif
+#endif
+#ifndef Z_HAVE_UNISTD_H
+#  if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32)
+#    define Z_HAVE_UNISTD_H
+#  endif
 #endif
 #ifndef Z_SOLO
-#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#  if defined(Z_HAVE_UNISTD_H)
 #    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
 #    ifdef VMS
 #      include <unixio.h>       /* for off_t */