|
@@ -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
|