From c10d592b7966e339bbc99bae14c8e8ba4752932d Mon Sep 17 00:00:00 2001 From: Jean-Louis Date: Sat, 26 Dec 2020 02:36:24 +0100 Subject: [PATCH 1/8] Fix material parsing in the 3MF importer --- code/AssetLib/3MF/D3MFImporter.cpp | 60 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index 089a680cf..7844c1a14 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -68,14 +68,11 @@ namespace D3MF { class XmlSerializer { public: - using MatArray = std::vector; - using MatId2MatArray = std::map>; XmlSerializer(XmlParser *xmlParser) : mMeshes(), - mMatArray(), - mActiveMatGroup(99999999), - mMatId2MatArray(), + mBasematerialsDictionnary(), + mMaterialCount(0), mXmlParser(xmlParser) { // empty } @@ -131,10 +128,14 @@ public: std::copy(mMeshes.begin(), mMeshes.end(), scene->mMeshes); // import the materials - scene->mNumMaterials = static_cast(mMatArray.size()); + scene->mNumMaterials = static_cast(mMaterialCount); if (0 != scene->mNumMaterials) { scene->mMaterials = new aiMaterial *[scene->mNumMaterials]; - std::copy(mMatArray.begin(), mMatArray.end(), scene->mMaterials); + for (auto it = mBasematerialsDictionnary.begin(); it != mBasematerialsDictionnary.end(); it++) { + for (unsigned int i = 0; i < it->second.size(); ++i) { + scene->mMaterials[it->second[i].first] = it->second[i].second; + } + } } // create the scene-graph @@ -242,10 +243,13 @@ private: const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::triangle) { faces.push_back(ReadTriangle(currentNode)); - const char *pidToken = currentNode.attribute(D3MF::XmlTag::p1.c_str()).as_string(); - if (nullptr != pidToken) { - int matIdx(std::atoi(pidToken)); - mesh->mMaterialIndex = matIdx; + const char *pidToken = currentNode.attribute(D3MF::XmlTag::pid.c_str()).as_string(); + const char *p1Token = currentNode.attribute(D3MF::XmlTag::p1.c_str()).as_string(); + if (nullptr != pidToken && nullptr != p1Token) { + int pid(std::atoi(pidToken)); + int p1(std::atoi(p1Token)); + mesh->mMaterialIndex = mBasematerialsDictionnary[pid][p1].first; + // TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material } } } @@ -274,22 +278,18 @@ private: const char *baseMaterialId = node.attribute(D3MF::XmlTag::basematerials_id.c_str()).as_string(); if (nullptr != baseMaterialId) { unsigned int id = std::atoi(baseMaterialId); - const size_t newMatIdx(mMatArray.size()); - if (id != mActiveMatGroup) { - mActiveMatGroup = id; - MatId2MatArray::const_iterator it(mMatId2MatArray.find(id)); - if (mMatId2MatArray.end() == it) { - MatIdArray.clear(); - mMatId2MatArray[id] = MatIdArray; - } else { - MatIdArray = it->second; + std::vector > materials; + + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) + { + if (currentNode.name() == D3MF::XmlTag::basematerials_base) { + materials.push_back(std::make_pair(mMaterialCount, readMaterialDef(currentNode, id))); + mMaterialCount++; } } - MatIdArray.push_back(static_cast(newMatIdx)); - mMatId2MatArray[mActiveMatGroup] = MatIdArray; - } - mMatArray.push_back(readMaterialDef(node)); + mBasematerialsDictionnary.insert(std::make_pair(id, materials)); + } } bool parseColor(const char *color, aiColor4D &diffuse) { @@ -347,7 +347,7 @@ private: } } - aiMaterial *readMaterialDef(XmlNode &node) { + aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId) { aiMaterial *mat(nullptr); const char *name(nullptr); const std::string nodeName = node.name(); @@ -355,14 +355,15 @@ private: name = node.attribute(D3MF::XmlTag::basematerials_name.c_str()).as_string(); std::string stdMatName; aiString matName; - std::string strId(to_string(mActiveMatGroup)); + std::string strId(to_string(basematerialsId)); stdMatName += "id"; stdMatName += strId; stdMatName += "_"; if (nullptr != name) { stdMatName += std::string(name); } else { - stdMatName += "basemat"; + stdMatName += "basemat_"; + stdMatName += to_string(mMaterialCount - basematerialsId); } matName.Set(stdMatName); @@ -382,9 +383,8 @@ private: }; std::vector mMetaData; std::vector mMeshes; - MatArray mMatArray; - unsigned int mActiveMatGroup; - MatId2MatArray mMatId2MatArray; + std::map>> mBasematerialsDictionnary; + unsigned int mMaterialCount; XmlParser *mXmlParser; }; From 09520384618c4ab26c0c14a1016f6e95b4f05c3b Mon Sep 17 00:00:00 2001 From: Jean-Louis Date: Sat, 26 Dec 2020 03:02:18 +0100 Subject: [PATCH 2/8] Small refactoring on 3MF export --- code/AssetLib/3MF/D3MFExporter.cpp | 45 ++++++++++-------------------- 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/code/AssetLib/3MF/D3MFExporter.cpp b/code/AssetLib/3MF/D3MFExporter.cpp index 8fb9009d1..b4e5d515c 100644 --- a/code/AssetLib/3MF/D3MFExporter.cpp +++ b/code/AssetLib/3MF/D3MFExporter.cpp @@ -137,7 +137,7 @@ bool D3MFExporter::exportContentTypes() { mContentOutput << std::endl; mContentOutput << ""; mContentOutput << std::endl; - exportContentTyp(XmlTag::CONTENT_TYPES_ARCHIVE); + zipContentType(XmlTag::CONTENT_TYPES_ARCHIVE); return true; } @@ -162,7 +162,7 @@ bool D3MFExporter::exportRelations() { mRelOutput << ""; mRelOutput << std::endl; - writeRelInfoToFile("_rels", ".rels"); + zipRelInfo("_rels", ".rels"); mRelOutput.flush(); return true; @@ -196,7 +196,7 @@ bool D3MFExporter::export3DModel() { info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; mRelations.push_back(info); - writeModelToArchive("3D", "3DModel.model"); + zipModel("3D", "3DModel.model"); mModelOutput.flush(); return true; @@ -357,42 +357,27 @@ void D3MFExporter::writeBuild() { mModelOutput << std::endl; } -void D3MFExporter::exportContentTyp(const std::string &filename) { - if (nullptr == m_zipArchive) { - throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr."); - } - const std::string entry = filename; - zip_entry_open(m_zipArchive, entry.c_str()); - - const std::string &exportTxt(mContentOutput.str()); - zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size()); - - zip_entry_close(m_zipArchive); +void D3MFExporter::zipContentType(const std::string &filename) { + addFileInZip(filename, mContentOutput.str()); } -void D3MFExporter::writeModelToArchive(const std::string &folder, const std::string &modelName) { - if (nullptr == m_zipArchive) { - throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr."); - } +void D3MFExporter::zipModel(const std::string &folder, const std::string &modelName) { const std::string entry = folder + "/" + modelName; - zip_entry_open(m_zipArchive, entry.c_str()); - - const std::string &exportTxt(mModelOutput.str()); - zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size()); - - zip_entry_close(m_zipArchive); + addFileInZip(entry, mModelOutput.str()); } -void D3MFExporter::writeRelInfoToFile(const std::string &folder, const std::string &relName) { +void D3MFExporter::zipRelInfo(const std::string &folder, const std::string &relName) { + const std::string entry = folder + "/" + relName; + addFileInZip(entry, mRelOutput.str()); +} + +void D3MFExporter::addFileInZip(const std::string& entry, const std::string& content) { if (nullptr == m_zipArchive) { throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr."); } - const std::string entry = folder + "/" + relName; + zip_entry_open(m_zipArchive, entry.c_str()); - - const std::string &exportTxt(mRelOutput.str()); - zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size()); - + zip_entry_write(m_zipArchive, content.c_str(), content.size()); zip_entry_close(m_zipArchive); } From 0ec8d6e285c3c5d99b71dae3afd1d3e36627edac Mon Sep 17 00:00:00 2001 From: Jean-Louis Date: Sat, 26 Dec 2020 14:04:45 +0100 Subject: [PATCH 3/8] [3MF] Missing file in previous commit + parse object material in the importer --- code/AssetLib/3MF/3MFXmlTags.h | 1 + code/AssetLib/3MF/D3MFExporter.h | 9 ++++--- code/AssetLib/3MF/D3MFImporter.cpp | 39 +++++++++++++++++++++--------- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/code/AssetLib/3MF/3MFXmlTags.h b/code/AssetLib/3MF/3MFXmlTags.h index 0c6b5d1eb..abad7793c 100644 --- a/code/AssetLib/3MF/3MFXmlTags.h +++ b/code/AssetLib/3MF/3MFXmlTags.h @@ -67,6 +67,7 @@ namespace XmlTag { 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"; diff --git a/code/AssetLib/3MF/D3MFExporter.h b/code/AssetLib/3MF/D3MFExporter.h index 24ddc9bba..abde3cea3 100644 --- a/code/AssetLib/3MF/D3MFExporter.h +++ b/code/AssetLib/3MF/D3MFExporter.h @@ -82,9 +82,12 @@ protected: void writeVertex( const aiVector3D &pos ); void writeFaces( aiMesh *mesh, unsigned int matIdx ); void writeBuild(); - void exportContentTyp( const std::string &filename ); - void writeModelToArchive( const std::string &folder, const std::string &modelName ); - void writeRelInfoToFile( const std::string &folder, const std::string &relName ); + + // Zip the data + void zipContentType( const std::string &filename ); + void zipModel( const std::string &folder, const std::string &modelName ); + void zipRelInfo( const std::string &folder, const std::string &relName ); + void addFileInZip( const std::string &entry, const std::string &content ); private: std::string mArchiveName; diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index 7844c1a14..f3bf92b83 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -145,23 +145,34 @@ public: } private: + + 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; + } + } + aiNode *ReadObject(XmlNode &node, aiScene *scene) { std::unique_ptr nodePtr(new aiNode()); std::vector meshIds; - std::string name, type; - pugi::xml_attribute attr = node.attribute(D3MF::XmlTag::id.c_str()); - if (!attr.empty()) { - name = attr.as_string(); - } - attr = node.attribute(D3MF::XmlTag::type.c_str()); - if (!attr.empty()) { - type = attr.as_string(); + std::string id, type, pid, pindex; + 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); + + if (!hasId) { + return nullptr; } nodePtr->mParent = scene->mRootNode; - nodePtr->mName.Set(name); + nodePtr->mName.Set(id); size_t meshIdx = mMeshes.size(); @@ -169,7 +180,13 @@ private: const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::mesh) { auto mesh = ReadMesh(currentNode); - mesh->mName.Set(name); + mesh->mName.Set(id); + if (hasPid && hasPindex && mBasematerialsDictionnary.find(atoi(pid.c_str())) != mBasematerialsDictionnary.end()) { + int iPid = atoi(pid.c_str()); + int iPindex = atoi(pindex.c_str()); + mesh->mMaterialIndex = mBasematerialsDictionnary[iPid][iPindex].first; + std::cout << "Set material " << mesh->mMaterialIndex << " from pid " << iPid << " and pindex " << iPindex << std::endl; + } mMeshes.push_back(mesh); meshIds.push_back(static_cast(meshIdx)); ++meshIdx; @@ -245,7 +262,7 @@ private: faces.push_back(ReadTriangle(currentNode)); const char *pidToken = currentNode.attribute(D3MF::XmlTag::pid.c_str()).as_string(); const char *p1Token = currentNode.attribute(D3MF::XmlTag::p1.c_str()).as_string(); - if (nullptr != pidToken && nullptr != p1Token) { + if (nullptr != pidToken && nullptr != p1Token && mBasematerialsDictionnary.find(std::atoi(pidToken)) != mBasematerialsDictionnary.end()) { int pid(std::atoi(pidToken)); int p1(std::atoi(p1Token)); mesh->mMaterialIndex = mBasematerialsDictionnary[pid][p1].first; From eed75aaf2c8b4d390f7e2a2bb71c1aab73bd7779 Mon Sep 17 00:00:00 2001 From: Jean-Louis Date: Sat, 26 Dec 2020 14:57:52 +0100 Subject: [PATCH 4/8] Remove debug print --- code/AssetLib/3MF/D3MFImporter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index f3bf92b83..84defe903 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -185,7 +185,6 @@ private: int iPid = atoi(pid.c_str()); int iPindex = atoi(pindex.c_str()); mesh->mMaterialIndex = mBasematerialsDictionnary[iPid][iPindex].first; - std::cout << "Set material " << mesh->mMaterialIndex << " from pid " << iPid << " and pindex " << iPindex << std::endl; } mMeshes.push_back(mesh); meshIds.push_back(static_cast(meshIdx)); From 629147043e4b565dc08be1135956824cef4c076e Mon Sep 17 00:00:00 2001 From: Jean-Louis Date: Sun, 27 Dec 2020 18:13:49 +0100 Subject: [PATCH 5/8] XmlParser: Fixed an error message when the file was correctly parsed --- include/assimp/XmlParser.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/assimp/XmlParser.h b/include/assimp/XmlParser.h index 3d430a278..46bb57295 100644 --- a/include/assimp/XmlParser.h +++ b/include/assimp/XmlParser.h @@ -121,7 +121,6 @@ public: return false; } - bool result = false; const size_t len = stream->FileSize(); mData.resize(len + 1); memset(&mData[0], '\0', len + 1); @@ -130,11 +129,11 @@ public: mDoc = new pugi::xml_document(); pugi::xml_parse_result parse_result = mDoc->load_string(&mData[0], pugi::parse_full); if (parse_result.status == pugi::status_ok) { + return true; + } else { ASSIMP_LOG_DEBUG("Error while parse xml."); - result = true; + return false; } - - return result; } pugi::xml_document *getDocument() const { From eda967bd02fd973060b1ad17db10aad37da9822f Mon Sep 17 00:00:00 2001 From: Jean-Louis Date: Mon, 28 Dec 2020 12:31:54 +0100 Subject: [PATCH 6/8] Parse the node + refactoring --- code/AssetLib/3MF/3MFXmlTags.h | 2 + code/AssetLib/3MF/D3MFImporter.cpp | 340 ++++++++++++++++++++--------- 2 files changed, 238 insertions(+), 104 deletions(-) diff --git a/code/AssetLib/3MF/3MFXmlTags.h b/code/AssetLib/3MF/3MFXmlTags.h index abad7793c..49e19c658 100644 --- a/code/AssetLib/3MF/3MFXmlTags.h +++ b/code/AssetLib/3MF/3MFXmlTags.h @@ -55,6 +55,8 @@ namespace XmlTag { 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"; diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index 84defe903..47cb5fa8d 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -66,19 +66,73 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace D3MF { +enum class ResourceType { + RT_Object, + RT_BaseMaterials, + RT_Unknown +}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...) + +class Resource +{ +public: + Resource(int id) : + mId(id) {} + + virtual ~Resource() {} + + int mId; + + virtual ResourceType getType() { + return ResourceType::RT_Unknown; + } +}; + +class BaseMaterials : public Resource { +public: + BaseMaterials(int id) : + Resource(id), + mMaterials(), + mMaterialIndex() {} + + std::vector mMaterials; + std::vector mMaterialIndex; + + virtual ResourceType getType() { + return ResourceType::RT_BaseMaterials; + } +}; + +class Object : public Resource { +public: + std::vector mMeshes; + std::vector mMeshIndex; + std::vector mComponents; + + Object(int id) : + Resource(id) {} + + virtual ResourceType getType() { + return ResourceType::RT_Object; + } +}; + + class XmlSerializer { public: XmlSerializer(XmlParser *xmlParser) : mMeshes(), - mBasematerialsDictionnary(), + mResourcesDictionnary(), mMaterialCount(0), + mMeshCount(0), mXmlParser(xmlParser) { // empty } ~XmlSerializer() { - // empty + for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) { + delete it->second; + } } void ImportXml(aiScene *scene) { @@ -86,10 +140,8 @@ public: return; } - scene->mRootNode = new aiNode(); - std::vector children; + scene->mRootNode = new aiNode("3MF"); - std::string nodeName; XmlNode node = mXmlParser->getRootNode().child("model"); if (node.empty()) { return; @@ -98,9 +150,7 @@ public: for (XmlNode currentNode = resNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tNodeName = currentNode.name(); if (currentNodeName == D3MF::XmlTag::object) { - children.push_back(ReadObject(currentNode, scene)); - } else if (currentNodeName == D3MF::XmlTag::build) { - // + ReadObject(currentNode);; } else if (currentNodeName == D3MF::XmlTag::basematerials) { ReadBaseMaterials(currentNode); } else if (currentNodeName == D3MF::XmlTag::meta) { @@ -108,10 +158,75 @@ public: } } - if (scene->mRootNode->mName.length == 0) { - scene->mRootNode->mName.Set("3MF"); + XmlNode buildNode = node.child("build"); + for (XmlNode currentNode = buildNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string ¤tNodeName = currentNode.name(); + if (currentNodeName == D3MF::XmlTag::item) { + int objectId = -1; + std::string transform; + getNodeAttribute(currentNode, D3MF::XmlTag::objectid, objectId); + bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transform); + + aiNode *sceneNode = new aiNode("item"); + auto it = mResourcesDictionnary.find(objectId); + if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) { + Object *obj = static_cast(it->second); + std::vector meshes; + getMeshesList(obj, meshes); + sceneNode->mNumMeshes = static_cast(meshes.size()); + sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes]; + std::copy(meshes.begin(), meshes.end(), sceneNode->mMeshes); + + if (hasTransform) { + // split the string + std::vector numbers; + std::string currentNumber; + for (size_t i = 0; i < transform.size(); ++i) { + const char c = transform[i]; + if (c == ' ') { + if (currentNumber.size() > 0) { + float f = std::stof(currentNumber); + numbers.push_back(f); + currentNumber.clear(); + } + } else { + currentNumber.push_back(c); + } + } + if (currentNumber.size() > 0) { + float f = std::stof(currentNumber); + numbers.push_back(f); + } + + aiMatrix4x4 transformMatrix; + transformMatrix.a1 = numbers[0]; + transformMatrix.b1 = numbers[1]; + transformMatrix.c1 = numbers[2]; + transformMatrix.d1 = 0; + + transformMatrix.a2 = numbers[3]; + transformMatrix.b2 = numbers[4]; + transformMatrix.c2 = numbers[5]; + transformMatrix.d2 = 0; + + transformMatrix.a3 = numbers[6]; + transformMatrix.b3 = numbers[7]; + transformMatrix.c3 = numbers[8]; + transformMatrix.d3 = 0; + + transformMatrix.a4 = numbers[9]; + transformMatrix.b4 = numbers[10]; + transformMatrix.c4 = numbers[11]; + transformMatrix.d4 = 1; + sceneNode->mTransformation = transformMatrix; + } + + scene->mRootNode->addChildren(1, &sceneNode); + } + } } + // import the metadata if (!mMetaData.empty()) { const size_t numMeta(mMetaData.size()); @@ -131,17 +246,15 @@ public: scene->mNumMaterials = static_cast(mMaterialCount); if (0 != scene->mNumMaterials) { scene->mMaterials = new aiMaterial *[scene->mNumMaterials]; - for (auto it = mBasematerialsDictionnary.begin(); it != mBasematerialsDictionnary.end(); it++) { - for (unsigned int i = 0; i < it->second.size(); ++i) { - scene->mMaterials[it->second[i].first] = it->second[i].second; + for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) { + if (it->second->getType() == ResourceType::RT_BaseMaterials) { + BaseMaterials *baseMaterials = static_cast(it->second); + for (unsigned int i = 0; i < baseMaterials->mMaterials.size(); ++i) { + scene->mMaterials[baseMaterials->mMaterialIndex[i]] = baseMaterials->mMaterials[i]; + } } } } - - // create the scene-graph - scene->mRootNode->mNumChildren = static_cast(children.size()); - scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren](); - std::copy(children.begin(), children.end(), scene->mRootNode->mChildren); } private: @@ -156,53 +269,79 @@ private: } } - aiNode *ReadObject(XmlNode &node, aiScene *scene) { - std::unique_ptr nodePtr(new aiNode()); + bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &value) { + std::string strValue; + bool ret = getNodeAttribute(node, attribute, strValue); + if (ret) { + value = std::atoi(strValue.c_str()); + return true; + } else { + return false; + } + } - std::vector meshIds; + void getMeshesList(Object *obj, std::vector &meshes) { + for (size_t i = 0; i < obj->mMeshIndex.size(); ++i) { + meshes.push_back(obj->mMeshIndex[i]); + } + for (size_t i = 0; i < obj->mComponents.size(); ++i) { + int componentId = obj->mComponents[i]; + auto it = mResourcesDictionnary.find(componentId); + if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) + getMeshesList(static_cast(it->second), meshes); + } + } - std::string id, type, pid, pindex; + 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 = to_string(id); + if (!hasId) { - return nullptr; + return; } - nodePtr->mParent = scene->mRootNode; - nodePtr->mName.Set(id); - - size_t meshIdx = mMeshes.size(); + Object *obj = new Object(id); for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::mesh) { auto mesh = ReadMesh(currentNode); - mesh->mName.Set(id); - if (hasPid && hasPindex && mBasematerialsDictionnary.find(atoi(pid.c_str())) != mBasematerialsDictionnary.end()) { - int iPid = atoi(pid.c_str()); - int iPindex = atoi(pindex.c_str()); - mesh->mMaterialIndex = mBasematerialsDictionnary[iPid][iPindex].first; + mesh->mName.Set(idStr); + + if (hasPid) { + auto it = mResourcesDictionnary.find(pid); + if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) { + BaseMaterials *materials = static_cast(it->second); + mesh->mMaterialIndex = materials->mMaterialIndex[pindex]; + } } mMeshes.push_back(mesh); - meshIds.push_back(static_cast(meshIdx)); - ++meshIdx; + + obj->mMeshes.push_back(mesh); + 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) { + int objectId = -1; + if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId)) + obj->mComponents.push_back(objectId); + } + } } } - nodePtr->mNumMeshes = static_cast(meshIds.size()); - - nodePtr->mMeshes = new unsigned int[nodePtr->mNumMeshes]; - - std::copy(meshIds.begin(), meshIds.end(), nodePtr->mMeshes); - - return nodePtr.release(); + mResourcesDictionnary.insert(std::make_pair(id, obj)); } aiMesh *ReadMesh(XmlNode &node) { aiMesh *mesh = new aiMesh(); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::vertices) { @@ -241,6 +380,7 @@ private: mesh->mNumVertices = static_cast(vertices.size()); mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; std::copy(vertices.begin(), vertices.end(), mesh->mVertices); } @@ -258,14 +398,23 @@ private: for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::triangle) { - faces.push_back(ReadTriangle(currentNode)); - const char *pidToken = currentNode.attribute(D3MF::XmlTag::pid.c_str()).as_string(); - const char *p1Token = currentNode.attribute(D3MF::XmlTag::p1.c_str()).as_string(); - if (nullptr != pidToken && nullptr != p1Token && mBasematerialsDictionnary.find(std::atoi(pidToken)) != mBasematerialsDictionnary.end()) { - int pid(std::atoi(pidToken)); - int p1(std::atoi(p1Token)); - mesh->mMaterialIndex = mBasematerialsDictionnary[pid][p1].first; - // TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material + aiFace face = ReadTriangle(currentNode); + faces.push_back(face); + + int pid, p1; + 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->second->getType() == ResourceType::RT_BaseMaterials) { + BaseMaterials *baseMaterials = static_cast(it->second); + mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1]; + } + // TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material + } } } } @@ -290,21 +439,20 @@ private: } void ReadBaseMaterials(XmlNode &node) { - std::vector MatIdArray; - const char *baseMaterialId = node.attribute(D3MF::XmlTag::basematerials_id.c_str()).as_string(); - if (nullptr != baseMaterialId) { - unsigned int id = std::atoi(baseMaterialId); - std::vector > materials; + int id = -1; + if (getNodeAttribute(node, D3MF::XmlTag::basematerials_id, id)) { + BaseMaterials* baseMaterials = new BaseMaterials(id); for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { if (currentNode.name() == D3MF::XmlTag::basematerials_base) { - materials.push_back(std::make_pair(mMaterialCount, readMaterialDef(currentNode, id))); + baseMaterials->mMaterialIndex.push_back(mMaterialCount); + baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id)); mMaterialCount++; } } - mBasematerialsDictionnary.insert(std::make_pair(id, materials)); + mResourcesDictionnary.insert(std::make_pair(id, baseMaterials)); } } @@ -320,37 +468,24 @@ private: } const char *buf(color); - if ('#' != *buf) { + if ('#' != buf[0]) { return false; } - ++buf; - char comp[3] = { 0, 0, '\0' }; - comp[0] = *buf; - ++buf; - comp[1] = *buf; - ++buf; - diffuse.r = static_cast(strtol(comp, nullptr, 16)) / ai_real(255.0); + char r[3] = { buf[1], buf[2], '\0' }; + diffuse.r = static_cast(strtol(r, nullptr, 16)) / ai_real(255.0); - comp[0] = *buf; - ++buf; - comp[1] = *buf; - ++buf; - diffuse.g = static_cast(strtol(comp, nullptr, 16)) / ai_real(255.0); + char g[3] = { buf[3], buf[4], '\0' }; + diffuse.g = static_cast(strtol(g, nullptr, 16)) / ai_real(255.0); - comp[0] = *buf; - ++buf; - comp[1] = *buf; - ++buf; - diffuse.b = static_cast(strtol(comp, nullptr, 16)) / ai_real(255.0); + char b[3] = { buf[5], buf[6], '\0' }; + diffuse.b = static_cast(strtol(b, nullptr, 16)) / ai_real(255.0); if (7 == len) return true; - comp[0] = *buf; - ++buf; - comp[1] = *buf; - ++buf; - diffuse.a = static_cast(strtol(comp, nullptr, 16)) / ai_real(255.0); + + char a[3] = { buf[7], buf[8], '\0' }; + diffuse.a = static_cast(strtol(a, nullptr, 16)) / ai_real(255.0); return true; } @@ -364,32 +499,29 @@ private: } aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId) { - aiMaterial *mat(nullptr); - const char *name(nullptr); - const std::string nodeName = node.name(); - if (nodeName == D3MF::XmlTag::basematerials_base) { - name = node.attribute(D3MF::XmlTag::basematerials_name.c_str()).as_string(); - std::string stdMatName; - aiString matName; - std::string strId(to_string(basematerialsId)); - stdMatName += "id"; - stdMatName += strId; - stdMatName += "_"; - if (nullptr != name) { - stdMatName += std::string(name); - } else { - stdMatName += "basemat_"; - stdMatName += to_string(mMaterialCount - basematerialsId); - } - matName.Set(stdMatName); + aiMaterial *material = new aiMaterial(); + material->mNumProperties = 0; + std::string name; + bool hasName = getNodeAttribute(node, D3MF::XmlTag::basematerials_name, name); - mat = new aiMaterial; - mat->AddProperty(&matName, AI_MATKEY_NAME); - - assignDiffuseColor(node, mat); + std::string stdMaterialName; + std::string strId(to_string(basematerialsId)); + stdMaterialName += "id"; + stdMaterialName += strId; + stdMaterialName += "_"; + if (hasName) { + stdMaterialName += std::string(name); + } else { + stdMaterialName += "basemat_"; + stdMaterialName += to_string(mMaterialCount - basematerialsId); } - return mat; + aiString assimpMaterialName(stdMaterialName); + material->AddProperty(&assimpMaterialName, AI_MATKEY_NAME); + + assignDiffuseColor(node, material); + + return material; } private: @@ -399,8 +531,8 @@ private: }; std::vector mMetaData; std::vector mMeshes; - std::map>> mBasematerialsDictionnary; - unsigned int mMaterialCount; + std::map mResourcesDictionnary; + unsigned int mMaterialCount, mMeshCount; XmlParser *mXmlParser; }; From 4025c57fd02810c513e2066339dbccb07f3905ea Mon Sep 17 00:00:00 2001 From: Jean-Louis Date: Mon, 28 Dec 2020 15:47:20 +0100 Subject: [PATCH 7/8] [3MF] Parse the transform of the components --- code/AssetLib/3MF/D3MFImporter.cpp | 140 ++++++++++++++++------------- 1 file changed, 78 insertions(+), 62 deletions(-) diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index 47cb5fa8d..691637578 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -102,11 +102,16 @@ public: } }; +struct Component { + int mObjectId; + aiMatrix4x4 mTransformation; +}; + class Object : public Resource { public: std::vector mMeshes; std::vector mMeshIndex; - std::vector mComponents; + std::vector mComponents; Object(int id) : Resource(id) {} @@ -163,65 +168,19 @@ public: const std::string ¤tNodeName = currentNode.name(); if (currentNodeName == D3MF::XmlTag::item) { int objectId = -1; - std::string transform; + std::string transformationMatrixStr; + aiMatrix4x4 transformationMatrix; getNodeAttribute(currentNode, D3MF::XmlTag::objectid, objectId); - bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transform); + bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transformationMatrixStr); - aiNode *sceneNode = new aiNode("item"); auto it = mResourcesDictionnary.find(objectId); if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) { Object *obj = static_cast(it->second); - std::vector meshes; - getMeshesList(obj, meshes); - sceneNode->mNumMeshes = static_cast(meshes.size()); - sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes]; - std::copy(meshes.begin(), meshes.end(), sceneNode->mMeshes); - if (hasTransform) { - // split the string - std::vector numbers; - std::string currentNumber; - for (size_t i = 0; i < transform.size(); ++i) { - const char c = transform[i]; - if (c == ' ') { - if (currentNumber.size() > 0) { - float f = std::stof(currentNumber); - numbers.push_back(f); - currentNumber.clear(); - } - } else { - currentNumber.push_back(c); - } - } - if (currentNumber.size() > 0) { - float f = std::stof(currentNumber); - numbers.push_back(f); - } - - aiMatrix4x4 transformMatrix; - transformMatrix.a1 = numbers[0]; - transformMatrix.b1 = numbers[1]; - transformMatrix.c1 = numbers[2]; - transformMatrix.d1 = 0; - - transformMatrix.a2 = numbers[3]; - transformMatrix.b2 = numbers[4]; - transformMatrix.c2 = numbers[5]; - transformMatrix.d2 = 0; - - transformMatrix.a3 = numbers[6]; - transformMatrix.b3 = numbers[7]; - transformMatrix.c3 = numbers[8]; - transformMatrix.d3 = 0; - - transformMatrix.a4 = numbers[9]; - transformMatrix.b4 = numbers[10]; - transformMatrix.c4 = numbers[11]; - transformMatrix.d4 = 1; - sceneNode->mTransformation = transformMatrix; + transformationMatrix = parseTransformMatrix(transformationMatrixStr); } - scene->mRootNode->addChildren(1, &sceneNode); + addObjectToNode(scene->mRootNode, obj, transformationMatrix); } } } @@ -259,6 +218,26 @@ public: private: + void addObjectToNode(aiNode* parent, Object* obj, aiMatrix4x4 nodeTransform) { + aiNode *sceneNode = new aiNode("item"); + sceneNode->mNumMeshes = static_cast(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); + + 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(it->second), c.mTransformation); + } + + } + } + bool getNodeAttribute(const XmlNode& node, const std::string& attribute, std::string& value) { pugi::xml_attribute objectAttribute = node.attribute(attribute.c_str()); if (!objectAttribute.empty()) { @@ -280,16 +259,48 @@ private: } } - void getMeshesList(Object *obj, std::vector &meshes) { - for (size_t i = 0; i < obj->mMeshIndex.size(); ++i) { - meshes.push_back(obj->mMeshIndex[i]); + aiMatrix4x4 parseTransformMatrix(std::string matrixStr) { + // split the string + std::vector numbers; + std::string currentNumber; + for (size_t i = 0; i < matrixStr.size(); ++i) { + const char c = matrixStr[i]; + if (c == ' ') { + if (currentNumber.size() > 0) { + float f = std::stof(currentNumber); + numbers.push_back(f); + currentNumber.clear(); + } + } else { + currentNumber.push_back(c); + } } - for (size_t i = 0; i < obj->mComponents.size(); ++i) { - int componentId = obj->mComponents[i]; - auto it = mResourcesDictionnary.find(componentId); - if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) - getMeshesList(static_cast(it->second), meshes); + if (currentNumber.size() > 0) { + float f = std::stof(currentNumber); + numbers.push_back(f); } + + aiMatrix4x4 transformMatrix; + transformMatrix.a1 = numbers[0]; + transformMatrix.b1 = numbers[1]; + transformMatrix.c1 = numbers[2]; + transformMatrix.d1 = 0; + + transformMatrix.a2 = numbers[3]; + transformMatrix.b2 = numbers[4]; + transformMatrix.c2 = numbers[5]; + transformMatrix.d2 = 0; + + transformMatrix.a3 = numbers[6]; + transformMatrix.b3 = numbers[7]; + transformMatrix.c3 = numbers[8]; + transformMatrix.d3 = 0; + + transformMatrix.a4 = numbers[9]; + transformMatrix.b4 = numbers[10]; + transformMatrix.c4 = numbers[11]; + transformMatrix.d4 = 1; + return transformMatrix; } void ReadObject(XmlNode &node) { @@ -329,8 +340,14 @@ private: for (XmlNode currentSubNode = currentNode.first_child(); currentSubNode; currentSubNode = currentSubNode.next_sibling()) { if (currentSubNode.name() == D3MF::XmlTag::component) { int objectId = -1; + std::string componentTransformStr; + aiMatrix4x4 componentTransform; + if (getNodeAttribute(currentSubNode, D3MF::XmlTag::transform, componentTransformStr)) { + componentTransform = parseTransformMatrix(componentTransformStr); + } + if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId)) - obj->mComponents.push_back(objectId); + obj->mComponents.push_back({ objectId, componentTransform }); } } } @@ -380,7 +397,6 @@ private: mesh->mNumVertices = static_cast(vertices.size()); mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; std::copy(vertices.begin(), vertices.end(), mesh->mVertices); } From 37df38f9511d9a38939b27eace0c8430161f19a8 Mon Sep 17 00:00:00 2001 From: Jean-Louis Date: Tue, 29 Dec 2020 15:46:28 +0100 Subject: [PATCH 8/8] [3MF] Improves node naming --- code/AssetLib/3MF/D3MFImporter.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index 691637578..66b2c965b 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -112,9 +112,11 @@ public: std::vector mMeshes; std::vector mMeshIndex; std::vector mComponents; + std::string mName; Object(int id) : - Resource(id) {} + Resource(id), + mName (std::string("Object_") + to_string(id)){} virtual ResourceType getType() { return ResourceType::RT_Object; @@ -126,7 +128,6 @@ class XmlSerializer { public: XmlSerializer(XmlParser *xmlParser) : - mMeshes(), mResourcesDictionnary(), mMaterialCount(0), mMeshCount(0), @@ -197,13 +198,23 @@ public: } // import the meshes - scene->mNumMeshes = static_cast(mMeshes.size()); - scene->mMeshes = new aiMesh *[scene->mNumMeshes](); - std::copy(mMeshes.begin(), mMeshes.end(), scene->mMeshes); + scene->mNumMeshes = static_cast(mMeshCount); + if (scene->mNumMeshes != 0) { + scene->mMeshes = new aiMesh *[scene->mNumMeshes](); + for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) { + if (it->second->getType() == ResourceType::RT_Object) { + Object *obj = static_cast(it->second); + 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(mMaterialCount); - if (0 != scene->mNumMaterials) { + if (scene->mNumMaterials != 0) { scene->mMaterials = new aiMaterial *[scene->mNumMaterials]; for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) { if (it->second->getType() == ResourceType::RT_BaseMaterials) { @@ -219,7 +230,7 @@ public: private: void addObjectToNode(aiNode* parent, Object* obj, aiMatrix4x4 nodeTransform) { - aiNode *sceneNode = new aiNode("item"); + aiNode *sceneNode = new aiNode(obj->mName); sceneNode->mNumMeshes = static_cast(obj->mMeshes.size()); sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes]; std::copy(obj->mMeshIndex.begin(), obj->mMeshIndex.end(), sceneNode->mMeshes); @@ -331,7 +342,6 @@ private: mesh->mMaterialIndex = materials->mMaterialIndex[pindex]; } } - mMeshes.push_back(mesh); obj->mMeshes.push_back(mesh); obj->mMeshIndex.push_back(mMeshCount); @@ -546,7 +556,6 @@ private: std::string value; }; std::vector mMetaData; - std::vector mMeshes; std::map mResourcesDictionnary; unsigned int mMaterialCount, mMeshCount; XmlParser *mXmlParser;