diff --git a/panda/src/display/displayRegion.I b/panda/src/display/displayRegion.I index 6f6db0676f..3eb65bb515 100644 --- a/panda/src/display/displayRegion.I +++ b/panda/src/display/displayRegion.I @@ -108,7 +108,7 @@ get_camera() const { // Description: Returns the camera associated with this // DisplayRegion, or NULL if no camera is associated. //////////////////////////////////////////////////////////////////// -INLINE const NodeChain &DisplayRegion:: +INLINE const qpNodePath &DisplayRegion:: get_qpcamera() const { return _qpcamera; } diff --git a/panda/src/display/displayRegion.cxx b/panda/src/display/displayRegion.cxx index 20a7b4f40d..c640cc7f85 100644 --- a/panda/src/display/displayRegion.cxx +++ b/panda/src/display/displayRegion.cxx @@ -98,7 +98,7 @@ operator = (const DisplayRegion&) { //////////////////////////////////////////////////////////////////// DisplayRegion:: ~DisplayRegion() { - set_qpcamera(NodeChain()); + set_qpcamera(qpNodePath()); } //////////////////////////////////////////////////////////////////// @@ -193,12 +193,12 @@ set_camera(Camera *camera) { // was already associated with a different // DisplayRegion, that association is removed. // -// The camera is actually set via a NodeChain, which +// The camera is actually set via a qpNodePath, which // clarifies which instance of the camera (if there // happen to be multiple instances) we should use. //////////////////////////////////////////////////////////////////// void DisplayRegion:: -set_qpcamera(const NodeChain &camera) { +set_qpcamera(const qpNodePath &camera) { qpCamera *camera_node = (qpCamera *)NULL; if (!camera.is_empty()) { DCAST_INTO_V(camera_node, camera.node()); diff --git a/panda/src/display/displayRegion.h b/panda/src/display/displayRegion.h index bc80dc3364..c9d2bdd010 100644 --- a/panda/src/display/displayRegion.h +++ b/panda/src/display/displayRegion.h @@ -22,7 +22,7 @@ #include "referenceCount.h" #include "camera.h" -#include "nodeChain.h" +#include "qpnodePath.h" #include "cullResult.h" #include "pointerTo.h" @@ -69,8 +69,8 @@ PUBLISHED: void set_camera(Camera *camera); INLINE Camera *get_camera() const; - void set_qpcamera(const NodeChain &camera); - INLINE const NodeChain &get_qpcamera() const; + void set_qpcamera(const qpNodePath &camera); + INLINE const qpNodePath &get_qpcamera() const; INLINE void set_cull_frustum(LensNode *cull_frustum); INLINE LensNode *get_cull_frustum() const; @@ -104,7 +104,7 @@ protected: GraphicsLayer *_layer; PT(Camera) _camera; - NodeChain _qpcamera; + qpNodePath _qpcamera; qpCamera *_camera_node; PT(LensNode) _cull_frustum; diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 6d502dc14c..8a03f3d62d 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -197,7 +197,7 @@ cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr) { // Description: Fires off a cull traversal using the indicated camera. //////////////////////////////////////////////////////////////////// void GraphicsEngine:: -do_cull(CullHandler *cull_handler, const NodeChain &camera, +do_cull(CullHandler *cull_handler, const qpNodePath &camera, GraphicsStateGuardian *gsg) { if (camera.is_empty()) { // No camera, no draw. @@ -218,7 +218,7 @@ do_cull(CullHandler *cull_handler, const NodeChain &camera, return; } - NodeChain scene = camera_node->get_scene(); + qpNodePath scene = camera_node->get_scene(); if (scene.is_empty()) { // No scene, no draw. return; @@ -298,7 +298,7 @@ do_draw(CullResult *cull_result, GraphicsStateGuardian *gsg, //////////////////////////////////////////////////////////////////// bool GraphicsEngine:: set_gsg_lens(GraphicsStateGuardian *gsg, DisplayRegion *dr) { - const NodeChain &camera = dr->get_qpcamera(); + const qpNodePath &camera = dr->get_qpcamera(); if (camera.is_empty()) { // No camera, no draw. return false; diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index e5b86f5a41..3943775ceb 100644 --- a/panda/src/display/graphicsEngine.h +++ b/panda/src/display/graphicsEngine.h @@ -57,7 +57,7 @@ private: void cull_bin_draw(); void cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr); - void do_cull(CullHandler *cull_handler, const NodeChain &camera, + void do_cull(CullHandler *cull_handler, const qpNodePath &camera, GraphicsStateGuardian *gsg); void do_draw(CullResult *cull_result, GraphicsStateGuardian *gsg, DisplayRegion *dr); diff --git a/panda/src/egg2pg/qpeggLoader.cxx b/panda/src/egg2pg/qpeggLoader.cxx index 0719250e11..5a6a2672bb 100644 --- a/panda/src/egg2pg/qpeggLoader.cxx +++ b/panda/src/egg2pg/qpeggLoader.cxx @@ -20,7 +20,7 @@ #include "qpeggLoader.h" #include "config_egg2pg.h" -#include "nodeChain.h" +#include "qpnodePath.h" #include "renderState.h" #include "transformState.h" #include "textureAttrib.h" @@ -154,14 +154,14 @@ reparent_decals() { PandaNode *node = (*di); nassertv(node != (PandaNode *)NULL); - // The NodeChain interface is best for this. - NodeChain parent(node); + // The qpNodePath interface is best for this. + qpNodePath parent(node); // First, search for the GeomNode. - NodeChain geom_parent; + qpNodePath geom_parent; int num_children = parent.get_num_children(); for (int i = 0; i < num_children; i++) { - NodeChain child = parent.get_child(i); + qpNodePath child = parent.get_child(i); if (child.node()->is_of_type(qpGeomNode::get_class_type())) { if (!geom_parent.is_empty()) { @@ -187,7 +187,7 @@ reparent_decals() { // list. int i = 0; while (i < num_children) { - NodeChain child = parent.get_child(i); + qpNodePath child = parent.get_child(i); if (child.node()->is_of_type(qpGeomNode::get_class_type())) { i++; diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 60f43f9a95..ddebe59864 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -31,8 +31,9 @@ qplensNode.h qplensNode.I \ qplodNode.h qplodNode.I \ materialAttrib.h materialAttrib.I \ - nodeChain.h nodeChain.I \ - nodeChainComponent.h nodeChainComponent.I \ + qpnodePath.h qpnodePath.I \ + qpnodePathCollection.h qpnodePathCollection.I \ + qpnodePathComponent.h qpnodePathComponent.I \ pandaNode.h pandaNode.I \ renderAttrib.h renderAttrib.I \ renderState.h renderState.I \ @@ -70,8 +71,9 @@ qplensNode.cxx \ qplodNode.cxx \ materialAttrib.cxx \ - nodeChain.cxx \ - nodeChainComponent.cxx \ + qpnodePath.cxx \ + qpnodePathCollection.cxx \ + qpnodePathComponent.cxx \ pandaNode.cxx \ renderAttrib.cxx \ renderState.cxx \ @@ -114,8 +116,9 @@ qplensNode.h qplensNode.I \ qplodNode.h qplodNode.I \ materialAttrib.h materialAttrib.I \ - nodeChain.h nodeChain.I \ - nodeChainComponent.h nodeChainComponent.I \ + qpnodePath.h qpnodePath.I \ + qpnodePathCollection.h qpnodePathCollection.I \ + qpnodePathComponent.h qpnodePathComponent.I \ pandaNode.h pandaNode.I \ renderAttrib.h renderAttrib.I \ renderState.h renderState.I \ diff --git a/panda/src/pgraph/billboardAttrib.I b/panda/src/pgraph/billboardAttrib.I index 579a2b8285..7596b7f16c 100644 --- a/panda/src/pgraph/billboardAttrib.I +++ b/panda/src/pgraph/billboardAttrib.I @@ -37,7 +37,7 @@ BillboardAttrib() { INLINE CPT(RenderAttrib) BillboardAttrib:: make_axis() { return make(LVector3f::up(), false, true, - 0.0f, NodeChain(), LPoint3f(0.0f, 0.0f, 0.0f)); + 0.0f, qpNodePath(), LPoint3f(0.0f, 0.0f, 0.0f)); } //////////////////////////////////////////////////////////////////// @@ -49,7 +49,7 @@ make_axis() { INLINE CPT(RenderAttrib) BillboardAttrib:: make_point_eye() { return make(LVector3f::up(), true, false, - 0.0f, NodeChain(), LPoint3f(0.0f, 0.0f, 0.0f)); + 0.0f, qpNodePath(), LPoint3f(0.0f, 0.0f, 0.0f)); } //////////////////////////////////////////////////////////////////// @@ -61,7 +61,7 @@ make_point_eye() { INLINE CPT(RenderAttrib) BillboardAttrib:: make_point_world() { return make(LVector3f::up(), false, false, - 0.0f, NodeChain(), LPoint3f(0.0f, 0.0f, 0.0f)); + 0.0f, qpNodePath(), LPoint3f(0.0f, 0.0f, 0.0f)); } //////////////////////////////////////////////////////////////////// @@ -73,7 +73,7 @@ make_point_world() { // particularly useful and isn't normally created or // stored in the graph; it might be implicitly // discovered as the result of a -// NodeChain::get_rel_state(). +// qpNodePath::get_rel_state(). //////////////////////////////////////////////////////////////////// INLINE bool BillboardAttrib:: is_off() const { @@ -135,7 +135,7 @@ get_offset() const { // will rotate towards the current camera node, wherever // that might be. //////////////////////////////////////////////////////////////////// -INLINE const NodeChain &BillboardAttrib:: +INLINE const qpNodePath &BillboardAttrib:: get_look_at() const { return _look_at; } diff --git a/panda/src/pgraph/billboardAttrib.cxx b/panda/src/pgraph/billboardAttrib.cxx index 2f21893bb2..3ea196472f 100644 --- a/panda/src/pgraph/billboardAttrib.cxx +++ b/panda/src/pgraph/billboardAttrib.cxx @@ -33,7 +33,7 @@ TypeHandle BillboardAttrib::_type_handle; //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) BillboardAttrib:: make(const LVector3f &up_vector, bool eye_relative, - bool axial_rotate, float offset, const NodeChain &look_at, + bool axial_rotate, float offset, const qpNodePath &look_at, const LPoint3f &look_at_point) { BillboardAttrib *attrib = new BillboardAttrib; attrib->_up_vector = up_vector; @@ -228,7 +228,7 @@ write_datagram(BamWriter *manager, Datagram &dg) { dg.add_float32(_offset); _look_at_point.write_datagram(dg); - // *** We don't write out the _look_at NodeChain right now. Maybe + // *** We don't write out the _look_at qpNodePath right now. Maybe // we should. } diff --git a/panda/src/pgraph/billboardAttrib.h b/panda/src/pgraph/billboardAttrib.h index c0f2077851..69085d355e 100644 --- a/panda/src/pgraph/billboardAttrib.h +++ b/panda/src/pgraph/billboardAttrib.h @@ -23,7 +23,7 @@ #include "renderAttrib.h" #include "luse.h" -#include "nodeChain.h" +#include "qpnodePath.h" //////////////////////////////////////////////////////////////////// // Class : BillboardAttrib @@ -40,7 +40,7 @@ PUBLISHED: bool eye_relative, bool axial_rotate, float offset, - const NodeChain &look_at, + const qpNodePath &look_at, const LPoint3f &look_at_point); INLINE static CPT(RenderAttrib) make_axis(); INLINE static CPT(RenderAttrib) make_point_eye(); @@ -51,7 +51,7 @@ PUBLISHED: INLINE bool get_eye_relative() const; INLINE bool get_axial_rotate() const; INLINE float get_offset() const; - INLINE const NodeChain &get_look_at() const; + INLINE const qpNodePath &get_look_at() const; INLINE const LPoint3f &get_look_at_point() const; public: @@ -70,7 +70,7 @@ private: bool _eye_relative; bool _axial_rotate; float _offset; - NodeChain _look_at; + qpNodePath _look_at; LPoint3f _look_at_point; public: diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index a33afb817c..15e86b0f03 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -35,8 +35,8 @@ #include "qplensNode.h" #include "qplodNode.h" #include "materialAttrib.h" -#include "nodeChain.h" -#include "nodeChainComponent.h" +#include "qpnodePath.h" +#include "qpnodePathComponent.h" #include "pandaNode.h" #include "renderAttrib.h" #include "renderState.h" @@ -95,8 +95,8 @@ init_libpgraph() { qpLensNode::init_type(); qpLODNode::init_type(); MaterialAttrib::init_type(); - NodeChain::init_type(); - NodeChainComponent::init_type(); + qpNodePath::init_type(); + qpNodePathComponent::init_type(); PandaNode::init_type(); RenderAttrib::init_type(); RenderState::init_type(); diff --git a/panda/src/pgraph/materialAttrib.h b/panda/src/pgraph/materialAttrib.h index 0b1d64e2b0..3169b47693 100644 --- a/panda/src/pgraph/materialAttrib.h +++ b/panda/src/pgraph/materialAttrib.h @@ -36,7 +36,7 @@ private: INLINE MaterialAttrib(); PUBLISHED: - static CPT(RenderAttrib) make(const Material *tex); + static CPT(RenderAttrib) make(const Material *material); static CPT(RenderAttrib) make_off(); INLINE bool is_off() const; diff --git a/panda/src/pgraph/nodeChain.I b/panda/src/pgraph/nodeChain.I deleted file mode 100644 index 54e95077f8..0000000000 --- a/panda/src/pgraph/nodeChain.I +++ /dev/null @@ -1,348 +0,0 @@ -// Filename: nodeChain.I -// Created by: drose (25Feb02) -// -//////////////////////////////////////////////////////////////////// -// -// 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: NodeChain::Default Constructor -// Access: Published -// Description: This constructs an empty NodeChain with no nodes. It -// cannot be extended, since you cannot add nodes without -// first specifying the top node. Use the constructor -// that receives a node if you ever want to do anything -// with this chain. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain:: -NodeChain() : - _error_type(ET_ok) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::Constructor -// Access: Published -// Description: This constructs an empty NodeChain with a single node. -// This chain may now be extended by repeatedly calling -// push_back() with each node below that node in -// sequence. -// -// If the Node pointer is NULL, this quietly creates an -// empty NodeChain. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain:: -NodeChain(PandaNode *top_node) : - _error_type(ET_ok) -{ - if (top_node != (PandaNode *)NULL) { - _head = top_node->get_generic_component(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::Copy Constructor -// Access: Published -// Description: -//////////////////////////////////////////////////////////////////// -INLINE NodeChain:: -NodeChain(const NodeChain ©) : - _head(copy._head), - _error_type(copy._error_type) -{ - uncollapse_head(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::Copy Assignment Operator -// Access: Published -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void NodeChain:: -operator = (const NodeChain ©) { - _head = copy._head; - _error_type = copy._error_type; - uncollapse_head(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::not_found named constructor -// Access: Published, Static -// Description: Creates a NodeChain with the ET_not_found error type -// set. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain NodeChain:: -not_found() { - NodeChain result; - result._error_type = ET_not_found; - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::removed named constructor -// Access: Published, Static -// Description: Creates a NodeChain with the ET_removed error type -// set. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain NodeChain:: -removed() { - NodeChain result; - result._error_type = ET_removed; - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::fail named constructor -// Access: Published, Static -// Description: Creates a NodeChain with the ET_fail error type -// set. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain NodeChain:: -fail() { - NodeChain result; - result._error_type = ET_fail; - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::is_empty -// Access: Published -// Description: Returns true if the NodeChain contains no nodes. -//////////////////////////////////////////////////////////////////// -INLINE bool NodeChain:: -is_empty() const { - return (_head == (NodeChainComponent *)NULL); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::is_singleton -// Access: Published -// Description: Returns true if the NodeChain contains exactly one -// node. -//////////////////////////////////////////////////////////////////// -INLINE bool NodeChain:: -is_singleton() const { - uncollapse_head(); - return (_head != (NodeChainComponent *)NULL && _head->is_top_node()); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_error_type -// Access: Published -// Description: If is_empty() is true, this returns a code that -// represents the reason why the NodeChain is empty. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain::ErrorType NodeChain:: -get_error_type() const { - return _error_type; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::node -// Access: Published -// Description: Returns the bottom node of the path, or NULL if the -// path is empty. -//////////////////////////////////////////////////////////////////// -INLINE PandaNode *NodeChain:: -node() const { - if (is_empty()) { - return (PandaNode *)NULL; - } - return _head->get_node(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_num_children -// Access: Published -// Description: Returns the number of children of the bottom node. -//////////////////////////////////////////////////////////////////// -INLINE int NodeChain:: -get_num_children() const { - nassertr(!is_empty(), 0); - return _head->get_node()->get_num_children(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_child -// Access: Published -// Description: Returns a NodeChain representing the nth child of the -// bottom node. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain NodeChain:: -get_child(int n) const { - nassertr(n >= 0 && n < get_num_children(), NodeChain()); - NodeChain child; - child._head = PandaNode::get_component(_head, _head->get_node()->get_child(n)); - return child; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::has_parent -// Access: Published -// Description: Returns true if the node at the bottom of the -// NodeChain has a parent; i.e. the NodeChain contains at -// least two nodes. -//////////////////////////////////////////////////////////////////// -INLINE bool NodeChain:: -has_parent() const { - return !is_empty() && !is_singleton(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_parent -// Access: Published -// Description: Returns the NodeChain to the parent of the bottom -// node: that is, this NodeChain, shortened by one node. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain NodeChain:: -get_parent() const { - nassertr(has_parent(), NodeChain::fail()); - NodeChain parent; - parent._head = _head->get_next(); - return parent; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::attach_new_node -// Access: Published -// Description: Creates an ordinary PandaNode and attaches it below -// the current NodeChain, returning a new NodeChain that -// references it. -//////////////////////////////////////////////////////////////////// -INLINE NodeChain NodeChain:: -attach_new_node(const string &name, int sort) const { - nassertr(verify_complete(), NodeChain::fail()); - nassertr(!is_empty(), *this); - - return attach_new_node(new PandaNode(name), sort); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_net_state -// Access: Published -// Description: Returns the net state on this node from the root. -//////////////////////////////////////////////////////////////////// -INLINE CPT(RenderState) NodeChain:: -get_net_state() const { - uncollapse_head(); - return r_get_net_state(_head); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_net_transform -// Access: Published -// Description: Returns the net transform on this node from the root. -//////////////////////////////////////////////////////////////////// -INLINE CPT(TransformState) NodeChain:: -get_net_transform() const { - uncollapse_head(); - return r_get_net_transform(_head); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_mat -// Access: Published -// Description: Returns the matrix that describes the coordinate -// space of this node, relative to the other -// node's coordinate space. If either NodeChain is -// empty, it is taken to indicate the top of the graph. -//////////////////////////////////////////////////////////////////// -INLINE const LMatrix4f &NodeChain:: -get_mat(const NodeChain &other) const { - CPT(TransformState) transform = get_rel_transform(other); - // We can safely assume the transform won't go away when the - // function returns, since its reference count is also held in the - // cache. This assumption allows us to return a reference to the - // matrix, instead of having to return a matrix on the stack. - nassertr(transform->get_ref_count() > 1, LMatrix4f::ident_mat()); - return transform->get_mat(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::operator == -// Access: Published -// Description: Returns true if the two chains are equivalent; that -// is, if they contain the same list of nodes in the same -// order. -//////////////////////////////////////////////////////////////////// -INLINE bool NodeChain:: -operator == (const NodeChain &other) const { - return (compare_to(other) == 0); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::operator != -// Access: Published -// Description: Returns true if the two chains are not equivalent. -//////////////////////////////////////////////////////////////////// -INLINE bool NodeChain:: -operator != (const NodeChain &other) const { - return (compare_to(other) != 0); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::operator < -// Access: Published -// Description: Returns true if this NodeChain sorts before the other -// one, false otherwise. The sorting order of two -// nonequivalent NodeChains is consistent but undefined, -// and is useful only for storing NodeChains in a sorted -// container like an STL set. -//////////////////////////////////////////////////////////////////// -INLINE bool NodeChain:: -operator < (const NodeChain &other) const { - return (compare_to(other) < 0); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::compare_to -// Access: Published -// Description: Returns a number less than zero if this NodeChain -// sorts before the other one, greater than zero if it -// sorts after, or zero if they are equivalent. -// -// Two NodeChains are considered equivalent if they -// consist of exactly the same list of nodes in the same -// order. Otherwise, they are different; different -// NodeChains will be ranked in a consistent but -// undefined ordering; the ordering is useful only for -// placing the NodeChains in a sorted container like an -// STL set. -//////////////////////////////////////////////////////////////////// -INLINE int NodeChain:: -compare_to(const NodeChain &other) const { - return r_compare_to(_head, other._head); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::output -// Access: Published -// Description: Writes a sensible description of the NodeChain to the -// indicated output stream. -//////////////////////////////////////////////////////////////////// -INLINE void NodeChain:: -output(ostream &out) const { - if (_head == (NodeChainComponent *)NULL) { - out << "(empty)"; - } else { - r_output(out, _head); - } -} - -INLINE ostream &operator << (ostream &out, const NodeChain &node_chain) { - node_chain.output(out); - return out; -} - diff --git a/panda/src/pgraph/nodeChain.cxx b/panda/src/pgraph/nodeChain.cxx deleted file mode 100644 index 7d76df31fe..0000000000 --- a/panda/src/pgraph/nodeChain.cxx +++ /dev/null @@ -1,514 +0,0 @@ -// Filename: nodeChain.cxx -// Created by: drose (25Feb02) -// -//////////////////////////////////////////////////////////////////// -// -// 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 "nodeChain.h" -#include "node.h" -#include "namedNode.h" -#include "config_pgraph.h" -#include "plist.h" - -TypeHandle NodeChain::_type_handle; - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_num_nodes -// Access: Published -// Description: Returns the number of nodes in the path. -//////////////////////////////////////////////////////////////////// -int NodeChain:: -get_num_nodes() const { - if (is_empty()) { - return 0; - } - uncollapse_head(); - return _head->get_length(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_node -// Access: Published -// Description: Returns the nth node of the path, where 0 is the -// bottom node and get_num_nodes() - 1 is the top node. -// This requires iterating through the path. -//////////////////////////////////////////////////////////////////// -PandaNode *NodeChain:: -get_node(int index) const { - nassertr(index >= 0 && index < get_num_nodes(), NULL); - - uncollapse_head(); - NodeChainComponent *comp = _head; - while (index > 0) { - // If this assertion fails, the index was out of range; the - // component's length must have been invalid. - nassertr(comp != (NodeChainComponent *)NULL, NULL); - comp = comp->get_next(); - index--; - } - - // If this assertion fails, the index was out of range; the - // component's length must have been invalid. - nassertr(comp != (NodeChainComponent *)NULL, NULL); - return comp->get_node(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_top_node -// Access: Published -// Description: Returns the top node of the path, or NULL if the path -// is empty. This requires iterating through the path. -//////////////////////////////////////////////////////////////////// -PandaNode *NodeChain:: -get_top_node() const { - if (is_empty()) { - return (PandaNode *)NULL; - } - - uncollapse_head(); - NodeChainComponent *comp = _head; - while (!comp->is_top_node()) { - comp = comp->get_next(); - nassertr(comp != (NodeChainComponent *)NULL, NULL); - } - - return comp->get_node(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::reparent_to -// Access: Published -// Description: Removes the bottom node of the NodeChain from its -// current parent and attaches it to the bottom node of -// the indicated NodeChain. -//////////////////////////////////////////////////////////////////// -void NodeChain:: -reparent_to(const NodeChain &other, int sort) { - nassertv(other.verify_complete()); - nassertv_always(!is_empty()); - nassertv_always(!other.is_empty()); - - uncollapse_head(); - other.uncollapse_head(); - PandaNode::reparent(other._head, _head, sort); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::wrt_reparent_to -// Access: Published -// Description: This functions identically to reparent_to(), except -// the transform on this node is also adjusted so that -// the node remains in the same place in world -// coordinates, even if it is reparented into a -// different coordinate system. -//////////////////////////////////////////////////////////////////// -void NodeChain:: -wrt_reparent_to(const NodeChain &other, int sort) { - nassertv(other.verify_complete()); - nassertv_always(!is_empty()); - nassertv_always(!other.is_empty()); - - //**** - /* - LMatrix4f mat = get_mat(other); - set_mat(mat); - */ - - reparent_to(other, sort); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::instance_to -// Access: Published -// Description: Adds the bottom node of the NodeChain as a child of -// the bottom node of the indicated other NodeChain. Any -// other parent-child relations of the node are -// unchanged; in particular, the node is not removed -// from its existing parent, if any. -// -// If the node already had an existing parent, this -// method will create a new instance of the node within -// the scene graph. -// -// This does not change the NodeChain itself, but does -// return a new NodeChain that reflects the new instance -// node. -//////////////////////////////////////////////////////////////////// -NodeChain NodeChain:: -instance_to(const NodeChain &other, int sort) const { - nassertr(verify_complete(), NodeChain::fail()); - nassertr(!is_empty(), NodeChain::fail()); - nassertr(!other.is_empty(), NodeChain::fail()); - - uncollapse_head(); - other.uncollapse_head(); - - NodeChain new_instance; - new_instance._head = PandaNode::attach(other._head, node(), sort); - - return new_instance; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::copy_to -// Access: Published -// Description: Functions exactly like instance_to(), except a deep -// copy is made of the bottom node and all of its -// descendents, which is then parented to the indicated -// node. A NodeChain to the newly created copy is -// returned. -// -// Certain kinds of nodes may not be copied; if one of -// these is encountered, the node will be "copied" as -// the nearest copyable base class. For instance, a -// Camera node in the graph will become a simple -// NamedNode. -//////////////////////////////////////////////////////////////////// -NodeChain NodeChain:: -copy_to(const NodeChain &other, int sort) const { - //***** - return instance_to(other, sort); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::attach_new_node -// Access: Published -// Description: Attaches a new node, with or without existing -// parents, to the scene graph below the bottom node of -// this NodeChain. This is the preferred way to add -// nodes to the graph. -// -// This does *not* automatically extend the current -// NodeChain to reflect the attachment; however, a -// NodeChain that does reflect this extension is -// returned. -//////////////////////////////////////////////////////////////////// -NodeChain NodeChain:: -attach_new_node(PandaNode *node, int sort) const { - nassertr(verify_complete(), NodeChain::fail()); - nassertr(!is_empty(), NodeChain()); - nassertr(node != (PandaNode *)NULL, NodeChain()); - - uncollapse_head(); - NodeChain new_path(*this); - new_path._head = PandaNode::attach(_head, node, sort); - return new_path; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::remove_node -// Access: Published -// Description: Disconnects the bottom node from the scene graph. -// This will also delete the node if there are no other -// pointers to it. -// -// Normally, this should be called only when you are -// really done with the node. If you want to remove a -// node from the scene graph but keep it around for -// later, you should probably use reparent_to() and put -// it under a holding node instead. -// -// After the node is removed, the NodeChain will have -// been cleared. -//////////////////////////////////////////////////////////////////// -void NodeChain:: -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 NodeChain is clear. - (*this) = NodeChain::removed(); - return; - } - - uncollapse_head(); - PandaNode::detach(_head); - - (*this) = NodeChain::removed(); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_rel_state -// Access: Published -// Description: Returns the state changes that must be made to -// transition from the render state of this node to the -// render state of the other node. -//////////////////////////////////////////////////////////////////// -CPT(RenderState) NodeChain:: -get_rel_state(const NodeChain &other) const { - if (is_empty()) { - return other.get_net_state(); - } - if (other.is_empty()) { - return get_net_state()->invert_compose(RenderState::make_empty()); - } - - nassertr(verify_complete(), RenderState::make_empty()); - nassertr(other.verify_complete(), RenderState::make_empty()); - - int a_count, b_count; - find_common_ancestor(*this, other, a_count, b_count); - - CPT(RenderState) a_state = r_get_partial_state(_head, a_count); - CPT(RenderState) b_state = r_get_partial_state(other._head, b_count); - return a_state->invert_compose(b_state); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::get_rel_transform -// Access: Published -// Description: Returns the relative transform from this node to the -// other node; i.e. the transformation of the other node -// as seen from this node. -//////////////////////////////////////////////////////////////////// -CPT(TransformState) NodeChain:: -get_rel_transform(const NodeChain &other) const { - if (is_empty()) { - return other.get_net_transform(); - } - if (other.is_empty()) { - return get_net_transform()->invert_compose(TransformState::make_identity()); - } - - nassertr(verify_complete(), TransformState::make_identity()); - nassertr(other.verify_complete(), TransformState::make_identity()); - - int a_count, b_count; - find_common_ancestor(*this, other, a_count, b_count); - - CPT(TransformState) a_transform = r_get_partial_transform(_head, a_count); - CPT(TransformState) b_transform = r_get_partial_transform(other._head, b_count); - return a_transform->invert_compose(b_transform); -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::verify_complete -// Access: Published -// Description: Returns true if all of the nodes described in the -// NodeChain are connected *and* the top node is the top -// of the graph, or false otherwise. -//////////////////////////////////////////////////////////////////// -bool NodeChain:: -verify_complete() const { - if (is_empty()) { - return true; - } - - uncollapse_head(); - const NodeChainComponent *comp = _head; - nassertr(comp != (const NodeChainComponent *)NULL, false); - - PandaNode *node = comp->get_node(); - nassertr(node != (const PandaNode *)NULL, false); - int length = comp->get_length(); - - comp = comp->get_next(); - length--; - while (comp != (const NodeChainComponent *)NULL) { - PandaNode *next_node = comp->get_node(); - nassertr(next_node != (const PandaNode *)NULL, false); - - if (next_node->find_child(node) < 0) { - return false; - } - - if (comp->get_length() != length) { - return false; - } - - node = next_node; - comp = comp->get_next(); - length--; - } - - // Now that we've reached the top, we should have no parents. - return length == 0 && node->get_num_parents() == 0; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::uncollapse_head -// Access: Private -// Description: Quietly and transparently uncollapses the _head -// pointer if it needs it. -//////////////////////////////////////////////////////////////////// -void NodeChain:: -uncollapse_head() const { - if (_head != (NodeChainComponent *)NULL && _head->is_collapsed()) { - ((NodeChain *)this)->_head = _head->uncollapse(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::find_common_ancestor -// Access: Private, Static -// Description: Walks up from both NodeChains to find the first node -// that both have in common, if any. Fills a_count and -// b_count with the number of nodes below the common -// node in each chain. -//////////////////////////////////////////////////////////////////// -void NodeChain:: -find_common_ancestor(const NodeChain &a, const NodeChain &b, - int &a_count, int &b_count) { - nassertv(!a.is_empty() && !b.is_empty()); - a.uncollapse_head(); - b.uncollapse_head(); - - NodeChainComponent *ac = a._head; - NodeChainComponent *bc = b._head; - a_count = 0; - b_count = 0; - - // Shorten up the longer one until they are the same length. - while (ac->get_length() > bc->get_length()) { - nassertv(ac != (NodeChainComponent *)NULL); - ac = ac->get_next(); - a_count++; - } - while (bc->get_length() > ac->get_length()) { - nassertv(bc != (NodeChainComponent *)NULL); - bc = bc->get_next(); - b_count++; - } - - // Now shorten them both up until we reach the same component. - while (ac != bc) { - // These shouldn't go to NULL unless they both go there together. - nassertv(ac != (NodeChainComponent *)NULL); - nassertv(bc != (NodeChainComponent *)NULL); - ac = ac->get_next(); - a_count++; - bc = bc->get_next(); - b_count++; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::r_get_net_state -// Access: Private -// Description: Recursively determines the net state chnages to the -// indicated component node from the root of the graph. -//////////////////////////////////////////////////////////////////// -CPT(RenderState) NodeChain:: -r_get_net_state(NodeChainComponent *comp) const { - if (comp == (NodeChainComponent *)NULL) { - return RenderState::make_empty(); - } else { - CPT(RenderState) state = comp->get_node()->get_state(); - return r_get_net_state(comp->get_next())->compose(state); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::r_get_partial_state -// Access: Private -// Description: Recursively determines the net state changes to the -// indicated component node from the nth node above it. -//////////////////////////////////////////////////////////////////// -CPT(RenderState) NodeChain:: -r_get_partial_state(NodeChainComponent *comp, int n) const { - nassertr(comp != (NodeChainComponent *)NULL, RenderState::make_empty()); - if (n == 0) { - return RenderState::make_empty(); - } else { - CPT(RenderState) state = comp->get_node()->get_state(); - return r_get_partial_state(comp->get_next(), n - 1)->compose(state); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::r_get_net_transform -// Access: Private -// Description: Recursively determines the net transform to the -// indicated component node from the root of the graph. -//////////////////////////////////////////////////////////////////// -CPT(TransformState) NodeChain:: -r_get_net_transform(NodeChainComponent *comp) const { - if (comp == (NodeChainComponent *)NULL) { - return TransformState::make_identity(); - } else { - CPT(TransformState) transform = comp->get_node()->get_transform(); - return r_get_net_transform(comp->get_next())->compose(transform); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::r_get_partial_transform -// Access: Private -// Description: Recursively determines the net transform to the -// indicated component node from the nth node above it. -//////////////////////////////////////////////////////////////////// -CPT(TransformState) NodeChain:: -r_get_partial_transform(NodeChainComponent *comp, int n) const { - nassertr(comp != (NodeChainComponent *)NULL, TransformState::make_identity()); - if (n == 0) { - return TransformState::make_identity(); - } else { - CPT(TransformState) transform = comp->get_node()->get_transform(); - return r_get_partial_transform(comp->get_next(), n - 1)->compose(transform); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::r_output -// Access: Private -// Description: The recursive implementation of output(), this writes -// the names of each node component in order from -// beginning to end, by first walking to the end of the -// linked list and then outputting from there. -//////////////////////////////////////////////////////////////////// -void NodeChain:: -r_output(ostream &out, NodeChainComponent *comp) const { - NodeChainComponent *next = comp->get_next(); - if (next != (NodeChainComponent *)NULL) { - // This is not the head of the list; keep going up. - r_output(out, next); - out << "/"; - } - - // Now output this component. - PandaNode *node = comp->get_node(); - if (node->has_name()) { - out << node->get_name(); - } else { - out << "+" << node->get_type(); - } - out << "[" << comp->get_length() << "]"; -} - -//////////////////////////////////////////////////////////////////// -// Function: NodeChain::r_compare_to -// Access: Private, Static -// Description: The recursive implementation of compare_to(). Returns -// < 0 if a sorts before b, > 0 if b sorts before a, or -// == 0 if they are equivalent. -//////////////////////////////////////////////////////////////////// -int NodeChain:: -r_compare_to(const NodeChainComponent *a, const NodeChainComponent *b) { - if (a == b) { - return 0; - - } else if (a == (const NodeChainComponent *)NULL) { - return -1; - - } else if (b == (const NodeChainComponent *)NULL) { - return 1; - - } else if (a->get_node() != b->get_node()) { - return a->get_node() - b->get_node(); - - } else { - return r_compare_to(a->get_next(), b->get_next()); - } -} diff --git a/panda/src/pgraph/nodeChain.h b/panda/src/pgraph/nodeChain.h deleted file mode 100644 index 0ef9512287..0000000000 --- a/panda/src/pgraph/nodeChain.h +++ /dev/null @@ -1,176 +0,0 @@ -// Filename: nodeChain.h -// Created by: drose (25Feb02) -// -//////////////////////////////////////////////////////////////////// -// -// 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 NODECHAIN_H -#define NODECHAIN_H - -#include "pandabase.h" - -#include "pandaNode.h" -#include "renderState.h" -#include "transformState.h" -#include "nodeChainComponent.h" - -#include "pointerTo.h" -#include "referenceCount.h" -#include "notify.h" -#include "typedObject.h" - -//////////////////////////////////////////////////////////////////// -// Class : NodeChain -// Description : A NodeChain is the fundamental system for -// disambiguating instances and manipulating the scene -// graph. NodeChain is the base class of NodePath, -// which adds a bit more high-level functionality, but -// the fundamental scene graph manipulations are defined -// at the NodeChain level. -// -// A NodeChain is a list of connected nodes from the -// root of the graph to any sub-node. Each NodeChain -// therefore unqiuely describes one instance of a node. -// -// NodeChains themselves are lightweight objects that -// may easily be copied and passed by value. Their data -// is stored as a series of NodeChainComponents that are -// stored on the nodes. Holding a NodeChain will keep a -// reference count to all the nodes in the chain. -// However, if any node in the chain is removed or -// reparented (perhaps through a different NodeChain), -// the NodeChain will automatically be updated to -// reflect the changes. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA NodeChain { -PUBLISHED: - // This enumeration is returned by get_error_type() for an empty - // NodeChain to report the reason it's empty. - enum ErrorType { - ET_ok = 0, // i.e. not empty, or never assigned to anything. - ET_not_found, // returned from a failed find() or similar function. - ET_removed, // remove_node() was previously called on this NodeChain. - ET_fail, // general failure return from some function. - }; - - INLINE NodeChain(); - INLINE NodeChain(PandaNode *top_node); - INLINE NodeChain(const NodeChain ©); - INLINE void operator = (const NodeChain ©); - - INLINE static NodeChain not_found(); - INLINE static NodeChain removed(); - INLINE static NodeChain fail(); - - // Methods to query a NodeChain's contents. - INLINE bool is_empty() const; - INLINE bool is_singleton() const; - int get_num_nodes() const; - PandaNode *get_node(int index) const; - - INLINE ErrorType get_error_type() const; - - PandaNode *get_top_node() const; - INLINE PandaNode *node() const; - - // Methods that return collections of NodePaths derived from or - // related to this one. - - /* - NodeChainCollection get_siblings() const; - NodeChainCollection get_children() const; - */ - INLINE int get_num_children() const; - INLINE NodeChain get_child(int n) const; - - INLINE bool has_parent() const; - INLINE NodeChain get_parent() const; - - /* - INLINE NodeChain find_path_down_to(Node *dnode) const; - INLINE NodeChain find(const string &chain) const; - - NodeChainCollection - find_all_paths_down_to(Node *dnode) const; - - NodeChainCollection - find_all_matches(const string &chain) const; - */ - - // Methods that actually move nodes around in the scene graph. The - // optional "sort" parameter can be used to force a particular - // ordering between sibling nodes, useful when dealing with LOD's - // and similar switch nodes. If the sort value is the same, nodes - // will be arranged in the order they were added. - void reparent_to(const NodeChain &other, int sort = 0); - void wrt_reparent_to(const NodeChain &other, int sort = 0); - NodeChain instance_to(const NodeChain &other, int sort = 0) const; - NodeChain copy_to(const NodeChain &other, int sort = 0) const; - NodeChain attach_new_node(PandaNode *node, int sort = 0) const; - INLINE NodeChain attach_new_node(const string &name, int sort = 0) const; - void remove_node(); - - - // Relative transform and state changes between nodes. - CPT(RenderState) get_rel_state(const NodeChain &other) const; - INLINE CPT(RenderState) get_net_state() const; - - CPT(TransformState) get_rel_transform(const NodeChain &other) const; - INLINE CPT(TransformState) get_net_transform() const; - - INLINE const LMatrix4f &get_mat(const NodeChain &other) const; - - bool verify_complete() const; - -public: - INLINE bool operator == (const NodeChain &other) const; - INLINE bool operator != (const NodeChain &other) const; - INLINE bool operator < (const NodeChain &other) const; - INLINE int compare_to(const NodeChain &other) const; - - INLINE void output(ostream &out) const; - -private: - void uncollapse_head() const; - static void find_common_ancestor(const NodeChain &a, const NodeChain &b, - int &a_count, int &b_count); - - CPT(RenderState) r_get_net_state(NodeChainComponent *comp) const; - CPT(RenderState) r_get_partial_state(NodeChainComponent *comp, int n) const; - CPT(TransformState) r_get_net_transform(NodeChainComponent *comp) const; - CPT(TransformState) r_get_partial_transform(NodeChainComponent *comp, int n) const; - void r_output(ostream &out, NodeChainComponent *comp) const; - static int r_compare_to(const NodeChainComponent *a, const NodeChainComponent *v); - - PT(NodeChainComponent) _head; - ErrorType _error_type; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - register_type(_type_handle, "NodeChain"); - } - -private: - static TypeHandle _type_handle; -}; - -INLINE ostream &operator << (ostream &out, const NodeChain &node_chain); - -#include "nodeChain.I" - -#endif diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index 6c61c616d9..002e69021b 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -271,6 +271,20 @@ get_attrib(TypeHandle type) const { return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::has_attrib +// Access: Published +// Description: Returns true if there is a render attribute of the +// indicated type defined on this node, or false if +// there is not. +//////////////////////////////////////////////////////////////////// +INLINE bool PandaNode:: +has_attrib(TypeHandle type) const { + CDReader cdata(_cycler); + int index = cdata->_state->find_attrib(type); + return (index >= 0); +} + //////////////////////////////////////////////////////////////////// // Function: PandaNode::clear_attrib // Access: Published @@ -370,17 +384,6 @@ clear_transform() { cdata->_transform = TransformState::make_identity(); } -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::ls -// Access: Published -// Description: Lists all the nodes at and below the current path -// hierarchically. -//////////////////////////////////////////////////////////////////// -INLINE void PandaNode:: -ls() const { - ls(nout); -} - //////////////////////////////////////////////////////////////////// // Function: PandaNode::ls // Access: Published diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 8853002bc4..13cefa8190 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -18,7 +18,7 @@ #include "pandaNode.h" #include "config_pgraph.h" -#include "nodeChainComponent.h" +#include "qpnodePathComponent.h" #include "bamReader.h" #include "bamWriter.h" #include "indent.h" @@ -369,7 +369,7 @@ add_child(PandaNode *child_node, int sort) { cdata->_down.insert(DownConnection(child_node, sort)); cdata_child->_up.insert(UpConnection(this)); - // We also have to adjust any NodeChainComponents the child might + // We also have to adjust any qpNodePathComponents the child might // have that reference the child as a top node. Any other // components we can leave alone, because we are making a new // instance of the child. @@ -402,24 +402,24 @@ remove_child(int n) { int num_erased = cdata_child->_up.erase(UpConnection(this)); nassertv(num_erased == 1); - // Now sever any NodeChainComponents on the child that reference + // Now sever any qpNodePathComponents on the child that reference // this node. If we have multiple of these, we have to collapse // them together. - NodeChainComponent *collapsed = (NodeChainComponent *)NULL; + qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL; Chains::iterator ci; ci = cdata_child->_chains.begin(); while (ci != cdata_child->_chains.end()) { Chains::iterator cnext = ci; ++cnext; if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) { - if (collapsed == (NodeChainComponent *)NULL) { + if (collapsed == (qpNodePathComponent *)NULL) { (*ci)->set_top_node(); collapsed = (*ci); } else { // This is a different component that used to reference a // different instance, but now it's all just the same topnode. // We have to collapse this and the previous one together. - // However, there might be some NodeChains out there that + // However, there might be some qpNodePaths out there that // still keep a pointer to this one, so we can't remove it // altogether. (*ci)->collapse_with(collapsed); @@ -453,17 +453,17 @@ remove_child(PandaNode *child_node) { return false; } - // Now sever any NodeChainComponents on the child that reference + // Now sever any qpNodePathComponents on the child that reference // this node. If we have multiple of these, we have to collapse // them together (see above). - NodeChainComponent *collapsed = (NodeChainComponent *)NULL; + qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL; Chains::iterator ci; ci = cdata_child->_chains.begin(); while (ci != cdata_child->_chains.end()) { Chains::iterator cnext = ci; ++cnext; if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) { - if (collapsed == (NodeChainComponent *)NULL) { + if (collapsed == (qpNodePathComponent *)NULL) { (*ci)->set_top_node(); collapsed = (*ci); } else { @@ -506,17 +506,17 @@ remove_all_children() { CDWriter cdata_child(child_node->_cycler); cdata_child->_up.erase(UpConnection(this)); - // Now sever any NodeChainComponents on the child that reference + // Now sever any qpNodePathComponents on the child that reference // this node. If we have multiple of these, we have to collapse // them together (see above). - NodeChainComponent *collapsed = (NodeChainComponent *)NULL; + qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL; Chains::iterator ci; ci = cdata_child->_chains.begin(); while (ci != cdata_child->_chains.end()) { Chains::iterator cnext = ci; ++cnext; if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) { - if (collapsed == (NodeChainComponent *)NULL) { + if (collapsed == (qpNodePathComponent *)NULL) { (*ci)->set_top_node(); collapsed = (*ci); } else { @@ -675,19 +675,19 @@ recompute_internal_bound() { // Function: PandaNode::attach // Access: Private, Static // Description: Creates a new parent-child relationship, and returns -// the new NodeChainComponent. If the child was already +// the new qpNodePathComponent. If the child was already // attached to the indicated parent, repositions it and -// returns the original NodeChainComponent. +// returns the original qpNodePathComponent. //////////////////////////////////////////////////////////////////// -PT(NodeChainComponent) PandaNode:: -attach(NodeChainComponent *parent, PandaNode *child_node, int sort) { - nassertr(parent != (NodeChainComponent *)NULL, (NodeChainComponent *)NULL); +PT(qpNodePathComponent) PandaNode:: +attach(qpNodePathComponent *parent, PandaNode *child_node, int sort) { + nassertr(parent != (qpNodePathComponent *)NULL, (qpNodePathComponent *)NULL); // See if the child was already attached to the parent. If it was, - // we'll use that same NodeChainComponent. - PT(NodeChainComponent) child = get_component(parent, child_node); + // we'll use that same qpNodePathComponent. + PT(qpNodePathComponent) child = get_component(parent, child_node); - if (child == (NodeChainComponent *)NULL) { + if (child == (qpNodePathComponent *)NULL) { // The child was not already attached to the parent, so get a new // component. child = get_top_component(child_node); @@ -703,13 +703,13 @@ attach(NodeChainComponent *parent, PandaNode *child_node, int sort) { // Description: Breaks a parent-child relationship. //////////////////////////////////////////////////////////////////// void PandaNode:: -detach(NodeChainComponent *child) { - nassertv(child != (NodeChainComponent *)NULL); +detach(qpNodePathComponent *child) { + nassertv(child != (qpNodePathComponent *)NULL); nassertv(!child->is_top_node()); PandaNode *child_node = child->get_node(); PandaNode *parent_node = child->get_next()->get_node(); - // Break the NodeChainComponent connection. + // Break the qpNodePathComponent connection. child->set_top_node(); CDWriter cdata_child(child_node->_cycler); @@ -762,15 +762,15 @@ detach(NodeChainComponent *child) { // Description: Switches a node from one parent to another. //////////////////////////////////////////////////////////////////// void PandaNode:: -reparent(NodeChainComponent *new_parent, NodeChainComponent *child, int sort) { - nassertv(new_parent != (NodeChainComponent *)NULL); - nassertv(child != (NodeChainComponent *)NULL); +reparent(qpNodePathComponent *new_parent, qpNodePathComponent *child, int sort) { + nassertv(new_parent != (qpNodePathComponent *)NULL); + nassertv(child != (qpNodePathComponent *)NULL); if (!child->is_top_node()) { detach(child); } - // Adjust the NodeChainComponents. + // Adjust the qpNodePathComponents. child->set_next(new_parent); PandaNode *child_node = child->get_node(); @@ -790,19 +790,19 @@ reparent(NodeChainComponent *new_parent, NodeChainComponent *child, int sort) { //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_component // Access: Private, Static -// Description: Returns the NodeChainComponent based on the indicated +// Description: Returns the qpNodePathComponent based on the indicated // child of the given parent, or NULL if there is no // such parent-child relationship. //////////////////////////////////////////////////////////////////// -PT(NodeChainComponent) PandaNode:: -get_component(NodeChainComponent *parent, PandaNode *child_node) { - nassertr(parent != (NodeChainComponent *)NULL, (NodeChainComponent *)NULL); +PT(qpNodePathComponent) PandaNode:: +get_component(qpNodePathComponent *parent, PandaNode *child_node) { + nassertr(parent != (qpNodePathComponent *)NULL, (qpNodePathComponent *)NULL); PandaNode *parent_node = parent->get_node(); { CDReader cdata_child(child_node->_cycler); - // First, walk through the list of NodeChainComponents we already + // First, walk through the list of qpNodePathComponents we already // have on the child, looking for one that already exists, // referencing the indicated parent component. Chains::const_iterator ci; @@ -816,13 +816,13 @@ get_component(NodeChainComponent *parent, PandaNode *child_node) { } } - // We don't already have a NodeChainComponent referring to this + // We don't already have a qpNodePathComponent referring to this // parent-child relationship. Are they actually related? int child_index = child_node->find_parent(parent_node); if (child_index >= 0) { // They are. Create and return a new one. - PT(NodeChainComponent) child = - new NodeChainComponent(child_node, parent); + PT(qpNodePathComponent) child = + new qpNodePathComponent(child_node, parent); CDWriter cdata_child(child_node->_cycler); cdata_child->_chains.insert(child); return child; @@ -835,18 +835,18 @@ get_component(NodeChainComponent *parent, PandaNode *child_node) { //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_top_component // Access: Private, Static -// Description: Returns a NodeChainComponent referencing the +// Description: Returns a qpNodePathComponent referencing the // indicated node as a singleton. It is invalid to call // this for a node that has parents, unless you are // about to create a new instance (and immediately -// reconnect the NodeChainComponent elsewhere). +// reconnect the qpNodePathComponent elsewhere). //////////////////////////////////////////////////////////////////// -PT(NodeChainComponent) PandaNode:: +PT(qpNodePathComponent) PandaNode:: get_top_component(PandaNode *child_node) { { CDReader cdata_child(child_node->_cycler); - // Walk through the list of NodeChainComponents we already have on + // Walk through the list of qpNodePathComponents we already have on // the child, looking for one that already exists as a top node. Chains::const_iterator ci; for (ci = cdata_child->_chains.begin(); @@ -859,10 +859,10 @@ get_top_component(PandaNode *child_node) { } } - // We don't already have such a NodeChainComponent; create and + // We don't already have such a qpNodePathComponent; create and // return a new one. - PT(NodeChainComponent) child = - new NodeChainComponent(child_node, (NodeChainComponent *)NULL); + PT(qpNodePathComponent) child = + new qpNodePathComponent(child_node, (qpNodePathComponent *)NULL); CDWriter cdata_child(child_node->_cycler); cdata_child->_chains.insert(child); @@ -872,13 +872,13 @@ get_top_component(PandaNode *child_node) { //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_generic_component // Access: Private -// Description: Returns a NodeChainComponent referencing this node as +// Description: Returns a qpNodePathComponent referencing this node as // a chain from the root. It is only valid to call this // if there is an unambiguous path from the root; // otherwise, a warning will be issued and one path will // be chosen arbitrarily. //////////////////////////////////////////////////////////////////// -PT(NodeChainComponent) PandaNode:: +PT(qpNodePathComponent) PandaNode:: get_generic_component() { int num_parents = get_num_parents(); if (num_parents == 0) { @@ -890,7 +890,7 @@ get_generic_component() { << *this << " has " << num_parents << " parents; choosing arbitrary path to root.\n"; } - PT(NodeChainComponent) parent = get_parent(0)->get_generic_component(); + PT(qpNodePathComponent) parent = get_parent(0)->get_generic_component(); return get_component(parent, this); } } @@ -898,12 +898,12 @@ get_generic_component() { //////////////////////////////////////////////////////////////////// // Function: PandaNode::delete_component // Access: Private -// Description: Removes a NodeChainComponent from the set prior to +// Description: Removes a qpNodePathComponent from the set prior to // its deletion. This should only be called by the -// NodeChainComponent destructor. +// qpNodePathComponent destructor. //////////////////////////////////////////////////////////////////// void PandaNode:: -delete_component(NodeChainComponent *component) { +delete_component(qpNodePathComponent *component) { // We have to remove the component from all of the pipeline stages, // not just the current one. int max_num_erased = 0; @@ -924,7 +924,7 @@ delete_component(NodeChainComponent *component) { // Function: PandaNode::fix_chain_lengths // Access: Private // Description: Recursively fixes the _length member of each -// NodeChainComponent at this level and below, after an +// qpNodePathComponent at this level and below, after an // add or delete child operation that might have messed // these up. //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 326f8dd36a..e92028b05d 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -37,7 +37,7 @@ #include "pointerTo.h" #include "notify.h" -class NodeChainComponent; +class qpNodePathComponent; class CullTraverserData; //////////////////////////////////////////////////////////////////// @@ -98,6 +98,7 @@ PUBLISHED: INLINE void set_attrib(const RenderAttrib *attrib, int override = 0); INLINE const RenderAttrib *get_attrib(TypeHandle type) const; + INLINE bool has_attrib(TypeHandle type) const; INLINE void clear_attrib(TypeHandle type); INLINE void set_state(const RenderState *state); @@ -111,8 +112,7 @@ PUBLISHED: virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level) const; - INLINE void ls() const; - INLINE void ls(ostream &out, int indent_level = 0) const; + INLINE void ls(ostream &out, int indent_level) const; // A node has two bounding volumes: the BoundedObject it inherits // from is the "external" bound and represnts the node and all of @@ -149,18 +149,18 @@ protected: BoundedObject _internal_bound; private: - // parent-child manipulation for NodeChain support. Don't try to + // parent-child manipulation for qpNodePath support. Don't try to // call these directly. - static PT(NodeChainComponent) attach(NodeChainComponent *parent, + static PT(qpNodePathComponent) attach(qpNodePathComponent *parent, PandaNode *child, int sort); - static void detach(NodeChainComponent *child); - static void reparent(NodeChainComponent *new_parent, - NodeChainComponent *child, int sort); - static PT(NodeChainComponent) get_component(NodeChainComponent *parent, + static void detach(qpNodePathComponent *child); + static void reparent(qpNodePathComponent *new_parent, + qpNodePathComponent *child, int sort); + static PT(qpNodePathComponent) get_component(qpNodePathComponent *parent, PandaNode *child); - static PT(NodeChainComponent) get_top_component(PandaNode *child); - PT(NodeChainComponent) get_generic_component(); - void delete_component(NodeChainComponent *component); + static PT(qpNodePathComponent) get_top_component(PandaNode *child); + PT(qpNodePathComponent) get_generic_component(); + void delete_component(qpNodePathComponent *component); void fix_chain_lengths(); void r_list_descendants(ostream &out, int indent_level) const; @@ -194,12 +194,12 @@ private: }; typedef ov_set Up; - // We also maintain a set of NodeChainComponents in the node. This + // We also maintain a set of qpNodePathComponents in the node. This // represents the set of instances of this node that we have - // requested a NodeChain for. We don't keep reference counts; when - // each NodeChainComponent destructs, it removes itself from this + // requested a qpNodePath for. We don't keep reference counts; when + // each qpNodePathComponent destructs, it removes itself from this // set. - typedef pset Chains; + typedef pset Chains; // This is the data that must be cycled between pipeline stages. class EXPCL_PANDA CData : public CycleData { @@ -271,8 +271,8 @@ private: static TypeHandle _type_handle; friend class PandaNode::Children; - friend class NodeChain; - friend class NodeChainComponent; + friend class qpNodePath; + friend class qpNodePathComponent; }; INLINE ostream &operator << (ostream &out, const PandaNode &node) { diff --git a/panda/src/pgraph/pgraph_composite2.cxx b/panda/src/pgraph/pgraph_composite2.cxx index 2fbfabfdda..ad25f5a4e1 100644 --- a/panda/src/pgraph/pgraph_composite2.cxx +++ b/panda/src/pgraph/pgraph_composite2.cxx @@ -6,8 +6,9 @@ #include "qplensNode.cxx" #include "qplodNode.cxx" #include "materialAttrib.cxx" -#include "nodeChain.cxx" -#include "nodeChainComponent.cxx" +#include "qpnodePath.cxx" +#include "qpnodePathCollection.cxx" +#include "qpnodePathComponent.cxx" #include "pandaNode.cxx" #include "renderAttrib.cxx" #include "renderState.cxx" diff --git a/panda/src/pgraph/qpcamera.I b/panda/src/pgraph/qpcamera.I index f9bb292e10..4fa5810aa1 100644 --- a/panda/src/pgraph/qpcamera.I +++ b/panda/src/pgraph/qpcamera.I @@ -48,7 +48,7 @@ is_active() const { // represent the root of any subgraph. //////////////////////////////////////////////////////////////////// INLINE void qpCamera:: -set_scene(const NodeChain &scene) { +set_scene(const qpNodePath &scene) { _scene = scene; } @@ -58,7 +58,7 @@ set_scene(const NodeChain &scene) { // Description: Returns the scene that will be rendered by the // camera. See set_scene(). //////////////////////////////////////////////////////////////////// -INLINE const NodeChain &qpCamera:: +INLINE const qpNodePath &qpCamera:: get_scene() const { return _scene; } diff --git a/panda/src/pgraph/qpcamera.h b/panda/src/pgraph/qpcamera.h index 83d2b67ebf..1a24455404 100644 --- a/panda/src/pgraph/qpcamera.h +++ b/panda/src/pgraph/qpcamera.h @@ -22,7 +22,7 @@ #include "pandabase.h" #include "qplensNode.h" -#include "nodeChain.h" +#include "qpnodePath.h" class DisplayRegion; @@ -49,8 +49,8 @@ PUBLISHED: INLINE void set_active(bool active); INLINE bool is_active() const; - INLINE void set_scene(const NodeChain &scene); - INLINE const NodeChain &get_scene() const; + INLINE void set_scene(const qpNodePath &scene); + INLINE const qpNodePath &get_scene() const; INLINE int get_num_display_regions() const; INLINE DisplayRegion *get_display_region(int n) const; @@ -60,7 +60,7 @@ private: void remove_display_region(DisplayRegion *display_region); bool _active; - NodeChain _scene; + qpNodePath _scene; typedef pvector DisplayRegions; DisplayRegions _display_regions; diff --git a/panda/src/pgraph/qpcullTraverser.h b/panda/src/pgraph/qpcullTraverser.h index 877141d45c..975e118f4f 100644 --- a/panda/src/pgraph/qpcullTraverser.h +++ b/panda/src/pgraph/qpcullTraverser.h @@ -29,6 +29,7 @@ class PandaNode; class CullHandler; class CullTraverserData; +class CullableObject; //////////////////////////////////////////////////////////////////// // Class : CullTraverser diff --git a/panda/src/pgraph/qpnodePath.I b/panda/src/pgraph/qpnodePath.I new file mode 100644 index 0000000000..99d64bc42b --- /dev/null +++ b/panda/src/pgraph/qpnodePath.I @@ -0,0 +1,1086 @@ +// Filename: qpnodePath.I +// Created by: drose (25Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// 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: qpNodePath::Default Constructor +// Access: Published +// Description: This constructs an empty qpNodePath with no nodes. It +// cannot be extended, since you cannot add nodes without +// first specifying the top node. Use the constructor +// that receives a node if you ever want to do anything +// with this path. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath:: +qpNodePath() : + _error_type(ET_ok) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::Constructor +// Access: Published +// Description: This constructs an empty qpNodePath with a single node. +// This path may now be extended by repeatedly calling +// push_back() with each node below that node in +// sequence. +// +// If the Node pointer is NULL, this quietly creates an +// empty qpNodePath. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath:: +qpNodePath(PandaNode *top_node) : + _error_type(ET_ok) +{ + if (top_node != (PandaNode *)NULL) { + _head = top_node->get_generic_component(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath:: +qpNodePath(const qpNodePath ©) : + _head(copy._head), + _error_type(copy._error_type) +{ + uncollapse_head(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +operator = (const qpNodePath ©) { + _head = copy._head; + _error_type = copy._error_type; + uncollapse_head(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::not_found named constructor +// Access: Published, Static +// Description: Creates a qpNodePath with the ET_not_found error type +// set. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath qpNodePath:: +not_found() { + qpNodePath result; + result._error_type = ET_not_found; + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::removed named constructor +// Access: Published, Static +// Description: Creates a qpNodePath with the ET_removed error type +// set. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath qpNodePath:: +removed() { + qpNodePath result; + result._error_type = ET_removed; + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::fail named constructor +// Access: Published, Static +// Description: Creates a qpNodePath with the ET_fail error type +// set. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath qpNodePath:: +fail() { + qpNodePath result; + result._error_type = ET_fail; + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::is_empty +// Access: Published +// Description: Returns true if the qpNodePath contains no nodes. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +is_empty() const { + return (_head == (qpNodePathComponent *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::is_singleton +// Access: Published +// Description: Returns true if the qpNodePath contains exactly one +// node. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +is_singleton() const { + uncollapse_head(); + return (_head != (qpNodePathComponent *)NULL && _head->is_top_node()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_error_type +// Access: Published +// Description: If is_empty() is true, this returns a code that +// represents the reason why the qpNodePath is empty. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath::ErrorType qpNodePath:: +get_error_type() const { + return _error_type; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::node +// Access: Published +// Description: Returns the referenced node of the path, or NULL if the +// path is empty. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *qpNodePath:: +node() const { + if (is_empty()) { + return (PandaNode *)NULL; + } + return _head->get_node(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_num_children +// Access: Published +// Description: Returns the number of children of the referenced node. +//////////////////////////////////////////////////////////////////// +INLINE int qpNodePath:: +get_num_children() const { + nassertr(!is_empty(), 0); + return _head->get_node()->get_num_children(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_child +// Access: Published +// Description: Returns a qpNodePath representing the nth child of the +// referenced node. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath qpNodePath:: +get_child(int n) const { + nassertr(n >= 0 && n < get_num_children(), qpNodePath()); + qpNodePath child; + child._head = PandaNode::get_component(_head, _head->get_node()->get_child(n)); + return child; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_parent +// Access: Published +// Description: Returns true if the referenced node has a parent; +// i.e. the NodePath chain contains at least two nodes. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +has_parent() const { + return !is_empty() && !is_singleton(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_parent +// Access: Published +// Description: Returns the qpNodePath to the parent of the referenced +// node: that is, this qpNodePath, shortened by one node. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath qpNodePath:: +get_parent() const { + nassertr(has_parent(), qpNodePath::fail()); + qpNodePath parent; + parent._head = _head->get_next(); + return parent; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::attach_new_node +// Access: Published +// Description: Creates an ordinary PandaNode and attaches it below +// the current qpNodePath, returning a new qpNodePath that +// references it. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath qpNodePath:: +attach_new_node(const string &name, int sort) const { + nassertr(verify_complete(), qpNodePath::fail()); + nassertr(!is_empty(), *this); + + return attach_new_node(new PandaNode(name), sort); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::output +// Access: Published +// Description: Writes a sensible description of the qpNodePath to the +// indicated output stream. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +output(ostream &out) const { + if (_head == (qpNodePathComponent *)NULL) { + out << "(empty)"; + } else { + r_output(out, _head); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::ls +// Access: Published +// Description: Lists the hierarchy at and below the referenced node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +ls() const { + ls(nout); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::ls +// Access: Published +// Description: Lists the hierarchy at and below the referenced node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +ls(ostream &out, int indent_level) const { + if (is_empty()) { + out << "(empty)\n"; + } else { + node()->ls(out, indent_level); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::ls_transitions +// Access: Published +// Description: Lists the hierarchy at and below the referenced node, +// along with the state transitions at each level. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +ls_transitions() const { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::ls_transforms +// Access: Published +// Description: Lists the hierarchy at and below the referenced node, +// along with the transforms at each level. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +ls_transforms() const { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_state +// Access: Published +// Description: Returns the complete state object set on this node. +//////////////////////////////////////////////////////////////////// +INLINE CPT(RenderState) qpNodePath:: +get_state() const { + nassertr(!is_empty(), RenderState::make_empty()); + return node()->get_state(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_state +// Access: Published +// Description: Changes the complete state object on this node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_state(const RenderState *state) const { + nassertv(!is_empty()); + node()->set_state(state); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_net_state +// Access: Published +// Description: Returns the net state on this node from the root. +//////////////////////////////////////////////////////////////////// +INLINE CPT(RenderState) qpNodePath:: +get_net_state() const { + uncollapse_head(); + return r_get_net_state(_head); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_transform +// Access: Published +// Description: Returns the complete transform object set on this node. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) qpNodePath:: +get_transform() const { + nassertr(!is_empty(), TransformState::make_identity()); + return node()->get_transform(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_transform +// Access: Published +// Description: Changes the complete transform object on this node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_transform(const TransformState *transform) const { + nassertv(!is_empty()); + node()->set_transform(transform); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_net_transform +// Access: Published +// Description: Returns the net transform on this node from the root. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) qpNodePath:: +get_net_transform() const { + uncollapse_head(); + return r_get_net_transform(_head); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos +// Access: Published +// Description: Sets the translation component of the transform, +// leaving rotation and scale untouched. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_pos(float x, float y, float z) { + set_pos(LPoint3f(x, y, z)); +} + +INLINE float qpNodePath:: +get_x() const { + return get_pos()[0]; +} + +INLINE float qpNodePath:: +get_y() const { + return get_pos()[1]; +} + +INLINE float qpNodePath:: +get_z() const { + return get_pos()[2]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_hpr +// Access: Published +// Description: Sets the rotation component of the transform, +// leaving translation and scale untouched. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_hpr(float h, float p, float r) { + set_hpr(LVecBase3f(h, p, r)); +} + +INLINE float qpNodePath:: +get_h() const { + return get_hpr()[0]; +} + +INLINE float qpNodePath:: +get_p() const { + return get_hpr()[1]; +} + +INLINE float qpNodePath:: +get_r() const { + return get_hpr()[2]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_scale +// Access: Published +// Description: Sets the scale component of the transform, +// leaving translation and rotation untouched. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_scale(float scale) { + set_scale(LVecBase3f(scale, scale, scale)); +} + +INLINE void qpNodePath:: +set_scale(float sx, float sy, float sz) { + set_scale(LVecBase3f(sx, sy, sz)); +} + +INLINE float qpNodePath:: +get_sx() const { + return get_scale()[0]; +} + +INLINE float qpNodePath:: +get_sy() const { + return get_scale()[1]; +} + +INLINE float qpNodePath:: +get_sz() const { + return get_scale()[2]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos_hpr +// Access: Published +// Description: Sets the translation and rotation component of the +// transform, leaving scale untouched. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_pos_hpr(float x, float y, float z, float h, float p, float r) { + set_pos_hpr(LVecBase3f(x, y, z), LVecBase3f(h, p, r)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_hpr_scale +// Access: Published +// Description: Sets the rotation and scale components of the +// transform, leaving translation untouched. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_hpr_scale(float h, float p, float r, float sx, float sy, float sz) { + set_hpr_scale(LVecBase3f(h, p, r), LVecBase3f(sx, sy, sz)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos_hpr_scale +// Access: Published +// Description: Completely replaces the transform with new +// translation, rotation, and scale components. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_pos_hpr_scale(float x, float y, float z, float h, float p, float r, + float sx, float sy, float sz) { + set_pos_hpr_scale(LVecBase3f(x, y, z), LVecBase3f(h, p, r), + LVecBase3f(sx, sy, sz)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_mat +// Access: Published +// Description: Completely removes any transform from the referenced +// node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +clear_mat() { + nassertv(!is_empty()); + node()->clear_transform(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_mat +// Access: Published +// Description: Returns true if a non-identity transform matrix has +// been applied to the referenced node, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +has_mat() const { + nassertr(!is_empty(), false); + return !node()->get_transform()->is_identity(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_mat +// Access: Published +// Description: Returns the transform matrix that has been applied to +// the referenced node, or the identity matrix if no +// matrix has been applied. +//////////////////////////////////////////////////////////////////// +INLINE const LMatrix4f &qpNodePath:: +get_mat() const { + nassertr(!is_empty(), LMatrix4f::ident_mat()); + + return node()->get_transform()->get_mat(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_color_scale +// Access: Published +// Description: Returns true if a color scale has been applied +// to the referenced node, false otherwise. It is still +// possible that color at this node might have been +// scaled by an ancestor node. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +has_color_scale() const { + nassertr(false, false); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_color_scale +// Access: Published +// Description: Completely removes any color scale from the +// referenced node. This is preferable to simply +// setting the color scale to identity, as it also +// removes the overhead associated with having a color +// scale at all. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +clear_color_scale() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_color_scale +// Access: Published +// Description: Sets the color scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_color_scale(float sr, float sg, float sb, float sa) { + set_color_scale(LVecBase4f(sr, sg, sb, sa)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_sr +// Access: Published +// Description: Sets the red scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_sr(float sr) { + LVecBase4f new_scale = get_color_scale(); + new_scale[0] = sr; + + set_color_scale(new_scale); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_sg +// Access: Published +// Description: Sets the alpha scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_sg(float sg) { + LVecBase4f new_scale = get_color_scale(); + new_scale[1] = sg; + + set_color_scale(new_scale); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_sb +// Access: Published +// Description: Sets the blue scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_sb(float sb) { + LVecBase4f new_scale = get_color_scale(); + new_scale[2] = sb; + + set_color_scale(new_scale); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_sa +// Access: Published +// Description: Sets the alpha scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_sa(float sa) { + LVecBase4f new_scale = get_color_scale(); + new_scale[3] = sa; + + set_color_scale(new_scale); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_sr +// Access: Published +// Description: Gets the red scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE float qpNodePath:: +get_sr() const { + return get_color_scale()[0]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_sg +// Access: Published +// Description: Gets the green scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE float qpNodePath:: +get_sg() const { + return get_color_scale()[1]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_sb +// Access: Published +// Description: Gets the blue scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE float qpNodePath:: +get_sb() const { + return get_color_scale()[2]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_sa +// Access: Published +// Description: Gets the alpha scale component of the transform +//////////////////////////////////////////////////////////////////// +INLINE float qpNodePath:: +get_sa() const { + return get_color_scale()[3]; +} + + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::look_at +// Access: Published +// Description: Sets the transform on this qpNodePath so that it +// rotates to face the indicated point in space. This +// will overwrite any previously existing scale on the +// node, although it will preserve any translation. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +look_at(float x, float y, float z) { + look_at(LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::heads_up +// Access: Published +// Description: Behaves like look_at(), but with a strong preference +// to keeping the up vector oriented in the indicated +// "up" direction. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +heads_up(float x, float y, float z) { + heads_up(LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::look_at_preserve_scale +// Access: Published +// Description: Functions like look_at(), but preforms additional +// work to preserve any scales that may already be +// present on the node. Normally, look_at() blows away +// the scale because scale and rotation are represented +// in the same part of the matrix. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +look_at_preserve_scale(float x, float y, float z) { + look_at_preserve_scale(LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::heads_up_preserve_scale +// Access: Published +// Description: Functions like heads_up(), but preforms additional +// work to preserve any scales that may already be +// present on the node. Normally, heads_up() blows away +// the scale because scale and rotation are represented +// in the same part of the matrix. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +heads_up_preserve_scale(float x, float y, float z) { + heads_up_preserve_scale(LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos +// Access: Published +// Description: Sets the translation component of the transform, +// relative to the other node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_pos(const qpNodePath &other, float x, float y, float z) { + set_pos(other, LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_pos +// Access: Published +// Description: Returns the relative position of the referenced node +// as seen from the other node. +//////////////////////////////////////////////////////////////////// +INLINE LPoint3f qpNodePath:: +get_pos(const qpNodePath &other) const { + LMatrix4f mat = get_mat(other); + return mat.get_row3(3); +} + +INLINE float qpNodePath:: +get_x(const qpNodePath &other) const { + return get_pos(other)[0]; +} + +INLINE float qpNodePath:: +get_y(const qpNodePath &other) const { + return get_pos(other)[1]; +} + +INLINE float qpNodePath:: +get_z(const qpNodePath &other) const { + return get_pos(other)[2]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_hpr +// Access: Published +// Description: Sets the rotation component of the transform, +// relative to the other node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_hpr(const qpNodePath &other, float h, float p, float r) { + set_hpr(other, LPoint3f(h, p, r)); +} + +INLINE float qpNodePath:: +get_h(const qpNodePath &other) const { + return get_hpr(other)[0]; +} + +INLINE float qpNodePath:: +get_p(const qpNodePath &other) const { + return get_hpr(other)[1]; +} + +INLINE float qpNodePath:: +get_r(const qpNodePath &other) const { + return get_hpr(other)[2]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_scale +// Access: Published +// Description: Sets the scale component of the transform, +// relative to the other node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_scale(const qpNodePath &other, float sx, float sy, float sz) { + set_scale(other, LPoint3f(sx, sy, sz)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_scale +// Access: Published +// Description: Returns the relative scale of the referenced node +// as seen from the other node. +//////////////////////////////////////////////////////////////////// +INLINE float qpNodePath:: +get_sx(const qpNodePath &other) const { + return get_scale(other)[0]; +} + +INLINE float qpNodePath:: +get_sy(const qpNodePath &other) const { + return get_scale(other)[1]; +} + +INLINE float qpNodePath:: +get_sz(const qpNodePath &other) const { + return get_scale(other)[2]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos_hpr +// Access: Published +// Description: Sets the translation and rotation component of the +// transform, relative to the other node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_pos_hpr(const qpNodePath &other, + float x, float y, float z, + float h, float p, float r) { + set_pos_hpr(other, LVecBase3f(x, y, z), LVecBase3f(h, p, r)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_hpr_scale +// Access: Published +// Description: Sets the rotation and scale components of the +// transform, leaving translation untouched. This, or +// set_pos_hpr_scale, is the preferred way to update a +// transform when both hpr and scale are to be changed. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_hpr_scale(const qpNodePath &other, + float h, float p, float r, float sx, float sy, float sz) { + set_hpr_scale(other, LVecBase3f(h, p, r), LVecBase3f(sx, sy, sz)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos_hpr_scale +// Access: Published +// Description: Completely replaces the transform with new +// translation, rotation, and scale components, relative +// to the other node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +set_pos_hpr_scale(const qpNodePath &other, + float x, float y, float z, + float h, float p, float r, + float sx, float sy, float sz) { + set_pos_hpr_scale(other, LVecBase3f(x, y, z), LVecBase3f(h, p, r), + LVecBase3f(sx, sy, sz)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::look_at +// Access: Published +// Description: Sets the transform on this qpNodePath so that it +// rotates to face the indicated point in space, which +// is relative to the other qpNodePath. This +// will overwrite any previously existing scale on the +// node, although it will preserve any translation. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +look_at(const qpNodePath &other, float x, float y, float z) { + look_at(other, LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::heads_up +// Access: Published +// Description: Behaves like look_at(), but with a strong preference +// to keeping the up vector oriented in the indicated +// "up" direction. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +heads_up(const qpNodePath &other, float x, float y, float z) { + heads_up(other, LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::look_at_preserve_scale +// Access: Published +// Description: Functions like look_at(), but preforms additional +// work to preserve any scales that may already be +// present on the node. Normally, look_at() blows away +// the scale because scale and rotation are represented +// in the same part of the matrix. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +look_at_preserve_scale(const qpNodePath &other, float x, float y, float z) { + look_at_preserve_scale(other, LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::heads_up_preserve_scale +// Access: Published +// Description: Functions like heads_up(), but preforms additional +// work to preserve any scales that may already be +// present on the node. Normally, heads_up() blows away +// the scale because scale and rotation are represented +// in the same part of the matrix. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +heads_up_preserve_scale(const qpNodePath &other, float x, float y, float z) { + heads_up_preserve_scale(other, LPoint3f(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_distance +// Access: Published +// Description: Returns the straight-line distance between this +// referenced node's coordinate frame's origin, and that +// of the other node's origin. +//////////////////////////////////////////////////////////////////// +INLINE float qpNodePath:: +get_distance(const qpNodePath &other) const { + LPoint3f pos = get_pos(other); + return length(LVector3f(pos)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::adjust_all_priorities +// Access: Published +// Description: Adds the indicated adjustment amount (which may be +// negative) to the priority for all transitions on the +// referenced node, and for all nodes in the subgraph +// below. This can be used to force these nodes not to +// be overridden by a high-level state change above. If +// the priority would drop below zero, it is set to +// zero. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +adjust_all_priorities(int adjustment) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::show +// Access: Published +// Description: Undoes the effect of a previous hide() on this node: +// makes the referenced node (and the entire subgraph +// below this node) visible. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +show() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::hide +// Access: Published +// Description: Makes the referenced node (and the entire subgraph +// below this node) invisible to rendering. It remains +// part of the scene graph, its bounding volume still +// contributes to its parent's bounding volume, and it +// will still be involved in collision tests. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +hide() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::show_collision_solids +// Access: Published +// Description: Shows all the collision solids at and below the +// referenced node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +show_collision_solids() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::hide_collision_solids +// Access: Published +// Description: Hides all the collision solids at and below the +// referenced node. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +hide_collision_solids() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::is_hidden +// Access: Published +// Description: Returns true if the referenced node is hidden either +// directly, or because some ancestor is hidden. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +is_hidden() const { + nassertr(false, false); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::unstash +// Access: Published +// Description: Undoes the effect of a previous stash() on this +// node: makes the referenced node (and the entire +// subgraph below this node) once again part of the +// scene graph. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +unstash() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::stash +// Access: Published +// Description: Removes the referenced node (and the entire subgraph +// below this node) from the scene graph in any normal +// sense. The node will no longer be visible and is not +// tested for collisions; furthermore, no normal scene +// graph traversal will visit the node. The node's +// bounding volume no longer contributes to its parent's +// bounding volume. +// +// A stashed node cannot be located by a normal find() +// operation (although a special find string can still +// retrieve it). +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePath:: +stash() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::is_stashed +// Access: Published +// Description: Returns true if the referenced node is stashed either +// directly, or because some ancestor is stashed. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +is_stashed() const { + nassertr(false, false); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::operator == +// Access: Published +// Description: Returns true if the two paths are equivalent; that +// is, if they contain the same list of nodes in the same +// order. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +operator == (const qpNodePath &other) const { + return (compare_to(other) == 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::operator != +// Access: Published +// Description: Returns true if the two paths are not equivalent. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +operator != (const qpNodePath &other) const { + return (compare_to(other) != 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::operator < +// Access: Published +// Description: Returns true if this qpNodePath sorts before the other +// one, false otherwise. The sorting order of two +// nonequivalent qpNodePaths is consistent but undefined, +// and is useful only for storing qpNodePaths in a sorted +// container like an STL set. +//////////////////////////////////////////////////////////////////// +INLINE bool qpNodePath:: +operator < (const qpNodePath &other) const { + return (compare_to(other) < 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::compare_to +// Access: Published +// Description: Returns a number less than zero if this qpNodePath +// sorts before the other one, greater than zero if it +// sorts after, or zero if they are equivalent. +// +// Two qpNodePaths are considered equivalent if they +// consist of exactly the same list of nodes in the same +// order. Otherwise, they are different; different +// qpNodePaths will be ranked in a consistent but +// undefined ordering; the ordering is useful only for +// placing the qpNodePaths in a sorted container like an +// STL set. +//////////////////////////////////////////////////////////////////// +INLINE int qpNodePath:: +compare_to(const qpNodePath &other) const { + return r_compare_to(_head, other._head); +} + + +INLINE ostream &operator << (ostream &out, const qpNodePath &node_path) { + node_path.output(out); + return out; +} + diff --git a/panda/src/pgraph/qpnodePath.cxx b/panda/src/pgraph/qpnodePath.cxx new file mode 100644 index 0000000000..09a4371710 --- /dev/null +++ b/panda/src/pgraph/qpnodePath.cxx @@ -0,0 +1,2284 @@ +// Filename: qpnodePath.cxx +// Created by: drose (25Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "qpnodePath.h" +#include "qpnodePathCollection.h" +#include "node.h" +#include "namedNode.h" +#include "config_pgraph.h" +#include "plist.h" +#include "colorAttrib.h" +#include "cullBinAttrib.h" +#include "textureAttrib.h" +#include "materialAttrib.h" +#include "cullFaceAttrib.h" +#include "billboardAttrib.h" +#include "transparencyAttrib.h" +#include "materialPool.h" +#include "look_at.h" +#include "compose_matrix.h" + +TypeHandle qpNodePath::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_num_nodes +// Access: Published +// Description: Returns the number of nodes in the path. +//////////////////////////////////////////////////////////////////// +int qpNodePath:: +get_num_nodes() const { + if (is_empty()) { + return 0; + } + uncollapse_head(); + return _head->get_length(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_node +// Access: Published +// Description: Returns the nth node of the path, where 0 is the +// referenced (bottom) node and get_num_nodes() - 1 is +// the top node. This requires iterating through the +// path. +//////////////////////////////////////////////////////////////////// +PandaNode *qpNodePath:: +get_node(int index) const { + nassertr(index >= 0 && index < get_num_nodes(), NULL); + + uncollapse_head(); + qpNodePathComponent *comp = _head; + while (index > 0) { + // If this assertion fails, the index was out of range; the + // component's length must have been invalid. + nassertr(comp != (qpNodePathComponent *)NULL, NULL); + comp = comp->get_next(); + index--; + } + + // If this assertion fails, the index was out of range; the + // component's length must have been invalid. + nassertr(comp != (qpNodePathComponent *)NULL, NULL); + return comp->get_node(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_top_node +// Access: Published +// Description: Returns the top node of the path, or NULL if the path +// is empty. This requires iterating through the path. +//////////////////////////////////////////////////////////////////// +PandaNode *qpNodePath:: +get_top_node() const { + if (is_empty()) { + return (PandaNode *)NULL; + } + + uncollapse_head(); + qpNodePathComponent *comp = _head; + while (!comp->is_top_node()) { + comp = comp->get_next(); + nassertr(comp != (qpNodePathComponent *)NULL, NULL); + } + + return comp->get_node(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_children +// Access: Published +// Description: Returns the set of all child nodes of the referenced +// node. +//////////////////////////////////////////////////////////////////// +qpNodePathCollection qpNodePath:: +get_children() const { + qpNodePathCollection result; + nassertr(!is_empty(), result); + + PandaNode *bottom_node = node(); + + PandaNode::Children cr = bottom_node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + qpNodePath child; + child._head = PandaNode::get_component(_head, cr.get_child(i)); + result.add_path(child); + } + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::reparent_to +// Access: Published +// Description: Removes the referenced node of the qpNodePath from its +// current parent and attaches it to the referenced node of +// the indicated qpNodePath. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +reparent_to(const qpNodePath &other, int sort) { + nassertv(other.verify_complete()); + nassertv_always(!is_empty()); + nassertv_always(!other.is_empty()); + + uncollapse_head(); + other.uncollapse_head(); + PandaNode::reparent(other._head, _head, sort); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::wrt_reparent_to +// Access: Published +// Description: This functions identically to reparent_to(), except +// the transform on this node is also adjusted so that +// the node remains in the same place in world +// coordinates, even if it is reparented into a +// different coordinate system. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +wrt_reparent_to(const qpNodePath &other, int sort) { + nassertv(other.verify_complete()); + nassertv_always(!is_empty()); + nassertv_always(!other.is_empty()); + + set_transform(get_transform(other)); + reparent_to(other, sort); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::instance_to +// Access: Published +// Description: Adds the referenced node of the NodePath as a child +// of the referenced node of the indicated other +// NodePath. Any other parent-child relations of the +// node are unchanged; in particular, the node is not +// removed from its existing parent, if any. +// +// If the node already had an existing parent, this +// method will create a new instance of the node within +// the scene graph. +// +// This does not change the NodePath itself, but does +// return a new NodePath that reflects the new instance +// node. +//////////////////////////////////////////////////////////////////// +qpNodePath qpNodePath:: +instance_to(const qpNodePath &other, int sort) const { + nassertr(verify_complete(), qpNodePath::fail()); + nassertr(!is_empty(), qpNodePath::fail()); + nassertr(!other.is_empty(), qpNodePath::fail()); + + uncollapse_head(); + other.uncollapse_head(); + + qpNodePath new_instance; + new_instance._head = PandaNode::attach(other._head, node(), sort); + + return new_instance; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::copy_to +// Access: Published +// Description: Functions exactly like instance_to(), except a deep +// copy is made of the referenced node and all of its +// descendents, which is then parented to the indicated +// node. A qpNodePath to the newly created copy is +// returned. +// +// Certain kinds of nodes may not be copied; if one of +// these is encountered, the node will be "copied" as +// the nearest copyable base class. For instance, a +// Camera node in the graph will become a simple +// NamedNode. +//////////////////////////////////////////////////////////////////// +qpNodePath qpNodePath:: +copy_to(const qpNodePath &other, int sort) const { + //***** + return instance_to(other, sort); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::attach_new_node +// Access: Published +// Description: Attaches a new node, with or without existing +// parents, to the scene graph below the referenced node +// of this NodePath. This is the preferred way to add +// nodes to the graph. +// +// This does *not* automatically extend the current +// NodePath to reflect the attachment; however, a +// NodePath that does reflect this extension is +// returned. +//////////////////////////////////////////////////////////////////// +qpNodePath qpNodePath:: +attach_new_node(PandaNode *node, int sort) const { + nassertr(verify_complete(), qpNodePath::fail()); + nassertr(!is_empty(), qpNodePath()); + nassertr(node != (PandaNode *)NULL, qpNodePath()); + + uncollapse_head(); + qpNodePath new_path(*this); + new_path._head = PandaNode::attach(_head, node, sort); + return new_path; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::remove_node +// Access: Published +// Description: Disconnects the referenced node from the scene graph. +// This will also delete the node if there are no other +// pointers to it. +// +// Normally, this should be called only when you are +// really done with the node. If you want to remove a +// node from the scene graph but keep it around for +// later, you should probably use reparent_to() and put +// it under a holding node instead. +// +// After the node is removed, the qpNodePath will have +// been cleared. +//////////////////////////////////////////////////////////////////// +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. + (*this) = qpNodePath::removed(); + return; + } + + uncollapse_head(); + PandaNode::detach(_head); + + (*this) = qpNodePath::removed(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_state +// Access: Published +// Description: Returns the state changes that must be made to +// transition from the render state of this node to the +// render state of the other node. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) qpNodePath:: +get_state(const qpNodePath &other) const { + if (is_empty()) { + return other.get_net_state(); + } + if (other.is_empty()) { + return get_net_state()->invert_compose(RenderState::make_empty()); + } + + nassertr(verify_complete(), RenderState::make_empty()); + nassertr(other.verify_complete(), RenderState::make_empty()); + + int a_count, b_count; + find_common_ancestor(*this, other, a_count, b_count); + + CPT(RenderState) a_state = r_get_partial_state(_head, a_count); + CPT(RenderState) b_state = r_get_partial_state(other._head, b_count); + return a_state->invert_compose(b_state); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_state +// Access: Published +// Description: Sets the state object on this node, relative to +// the other node. This computes a new state object +// that has the indicated value when seen relative to +// the other node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_state(const qpNodePath &other, const RenderState *state) const { + nassertv(_error_type == ET_ok && other._error_type == ET_ok); + nassertv_always(!is_empty()); + + // First, we perform a wrt to the parent, to get the conversion. + qpNodePath parent = get_parent(); + CPT(RenderState) rel_state = parent.get_state(other); + + CPT(RenderState) new_state = rel_state->compose(state); + set_state(new_state); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_transform +// Access: Published +// Description: Returns the relative transform from this node to the +// other node; i.e. the transformation of the other node +// as seen from this node. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) qpNodePath:: +get_transform(const qpNodePath &other) const { + if (is_empty()) { + return other.get_net_transform(); + } + if (other.is_empty()) { + return get_net_transform()->invert_compose(TransformState::make_identity()); + } + + nassertr(verify_complete(), TransformState::make_identity()); + nassertr(other.verify_complete(), TransformState::make_identity()); + + int a_count, b_count; + find_common_ancestor(*this, other, a_count, b_count); + + CPT(TransformState) a_transform = r_get_partial_transform(_head, a_count); + CPT(TransformState) b_transform = r_get_partial_transform(other._head, b_count); + return a_transform->invert_compose(b_transform); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_transform +// Access: Published +// Description: Sets the transform object on this node, relative to +// the other node. This computes a new transform object +// that has the indicated value when seen relative to +// the other node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_transform(const qpNodePath &other, const TransformState *transform) const { + nassertv(_error_type == ET_ok && other._error_type == ET_ok); + nassertv_always(!is_empty()); + + // First, we perform a wrt to the parent, to get the conversion. + qpNodePath parent = get_parent(); + CPT(TransformState) rel_trans = parent.get_transform(other); + + CPT(TransformState) new_trans = rel_trans->compose(transform); + set_transform(new_trans); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos +// Access: Published +// Description: Sets the translation component of the transform, +// leaving rotation and scale untouched. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_pos(const LVecBase3f &pos) { + nassertv(!is_empty()); + set_transform(get_transform()->set_pos(pos)); +} + +void qpNodePath:: +set_x(float x) { + nassertv(!is_empty()); + LPoint3f pos = get_pos(); + pos[0] = x; + set_pos(pos); +} + +void qpNodePath:: +set_y(float y) { + nassertv(!is_empty()); + LPoint3f pos = get_pos(); + pos[1] = y; + set_pos(pos); +} + +void qpNodePath:: +set_z(float z) { + nassertv(!is_empty()); + LPoint3f pos = get_pos(); + pos[2] = z; + set_pos(pos); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_pos +// Access: Published +// Description: Retrieves the translation component of the transform. +//////////////////////////////////////////////////////////////////// +LPoint3f qpNodePath:: +get_pos() const { + nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f)); + return get_transform()->get_pos(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_hpr +// Access: Published +// Description: Sets the rotation component of the transform, +// leaving translation and scale untouched. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_hpr(const LVecBase3f &hpr) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + set_transform(transform->set_hpr(hpr)); +} + +void qpNodePath:: +set_h(float h) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + LVecBase3f hpr = transform->get_hpr(); + hpr[0] = h; + set_transform(transform->set_hpr(hpr)); +} + +void qpNodePath:: +set_p(float p) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + LVecBase3f hpr = transform->get_hpr(); + hpr[1] = p; + set_transform(transform->set_hpr(hpr)); +} + +void qpNodePath:: +set_r(float r) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + LVecBase3f hpr = transform->get_hpr(); + hpr[2] = r; + set_transform(transform->set_hpr(hpr)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_hpr +// Access: Published +// Description: Retrieves the rotation component of the transform. +//////////////////////////////////////////////////////////////////// +LVecBase3f qpNodePath:: +get_hpr() const { + nassertr(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); + CPT(TransformState) transform = get_transform(); + nassertr(transform->has_components(), LVecBase3f(0.0f, 0.0f, 0.0f)); + return transform->get_hpr(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_hpr +// Access: Published +// Description: Retrieves the rotation component of the transform. +//////////////////////////////////////////////////////////////////// +LVecBase3f qpNodePath:: +get_hpr(float roll) const { + // This function is deprecated. It used to be a hack to work around + // a problem with decomposing Euler angles, but since we no longer + // depend on decomposing these, we shouldn't need this any more. + return get_hpr(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_scale +// Access: Published +// Description: Sets the scale component of the transform, +// leaving translation and rotation untouched. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_scale(const LVecBase3f &sv3) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + set_transform(transform->set_scale(sv3)); +} + +void qpNodePath:: +set_sx(float sx) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + LVecBase3f scale = transform->get_scale(); + scale[0] = sx; + set_transform(transform->set_scale(scale)); +} + +void qpNodePath:: +set_sy(float sy) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + LVecBase3f scale = transform->get_scale(); + scale[1] = sy; + set_transform(transform->set_scale(scale)); +} + +void qpNodePath:: +set_sz(float sz) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + LVecBase3f scale = transform->get_scale(); + scale[2] = sz; + set_transform(transform->set_scale(scale)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_scale +// Access: Published +// Description: Retrieves the scale component of the transform. +//////////////////////////////////////////////////////////////////// +LVecBase3f qpNodePath:: +get_scale() const { + nassertr(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); + CPT(TransformState) transform = get_transform(); + nassertr(transform->has_components(), LVecBase3f(0.0f, 0.0f, 0.0f)); + return transform->get_scale(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos_hpr +// Access: Published +// Description: Sets the translation and rotation component of the +// transform, leaving scale untouched. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) { + nassertv_always(!is_empty()); + CPT(TransformState) transform = get_transform(); + nassertv(transform->has_components()); + transform = TransformState::make_pos_hpr_scale + (pos, hpr, transform->get_scale()); + set_transform(transform); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_hpr_scale +// Access: Published +// Description: Sets the rotation and scale components of the +// transform, leaving translation untouched. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_hpr_scale(const LVecBase3f &hpr, const LVecBase3f &scale) { + nassertv_always(!is_empty()); + CPT(TransformState) transform = get_transform(); + transform = TransformState::make_pos_hpr_scale + (transform->get_pos(), hpr, scale); + set_transform(transform); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos_hpr_scale +// Access: Published +// Description: Completely replaces the transform with new +// translation, rotation, and scale components. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr, + const LVecBase3f &scale) { + nassertv_always(!is_empty()); + set_transform(TransformState::make_pos_hpr_scale + (pos, hpr, scale)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_mat +// Access: Published +// Description: Directly sets an arbitrary 4x4 transform matrix. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_mat(const LMatrix4f &mat) { + nassertv_always(!is_empty()); + set_transform(TransformState::make_mat(mat)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_color_scale +// Access: Published +// Description: Sets the color scale component of the transform, +// leaving translation and rotation untouched. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_color_scale(const LVecBase4f &sv4) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_color_scale +// Access: Published +// Description: Returns the complete transform vector that has been +// applied to the bottom node, or the all 1's if no +// scale has been applied +//////////////////////////////////////////////////////////////////// +LVecBase4f qpNodePath:: +get_color_scale() const { + nassertr(false, LVecBase4f(1.0f,1.0f,1.0f,1.0f)); + return LVecBase4f(1.0f,1.0f,1.0f,1.0f); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::look_at +// Access: Published +// Description: Sets the transform on this qpNodePath so that it +// rotates to face the indicated point in space. This +// will overwrite any previously existing scale on the +// node, although it will preserve any translation. See +// also look_at_preserve_scale(). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +look_at(const LPoint3f &point, const LVector3f &up) { + nassertv(!is_empty()); + + LPoint3f pos = get_pos(); + + LMatrix4f mat; + ::look_at(mat, point - pos, up); + mat.set_row(3, pos); + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::heads_up +// Access: Published +// Description: Behaves like look_at(), but with a strong preference +// to keeping the up vector oriented in the indicated +// "up" direction. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +heads_up(const LPoint3f &point, const LVector3f &up) { + nassertv(!is_empty()); + + LPoint3f pos = get_pos(); + + LMatrix4f mat; + ::heads_up(mat, point - pos, up); + mat.set_row(3, pos); + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::look_at_preserve_scale +// Access: Published +// Description: Functions like look_at(), but preforms additional +// work to preserve any scales that may already be +// present on the node. Normally, look_at() blows away +// the scale because scale and rotation are represented +// in the same part of the matrix. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +look_at_preserve_scale(const LPoint3f &point, const LVector3f &up) { + nassertv(!is_empty()); + + LMatrix4f mat = get_mat(); + + // Extract the axes from the matrix. + LVector3f x, y, z; + + mat.get_row3(x,0); + mat.get_row3(y,1); + mat.get_row3(z,2); + + // The lengths of the axes defines the scale. + + float scale_0 = length(x); + float scale_1 = length(y); + float scale_2 = length(z); + + LPoint3f pos; + mat.get_row3(pos,3); + ::look_at(mat, point - pos, up); + + // Now reapply the scale and position. + + mat.get_row3(x,0); + mat.get_row3(y,1); + mat.get_row3(z,2); + + x *= scale_0; + y *= scale_1; + z *= scale_2; + + mat.set_row(0, x); + mat.set_row(1, y); + mat.set_row(2, z); + mat.set_row(3, pos); + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::heads_up_preserve_scale +// Access: Published +// Description: Functions like heads_up(), but preforms additional +// work to preserve any scales that may already be +// present on the node. Normally, heads_up() blows away +// the scale because scale and rotation are represented +// in the same part of the matrix. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +heads_up_preserve_scale(const LPoint3f &point, const LVector3f &up) { + nassertv(!is_empty()); + + LMatrix4f mat = get_mat(); + + // Extract the axes from the matrix. + LVector3f x, y, z; + mat.get_row3(x,0); + mat.get_row3(y,1); + mat.get_row3(z,2); + + float scale_0 = length(x); + float scale_1 = length(y); + float scale_2 = length(z); + + // The lengths of the axes defines the scale. + LPoint3f pos; + mat.get_row3(pos,3); + + ::heads_up(mat, point - pos, up); + + // Now reapply the scale and position. + + mat.get_row3(x,0); + mat.get_row3(y,1); + mat.get_row3(z,2); + + x *= scale_0; + y *= scale_1; + z *= scale_2; + + mat.set_row(0, x); + mat.set_row(1, y); + mat.set_row(2, z); + mat.set_row(3, pos); + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos +// Access: Published +// Description: Sets the translation component of the transform, +// relative to the other node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_pos(const qpNodePath &other, const LVecBase3f &pos) { + nassertv(!is_empty()); + set_transform(other, get_transform(other)->set_pos(pos)); +} + +void qpNodePath:: +set_x(const qpNodePath &other, float x) { + nassertv(!is_empty()); + LPoint3f pos = get_pos(other); + pos[0] = x; + set_pos(other, pos); +} + +void qpNodePath:: +set_y(const qpNodePath &other, float y) { + nassertv(!is_empty()); + LPoint3f pos = get_pos(other); + pos[1] = y; + set_pos(other, pos); +} + +void qpNodePath:: +set_z(const qpNodePath &other, float z) { + nassertv(!is_empty()); + LPoint3f pos = get_pos(other); + pos[2] = z; + set_pos(other, pos); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_hpr +// Access: Published +// Description: Sets the rotation component of the transform, +// relative to the other node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_hpr(const qpNodePath &other, const LVecBase3f &hpr) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + set_transform(other, transform->set_hpr(hpr)); +} + +void qpNodePath:: +set_h(const qpNodePath &other, float h) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + LVecBase3f hpr = transform->get_hpr(); + hpr[0] = h; + set_transform(other, transform->set_hpr(hpr)); +} + +void qpNodePath:: +set_p(const qpNodePath &other, float p) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + LVecBase3f hpr = transform->get_hpr(); + hpr[1] = p; + set_transform(other, transform->set_hpr(hpr)); +} + +void qpNodePath:: +set_r(const qpNodePath &other, float r) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + LVecBase3f hpr = transform->get_hpr(); + hpr[2] = r; + set_transform(other, transform->set_hpr(hpr)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_hpr +// Access: Published +// Description: Returns the relative orientation of the bottom node +// as seen from the other node. +//////////////////////////////////////////////////////////////////// +LVecBase3f qpNodePath:: +get_hpr(const qpNodePath &other) const { + nassertr(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); + CPT(TransformState) transform = get_transform(other); + nassertr(transform->has_components(), LVecBase3f(0.0f, 0.0f, 0.0f)); + return transform->get_hpr(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_hpr +// Access: Published +// Description: Returns the relative orientation of the bottom node +// as seen from the other node. +//////////////////////////////////////////////////////////////////// +LVecBase3f qpNodePath:: +get_hpr(const qpNodePath &other, float roll) const { + // This is still doing it the dumb way, with a decomposition. This + // function is deprecated anyway. + LMatrix4f mat = get_mat(other); + LVector3f scale, hpr, pos; + decompose_matrix(mat, scale, hpr, pos, roll); + return hpr; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_scale +// Access: Published +// Description: Sets the scale component of the transform, +// relative to the other node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_scale(const qpNodePath &other, const LVecBase3f &scale) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + set_transform(other, transform->set_scale(scale)); +} + +void qpNodePath:: +set_sx(const qpNodePath &other, float sx) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + LVecBase3f scale = transform->get_scale(); + scale[0] = sx; + set_transform(other, transform->set_scale(scale)); +} + +void qpNodePath:: +set_sy(const qpNodePath &other, float sy) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + LVecBase3f scale = transform->get_scale(); + scale[1] = sy; + set_transform(other, transform->set_scale(scale)); +} + +void qpNodePath:: +set_sz(const qpNodePath &other, float sz) { + nassertv(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + LVecBase3f scale = transform->get_scale(); + scale[2] = sz; + set_transform(other, transform->set_scale(scale)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_scale +// Access: Published +// Description: Returns the relative scale of the bottom node +// as seen from the other node. +//////////////////////////////////////////////////////////////////// +LVecBase3f qpNodePath:: +get_scale(const qpNodePath &other) const { + nassertr(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); + CPT(TransformState) transform = get_transform(other); + nassertr(transform->has_components(), LVecBase3f(0.0f, 0.0f, 0.0f)); + return transform->get_scale(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos_hpr +// Access: Published +// Description: Sets the translation and rotation component of the +// transform, relative to the other node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_pos_hpr(const qpNodePath &other, const LVecBase3f &pos, + const LVecBase3f &hpr) { + nassertv_always(!is_empty()); + CPT(TransformState) transform = get_transform(other); + nassertv(transform->has_components()); + transform = TransformState::make_pos_hpr_scale + (pos, hpr, transform->get_scale()); + set_transform(other, transform); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_hpr_scale +// Access: Published +// Description: Sets the rotation and scale components of the +// transform, leaving translation untouched. This, or +// set_pos_hpr_scale, is the preferred way to update a +// transform when both hpr and scale are to be changed. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_hpr_scale(const qpNodePath &other, const LVecBase3f &hpr, const LVecBase3f &scale) { + nassertv_always(!is_empty()); + CPT(TransformState) transform = get_transform(other); + transform = TransformState::make_pos_hpr_scale + (transform->get_pos(), hpr, scale); + set_transform(other, transform); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_pos_hpr_scale +// Access: Published +// Description: Completely replaces the transform with new +// translation, rotation, and scale components, relative +// to the other node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_pos_hpr_scale(const qpNodePath &other, + const LVecBase3f &pos, const LVecBase3f &hpr, + const LVecBase3f &scale) { + nassertv_always(!is_empty()); + set_transform(other, TransformState::make_pos_hpr_scale + (pos, hpr, scale)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_mat +// Access: Published +// Description: Returns the matrix that describes the coordinate +// space of the bottom node, relative to the other +// path's bottom node's coordinate space. +//////////////////////////////////////////////////////////////////// +const LMatrix4f &qpNodePath:: +get_mat(const qpNodePath &other) const { + CPT(TransformState) transform = get_transform(other); + // We can safely assume the transform won't go away when the + // function returns, since its reference count is also held in the + // cache. This assumption allows us to return a reference to the + // matrix, instead of having to return a matrix on the stack. + nassertr(transform->get_ref_count() > 1, LMatrix4f::ident_mat()); + return transform->get_mat(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_mat +// Access: Published +// Description: Converts the indicated matrix from the other's +// coordinate space to the local coordinate space, and +// applies it to the node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_mat(const qpNodePath &other, const LMatrix4f &mat) { + nassertv_always(!is_empty()); + set_transform(other, TransformState::make_mat(mat)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_relative_point +// Access: Published +// Description: Given that the indicated point is in the coordinate +// system of the other node, returns the same point in +// this node's coordinate system. +//////////////////////////////////////////////////////////////////// +LPoint3f qpNodePath:: +get_relative_point(const qpNodePath &other, const LVecBase3f &point) { + LPoint3f rel_point = LPoint3f(point) * other.get_mat(*this); + return rel_point; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::look_at +// Access: Published +// Description: Sets the transform on this qpNodePath so that it +// rotates to face the indicated point in space, which +// is relative to the other qpNodePath. This +// will overwrite any previously existing scale on the +// node, although it will preserve any translation. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +look_at(const qpNodePath &other, const LPoint3f &point, const LVector3f &up) { + nassertv(!is_empty()); + + LPoint3f pos = get_pos(); + + qpNodePath parent = get_parent(); + LPoint3f rel_point = point * other.get_mat(parent); + + LMatrix4f mat; + ::look_at(mat, rel_point - pos, up); + mat.set_row(3, pos); + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::heads_up +// Access: Published +// Description: Behaves like look_at(), but with a strong preference +// to keeping the up vector oriented in the indicated +// "up" direction. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +heads_up(const qpNodePath &other, const LPoint3f &point, const LVector3f &up) { + nassertv(!is_empty()); + + LPoint3f pos = get_pos(); + + qpNodePath parent = get_parent(); + LPoint3f rel_point = point * other.get_mat(parent); + + LMatrix4f mat; + ::heads_up(mat, rel_point - pos, up); + mat.set_row(3, pos); + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::look_at_preserve_scale +// Access: Published +// Description: Functions like look_at(), but preforms additional +// work to preserve any scales that may already be +// present on the node. Normally, look_at() blows away +// the scale because scale and rotation are represented +// in the same part of the matrix. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +look_at_preserve_scale(const qpNodePath &other, const LPoint3f &point, + const LVector3f &up) { + nassertv(!is_empty()); + + LMatrix4f mat = get_mat(); + + // Extract the axes from the matrix. + LVector3f x, y, z; + mat.get_row3(x,0); + mat.get_row3(y,1); + mat.get_row3(z,2); + + // The lengths of the axes defines the scale. + float scale_0 = length(x); + float scale_1 = length(y); + float scale_2 = length(z); + + LPoint3f pos; + mat.get_row3(pos,3); + + qpNodePath parent = get_parent(); + LPoint3f rel_point = point * other.get_mat(parent); + + ::look_at(mat, rel_point - pos, up); + + // Now reapply the scale and position. + + mat.get_row3(x,0); + mat.get_row3(y,1); + mat.get_row3(z,2); + + x *= scale_0; + y *= scale_1; + z *= scale_2; + + mat.set_row(0, x); + mat.set_row(1, y); + mat.set_row(2, z); + mat.set_row(3, pos); + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::heads_up_preserve_scale +// Access: Published +// Description: Functions like heads_up(), but preforms additional +// work to preserve any scales that may already be +// present on the node. Normally, heads_up() blows away +// the scale because scale and rotation are represented +// in the same part of the matrix. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +heads_up_preserve_scale(const qpNodePath &other, const LPoint3f &point, + const LVector3f &up) { + nassertv(!is_empty()); + + LMatrix4f mat = get_mat(); + + // Extract the axes from the matrix. + LVector3f x, y, z; + mat.get_row3(x,0); + mat.get_row3(y,1); + mat.get_row3(z,2); + + // The lengths of the axes defines the scale. + float scale_0 = length(x); + float scale_1 = length(y); + float scale_2 = length(z); + + LPoint3f pos; + mat.get_row3(pos,3); + + qpNodePath parent = get_parent(); + LPoint3f rel_point = point * other.get_mat(parent); + + ::heads_up(mat, rel_point - pos, up); + + // Now reapply the scale and position. + mat.get_row3(x,0); + mat.get_row3(y,1); + mat.get_row3(z,2); + + x *= scale_0; + y *= scale_1; + z *= scale_2; + + mat.set_row(0, x); + mat.set_row(1, y); + mat.set_row(2, z); + mat.set_row(3, pos); + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_color +// Access: Published +// Description: Applies a scene-graph color to the referenced node. +// This color will apply to all geometry at this level +// and below (that does not specify a new color or a +// set_color_off()). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_color(float r, float g, float b, float a, + int priority) { + set_color(Colorf(r, g, b, a), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_color +// Access: Published +// Description: Applies a scene-graph color to the referenced node. +// This color will apply to all geometry at this level +// and below (that does not specify a new color or a +// set_color_off()). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_color(const Colorf &color, int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(ColorAttrib::make_flat(color), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_color_off +// Access: Published +// Description: Sets the geometry at this level and below to render +// using the geometry color. This is normally the +// default, but it may be useful to use this to +// contradict set_color() at a higher node level (or, +// with a priority, to override a set_color() at a lower +// level). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_color_off(int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(ColorAttrib::make_vertex(), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_color +// Access: Published +// Description: Completely removes any color adjustment from the node. +// This allows the natural color of the geometry, or +// whatever color transitions might be otherwise +// affecting the geometry, to show instead. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_color() { + nassertv(!is_empty()); + node()->clear_attrib(ColorAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_color +// Access: Published +// Description: Returns true if a color has been applied to the given +// node, false otherwise. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_color() const { + nassertr(!is_empty(), false); + return node()->has_attrib(ColorAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_color +// Access: Published +// Description: Returns the color that has been assigned to the node, +// or black if no color has been assigned. +//////////////////////////////////////////////////////////////////// +Colorf qpNodePath:: +get_color() const { + nassertr(!is_empty(), false); + const RenderAttrib *attrib = + node()->get_attrib(ColorAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const ColorAttrib *ca = DCAST(ColorAttrib, attrib); + if (ca->get_color_type() == ColorAttrib::T_flat) { + return ca->get_color(); + } + } + + pgraph_cat.warning() + << "get_color() called on " << *this << " which has no color set.\n"; + + return Colorf(0.0f, 0.0f, 0.0f, 0.0f); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_bin +// Access: Published +// Description: Assigns the geometry at this level and below to the +// named rendering bin. It is the user's responsibility +// to ensure that such a bin already exists, either via +// the cull-bin Configrc variable, or by explicitly +// creating a GeomBin of the appropriate type at +// runtime. +// +// There are two default bins created when Panda is +// started: "default" and "fixed". Normally, all +// geometry is assigned to "default" unless specified +// otherwise. This bin renders opaque geometry in +// state-sorted order, followed by transparent geometry +// sorted back-to-front. If any geometry is assigned to +// "fixed", this will be rendered following all the +// geometry in "default", in the order specified by +// draw_order for each piece of geometry so assigned. +// +// The draw_order parameter is meaningful only for +// GeomBinFixed type bins, e.g. "fixed". Other kinds of +// bins ignore it. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_bin(const string &bin_name, int draw_order, int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_bin +// Access: Published +// Description: Completely removes any bin adjustment that may have +// been set via set_bin() from this particular node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_bin() { + nassertv(!is_empty()); + node()->clear_attrib(CullBinAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_bin +// Access: Published +// Description: Returns true if the node has been assigned to the a +// particular rendering bin via set_bin(), false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_bin() const { + nassertr(!is_empty(), false); + return node()->has_attrib(CullBinAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_bin_name +// Access: Published +// Description: Returns the name of the bin that this particular node +// was assigned to via set_bin(), or the empty string if +// no bin was assigned. See set_bin() and has_bin(). +//////////////////////////////////////////////////////////////////// +string qpNodePath:: +get_bin_name() const { + nassertr(!is_empty(), string()); + const RenderAttrib *attrib = + node()->get_attrib(ColorAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib); + return ba->get_bin_name(); + } + + return string(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_bin_draw_order +// Access: Published +// Description: Returns the drawing order associated with the bin +// that this particular node was assigned to via +// set_bin(), or 0 if no bin was assigned. See +// set_bin() and has_bin(). +//////////////////////////////////////////////////////////////////// +int qpNodePath:: +get_bin_draw_order() const { + nassertr(!is_empty(), false); + const RenderAttrib *attrib = + node()->get_attrib(ColorAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib); + return ba->get_draw_order(); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_texture +// Access: Published +// Description: Sets the geometry at this level and below to render +// using the indicated texture. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_texture(Texture *tex, int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(TextureAttrib::make(tex), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_texture_off +// Access: Published +// Description: Sets the geometry at this level and below to render +// using no texture. This is normally the default, but +// it may be useful to use this to contradict +// set_texture() at a higher node level (or, with a +// priority, to override a set_texture() at a lower +// level). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_texture_off(int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(TextureAttrib::make_off(), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_texture +// Access: Published +// Description: Completely removes any texture adjustment that may +// have been set via set_texture() or set_texture_off() +// from this particular node. This allows whatever +// textures might be otherwise affecting the geometry to +// show instead. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_texture() { + nassertv(!is_empty()); + node()->clear_attrib(TextureAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_texture +// Access: Published +// Description: Returns true if a texture has been applied to this +// particular node via set_texture(), false otherwise. +// This is not the same thing as asking whether the +// geometry at this node will be rendered with +// texturing, as there may be a texture in effect from a +// higher or lower level. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_texture() const { + nassertr(!is_empty(), false); + const RenderAttrib *attrib = + node()->get_attrib(TextureAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const TextureAttrib *ta = DCAST(TextureAttrib, attrib); + return !ta->is_off(); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_texture_off +// Access: Published +// Description: Returns true if a texture has been specifically +// disabled on this particular node via +// set_texture_off(), false otherwise. This is not the +// same thing as asking whether the geometry at this +// node will be rendered untextured, as there may be a +// texture in effect from a higher or lower level. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_texture_off() const { + nassertr(!is_empty(), false); + const RenderAttrib *attrib = + node()->get_attrib(ColorAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const TextureAttrib *ta = DCAST(TextureAttrib, attrib); + return ta->is_off(); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_texture +// Access: Published +// Description: Returns the texture that has been set on this +// particular node, or NULL if no texture has been set. +// This is not necessarily the texture that will be +// applied to the geometry at or below this level, as +// another texture at a higher or lower level may +// override. +//////////////////////////////////////////////////////////////////// +Texture *qpNodePath:: +get_texture() const { + nassertr(!is_empty(), NULL); + const RenderAttrib *attrib = + node()->get_attrib(TextureAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const TextureAttrib *ta = DCAST(TextureAttrib, attrib); + return ta->get_texture(); + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_material +// Access: Published +// Description: Sets the geometry at this level and below to render +// using the indicated material. +// +// This operation copies the given material pointer. If +// the material structure is changed later, it must be +// reapplied via another call to set_material(). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_material(Material *mat, int priority) { + nassertv_always(!is_empty()); + nassertv(mat != NULL); + + // We create a temporary Material pointer, a copy of the one we are + // given, to allow the user to monkey with the material and set it + // again later, with the desired effect. If we stored the user's + // pointer directly, it would be bad if the user later modified the + // values within the Material. + PT(Material) temp = new Material(*mat); + const Material *mp = MaterialPool::get_material(temp); + + node()->set_attrib(MaterialAttrib::make(mp), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_material_off +// Access: Published +// Description: Sets the geometry at this level and below to render +// using no material. This is normally the default, but +// it may be useful to use this to contradict +// set_material() at a higher node level (or, with a +// priority, to override a set_material() at a lower +// level). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_material_off(int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(MaterialAttrib::make_off(), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_material +// Access: Published +// Description: Completely removes any material adjustment that may +// have been set via set_material() from this particular +// node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_material() { + nassertv(!is_empty()); + node()->clear_attrib(MaterialAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_material +// Access: Published +// Description: Returns true if a material has been applied to this +// particular node via set_material(), false otherwise. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_material() const { + nassertr(!is_empty(), false); + const RenderAttrib *attrib = + node()->get_attrib(MaterialAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib); + return !ma->is_off(); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_material +// Access: Published +// Description: Returns the material that has been set on this +// particular node, or NULL if no material has been set. +// This is not necessarily the material that will be +// applied to the geometry at or below this level, as +// another material at a higher or lower level may +// override. +// +// This function returns a copy of the given material, +// to allow changes, if desired. Once changes are made, +// they should be reapplied via set_material(). +//////////////////////////////////////////////////////////////////// +PT(Material) qpNodePath:: +get_material() const { + nassertr(!is_empty(), NULL); + const RenderAttrib *attrib = + node()->get_attrib(MaterialAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib); + return new Material(*ma->get_material()); + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_fog +// Access: Published +// Description: Sets the geometry at this level and below to render +// using the indicated fog. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_fog(Fog *fog, int priority) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_fog_off +// Access: Published +// Description: Sets the geometry at this level and below to render +// using no fog. This is normally the default, but +// it may be useful to use this to contradict +// set_fog() at a higher node level (or, with a +// priority, to override a set_fog() at a lower +// level). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_fog_off(int priority) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_fog +// Access: Published +// Description: Completely removes any fog adjustment that may +// have been set via set_fog() or set_fog_off() +// from this particular node. This allows whatever +// fogs might be otherwise affecting the geometry to +// show instead. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_fog() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_fog +// Access: Published +// Description: Returns true if a fog has been applied to this +// particular node via set_fog(), false otherwise. +// This is not the same thing as asking whether the +// geometry at this node will be rendered with +// fog, as there may be a fog in effect from a higher or +// lower level. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_fog() const { + nassertr(false, false); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_fog_off +// Access: Published +// Description: Returns true if a fog has been specifically +// disabled on this particular node via +// set_fog_off(), false otherwise. This is not the +// same thing as asking whether the geometry at this +// node will be rendered unfogged, as there may be a +// fog in effect from a higher or lower level. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_fog_off() const { + nassertr(false, false); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_fog +// Access: Published +// Description: Returns the fog that has been set on this +// particular node, or NULL if no fog has been set. +// This is not necessarily the fog that will be +// applied to the geometry at or below this level, as +// another fog at a higher or lower level may +// override. +//////////////////////////////////////////////////////////////////// +Fog *qpNodePath:: +get_fog() const { + nassertr(false, NULL); + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_render_mode_wireframe +// Access: Published +// Description: Sets up the geometry at this level and below (unless +// overridden) to render in wireframe mode. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_render_mode_wireframe(int priority) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_render_mode_filled +// Access: Published +// Description: Sets up the geometry at this level and below (unless +// overridden) to render in filled (i.e. not wireframe) +// mode. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_render_mode_filled(int priority) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_render_mode +// Access: Published +// Description: Completely removes any render mode adjustment that +// may have been set on this node via +// set_render_mode_wireframe() or +// set_render_mode_filled(). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_render_mode() { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_render_mode +// Access: Published +// Description: Returns true if a render mode has been explicitly set +// on this particular node via +// set_render_mode_wireframe() or +// set_render_mode_filled(), false otherwise. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_render_mode() const { + nassertr(false, false); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_two_sided +// Access: Published +// Description: Specifically sets or disables two-sided rendering +// mode on this particular node. If no other nodes +// override, this will cause backfacing polygons to be +// drawn (in two-sided mode, true) or culled (in +// one-sided mode, false). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_two_sided(bool two_sided, int priority) { + nassertv_always(!is_empty()); + + CullFaceAttrib::Mode mode = + two_sided ? + CullFaceAttrib::M_cull_none : + CullFaceAttrib::M_cull_clockwise; + + node()->set_attrib(CullFaceAttrib::make(mode), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_two_sided +// Access: Published +// Description: Completely removes any two-sided adjustment that +// may have been set on this node via set_two_sided(). +// The geometry at this level and below will +// subsequently be rendered either two-sided or +// one-sided, according to whatever other nodes may have +// had set_two_sided() on it, or according to the +// initial state otherwise. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_two_sided() { + nassertv(!is_empty()); + node()->clear_attrib(CullFaceAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_two_sided +// Access: Published +// Description: Returns true if a two-sided adjustment has been +// explicitly set on this particular node via +// set_two_sided(). If this returns true, then +// get_two_sided() may be called to determine which has +// been set. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_two_sided() const { + nassertr(!is_empty(), false); + return node()->has_attrib(CullFaceAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_two_sided +// Access: Published +// Description: Returns true if two-sided rendering has been +// specifically set on this node via set_two_sided(), or +// false if one-sided rendering has been specifically +// set, or if nothing has been specifically set. See +// also has_two_sided(). This does not necessarily +// imply that the geometry will or will not be rendered +// two-sided, as there may be other nodes that override. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +get_two_sided() const { + nassertr(!is_empty(), false); + const RenderAttrib *attrib = + node()->get_attrib(CullFaceAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib); + return (cfa->get_mode() == CullFaceAttrib::M_cull_none); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::do_billboard_axis +// Access: Published +// Description: Performs a billboard-type rotate to the indicated +// camera node, one time only, and leaves the object +// rotated. This is similar in principle to heads_up(). +// However, it does lose both translate and scale +// components of the matrix. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +do_billboard_axis(const qpNodePath &camera, float offset) { + nassertv(!is_empty()); + + qpNodePath parent = get_parent(); + LMatrix4f rel_mat = camera.get_mat(parent); + + LVector3f up = LVector3f::up(); + LVector3f rel_pos = -rel_mat.get_row3(3); + + LMatrix4f mat; + ::heads_up(mat, rel_pos, up); + + // Also slide the geometry towards the camera according to the + // offset factor. + if (offset != 0.0f) { + LVector3f translate = rel_mat.get_row3(3); + translate.normalize(); + translate *= offset; + mat.set_row(3, translate); + } + + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::do_billboard_point_eye +// Access: Published +// Description: Performs a billboard-type rotate to the indicated +// camera node, one time only, and leaves the object +// rotated. This is similar in principle to look_at(), +// although the point_eye billboard effect cannot be +// achieved using the ordinary look_at() call. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +do_billboard_point_eye(const qpNodePath &camera, float offset) { + nassertv(!is_empty()); + + qpNodePath parent = get_parent(); + LMatrix4f rel_mat = camera.get_mat(parent); + + LVector3f up = LVector3f::up() * rel_mat; + LVector3f rel_pos = LVector3f::forward() * rel_mat; + + LMatrix4f mat; + ::look_at(mat, rel_pos, up); + + // Also slide the geometry towards the camera according to the + // offset factor. + if (offset != 0.0f) { + LVector3f translate = rel_mat.get_row3(3); + translate.normalize(); + translate *= offset; + mat.set_row(3, translate); + } + + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::do_billboard_point_world +// Access: Published +// Description: Performs a billboard-type rotate to the indicated +// camera node, one time only, and leaves the object +// rotated. This is similar in principle to look_at(). +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +do_billboard_point_world(const qpNodePath &camera, float offset) { + nassertv(!is_empty()); + + qpNodePath parent = get_parent(); + LMatrix4f rel_mat = camera.get_mat(parent); + + LVector3f up = LVector3f::up(); + LVector3f rel_pos = -rel_mat.get_row3(3); + + LMatrix4f mat; + ::look_at(mat, rel_pos, up); + + // Also slide the geometry towards the camera according to the + // offset factor. + if (offset != 0.0f) { + LVector3f translate = rel_mat.get_row3(3); + translate.normalize(); + translate *= offset; + mat.set_row(3, translate); + } + + set_mat(mat); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_billboard_axis +// Access: Published +// Description: Puts a billboard transition on the node such that it +// will rotate in two dimensions around the up axis. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_billboard_axis(float offset) { + nassertv(!is_empty()); + CPT(RenderAttrib) billboard = BillboardAttrib::make + (LVector3f::up(), false, true, + offset, qpNodePath(), LPoint3f(0.0f, 0.0f, 0.0f)); + node()->set_attrib(billboard); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_billboard_point_eye +// Access: Published +// Description: Puts a billboard transition on the node such that it +// will rotate in three dimensions about the origin, +// keeping its up vector oriented to the top of the +// camera. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_billboard_point_eye(float offset) { + nassertv(!is_empty()); + CPT(RenderAttrib) billboard = BillboardAttrib::make + (LVector3f::up(), true, false, + offset, qpNodePath(), LPoint3f(0.0f, 0.0f, 0.0f)); + node()->set_attrib(billboard); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_billboard_point_world +// Access: Published +// Description: Puts a billboard transition on the node such that it +// will rotate in three dimensions about the origin, +// keeping its up vector oriented to the sky. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_billboard_point_world(float offset) { + nassertv(!is_empty()); + CPT(RenderAttrib) billboard = BillboardAttrib::make + (LVector3f::up(), false, false, + offset, qpNodePath(), LPoint3f(0.0f, 0.0f, 0.0f)); + node()->set_attrib(billboard); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_billboard +// Access: Published +// Description: Removes any billboard attributes from the node. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_billboard() { + nassertv(!is_empty()); + node()->clear_attrib(BillboardAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_billboard +// Access: Published +// Description: Returns true if there is any billboard attribute on +// the node. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_billboard() const { + nassertr(!is_empty(), false); + return node()->has_attrib(BillboardAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::set_transparency +// Access: Published +// Description: Specifically sets or disables transparent rendering +// mode on this particular node. If no other nodes +// override, this will cause items with a non-1 value +// for alpha color to be rendered partially transparent. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +set_transparency(bool transparency, int priority) { + nassertv_always(!is_empty()); + + TransparencyAttrib::Mode mode = + transparency ? + TransparencyAttrib::M_alpha : + TransparencyAttrib::M_none; + + node()->set_attrib(TransparencyAttrib::make(mode), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_transparency +// Access: Published +// Description: Completely removes any transparency adjustment that +// may have been set on this node via set_transparency(). +// The geometry at this level and below will +// subsequently be rendered either transparent or not, +// to whatever other nodes may have had +// set_transparency() on them. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_transparency() { + nassertv(!is_empty()); + node()->clear_attrib(TransparencyAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_transparency +// Access: Published +// Description: Returns true if a transparent-rendering adjustment +// has been explicitly set on this particular node via +// set_transparency(). If this returns true, then +// get_transparency() may be called to determine whether +// transparency has been explicitly enabled or +// explicitly disabled for this node. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_transparency() const { + nassertr(!is_empty(), false); + return node()->has_attrib(TransparencyAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_transparency +// Access: Published +// Description: Returns true if transparent rendering has been +// specifically set on this node via set_transparency(), or +// false if nontransparent rendering has been specifically +// set, or if nothing has been specifically set. See +// also has_transparency(). This does not necessarily +// imply that the geometry will or will not be rendered +// transparent, as there may be other nodes that override. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +get_transparency() const { + nassertr(!is_empty(), false); + const RenderAttrib *attrib = + node()->get_attrib(TransparencyAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const TransparencyAttrib *cfa = DCAST(TransparencyAttrib, attrib); + return (cfa->get_mode() != TransparencyAttrib::M_none); + } + + return false; +} + + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_hidden_ancestor +// Access: Published +// Description: Returns the NodePath at or above the referenced node +// that is hidden, or an empty NodePath if no ancestor +// of the referenced node is hidden (and the node should +// be visible). +//////////////////////////////////////////////////////////////////// +qpNodePath qpNodePath:: +get_hidden_ancestor() const { + nassertr(false, qpNodePath()); + return qpNodePath(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::get_stashed_ancestor +// Access: Published +// Description: Returns the NodePath at or above the referenced node +// that is stashed, or an empty NodePath if no ancestor +// of the referenced node is stashed (and the node should +// be visible). +//////////////////////////////////////////////////////////////////// +qpNodePath qpNodePath:: +get_stashed_ancestor() const { + nassertr(false, qpNodePath()); + return qpNodePath(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::verify_complete +// Access: Published +// Description: Returns true if all of the nodes described in the +// qpNodePath are connected *and* the top node is the top +// of the graph, or false otherwise. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +verify_complete() const { + if (is_empty()) { + return true; + } + + uncollapse_head(); + const qpNodePathComponent *comp = _head; + nassertr(comp != (const qpNodePathComponent *)NULL, false); + + PandaNode *node = comp->get_node(); + nassertr(node != (const PandaNode *)NULL, false); + int length = comp->get_length(); + + comp = comp->get_next(); + length--; + while (comp != (const qpNodePathComponent *)NULL) { + PandaNode *next_node = comp->get_node(); + nassertr(next_node != (const PandaNode *)NULL, false); + + if (next_node->find_child(node) < 0) { + return false; + } + + if (comp->get_length() != length) { + return false; + } + + node = next_node; + comp = comp->get_next(); + length--; + } + + // Now that we've reached the top, we should have no parents. + return length == 0 && node->get_num_parents() == 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::uncollapse_head +// Access: Private +// Description: Quietly and transparently uncollapses the _head +// pointer if it needs it. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +uncollapse_head() const { + if (_head != (qpNodePathComponent *)NULL && _head->is_collapsed()) { + ((qpNodePath *)this)->_head = _head->uncollapse(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::find_common_ancestor +// Access: Private, Static +// Description: Walks up from both qpNodePaths to find the first node +// that both have in common, if any. Fills a_count and +// b_count with the number of nodes below the common +// node in each path. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +find_common_ancestor(const qpNodePath &a, const qpNodePath &b, + int &a_count, int &b_count) { + nassertv(!a.is_empty() && !b.is_empty()); + a.uncollapse_head(); + b.uncollapse_head(); + + qpNodePathComponent *ac = a._head; + qpNodePathComponent *bc = b._head; + a_count = 0; + b_count = 0; + + // Shorten up the longer one until they are the same length. + while (ac->get_length() > bc->get_length()) { + nassertv(ac != (qpNodePathComponent *)NULL); + ac = ac->get_next(); + a_count++; + } + while (bc->get_length() > ac->get_length()) { + nassertv(bc != (qpNodePathComponent *)NULL); + bc = bc->get_next(); + b_count++; + } + + // Now shorten them both up until we reach the same component. + while (ac != bc) { + // These shouldn't go to NULL unless they both go there together. + nassertv(ac != (qpNodePathComponent *)NULL); + nassertv(bc != (qpNodePathComponent *)NULL); + ac = ac->get_next(); + a_count++; + bc = bc->get_next(); + b_count++; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::r_get_net_state +// Access: Private +// Description: Recursively determines the net state chnages to the +// indicated component node from the root of the graph. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) qpNodePath:: +r_get_net_state(qpNodePathComponent *comp) const { + if (comp == (qpNodePathComponent *)NULL) { + return RenderState::make_empty(); + } else { + CPT(RenderState) state = comp->get_node()->get_state(); + return r_get_net_state(comp->get_next())->compose(state); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::r_get_partial_state +// Access: Private +// Description: Recursively determines the net state changes to the +// indicated component node from the nth node above it. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) qpNodePath:: +r_get_partial_state(qpNodePathComponent *comp, int n) const { + nassertr(comp != (qpNodePathComponent *)NULL, RenderState::make_empty()); + if (n == 0) { + return RenderState::make_empty(); + } else { + CPT(RenderState) state = comp->get_node()->get_state(); + return r_get_partial_state(comp->get_next(), n - 1)->compose(state); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::r_get_net_transform +// Access: Private +// Description: Recursively determines the net transform to the +// indicated component node from the root of the graph. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) qpNodePath:: +r_get_net_transform(qpNodePathComponent *comp) const { + if (comp == (qpNodePathComponent *)NULL) { + return TransformState::make_identity(); + } else { + CPT(TransformState) transform = comp->get_node()->get_transform(); + return r_get_net_transform(comp->get_next())->compose(transform); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::r_get_partial_transform +// Access: Private +// Description: Recursively determines the net transform to the +// indicated component node from the nth node above it. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) qpNodePath:: +r_get_partial_transform(qpNodePathComponent *comp, int n) const { + nassertr(comp != (qpNodePathComponent *)NULL, TransformState::make_identity()); + if (n == 0) { + return TransformState::make_identity(); + } else { + CPT(TransformState) transform = comp->get_node()->get_transform(); + return r_get_partial_transform(comp->get_next(), n - 1)->compose(transform); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::r_output +// Access: Private +// Description: The recursive implementation of output(), this writes +// the names of each node component in order from +// beginning to end, by first walking to the end of the +// linked list and then outputting from there. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +r_output(ostream &out, qpNodePathComponent *comp) const { + qpNodePathComponent *next = comp->get_next(); + if (next != (qpNodePathComponent *)NULL) { + // This is not the head of the list; keep going up. + r_output(out, next); + out << "/"; + } + + // Now output this component. + PandaNode *node = comp->get_node(); + if (node->has_name()) { + out << node->get_name(); + } else { + out << "+" << node->get_type(); + } + out << "[" << comp->get_length() << "]"; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::r_compare_to +// Access: Private, Static +// Description: The recursive implementation of compare_to(). Returns +// < 0 if a sorts before b, > 0 if b sorts before a, or +// == 0 if they are equivalent. +//////////////////////////////////////////////////////////////////// +int qpNodePath:: +r_compare_to(const qpNodePathComponent *a, const qpNodePathComponent *b) { + if (a == b) { + return 0; + + } else if (a == (const qpNodePathComponent *)NULL) { + return -1; + + } else if (b == (const qpNodePathComponent *)NULL) { + return 1; + + } else if (a->get_node() != b->get_node()) { + return a->get_node() - b->get_node(); + + } else { + return r_compare_to(a->get_next(), b->get_next()); + } +} diff --git a/panda/src/pgraph/qpnodePath.h b/panda/src/pgraph/qpnodePath.h new file mode 100644 index 0000000000..0a23d10f7d --- /dev/null +++ b/panda/src/pgraph/qpnodePath.h @@ -0,0 +1,427 @@ +// Filename: qpnodePath.h +// Created by: drose (25Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 qpNODEPATH_H +#define qpNODEPATH_H + +#include "pandabase.h" + +#include "pandaNode.h" +#include "renderState.h" +#include "transformState.h" +#include "qpnodePathComponent.h" + +#include "pointerTo.h" +#include "referenceCount.h" +#include "notify.h" +#include "typedObject.h" + +class qpNodePathCollection; +class Texture; +class Material; +class Fog; + +//////////////////////////////////////////////////////////////////// +// Class : NodePath +// Description : NodePath is the fundamental system for disambiguating +// instances, and also provides a higher-level interface +// for manipulating the scene graph. +// +// A NodePath is a list of connected nodes from the root +// of the graph to any sub-node. Each NodePath +// therefore unqiuely describes one instance of a node. +// +// NodePaths themselves are lightweight objects that may +// easily be copied and passed by value. Their data is +// stored as a series of NodePathComponents that are +// stored on the nodes. Holding a NodePath will keep a +// reference count to all the nodes in the chain. +// However, if any node in the chain is removed or +// reparented (perhaps through a different NodePath), +// the NodePath will automatically be updated to reflect +// the changes. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA qpNodePath { +PUBLISHED: + // This enumeration is returned by get_error_type() for an empty + // qpNodePath to report the reason it's empty. + enum ErrorType { + ET_ok = 0, // i.e. not empty, or never assigned to anything. + ET_not_found, // returned from a failed find() or similar function. + ET_removed, // remove_node() was previously called on this qpNodePath. + ET_fail, // general failure return from some function. + }; + + INLINE qpNodePath(); + INLINE qpNodePath(PandaNode *top_node); + INLINE qpNodePath(const qpNodePath ©); + INLINE void operator = (const qpNodePath ©); + + INLINE static qpNodePath not_found(); + INLINE static qpNodePath removed(); + INLINE static qpNodePath fail(); + + // Methods to query a qpNodePath's contents. + INLINE bool is_empty() const; + INLINE bool is_singleton() const; + int get_num_nodes() const; + PandaNode *get_node(int index) const; + + INLINE ErrorType get_error_type() const; + + PandaNode *get_top_node() const; + INLINE PandaNode *node() const; + + // Methods that return collections of NodePaths derived from or + // related to this one. + + qpNodePathCollection get_children() const; + INLINE int get_num_children() const; + INLINE qpNodePath get_child(int n) const; + + 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; + */ + + // Methods that actually move nodes around in the scene graph. The + // optional "sort" parameter can be used to force a particular + // ordering between sibling nodes, useful when dealing with LOD's + // and similar switch nodes. If the sort value is the same, nodes + // will be arranged in the order they were added. + void reparent_to(const qpNodePath &other, int sort = 0); + void wrt_reparent_to(const qpNodePath &other, int sort = 0); + qpNodePath instance_to(const qpNodePath &other, int sort = 0) const; + qpNodePath copy_to(const qpNodePath &other, int sort = 0) const; + qpNodePath attach_new_node(PandaNode *node, int sort = 0) const; + INLINE qpNodePath attach_new_node(const string &name, int sort = 0) const; + void remove_node(); + + // Handy ways to look at what's there, and other miscellaneous + // operations. + + INLINE void output(ostream &out) const; + + INLINE void ls() const; + INLINE void ls(ostream &out, int indent_level = 0) const; + INLINE void ls_transitions() const; + INLINE void ls_transforms() const; + + + // Aggregate transform and state information. + INLINE CPT(RenderState) get_state() const; + INLINE void set_state(const RenderState *state) const; + CPT(RenderState) get_state(const qpNodePath &other) const; + void set_state(const qpNodePath &other, const RenderState *state) const; + INLINE CPT(RenderState) get_net_state() const; + + INLINE CPT(TransformState) get_transform() const; + INLINE void set_transform(const TransformState *transform) const; + CPT(TransformState) get_transform(const qpNodePath &other) const; + void set_transform(const qpNodePath &other, const TransformState *transform) const; + INLINE CPT(TransformState) get_net_transform() const; + + + // Methods that get and set the matrix transform: pos, hpr, scale, + // in the local coordinate system. + + INLINE void set_pos(float x, float y, float z); + void set_pos(const LVecBase3f &pos); + void set_x(float x); + void set_y(float y); + void set_z(float z); + LPoint3f get_pos() const; + INLINE float get_x() const; + INLINE float get_y() const; + INLINE float get_z() const; + + INLINE void set_hpr(float h, float p, float r); + void set_hpr(const LVecBase3f &hpr); + void set_h(float h); + void set_p(float p); + void set_r(float r); + LVecBase3f get_hpr() const; + LVecBase3f get_hpr(float roll) const; + INLINE float get_h() const; + INLINE float get_p() const; + INLINE float get_r() const; + + INLINE void set_scale(float scale); + INLINE void set_scale(float sx, float sy, float sz); + void set_scale(const LVecBase3f &sv3); + void set_sx(float sx); + void set_sy(float sy); + void set_sz(float sz); + LVecBase3f get_scale() const; + INLINE float get_sx() const; + INLINE float get_sy() const; + INLINE float get_sz() const; + + INLINE void set_pos_hpr(float x, float y, float z, + float h, float p, float r); + void set_pos_hpr(const LVecBase3f &pos, + const LVecBase3f &hpr); + + INLINE void set_hpr_scale(float h, float p, float r, + float sx, float sy, float sz); + void set_hpr_scale(const LVecBase3f &hpr, + const LVecBase3f &scale); + INLINE void set_pos_hpr_scale(float x, float y, float z, + float h, float p, float r, + float sx, float sy, float sz); + void set_pos_hpr_scale(const LVecBase3f &pos, + const LVecBase3f &hpr, + const LVecBase3f &scale); + + void set_mat(const LMatrix4f &mat); + INLINE void clear_mat(); + INLINE bool has_mat() const; + INLINE const LMatrix4f &get_mat() const; + + INLINE bool has_color_scale() const; + INLINE void clear_color_scale(); + + void set_color_scale(const LVecBase4f &sv4); + INLINE void set_color_scale(float sx, float sy, float sz, float sa); + INLINE void set_sr(float sr); + INLINE void set_sg(float sg); + INLINE void set_sb(float sb); + INLINE void set_sa(float sa); + + LVecBase4f get_color_scale() const; + INLINE float get_sr() const; + INLINE float get_sg() const; + INLINE float get_sb() const; + INLINE float get_sa() const; + + INLINE void look_at(float x, float y, float z); + void look_at(const LPoint3f &point, const LVector3f &up = LVector3f::up()); + INLINE void heads_up(float x, float y, float z); + void heads_up(const LPoint3f &point, const LVector3f &up = LVector3f::up()); + + INLINE void look_at_preserve_scale(float x, float y, float z); + void look_at_preserve_scale(const LPoint3f &point, const LVector3f &up = LVector3f::up()); + INLINE void heads_up_preserve_scale(float x, float y, float z); + void heads_up_preserve_scale(const LPoint3f &point, const LVector3f &up = LVector3f::up()); + + // Methods that get and set the matrix transforms relative to some + // other node in the scene graph. These perform an implicit wrt(). + + INLINE void set_pos(const qpNodePath &other, float x, float y, float z); + void set_pos(const qpNodePath &other, const LVecBase3f &pos); + void set_x(const qpNodePath &other, float x); + void set_y(const qpNodePath &other, float y); + void set_z(const qpNodePath &other, float z); + INLINE LPoint3f get_pos(const qpNodePath &other) const; + INLINE float get_x(const qpNodePath &other) const; + INLINE float get_y(const qpNodePath &other) const; + INLINE float get_z(const qpNodePath &other) const; + + INLINE void set_hpr(const qpNodePath &other, float h, float p, float r); + void set_hpr(const qpNodePath &other, const LVecBase3f &hpr); + void set_h(const qpNodePath &other, float h); + void set_p(const qpNodePath &other, float p); + void set_r(const qpNodePath &other, float r); + LVecBase3f get_hpr(const qpNodePath &other) const; + LVecBase3f get_hpr(const qpNodePath &other, float roll) const; + INLINE float get_h(const qpNodePath &other) const; + INLINE float get_p(const qpNodePath &other) const; + INLINE float get_r(const qpNodePath &other) const; + + INLINE void set_scale(const qpNodePath &other, float sx, float sy, float sz); + void set_scale(const qpNodePath &other, const LVecBase3f &scale); + void set_sx(const qpNodePath &other, float sx); + void set_sy(const qpNodePath &other, float sy); + void set_sz(const qpNodePath &other, float sz); + LVecBase3f get_scale(const qpNodePath &other) const; + INLINE float get_sx(const qpNodePath &other) const; + INLINE float get_sy(const qpNodePath &other) const; + INLINE float get_sz(const qpNodePath &other) const; + + INLINE void set_pos_hpr(const qpNodePath &other, + float x, float y, float z, + float h, float p, float r); + void set_pos_hpr(const qpNodePath &other, + const LVecBase3f &pos, + const LVecBase3f &hpr); + INLINE void set_hpr_scale(const qpNodePath &other, + float h, float p, float r, + float sx, float sy, float sz); + void set_hpr_scale(const qpNodePath &other, + const LVecBase3f &hpr, + const LVecBase3f &scale); + INLINE void set_pos_hpr_scale(const qpNodePath &other, + float x, float y, float z, + float h, float p, float r, + float sx, float sy, float sz); + void set_pos_hpr_scale(const qpNodePath &other, + const LVecBase3f &pos, + const LVecBase3f &hpr, + const LVecBase3f &scale); + + const LMatrix4f &get_mat(const qpNodePath &other) const; + void set_mat(const qpNodePath &other, const LMatrix4f &mat); + + LPoint3f get_relative_point(const qpNodePath &other, const LVecBase3f &point); + + INLINE void look_at(const qpNodePath &other, + float x, float y, float z); + void look_at(const qpNodePath &other, + const LPoint3f &point = LPoint3f(0.0, 0.0, 0.0), + const LVector3f &up = LVector3f::up()); + INLINE void heads_up(const qpNodePath &other, + float x, float y, float z); + void heads_up(const qpNodePath &other, + const LPoint3f &point = LPoint3f(0.0, 0.0, 0.0), + const LVector3f &up = LVector3f::up()); + + INLINE void look_at_preserve_scale(const qpNodePath &other, + float x, float y, float z); + void look_at_preserve_scale(const qpNodePath &other, + const LPoint3f &point = LPoint3f(0.0, 0.0, 0.0), + const LVector3f &up = LVector3f::up()); + INLINE void heads_up_preserve_scale(const qpNodePath &other, + float x, float y, float z); + void heads_up_preserve_scale(const qpNodePath &other, + const LPoint3f &point = LPoint3f(0.0, 0.0, 0.0), + const LVector3f &up = LVector3f::up()); + + INLINE float get_distance(const qpNodePath &other) const; + + + // Methods that affect appearance of geometry: color, texture, etc. + // These affect the state at the bottom level only. + + void set_color(float r, float g, float b, float a = 1.0, + int priority = 0); + void set_color(const Colorf &color, int priority = 0); + void set_color_off(int priority = 0); + void clear_color(); + bool has_color() const; + Colorf get_color() const; + + void set_bin(const string &bin_name, int draw_order, int priority = 0); + void clear_bin(); + bool has_bin() const; + string get_bin_name() const; + int get_bin_draw_order() const; + + void set_texture(Texture *tex, int priority = 0); + void set_texture_off(int priority = 0); + void clear_texture(); + bool has_texture() const; + bool has_texture_off() const; + Texture *get_texture() const; + + void set_material(Material *tex, int priority = 0); + void set_material_off(int priority = 0); + void clear_material(); + bool has_material() const; + PT(Material) get_material() const; + + void set_fog(Fog *fog, int priority = 0); + void set_fog_off(int priority = 0); + void clear_fog(); + bool has_fog() const; + bool has_fog_off() const; + Fog *get_fog() const; + + void set_render_mode_wireframe(int priority = 0); + void set_render_mode_filled(int priority = 0); + void clear_render_mode(); + bool has_render_mode() const; + + void set_two_sided(bool two_sided, int priority = 0); + void clear_two_sided(); + bool has_two_sided() const; + bool get_two_sided() const; + + void do_billboard_axis(const qpNodePath &camera, float offset); + void do_billboard_point_eye(const qpNodePath &camera, float offset); + void do_billboard_point_world(const qpNodePath &camera, float offset); + void set_billboard_axis(float offset = 0.0); + void set_billboard_point_eye(float offset = 0.0); + void set_billboard_point_world(float offset = 0.0); + void clear_billboard(); + bool has_billboard() const; + + void set_transparency(bool transparency, int priority = 0); + void clear_transparency(); + bool has_transparency() const; + bool get_transparency() const; + + INLINE void adjust_all_priorities(int adjustment); + + // Variants on show and hide + INLINE void show(); + INLINE void hide(); + INLINE void show_collision_solids(); + INLINE void hide_collision_solids(); + INLINE bool is_hidden() const; + qpNodePath get_hidden_ancestor() const; + + INLINE void stash(); + INLINE void unstash(); + INLINE bool is_stashed() const; + qpNodePath get_stashed_ancestor() const; + + // Comparison methods + INLINE bool operator == (const qpNodePath &other) const; + INLINE bool operator != (const qpNodePath &other) const; + INLINE bool operator < (const qpNodePath &other) const; + INLINE int compare_to(const qpNodePath &other) const; + + bool verify_complete() const; + +private: + void uncollapse_head() const; + static void find_common_ancestor(const qpNodePath &a, const qpNodePath &b, + int &a_count, int &b_count); + + CPT(RenderState) r_get_net_state(qpNodePathComponent *comp) const; + CPT(RenderState) r_get_partial_state(qpNodePathComponent *comp, int n) const; + CPT(TransformState) r_get_net_transform(qpNodePathComponent *comp) const; + CPT(TransformState) r_get_partial_transform(qpNodePathComponent *comp, int n) const; + void r_output(ostream &out, qpNodePathComponent *comp) const; + static int r_compare_to(const qpNodePathComponent *a, const qpNodePathComponent *v); + + PT(qpNodePathComponent) _head; + ErrorType _error_type; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + register_type(_type_handle, "qpNodePath"); + } + +private: + static TypeHandle _type_handle; +}; + +INLINE ostream &operator << (ostream &out, const qpNodePath &node_path); + +#include "qpnodePath.I" + +#endif diff --git a/panda/src/pgraph/qpnodePathCollection.I b/panda/src/pgraph/qpnodePathCollection.I new file mode 100644 index 0000000000..cf8ca803b0 --- /dev/null +++ b/panda/src/pgraph/qpnodePathCollection.I @@ -0,0 +1,38 @@ +// Filename: qpnodePathCollection.I +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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: qpNodePathCollection::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE qpNodePathCollection:: +~qpNodePathCollection() { +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::ls +// Access: Published +// Description: Lists all the nodes at and below each node in the +// collection hierarchically. +//////////////////////////////////////////////////////////////////// +INLINE void qpNodePathCollection:: +ls() const { + ls(nout); +} diff --git a/panda/src/pgraph/qpnodePathCollection.cxx b/panda/src/pgraph/qpnodePathCollection.cxx new file mode 100644 index 0000000000..84b98d43b5 --- /dev/null +++ b/panda/src/pgraph/qpnodePathCollection.cxx @@ -0,0 +1,397 @@ +// Filename: qpnodePathCollection.cxx +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "qpnodePathCollection.h" +//#include "findApproxPath.h" +//#include "findApproxLevel.h" + +#include "indent.h" + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +qpNodePathCollection:: +qpNodePathCollection() { +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +qpNodePathCollection:: +qpNodePathCollection(const qpNodePathCollection ©) : + _node_paths(copy._node_paths) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +operator = (const qpNodePathCollection ©) { + _node_paths = copy._node_paths; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::add_path +// Access: Published +// Description: Adds a new qpNodePath to the collection. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +add_path(const qpNodePath &node_path) { + // If the pointer to our internal array is shared by any other + // NodePathCollections, we have to copy the array now so we won't + // inadvertently modify any of our brethren NodePathCollection + // objects. + + if (_node_paths.get_ref_count() > 1) { + PTA(qpNodePath) old_node_paths = _node_paths; + _node_paths = PTA(qpNodePath)::empty_array(0); + _node_paths.v() = old_node_paths.v(); + } + + _node_paths.push_back(node_path); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::remove_path +// Access: Published +// Description: Removes the indicated qpNodePath from the collection. +// Returns true if the path was removed, false if it was +// not a member of the collection. +//////////////////////////////////////////////////////////////////// +bool qpNodePathCollection:: +remove_path(const qpNodePath &node_path) { + int path_index = -1; + for (int i = 0; path_index == -1 && i < (int)_node_paths.size(); i++) { + if (_node_paths[i] == node_path) { + path_index = i; + } + } + + if (path_index == -1) { + // The indicated path was not a member of the collection. + return false; + } + + // If the pointer to our internal array is shared by any other + // NodePathCollections, we have to copy the array now so we won't + // inadvertently modify any of our brethren NodePathCollection + // objects. + + if (_node_paths.get_ref_count() > 1) { + PTA(qpNodePath) old_node_paths = _node_paths; + _node_paths = PTA(qpNodePath)::empty_array(0); + _node_paths.v() = old_node_paths.v(); + } + + _node_paths.erase(_node_paths.begin() + path_index); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::add_paths_from +// Access: Published +// Description: Adds all the qpNodePaths indicated in the other +// collection to this path. The other paths are simply +// appended to the end of the paths in this list; +// duplicates are not automatically removed. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +add_paths_from(const qpNodePathCollection &other) { + int other_num_paths = other.get_num_paths(); + for (int i = 0; i < other_num_paths; i++) { + add_path(other.get_path(i)); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::remove_paths_from +// Access: Published +// Description: Removes from this collection all of the qpNodePaths +// listed in the other collection. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +remove_paths_from(const qpNodePathCollection &other) { + NodePaths new_paths; + int num_paths = get_num_paths(); + for (int i = 0; i < num_paths; i++) { + qpNodePath path = get_path(i); + if (!other.has_path(path)) { + new_paths.push_back(path); + } + } + _node_paths = new_paths; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::remove_duplicate_paths +// Access: Published +// Description: Removes any duplicate entries of the same NodePaths +// on this collection. If a qpNodePath appears multiple +// times, the first appearance is retained; subsequent +// appearances are removed. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +remove_duplicate_paths() { + NodePaths new_paths; + + int num_paths = get_num_paths(); + for (int i = 0; i < num_paths; i++) { + qpNodePath path = get_path(i); + bool duplicated = false; + + for (int j = 0; j < i && !duplicated; j++) { + duplicated = (path == get_path(j)); + } + + if (!duplicated) { + new_paths.push_back(path); + } + } + + _node_paths = new_paths; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::has_path +// Access: Published +// Description: Returns true if the indicated qpNodePath appears in +// this collection, false otherwise. +//////////////////////////////////////////////////////////////////// +bool qpNodePathCollection:: +has_path(const qpNodePath &path) const { + for (int i = 0; i < get_num_paths(); i++) { + if (path == get_path(i)) { + return true; + } + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::clear +// Access: Published +// Description: Removes all NodePaths from the collection. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +clear() { + _node_paths.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::is_empty +// Access: Published +// Description: Returns true if there are no NodePaths in the +// collection, false otherwise. +//////////////////////////////////////////////////////////////////// +bool qpNodePathCollection:: +is_empty() const { + return _node_paths.empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::get_num_paths +// Access: Published +// Description: Returns the number of NodePaths in the collection. +//////////////////////////////////////////////////////////////////// +int qpNodePathCollection:: +get_num_paths() const { + return _node_paths.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::get_path +// Access: Published +// Description: Returns the nth qpNodePath in the collection. +//////////////////////////////////////////////////////////////////// +qpNodePath qpNodePathCollection:: +get_path(int index) const { + nassertr(index >= 0 && index < (int)_node_paths.size(), qpNodePath()); + + return _node_paths[index]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::operator [] +// Access: Published +// Description: Returns the nth qpNodePath in the collection. This is +// the same as get_path(), but it may be a more +// convenient way to access it. +//////////////////////////////////////////////////////////////////// +qpNodePath qpNodePathCollection:: +operator [] (int index) const { + nassertr(index >= 0 && index < (int)_node_paths.size(), qpNodePath()); + + return _node_paths[index]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::ls +// Access: Published +// Description: Lists all the nodes at and below each node in the +// collection hierarchically. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +ls(ostream &out, int indent_level) const { + for (int i = 0; i < get_num_paths(); i++) { + qpNodePath path = get_path(i); + indent(out, indent_level) << path << "\n"; + path.ls(out, indent_level + 2); + out << "\n"; + } +} + +/* +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::find_all_matches +// Access: Published +// Description: Returns the complete set of all NodePaths that begin +// with any qpNodePath in this collection and can be +// extended by path. The shortest paths will be listed +// first. +//////////////////////////////////////////////////////////////////// +qpNodePathCollection qpNodePathCollection:: +find_all_matches(const string &path) const { + qpNodePathCollection result; + + FindApproxPath approx_path; + if (approx_path.add_string(path)) { + if (!is_empty()) { + FindApproxLevel level; + for (int i = 0; i < get_num_paths(); i++) { + FindApproxLevelEntry start(get_path(i), approx_path); + level.add_entry(start); + } + get_path(0).r_find_matches(result, level, -1, + qpNodePath::get_max_search_depth()); + } + } + + return result; +} +*/ + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::reparent_to +// Access: Published +// Description: Reparents all the NodePaths in the collection to the +// indicated node. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +reparent_to(const qpNodePath &other) { + for (int i = 0; i < get_num_paths(); i++) { + get_path(i).reparent_to(other); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::wrt_reparent_to +// Access: Published +// Description: Reparents all the NodePaths in the collection to the +// indicated node, adjusting each transform so as not to +// move in world coordinates. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +wrt_reparent_to(const qpNodePath &other) { + for (int i = 0; i < get_num_paths(); i++) { + get_path(i).wrt_reparent_to(other); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::show +// Access: Published +// Description: Shows all NodePaths in the collection. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +show() { + for (int i = 0; i < get_num_paths(); i++) { + get_path(i).show(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::show +// Access: Published +// Description: Hides all NodePaths in the collection. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +hide() { + for (int i = 0; i < get_num_paths(); i++) { + get_path(i).hide(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::stash +// Access: Published +// Description: Stashes all NodePaths in the collection. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +stash() { + for (int i = 0; i < get_num_paths(); i++) { + get_path(i).stash(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::unstash +// Access: Published +// Description: Unstashes all NodePaths in the collection. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +unstash() { + for (int i = 0; i < get_num_paths(); i++) { + get_path(i).unstash(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::output +// Access: Published +// Description: Writes a brief one-line description of the +// qpNodePathCollection to the indicated output stream. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +output(ostream &out) const { + if (get_num_paths() == 1) { + out << "1 NodePath"; + } else { + out << get_num_paths() << " NodePaths"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePathCollection::write +// Access: Published +// Description: Writes a complete multi-line description of the +// qpNodePathCollection to the indicated output stream. +//////////////////////////////////////////////////////////////////// +void qpNodePathCollection:: +write(ostream &out, int indent_level) const { + for (int i = 0; i < get_num_paths(); i++) { + indent(out, indent_level) << get_path(i) << "\n"; + } +} diff --git a/panda/src/pgraph/qpnodePathCollection.h b/panda/src/pgraph/qpnodePathCollection.h new file mode 100644 index 0000000000..87f03e4b9a --- /dev/null +++ b/panda/src/pgraph/qpnodePathCollection.h @@ -0,0 +1,83 @@ +// Filename: qpnodePathCollection.h +// Created by: drose (06Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 qpNODEPATHCOLLECTION_H +#define qpNODEPATHCOLLECTION_H + +#include "pandabase.h" +#include "qpnodePath.h" +#include "pointerToArray.h" + +//////////////////////////////////////////////////////////////////// +// Class : NodePathCollection +// Description : This is a set of zero or more NodePaths. It's handy +// for returning from functions that need to return +// multiple NodePaths (for instance, +// NodePaths::get_children). +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA qpNodePathCollection { +PUBLISHED: + qpNodePathCollection(); + qpNodePathCollection(const qpNodePathCollection ©); + void operator = (const qpNodePathCollection ©); + INLINE ~qpNodePathCollection(); + + void add_path(const qpNodePath &node_path); + bool remove_path(const qpNodePath &node_path); + void add_paths_from(const qpNodePathCollection &other); + void remove_paths_from(const qpNodePathCollection &other); + void remove_duplicate_paths(); + bool has_path(const qpNodePath &path) const; + void clear(); + + bool is_empty() const; + int get_num_paths() const; + qpNodePath get_path(int index) const; + qpNodePath operator [] (int index) const; + + // Handy operations on many NodePaths at once. + INLINE void ls() const; + void ls(ostream &out, int indent_level = 0) const; + + // qpNodePathCollection find_all_matches(const string &path) const; + void reparent_to(const qpNodePath &other); + void wrt_reparent_to(const qpNodePath &other); + + void show(); + void hide(); + void stash(); + void unstash(); + + void output(ostream &out) const; + void write(ostream &out, int indent_level = 0) const; + +private: + typedef PTA(qpNodePath) NodePaths; + NodePaths _node_paths; +}; + +INLINE ostream &operator << (ostream &out, const qpNodePathCollection &col) { + col.output(out); + return out; +} + +#include "qpnodePathCollection.I" + +#endif + + diff --git a/panda/src/pgraph/nodeChainComponent.I b/panda/src/pgraph/qpnodePathComponent.I similarity index 71% rename from panda/src/pgraph/nodeChainComponent.I rename to panda/src/pgraph/qpnodePathComponent.I index bd5efda076..09eb73f6ac 100644 --- a/panda/src/pgraph/nodeChainComponent.I +++ b/panda/src/pgraph/qpnodePathComponent.I @@ -1,4 +1,4 @@ -// Filename: nodeChainComponent.I +// Filename: qpnodePathComponent.I // Created by: drose (25Feb02) // //////////////////////////////////////////////////////////////////// @@ -18,36 +18,36 @@ //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::CData::Constructor +// Function: qpNodePathComponent::CData::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE NodeChainComponent::CData:: +INLINE qpNodePathComponent::CData:: CData() { _length = 1; } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::CData::Copy Constructor +// Function: qpNodePathComponent::CData::Copy Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE NodeChainComponent::CData:: -CData(const NodeChainComponent::CData ©) : +INLINE qpNodePathComponent::CData:: +CData(const qpNodePathComponent::CData ©) : _next(copy._next), _length(copy._length) { } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::Constructor +// Function: qpNodePathComponent::Constructor // Access: Private -// Description: Constructs a new NodeChainComponent from the +// Description: Constructs a new qpNodePathComponent from the // indicated node. Don't try to call this directly; ask // the PandaNode to do it for you. //////////////////////////////////////////////////////////////////// -INLINE NodeChainComponent:: -NodeChainComponent(PandaNode *node, NodeChainComponent *next) : +INLINE qpNodePathComponent:: +qpNodePathComponent(PandaNode *node, qpNodePathComponent *next) : _node(node) { #ifdef DO_MEMORY_USAGE @@ -56,85 +56,85 @@ NodeChainComponent(PandaNode *node, NodeChainComponent *next) : CDWriter cdata(_cycler); cdata->_next = next; - if (next != (NodeChainComponent *)NULL) { + if (next != (qpNodePathComponent *)NULL) { cdata->_length = next->get_length() + 1; } } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::Copy Constructor +// Function: qpNodePathComponent::Copy Constructor // Access: Private -// Description: NodeChainComponents should not be copied. +// Description: qpNodePathComponents should not be copied. //////////////////////////////////////////////////////////////////// -INLINE NodeChainComponent:: -NodeChainComponent(const NodeChainComponent ©) { +INLINE qpNodePathComponent:: +qpNodePathComponent(const qpNodePathComponent ©) { nassertv(false); } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::Copy Assignment Operator +// Function: qpNodePathComponent::Copy Assignment Operator // Access: Private -// Description: NodeChainComponents should not be copied. +// Description: qpNodePathComponents should not be copied. //////////////////////////////////////////////////////////////////// -INLINE void NodeChainComponent:: -operator = (const NodeChainComponent ©) { +INLINE void qpNodePathComponent:: +operator = (const qpNodePathComponent ©) { nassertv(false); } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::Destructor +// Function: qpNodePathComponent::Destructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE NodeChainComponent:: -~NodeChainComponent() { +INLINE qpNodePathComponent:: +~qpNodePathComponent() { nassertv(_node != (PandaNode *)NULL); _node->delete_component(this); } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::get_node +// Function: qpNodePathComponent::get_node // Access: Public // Description: Returns the node referenced by this component. //////////////////////////////////////////////////////////////////// -INLINE PandaNode *NodeChainComponent:: +INLINE PandaNode *qpNodePathComponent:: get_node() const { return _node; } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::is_top_node +// Function: qpNodePathComponent::is_top_node // Access: Public // Description: Returns true if this component represents the top // node in the chain. //////////////////////////////////////////////////////////////////// -INLINE bool NodeChainComponent:: +INLINE bool qpNodePathComponent:: is_top_node() const { CDReader cdata(_cycler); - return (cdata->_next == (NodeChainComponent *)NULL); + return (cdata->_next == (qpNodePathComponent *)NULL); } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::is_collapsed +// Function: qpNodePathComponent::is_collapsed // Access: Public // Description: Returns true if this component has been collapsed // with another component. In this case, the component // itself is invalid, and the collapsed component should // be used instead. //////////////////////////////////////////////////////////////////// -INLINE bool NodeChainComponent:: +INLINE bool qpNodePathComponent:: is_collapsed() const { CDReader cdata(_cycler); return (cdata->_length == 0); } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::get_length +// Function: qpNodePathComponent::get_length // Access: Public // Description: Returns the length of the chain. //////////////////////////////////////////////////////////////////// -INLINE int NodeChainComponent:: +INLINE int qpNodePathComponent:: get_length() const { CDReader cdata(_cycler); nassertr(!is_collapsed(), 0); @@ -142,59 +142,59 @@ get_length() const { } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::get_collapsed +// Function: qpNodePathComponent::get_collapsed // Access: Public // Description: If is_collapsed() returns true, this is the component // that this one has been collapsed with, and should be // replaced with. //////////////////////////////////////////////////////////////////// -INLINE NodeChainComponent *NodeChainComponent:: +INLINE qpNodePathComponent *qpNodePathComponent:: get_collapsed() const { CDReader cdata(_cycler); - nassertr(is_collapsed(), (NodeChainComponent *)NULL); + nassertr(is_collapsed(), (qpNodePathComponent *)NULL); return cdata->_next; } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::set_next +// Function: qpNodePathComponent::set_next // Access: Private // Description: Sets the next pointer in the chain. //////////////////////////////////////////////////////////////////// -INLINE void NodeChainComponent:: -set_next(NodeChainComponent *next) { +INLINE void qpNodePathComponent:: +set_next(qpNodePathComponent *next) { CDWriter cdata(_cycler); nassertv(!is_collapsed()); - nassertv(next != (NodeChainComponent *)NULL); + nassertv(next != (qpNodePathComponent *)NULL); cdata->_next = next; } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::set_top_node +// Function: qpNodePathComponent::set_top_node // Access: Private // Description: Severs any connection to the next pointer in the // chain and makes this component a top node. //////////////////////////////////////////////////////////////////// -INLINE void NodeChainComponent:: +INLINE void qpNodePathComponent:: set_top_node() { CDWriter cdata(_cycler); nassertv(!is_collapsed()); - cdata->_next = (NodeChainComponent *)NULL; + cdata->_next = (qpNodePathComponent *)NULL; } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::collapse_with +// Function: qpNodePathComponent::collapse_with // Access: Private // Description: Indicates that this component pointer is no longer // valid, and that the indicated component should be // used instead. This is done whenever two -// NodeChainComponents have been collapsed together due +// qpNodePathComponents have been collapsed together due // to an instance being removed higher up in the graph. //////////////////////////////////////////////////////////////////// -INLINE void NodeChainComponent:: -collapse_with(NodeChainComponent *next) { +INLINE void qpNodePathComponent:: +collapse_with(qpNodePathComponent *next) { CDWriter cdata(_cycler); nassertv(!is_collapsed()); - nassertv(next != (NodeChainComponent *)NULL); + nassertv(next != (qpNodePathComponent *)NULL); cdata->_next = next; cdata->_length = 0; diff --git a/panda/src/pgraph/nodeChainComponent.cxx b/panda/src/pgraph/qpnodePathComponent.cxx similarity index 79% rename from panda/src/pgraph/nodeChainComponent.cxx rename to panda/src/pgraph/qpnodePathComponent.cxx index dbb2cf59f4..b626afdb72 100644 --- a/panda/src/pgraph/nodeChainComponent.cxx +++ b/panda/src/pgraph/qpnodePathComponent.cxx @@ -1,4 +1,4 @@ -// Filename: nodeChainComponent.cxx +// Filename: qpnodePathComponent.cxx // Created by: drose (25Feb02) // //////////////////////////////////////////////////////////////////// @@ -16,54 +16,54 @@ // //////////////////////////////////////////////////////////////////// -#include "nodeChainComponent.h" +#include "qpnodePathComponent.h" -TypeHandle NodeChainComponent::_type_handle; +TypeHandle qpNodePathComponent::_type_handle; //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::CData::make_copy +// Function: qpNodePathComponent::CData::make_copy // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// -CycleData *NodeChainComponent::CData:: +CycleData *qpNodePathComponent::CData:: make_copy() const { return new CData(*this); } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::get_next +// Function: qpNodePathComponent::get_next // Access: Public // Description: Returns the next component in the chain. //////////////////////////////////////////////////////////////////// -NodeChainComponent *NodeChainComponent:: +qpNodePathComponent *qpNodePathComponent:: get_next() const { CDReader cdata(_cycler); - nassertr(!is_collapsed(), (NodeChainComponent *)NULL); + nassertr(!is_collapsed(), (qpNodePathComponent *)NULL); - NodeChainComponent *next = cdata->_next; + qpNodePathComponent *next = cdata->_next; // If the next component has been collapsed, transparently update // the pointer to get the actual node, and store the new pointer, // before we return. Collapsing can happen at any time to any // component in the chain and we have to deal with it. - if (next != (NodeChainComponent *)NULL && next->is_collapsed()) { + if (next != (qpNodePathComponent *)NULL && next->is_collapsed()) { next = next->uncollapse(); - ((NodeChainComponent *)this)->set_next(next); + ((qpNodePathComponent *)this)->set_next(next); } return next; } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::fix_length +// Function: qpNodePathComponent::fix_length // Access: Public // Description: Checks that the length indicated by the component is // one more than the length of its predecessor. If this // is broken, fixes it and returns true indicating the // component has been changed; otherwise, returns false. //////////////////////////////////////////////////////////////////// -bool NodeChainComponent:: +bool qpNodePathComponent:: fix_length() { int length_should_be = 1; if (!is_top_node()) { @@ -79,7 +79,7 @@ fix_length() { } //////////////////////////////////////////////////////////////////// -// Function: NodeChainComponent::uncollapse +// Function: qpNodePathComponent::uncollapse // Access: Public // Description: Returns this component pointer if the component is // not collapsed; or if it has been collapsed, returns @@ -90,9 +90,9 @@ fix_length() { // when a node is removed further up the chain that // results in two instances becoming the same thing. //////////////////////////////////////////////////////////////////// -NodeChainComponent *NodeChainComponent:: +qpNodePathComponent *qpNodePathComponent:: uncollapse() { - NodeChainComponent *comp = this; + qpNodePathComponent *comp = this; while (comp->is_collapsed()) { comp = comp->get_collapsed(); diff --git a/panda/src/pgraph/nodeChainComponent.h b/panda/src/pgraph/qpnodePathComponent.h similarity index 65% rename from panda/src/pgraph/nodeChainComponent.h rename to panda/src/pgraph/qpnodePathComponent.h index a245ba340e..466fcb3161 100644 --- a/panda/src/pgraph/nodeChainComponent.h +++ b/panda/src/pgraph/qpnodePathComponent.h @@ -1,4 +1,4 @@ -// Filename: nodeChainComponent.h +// Filename: qpnodePathComponent.h // Created by: drose (25Feb02) // //////////////////////////////////////////////////////////////////// @@ -16,8 +16,8 @@ // //////////////////////////////////////////////////////////////////// -#ifndef NODECHAINCOMPONENT_H -#define NODECHAINCOMPONENT_H +#ifndef qpNODEPATHCOMPONENT_H +#define qpNODEPATHCOMPONENT_H #include "pandabase.h" @@ -29,45 +29,45 @@ #include "cycleDataWriter.h" //////////////////////////////////////////////////////////////////// -// Class : NodeChainComponent -// Description : This is one component of a NodeChain. These are +// Class : qpNodePathComponent +// Description : This is one component of a NodePath. These are // stored on each PandaNode, as many as one for each of // the possible instances of the node (but they only // exist when they are requested, to minimize memory -// waste). A NodeChain represents a singly-linked list +// waste). A NodePath represents a singly-linked list // of these from an arbitrary component in the graph to // the root. // -// This whole NodeChain system is used to disambiguate +// This whole NodePath system is used to disambiguate // instances in the scene graph, and the -// NodeChainComponents are stored in the nodes -// themselves to allow the nodes to keep these up to -// date as the scene graph is manipulated. +// NodePathComponents are stored in the nodes themselves +// to allow the nodes to keep these up to date as the +// scene graph is manipulated. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA NodeChainComponent : public ReferenceCount { +class EXPCL_PANDA qpNodePathComponent : public ReferenceCount { private: - INLINE NodeChainComponent(PandaNode *node, NodeChainComponent *next = NULL); - INLINE NodeChainComponent(const NodeChainComponent ©); - INLINE void operator = (const NodeChainComponent ©); + INLINE qpNodePathComponent(PandaNode *node, qpNodePathComponent *next = NULL); + INLINE qpNodePathComponent(const qpNodePathComponent ©); + INLINE void operator = (const qpNodePathComponent ©); public: - INLINE ~NodeChainComponent(); + INLINE ~qpNodePathComponent(); INLINE PandaNode *get_node() const; INLINE bool is_top_node() const; INLINE bool is_collapsed() const; - NodeChainComponent *get_next() const; + qpNodePathComponent *get_next() const; INLINE int get_length() const; - INLINE NodeChainComponent *get_collapsed() const; + INLINE qpNodePathComponent *get_collapsed() const; bool fix_length(); - NodeChainComponent *uncollapse(); + qpNodePathComponent *uncollapse(); private: - INLINE void set_next(NodeChainComponent *next); + INLINE void set_next(qpNodePathComponent *next); INLINE void set_top_node(); - INLINE void collapse_with(NodeChainComponent *next); + INLINE void collapse_with(qpNodePathComponent *next); PT(PandaNode) _node; @@ -78,7 +78,7 @@ private: CData(const CData ©); virtual CycleData *make_copy() const; - PT(NodeChainComponent) _next; + PT(qpNodePathComponent) _next; int _length; }; @@ -92,7 +92,7 @@ public: } static void init_type() { ReferenceCount::init_type(); - register_type(_type_handle, "NodeChainComponent", + register_type(_type_handle, "qpNodePathComponent", ReferenceCount::get_class_type()); } @@ -101,6 +101,6 @@ private: friend class PandaNode; }; -#include "nodeChainComponent.I" +#include "qpnodePathComponent.I" #endif diff --git a/panda/src/pgraph/test_pgraph.cxx b/panda/src/pgraph/test_pgraph.cxx index b1d60316ae..9e4e199e55 100644 --- a/panda/src/pgraph/test_pgraph.cxx +++ b/panda/src/pgraph/test_pgraph.cxx @@ -17,7 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "pandaNode.h" -#include "nodeChain.h" +#include "qpnodePath.h" #include "textureAttrib.h" #include "colorAttrib.h" #include "transformState.h" @@ -74,20 +74,20 @@ main(int argc, char *argv[]) { cerr << "\n"; list_hierarchy(root, 0); - NodeChain ch_g1(g1); + qpNodePath ch_g1(g1); cerr << ch_g1 << "\n"; - NodeChain ch_g2(g2); + qpNodePath ch_g2(g2); cerr << ch_g2 << "\n"; - cerr << *ch_g1.get_rel_transform(ch_g2) << "\n"; - cerr << *ch_g2.get_rel_transform(ch_g1) << "\n"; + cerr << *ch_g1.get_transform(ch_g2) << "\n"; + cerr << *ch_g2.get_transform(ch_g1) << "\n"; - cerr << *ch_g1.get_rel_state(ch_g2) << "\n"; - cerr << *ch_g2.get_rel_state(ch_g1) << "\n"; + cerr << *ch_g1.get_state(ch_g2) << "\n"; + cerr << *ch_g2.get_state(ch_g1) << "\n"; - cerr << *ch_g2.get_rel_transform(ch_g2) << "\n"; - cerr << *ch_g2.get_rel_state(ch_g2) << "\n"; + cerr << *ch_g2.get_transform(ch_g2) << "\n"; + cerr << *ch_g2.get_state(ch_g2) << "\n"; cerr << "\n"; return 0; diff --git a/panda/src/pgraph/transformState.I b/panda/src/pgraph/transformState.I index a6f4dd51e9..f151fcce16 100644 --- a/panda/src/pgraph/transformState.I +++ b/panda/src/pgraph/transformState.I @@ -128,17 +128,52 @@ has_components() const { return ((_flags & F_has_components) != 0); } +//////////////////////////////////////////////////////////////////// +// Function: TransformState::has_pos +// Access: Published +// Description: Returns true if the transform's pos component can be +// extracted out separately. This is generally always +// true. +//////////////////////////////////////////////////////////////////// +INLINE bool TransformState:: +has_pos() const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::has_hpr +// Access: Published +// Description: Returns true if the transform's rotation component +// can be extracted out separately and described as a +// set of Euler angles. This is generally true only +// when has_components() is true. +//////////////////////////////////////////////////////////////////// +INLINE bool TransformState:: +has_hpr() const { + return has_components(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::has_scale +// Access: Published +// Description: Returns true if the transform's scale component +// can be extracted out separately. This is generally +// true only when has_components() is true. +//////////////////////////////////////////////////////////////////// +INLINE bool TransformState:: +has_scale() const { + return has_components(); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::get_pos // Access: Published // Description: Returns the pos component of the transform. It is an -// error to call this if has_components() returned -// false. +// error to call this if has_pos() returned false. //////////////////////////////////////////////////////////////////// INLINE const LVecBase3f &TransformState:: get_pos() const { check_components(); - nassertr(has_components(), _pos); return _pos; } @@ -152,7 +187,7 @@ get_pos() const { INLINE const LVecBase3f &TransformState:: get_hpr() const { check_components(); - nassertr(has_components(), _hpr); + nassertr(has_hpr(), _hpr); return _hpr; } @@ -166,7 +201,7 @@ get_hpr() const { INLINE const LVecBase3f &TransformState:: get_scale() const { check_components(); - nassertr(has_components(), _scale); + nassertr(has_scale(), _scale); return _scale; } diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 21b8b67037..e0221fee42 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -238,6 +238,54 @@ make_mat(const LMatrix4f &mat) { return return_new(attrib); } +//////////////////////////////////////////////////////////////////// +// Function: TransformState::set_pos +// Access: Published +// Description: Returns a new TransformState object that represents the +// original TransformState with its pos component +// replaced with the indicated value. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +set_pos(const LVecBase3f &pos) const { + if ((_flags & F_components_given) != 0) { + // If we started with a componentwise transform, we keep it that + // way. + return make_pos_hpr_scale(pos, get_hpr(), get_scale()); + + } else { + // Otherwise, we have a matrix transform, and we keep it that way. + LMatrix4f mat = get_mat(); + mat.set_row(3, pos); + return make_mat(mat); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::set_hpr +// Access: Published +// Description: Returns a new TransformState object that represents the +// original TransformState with its hpr component +// replaced with the indicated value, if possible. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +set_hpr(const LVecBase3f &hpr) const { + nassertr(has_components(), this); + return make_pos_hpr_scale(get_pos(), hpr, get_scale()); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::set_scale +// Access: Published +// Description: Returns a new TransformState object that represents the +// original TransformState with its scale component +// replaced with the indicated value, if possible. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +set_scale(const LVecBase3f &scale) const { + nassertr(has_components(), this); + return make_pos_hpr_scale(get_pos(), get_scale(), get_hpr()); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::compose // Access: Published @@ -532,10 +580,14 @@ calc_components() { // other explanation is that we were constructed via a matrix. nassertv((_flags & F_mat_known) != 0); - bool possible = decompose_matrix(get_mat(), _scale, _hpr, _pos); + const LMatrix4f &mat = get_mat(); + bool possible = decompose_matrix(mat, _scale, _hpr, _pos); if (possible) { // Some matrices can't be decomposed into scale, hpr, pos. _flags |= F_has_components; + + // However, we can always get at least the pos. + mat.get_row3(_pos, 3); } } diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index ad1dda51fb..aba2b1fbbd 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -80,11 +80,18 @@ PUBLISHED: INLINE bool is_identity() const; INLINE bool is_singular() const; INLINE bool has_components() const; + INLINE bool has_pos() const; + INLINE bool has_hpr() const; + INLINE bool has_scale() const; INLINE const LVecBase3f &get_pos() const; INLINE const LVecBase3f &get_hpr() const; INLINE const LVecBase3f &get_scale() const; INLINE const LMatrix4f &get_mat() const; + CPT(TransformState) set_pos(const LVecBase3f &pos) const; + CPT(TransformState) set_hpr(const LVecBase3f &hpr) const; + CPT(TransformState) set_scale(const LVecBase3f &scale) const; + CPT(TransformState) compose(const TransformState *other) const; CPT(TransformState) invert_compose(const TransformState *other) const; diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index f067354e84..15c01c99ee 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -144,7 +144,7 @@ make_camera(GraphicsWindow *window) { PT(Lens) lens = new PerspectiveLens; lens->set_film_size(win_width, win_height); camera->set_lens(lens); - dr->set_qpcamera(NodeChain(camera)); + dr->set_qpcamera(qpNodePath(camera)); return camera; } @@ -216,7 +216,7 @@ get_models(PandaNode *parent, int argc, char *argv[]) { cerr << "Unable to load " << filename << "\n"; } else { - node->ls(); + node->ls(cerr, 0); parent->add_child(node); } } @@ -277,7 +277,7 @@ main(int argc, char *argv[]) { // Now we just need to make a scene graph for the camera to render. PT(PandaNode) render = new PandaNode("render"); render->add_child(camera); - camera->set_scene(NodeChain(render)); + camera->set_scene(qpNodePath(render)); // Set up a data graph for tracking user input. For now, this uses // the old-style graph interface.