Browse Source

Merge pull request #1812 from benloong/fix_findNode

fix findNode with mesh skin may lead to stack overflow.
Sean Taylor 10 years ago
parent
commit
c1893ab50a
2 changed files with 73 additions and 21 deletions
  1. 40 21
      gameplay/src/Node.cpp
  2. 33 0
      gameplay/src/Node.h

+ 40 - 21
gameplay/src/Node.cpp

@@ -218,23 +218,32 @@ Node* Node::getRootNode() const
 }
 
 Node* Node::findNode(const char* id, bool recursive, bool exactMatch) const
+{
+    return findNode(id, recursive, exactMatch, false);
+}
+
+Node* Node::findNode(const char* id, bool recursive, bool exactMatch, bool skipSkin) const
 {
     GP_ASSERT(id);
 
-    // If the drawable is a model with a mesh skin, search the skin's hierarchy as well.
-    Node* rootNode = NULL;
-    Model* model = dynamic_cast<Model*>(_drawable);
-    if (model)
+    // If not skipSkin hierarchy, try searching the skin hierarchy
+    if (!skipSkin)
     {
-        if (model->getSkin() != NULL && (rootNode = model->getSkin()->_rootNode) != NULL)
+        // If the drawable is a model with a mesh skin, search the skin's hierarchy as well.
+        Node* rootNode = NULL;
+        Model* model = dynamic_cast<Model*>(_drawable);
+        if (model)
         {
-            if ((exactMatch && rootNode->_id == id) || (!exactMatch && rootNode->_id.find(id) == 0))
-                return rootNode;
-
-            Node* match = rootNode->findNode(id, true, exactMatch);
-            if (match)
+            if (model->getSkin() != NULL && (rootNode = model->getSkin()->_rootNode) != NULL)
             {
-                return match;
+                if ((exactMatch && rootNode->_id == id) || (!exactMatch && rootNode->_id.find(id) == 0))
+                    return rootNode;
+
+                Node* match = rootNode->findNode(id, true, exactMatch, true);
+                if (match)
+                {
+                    return match;
+                }
             }
         }
     }
@@ -252,7 +261,7 @@ Node* Node::findNode(const char* id, bool recursive, bool exactMatch) const
     {
         for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
         {
-            Node* match = child->findNode(id, true, exactMatch);
+            Node* match = child->findNode(id, true, exactMatch, skipSkin);
             if (match)
             {
                 return match;
@@ -263,25 +272,35 @@ Node* Node::findNode(const char* id, bool recursive, bool exactMatch) const
 }
 
 unsigned int Node::findNodes(const char* id, std::vector<Node*>& nodes, bool recursive, bool exactMatch) const
+{
+    return findNodes(id, nodes, recursive, exactMatch, false);
+}
+
+unsigned int Node::findNodes(const char* id, std::vector<Node*>& nodes, bool recursive, bool exactMatch, bool skipSkin) const
 {
     GP_ASSERT(id);
 
     // If the drawable is a model with a mesh skin, search the skin's hierarchy as well.
     unsigned int count = 0;
-    Node* rootNode = NULL;
-    Model* model = dynamic_cast<Model*>(_drawable);
-    if (model)
+
+    if (!skipSkin)
     {
-        if (model->getSkin() != NULL && (rootNode = model->getSkin()->_rootNode) != NULL)
+        Node* rootNode = NULL;
+        Model* model = dynamic_cast<Model*>(_drawable);
+        if (model)
         {
-            if ((exactMatch && rootNode->_id == id) || (!exactMatch && rootNode->_id.find(id) == 0))
+            if (model->getSkin() != NULL && (rootNode = model->getSkin()->_rootNode) != NULL)
             {
-                nodes.push_back(rootNode);
-                ++count;
+                if ((exactMatch && rootNode->_id == id) || (!exactMatch && rootNode->_id.find(id) == 0))
+                {
+                    nodes.push_back(rootNode);
+                    ++count;
+                }
+                count += rootNode->findNodes(id, nodes, recursive, exactMatch, true);
             }
-            count += rootNode->findNodes(id, nodes, true, exactMatch);
         }
     }
+
     // Search immediate children first.
     for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
     {
@@ -297,7 +316,7 @@ unsigned int Node::findNodes(const char* id, std::vector<Node*>& nodes, bool rec
     {
         for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
         {
-            count += child->findNodes(id, nodes, true, exactMatch);
+            count += child->findNodes(id, nodes, recursive, exactMatch, skipSkin);
         }
     }
 

+ 33 - 0
gameplay/src/Node.h

@@ -665,6 +665,39 @@ protected:
      */
     void setBoundsDirty();
 
+    /**
+     * Returns the first child node that matches the given ID.
+     *
+     * This method checks the specified ID against its immediate child nodes
+     * but does not check the ID against itself.
+     * If recursive is true, it also traverses the Node's hierarchy with a breadth first search.
+     *
+     * @param id The ID of the child to find.
+     * @param recursive True to search recursively all the node's children, false for only direct children.
+     * @param exactMatch true if only nodes whose ID exactly matches the specified ID are returned,
+     *        or false if nodes that start with the given ID are returned.
+     * @param skipSkin Set true to skip skin hierarchy, initial find may set false to include skin hierarchy.
+     *
+     * @return The Node found or NULL if not found.
+     */
+    Node* findNode(const char* id, bool recursive, bool exactMatch, bool skipSkin) const;
+
+
+    /**
+     * Returns all child nodes that match the given ID.
+     *
+     * @param id The ID of the node to find.
+     * @param nodes A vector of nodes to be populated with matches.
+     * @param recursive true if a recursive search should be performed, false otherwise.
+     * @param exactMatch true if only nodes whose ID exactly matches the specified ID are returned,
+     *        or false if nodes that start with the given ID are returned.
+     * @param skipSkin Set true to skip skin hierarchy, initial find may set false to include skin hierarchy.
+     * 
+     * @return The number of matches found.
+     * @script{ignore}
+     */
+    unsigned int findNodes(const char* id, std::vector<Node*>& nodes, bool recursive, bool exactMatch, bool skipSkin) const;
+
 private:
 
     /**