diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 5a8414bf85..44722c5491 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -41,7 +41,6 @@ depthWriteAttrib.I depthWriteAttrib.h \ directionalLight.I directionalLight.h \ drawCullHandler.I drawCullHandler.h \ - findApproxLevel.I findApproxLevel.h \ findApproxLevelEntry.I findApproxLevelEntry.h \ findApproxPath.I findApproxPath.h \ fog.I fog.h \ @@ -129,7 +128,6 @@ depthWriteAttrib.cxx \ directionalLight.cxx \ drawCullHandler.cxx \ - findApproxLevel.cxx \ findApproxLevelEntry.cxx \ findApproxPath.cxx \ fog.cxx \ @@ -267,7 +265,6 @@ workingNodePath.I workingNodePath.h // No need to install these. -// findApproxLevel.I findApproxLevel.h \ // findApproxLevelEntry.I findApproxLevelEntry.h \ // findApproxPath.I findApproxPath.h \ diff --git a/panda/src/pgraph/findApproxLevel.I b/panda/src/pgraph/findApproxLevel.I deleted file mode 100644 index 144084e666..0000000000 --- a/panda/src/pgraph/findApproxLevel.I +++ /dev/null @@ -1,29 +0,0 @@ -// Filename: findApproxLevel.I -// Created by: drose (13Mar02) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://etc.cmu.edu/panda3d/docs/license/ . -// -// To contact the maintainers of this program write to -// panda3d-general@lists.sourceforge.net . -// -//////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////// -// Function: FindApproxLevel::add_entry -// Access: Public -// Description: Adds a new entry to the level. -//////////////////////////////////////////////////////////////////// -INLINE void FindApproxLevel:: -add_entry(const FindApproxLevelEntry &entry) { - _v.push_back(entry); -} - diff --git a/panda/src/pgraph/findApproxLevel.cxx b/panda/src/pgraph/findApproxLevel.cxx deleted file mode 100644 index e47cd4e2ec..0000000000 --- a/panda/src/pgraph/findApproxLevel.cxx +++ /dev/null @@ -1,34 +0,0 @@ -// Filename: findApproxLevel.cxx -// Created by: drose (13Mar02) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://etc.cmu.edu/panda3d/docs/license/ . -// -// To contact the maintainers of this program write to -// panda3d-general@lists.sourceforge.net . -// -//////////////////////////////////////////////////////////////////// - -#include "findApproxLevel.h" - -//////////////////////////////////////////////////////////////////// -// Function: FindApproxLevel::write -// Access: Public -// Description: Shows the entire contents of the level, one entry per -// line. For debugging only. -//////////////////////////////////////////////////////////////////// -void FindApproxLevel:: -write(ostream &out) const { - Vec::const_iterator vi; - for (vi = _v.begin(); vi != _v.end(); ++vi) { - (*vi).output(out); - out << "\n"; - } -} diff --git a/panda/src/pgraph/findApproxLevel.h b/panda/src/pgraph/findApproxLevel.h deleted file mode 100644 index 1b6ee1c6a4..0000000000 --- a/panda/src/pgraph/findApproxLevel.h +++ /dev/null @@ -1,46 +0,0 @@ -// Filename: findApproxLevel.h -// Created by: drose (13Mar02) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://etc.cmu.edu/panda3d/docs/license/ . -// -// To contact the maintainers of this program write to -// panda3d-general@lists.sourceforge.net . -// -//////////////////////////////////////////////////////////////////// - -#ifndef FINDAPPROXLEVEL_H -#define FINDAPPROXLEVEL_H - -#include "pandabase.h" - -#include "findApproxLevelEntry.h" -#include "pvector.h" - -//////////////////////////////////////////////////////////////////// -// Class : FindApproxLevel -// Description : This class is local to this package only; it doesn't -// get exported. It maintains the list of nodes -// find_approx() considers for each level of the scene -// graph it visits, in its breadth-first search. -//////////////////////////////////////////////////////////////////// -class FindApproxLevel { -public: - INLINE void add_entry(const FindApproxLevelEntry &entry); - - void write(ostream &out) const; - - typedef pvector Vec; - Vec _v; -}; - -#include "findApproxLevel.I" - -#endif diff --git a/panda/src/pgraph/findApproxLevelEntry.I b/panda/src/pgraph/findApproxLevelEntry.I index 45e3106dcb..017e027cc3 100644 --- a/panda/src/pgraph/findApproxLevelEntry.I +++ b/panda/src/pgraph/findApproxLevelEntry.I @@ -28,6 +28,25 @@ FindApproxLevelEntry(const WorkingNodePath &node_path, FindApproxPath &approx_pa _approx_path(approx_path) { _i = 0; + _next = NULL; + nassertv(_node_path.is_valid()); +} + +//////////////////////////////////////////////////////////////////// +// Function: FindApproxLevelEntry::Constructor +// Access: Public +// Description: This constructor is used to construct the next entry +// based on a child node of the previous entry's node. +//////////////////////////////////////////////////////////////////// +INLINE FindApproxLevelEntry:: +FindApproxLevelEntry(const FindApproxLevelEntry &parent, + PandaNode *child_node, int i, + FindApproxLevelEntry *next) : + _node_path(parent._node_path, child_node), + _i(i), + _approx_path(parent._approx_path), + _next(next) +{ nassertv(_node_path.is_valid()); } @@ -37,11 +56,12 @@ FindApproxLevelEntry(const WorkingNodePath &node_path, FindApproxPath &approx_pa // Description: //////////////////////////////////////////////////////////////////// INLINE FindApproxLevelEntry:: -FindApproxLevelEntry(const FindApproxLevelEntry ©, int increment) : +FindApproxLevelEntry(const FindApproxLevelEntry ©) : _node_path(copy._node_path), - _i(copy._i + increment), + _i(copy._i), _approx_path(copy._approx_path) { + _next = NULL; nassertv(_node_path.is_valid()); } @@ -81,3 +101,50 @@ INLINE bool FindApproxLevelEntry:: is_solution(int increment) const { return (_i + increment >= _approx_path.get_num_components()); } + +//////////////////////////////////////////////////////////////////// +// Function: FindApproxLevelEntry::operator new +// Access: Public +// Description: Allocates the memory for a new FindApproxLevelEntry. +// This is specialized here to provide for fast +// allocation of these things. +//////////////////////////////////////////////////////////////////// +INLINE void *FindApproxLevelEntry:: +operator new(size_t size) { + if (_deleted_chain != (FindApproxLevelEntry *)NULL) { + FindApproxLevelEntry *obj = _deleted_chain; + _deleted_chain = _deleted_chain->_next; + return obj; + } +#ifndef NDEBUG + _num_ever_allocated++; +#endif // NDEBUG + return ::operator new(size); +} + +//////////////////////////////////////////////////////////////////// +// Function: FindApproxLevelEntry::operator delete +// Access: Public +// Description: Frees the memory for a deleted FindApproxLevelEntry. +// This is specialized here to provide for fast +// allocation of these things. +//////////////////////////////////////////////////////////////////// +INLINE void FindApproxLevelEntry:: +operator delete(void *ptr) { + FindApproxLevelEntry *obj = (FindApproxLevelEntry *)ptr; + obj->_next = _deleted_chain; + _deleted_chain = obj; +} + +//////////////////////////////////////////////////////////////////// +// Function: FindApproxLevelEntry::get_num_ever_allocated +// Access: Published, Static +// Description: Returns the number of FindApproxLevelEntry pointers +// ever simultaneously allocated; these are now either +// in active use or have been recycled into the deleted +// FindApproxLevelEntry pool to be used again. +//////////////////////////////////////////////////////////////////// +INLINE int FindApproxLevelEntry:: +get_num_ever_allocated() { + return _num_ever_allocated; +} diff --git a/panda/src/pgraph/findApproxLevelEntry.cxx b/panda/src/pgraph/findApproxLevelEntry.cxx index 82e9eb0561..adbfc2fbda 100644 --- a/panda/src/pgraph/findApproxLevelEntry.cxx +++ b/panda/src/pgraph/findApproxLevelEntry.cxx @@ -19,6 +19,10 @@ #include "findApproxLevelEntry.h" #include "nodePathCollection.h" #include "pandaNode.h" +#include "indent.h" + +FindApproxLevelEntry *FindApproxLevelEntry::_deleted_chain = (FindApproxLevelEntry *)NULL; +int FindApproxLevelEntry::_num_ever_allocated = 0; //////////////////////////////////////////////////////////////////// @@ -40,14 +44,49 @@ output(ostream &out) const { } //////////////////////////////////////////////////////////////////// -// Function: FindApproxLevelEntry::consider_node +// Function: FindApproxLevelEntry::write_level // Access: Public -// Description: +// Description: Writes the entire level (a linked list of entries +// beginning at this entry). For debugging only. //////////////////////////////////////////////////////////////////// void FindApproxLevelEntry:: -consider_node(NodePathCollection &result, FindApproxLevel &next_level, +write_level(ostream &out, int indent_level) const { + for (const FindApproxLevelEntry *entry = this; + entry != (const FindApproxLevelEntry *)NULL; + entry = entry->_next) { + indent(out, indent_level); + out << *entry << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: FindApproxLevelEntry::consider_node +// Access: Public +// Description: Considers the node represented by the entry for +// matching the find path. If a solution is found, it +// is added to result; if the children of this node +// should be considered, the appropriate entries are +// added to next_level. +// +// The return value is true if result now contains +// max_matches solutions, or false if we should keep +// looking. +//////////////////////////////////////////////////////////////////// +bool FindApproxLevelEntry:: +consider_node(NodePathCollection &result, FindApproxLevelEntry *&next_level, int max_matches, int increment) const { - nassertv(_i + increment < _approx_path.get_num_components()); + if (is_solution(increment)) { + // If the entry represents a solution, save it and we're done with + // the entry. + result.add_path(_node_path.get_node_path()); + if (max_matches > 0 && result.get_num_paths() >= max_matches) { + return true; + } + + return false; + } + + // If the entry is not itself a solution, consider its children. if (_approx_path.is_component_match_many(_i + increment)) { // Match any number, zero or more, levels of nodes. This is the @@ -64,32 +103,24 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level, // FindApproxLevelEntry objects. Instead, we pass around the // increment parameter, which increments _i on the fly. - if (is_solution(increment + 1)) { - // Does this now represent a solution? - result.add_path(_node_path.get_node_path()); - if (max_matches > 0 && result.get_num_paths() >= max_matches) { - return; - } - } else { - consider_node(result, next_level, max_matches, increment + 1); + if (consider_node(result, next_level, max_matches, increment + 1)) { + return true; } } PandaNode *this_node = _node_path.node(); - nassertv(this_node != (PandaNode *)NULL); + nassertr(this_node != (PandaNode *)NULL, false); bool stashed_only = next_is_stashed(increment); if (!stashed_only) { // Check the normal list of children. - int num_children = this_node->get_num_children(); + PandaNode::Children children = this_node->get_children(); + int num_children = children.get_num_children(); for (int i = 0; i < num_children; i++) { - PandaNode *child_node = this_node->get_child(i); + PandaNode *child_node = children.get_child(i); - consider_next_step(result, child_node, next_level, max_matches, increment); - if (max_matches > 0 && result.get_num_paths() >= max_matches) { - return; - } + consider_next_step(child_node, next_level, increment); } } @@ -99,12 +130,11 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level, for (int i = 0; i < num_stashed; i++) { PandaNode *stashed_node = this_node->get_stashed(i); - consider_next_step(result, stashed_node, next_level, max_matches, increment); - if (max_matches > 0 && result.get_num_paths() >= max_matches) { - return; - } + consider_next_step(stashed_node, next_level, increment); } } + + return false; } //////////////////////////////////////////////////////////////////// @@ -115,12 +145,9 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level, // of the path. If it matches, generates whatever // additional entries are appropriate and stores them in // next_level. -// -// If a complete solution is found, stores it in result. //////////////////////////////////////////////////////////////////// void FindApproxLevelEntry:: -consider_next_step(NodePathCollection &result, PandaNode *child_node, - FindApproxLevel &next_level, int max_matches, +consider_next_step(PandaNode *child_node, FindApproxLevelEntry *&next_level, int increment) const { if (!_approx_path.return_hidden() && child_node->get_draw_mask().is_zero()) { @@ -139,17 +166,14 @@ consider_next_step(NodePathCollection &result, PandaNode *child_node, // And now we just add the next entry without incrementing its // path entry. - FindApproxLevelEntry next(*this, increment); - next._node_path = WorkingNodePath(_node_path, child_node); - next_level.add_entry(next); + next_level = new FindApproxLevelEntry + (*this, child_node, _i + increment, next_level); } else { if (_approx_path.matches_component(_i + increment, child_node)) { // That matched, and it consumes one path entry. - FindApproxLevelEntry next(*this, increment); - next._i++; - next._node_path = WorkingNodePath(_node_path, child_node); - next_level.add_entry(next); + next_level = new FindApproxLevelEntry + (*this, child_node, _i + increment + 1, next_level); } } } diff --git a/panda/src/pgraph/findApproxLevelEntry.h b/panda/src/pgraph/findApproxLevelEntry.h index e93e417b4d..f11dd225d0 100644 --- a/panda/src/pgraph/findApproxLevelEntry.h +++ b/panda/src/pgraph/findApproxLevelEntry.h @@ -24,7 +24,6 @@ #include "findApproxPath.h" #include "workingNodePath.h" -class FindApproxLevel; class NodePathCollection; //////////////////////////////////////////////////////////////////// @@ -38,19 +37,33 @@ class FindApproxLevelEntry { public: INLINE FindApproxLevelEntry(const WorkingNodePath &node_path, FindApproxPath &approx_path); - INLINE FindApproxLevelEntry(const FindApproxLevelEntry ©, int increment = 0); + INLINE FindApproxLevelEntry(const FindApproxLevelEntry &parent, + PandaNode *child_node, int i, + FindApproxLevelEntry *next); + INLINE FindApproxLevelEntry(const FindApproxLevelEntry ©); INLINE void operator = (const FindApproxLevelEntry ©); INLINE bool next_is_stashed(int increment) const; - void consider_node(NodePathCollection &result, FindApproxLevel &next_level, + bool consider_node(NodePathCollection &result, + FindApproxLevelEntry *&next_level, int max_matches, int increment) const; - void consider_next_step(NodePathCollection &result, - PandaNode *child_node, FindApproxLevel &next_level, - int max_matches, int increment) const; + void consider_next_step(PandaNode *child_node, + FindApproxLevelEntry *&next_level, + int increment) const; INLINE bool is_solution(int increment) const; + // We will allocate and destroy thousands of these during a typical + // NodePath::find() or find_all_matches() operation. As an + // optimization, then, we implement operator new and delete here to + // minimize this overhead. + INLINE void *operator new(size_t size); + INLINE void operator delete(void *ptr); + + INLINE static int get_num_ever_allocated(); + void output(ostream &out) const; + void write_level(ostream &out, int indent_level) const; // _node_path represents the most recent node that we have // previously accepted as being a partial solution. @@ -62,6 +75,11 @@ public: // solution. int _i; FindApproxPath &_approx_path; + FindApproxLevelEntry *_next; + +private: + static FindApproxLevelEntry *_deleted_chain; + static int _num_ever_allocated; }; INLINE ostream & diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index c046859ca2..fe36f86b6c 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -20,7 +20,6 @@ #include "nodePathCollection.h" #include "findApproxPath.h" #include "findApproxLevelEntry.h" -#include "findApproxLevel.h" #include "config_pgraph.h" #include "colorAttrib.h" #include "colorScaleAttrib.h" @@ -3701,64 +3700,97 @@ find_matches(NodePathCollection &result, FindApproxPath &approx_path, << "Attempt to extend an empty NodePath by: " << approx_path << ".\n"; return; } - FindApproxLevelEntry start(WorkingNodePath(*this), approx_path); - nassertv(start._node_path.is_valid()); - FindApproxLevel level; - level.add_entry(start); - r_find_matches(result, level, max_matches, _max_search_depth); + + // We start with just one entry on the level. + FindApproxLevelEntry *level = + new FindApproxLevelEntry(WorkingNodePath(*this), approx_path); + nassertv(level->_node_path.is_valid()); + + find_matches(result, level, max_matches); } //////////////////////////////////////////////////////////////////// -// Function: NodePath::r_find_matches +// Function: NodePath::find_matches // Access: Private -// Description: The recursive implementation of find_matches. +// Description: The fundamental implementation of find_matches(), +// given a starting level (a linked list of +// FindApproxLevelEntry objects). //////////////////////////////////////////////////////////////////// void NodePath:: -r_find_matches(NodePathCollection &result, - const FindApproxLevel &level, - int max_matches, int num_levels_remaining) const { - if (pgraph_cat.is_debug()) { - pgraph_cat.debug() - << "r_find_matches(" << result << ", level, " - << max_matches << ", " << num_levels_remaining << ")\n"; - level.write(pgraph_cat.debug(false)); - } +find_matches(NodePathCollection &result, FindApproxLevelEntry *level, + int max_matches) const { + + int num_levels_remaining = _max_search_depth; - // Go on to the next level. If we exceeded the requested maximum - // depth (or if there are no more levels to visit), stop. - if (num_levels_remaining <= 0 || level._v.empty()) { - return; - } - num_levels_remaining--; + FindApproxLevelEntry *deleted_entries = NULL; - FindApproxLevel next_level; - bool okflag = true; - - // For each node in the current level, build up the set of possible - // matches in the next level. - FindApproxLevel::Vec::const_iterator li; - for (li = level._v.begin(); li != level._v.end() && okflag; ++li) { - const FindApproxLevelEntry &entry = (*li); - - if (entry.is_solution(0)) { - // Does this entry already represent a solution? - result.add_path(entry._node_path.get_node_path()); - } else { - entry.consider_node(result, next_level, max_matches, 0); + while (num_levels_remaining > 0 && level != NULL) { + if (pgraph_cat.is_debug()) { + pgraph_cat.debug() + << "find_matches pass: " << result << ", " + << max_matches << ", " << num_levels_remaining << "\n"; + level->write_level(pgraph_cat.debug(false), 4); } - if (max_matches > 0 && result.get_num_paths() >= max_matches) { - // Really, we just want to return here. But returning from - // within the conditional within the for loop seems to sometimes - // cause a compiler fault in GCC. We'll use a semaphore - // variable instead. - okflag = false; + num_levels_remaining--; + + FindApproxLevelEntry *next_level = NULL; + + // For each node in the current level, build up the set of possible + // matches in the next level. + FindApproxLevelEntry *entry = level; + while (entry != (FindApproxLevelEntry *)NULL) { + if (entry->consider_node(result, next_level, max_matches, 0)) { + // If we found the requisite number of matches, we can stop. + // Delete all remaining entries and return immediately. + + while (entry != (FindApproxLevelEntry *)NULL) { + FindApproxLevelEntry *next = entry->_next; + delete entry; + entry = next; + } + while (next_level != (FindApproxLevelEntry *)NULL) { + FindApproxLevelEntry *next = next_level->_next; + delete next_level; + next_level = next; + } + while (deleted_entries != (FindApproxLevelEntry *)NULL) { + FindApproxLevelEntry *next = deleted_entries->_next; + delete deleted_entries; + deleted_entries = next; + } + return; + } + + // Move the entry to the delete chain so we can delete it before + // we return from this method. (We can't delete it immediately, + // because there might be WorkingNodePaths in the next_level + // that reference the WorkingNodePath object within the entry.) + FindApproxLevelEntry *next = entry->_next; + entry->_next = deleted_entries; + deleted_entries = entry; + + entry = next; } + + // Make sure the remaining entries from this level are added to + // the delete chain. + while (entry != (FindApproxLevelEntry *)NULL) { + FindApproxLevelEntry *next = entry->_next; + entry->_next = deleted_entries; + deleted_entries = entry; + + entry = next; + } + + level = next_level; } - // Now recurse on the next level. - if (okflag) { - r_find_matches(result, next_level, max_matches, num_levels_remaining); + // Now it's safe to delete all entries on the delete chain. + while (deleted_entries != (FindApproxLevelEntry *)NULL) { + FindApproxLevelEntry *next = deleted_entries->_next; + delete deleted_entries; + deleted_entries = next; } } diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 38093ec681..f64dedf24b 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -33,8 +33,8 @@ class NodePathCollection; class TextureCollection; -class FindApproxLevel; class FindApproxPath; +class FindApproxLevelEntry; class Texture; class Material; class Fog; @@ -621,9 +621,9 @@ private: void find_matches(NodePathCollection &result, FindApproxPath &approx_path, int max_matches) const; - void r_find_matches(NodePathCollection &result, - const FindApproxLevel &level, - int max_matches, int num_levels_remaining) const; + void find_matches(NodePathCollection &result, + FindApproxLevelEntry *level, + int max_matches) const; void r_adjust_all_priorities(PandaNode *node, int adjustment); diff --git a/panda/src/pgraph/nodePathCollection.cxx b/panda/src/pgraph/nodePathCollection.cxx index 438839786c..b6f5b47597 100644 --- a/panda/src/pgraph/nodePathCollection.cxx +++ b/panda/src/pgraph/nodePathCollection.cxx @@ -18,7 +18,7 @@ #include "nodePathCollection.h" #include "findApproxPath.h" -#include "findApproxLevel.h" +#include "findApproxLevelEntry.h" #include "indent.h" @@ -278,13 +278,14 @@ find_all_matches(const string &path) const { FindApproxPath approx_path; if (approx_path.add_string(path)) { if (!is_empty()) { - FindApproxLevel level; + FindApproxLevelEntry *level = NULL; for (int i = 0; i < get_num_paths(); i++) { - FindApproxLevelEntry start(get_path(i), approx_path); - level.add_entry(start); + FindApproxLevelEntry *start = + new FindApproxLevelEntry(get_path(i), approx_path); + start->_next = level; + level = start; } - get_path(0).r_find_matches(result, level, -1, - NodePath::get_max_search_depth()); + get_path(0).find_matches(result, level, -1); } } diff --git a/panda/src/pgraph/pgraph_composite1.cxx b/panda/src/pgraph/pgraph_composite1.cxx index c9d0af3ae8..bdd20fccfd 100644 --- a/panda/src/pgraph/pgraph_composite1.cxx +++ b/panda/src/pgraph/pgraph_composite1.cxx @@ -32,7 +32,6 @@ #include "directionalLight.cxx" #include "drawCullHandler.cxx" #include "findApproxPath.cxx" -#include "findApproxLevel.cxx" #include "findApproxLevelEntry.cxx" #include "fog.cxx" #include "fogAttrib.cxx" diff --git a/panda/src/pgraph/test_pgraph.cxx b/panda/src/pgraph/test_pgraph.cxx index f4700e9128..53a28cb84e 100644 --- a/panda/src/pgraph/test_pgraph.cxx +++ b/panda/src/pgraph/test_pgraph.cxx @@ -18,21 +18,61 @@ #include "pandaNode.h" #include "nodePath.h" +#include "nodePathCollection.h" +#include "findApproxLevelEntry.h" +#include "clockObject.h" + +NodePath +build_tree(const string &name, int depth) { + NodePath node(name); + if (depth > 1) { + for (int i = 0; i < 3; i++) { + char letter = 'a' + i; + string child_name = name + string(1, letter); + NodePath child = build_tree(child_name, depth - 1); + child.reparent_to(node); + } + } + + return node; +} int main(int argc, char *argv[]) { - NodePath h("h"); - NodePath n1("n1"); - NodePath n2("n2"); - PT(PandaNode) node = new PandaNode("node"); + // Build up a tree of height 6. Each level has three children, so + // that there are 3^5 + 3^4 + 3^3 + 3^2 + 3^1 + 3^0 = 364 total nodes. - NodePath t1 = h.attach_new_node(node); - t1.reparent_to(n1); + NodePath root = build_tree("a", 6); - t1 = NodePath(); + NodePath abba = root.find("**/abba"); + cerr << abba << "\n"; + cerr << "entries allocated: " << FindApproxLevelEntry::get_num_ever_allocated() << "\n"; + + NodePath abaab = root.find("ab/aba/abaa/abaab"); + cerr << abaab << "\n"; + cerr << "entries allocated: " << FindApproxLevelEntry::get_num_ever_allocated() << "\n"; + + NodePathCollection col = root.find_all_matches("**"); + cerr << col << "\n"; + cerr << "entries allocated: " << FindApproxLevelEntry::get_num_ever_allocated() << "\n"; + + // Now time a bunch of find operations. + ClockObject *clock = ClockObject::get_global_clock(); + static const int num_ops = 10000; + + volatile double start, end; + { + start = clock->get_real_time(); + for (int i = 0; i < num_ops; i++) { + root.find_all_matches("**/aabca"); + } + end = clock->get_real_time(); + } + + double avg_time = (end - start) / (double)num_ops; + cerr << "Find operation took " << avg_time * 1000 << " ms\n"; + cerr << "entries allocated: " << FindApproxLevelEntry::get_num_ever_allocated() << "\n"; - NodePath t2 = h.attach_new_node(node); - t2.reparent_to(n2); return 0; }