diff --git a/direct/src/showbase/qpShowBase.py b/direct/src/showbase/qpShowBase.py index c30ed4e4b7..0b283263d2 100644 --- a/direct/src/showbase/qpShowBase.py +++ b/direct/src/showbase/qpShowBase.py @@ -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 diff --git a/panda/src/dgraph/qpdataNode.cxx b/panda/src/dgraph/qpdataNode.cxx index 4ccb594a5c..67335bb2a4 100644 --- a/panda/src/dgraph/qpdataNode.cxx +++ b/panda/src/dgraph/qpdataNode.cxx @@ -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"; } diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index ddebe59864..9222afc3a8 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -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 diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 82362b7def..9717fa7740 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -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; diff --git a/panda/src/pgraph/pgraph_composite2.cxx b/panda/src/pgraph/pgraph_composite2.cxx index ad25f5a4e1..68a3146f85 100644 --- a/panda/src/pgraph/pgraph_composite2.cxx +++ b/panda/src/pgraph/pgraph_composite2.cxx @@ -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" diff --git a/panda/src/pgraph/qpfindApproxLevel.I b/panda/src/pgraph/qpfindApproxLevel.I new file mode 100644 index 0000000000..f2b74a4189 --- /dev/null +++ b/panda/src/pgraph/qpfindApproxLevel.I @@ -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); +} + diff --git a/panda/src/pgraph/qpfindApproxLevel.cxx b/panda/src/pgraph/qpfindApproxLevel.cxx new file mode 100644 index 0000000000..b114f7c94b --- /dev/null +++ b/panda/src/pgraph/qpfindApproxLevel.cxx @@ -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"; + } +} diff --git a/panda/src/pgraph/qpfindApproxLevel.h b/panda/src/pgraph/qpfindApproxLevel.h new file mode 100644 index 0000000000..a19b1892b7 --- /dev/null +++ b/panda/src/pgraph/qpfindApproxLevel.h @@ -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 Vec; + Vec _v; +}; + +#include "qpfindApproxLevel.I" + +#endif diff --git a/panda/src/pgraph/qpfindApproxLevelEntry.I b/panda/src/pgraph/qpfindApproxLevelEntry.I new file mode 100644 index 0000000000..ab8da5e4e0 --- /dev/null +++ b/panda/src/pgraph/qpfindApproxLevelEntry.I @@ -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 ©) : + _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 ©) { + _node_path = copy._node_path; + _i = copy._i; + nassertv(&_approx_path == ©._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()); +} diff --git a/panda/src/pgraph/qpfindApproxLevelEntry.cxx b/panda/src/pgraph/qpfindApproxLevelEntry.cxx new file mode 100644 index 0000000000..3916b5254f --- /dev/null +++ b/panda/src/pgraph/qpfindApproxLevelEntry.cxx @@ -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); + } + } +} diff --git a/panda/src/pgraph/qpfindApproxLevelEntry.h b/panda/src/pgraph/qpfindApproxLevelEntry.h new file mode 100644 index 0000000000..50a14cacc8 --- /dev/null +++ b/panda/src/pgraph/qpfindApproxLevelEntry.h @@ -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 ©); + INLINE void operator = (const qpFindApproxLevelEntry ©); + + 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 diff --git a/panda/src/pgraph/qpfindApproxPath.I b/panda/src/pgraph/qpfindApproxPath.I new file mode 100644 index 0000000000..3dc08169a3 --- /dev/null +++ b/panda/src/pgraph/qpfindApproxPath.I @@ -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]; +} diff --git a/panda/src/pgraph/qpfindApproxPath.cxx b/panda/src/pgraph/qpfindApproxPath.cxx new file mode 100644 index 0000000000..6be73b5375 --- /dev/null +++ b/panda/src/pgraph/qpfindApproxPath.cxx @@ -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**"; +}; + diff --git a/panda/src/pgraph/qpfindApproxPath.h b/panda/src/pgraph/qpfindApproxPath.h new file mode 100644 index 0000000000..0ebf8a8a43 --- /dev/null +++ b/panda/src/pgraph/qpfindApproxPath.h @@ -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 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 diff --git a/panda/src/pgraph/qpnodePath.I b/panda/src/pgraph/qpnodePath.I index e3da2936da..c3d3e9f760 100644 --- a/panda/src/pgraph/qpnodePath.I +++ b/panda/src/pgraph/qpnodePath.I @@ -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 diff --git a/panda/src/pgraph/qpnodePath.cxx b/panda/src/pgraph/qpnodePath.cxx index d7f45cd06b..0f49b7c90a 100644 --- a/panda/src/pgraph/qpnodePath.cxx +++ b/panda/src/pgraph/qpnodePath.cxx @@ -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); + } +} diff --git a/panda/src/pgraph/qpnodePath.h b/panda/src/pgraph/qpnodePath.h index eef9c7b8a7..0ef4e0fd4d 100644 --- a/panda/src/pgraph/qpnodePath.h +++ b/panda/src/pgraph/qpnodePath.h @@ -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 ©); + INLINE qpNodePath(const qpNodePath &parent, PandaNode *child_node); INLINE void operator = (const qpNodePath ©); 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() {