pgraph find

This commit is contained in:
David Rose 2002-03-13 18:45:51 +00:00
parent fc26653ada
commit adfa89b233
17 changed files with 1364 additions and 24 deletions

View File

@ -314,8 +314,6 @@ class ShowBase:
per application.
"""
print 'setup mouse'
# We create both a MouseAndKeyboard object and a MouseWatcher object
# for the window. The MouseAndKeyboard generates mouse events and
# mouse button/keyboard events; the MouseWatcher passes them through
@ -341,7 +339,12 @@ class ShowBase:
self.drive = self.dataUnused.attachNewNode(DriveInterface('drive'))
self.mouse2cam = self.dataUnused.attachNewNode(Transform2SG('mouse2cam'))
self.mouse2cam.node().setNode(self.camera.node())
self.useDrive()
# The default is trackball mode, which is more convenient for
# ad-hoc development in Python using ShowBase. Applications
# can expclitly call base.useDrive() if they prefer a drive
# interface.
self.useTrackball()
# A ButtonThrower to generate events from the mouse and
# keyboard buttons as they are pressed.
@ -386,8 +389,7 @@ class ShowBase:
# one.
for i in range(chanConfig.getNumGroups()):
camera = self.camera.attachNewNode(chanConfig.getGroupNode(i))
#cam = camera.find('**/+Camera')
cam = camera.getChild(0)
cam = camera.find('**/+Camera')
lens = cam.node().getLens()
# Enforce our expected aspect ratio, overriding whatever

View File

@ -244,6 +244,7 @@ reconnect() {
int num_parents = get_num_parents();
_data_connections.clear();
// Look for each input among one of the parents.
int num_datanode_parents = 0;
Wires::const_iterator wi;
for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) {
@ -255,6 +256,7 @@ reconnect() {
PandaNode *parent_node = get_parent(i);
if (parent_node->is_of_type(qpDataNode::get_class_type())) {
qpDataNode *data_node = DCAST(qpDataNode, parent_node);
num_datanode_parents++;
Wires::const_iterator pi;
pi = data_node->_output_wires.find(name);
if (pi != data_node->_output_wires.end()) {
@ -282,7 +284,8 @@ reconnect() {
}
}
if (_data_connections.empty() && get_num_inputs() != 0 && num_parents != 0) {
if (_data_connections.empty() && get_num_inputs() != 0 &&
num_datanode_parents != 0) {
dgraph_cat.warning()
<< "No data connected to " << *this << "\n";
}

View File

@ -27,6 +27,9 @@
depthTestAttrib.h depthTestAttrib.I \
depthWriteAttrib.h depthWriteAttrib.I \
drawCullHandler.h drawCullHandler.I \
qpfindApproxLevel.I qpfindApproxLevel.h \
qpfindApproxLevelEntry.I qpfindApproxLevelEntry.h \
qpfindApproxPath.I qpfindApproxPath.h \
qpgeomNode.h qpgeomNode.I \
qplensNode.h qplensNode.I \
qplodNode.h qplodNode.I \
@ -67,6 +70,9 @@
depthTestAttrib.cxx \
depthWriteAttrib.cxx \
drawCullHandler.cxx \
qpfindApproxLevel.cxx \
qpfindApproxLevelEntry.cxx \
qpfindApproxPath.cxx \
qpgeomNode.cxx \
qplensNode.cxx \
qplodNode.cxx \
@ -129,6 +135,11 @@
transformState.h transformState.I \
transparencyAttrib.h transparencyAttrib.I
// No need to install these.
// qpfindApproxLevel.I qpfindApproxLevel.h \
// qpfindApproxLevelEntry.I qpfindApproxLevelEntry.h \
// qpfindApproxPath.I qpfindApproxPath.h \
#define IGATESCAN all
#end lib_target

View File

@ -1380,7 +1380,7 @@ fix_path_lengths(const CData *cdata) {
////////////////////////////////////////////////////////////////////
void PandaNode::
r_list_descendants(ostream &out, int indent_level) const {
write(out, indent_level);
indent(out, indent_level) << *this << "\n";
CDReader cdata(_cycler);
Down::const_iterator di;

View File

@ -2,6 +2,9 @@
#include "depthTestAttrib.cxx"
#include "depthWriteAttrib.cxx"
#include "drawCullHandler.cxx"
#include "qpfindApproxPath.cxx"
#include "qpfindApproxLevel.cxx"
#include "qpfindApproxLevelEntry.cxx"
#include "qpgeomNode.cxx"
#include "qplensNode.cxx"
#include "qplodNode.cxx"

View File

@ -0,0 +1,29 @@
// Filename: qpfindApproxLevel.I
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevel::add_entry
// Access: Public
// Description: Adds a new entry to the level.
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxLevel::
add_entry(const qpFindApproxLevelEntry &entry) {
_v.push_back(entry);
}

View File

@ -0,0 +1,34 @@
// Filename: qpfindApproxLevel.cxx
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qpfindApproxLevel.h"
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevel::write
// Access: Public
// Description: Shows the entire contents of the level, one entry per
// line. For debugging only.
////////////////////////////////////////////////////////////////////
void qpFindApproxLevel::
write(ostream &out) const {
Vec::const_iterator vi;
for (vi = _v.begin(); vi != _v.end(); ++vi) {
(*vi).output(out);
out << "\n";
}
}

View File

@ -0,0 +1,46 @@
// Filename: qpfindApproxLevel.h
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpFINDAPPROXLEVEL_H
#define qpFINDAPPROXLEVEL_H
#include "pandabase.h"
#include "qpfindApproxLevelEntry.h"
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : qpFindApproxLevel
// 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 qpFindApproxLevel {
public:
INLINE void add_entry(const qpFindApproxLevelEntry &entry);
void write(ostream &out) const;
typedef pvector<qpFindApproxLevelEntry> Vec;
Vec _v;
};
#include "qpfindApproxLevel.I"
#endif

View File

@ -0,0 +1,80 @@
// Filename: qpfindApproxLevelEntry.I
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevelEntry::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpFindApproxLevelEntry::
qpFindApproxLevelEntry(const qpNodePath &node_path, qpFindApproxPath &approx_path) :
_node_path(node_path),
_approx_path(approx_path)
{
_i = 0;
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevelEntry::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpFindApproxLevelEntry::
qpFindApproxLevelEntry(const qpFindApproxLevelEntry &copy) :
_node_path(copy._node_path),
_i(copy._i),
_approx_path(copy._approx_path)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevelEntry::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxLevelEntry::
operator = (const qpFindApproxLevelEntry &copy) {
_node_path = copy._node_path;
_i = copy._i;
nassertv(&_approx_path == &copy._approx_path);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevelEntry::next_is_stashed
// Access: Public
// Description: Returns true if the next node matched by this entry
// must be a stashed node, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool qpFindApproxLevelEntry::
next_is_stashed() const {
return _approx_path.matches_stashed(_i);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevelEntry::is_solution
// Access: Public
// Description: Returns true if this entry represents a solution to
// the search; i.e. all the components of the path have
// been successfully matched.
////////////////////////////////////////////////////////////////////
INLINE bool qpFindApproxLevelEntry::
is_solution() const {
return (_i >= _approx_path.get_num_components());
}

View File

@ -0,0 +1,149 @@
// Filename: qpfindApproxLevelEntry.cxx
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qpfindApproxLevelEntry.h"
#include "qpnodePathCollection.h"
#include "pandaNode.h"
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevelEntry::output
// Access: Public
// Description: Formats the entry for meaningful output. For
// debugging only.
////////////////////////////////////////////////////////////////////
void qpFindApproxLevelEntry::
output(ostream &out) const {
out << "(" << _node_path << "):";
if (is_solution()) {
out << " solution!";
} else {
out << "(";
_approx_path.output_component(out, _i);
out << ")," << _i;
}
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevelEntry::consider_node
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void qpFindApproxLevelEntry::
consider_node(qpNodePathCollection &result, qpFindApproxLevel &next_level,
int max_matches) const {
nassertv(_i < _approx_path.get_num_components());
if (_approx_path.is_component_match_many(_i)) {
// 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.
qpFindApproxLevelEntry reconsider(*this);
++reconsider._i;
if (reconsider.is_solution()) {
// Does this now represent a solution?
result.add_path(reconsider._node_path);
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return;
}
} else {
reconsider.consider_node(result, next_level, max_matches);
}
}
PandaNode *this_node = _node_path.node();
nassertv(this_node != (PandaNode *)NULL);
bool stashed_only = next_is_stashed();
if (!stashed_only) {
// Check the normal list of children.
int num_children = this_node->get_num_children();
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);
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return;
}
}
}
if (_approx_path.return_stashed() || stashed_only) {
// Also check the stashed list.
int num_stashed = this_node->get_num_stashed();
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);
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return;
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxLevelEntry::consider_next_step
// Access: Public
// Description: Compares the indicated child node (which is assumed
// to be a child of _node_path) with the next component
// 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 qpFindApproxLevelEntry::
consider_next_step(qpNodePathCollection &result, PandaNode *child_node,
qpFindApproxLevel &next_level, int max_matches) 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,
// and this node has indeed been completely hidden, then stop
// here.
return;
}
nassertv(_i < _approx_path.get_num_components());
if (_approx_path.is_component_match_many(_i)) {
// 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.
qpFindApproxLevelEntry next(*this);
next._node_path = qpNodePath(_node_path, child_node);
next_level.add_entry(next);
} else {
if (_approx_path.matches_component(_i, child_node)) {
// That matched, and it consumes one path entry.
qpFindApproxLevelEntry next(*this);
++next._i;
next._node_path = qpNodePath(_node_path, child_node);
next_level.add_entry(next);
}
}
}

View File

@ -0,0 +1,75 @@
// Filename: qpfindApproxLevelEntry.h
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpFINDAPPROXLEVELENTRY_H
#define qpFINDAPPROXLEVELENTRY_H
#include "pandabase.h"
#include "qpfindApproxPath.h"
#include "qpnodePath.h"
class qpFindApproxLevel;
class qpNodePathCollection;
////////////////////////////////////////////////////////////////////
// Class : qpFindApproxLevelEntry
// Description : This class is local to this package only; it doesn't
// get exported. It represents a single node under
// consideration for matching at a single point in the
// breadth-first search.
////////////////////////////////////////////////////////////////////
class qpFindApproxLevelEntry {
public:
INLINE qpFindApproxLevelEntry(const qpNodePath &node_path,
qpFindApproxPath &approx_path);
INLINE qpFindApproxLevelEntry(const qpFindApproxLevelEntry &copy);
INLINE void operator = (const qpFindApproxLevelEntry &copy);
INLINE bool next_is_stashed() const;
void consider_node(qpNodePathCollection &result, qpFindApproxLevel &next_level,
int max_matches) const;
void consider_next_step(qpNodePathCollection &result,
PandaNode *child_node, qpFindApproxLevel &next_level,
int max_matches) const;
INLINE bool is_solution() const;
void output(ostream &out) const;
// _node_path represents the most recent node that we have
// previously accepted as being a partial solution.
qpNodePath _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
// refers to the end of the approx_path, then _node_path is a
// solution.
int _i;
qpFindApproxPath &_approx_path;
};
INLINE ostream &
operator << (ostream &out, const qpFindApproxLevelEntry &entry) {
entry.output(out);
return out;
}
#include "qpfindApproxLevelEntry.I"
#endif

View File

@ -0,0 +1,216 @@
// Filename: qpfindApproxPath.I
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpFindApproxPath::
qpFindApproxPath() {
_return_hidden = true;
_return_stashed = false;
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_match_name
// Access: Public
// Description: Adds a component that must match the name of a node
// exactly.
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxPath::
add_match_name(const string &name, int flags) {
Component comp;
comp._type = CT_match_name;
comp._name = name;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_match_name_glob
// Access: Public
// Description: Adds a component that must match the name of a node
// using standard shell globbing rules, with wildcard
// characters accepted.
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxPath::
add_match_name_glob(const string &name, int flags) {
Component comp;
comp._type = CT_match_name_glob;
comp._name = name;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_match_exact_type
// Access: Public
// Description: Adds a component that must match the type of a node
// exactly, with no derived types matching.
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxPath::
add_match_exact_type(TypeHandle type, int flags) {
Component comp;
comp._type = CT_match_exact_type;
comp._type_handle = type;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_match_inexact_type
// Access: Public
// Description: Adds a component that must match the type of a node
// or be a base class of the node's type.
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxPath::
add_match_inexact_type(TypeHandle type, int flags) {
Component comp;
comp._type = CT_match_inexact_type;
comp._type_handle = type;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_match_one
// Access: Public
// Description: Adds a component that will match any node (but not a
// chain of many nodes).
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxPath::
add_match_one(int flags) {
Component comp;
comp._type = CT_match_one;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_match_many
// Access: Public
// Description: Adds a component that will match a chain of zero or
// more consecutive nodes.
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxPath::
add_match_many(int flags) {
Component comp;
comp._type = CT_match_many;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_match_pointer
// Access: Public
// Description: Adds a component that must match a particular node
// exactly, by pointer.
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxPath::
add_match_pointer(PandaNode *pointer, int flags) {
Component comp;
comp._type = CT_match_pointer;
comp._pointer = pointer;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::get_num_components
// Access: Public
// Description: Returns the number of components in the path.
////////////////////////////////////////////////////////////////////
INLINE int qpFindApproxPath::
get_num_components() const {
return _path.size();
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::is_component_match_many
// Access: Public
// Description: Returns true if the nth component is of type
// match_many, which will require special handling.
////////////////////////////////////////////////////////////////////
INLINE bool qpFindApproxPath::
is_component_match_many(int index) const {
nassertr(index >= 0 && index < (int)_path.size(), false);
return (_path[index]._type == CT_match_many);
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::matches_component
// Access: Public
// Description: Returns true if the nth component of the path matches
// the indicated node, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool qpFindApproxPath::
matches_component(int index, PandaNode *node) const {
nassertr(index >= 0 && index < (int)_path.size(), false);
return (_path[index].matches(node));
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::matches_stashed
// Access: Public
// Description: Returns true if the nth component of the path matches
// a stashed node only, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool qpFindApproxPath::
matches_stashed(int index) const {
if (index >= 0 && index < (int)_path.size()) {
return ((_path[index]._flags & CF_stashed) != 0);
} else {
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::return_hidden
// Access: Public
// Description: Returns true if this path allows returning of hidden
// nodes, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool qpFindApproxPath::
return_hidden() const {
return _return_hidden;
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::return_stashed
// Access: Public
// Description: Returns true if this path allows returning of stashed
// nodes, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool qpFindApproxPath::
return_stashed() const {
return _return_stashed;
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::output_component
// Access: Public
// Description: Formats the nth component of the path to the
// indicated output stream.
////////////////////////////////////////////////////////////////////
INLINE void qpFindApproxPath::
output_component(ostream &out, int index) const {
nassertv(index >= 0 && index < (int)_path.size());
out << _path[index];
}

View File

@ -0,0 +1,306 @@
// Filename: qpfindApproxPath.cxx
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qpfindApproxPath.h"
#include "config_pgraph.h"
#include "globPattern.h"
#include "pandaNode.h"
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::Component::matches
// Access: Public
// Description: Returns true if the indicated node matches this
// component, false otherwise.
////////////////////////////////////////////////////////////////////
bool qpFindApproxPath::Component::
matches(PandaNode *node) const {
string node_name;
switch (_type) {
case CT_match_name:
// Match the node's name exactly.
return (_name == node->get_name());
case CT_match_name_glob:
// Match the node's name according to filename globbing rules.
{
GlobPattern pattern(_name);
return (pattern.matches(node->get_name()));
}
case CT_match_exact_type:
// Match the node's type exactly.
return (node->is_exact_type(_type_handle));
case CT_match_inexact_type:
// Match the node's type inexactly: it's a match if the node
// is the type, or is derived from the type.
return (node->is_of_type(_type_handle));
case CT_match_one:
case CT_match_many:
// Match any node.
return true;
case CT_match_pointer:
// Match only this one particular node.
return (_pointer == node);
}
pgraph_cat.error()
<< "Invalid component in qpFindApproxPath\n";
return false;
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::Component::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void qpFindApproxPath::Component::
output(ostream &out) const {
out << _type;
if (_type == CT_match_name || _type == CT_match_name_glob) {
out << " \"" << _name << "\"";
} else if (_type == CT_match_exact_type || _type == CT_match_inexact_type) {
out << " " << _type_handle;
} else if (_type == CT_match_pointer) {
out << " (" << *_pointer << ")";
}
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_string
// Access: Public
// Description: Adds a sequence of components separated by slashes,
// followed optionally by a semicolon and a sequence of
// control flags, to the path sequence. Returns true if
// successful, false if the string contained an error.
////////////////////////////////////////////////////////////////////
bool qpFindApproxPath::
add_string(const string &str_path) {
size_t start = 0;
size_t slash = str_path.find('/');
while (slash != string::npos) {
if (!add_component(str_path.substr(start, slash - start))) {
return false;
}
start = slash + 1;
slash = str_path.find('/', start);
}
size_t semicolon = str_path.rfind(';');
// We want to find the *last* semicolon at start or later, if there
// happens to be more than one. rfind will find the rightmost
// semicolon in the entire string; if this is less than start, there
// is no semicolon right of start.
if (semicolon < start) {
semicolon = string::npos;
}
if (!add_component(str_path.substr(start, semicolon - start))) {
return false;
}
if (semicolon != string::npos) {
return add_flags(str_path.substr(semicolon + 1));
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_flags
// Access: Public
// Description: Adds a sequence of control flags. This will be a
// sequence of letters preceded by either '+' or '-',
// with no intervening punctuation. Returns true if
// successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool qpFindApproxPath::
add_flags(const string &str_flags) {
string::const_iterator pi = str_flags.begin();
while (pi != str_flags.end()) {
bool on;
switch (*pi) {
case '+':
on = true;
break;
case '-':
on = false;
break;
default:
pgraph_cat.error()
<< "Invalid control flag string: " << str_flags << "\n";
return false;
}
++pi;
if (pi == str_flags.end()) {
pgraph_cat.error()
<< "Invalid control flag string: " << str_flags << "\n";
return false;
}
switch (*pi) {
case 'h':
_return_hidden = on;
break;
case 's':
_return_stashed = on;
break;
default:
pgraph_cat.error()
<< "Invalid control flag string: " << str_flags << "\n";
return false;
}
++pi;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::add_component
// Access: Public
// Description: Adds a single component to the path sequence, defined
// by a string as might appear between slashes in the
// path string. Returns true if successful, false if
// the string component was in some way invalid.
////////////////////////////////////////////////////////////////////
bool qpFindApproxPath::
add_component(string str_component) {
int flags = 0;
if (str_component.size() >= 2 && str_component.substr(0, 2) == "@@") {
flags |= CF_stashed;
str_component = str_component.substr(2);
}
if (str_component == "*") {
add_match_one(flags);
} else if (str_component == "**") {
if ((flags & CF_stashed) != 0) {
pgraph_cat.error()
<< "@@** is undefined; use @@*/** or **/@@* instead.\n";
return false;
}
add_match_many(flags);
} else if (!str_component.empty() && str_component[0] == '-') {
string type_name = str_component.substr(1);
// *** for now, as a quick hack, if a type exists with the "qp"
// prefix on the named type, we search for that type instead.
TypeHandle handle = TypeRegistry::ptr()->find_type("qp" + type_name);
if (handle == TypeHandle::none()) {
handle = TypeRegistry::ptr()->find_type(type_name);
}
if (handle == TypeHandle::none()) {
pgraph_cat.error()
<< "Invalid type name: " + type_name;
return false;
} else {
add_match_exact_type(handle, flags);
}
} else if (!str_component.empty() && str_component[0] == '+') {
string type_name = str_component.substr(1);
// *** for now, as a quick hack, if a type exists with the "qp"
// prefix on the named type, we search for that type instead.
TypeHandle handle = TypeRegistry::ptr()->find_type("qp" + type_name);
if (handle == TypeHandle::none()) {
handle = TypeRegistry::ptr()->find_type(type_name);
}
if (handle == TypeHandle::none()) {
pgraph_cat.error()
<< "Invalid type name: " + type_name;
return false;
} else {
add_match_inexact_type(handle, flags);
}
} else {
add_match_name_glob(str_component, flags);
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: qpFindApproxPath::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void qpFindApproxPath::
output(ostream &out) const {
out << "(";
if (!_path.empty()) {
Path::const_iterator pi = _path.begin();
out << *pi;
++pi;
while (pi != _path.end()) {
out << " / " << *pi;
++pi;
}
}
out << ")";
}
ostream &
operator << (ostream &out, qpFindApproxPath::ComponentType type) {
switch (type) {
case qpFindApproxPath::CT_match_name:
return out << "match_name";
case qpFindApproxPath::CT_match_name_glob:
return out << "match_name_glob";
case qpFindApproxPath::CT_match_exact_type:
return out << "match_exact_type";
case qpFindApproxPath::CT_match_inexact_type:
return out << "match_inexact_type";
case qpFindApproxPath::CT_match_one:
return out << "match_one";
case qpFindApproxPath::CT_match_many:
return out << "match_many";
case qpFindApproxPath::CT_match_pointer:
return out << "match_pointer";
};
return out << "**invalid**";
};

View File

@ -0,0 +1,119 @@
// Filename: qpqpFindApproxPath.h
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpFINDAPPROXPATH_H
#define qpFINDAPPROXPATH_H
#include "pandabase.h"
#include "pvector.h"
class PandaNode;
////////////////////////////////////////////////////////////////////
// Class : qpFindApproxPath
// Description : This class is local to this package only; it doesn't
// get exported. It chops a string path, as supplied to
// find_up() or find_down(), and breaks it up into its
// component pieces.
////////////////////////////////////////////////////////////////////
class qpFindApproxPath {
public:
INLINE qpFindApproxPath();
bool add_string(const string &str_path);
bool add_flags(const string &str_flags);
bool add_component(string str_component);
INLINE void add_match_name(const string &name, int flags);
INLINE void add_match_name_glob(const string &glob, int flags);
INLINE void add_match_exact_type(TypeHandle type, int flags);
INLINE void add_match_inexact_type(TypeHandle type, int flags);
INLINE void add_match_one(int flags);
INLINE void add_match_many(int flags);
INLINE void add_match_pointer(PandaNode *pointer, int flags);
INLINE int get_num_components() const;
INLINE bool is_component_match_many(int index) const;
INLINE bool matches_component(int index, PandaNode *node) const;
INLINE bool matches_stashed(int index) const;
INLINE bool return_hidden() const;
INLINE bool return_stashed() const;
void output(ostream &out) const;
INLINE void output_component(ostream &out, int index) const;
#ifndef WIN32_VC
// Visual C++ won't let us define the ostream operator functions for
// these guys if they're private--even though we declare them friends.
private:
#endif
enum ComponentType {
CT_match_name,
CT_match_name_glob,
CT_match_exact_type,
CT_match_inexact_type,
CT_match_one,
CT_match_many,
CT_match_pointer
};
enum ComponentFlags {
CF_stashed = 0x001,
};
class Component {
public:
bool matches(PandaNode *node) const;
void output(ostream &out) const;
ComponentType _type;
string _name;
TypeHandle _type_handle;
PandaNode *_pointer;
int _flags;
};
typedef pvector<Component> Path;
Path _path;
bool _return_hidden;
bool _return_stashed;
friend ostream &operator << (ostream &, qpFindApproxPath::ComponentType);
friend INLINE ostream &operator << (ostream &, const qpFindApproxPath::Component &);
};
ostream &
operator << (ostream &out, qpFindApproxPath::ComponentType type);
INLINE ostream &
operator << (ostream &out, const qpFindApproxPath::Component &component) {
component.output(out);
return out;
}
INLINE ostream &
operator << (ostream &out, const qpFindApproxPath &path) {
path.output(out);
return out;
}
#include "qpfindApproxPath.I"
#endif

View File

@ -50,10 +50,12 @@ qpNodePath(const string &top_node_name) :
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::Constructor
// Access: Published
// Description: This constructs an empty qpNodePath with a single node.
//
// If the Node pointer is NULL, this quietly creates an
// empty qpNodePath.
// Description: This constructs a NodePath for the indicated node.
// If the node does not have any parents, this creates a
// single NodePath; otherwise, it automatically finds
// the path from the node to the root. If the node has
// multiple paths to the root, one path is chosen
// arbitrarily and a warning message is printed.
////////////////////////////////////////////////////////////////////
INLINE qpNodePath::
qpNodePath(PandaNode *top_node) :
@ -64,6 +66,28 @@ qpNodePath(PandaNode *top_node) :
}
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::Constructor
// Access: Published
// Description: Constructs a NodePath with the indicated parent
// NodePath and child node; the child node must be a
// stashed or unstashed child of the parent.
////////////////////////////////////////////////////////////////////
INLINE qpNodePath::
qpNodePath(const qpNodePath &parent, PandaNode *child) :
_error_type(ET_fail)
{
nassertv(!parent.is_empty());
nassertv(child != (PandaNode *)NULL);
_head = PandaNode::get_component(parent._head, child);
nassertv(_head != (qpNodePathComponent *)NULL);
if (_head != (qpNodePathComponent *)NULL) {
_error_type = ET_ok;
}
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::Copy Constructor
// Access: Published

View File

@ -18,10 +18,10 @@
#include "qpnodePath.h"
#include "qpnodePathCollection.h"
#include "node.h"
#include "namedNode.h"
#include "qpfindApproxPath.h"
#include "qpfindApproxLevelEntry.h"
#include "qpfindApproxLevel.h"
#include "config_pgraph.h"
#include "plist.h"
#include "colorAttrib.h"
#include "cullBinAttrib.h"
#include "textureAttrib.h"
@ -32,7 +32,11 @@
#include "materialPool.h"
#include "look_at.h"
#include "compose_matrix.h"
#include "plist.h"
// stack seems to overflow on Intel C++ at 7000. If we need more than
// 7000, need to increase stack size.
int qpNodePath::_max_search_depth = 7000;
TypeHandle qpNodePath::_type_handle;
////////////////////////////////////////////////////////////////////
@ -124,6 +128,65 @@ get_children() const {
return result;
}
////////////////////////////////////////////////////////////////////
// Function: qoNodePath::find
// Access: Published
// Description: Searches for a node below the referenced node that
// matches the indicated string. Returns the shortest
// match found, if any, or an empty NodePath if no match
// can be found.
////////////////////////////////////////////////////////////////////
qpNodePath qpNodePath::
find(const string &path) const {
nassertr(!is_empty(), fail());
qpNodePathCollection col;
find_matches(col, path, 1);
if (col.is_empty()) {
return qpNodePath::not_found();
}
return col.get_path(0);
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::find_all_matches
// Access: Published
// Description: Returns the complete set of all NodePaths that begin
// with this NodePath and can be extended by
// path. The shortest paths will be listed
// first.
////////////////////////////////////////////////////////////////////
qpNodePathCollection qpNodePath::
find_all_matches(const string &path) const {
qpNodePathCollection col;
nassertr(!is_empty(), col);
nassertr(verify_complete(), col);
find_matches(col, path, -1);
return col;
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::find_all_paths_to
// Access: Published
// Description: Returns the set of all NodePaths that extend from
// this NodePath down to the indicated node. The
// shortest paths will be listed first.
////////////////////////////////////////////////////////////////////
qpNodePathCollection qpNodePath::
find_all_paths_to(PandaNode *node) const {
qpNodePathCollection col;
nassertr(!is_empty(), col);
nassertr(verify_complete(), col);
nassertr(node != (PandaNode *)NULL, col);
qpFindApproxPath approx_path;
approx_path.add_match_many(0);
approx_path.add_match_pointer(node, 0);
find_matches(col, approx_path, -1);
return col;
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::reparent_to
// Access: Published
@ -258,9 +321,11 @@ attach_new_node(PandaNode *node, int sort) const {
void qpNodePath::
remove_node() {
nassertv(_error_type != ET_not_found);
if (is_empty()) {
// If we have no arcs (maybe we were already removed), quietly do
// nothing except to ensure the qpNodePath is clear.
if (is_empty() || is_singleton()) {
// If we have no parents, remove_node() is just a do-nothing
// operation; if we have no nodes, maybe we were already removed.
// In either case, quietly do nothing except to ensure the
// qpNodePath is clear.
(*this) = qpNodePath::removed();
return;
}
@ -2303,7 +2368,101 @@ r_output(ostream &out, qpNodePathComponent *comp) const {
if (node->has_name()) {
out << node->get_name();
} else {
out << "+" << node->get_type();
out << "-" << node->get_type();
}
// out << "[" << comp->get_length() << "]";
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::find_matches
// Access: Private
// Description: Finds up to max_matches matches against the given
// path string from this node and deeper. The
// max_matches count indicates the maximum number of
// matches to return, or -1 not to limit the number
// returned.
////////////////////////////////////////////////////////////////////
void qpNodePath::
find_matches(qpNodePathCollection &result, const string &path,
int max_matches) const {
if (is_empty()) {
pgraph_cat.warning()
<< "Attempt to extend an empty qpNodePath by '" << path
<< "'.\n";
return;
}
qpFindApproxPath approx_path;
if (approx_path.add_string(path)) {
find_matches(result, approx_path, max_matches);
}
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::find_matches
// Access: Private
// Description: Finds up to max_matches matches against the given
// approx_path from this node and deeper. The
// max_matches count indicates the maximum number of
// matches to return, or -1 not to limit the number
// returned.
////////////////////////////////////////////////////////////////////
void qpNodePath::
find_matches(qpNodePathCollection &result, qpFindApproxPath &approx_path,
int max_matches) const {
if (is_empty()) {
pgraph_cat.warning()
<< "Attempt to extend an empty qpNodePath by: " << approx_path << ".\n";
return;
}
qpFindApproxLevelEntry start(*this, approx_path);
qpFindApproxLevel level;
level.add_entry(start);
r_find_matches(result, level, max_matches, _max_search_depth);
}
////////////////////////////////////////////////////////////////////
// Function: qpNodePath::r_find_matches
// Access: Private
// Description: The recursive implementation of find_matches.
////////////////////////////////////////////////////////////////////
void qpNodePath::
r_find_matches(qpNodePathCollection &result,
const qpFindApproxLevel &level,
int max_matches, int num_levels_remaining) const {
// Go on to the next level. If we exceeded the requested maximum
// depth, stop.
if (num_levels_remaining <= 0) {
return;
}
num_levels_remaining--;
qpFindApproxLevel next_level;
bool okflag = true;
// For each node in the current level, build up the set of possible
// matches in the next level.
qpFindApproxLevel::Vec::const_iterator li;
for (li = level._v.begin(); li != level._v.end() && okflag; ++li) {
const qpFindApproxLevelEntry &entry = (*li);
if (entry.is_solution()) {
// Does this entry already represent a solution?
result.add_path(entry._node_path);
} else {
entry.consider_node(result, next_level, max_matches);
}
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;
}
}
// Now recurse on the next level.
if (okflag) {
r_find_matches(result, next_level, max_matches, num_levels_remaining);
}
}

View File

@ -32,10 +32,85 @@
#include "typedObject.h"
class qpNodePathCollection;
class qpFindApproxLevel;
class qpFindApproxPath;
class Texture;
class Material;
class Fog;
//
// A NodePath is the fundamental unit of high-level interaction with
// the scene graph. It encapsulates the complete path down to a node
// from some other node, usually the root of the scene graph. This is
// used to resolve ambiguities associated with instancing.
//
// NodePath also contains a number of handy high-level methods for
// common scene-graph manipulations, such as reparenting, and common
// state changes, such as repositioning.
//
// There are also a number of NodePath methods for finding nodes deep
// within the tree by name or by type. These take a path string,
// which at its simplest consists of a series of node names separated
// by slashes, like a directory pathname.
//
// Each component of the path string may optionally consist of one of
// the following special names, instead of a node name:
//
// * -- matches exactly one node, with any name.
// ** -- matches any sequence of zero or more nodes.
// +typename -- matches any node that is or derives from the given type.
// -typename -- matches any node that is the given type exactly.
//
// Furthermore, a node name may itself contain standard filename
// globbing characters, like *, ?, and [a-z], that will be accepted as
// a partial match. (In fact, the '*' special name may be seen as
// just a special case of this.) The globbing characters may not be
// used with the typename matches.
//
// The special characters "@@", appearing at the beginning of a node
// name, indicate a stashed node. Normally, stashed nodes are not
// returned by a find (but see the special flags, below), but a
// stashed node may be found if it is explicitly named with its
// leading @@ characters. By extension, "@@*" may be used to identify
// any stashed node.
//
// Examples:
//
// "room//graph" will look for a node named "graph", which is a child
// of an unnamed node, which is a child of a node named "room", which
// is a child of the starting path.
//
// "**/red*" will look for any node anywhere in the tree (below the
// starting path) with a name that begins with "red".
//
// "**/+PartBundleNode/**/head" will look for a node named "head",
// somewhere below a PartBundleNode anywhere in the tree.
//
//
// The search is always potentially ambiguous, even if the special
// wildcard operators are not used, because there may be multiple
// nodes in the tree with the same name. In general, in the case of
// an ambiguity, the shortest path is preferred; when a method (such
// as extend_by) must choose only only one of several possible paths,
// it will choose the shortest available; on the other hand, when a
// method (such as find_all_matches) is to return all of the matching
// paths, it will sort them so that the shortest paths appear first in
// the output.
//
//
// Special flags. The entire string may optionally be followed by the
// ";" character, followed by one or more of the following special
// control flags, with no intervening spaces or punctuation:
//
// -h Do not return hidden nodes.
// +h Do return hidden nodes.
// -s Do not return stashed nodes unless explicitly referenced with @@.
// +s Return stashed nodes even without any explicit @@ characters.
//
// The default flags are +h-s.
//
////////////////////////////////////////////////////////////////////
// Class : NodePath
// Description : NodePath is the fundamental system for disambiguating
@ -71,6 +146,7 @@ PUBLISHED:
INLINE qpNodePath(const string &top_node_name);
INLINE qpNodePath(PandaNode *top_node);
INLINE qpNodePath(const qpNodePath &copy);
INLINE qpNodePath(const qpNodePath &parent, PandaNode *child_node);
INLINE void operator = (const qpNodePath &copy);
INLINE static qpNodePath not_found();
@ -98,12 +174,9 @@ PUBLISHED:
INLINE bool has_parent() const;
INLINE qpNodePath get_parent() const;
/*
INLINE qpNodePath find(const string &path) const;
qpNodePathCollection
find_all_matches(const string &path) const;
*/
qpNodePath find(const string &path) const;
qpNodePathCollection find_all_matches(const string &path) const;
qpNodePathCollection find_all_paths_to(PandaNode *node) const;
// Methods that actually move nodes around in the scene graph. The
// optional "sort" parameter can be used to force a particular
@ -405,8 +478,19 @@ private:
CPT(TransformState) r_get_partial_transform(qpNodePathComponent *comp, int n) const;
void r_output(ostream &out, qpNodePathComponent *comp) const;
void find_matches(qpNodePathCollection &result,
const string &approx_path_str,
int max_matches) const;
void find_matches(qpNodePathCollection &result,
qpFindApproxPath &approx_path,
int max_matches) const;
void r_find_matches(qpNodePathCollection &result,
const qpFindApproxLevel &level,
int max_matches, int num_levels_remaining) const;
PT(qpNodePathComponent) _head;
ErrorType _error_type;
static int _max_search_depth;
public:
static TypeHandle get_class_type() {