From 21678df589b522e5c88050ad34335dd20449f764 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 10 Jul 2020 22:25:38 +0200 Subject: [PATCH] ogre + collada migration. --- code/AssetLib/AMF/AMFImporter.cpp | 239 +------- code/AssetLib/AMF/AMFImporter.hpp | 1 - code/AssetLib/AMF/AMFImporter_Geometry.cpp | 190 +----- code/AssetLib/AMF/AMFImporter_Macro.hpp | 2 - code/AssetLib/AMF/AMFImporter_Material.cpp | 3 - code/AssetLib/Collada/ColladaLoader.cpp | 80 ++- code/AssetLib/Collada/ColladaParser.cpp | 673 +++++++++++++++------ code/AssetLib/Ogre/OgreXmlSerializer.cpp | 440 ++++++++++---- code/AssetLib/Ogre/OgreXmlSerializer.h | 71 ++- 9 files changed, 892 insertions(+), 807 deletions(-) diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp index 28089d906..d3bd03412 100644 --- a/code/AssetLib/AMF/AMFImporter.cpp +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -181,118 +181,10 @@ void AMFImporter::XML_CheckNode_MustHaveChildren(pugi::xml_node &node) { } } -/*void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string &pParentNodeName) { - static const size_t Uns_Skip_Len = 3; - const char *Uns_Skip[Uns_Skip_Len] = { "composite", "edge", "normal" }; - - static bool skipped_before[Uns_Skip_Len] = { false, false, false }; - - std::string nn(mReader->getNodeName()); - bool found = false; - bool close_found = false; - size_t sk_idx; - - for (sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++) { - if (nn != Uns_Skip[sk_idx]) continue; - - found = true; - if (mReader->isEmptyElement()) { - close_found = true; - - goto casu_cres; - } - - while (mReader->read()) { - if ((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName())) { - close_found = true; - - goto casu_cres; - } - } - } // for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++) - -casu_cres: - - if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + "."); - if (!close_found) Throw_CloseNotFound(nn); - - if (!skipped_before[sk_idx]) { - skipped_before[sk_idx] = true; - ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, "."); - } -}*/ - bool AMFImporter::XML_SearchNode(const std::string &nodeName) { return nullptr != mXmlParser->findNode(nodeName); } -/*bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) { - std::string val(mReader->getAttributeValue(pAttrIdx)); - - if ((val == "false") || (val == "0")) - return false; - else if ((val == "true") || (val == "1")) - return true; - else - throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\""); -} - -float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) { - std::string val; - float tvalf; - - ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val); - fast_atoreal_move(val.c_str(), tvalf, false); - - return tvalf; -} - -uint32_t AMFImporter::XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx) { - return strtoul10(mReader->getAttributeValue(pAttrIdx)); -} - -float AMFImporter::XML_ReadNode_GetVal_AsFloat() { - std::string val; - float tvalf; - - if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. No data, seems file is corrupt."); - if (mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. Invalid type of XML element, seems file is corrupt."); - - ParseHelper_FixTruncatedFloatString(mReader->getNodeData(), val); - fast_atoreal_move(val.c_str(), tvalf, false); - - return tvalf; -} - -uint32_t AMFImporter::XML_ReadNode_GetVal_AsU32() { - if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. No data, seems file is corrupt."); - if (mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. Invalid type of XML element, seems file is corrupt."); - - return strtoul10(mReader->getNodeData()); -} - -void AMFImporter::XML_ReadNode_GetVal_AsString(std::string &pValue) { - if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsString. No data, seems file is corrupt."); - if (mReader->getNodeType() != irr::io::EXN_TEXT) - throw DeadlyImportError("XML_ReadNode_GetVal_AsString. Invalid type of XML element, seems file is corrupt."); - - pValue = mReader->getNodeData(); -}*/ - -/*********************************************************************************************************************************************/ -/************************************************************ Functions: parse set ***********************************************************/ -/*********************************************************************************************************************************************/ - -/*void AMFImporter::ParseHelper_Node_Enter(CAMFImporter_NodeElement *pNode) { - mNodeElement_Cur->Child.push_back(pNode); // add new element to current element child list. - mNodeElement_Cur = pNode; // switch current element to new one. -} - -void AMFImporter::ParseHelper_Node_Exit() { - // check if we can walk up. - if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent; -} -*/ void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) { size_t instr_len; @@ -369,7 +261,6 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std } void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { -// irr::io::IrrXMLReader *OldReader = mReader; // store current XMLreader. std::unique_ptr file(pIOHandler->Open(pFile, "rb")); // Check whether we can read from the file @@ -388,8 +279,6 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { throw DeadlyImportError("Root node \"amf\" not found."); } ParseNode_Root(); - - //delete mReader; } // namespace Assimp // attribute("version").as_string(); // Read attributes for node . - /*MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("unit", unit, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("version", version, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND_WSKIP;*/ - // Check attributes if (!mUnit.empty()) { if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) { @@ -428,6 +312,7 @@ void AMFImporter::ParseNode_Root() { ((AMFRoot *)ne)->Unit = unit; ((AMFRoot *)ne)->Version = version; + // Check for child nodes for (pugi::xml_node ¤tNode : root->children()) { const std::string currentName = currentNode.name(); if (currentName == "object") { @@ -443,32 +328,6 @@ void AMFImporter::ParseNode_Root() { } mNodeElement_Cur = ne; // force restore "current" element } - // Check for child nodes - /*if (!mReader->isEmptyElement()) { - MACRO_NODECHECK_LOOPBEGIN("amf"); - if (XML_CheckNode_NameEqual("object")) { - ParseNode_Object(); - continue; - } - if (XML_CheckNode_NameEqual("material")) { - ParseNode_Material(); - continue; - } - if (XML_CheckNode_NameEqual("texture")) { - ParseNode_Texture(); - continue; - } - if (XML_CheckNode_NameEqual("constellation")) { - ParseNode_Constellation(); - continue; - } - if (XML_CheckNode_NameEqual("metadata")) { - ParseNode_Metadata(); - continue; - } - MACRO_NODECHECK_LOOPEND("amf"); - mNodeElement_Cur = ne; // force restore "current" element - } // if(!mReader->isEmptyElement())*/ mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph. } @@ -483,10 +342,6 @@ void AMFImporter::ParseNode_Root() { void AMFImporter::ParseNode_Constellation(XmlNode &node) { std::string id; id = node.attribute("id").as_string(); - // Read attributes for node . - /*MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND;*/ // create and if needed - define new grouping object. AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur); @@ -497,6 +352,7 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) { als.ID = id; } + // Check for child nodes for (pugi::xml_node ¤tNode : node.children()) { std::string name = currentNode.name(); if (name == "instance") { @@ -509,26 +365,6 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) { mNodeElement_Cur->Child.push_back(ne); } mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. - // Check for child nodes - /*if (!mReader->isEmptyElement()) { - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("constellation"); - if (XML_CheckNode_NameEqual("instance")) { - ParseNode_Instance(); - continue; - } - if (XML_CheckNode_NameEqual("metadata")) { - ParseNode_Metadata(); - continue; - } - MACRO_NODECHECK_LOOPEND("constellation"); - ParseHelper_Node_Exit(); - } // if(!mReader->isEmptyElement()) - else { - mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element - } // if(!mReader->isEmptyElement()) else - - mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.*/ } // . -/* MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND;*/ std::string objectid = node.attribute("objectid").as_string(); // used object id must be defined, check that. @@ -552,9 +385,7 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) { throw DeadlyImportError("\"objectid\" in must be defined."); } // create and define new grouping object. - //ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur); ne = new AMFInstance(mNodeElement_Cur); - //CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne); // alias for convenience AMFInstance &als = *((AMFInstance *)ne); als.ObjectID = objectid; @@ -584,29 +415,6 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) { als.Delta.z = (ai_real)std::atof(currentNode.value()); } } - // Check for child nodes - /*if (!mReader->isEmptyElement()) { - - als.Delta.Set(0, 0, 0); - als.Rotation.Set(0, 0, 0); - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("instance"); - MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x); - MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y); - MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z); - MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x); - MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y); - MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z); - MACRO_NODECHECK_LOOPEND("instance"); - ParseHelper_Node_Exit(); - // also convert degrees to radians. - als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f; - als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f; - als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f; - } // if(!mReader->isEmptyElement()) - else { - mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element - } // if(!mReader->isEmptyElement()) else*/ mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. } @@ -623,10 +431,8 @@ void AMFImporter::ParseNode_Object(XmlNode &node) { AMFNodeElementBase *ne(nullptr); // Read attributes for node . - /*MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND;*/ std::string id = node.attribute("id").as_string(); + // create and if needed - define new geometry object. ne = new AMFObject(mNodeElement_Cur); @@ -652,35 +458,6 @@ void AMFImporter::ParseNode_Object(XmlNode &node) { ParseNode_Metadata(currentNode); } } - /*if (!mReader->isEmptyElement()) { - bool col_read = false; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("object"); - if (XML_CheckNode_NameEqual("color")) { - // Check if color already defined for object. - if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; - } - - if (XML_CheckNode_NameEqual("mesh")) { - ParseNode_Mesh(); - continue; - } - if (XML_CheckNode_NameEqual("metadata")) { - ParseNode_Metadata(); - continue; - } - MACRO_NODECHECK_LOOPEND("object"); - ParseHelper_Node_Exit(); - } // if(!mReader->isEmptyElement()) - else {*/ - //mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element - //} // if(!mReader->isEmptyElement()) else mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. } @@ -711,12 +488,6 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) { value = node.value(); // read attribute - /*MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND;*/ - // and value of node. - //value = mReader->getNodeData(); - // Create node element and assign read data. ne = new AMFMetadata(mNodeElement_Cur); ((AMFMetadata *)ne)->Type = type; ((AMFMetadata *)ne)->Value = value; @@ -724,10 +495,6 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) { mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. } -/*********************************************************************************************************************************************/ -/******************************************************** Functions: BaseImporter set ********************************************************/ -/*********************************************************************************************************************************************/ - bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const { const std::string extension = GetExtension(pFile); diff --git a/code/AssetLib/AMF/AMFImporter.hpp b/code/AssetLib/AMF/AMFImporter.hpp index 2833e2aba..734cfa977 100644 --- a/code/AssetLib/AMF/AMFImporter.hpp +++ b/code/AssetLib/AMF/AMFImporter.hpp @@ -101,7 +101,6 @@ class AMFImporter : public BaseImporter { private: struct SPP_Material; // forward declaration - /// \struct SPP_Composite /// Data type for post-processing step. More suitable container for part of material's composition. struct SPP_Composite { SPP_Material *Material; ///< Pointer to material - part of composition. diff --git a/code/AssetLib/AMF/AMFImporter_Geometry.cpp b/code/AssetLib/AMF/AMFImporter_Geometry.cpp index 72d0d69ac..0a48b2f09 100644 --- a/code/AssetLib/AMF/AMFImporter_Geometry.cpp +++ b/code/AssetLib/AMF/AMFImporter_Geometry.cpp @@ -81,29 +81,6 @@ void AMFImporter::ParseNode_Mesh(XmlNode &node) { found_volumes = true; } - /*if(!mReader->isEmptyElement()) - { - bool vert_read = false; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("mesh"); - if(XML_CheckNode_NameEqual("vertices")) - { - // Check if data already defined. - if(vert_read) Throw_MoreThanOnceDefined("vertices", "Only one vertices set can be defined for ."); - // read data and set flag about it - ParseNode_Vertices(); - vert_read = true; - - continue; - } - - if(XML_CheckNode_NameEqual("volume")) { ParseNode_Volume(); continue; } - MACRO_NODECHECK_LOOPEND("mesh"); - ParseHelper_Node_Exit(); - }// if(!mReader->isEmptyElement()) - else*/ - // Add element to child list of current element if (!found_verts && !found_volumes) { mNodeElement_Cur->Child.push_back(ne); } // if(!mReader->isEmptyElement()) else @@ -130,20 +107,6 @@ void AMFImporter::ParseNode_Vertices(XmlNode &node) { mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element } // if(!mReader->isEmptyElement()) else - /*if (!mReader->isEmptyElement()) { - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("vertices"); - if (XML_CheckNode_NameEqual("vertex")) { - ParseNode_Vertex(); - continue; - } - MACRO_NODECHECK_LOOPEND("vertices"); - ParseHelper_Node_Exit(); - } // if(!mReader->isEmptyElement()) - else { - mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element - } // if(!mReader->isEmptyElement()) else*/ - mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. } @@ -157,6 +120,8 @@ void AMFImporter::ParseNode_Vertex(XmlNode &node) { // create new mesh object. ne = new AMFVertex(mNodeElement_Cur); + + // Check for child nodes pugi::xml_node colorNode = node.child("color"); bool col_read = false; bool coord_read = false; @@ -173,42 +138,6 @@ void AMFImporter::ParseNode_Vertex(XmlNode &node) { mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element } - // Check for child nodes -/* if (!mReader->isEmptyElement()) { - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("vertex"); - if (XML_CheckNode_NameEqual("color")) { - // Check if data already defined. - if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; - } - - if (XML_CheckNode_NameEqual("coordinates")) { - // Check if data already defined. - if (coord_read) Throw_MoreThanOnceDefined("coordinates", "Only one coordinates set can be defined for ."); - // read data and set flag about it - ParseNode_Coordinates(); - coord_read = true; - - continue; - } - - if (XML_CheckNode_NameEqual("metadata")) { - ParseNode_Metadata(); - continue; - } - MACRO_NODECHECK_LOOPEND("vertex"); - ParseHelper_Node_Exit(); - } // if(!mReader->isEmptyElement()) - else { - mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element - } // if(!mReader->isEmptyElement()) else - */ mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. } @@ -238,25 +167,6 @@ void AMFImporter::ParseNode_Coordinates(XmlNode &node) { mNodeElement_Cur->Child.push_back(ne); } - /*// Check for child nodes - if (!mReader->isEmptyElement()) { - bool read_flag[3] = { false, false, false }; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("coordinates"); - MACRO_NODECHECK_READCOMP_F("x", read_flag[0], als.Coordinate.x); - MACRO_NODECHECK_READCOMP_F("y", read_flag[1], als.Coordinate.y); - MACRO_NODECHECK_READCOMP_F("z", read_flag[2], als.Coordinate.z); - MACRO_NODECHECK_LOOPEND("coordinates"); - ParseHelper_Node_Exit(); - // check that all components was defined - if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all coordinate's components are defined."); - - } // if(!mReader->isEmptyElement()) - else { - mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element - } // if(!mReader->isEmptyElement()) else*/ - mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. } @@ -275,13 +185,6 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) { AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur); // Read attributes for node . - /*MACRO_ATTRREAD_LOOPBEG; - MACRO_ATTRREAD_CHECK_RET("materialid", materialid, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue); - MACRO_ATTRREAD_LOOPEND;*/ - - // create new object. - //ne = new CAMFImporter_NodeElement_Volume(mNodeElement_Cur); // and assign read data ((AMFVolume *)ne)->MaterialID = node.attribute("materialid").as_string(); @@ -308,36 +211,6 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) { } } - /*if (!mReader->isEmptyElement()) { - bool col_read = false; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("volume"); - if (XML_CheckNode_NameEqual("color")) { - // Check if data already defined. - if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; - } - - if (XML_CheckNode_NameEqual("triangle")) { - ParseNode_Triangle(); - continue; - } - if (XML_CheckNode_NameEqual("metadata")) { - ParseNode_Metadata(); - continue; - } - MACRO_NODECHECK_LOOPEND("volume"); - ParseHelper_Node_Exit(); - } // if(!mReader->isEmptyElement()) - else { - mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element - } // if(!mReader->isEmptyElement()) else*/ - mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. } @@ -354,14 +227,15 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) { void AMFImporter::ParseNode_Triangle(XmlNode &node) { AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur); - // create new color object. - //ne = new CAMFImporter_NodeElement_Triangle(mNodeElement_Cur); + // create new triangle object. AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience if (node.empty()) { mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element } + + // Check for child nodes bool col_read = false, tex_read = false; bool read_flag[3] = { false, false, false }; for (pugi::xml_node currentNode : node.children()) { @@ -387,59 +261,11 @@ void AMFImporter::ParseNode_Triangle(XmlNode &node) { read_flag[2] = true; } } - if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all vertices of the triangle are defined."); + if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) { + throw DeadlyImportError("Not all vertices of the triangle are defined."); + } - // Check for child nodes - /*if (!mReader->isEmptyElement()) { - bool col_read = false, tex_read = false; - bool read_flag[3] = { false, false, false }; - - ParseHelper_Node_Enter(ne); - MACRO_NODECHECK_LOOPBEGIN("triangle"); - if (XML_CheckNode_NameEqual("color")) { - // Check if data already defined. - if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for ."); - // read data and set flag about it - ParseNode_Color(); - col_read = true; - - continue; - } - - if (XML_CheckNode_NameEqual("texmap")) // new name of node: "texmap". - { - // Check if data already defined. - if (tex_read) Throw_MoreThanOnceDefined("texmap", "Only one texture coordinate can be defined for ."); - // read data and set flag about it - ParseNode_TexMap(); - tex_read = true; - - continue; - } else if (XML_CheckNode_NameEqual("map")) // old name of node: "map". - { - // Check if data already defined. - if (tex_read) Throw_MoreThanOnceDefined("map", "Only one texture coordinate can be defined for ."); - // read data and set flag about it - ParseNode_TexMap(true); - tex_read = true; - - continue; - } - - MACRO_NODECHECK_READCOMP_U32("v1", read_flag[0], als.V[0]); - MACRO_NODECHECK_READCOMP_U32("v2", read_flag[1], als.V[1]); - MACRO_NODECHECK_READCOMP_U32("v3", read_flag[2], als.V[2]); - MACRO_NODECHECK_LOOPEND("triangle"); - ParseHelper_Node_Exit(); - // check that all components was defined - if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all vertices of the triangle are defined."); - - } // if(!mReader->isEmptyElement()) - else { - mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element - } // if(!mReader->isEmptyElement()) else - */ mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. } diff --git a/code/AssetLib/AMF/AMFImporter_Macro.hpp b/code/AssetLib/AMF/AMFImporter_Macro.hpp index 5877a62d2..c1a6e3f2d 100644 --- a/code/AssetLib/AMF/AMFImporter_Macro.hpp +++ b/code/AssetLib/AMF/AMFImporter_Macro.hpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssetLib/AMF/AMFImporter_Material.cpp b/code/AssetLib/AMF/AMFImporter_Material.cpp index df627dc0c..0dde37d35 100644 --- a/code/AssetLib/AMF/AMFImporter_Material.cpp +++ b/code/AssetLib/AMF/AMFImporter_Material.cpp @@ -177,9 +177,6 @@ void AMFImporter::ParseNode_Texture(XmlNode &node) { std::string enc64_data = node.value(); // Check for child nodes - //if (!mXmlParser->isEmptyElement()) { - // XML_ReadNode_GetVal_AsString(enc64_data); - //} // check that all components was defined if (id.empty()) { diff --git a/code/AssetLib/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp index 7b0fdd8e0..04d995979 100644 --- a/code/AssetLib/Collada/ColladaLoader.cpp +++ b/code/AssetLib/Collada/ColladaLoader.cpp @@ -45,24 +45,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaLoader.h" #include "ColladaParser.h" - #include -#include -#include -#include -#include -#include -#include - #include +#include #include #include #include +#include #include - -#include "math.h" -#include "time.h" +#include +#include +#include +#include #include +#include +#include #include #include @@ -125,20 +122,17 @@ ColladaLoader::~ColladaLoader() { bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { // check file extension const std::string extension = GetExtension(pFile); - - bool readSig = checkSig && (pIOHandler != nullptr); - + const bool readSig = checkSig && (pIOHandler != nullptr); if (!readSig) { if (extension == "dae" || extension == "zae") { return true; } - } - - if (readSig) { + } else { // Look for a DAE file inside, but don't extract it ZipArchiveIOSystem zip_archive(pIOHandler, pFile); - if (zip_archive.isOpen()) + if (zip_archive.isOpen()) { return !ColladaParser::ReadZaeManifest(zip_archive).empty(); + } } // XML - too generic, we need to open the file and search for typical keywords @@ -585,10 +579,10 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Colla // ------------------------------------------------------------------------------------------------ // Find mesh from either meshes or morph target meshes aiMesh *ColladaLoader::findMesh(const std::string &meshid) { - if ( meshid.empty()) { + if (meshid.empty()) { return nullptr; } - + for (unsigned int i = 0; i < mMeshes.size(); ++i) { if (std::string(mMeshes[i]->mName.data) == meshid) { return mMeshes[i]; @@ -1377,9 +1371,9 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse double time = double(mat.d4); // remember? time is stored in mat.d4 mat.d4 = 1.0f; - dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds ; - dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds ; - dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds ; + dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds; + dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds; + dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds; mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue); } @@ -1400,7 +1394,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse if (e.mTargetId.find("morph-weights") != std::string::npos) morphChannels.push_back(e); } - if (!morphChannels.empty() ) { + if (!morphChannels.empty()) { // either 1) morph weight animation count should contain morph target count channels // or 2) one channel with morph target count arrays // assume first @@ -1434,8 +1428,8 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()]; morphAnim->mKeys[key].mWeights = new double[morphChannels.size()]; - morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds ; - for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex ) { + morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds; + for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex) { morphAnim->mKeys[key].mValues[valueIndex] = valueIndex; morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex); } @@ -1552,23 +1546,23 @@ void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pSce shadeMode = aiShadingMode_Flat; } else { switch (effect.mShadeType) { - case Collada::Shade_Constant: - shadeMode = aiShadingMode_NoShading; - break; - case Collada::Shade_Lambert: - shadeMode = aiShadingMode_Gouraud; - break; - case Collada::Shade_Blinn: - shadeMode = aiShadingMode_Blinn; - break; - case Collada::Shade_Phong: - shadeMode = aiShadingMode_Phong; - break; + case Collada::Shade_Constant: + shadeMode = aiShadingMode_NoShading; + break; + case Collada::Shade_Lambert: + shadeMode = aiShadingMode_Gouraud; + break; + case Collada::Shade_Blinn: + shadeMode = aiShadingMode_Blinn; + break; + case Collada::Shade_Phong: + shadeMode = aiShadingMode_Phong; + break; - default: - ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading"); - shadeMode = aiShadingMode_Gouraud; - break; + default: + ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading"); + shadeMode = aiShadingMode_Gouraud; + break; } } mat.AddProperty(&shadeMode, 1, AI_MATKEY_SHADING_MODEL); @@ -1734,7 +1728,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse // and add this texture to the list mTextures.push_back(tex); return result; - } + } if (imIt->second.mFileName.empty()) { throw DeadlyImportError("Collada: Invalid texture, no data or file reference given"); diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index 87a84710a..a4e502a43 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -160,11 +160,26 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) { return file_list.front(); } + XmlParser manifestParser; + XmlNode *root = manifestParser.parse(manifestfile.get()); + if (nullptr == root) { + return std::string(); + } + const std::string name = root->name(); + if (name != "dae_root") { + root = manifestParser.findNode("dae_root"); + if (nullptr == root) { + return std::string(); + } + const char *filepath = root->value(); + aiString ai_str(filepath); + UriDecodePath(ai_str); + return std::string(ai_str.C_Str()); + } + /*std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(manifestfile.get())); + std::unique_ptr manifest_reader(irr::io::createIrrXMLReader(mIOWrapper.get()));*/ - std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(manifestfile.get())); - std::unique_ptr manifest_reader(irr::io::createIrrXMLReader(mIOWrapper.get())); - - while (manifest_reader->read()) { + /*while (manifest_reader->read()) { // find the manifest "dae_root" element if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT) { if (::strcmp(manifest_reader->getNodeName(), "dae_root") == 0) { @@ -183,7 +198,7 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) { return std::string(ai_str.C_Str()); } } - } + }*/ return std::string(); } @@ -314,7 +329,6 @@ void ColladaParser::ReadContents(XmlNode &node) { // ------------------------------------------------------------------------------------------------ // Reads the structure of the file -<<<<<<< HEAD void ColladaParser::ReadStructure(XmlNode &node) { for (pugi::xml_node curNode : node.children()) { const std::string name = std::string(curNode.name()); @@ -341,7 +355,7 @@ void ColladaParser::ReadStructure(XmlNode &node) { else if (name == "library_cameras") ReadCameraLibrary(curNode); else if (name == "library_nodes") - ReadSceneNode(NULL); /* some hacking to reuse this piece of code */ + ReadSceneNode(curNode, nullptr); /* some hacking to reuse this piece of code */ else if (name == "scene") ReadScene(curNode); //else @@ -381,44 +395,6 @@ void ColladaParser::ReadStructure(XmlNode &node) { } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; }*/ -======= -void ColladaParser::ReadStructure() { - while (mReader->read()) { - // beginning of elements - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("asset")) - ReadAssetInfo(); - else if (IsElement("library_animations")) - ReadAnimationLibrary(); - else if (IsElement("library_animation_clips")) - ReadAnimationClipLibrary(); - else if (IsElement("library_controllers")) - ReadControllerLibrary(); - else if (IsElement("library_images")) - ReadImageLibrary(); - else if (IsElement("library_materials")) - ReadMaterialLibrary(); - else if (IsElement("library_effects")) - ReadEffectLibrary(); - else if (IsElement("library_geometries")) - ReadGeometryLibrary(); - else if (IsElement("library_visual_scenes")) - ReadSceneLibrary(); - else if (IsElement("library_lights")) - ReadLightLibrary(); - else if (IsElement("library_cameras")) - ReadCameraLibrary(); - else if (IsElement("library_nodes")) - ReadSceneNode(nullptr); /* some hacking to reuse this piece of code */ - else if (IsElement("scene")) - ReadScene(); - else - SkipElement(); - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - break; - } - } ->>>>>>> master PostProcessRootAnimations(); PostProcessControllers(); @@ -436,7 +412,7 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) { pugi::xml_attribute attr = curNode.attribute("meter"); mUnitSize = 1.f; if (attr) { - mUnitSize = attr.as_double(); + mUnitSize = static_cast(attr.as_double()); } } else if (name == "up_axis") { const char *content = curNode.value(); @@ -602,7 +578,7 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) { if (urlName[0] != '#') { ThrowException("Unknown reference format"); } - clip.second.push_back(url); + clip.second.push_back(url.as_string()); } } @@ -919,8 +895,27 @@ void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChanne for (pugi::xml_node &curNode : node.children()) { const std::string currentName = curNode.name(); if (currentName == "input") { - pugi::xml_attribute semantic = curNode.attribute("semantic"); - if (semantic) { + pugi::xml_attribute semanticAttr = curNode.attribute("semantic"); + if (!semanticAttr.empty()) { + const char *semantic = semanticAttr.as_string(); + pugi::xml_attribute sourceAttr = curNode.attribute("source"); + if (!sourceAttr.empty()) { + const char *source = sourceAttr.as_string(); + if (source[0] != '#') + ThrowException("Unsupported URL format"); + source++; + + if (strcmp(semantic, "INPUT") == 0) + pChannel.mSourceTimes = source; + else if (strcmp(semantic, "OUTPUT") == 0) + pChannel.mSourceValues = source; + else if (strcmp(semantic, "IN_TANGENT") == 0) + pChannel.mInTanValues = source; + else if (strcmp(semantic, "OUT_TANGENT") == 0) + pChannel.mOutTanValues = source; + else if (strcmp(semantic, "INTERPOLATION") == 0) + pChannel.mInterpolationValues = source; + } } } } @@ -970,7 +965,23 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) { /*if (mReader->isEmptyElement()) return;*/ - while (mReader->read()) { + const std::string name = node.name(); + if (name != "controller") { + return; + } + int attrId = node.attribute("id").as_int(); + std::string id = node.value(); + mControllerLibrary[id] = Controller(); + for (XmlNode currentNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == "controller") { + int attrID = currentNode.attribute("id").as_int(); + std::string controllerId = currentNode.attribute(itoa(attrID, NULL, 10)).value(); + ReadController(node, mControllerLibrary[controllerId]); + } + } + + /*while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("controller")) { // read ID. Ask the spec if it's necessary or optional... you might be surprised. @@ -992,7 +1003,7 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) { break; } - } + }*/ } // ------------------------------------------------------------------------------------------------ @@ -1001,7 +1012,54 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll // initial values pController.mType = Skin; pController.mMethod = Normalized; - while (mReader->read()) { + for (XmlNode currentNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == "morph") { + pController.mType = Morph; + int baseIndex = currentNode.attribute("source").as_int(); + pController.mMeshId = currentNode.attribute.begin() + baseIndex + 1; + int methodIndex = currentNode.attribute("method").as_int(); + if (methodIndex > 0) { + const char *method = currentNode.attribute("method").value(); + if (strcmp(method, "RELATIVE") == 0) { + pController.mMethod = Relative; + } + } + } else if (currentName == "skin") { + int sourceIndex = currentNode.attribute("source").as_int(); + pController.mMeshId = currentNode.attribute.begin() + sourceIndex + 1; + } else if (currentName == "bind_shape_matrix") { + const char *content = currentNode.value(); + for (unsigned int a = 0; a < 16; a++) { + // read a number + content = fast_atoreal_move(content, pController.mBindShapeMatrix[a]); + // skip whitespace after it + SkipSpacesAndLineEnd(&content); + } + } else if (currentName == "source") { + ReadSource(currentNode); + } else if (IsElement("joints")) { + ReadControllerJoints(currentNode, pController); + } else if (IsElement("vertex_weights")) { + ReadControllerWeights(currentNode, pController); + } else if (IsElement("targets")) { + for (XmlNode currendChildNode : currentNode.children()) { + const std::string currentChildName = currendChildNode.name(); + if (currentChildName == "input") { + int semanticsIndex = currendChildNode.attribute("semantic").as_int(); + int sourceIndex = currendChildNode.attribute("source").as_int(); + const char *semantics = currendChildNode.attributes.begin() + semanticsIndex; + const char *source = currendChildNode.attributes.begin() + sourceIndex; + if (strcmp(semantics, "MORPH_TARGET") == 0) { + pController.mMorphTarget = source + 1; + } else if (strcmp(semantics, "MORPH_WEIGHT") == 0) { + pController.mMorphWeight = source + 1; + } + } + } + } + } + /*while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other if (IsElement("morph")) { @@ -1071,59 +1129,141 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll else if (strcmp(mReader->getNodeName(), "skin") != 0 && strcmp(mReader->getNodeName(), "morph") != 0) ThrowException("Expected end of element."); } - } + }*/ } // ------------------------------------------------------------------------------------------------ // Reads the joint definitions for the given controller void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) { - while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - // Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX" - if (IsElement("input")) { - int indexSemantic = GetAttribute("semantic"); - const char *attrSemantic = mReader->getAttributeValue(indexSemantic); - int indexSource = GetAttribute("source"); - const char *attrSource = mReader->getAttributeValue(indexSource); - - // local URLS always start with a '#'. We don't support global URLs - if (attrSource[0] != '#') - ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element"); - attrSource++; - - // parse source URL to corresponding source - if (strcmp(attrSemantic, "JOINT") == 0) - pController.mJointNameSource = attrSource; - else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) - pController.mJointOffsetMatrixSource = attrSource; - else - ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in data element"); - - // skip inner data, if present - if (!mReader->isEmptyElement()) - SkipElement(); - } else { - // ignore the rest - SkipElement(); + for (XmlNode currentNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == "input") { + int indexSemantic = currentNode.attribute("semantic").as_int(); + const char *attrSemantic = currentNode.attributes.begin() + indexSemantic; + int indexSource = currentNode.attribute("source").as_int(); + const char *attrSource = currentNode.attributes.begin() + indexSource; + if (attrSource[0] != '#') { + ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element"); + } + attrSource++; + // parse source URL to corresponding source + if (strcmp(attrSemantic, "JOINT") == 0) { + pController.mJointNameSource = attrSource; + } else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) { + pController.mJointOffsetMatrixSource = attrSource; + } else { + ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in data element"); } - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if (strcmp(mReader->getNodeName(), "joints") != 0) - ThrowException("Expected end of element."); - - break; } } + /*while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + // Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX" + if (IsElement("input")) { + int indexSemantic = GetAttribute("semantic"); + const char *attrSemantic = mReader->getAttributeValue(indexSemantic); + int indexSource = GetAttribute("source"); + const char *attrSource = mReader->getAttributeValue(indexSource); + + // local URLS always start with a '#'. We don't support global URLs + if (attrSource[0] != '#') + ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element"); + attrSource++; + + // parse source URL to corresponding source + if (strcmp(attrSemantic, "JOINT") == 0) + pController.mJointNameSource = attrSource; + else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) + pController.mJointOffsetMatrixSource = attrSource; + else + ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in data element"); + + // skip inner data, if present + if (!mReader->isEmptyElement()) + SkipElement(); + } else { + // ignore the rest + SkipElement(); + } + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "joints") != 0) + ThrowException("Expected end of element."); + + break; + } + }*/ } // ------------------------------------------------------------------------------------------------ // Reads the joint weights for the given controller void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pController) { - // read vertex count from attributes and resize the array accordingly - int indexCount = GetAttribute("count"); - size_t vertexCount = (size_t)mReader->getAttributeValueAsInt(indexCount); + // Read vertex count from attributes and resize the array accordingly + int indexCount = node.attribute("count").as_int(); + size_t vertexCount = node.attributes.begin() + indexCount; pController.mWeightCounts.resize(vertexCount); - while (mReader->read()) { + /*// read vertex count from attributes and resize the array accordingly + int indexCount = GetAttribute("count"); + size_t vertexCount = (size_t)mReader->getAttributeValueAsInt(indexCount); + pController.mWeightCounts.resize(vertexCount);*/ + + for (XmlNode currentNode : node.children()) { + std::string currentName = currentNode.name(); + if (currentName == "input") { + InputChannel channel; + + int indexSemantic = currentNode.attribute("semantic").as_int(); + const char *attrSemantic = currentNode.attributes.begin() + indexSemantic; + int indexSource = currentNode.attribute("source").as_int(); + const char *attrSource = currentNode.attributes.begin() + indexSource; + int indexOffset = currentNode.attribute("offset").as_int(); + if (indexOffset >= 0) + channel.mOffset = currentNode.attributes.begin + indexOffset; + + // local URLS always start with a '#'. We don't support global URLs + if (attrSource[0] != '#') + ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element"); + channel.mAccessor = attrSource + 1; + + // parse source URL to corresponding source + if (strcmp(attrSemantic, "JOINT") == 0) { + pController.mWeightInputJoints = channel; + } else if (strcmp(attrSemantic, "WEIGHT") == 0) { + pController.mWeightInputWeights = channel; + } else { + ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in data element"); + } + } else if (currentName == "vcount" && vertexCount > 0) { + const char *text = currentNode.value(); + size_t numWeights = 0; + for (std::vector::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) { + if (*text == 0) { + ThrowException("Out of data while reading "); + } + + *it = strtoul10(text, &text); + numWeights += *it; + SkipSpacesAndLineEnd(&text); + } + // reserve weight count + pController.mWeights.resize(numWeights); + } else if (currentName == "v" && vertexCount > 0) { + // read JointIndex - WeightIndex pairs + const char *text = currentNode.value(); + for (std::vector>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) { + if (*text == 0) { + ThrowException("Out of data while reading "); + } + it->first = strtoul10(text, &text); + SkipSpacesAndLineEnd(&text); + if (*text == 0) + ThrowException("Out of data while reading "); + it->second = strtoul10(text, &text); + SkipSpacesAndLineEnd(&text); + } + } + } + /*while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT" if (IsElement("input") && vertexCount > 0) { @@ -1196,7 +1336,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC break; } - } + }*/ } // ------------------------------------------------------------------------------------------------ @@ -1208,75 +1348,54 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) { /*if (mReader->isEmptyElement()) return;*/ - while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("image")) { - // read ID. Another entry which is "optional" by design but obligatory in reality - int attrID = GetAttribute("id"); - std::string id = mReader->getAttributeValue(attrID); + for (XmlNode currentNode : node.children()) { + const std::string name = currentNode.name(); + if (name == "image") { + int attrID = currentNode.attribute("id").as_int(); + std::string id = currentNode.attributes.begin() + attrID; + mImageLibrary[id] = Image(); - // create an entry and store it in the library under its ID - mImageLibrary[id] = Image(); - - // read on from there - ReadImage(mImageLibrary[id]); - } else { - // ignore the rest - SkipElement(); - } - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if (strcmp(mReader->getNodeName(), "library_images") != 0) - ThrowException("Expected end of element."); - - break; + // read on from there + ReadImage(currentNode, mImageLibrary[id]); } } + /*while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("image")) { + // read ID. Another entry which is "optional" by design but obligatory in reality + int attrID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(attrID); + + // create an entry and store it in the library under its ID + mImageLibrary[id] = Image(); + + // read on from there + ReadImage(mImageLibrary[id]); + } else { + // ignore the rest + SkipElement(); + } + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "library_images") != 0) + ThrowException("Expected end of element."); + + break; + } + }*/ } // ------------------------------------------------------------------------------------------------ // Reads an image entry into the given image void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) { - while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - // Need to run different code paths here, depending on the Collada XSD version - if (IsElement("image")) { - SkipElement(); - } else if (IsElement("init_from")) { - if (mFormat == FV_1_4_n) { - // FIX: C4D exporter writes empty tags - if (!mReader->isEmptyElement()) { - // element content is filename - hopefully - const char *sz = TestTextContent(); - if (sz) { - aiString filepath(sz); - UriDecodePath(filepath); - pImage.mFileName = filepath.C_Str(); - } - TestClosing("init_from"); - } - if (!pImage.mFileName.length()) { - pImage.mFileName = "unknown_texture"; - } - } else if (mFormat == FV_1_5_n) { - // make sure we skip over mip and array initializations, which - // we don't support, but which could confuse the loader if - // they're not skipped. - int attrib = TestAttribute("array_index"); - if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) { - ASSIMP_LOG_WARN("Collada: Ignoring texture array index"); - continue; - } - - attrib = TestAttribute("mip_index"); - if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) { - ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer"); - continue; - } - - // TODO: correctly jump over cube and volume maps? - } - } else if (mFormat == FV_1_5_n) { - if (IsElement("ref")) { + for (XmlNode currentNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == "image") { + // Ignore + continue; + } else if (currentName == "init_from") { + if (mFormat == FV_1_4_n) { + // FIX: C4D exporter writes empty tags + if (!currentNode.empty()) { // element content is filename - hopefully const char *sz = TestTextContent(); if (sz) { @@ -1284,39 +1403,150 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) { UriDecodePath(filepath); pImage.mFileName = filepath.C_Str(); } - TestClosing("ref"); - } else if (IsElement("hex") && !pImage.mFileName.length()) { - // embedded image. get format - const int attrib = TestAttribute("format"); - if (-1 == attrib) - ASSIMP_LOG_WARN("Collada: Unknown image file format"); - else - pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib); - - const char *data = GetTextContent(); - - // hexadecimal-encoded binary octets. First of all, find the - // required buffer size to reserve enough storage. - const char *cur = data; - while (!IsSpaceOrNewLine(*cur)) - cur++; - - const unsigned int size = (unsigned int)(cur - data) * 2; - pImage.mImageData.resize(size); - for (unsigned int i = 0; i < size; ++i) - pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1)); - - TestClosing("hex"); + TestClosing("init_from"); } - } else { - // ignore the rest - SkipElement(); + if (!pImage.mFileName.length()) { + pImage.mFileName = "unknown_texture"; + } + } else if (mFormat == FV_1_5_n) { + // make sure we skip over mip and array initializations, which + // we don't support, but which could confuse the loader if + // they're not skipped. + int attrib = currentNode.attribute("ref").as_int(); + int v = currentNode.attributes.begin + attrib; + if (attrib != -1 && v > 0) { + ASSIMP_LOG_WARN("Collada: Ignoring texture array index"); + continue; + } + + attrib = currentNode.attribute("mip_index").as_int(); + v = currentNode.attributes.begin + attrib; + if (attrib != -1 && v > 0) { + ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer"); + continue; + } + + // TODO: correctly jump over cube and volume maps? } - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if (strcmp(mReader->getNodeName(), "image") == 0) - break; - } + } else if (mFormat == FV_1_5_n) { + XmlNode refChild = currentNode.child("ref"); + XmlNode hexChild = currentNode.child("hex"); + if (refChild) { + // element content is filename - hopefully + const char *sz = refChild.value(); + if (sz) { + aiString filepath(sz); + UriDecodePath(filepath); + pImage.mFileName = filepath.C_Str(); + } + } else if (hexChild && !pImage.mFileName.length()) { + // embedded image. get format + const int attrib = hexChild.attribute("format").as_int(); + if (-1 == attrib) { + ASSIMP_LOG_WARN("Collada: Unknown image file format"); + } else { + pImage.mEmbeddedFormat = hexChild.attributes.begin() + attrib; + } + + const char *data = hexChild.value(); + + // hexadecimal-encoded binary octets. First of all, find the + // required buffer size to reserve enough storage. + const char *cur = data; + while (!IsSpaceOrNewLine(*cur)) { + ++cur; + } + + const unsigned int size = (unsigned int)(cur - data) * 2; + pImage.mImageData.resize(size); + for (unsigned int i = 0; i < size; ++i) { + pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1)); + } + } + } } + + /*while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + // Need to run different code paths here, depending on the Collada XSD version + if (IsElement("image")) { + SkipElement(); + } else if (IsElement("init_from")) { + if (mFormat == FV_1_4_n) { + // FIX: C4D exporter writes empty tags + if (!mReader->isEmptyElement()) { + // element content is filename - hopefully + const char *sz = TestTextContent(); + if (sz) { + aiString filepath(sz); + UriDecodePath(filepath); + pImage.mFileName = filepath.C_Str(); + } + TestClosing("init_from"); + } + if (!pImage.mFileName.length()) { + pImage.mFileName = "unknown_texture"; + } + } else if (mFormat == FV_1_5_n) { + // make sure we skip over mip and array initializations, which + // we don't support, but which could confuse the loader if + // they're not skipped. + int attrib = TestAttribute("array_index"); + if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) { + ASSIMP_LOG_WARN("Collada: Ignoring texture array index"); + continue; + } + + attrib = TestAttribute("mip_index"); + if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) { + ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer"); + continue; + } + + // TODO: correctly jump over cube and volume maps? + } + } else if (mFormat == FV_1_5_n) { + if (IsElement("ref")) { + // element content is filename - hopefully + const char *sz = TestTextContent(); + if (sz) { + aiString filepath(sz); + UriDecodePath(filepath); + pImage.mFileName = filepath.C_Str(); + } + TestClosing("ref"); + } else if (IsElement("hex") && !pImage.mFileName.length()) { + // embedded image. get format + const int attrib = TestAttribute("format"); + if (-1 == attrib) + ASSIMP_LOG_WARN("Collada: Unknown image file format"); + else + pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib); + + const char *data = GetTextContent(); + + // hexadecimal-encoded binary octets. First of all, find the + // required buffer size to reserve enough storage. + const char *cur = data; + while (!IsSpaceOrNewLine(*cur)) + cur++; + + const unsigned int size = (unsigned int)(cur - data) * 2; + pImage.mImageData.resize(size); + for (unsigned int i = 0; i < size; ++i) + pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1)); + + TestClosing("hex"); + } + } else { + // ignore the rest + SkipElement(); + } + } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "image") == 0) + break; + } + }*/ } // ------------------------------------------------------------------------------------------------ @@ -1329,7 +1559,36 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) { return;*/ std::map names; - while (mReader->read()) { + + for (XmlNode currentNode : node.children()) { + const std::string currentName = currentNode.name(); + int attrID = currentNode.attribute("id").as_int(); + std::string id = currentNode.attributes.begin() + attrID; + std::string name; + int attrName = currentNode.attribute("name").as_int(); + if (attrName >= 0) { + name = currentNode.attributes.begin() + attrName; + } + mMaterialLibrary[id] = Material(); + + if (!name.empty()) { + std::map::iterator it = names.find(name); + if (it != names.end()) { + std::ostringstream strStream; + strStream << ++it->second; + name.append(" " + strStream.str()); + } else { + names[name] = 0; + } + + mMaterialLibrary[id].mName = name; + } + + ReadMaterial(currentNode, mMaterialLibrary[id]); + + } + + /*while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("material")) { // read ID. By now you probably know my opinion about this "specification" @@ -1368,7 +1627,7 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) { break; } - } + }*/ } // ------------------------------------------------------------------------------------------------ @@ -2778,7 +3037,7 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) { return; } -/* if (mReader->isEmptyElement()) + /* if (mReader->isEmptyElement()) return;*/ while (mReader->read()) { @@ -2796,7 +3055,6 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) { if (attrName > -1) child->mName = mReader->getAttributeValue(attrName); - if (pNode) { pNode->mChildren.push_back(child); child->mParent = pNode; @@ -3034,7 +3292,30 @@ void ColladaParser::ReadScene(XmlNode &node) { /*if (mReader->isEmptyElement()) return;*/ - while (mReader->read()) { + for (XmlNode currentNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == "instance_visual_scene") { + // should be the first and only occurrence + if (mRootNode) + ThrowException("Invalid scene containing multiple root nodes in element"); + + // read the url of the scene to instance. Should be of format "#some_name" + int urlIndex = currentNode.attribute("url").as_int(); + const char *url = currentNode.attributes.begin() + urlIndex; + if (url[0] != '#') { + ThrowException("Unknown reference format in element"); + } + + // find the referred scene, skip the leading # + NodeLibrary::const_iterator sit = mNodeLibrary.find(url + 1); + if (sit == mNodeLibrary.end()) { + ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in element."); + } + mRootNode = sit->second; + } + } + + /*while (mReader->read()) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("instance_visual_scene")) { // should be the first and only occurrence @@ -3058,7 +3339,7 @@ void ColladaParser::ReadScene(XmlNode &node) { } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } - } + }*/ } // ------------------------------------------------------------------------------------------------ @@ -3159,7 +3440,7 @@ void ColladaParser::ReportWarning(const char *msg, ...) { // ------------------------------------------------------------------------------------------------ // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes -int ColladaParser::GetAttribute(const char *pAttr) const { +/*int ColladaParser::GetAttribute(const char *pAttr) const { int index = TestAttribute(pAttr); if (index == -1) { ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); @@ -3167,31 +3448,31 @@ int ColladaParser::GetAttribute(const char *pAttr) const { // attribute not found -> throw an exception return index; -} +}*/ // ------------------------------------------------------------------------------------------------ // Tests the present element for the presence of one attribute, returns its index or throws an exception if not found -int ColladaParser::TestAttribute(const char *pAttr) const { +/*int ColladaParser::TestAttribute(const char *pAttr) const { for (int a = 0; a < mReader->getAttributeCount(); a++) if (strcmp(mReader->getAttributeName(a), pAttr) == 0) return a; return -1; -} +}*/ // ------------------------------------------------------------------------------------------------ // Reads the text contents of an element, throws an exception if not given. Skips leading whitespace. -const char *ColladaParser::GetTextContent() { +/*const char *ColladaParser::GetTextContent() { const char *sz = TestTextContent(); if (!sz) { ThrowException("Invalid contents in element \"n\"."); } return sz; -} +}*/ // ------------------------------------------------------------------------------------------------ // Reads the text contents of an element, returns nullptr if not given. Skips leading whitespace. -const char *ColladaParser::TestTextContent() { +/*const char *ColladaParser::TestTextContent() { // present node should be the beginning of an element if (mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement()) return nullptr; @@ -3209,7 +3490,7 @@ const char *ColladaParser::TestTextContent() { SkipSpacesAndLineEnd(&text); return text; -} +}*/ // ------------------------------------------------------------------------------------------------ // Calculates the resulting transformation from all the given transform steps diff --git a/code/AssetLib/Ogre/OgreXmlSerializer.cpp b/code/AssetLib/Ogre/OgreXmlSerializer.cpp index 31c2ee74e..489a356f7 100644 --- a/code/AssetLib/Ogre/OgreXmlSerializer.cpp +++ b/code/AssetLib/Ogre/OgreXmlSerializer.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -43,7 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "OgreXmlSerializer.h" #include "OgreBinarySerializer.h" #include "OgreParsingUtils.h" - #include #include #include @@ -56,85 +54,86 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace Ogre { -AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX; -AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error) { +AI_WONT_RETURN void ThrowAttibuteError(const XmlParser *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX; + +AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) { if (!error.empty()) { - throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'"); + throw DeadlyImportError(error + " in node '" + nodeName + "' and attribute '" + name + "'"); } else { - throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'"); + throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + nodeName + "'"); } } +static inline bool hasAttribute( XmlNode &xmlNode, const char *name ) { + pugi::xml_attribute attr = xmlNode.attribute(name); + return !attr.empty(); +} template <> -int32_t OgreXmlSerializer::ReadAttribute(const char *name) const { - if (!HasAttribute(name)) { - ThrowAttibuteError(m_reader, name); +int32_t OgreXmlSerializer::ReadAttribute(XmlNode &xmlNode, const char *name) const { + if (!hasAttribute(xmlNode, name )) { + ThrowAttibuteError(mParser, name); } - - return static_cast(m_reader->getAttributeValueAsInt(name)); + pugi::xml_attribute attr = xmlNode.attribute(name); + return static_cast(attr.as_int()); } template <> -uint32_t OgreXmlSerializer::ReadAttribute(const char *name) const { - if (!HasAttribute(name)) { - ThrowAttibuteError(m_reader, name); +uint32_t OgreXmlSerializer::ReadAttribute(XmlNode &xmlNode, const char *name) const { + if (!hasAttribute(xmlNode, name)) { + ThrowAttibuteError(mParser, name); } + // @note This is hackish. But we are never expecting unsigned values that go outside the // int32_t range. Just monitor for negative numbers and kill the import. - int32_t temp = ReadAttribute(name); + int32_t temp = ReadAttribute(xmlNode, name); if (temp < 0) { - ThrowAttibuteError(m_reader, name, "Found a negative number value where expecting a uint32_t value"); + ThrowAttibuteError(mParser, name, "Found a negative number value where expecting a uint32_t value"); } return static_cast(temp); } template <> -uint16_t OgreXmlSerializer::ReadAttribute(const char *name) const { - if (!HasAttribute(name)) { - ThrowAttibuteError(m_reader, name); +uint16_t OgreXmlSerializer::ReadAttribute(XmlNode &xmlNode, const char *name) const { + if (!hasAttribute(xmlNode, name)) { + ThrowAttibuteError(mParser, name); } - return static_cast(ReadAttribute(name)); + return static_cast(xmlNode.attribute(name).as_int()); } template <> -float OgreXmlSerializer::ReadAttribute(const char *name) const { - if (!HasAttribute(name)) { - ThrowAttibuteError(m_reader, name); +float OgreXmlSerializer::ReadAttribute(XmlNode &xmlNode, const char *name) const { + if (!hasAttribute(xmlNode, name)) { + ThrowAttibuteError(mParser, name); } - - return m_reader->getAttributeValueAsFloat(name); + + return xmlNode.attribute(name).as_float(); } template <> -std::string OgreXmlSerializer::ReadAttribute(const char *name) const { - const char *value = m_reader->getAttributeValue(name); - if (nullptr == value) { - ThrowAttibuteError(m_reader, name); +std::string OgreXmlSerializer::ReadAttribute(XmlNode &xmlNode, const char *name) const { + if (!hasAttribute(xmlNode, name)) { + ThrowAttibuteError(mParser, name); } - return std::string(value); + return xmlNode.attribute(name).as_string(); } template <> -bool OgreXmlSerializer::ReadAttribute(const char *name) const { - std::string value = Ogre::ToLower(ReadAttribute(name)); +bool OgreXmlSerializer::ReadAttribute(XmlNode &xmlNode, const char *name) const { + std::string value = Ogre::ToLower(ReadAttribute(xmlNode, name)); if (ASSIMP_stricmp(value, "true") == 0) { return true; } else if (ASSIMP_stricmp(value, "false") == 0) { return false; - } else { - ThrowAttibuteError(m_reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'"); - return false; - } + } + + ThrowAttibuteError(mParser, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'"); + return false; } -bool OgreXmlSerializer::HasAttribute(const char *name) const { - return (m_reader->getAttributeValue(name) != 0); -} - -std::string &OgreXmlSerializer::NextNode() { +/*std::string &OgreXmlSerializer::NextNode() { do { if (!m_reader->read()) { m_currentNodeName = ""; @@ -178,7 +177,7 @@ std::string &OgreXmlSerializer::SkipCurrentNode() { return NextNode(); } - +*/ // Mesh XML constants // @@ -247,15 +246,14 @@ static const char *nnTranslate = "translate"; static const char *nnRotate = "rotate"; // Common XML constants - static const char *anX = "x"; static const char *anY = "y"; static const char *anZ = "z"; // Mesh -MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) { - OgreXmlSerializer serializer(reader); +MeshXml *OgreXmlSerializer::ImportMesh(XmlParser *xmlParser) { + OgreXmlSerializer serializer(xmlParser); MeshXml *mesh = new MeshXml(); serializer.ReadMesh(mesh); @@ -264,16 +262,32 @@ MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) { } void OgreXmlSerializer::ReadMesh(MeshXml *mesh) { - if (NextNode() != nnMesh) { + const XmlNode *root = mParser->getRootNode(); + if (nullptr == root || std::string(nnMesh)!=root->name()) { throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting "); } + for (XmlNode currentNode : root->children()) { + const std::string currentName = currentNode.name(); + if (currentName == nnSharedGeometry) { + mesh->sharedVertexData = new VertexDataXml(); + ReadGeometry(currentNode, mesh->sharedVertexData); + } else if (currentName == nnSubMesh) { + ReadSubMesh(currentNode, mesh); + } else if (currentName == nnBoneAssignments) { + ReadBoneAssignments(currentNode, mesh->sharedVertexData); + } else if (currentName == nnSkeletonLink) { + } + } + /*if (NextNode() != nnMesh) { + }*/ + ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh"); - NextNode(); + //NextNode(); // Root level nodes - while (m_currentNodeName == nnSharedGeometry || + /*while (m_currentNodeName == nnSharedGeometry || m_currentNodeName == nnSubMeshes || m_currentNodeName == nnSkeletonLink || m_currentNodeName == nnBoneAssignments || @@ -298,26 +312,33 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) { NextNode(); } // Assimp incompatible/ignored nodes - else + else { SkipCurrentNode(); - } + } + }*/ } -void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest) { - dest->count = ReadAttribute("vertexcount"); +void OgreXmlSerializer::ReadGeometry(XmlNode &node, VertexDataXml *dest) { + dest->count = ReadAttribute(node, "vertexcount"); ASSIMP_LOG_VERBOSE_DEBUG_F(" - Reading geometry of ", dest->count, " vertices"); - NextNode(); - while (m_currentNodeName == nnVertexBuffer) { - ReadGeometryVertexBuffer(dest); + for (XmlNode currentNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == nnVertexBuffer) { + ReadGeometryVertexBuffer(currentNode, dest); + } } + //NextNode(); + /*while (m_currentNodeName == nnVertexBuffer) { + ReadGeometryVertexBuffer(dest); + }*/ } -void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) { - bool positions = (HasAttribute("positions") && ReadAttribute("positions")); - bool normals = (HasAttribute("normals") && ReadAttribute("normals")); - bool tangents = (HasAttribute("tangents") && ReadAttribute("tangents")); - uint32_t uvs = (HasAttribute("texture_coords") ? ReadAttribute("texture_coords") : 0); +void OgreXmlSerializer::ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest) { + bool positions = (hasAttribute(node, "positions") && ReadAttribute(node, "positions")); + bool normals = (hasAttribute(node, "normals") && ReadAttribute(node, "normals")); + bool tangents = (hasAttribute(node, "tangents") && ReadAttribute(node, "tangents")); + uint32_t uvs = (hasAttribute(node, "texture_coords") ? ReadAttribute(node, "texture_coords") : 0); // Not having positions is a error only if a previous vertex buffer did not have them. if (!positions && !dest->HasPositions()) { @@ -348,9 +369,38 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) { bool warnColorDiffuse = true; bool warnColorSpecular = true; - NextNode(); + //NextNode(); + for (XmlNode currentNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (positions && currentName == nnPosition) { + aiVector3D pos; + pos.x = ReadAttribute(currentNode, anX); + pos.y = ReadAttribute(currentNode, anY); + pos.z = ReadAttribute(currentNode, anZ); + dest->positions.push_back(pos); + } else if (normals && currentName == nnNormal) { + aiVector3D normal; + normal.x = ReadAttribute(currentNode, anX); + normal.y = ReadAttribute(currentNode, anY); + normal.z = ReadAttribute(currentNode, anZ); + dest->normals.push_back(normal); + } else if (tangents && currentName == nnTangent) { + aiVector3D tangent; + tangent.x = ReadAttribute(currentNode, anX); + tangent.y = ReadAttribute(currentNode, anY); + tangent.z = ReadAttribute(currentNode, anZ); + dest->tangents.push_back(tangent); + } else if (uvs > 0 && currentName == nnTexCoord) { + for (auto &curUvs : dest->uvs) { + aiVector3D uv; + uv.x = ReadAttribute(currentNode, "u"); + uv.y = (ReadAttribute(currentNode, "v") * -1) + 1; // Flip UV from Ogre to Assimp form + curUvs.push_back(uv); + } + } + } - while (m_currentNodeName == nnVertex || + /*while (m_currentNodeName == nnVertex || m_currentNodeName == nnPosition || m_currentNodeName == nnNormal || m_currentNodeName == nnTangent || @@ -422,11 +472,11 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) { if (warn) { ASSIMP_LOG_WARN_F("Vertex buffer attribute read not implemented for element: ", m_currentNodeName); } - } + }*/ // Advance - NextNode(); - } + //NextNode(); + //} // Sanity checks if (dest->positions.size() != dest->count) { @@ -446,7 +496,7 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) { } } -void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) { +void OgreXmlSerializer::ReadSubMesh(XmlNode &node, MeshXml *mesh) { static const char *anMaterial = "material"; static const char *anUseSharedVertices = "usesharedvertices"; static const char *anCount = "count"; @@ -457,10 +507,10 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) { SubMeshXml *submesh = new SubMeshXml(); - if (HasAttribute(anMaterial)) { - submesh->materialRef = ReadAttribute(anMaterial); + if (hasAttribute(node, anMaterial)) { + submesh->materialRef = ReadAttribute(node, anMaterial); } - if (HasAttribute(anUseSharedVertices)) { + if (hasAttribute(node, anUseSharedVertices)) { submesh->usesSharedVertexData = ReadAttribute(anUseSharedVertices); } @@ -474,7 +524,46 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) { bool quadWarned = false; - NextNode(); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == nnFaces) { + submesh->indexData->faceCount = ReadAttribute(currentNode, anCount); + submesh->indexData->faces.reserve(submesh->indexData->faceCount); + for (XmlNode currentChildNode : currentNode.children()) { + const std::string ¤tChildName = currentNode.name(); + if (currentChildName == nnFace) { + aiFace face; + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + face.mIndices[0] = ReadAttribute(currentChildNode, anV1); + face.mIndices[1] = ReadAttribute(currentChildNode, anV2); + face.mIndices[2] = ReadAttribute(currentChildNode, anV3); + /// @todo Support quads if Ogre even supports them in XML (I'm not sure but I doubt it) + if (!quadWarned && hasAttribute(currentChildNode, anV4)) { + ASSIMP_LOG_WARN("Submesh has quads with , only triangles are supported at the moment!"); + quadWarned = true; + } + } + } + if (submesh->indexData->faces.size() == submesh->indexData->faceCount) { + ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount); + } else { + throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount); + } + + } else if (currentName == nnGeometry) { + if (submesh->usesSharedVertexData) { + throw DeadlyImportError("Found in when use shared geometry is true. Invalid mesh file."); + } + + submesh->vertexData = new VertexDataXml(); + ReadGeometry(currentNode, submesh->vertexData); + } else if (m_currentNodeName == nnBoneAssignments) { + ReadBoneAssignments(currentNode, submesh->vertexData); + } + } + + /*NextNode(); while (m_currentNodeName == nnFaces || m_currentNodeName == nnGeometry || m_currentNodeName == nnTextures || @@ -523,13 +612,13 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) { else { SkipCurrentNode(); } - } + }*/ submesh->index = static_cast(mesh->subMeshes.size()); mesh->subMeshes.push_back(submesh); } -void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) { +void OgreXmlSerializer::ReadBoneAssignments(XmlNode &node, VertexDataXml *dest) { if (!dest) { throw DeadlyImportError("Cannot read bone assignments, vertex data is null."); } @@ -539,8 +628,20 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) { static const char *anWeight = "weight"; std::set influencedVertices; + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == nnVertexBoneAssignment) { + VertexBoneAssignment ba; + ba.vertexIndex = ReadAttribute(currentNode, anVertexIndex); + ba.boneIndex = ReadAttribute(currentNode, anBoneIndex); + ba.weight = ReadAttribute(currentNode, anWeight); - NextNode(); + dest->boneAssignments.push_back(ba); + influencedVertices.insert(ba.vertexIndex); + } + } + + /*NextNode(); while (m_currentNodeName == nnVertexBoneAssignment) { VertexBoneAssignment ba; ba.vertexIndex = ReadAttribute(anVertexIndex); @@ -551,7 +652,7 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) { influencedVertices.insert(ba.vertexIndex); NextNode(); - } + }*/ /** Normalize bone weights. Some exporters won't care if the sum of all bone weights @@ -593,41 +694,43 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me mesh->skeletonRef = mesh->skeletonRef + ".xml"; } - XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); - if (!reader.get()) + XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef); + if (!xmlParser.get()) return false; Skeleton *skeleton = new Skeleton(); - OgreXmlSerializer serializer(reader.get()); + OgreXmlSerializer serializer(xmlParser.get()); serializer.ReadSkeleton(skeleton); mesh->skeleton = skeleton; return true; } bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) { - if (!mesh || mesh->skeletonRef.empty()) + if (!mesh || mesh->skeletonRef.empty()) { return false; + } - XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); - if (!reader.get()) + XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef); + if (!xmlParser.get()) { return false; + } Skeleton *skeleton = new Skeleton(); - OgreXmlSerializer serializer(reader.get()); + OgreXmlSerializer serializer(xmlParser.get()); serializer.ReadSkeleton(skeleton); mesh->skeleton = skeleton; return true; } -XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename) { +XmlParserPtr OgreXmlSerializer::OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename) { if (!EndsWith(filename, ".skeleton.xml", false)) { ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file."); - return XmlReaderPtr(); + return XmlParserPtr(); } if (!pIOHandler->Exists(filename)) { ASSIMP_LOG_ERROR_F("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh."); - return XmlReaderPtr(); + return XmlParserPtr(); } std::unique_ptr file(pIOHandler->Open(filename)); @@ -635,27 +738,36 @@ XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const s throw DeadlyImportError("Failed to open skeleton file " + filename); } - std::unique_ptr stream(new CIrrXML_IOStreamReader(file.get())); - XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get())); - if (!reader.get()) { + XmlParserPtr xmlParser = XmlParserPtr(new XmlParser); + if (!xmlParser->parse(file.get())) { throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename); } - return reader; + return xmlParser; } -void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) { - if (NextNode() != nnSkeleton) { - throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting "); +void OgreXmlSerializer::ReadSkeleton(XmlNode &node, Skeleton *skeleton) { + if (node.name() != nnSkeleton) { + throw DeadlyImportError("Root node is <" + node.name() + "> expecting "); } ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); // Optional blend mode from root node - if (HasAttribute("blendmode")) { - skeleton->blendMode = (ToLower(ReadAttribute("blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE); + if (hasAttribute(node, "blendmode")) { + skeleton->blendMode = (ToLower(ReadAttribute(node, "blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE); } - NextNode(); + for (XmlNode ¤tNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == nnBones) { + ReadBones(currentNode, skeleton); + } else if (currentName == nnBoneHierarchy) { + ReadBoneHierarchy(currentNode, skeleton); + } else if (currentName == nnAnimations) { + ReadAnimations(currentNode, skeleton); + } + } + /*NextNode(); // Root level nodes while (m_currentNodeName == nnBones || @@ -670,17 +782,35 @@ void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) { ReadAnimations(skeleton); else SkipCurrentNode(); - } + }*/ } -void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) { +void OgreXmlSerializer::ReadAnimations(XmlNode &node, Skeleton *skeleton) { if (skeleton->bones.empty()) { throw DeadlyImportError("Cannot read for a Skeleton without bones"); } ASSIMP_LOG_VERBOSE_DEBUG(" - Animations"); - NextNode(); + for (XmlNode ¤tNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == nnAnimation) { + Animation *anim = new Animation(skeleton); + anim->name = ReadAttribute(currentNode, "name"); + anim->length = ReadAttribute(currentNode , "length"); + for (XmlNode ¤tChildNode : currentNode.children()) { + const std::string currentChildName = currentNode.name(); + if (currentChildName == nnTracks) { + ReadAnimationTracks(currentChildNode, anim); + skeleton->animations.push_back(anim); + } else { + throw DeadlyImportError(Formatter::format() << "No found in " << anim->name); + } + } + } + } + +/* NextNode(); while (m_currentNodeName == nnAnimation) { Animation *anim = new Animation(skeleton); anim->name = ReadAttribute("name"); @@ -694,11 +824,29 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) { skeleton->animations.push_back(anim); ASSIMP_LOG_VERBOSE_DEBUG_F(" ", anim->name, " (", anim->length, " sec, ", anim->tracks.size(), " tracks)"); - } + }*/ } -void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) { - NextNode(); +void OgreXmlSerializer::ReadAnimationTracks(XmlNode &node, Animation *dest) { + for (XmlNode ¤tNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == nnTrack) { + VertexAnimationTrack track; + track.type = VertexAnimationTrack::VAT_TRANSFORM; + track.boneName = ReadAttribute(currentNode, "bone"); + for (XmlNode ¤tChildNode : currentNode.children()) { + const std::string currentChildName = currentNode.name(); + if (currentChildName == nnKeyFrames) { + ReadAnimationKeyFrames(currentChildNode, dest, &track); + dest->tracks.push_back(track); + } else { + throw DeadlyImportError(Formatter::format() << "No found in " << dest->name); + } + } + + } + } + /*NextNode(); while (m_currentNodeName == nnTrack) { VertexAnimationTrack track; track.type = VertexAnimationTrack::VAT_TRANSFORM; @@ -711,13 +859,52 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) { ReadAnimationKeyFrames(dest, &track); dest->tracks.push_back(track); - } + }*/ } -void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest) { +void OgreXmlSerializer::ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest) { const aiVector3D zeroVec(0.f, 0.f, 0.f); + for (XmlNode ¤tNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == nnKeyFrame) { + TransformKeyFrame keyframe; + keyframe.timePos = ReadAttribute(currentNode, "time"); + for (XmlNode ¤tChildNode : currentNode.children()) { + const std::string currentChildName = currentNode.name(); + if (currentChildName == nnTranslate) { + keyframe.position.x = ReadAttribute(currentChildNode, anX); + keyframe.position.y = ReadAttribute(currentChildNode, anY); + keyframe.position.z = ReadAttribute(currentChildNode, anZ); + } else if (currentChildName == nnRotate) { + float angle = ReadAttribute(currentChildNode, "angle"); + for (XmlNode ¤tChildChildNode : currentNode.children()) { + const std::string currentChildChildName = currentNode.name(); + if (currentChildChildName == nnAxis) { + aiVector3D axis; + axis.x = ReadAttribute(currentChildChildNode, anX); + axis.y = ReadAttribute(currentChildChildNode, anY); + axis.z = ReadAttribute(currentChildChildNode, anZ); + if (axis.Equal(zeroVec)) { + axis.x = 1.0f; + if (angle != 0) { + ASSIMP_LOG_WARN_F("Found invalid a key frame with a zero rotation axis in animation: ", anim->name); + } + } + keyframe.rotation = aiQuaternion(axis, angle); + } + } + } else if (currentChildName == nnScale) { + keyframe.scale.x = ReadAttribute(currentChildNode, anX); + keyframe.scale.y = ReadAttribute(currentChildNode, anY); + keyframe.scale.z = ReadAttribute(currentChildNode, anZ); - NextNode(); + } + + } + } + dest->transformKeyFrames.push_back(keyframe); + } + /*NextNode(); while (m_currentNodeName == nnKeyFrame) { TransformKeyFrame keyframe; keyframe.timePos = ReadAttribute("time"); @@ -756,15 +943,33 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT } dest->transformKeyFrames.push_back(keyframe); - } + }*/ } -void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) { +void OgreXmlSerializer::ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton) { if (skeleton->bones.empty()) { throw DeadlyImportError("Cannot read for a Skeleton without bones"); } - while (NextNode() == nnBoneParent) { + for (XmlNode ¤tNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == nnBoneParent) { + const std::string name = ReadAttribute(currentNode, "bone"); + const std::string parentName = ReadAttribute(currentNode, "parent"); + + Bone *bone = skeleton->BoneByName(name); + Bone *parent = skeleton->BoneByName(parentName); + + if (bone && parent) { + parent->AddChild(bone); + } else { + throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName); + } + } + } + + + /*while (NextNode() == nnBoneParent) { const std::string name = ReadAttribute("bone"); const std::string parentName = ReadAttribute("parent"); @@ -775,7 +980,7 @@ void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) { parent->AddChild(bone); else throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName); - } + }*/ // Calculate bone matrices for root bones. Recursively calculates their children. for (size_t i = 0, len = skeleton->bones.size(); i < len; ++i) { @@ -792,9 +997,28 @@ static bool BoneCompare(Bone *a, Bone *b) { return (a->id < b->id); } -void OgreXmlSerializer::ReadBones(Skeleton *skeleton) { +void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) { ASSIMP_LOG_VERBOSE_DEBUG(" - Bones"); + for (XmlNode ¤tNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == nnBone) { + Bone *bone = new Bone(); + bone->id = ReadAttribute(currentNode, "id"); + bone->name = ReadAttribute(currentNode, "name"); + for (XmlNode ¤tChildNode : currentNode.children()) { + const std::string currentChildName = currentNode.name(); + if (currentChildName == nnPosition) { + bone->position.x = ReadAttribute(currentChildNode, anX); + bone->position.y = ReadAttribute(currentChildNode, anY); + bone->position.z = ReadAttribute(currentChildNode, anZ); + } else if (currentChildName == nnScale) { + } else if (currentChildName == nnScale) { + } + } + } + } + NextNode(); while (m_currentNodeName == nnBone) { Bone *bone = new Bone(); diff --git a/code/AssetLib/Ogre/OgreXmlSerializer.h b/code/AssetLib/Ogre/OgreXmlSerializer.h index 2b35b9f2c..f18791e86 100644 --- a/code/AssetLib/Ogre/OgreXmlSerializer.h +++ b/code/AssetLib/Ogre/OgreXmlSerializer.h @@ -48,71 +48,70 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "OgreStructs.h" #include -namespace Assimp -{ -namespace Ogre -{ +namespace Assimp { +namespace Ogre { -typedef irr::io::IrrXMLReader XmlReader; -typedef std::shared_ptr XmlReaderPtr; +//typedef irr::io::IrrXMLReader XmlReader; +using XmlParserPtr = std::shared_ptr ; -class OgreXmlSerializer -{ +class OgreXmlSerializer { public: /// Imports mesh and returns the result. /** @note Fatal unrecoverable errors will throw a DeadlyImportError. */ - static MeshXml *ImportMesh(XmlReader *reader); + static MeshXml *ImportMesh(XmlParser *parser); /// Imports skeleton to @c mesh. /** If mesh does not have a skeleton reference or the skeleton file cannot be found it is not a fatal DeadlyImportError. @return If skeleton import was successful. */ - static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh); - static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh); + static bool ImportSkeleton(IOSystem *pIOHandler, MeshXml *mesh); + static bool ImportSkeleton(IOSystem *pIOHandler, Mesh *mesh); private: - explicit OgreXmlSerializer(XmlReader *reader) : - m_reader(reader) - { - } + explicit OgreXmlSerializer(XmlParser *xmlParser); - static XmlReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename); + static XmlParserPtr OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename); // Mesh void ReadMesh(MeshXml *mesh); - void ReadSubMesh(MeshXml *mesh); + void ReadSubMesh(XmlNode &node, MeshXml *mesh); - void ReadGeometry(VertexDataXml *dest); - void ReadGeometryVertexBuffer(VertexDataXml *dest); + void ReadGeometry(XmlNode &node, VertexDataXml *dest); + void ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest); - void ReadBoneAssignments(VertexDataXml *dest); + void ReadBoneAssignments(XmlNode &node, VertexDataXml *dest); // Skeleton - void ReadSkeleton(Skeleton *skeleton); + void ReadSkeleton(XmlNode &node, Skeleton *skeleton); - void ReadBones(Skeleton *skeleton); - void ReadBoneHierarchy(Skeleton *skeleton); + void ReadBones(XmlNode &node, Skeleton *skeleton); + void ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton); - void ReadAnimations(Skeleton *skeleton); - void ReadAnimationTracks(Animation *dest); - void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest); + void ReadAnimations(XmlNode &node, Skeleton *skeleton); + void ReadAnimationTracks(XmlNode &node, Animation *dest); + void ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest); - template - T ReadAttribute(const char *name) const; - bool HasAttribute(const char *name) const; + template + T ReadAttribute(XmlNode &xmlNode, const char *name) const; + //bool HasAttribute(const char *name) const; - std::string &NextNode(); - std::string &SkipCurrentNode(); + //std::string &NextNode(); + //std::string &SkipCurrentNode(); - bool CurrentNodeNameEquals(const std::string &name) const; - std::string CurrentNodeName(bool forceRead = false); + //bool CurrentNodeNameEquals(const std::string &name) const; + //std::string CurrentNodeName(bool forceRead = false); - XmlReader *m_reader; + XmlParser *mParser; std::string m_currentNodeName; }; -} // Ogre -} // Assimp +inline OgreXmlSerializer::OgreXmlSerializer(XmlParser *xmlParser) : + mParser(xmlParser) { + // empty +} + +} // namespace Ogre +} // namespace Assimp #endif // ASSIMP_BUILD_NO_OGRE_IMPORTER #endif // AI_OGREXMLSERIALIZER_H_INC