Further NodePath::find() optimizations
This commit is contained in:
parent
1898df8d54
commit
90bf34ddcf
|
|
@ -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 \
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
@ -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<FindApproxLevelEntry> Vec;
|
||||
Vec _v;
|
||||
};
|
||||
|
||||
#include "findApproxLevel.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 &
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue