mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
reduce overhead on NodePath::find() operations
This commit is contained in:
parent
c231386f16
commit
5c48c68569
@ -23,11 +23,12 @@
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE FindApproxLevelEntry::
|
||||
FindApproxLevelEntry(const NodePath &node_path, FindApproxPath &approx_path) :
|
||||
FindApproxLevelEntry(const WorkingNodePath &node_path, FindApproxPath &approx_path) :
|
||||
_node_path(node_path),
|
||||
_approx_path(approx_path)
|
||||
{
|
||||
_i = 0;
|
||||
nassertv(_node_path.is_valid());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -36,11 +37,12 @@ FindApproxLevelEntry(const NodePath &node_path, FindApproxPath &approx_path) :
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE FindApproxLevelEntry::
|
||||
FindApproxLevelEntry(const FindApproxLevelEntry ©) :
|
||||
FindApproxLevelEntry(const FindApproxLevelEntry ©, int increment) :
|
||||
_node_path(copy._node_path),
|
||||
_i(copy._i),
|
||||
_i(copy._i + increment),
|
||||
_approx_path(copy._approx_path)
|
||||
{
|
||||
nassertv(_node_path.is_valid());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -53,6 +55,7 @@ operator = (const FindApproxLevelEntry ©) {
|
||||
_node_path = copy._node_path;
|
||||
_i = copy._i;
|
||||
nassertv(&_approx_path == ©._approx_path);
|
||||
nassertv(_node_path.is_valid());
|
||||
}
|
||||
|
||||
|
||||
@ -63,8 +66,8 @@ operator = (const FindApproxLevelEntry ©) {
|
||||
// must be a stashed node, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool FindApproxLevelEntry::
|
||||
next_is_stashed() const {
|
||||
return _approx_path.matches_stashed(_i);
|
||||
next_is_stashed(int increment) const {
|
||||
return _approx_path.matches_stashed(_i + increment);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -75,6 +78,6 @@ next_is_stashed() const {
|
||||
// been successfully matched.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool FindApproxLevelEntry::
|
||||
is_solution() const {
|
||||
return (_i >= _approx_path.get_num_components());
|
||||
is_solution(int increment) const {
|
||||
return (_i + increment >= _approx_path.get_num_components());
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
void FindApproxLevelEntry::
|
||||
output(ostream &out) const {
|
||||
out << "(" << _node_path << "):";
|
||||
if (is_solution()) {
|
||||
if (is_solution(0)) {
|
||||
out << " solution!";
|
||||
} else {
|
||||
out << "(";
|
||||
@ -46,34 +46,39 @@ output(ostream &out) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FindApproxLevelEntry::
|
||||
consider_node(NodePathCollection &result, FindApproxLevel &next_level,
|
||||
int max_matches) const {
|
||||
nassertv(_i < _approx_path.get_num_components());
|
||||
int max_matches, int increment) const {
|
||||
nassertv(_i + increment < _approx_path.get_num_components());
|
||||
|
||||
if (_approx_path.is_component_match_many(_i)) {
|
||||
if (_approx_path.is_component_match_many(_i + increment)) {
|
||||
// Match any number, zero or more, levels of nodes. This is the
|
||||
// tricky case that requires this whole nutty breadth-first thing.
|
||||
|
||||
// This means we must reconsider our own entry with the next path
|
||||
// entry, before we consider the next entry--this supports
|
||||
// matching zero levels of nodes.
|
||||
FindApproxLevelEntry reconsider(*this);
|
||||
++reconsider._i;
|
||||
|
||||
if (reconsider.is_solution()) {
|
||||
// We used to make a temporary copy of our own record, and then
|
||||
// increment _i on that copy, but we can't do that nowadays
|
||||
// because the WorkingNodePath object stores a pointer to each
|
||||
// previous generation, which means we can't use any temporary
|
||||
// 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(reconsider._node_path);
|
||||
result.add_path(_node_path.get_node_path());
|
||||
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
reconsider.consider_node(result, next_level, max_matches);
|
||||
consider_node(result, next_level, max_matches, increment + 1);
|
||||
}
|
||||
}
|
||||
|
||||
PandaNode *this_node = _node_path.node();
|
||||
nassertv(this_node != (PandaNode *)NULL);
|
||||
|
||||
bool stashed_only = next_is_stashed();
|
||||
bool stashed_only = next_is_stashed(increment);
|
||||
|
||||
if (!stashed_only) {
|
||||
// Check the normal list of children.
|
||||
@ -81,7 +86,7 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
PandaNode *child_node = this_node->get_child(i);
|
||||
|
||||
consider_next_step(result, child_node, next_level, max_matches);
|
||||
consider_next_step(result, child_node, next_level, max_matches, increment);
|
||||
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
|
||||
return;
|
||||
}
|
||||
@ -94,7 +99,7 @@ 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);
|
||||
consider_next_step(result, stashed_node, next_level, max_matches, increment);
|
||||
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
|
||||
return;
|
||||
}
|
||||
@ -115,7 +120,8 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FindApproxLevelEntry::
|
||||
consider_next_step(NodePathCollection &result, PandaNode *child_node,
|
||||
FindApproxLevel &next_level, int max_matches) const {
|
||||
FindApproxLevel &next_level, int max_matches,
|
||||
int increment) const {
|
||||
if (!_approx_path.return_hidden() &&
|
||||
child_node->get_draw_mask().is_zero()) {
|
||||
// If the approx path does not allow us to return hidden nodes,
|
||||
@ -124,25 +130,25 @@ consider_next_step(NodePathCollection &result, PandaNode *child_node,
|
||||
return;
|
||||
}
|
||||
|
||||
nassertv(_i < _approx_path.get_num_components());
|
||||
nassertv(_i + increment < _approx_path.get_num_components());
|
||||
|
||||
if (_approx_path.is_component_match_many(_i)) {
|
||||
if (_approx_path.is_component_match_many(_i + increment)) {
|
||||
// Match any number, zero or more, levels of nodes. This is the
|
||||
// tricky case that requires this whole nutty breadth-first thing.
|
||||
|
||||
// And now we just add the next entry without incrementing its
|
||||
// path entry.
|
||||
|
||||
FindApproxLevelEntry next(*this);
|
||||
next._node_path = NodePath(_node_path, child_node);
|
||||
FindApproxLevelEntry next(*this, increment);
|
||||
next._node_path = WorkingNodePath(_node_path, child_node);
|
||||
next_level.add_entry(next);
|
||||
|
||||
} else {
|
||||
if (_approx_path.matches_component(_i, child_node)) {
|
||||
if (_approx_path.matches_component(_i + increment, child_node)) {
|
||||
// That matched, and it consumes one path entry.
|
||||
FindApproxLevelEntry next(*this);
|
||||
++next._i;
|
||||
next._node_path = NodePath(_node_path, child_node);
|
||||
FindApproxLevelEntry next(*this, increment);
|
||||
next._i++;
|
||||
next._node_path = WorkingNodePath(_node_path, child_node);
|
||||
next_level.add_entry(next);
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "findApproxPath.h"
|
||||
#include "nodePath.h"
|
||||
#include "workingNodePath.h"
|
||||
|
||||
class FindApproxLevel;
|
||||
class NodePathCollection;
|
||||
@ -36,25 +36,25 @@ class NodePathCollection;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class FindApproxLevelEntry {
|
||||
public:
|
||||
INLINE FindApproxLevelEntry(const NodePath &node_path,
|
||||
INLINE FindApproxLevelEntry(const WorkingNodePath &node_path,
|
||||
FindApproxPath &approx_path);
|
||||
INLINE FindApproxLevelEntry(const FindApproxLevelEntry ©);
|
||||
INLINE FindApproxLevelEntry(const FindApproxLevelEntry ©, int increment = 0);
|
||||
INLINE void operator = (const FindApproxLevelEntry ©);
|
||||
|
||||
INLINE bool next_is_stashed() const;
|
||||
INLINE bool next_is_stashed(int increment) const;
|
||||
|
||||
void consider_node(NodePathCollection &result, FindApproxLevel &next_level,
|
||||
int max_matches) const;
|
||||
int max_matches, int increment) const;
|
||||
void consider_next_step(NodePathCollection &result,
|
||||
PandaNode *child_node, FindApproxLevel &next_level,
|
||||
int max_matches) const;
|
||||
INLINE bool is_solution() const;
|
||||
int max_matches, int increment) const;
|
||||
INLINE bool is_solution(int increment) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
// _node_path represents the most recent node that we have
|
||||
// previously accepted as being a partial solution.
|
||||
NodePath _node_path;
|
||||
WorkingNodePath _node_path;
|
||||
|
||||
// _i represents the next component in the approx_path that must be
|
||||
// matched against all of the children of _node_path, above. If _i
|
||||
|
@ -3083,7 +3083,8 @@ find_matches(NodePathCollection &result, FindApproxPath &approx_path,
|
||||
<< "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
|
||||
return;
|
||||
}
|
||||
FindApproxLevelEntry start(*this, approx_path);
|
||||
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);
|
||||
@ -3114,11 +3115,11 @@ r_find_matches(NodePathCollection &result,
|
||||
for (li = level._v.begin(); li != level._v.end() && okflag; ++li) {
|
||||
const FindApproxLevelEntry &entry = (*li);
|
||||
|
||||
if (entry.is_solution()) {
|
||||
if (entry.is_solution(0)) {
|
||||
// Does this entry already represent a solution?
|
||||
result.add_path(entry._node_path);
|
||||
result.add_path(entry._node_path.get_node_path());
|
||||
} else {
|
||||
entry.consider_node(result, next_level, max_matches);
|
||||
entry.consider_node(result, next_level, max_matches, 0);
|
||||
}
|
||||
|
||||
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
|
||||
|
@ -33,6 +33,21 @@ WorkingNodePath(const NodePath &start) {
|
||||
_node = start.node();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE WorkingNodePath::
|
||||
WorkingNodePath(const WorkingNodePath ©) :
|
||||
_next(copy._next),
|
||||
_start(copy._start),
|
||||
_node(copy._node)
|
||||
{
|
||||
nassertv(_next != (WorkingNodePath *)NULL ||
|
||||
_start != (NodePathComponent *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::Constructor
|
||||
// Access: Public
|
||||
@ -57,6 +72,21 @@ INLINE WorkingNodePath::
|
||||
~WorkingNodePath() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void WorkingNodePath::
|
||||
operator = (const WorkingNodePath ©) {
|
||||
_next = copy._next;
|
||||
_start = copy._start;
|
||||
_node = copy._node;
|
||||
|
||||
nassertv(_next != (WorkingNodePath *)NULL ||
|
||||
_start != (NodePathComponent *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::get_node_path
|
||||
// Access: Public
|
||||
@ -80,3 +110,9 @@ INLINE PandaNode *WorkingNodePath::
|
||||
node() const {
|
||||
return _node;
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const WorkingNodePath &node_path) {
|
||||
node_path.output(out);
|
||||
return out;
|
||||
}
|
||||
|
@ -19,9 +19,27 @@
|
||||
#include "workingNodePath.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::is_valid
|
||||
// Access: Public
|
||||
// Description: Returns true if the WorkingNodePath object appears to
|
||||
// be a valid NodePath reference, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool WorkingNodePath::
|
||||
is_valid() const {
|
||||
if (_node == (PandaNode *)NULL) {
|
||||
return false;
|
||||
}
|
||||
if (_next == (WorkingNodePath *)NULL) {
|
||||
return (_start != (NodePathComponent *)NULL);
|
||||
}
|
||||
|
||||
return _next->is_valid();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::get_num_nodes
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description: Returns the number of nodes in the path from the root
|
||||
// to the current node.
|
||||
//
|
||||
@ -40,7 +58,7 @@ get_num_nodes() const {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::get_node
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description: Returns the nth node of the path, where 0 is the
|
||||
// referenced (bottom) node and get_num_nodes() - 1 is
|
||||
// the top node. This requires iterating through the
|
||||
@ -60,6 +78,18 @@ get_node(int index) const {
|
||||
return _next->get_node(index - 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void WorkingNodePath::
|
||||
output(ostream &out) const {
|
||||
// Cheesy and slow, but when you're outputting the thing, presumably
|
||||
// you're not in a hurry.
|
||||
get_node_path().output(out);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WorkingNodePath::r_get_node_path
|
||||
// Access: Private
|
||||
@ -70,6 +100,7 @@ get_node(int index) const {
|
||||
PT(NodePathComponent) WorkingNodePath::
|
||||
r_get_node_path() const {
|
||||
if (_next == (WorkingNodePath *)NULL) {
|
||||
nassertr(_start != (NodePathComponent *)NULL, NULL);
|
||||
return _start;
|
||||
}
|
||||
|
||||
@ -78,5 +109,8 @@ r_get_node_path() const {
|
||||
|
||||
PT(NodePathComponent) comp = _next->r_get_node_path();
|
||||
nassertr(comp != (NodePathComponent *)NULL, NULL);
|
||||
return PandaNode::get_component(comp, _node);
|
||||
|
||||
PT(NodePathComponent) result = PandaNode::get_component(comp, _node);
|
||||
nassertr(result != (NodePathComponent *)NULL, NULL);
|
||||
return result;
|
||||
}
|
||||
|
@ -49,15 +49,22 @@
|
||||
class EXPCL_PANDA WorkingNodePath {
|
||||
public:
|
||||
INLINE WorkingNodePath(const NodePath &start);
|
||||
INLINE WorkingNodePath(const WorkingNodePath ©);
|
||||
INLINE WorkingNodePath(const WorkingNodePath &parent, PandaNode *child);
|
||||
INLINE ~WorkingNodePath();
|
||||
|
||||
INLINE void operator = (const WorkingNodePath ©);
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
INLINE NodePath get_node_path() const;
|
||||
INLINE PandaNode *node() const;
|
||||
|
||||
int get_num_nodes() const;
|
||||
PandaNode *get_node(int index) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
PT(NodePathComponent) r_get_node_path() const;
|
||||
|
||||
@ -70,6 +77,8 @@ private:
|
||||
PandaNode *_node;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const WorkingNodePath &node_path);
|
||||
|
||||
#include "workingNodePath.I"
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user