소스 검색

Introduce node iterator.

Kim Kulling 5 년 전
부모
커밋
6d5c388780

+ 11 - 8
code/AssetLib/AMF/AMFImporter.cpp

@@ -291,10 +291,13 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
 void AMFImporter::ParseNode_Root() {
     std::string unit, version;
     AMFNodeElementBase *ne(nullptr);
-    pugi::xml_node *root = mXmlParser->findNode("amf");
-    
-    unit = root->attribute("unit").as_string();
-    version = root->attribute("version").as_string();
+    XmlNode *root = mXmlParser->findNode("amf");
+    if (nullptr == root) {
+        throw DeadlyImportError("Root node \"amf\" not found.");
+    }
+    XmlNode node = *root;
+    unit = node.attribute("unit").as_string();
+    version = node.attribute("version").as_string();
 
     // Read attributes for node <amf>.
     // Check attributes
@@ -313,7 +316,7 @@ void AMFImporter::ParseNode_Root() {
     ((AMFRoot *)ne)->Version = version;
 
     // Check for child nodes
-    for (pugi::xml_node &currentNode : root->children()) {
+    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
         const std::string currentName = currentNode.name();
         if (currentName == "object") {
             ParseNode_Object(currentNode);
@@ -353,7 +356,7 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) {
     }
 
     // Check for child nodes
-    for (pugi::xml_node &currentNode : node.children()) {
+    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
         std::string name = currentNode.name();
         if (name == "instance") {
             ParseNode_Instance(currentNode);
@@ -392,7 +395,7 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
     if (node.empty()) {
         mNodeElement_Cur->Child.push_back(ne);
     }
-    for (pugi::xml_node currentNode : node.children()) {
+    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
         bool read_flag[6] = { false, false, false, false, false, false };
         std::string currentName = currentNode.name();
         if (currentName == "deltax") {
@@ -447,7 +450,7 @@ void AMFImporter::ParseNode_Object(XmlNode &node) {
     if (node.empty()) {
         mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
     }
-    for (pugi::xml_node &currentNode : node.children()) {
+    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
         const std::string currentName = currentNode.name();
         if (currentName == "color") {
             ParseNode_Color(currentNode);

+ 2 - 2
code/AssetLib/AMF/AMFImporter_Geometry.cpp

@@ -196,7 +196,7 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) {
     }
 
     bool col_read = false;
-    for (pugi::xml_node currentNode : node.children()) {
+    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
         const std::string currentName = currentNode.name();
         if (currentName == "color") {
             if (col_read) Throw_MoreThanOnceDefined(currentName ,"color", "Only one color can be defined for <volume>.");
@@ -238,7 +238,7 @@ void AMFImporter::ParseNode_Triangle(XmlNode &node) {
     // 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()) {
+    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
         const std::string currentName = currentNode.name();
         if (currentName == "color") {
             if (col_read) Throw_MoreThanOnceDefined(currentName , "color", "Only one color can be defined for <triangle>.");

+ 37 - 39
code/AssetLib/AMF/AMFImporter_Postprocess.cpp

@@ -98,9 +98,13 @@ void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElem
         return;
     }
 
-    pVertexCoordinateArray.reserve(vn->Child.size()); // all coordinates stored as child and we need to reserve space for future push_back's.
-    pVertexColorArray.resize(vn->Child.size()); // colors count equal vertices count.
+    // all coordinates stored as child and we need to reserve space for future push_back's.
+    pVertexCoordinateArray.reserve(vn->Child.size()); 
+
+    // colors count equal vertices count.
+    pVertexColorArray.resize(vn->Child.size()); 
     col_idx = 0;
+
     // Inside vertices collect all data and place to arrays
     for (AMFNodeElementBase *vn_child : vn->Child) {
         // vertices, colors
@@ -118,26 +122,20 @@ void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElem
                     pVertexColorArray[col_idx] = (AMFColor *)vtx;
                     continue;
                 }
-            } // for(CAMFImporter_NodeElement* vtx: vn_child->Child)
+            }
 
             col_idx++;
-        } // if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
-    } // for(CAMFImporter_NodeElement* vn_child: vn->Child)
+        }
+    }
 }
 
-size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &pID_R, const std::string &pID_G, const std::string &pID_B,
-        const std::string &pID_A) {
-    size_t TextureConverted_Index;
-    std::string TextureConverted_ID;
-
-    // check input data
-    if (pID_R.empty() && pID_G.empty() && pID_B.empty() && pID_A.empty())
+size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &r, const std::string &g, const std::string &b, const std::string &a) {
+    if (r.empty() && g.empty() && b.empty() && a.empty()) {
         throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined.");
+    }
 
-    // Create ID
-    TextureConverted_ID = pID_R + "_" + pID_G + "_" + pID_B + "_" + pID_A;
-    // Check if texture specified by set of IDs is converted already.
-    TextureConverted_Index = 0;
+    std::string TextureConverted_ID = r + "_" + g + "_" + b + "_" + a;
+    size_t TextureConverted_Index = 0;
     for (const SPP_Texture &tex_convd : mTexture_Converted) {
         if (tex_convd.ID == TextureConverted_ID) {
             return TextureConverted_Index;
@@ -146,10 +144,10 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
         }
     }
 
-    //
     // Converted texture not found, create it.
-    //
-    AMFTexture *src_texture[4]{ nullptr };
+    AMFTexture *src_texture[4] {
+        nullptr
+    };
     std::vector<AMFTexture *> src_texture_4check;
     SPP_Texture converted_texture;
 
@@ -157,8 +155,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
         AMFNodeElementBase *t_tex = nullptr;
 
         // R
-        if (!pID_R.empty()) {
-            if (!Find_NodeElement(pID_R, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
+        if (!r.empty()) {
+            if (!Find_NodeElement(r, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) Throw_ID_NotFound(r);
 
             src_texture[0] = (AMFTexture *)t_tex;
             src_texture_4check.push_back((AMFTexture *)t_tex);
@@ -167,8 +165,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
         }
 
         // G
-        if (!pID_G.empty()) {
-            if (!Find_NodeElement(pID_G, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
+        if (!g.empty()) {
+            if (!Find_NodeElement(g, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(g);
 
             src_texture[1] = (AMFTexture *)t_tex;
             src_texture_4check.push_back((AMFTexture *)t_tex);
@@ -177,8 +175,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
         }
 
         // B
-        if (!pID_B.empty()) {
-            if (!Find_NodeElement(pID_B, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
+        if (!b.empty()) {
+            if (!Find_NodeElement(b, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(b);
 
             src_texture[2] = (AMFTexture *)t_tex;
             src_texture_4check.push_back((AMFTexture *)t_tex);
@@ -187,8 +185,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
         }
 
         // A
-        if (!pID_A.empty()) {
-            if (!Find_NodeElement(pID_A, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
+        if (!a.empty()) {
+            if (!Find_NodeElement(a, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(a);
 
             src_texture[3] = (AMFTexture *)t_tex;
             src_texture_4check.push_back((AMFTexture *)t_tex);
@@ -218,10 +216,10 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
 
     // Create format hint.
     strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
-    if (!pID_R.empty()) converted_texture.FormatHint[4] = '8';
-    if (!pID_G.empty()) converted_texture.FormatHint[5] = '8';
-    if (!pID_B.empty()) converted_texture.FormatHint[6] = '8';
-    if (!pID_A.empty()) converted_texture.FormatHint[7] = '8';
+    if (!r.empty()) converted_texture.FormatHint[4] = '8';
+    if (!g.empty()) converted_texture.FormatHint[5] = '8';
+    if (!b.empty()) converted_texture.FormatHint[6] = '8';
+    if (!a.empty()) converted_texture.FormatHint[7] = '8';
 
     // Сopy data of textures.
     size_t tex_size = 0;
@@ -230,19 +228,19 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
     size_t off_b = 0;
 
     // Calculate size of the target array and rule how data will be copied.
-    if (!pID_R.empty() && nullptr != src_texture[0]) {
+    if (!r.empty() && nullptr != src_texture[0]) {
         tex_size += src_texture[0]->Data.size();
         step++, off_g++, off_b++;
     }
-    if (!pID_G.empty() && nullptr != src_texture[1]) {
+    if (!g.empty() && nullptr != src_texture[1]) {
         tex_size += src_texture[1]->Data.size();
         step++, off_b++;
     }
-    if (!pID_B.empty() && nullptr != src_texture[2]) {
+    if (!b.empty() && nullptr != src_texture[2]) {
         tex_size += src_texture[2]->Data.size();
         step++;
     }
-    if (!pID_A.empty() && nullptr != src_texture[3]) {
+    if (!a.empty() && nullptr != src_texture[3]) {
         tex_size += src_texture[3]->Data.size();
         step++;
     }
@@ -260,10 +258,10 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
         }
     }; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
 
-    CopyTextureData(pID_R, 0, step, 0);
-    CopyTextureData(pID_G, off_g, step, 1);
-    CopyTextureData(pID_B, off_b, step, 2);
-    CopyTextureData(pID_A, step - 1, step, 3);
+    CopyTextureData(r, 0, step, 0);
+    CopyTextureData(g, off_g, step, 1);
+    CopyTextureData(b, off_b, step, 2);
+    CopyTextureData(a, step - 1, step, 3);
 
     // Store new converted texture ID
     converted_texture.ID = TextureConverted_ID;

+ 66 - 52
code/AssetLib/Collada/ColladaParser.cpp

@@ -170,8 +170,9 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
         if (nullptr == root) {
             return std::string();
         }
-        const char *filepath = root->value();
-        aiString ai_str(filepath);
+        std::string v;
+        XmlParser::getValueAsString(*root, v);
+        aiString ai_str(v);
         UriDecodePath(ai_str);
         return std::string(ai_str.C_Str());
     }
@@ -302,10 +303,11 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
                 mUnitSize = static_cast<ai_real>(attr.as_double());
             }
         } else if (name == "up_axis") {
-            const char *content = currentNode.value();
-            if (strncmp(content, "X_UP", 4) == 0) {
+            std::string v;
+            XmlParser::getValueAsString(currentNode, v);
+            if (v == "X_UP" ) {
                 mUpDirection = UP_X;
-            } else if (strncmp(content, "Z_UP", 4) == 0) {
+            } else if (v == "Z_UP" ) {
                 mUpDirection = UP_Z;
             } else {
                 mUpDirection = UP_Y;
@@ -334,21 +336,23 @@ void ColladaParser::ReadMetaDataItem(XmlNode &node, StringMetaData &metadata) {
     const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase();
 
     const std::string name = node.name();
-    if (!name.empty()) {
-        const char *value_char = node.value();
-        if (nullptr != value_char) {
-            aiString aistr;
-            aistr.Set(value_char);
-
-            std::string camel_key_str(name);
-            ToCamelCase(camel_key_str);
-
-            size_t found_index;
-            if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
-                metadata.emplace(key_renaming[found_index].second, aistr);
-            } else {
-                metadata.emplace(camel_key_str, aistr);
-            }
+    if (name.empty()) {
+        return;
+    }
+
+    std::string v;
+    if (XmlParser::getValueAsString(node, v)) {
+        aiString aistr;
+        aistr.Set(v);
+
+        std::string camel_key_str(name);
+        ToCamelCase(camel_key_str);
+
+        size_t found_index;
+        if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
+            metadata.emplace(key_renaming[found_index].second, aistr);
+        } else {
+            metadata.emplace(camel_key_str, aistr);
         }
     }
 }
@@ -588,17 +592,9 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) {
         return;
     }
 
-    int attrId = node.attribute("id").as_int();
-    std::string id = node.value();
+    std::string id = node.attribute("id").as_string();
     mControllerLibrary[id] = Controller();
-    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
-        const std::string currentName = currentNode.name();
-        if (currentName == "controller") {
-            attrId = currentNode.attribute("id").as_int();
-            std::string controllerId = currentNode.attribute(std::to_string(attrId).c_str()).value();
-            ReadController(node, mControllerLibrary[controllerId]);
-        }
-    }
+    ReadController(node, mControllerLibrary[id]);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -614,8 +610,10 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
             pController.mMeshId = currentNode.attribute("source").as_string();
             int methodIndex = currentNode.attribute("method").as_int();
             if (methodIndex > 0) {
-                const char *method = currentNode.attribute("method").value();
-                if (strcmp(method, "RELATIVE") == 0) {
+                std::string method;
+                XmlParser::getValueAsString(currentNode, method);
+                
+                if (method == "RELATIVE" ) {
                     pController.mMethod = Relative;
                 }
             }
@@ -722,9 +720,11 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
             pController.mWeights.resize(numWeights);
         } else if (currentName == "v" && vertexCount > 0) {
             // read JointIndex - WeightIndex pairs
-            const char *text = currentNode.value();
+            std::string stdText;
+            XmlParser::getValueAsString(currentNode, stdText);
+            const char *text = stdText.c_str();
             for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
-                if (*text == 0) {
+                if (text == 0) {
                     ThrowException("Out of data while reading <vertex_weights>");
                 }
                 it->first = strtoul10(text, &text);
@@ -770,13 +770,12 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
                 // FIX: C4D exporter writes empty <init_from/> tags
                 if (!currentNode.empty()) {
                     // element content is filename - hopefully
-                    const char *sz = currentNode.value();
+                    const char *sz = currentNode.text().as_string();
                     if (sz) {
                         aiString filepath(sz);
                         UriDecodePath(filepath);
                         pImage.mFileName = filepath.C_Str();
                     }
-                    //                    TestClosing("init_from");
                 }
                 if (!pImage.mFileName.length()) {
                     pImage.mFileName = "unknown_texture";
@@ -800,13 +799,13 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
                 // TODO: correctly jump over cube and volume maps?
             }
         } else if (mFormat == FV_1_5_n) {
+            std::string value;
             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);
+                if (XmlParser::getValueAsString(refChild, value)) {
+                    aiString filepath(value);
                     UriDecodePath(filepath);
                     pImage.mFileName = filepath.C_Str();
                 }
@@ -817,8 +816,8 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
                     ASSIMP_LOG_WARN("Collada: Unknown image file format");
                 }
 
-                const char *data = hexChild.value();
-
+                XmlParser::getValueAsString(hexChild, value);
+                const char *data = value.c_str();
                 // hexadecimal-encoded binary octets. First of all, find the
                 // required buffer size to reserve enough storage.
                 const char *cur = data;
@@ -924,7 +923,10 @@ void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) {
 // ------------------------------------------------------------------------------------------------
 // Reads a light entry into the given light
 void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
-    for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+    XmlNodeIterator xmlIt;
+    xmlIt.collectChildrenPreOrder(node);
+    XmlNode currentNode;
+    while (xmlIt.getNext(currentNode)) {
         const std::string &currentName = currentNode.name();
         if (currentName == "spot") {
             pLight.mType = aiLightSource_SPOT;
@@ -936,7 +938,9 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
             pLight.mType = aiLightSource_POINT;
         } else if (currentName == "color") {
             // text content contains 3 floats
-            const char *content = currentNode.value();
+            std::string v;
+            XmlParser::getValueAsString(currentNode, v);
+            const char *content = v.c_str();
 
             content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.r);
             SkipSpacesAndLineEnd(&content);
@@ -1156,8 +1160,9 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) {
         } else if (currentName == "rotateUV") {
             XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mTransform.mRotation);
         } else if (currentName == "blend_mode") {
-
-            const char *sz = currentNode.value();
+            std::string v;
+            XmlParser::getValueAsString(currentNode, v);
+            const char *sz = v.c_str();
             // http://www.feelingsoftware.com/content/view/55/72/lang,en/
             // NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE
             if (0 == ASSIMP_strincmp(sz, "ADD", 3))
@@ -1196,7 +1201,9 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p
         const std::string &currentName = currentNode.name();
         if (currentName == "color") {
             // text content contains 4 floats
-            const char *content = currentNode.value();
+            std::string v;
+            XmlParser::getValueAsString(currentNode, v);
+            const char *content = v.c_str();
 
             content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.r);
             SkipSpacesAndLineEnd(&content);
@@ -1353,9 +1360,10 @@ void ColladaParser::ReadSource(XmlNode &node) {
         if (currentName == "float_array" || currentName == "IDREF_array" || currentName == "Name_array") {
             ReadDataArray(currentNode);
         } else if (currentName == "technique_common") {
-            // I don't care for your profiles
-        } else if (currentName == "accessor") {
-            ReadAccessor(currentNode, sourceID);
+            XmlNode technique = currentNode.child("accessor");
+            if (!technique.empty()) {
+                ReadAccessor(technique, sourceID);
+            }
         }
     }
 }
@@ -1371,7 +1379,9 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
     XmlParser::getStdStrAttribute(node, "id", id);
     unsigned int count;
     XmlParser::getUIntAttribute(node, "count", count);
-    const char *content = node.value();
+    std::string v;
+    XmlParser::getValueAsString(node, v);
+    const char *content = v.c_str();
 
     // read values and store inside an array in the data library
     mDataLibrary[id] = Data();
@@ -1575,7 +1585,9 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
                 if (numPrimitives) // It is possible to define a mesh without any primitives
                 {
                     // case <polylist> - specifies the number of indices for each polygon
-                    const char *content = currentNode.value();
+                    std::string v;
+                    XmlParser::getValueAsString(currentNode, v);
+                    const char *content = v.c_str();
                     vcount.reserve(numPrimitives);
                     for (unsigned int a = 0; a < numPrimitives; a++) {
                         if (*content == 0)
@@ -1694,7 +1706,9 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
 
     if (pNumPrimitives > 0) // It is possible to not contain any indices
     {
-        const char *content = node.value();
+        std::string v;
+        XmlParser::getValueAsString(node, v);
+        const char *content = v.c_str();
         while (*content != 0) {
             // read a value.
             // Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways.

+ 58 - 1
include/assimp/XmlParser.h

@@ -209,7 +209,18 @@ public:
 
     }
 
-private:
+    static inline bool getValueAsString( XmlNode &node, std::string &text ) {
+        text = "";
+        if (node.empty()) {
+            return false;
+        }
+
+        text = node.text().as_string();
+
+        return true;
+    }
+
+ private:
     pugi::xml_document *mDoc;
     TNodeType *mRoot;
     TNodeType mCurrent;
@@ -218,6 +229,52 @@ private:
 
 using XmlParser = TXmlParser<pugi::xml_node>;
 
+class XmlNodeIterator {
+public:
+    XmlNodeIterator() :
+            mNodes(),
+            mIndex(9999999) {
+        // empty
+    }
+
+    void collectChildrenPreOrder( XmlNode &node ) {
+        mNodes.push_back(&node);
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            collectChildrenPreOrder(currentNode);
+        }
+    }
+
+    void collectChildrenPostOrder(XmlNode &node) {
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            collectChildrenPostOrder(currentNode);
+        }
+        mNodes.push_back(&node);
+    }
+
+    bool getNext(XmlNode &next) {
+        if (mIndex == mNodes.size()) {
+            return false;
+        }
+
+        mNodes[mIndex];
+        ++mIndex;
+
+        return true;
+    }
+
+    void clear() {
+        if (mNodes.empty()) {
+            return;
+        }
+
+        mNodes.clear();
+    }
+
+private:
+    std::vector<XmlNode *> mNodes;
+    size_t mIndex;
+    TraverseOrder mTraverseOrder;
+};
 } // namespace Assimp
 
 #endif // !! INCLUDED_AI_IRRXML_WRAPPER