Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/pgraph/nodePath.cxx

Go to the documentation of this file.
00001 // Filename: nodePath.cxx
00002 // Created by:  drose (25Feb02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "nodePath.h"
00020 #include "nodePathCollection.h"
00021 #include "findApproxPath.h"
00022 #include "findApproxLevelEntry.h"
00023 #include "findApproxLevel.h"
00024 #include "config_pgraph.h"
00025 #include "colorAttrib.h"
00026 #include "colorScaleAttrib.h"
00027 #include "cullBinAttrib.h"
00028 #include "textureAttrib.h"
00029 #include "materialAttrib.h"
00030 #include "fogAttrib.h"
00031 #include "renderModeAttrib.h"
00032 #include "cullFaceAttrib.h"
00033 #include "alphaTestAttrib.h"
00034 #include "depthTestAttrib.h"
00035 #include "depthWriteAttrib.h"
00036 #include "billboardEffect.h"
00037 #include "compassEffect.h"
00038 #include "showBoundsEffect.h"
00039 #include "transparencyAttrib.h"
00040 #include "materialPool.h"
00041 #include "look_at.h"
00042 #include "compose_matrix.h"
00043 #include "plist.h"
00044 #include "boundingSphere.h"
00045 #include "geomNode.h"
00046 #include "sceneGraphReducer.h"
00047 #include "textureCollection.h"
00048 #include "globPattern.h"
00049 #include "config_gobj.h"
00050 #include "bamFile.h"
00051 #include "dcast.h"
00052 
00053 // stack seems to overflow on Intel C++ at 7000.  If we need more than 
00054 // 7000, need to increase stack size.
00055 int NodePath::_max_search_depth = 7000; 
00056 TypeHandle NodePath::_type_handle;
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: NodePath::get_num_nodes
00060 //       Access: Published
00061 //  Description: Returns the number of nodes in the path.
00062 ////////////////////////////////////////////////////////////////////
00063 int NodePath::
00064 get_num_nodes() const {
00065   if (is_empty()) {
00066     return 0;
00067   }
00068   uncollapse_head();
00069   return _head->get_length();
00070 }
00071 
00072 ////////////////////////////////////////////////////////////////////
00073 //     Function: NodePath::get_node
00074 //       Access: Published
00075 //  Description: Returns the nth node of the path, where 0 is the
00076 //               referenced (bottom) node and get_num_nodes() - 1 is
00077 //               the top node.  This requires iterating through the
00078 //               path.
00079 ////////////////////////////////////////////////////////////////////
00080 PandaNode *NodePath::
00081 get_node(int index) const {
00082   nassertr(index >= 0 && index < get_num_nodes(), NULL);
00083 
00084   uncollapse_head();
00085   NodePathComponent *comp = _head;
00086   while (index > 0) {
00087     // If this assertion fails, the index was out of range; the
00088     // component's length must have been invalid.
00089     nassertr(comp != (NodePathComponent *)NULL, NULL);
00090     comp = comp->get_next();
00091     index--;
00092   }
00093 
00094   // If this assertion fails, the index was out of range; the
00095   // component's length must have been invalid.
00096   nassertr(comp != (NodePathComponent *)NULL, NULL);
00097   return comp->get_node();
00098 }
00099 
00100 ////////////////////////////////////////////////////////////////////
00101 //     Function: NodePath::get_top_node
00102 //       Access: Published
00103 //  Description: Returns the top node of the path, or NULL if the path
00104 //               is empty.  This requires iterating through the path.
00105 ////////////////////////////////////////////////////////////////////
00106 PandaNode *NodePath::
00107 get_top_node() const {
00108   if (is_empty()) {
00109     return (PandaNode *)NULL;
00110   }
00111 
00112   uncollapse_head();
00113   NodePathComponent *comp = _head;
00114   while (!comp->is_top_node()) {
00115     comp = comp->get_next();
00116     nassertr(comp != (NodePathComponent *)NULL, NULL);
00117   }
00118 
00119   return comp->get_node();
00120 }
00121 
00122 
00123 ////////////////////////////////////////////////////////////////////
00124 //     Function: NodePath::get_children
00125 //       Access: Published
00126 //  Description: Returns the set of all child nodes of the referenced
00127 //               node.
00128 ////////////////////////////////////////////////////////////////////
00129 NodePathCollection NodePath::
00130 get_children() const {
00131   NodePathCollection result;
00132   nassertr_always(!is_empty(), result);
00133 
00134   PandaNode *bottom_node = node();
00135 
00136   PandaNode::Children cr = bottom_node->get_children();
00137   int num_children = cr.get_num_children();
00138   for (int i = 0; i < num_children; i++) {
00139     NodePath child;
00140     child._head = PandaNode::get_component(_head, cr.get_child(i));
00141     result.add_path(child);
00142   }
00143 
00144   return result;
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: NodePath::find
00149 //       Access: Published
00150 //  Description: Searches for a node below the referenced node that
00151 //               matches the indicated string.  Returns the shortest
00152 //               match found, if any, or an empty NodePath if no match
00153 //               can be found.
00154 ////////////////////////////////////////////////////////////////////
00155 NodePath NodePath::
00156 find(const string &path) const {
00157   nassertr_always(!is_empty(), fail());
00158 
00159   NodePathCollection col;
00160   find_matches(col, path, 1);
00161 
00162   if (col.is_empty()) {
00163     return NodePath::not_found();
00164   }
00165 
00166   return col.get_path(0);
00167 }
00168 
00169 ////////////////////////////////////////////////////////////////////
00170 //     Function: NodePath::find_path_to
00171 //       Access: Published
00172 //  Description: Searches for the indicated node below this node and
00173 //               returns the shortest NodePath that connects them.
00174 ////////////////////////////////////////////////////////////////////
00175 NodePath NodePath::
00176 find_path_to(PandaNode *node) const {
00177   nassertr_always(!is_empty(), fail());
00178   nassertr(node != (PandaNode *)NULL, fail());
00179 
00180   NodePathCollection col;
00181   FindApproxPath approx_path;
00182   approx_path.add_match_many(0);
00183   approx_path.add_match_pointer(node, 0);
00184   find_matches(col, approx_path, 1);
00185 
00186   if (col.is_empty()) {
00187     return NodePath::not_found();
00188   }
00189 
00190   return col.get_path(0);
00191 }
00192 
00193 ////////////////////////////////////////////////////////////////////
00194 //     Function: NodePath::find_all_matches
00195 //       Access: Published
00196 //  Description: Returns the complete set of all NodePaths that begin
00197 //               with this NodePath and can be extended by
00198 //               path.  The shortest paths will be listed
00199 //               first.
00200 ////////////////////////////////////////////////////////////////////
00201 NodePathCollection NodePath::
00202 find_all_matches(const string &path) const {
00203   NodePathCollection col;
00204   nassertr_always(!is_empty(), col);
00205   nassertr(verify_complete(), col);
00206   find_matches(col, path, -1);
00207   return col;
00208 }
00209 
00210 ////////////////////////////////////////////////////////////////////
00211 //     Function: NodePath::find_all_paths_to
00212 //       Access: Published
00213 //  Description: Returns the set of all NodePaths that extend from
00214 //               this NodePath down to the indicated node.  The
00215 //               shortest paths will be listed first.
00216 ////////////////////////////////////////////////////////////////////
00217 NodePathCollection NodePath::
00218 find_all_paths_to(PandaNode *node) const {
00219   NodePathCollection col;
00220   nassertr_always(!is_empty(), col);
00221   nassertr(verify_complete(), col);
00222   nassertr(node != (PandaNode *)NULL, col);
00223   FindApproxPath approx_path;
00224   approx_path.add_match_many(0);
00225   approx_path.add_match_pointer(node, 0);
00226   find_matches(col, approx_path, -1);
00227   return col;
00228 }
00229 
00230 ////////////////////////////////////////////////////////////////////
00231 //     Function: NodePath::reparent_to
00232 //       Access: Published
00233 //  Description: Removes the referenced node of the NodePath from its
00234 //               current parent and attaches it to the referenced node of
00235 //               the indicated NodePath.
00236 ////////////////////////////////////////////////////////////////////
00237 void NodePath::
00238 reparent_to(const NodePath &other, int sort) {
00239   nassertv(verify_complete());
00240   nassertv(other.verify_complete());
00241   nassertv_always(!is_empty());
00242   nassertv_always(!other.is_empty());
00243 
00244   uncollapse_head();
00245   other.uncollapse_head();
00246   PandaNode::reparent(other._head, _head, sort);
00247 }
00248 
00249 ////////////////////////////////////////////////////////////////////
00250 //     Function: NodePath::wrt_reparent_to
00251 //       Access: Published
00252 //  Description: This functions identically to reparent_to(), except
00253 //               the transform on this node is also adjusted so that
00254 //               the node remains in the same place in world
00255 //               coordinates, even if it is reparented into a
00256 //               different coordinate system.
00257 ////////////////////////////////////////////////////////////////////
00258 void NodePath::
00259 wrt_reparent_to(const NodePath &other, int sort) {
00260   nassertv(verify_complete());
00261   nassertv(other.verify_complete());
00262   nassertv_always(!is_empty());
00263   nassertv_always(!other.is_empty());
00264 
00265   set_transform(get_transform(other));
00266   reparent_to(other, sort);
00267 }
00268 
00269 ////////////////////////////////////////////////////////////////////
00270 //     Function: NodePath::instance_to
00271 //       Access: Published
00272 //  Description: Adds the referenced node of the NodePath as a child
00273 //               of the referenced node of the indicated other
00274 //               NodePath.  Any other parent-child relations of the
00275 //               node are unchanged; in particular, the node is not
00276 //               removed from its existing parent, if any.
00277 //
00278 //               If the node already had an existing parent, this
00279 //               method will create a new instance of the node within
00280 //               the scene graph.
00281 //
00282 //               This does not change the NodePath itself, but does
00283 //               return a new NodePath that reflects the new instance
00284 //               node.
00285 ////////////////////////////////////////////////////////////////////
00286 NodePath NodePath::
00287 instance_to(const NodePath &other, int sort) const {
00288   nassertr(verify_complete(), NodePath::fail());
00289   nassertr(other.verify_complete(), NodePath::fail());
00290   nassertr_always(!is_empty(), NodePath::fail());
00291   nassertr(!other.is_empty(), NodePath::fail());
00292 
00293   uncollapse_head();
00294   other.uncollapse_head();
00295 
00296   NodePath new_instance;
00297   new_instance._head = PandaNode::attach(other._head, node(), sort);
00298 
00299   return new_instance;
00300 }
00301 
00302 ////////////////////////////////////////////////////////////////////
00303 //     Function: NodePath::instance_under_node
00304 //       Access: Published
00305 //  Description: Behaves like instance_to(), but implicitly creates a
00306 //               new node to instance the geometry under, and returns a
00307 //               NodePath to that new node.  This allows the
00308 //               programmer to set a unique state and/or transform on
00309 //               this instance.
00310 ////////////////////////////////////////////////////////////////////
00311 NodePath NodePath::
00312 instance_under_node(const NodePath &other, const string &name, int sort) const {
00313   NodePath new_node = other.attach_new_node(name, sort);
00314   NodePath instance = instance_to(new_node);
00315   if (instance.is_empty()) {
00316     new_node.remove_node();
00317     return instance;
00318   }
00319   return new_node;
00320 }
00321 
00322 ////////////////////////////////////////////////////////////////////
00323 //     Function: NodePath::copy_to
00324 //       Access: Published
00325 //  Description: Functions exactly like instance_to(), except a deep
00326 //               copy is made of the referenced node and all of its
00327 //               descendents, which is then parented to the indicated
00328 //               node.  A NodePath to the newly created copy is
00329 //               returned.
00330 ////////////////////////////////////////////////////////////////////
00331 NodePath NodePath::
00332 copy_to(const NodePath &other, int sort) const {
00333   nassertr(verify_complete(), fail());
00334   nassertr(other.verify_complete(), fail());
00335   nassertr_always(!is_empty(), fail());
00336   nassertr(!other.is_empty(), fail());
00337 
00338   PandaNode *source_node = node();
00339   PT(PandaNode) copy_node = source_node->copy_subgraph();
00340   nassertr(copy_node != (PandaNode *)NULL, fail());
00341 
00342   return other.attach_new_node(copy_node, sort);
00343 }
00344 
00345 ////////////////////////////////////////////////////////////////////
00346 //     Function: NodePath::attach_new_node
00347 //       Access: Published
00348 //  Description: Attaches a new node, with or without existing
00349 //               parents, to the scene graph below the referenced node
00350 //               of this NodePath.  This is the preferred way to add
00351 //               nodes to the graph.
00352 //
00353 //               This does *not* automatically extend the current
00354 //               NodePath to reflect the attachment; however, a
00355 //               NodePath that does reflect this extension is
00356 //               returned.
00357 ////////////////////////////////////////////////////////////////////
00358 NodePath NodePath::
00359 attach_new_node(PandaNode *node, int sort) const {
00360   nassertr(verify_complete(), NodePath::fail());
00361   nassertr_always(!is_empty(), NodePath());
00362   nassertr(node != (PandaNode *)NULL, NodePath());
00363 
00364   uncollapse_head();
00365   NodePath new_path(*this);
00366   new_path._head = PandaNode::attach(_head, node, sort);
00367   return new_path;
00368 }
00369 
00370 ////////////////////////////////////////////////////////////////////
00371 //     Function: NodePath::remove_node
00372 //       Access: Published
00373 //  Description: Disconnects the referenced node from the scene graph.
00374 //               This will also delete the node if there are no other
00375 //               pointers to it.
00376 //
00377 //               Normally, this should be called only when you are
00378 //               really done with the node.  If you want to remove a
00379 //               node from the scene graph but keep it around for
00380 //               later, you should probably use reparent_to() and put
00381 //               it under a holding node instead.
00382 //
00383 //               After the node is removed, the NodePath will have
00384 //               been cleared.
00385 ////////////////////////////////////////////////////////////////////
00386 void NodePath::
00387 remove_node() {
00388   nassertv(_error_type != ET_not_found);
00389 
00390   // If we have no parents, remove_node() is just a do-nothing
00391   // operation; if we have no nodes, maybe we were already removed.
00392   // In either case, quietly do nothing except to ensure the
00393   // NodePath is clear.
00394   if (!is_empty() && !is_singleton()) {
00395     uncollapse_head();
00396     PandaNode::detach(_head);
00397   }
00398 
00399   (*this) = NodePath::removed();
00400 }
00401 
00402 ////////////////////////////////////////////////////////////////////
00403 //     Function: NodePath::detach_node
00404 //       Access: Published
00405 //  Description: Disconnects the referenced node from its parent, but
00406 //               does not immediately delete it.  The NodePath retains
00407 //               a pointer to the node.  If there are no other
00408 //               instances to the node, this becomes a singleton
00409 //               NodePath; otherwise, this NodePath becomes the same
00410 //               as another arbitrary instance.
00411 //
00412 //               If the NodePath later goes out of scope or is
00413 //               reassigned to something else, this will have the same
00414 //               effect as remove_node().
00415 ////////////////////////////////////////////////////////////////////
00416 void NodePath::
00417 detach_node() {
00418   nassertv(_error_type != ET_not_found);
00419   if (!is_empty() && !is_singleton()) {
00420     uncollapse_head();
00421     PandaNode::detach(_head);
00422   }
00423 }
00424 
00425 ////////////////////////////////////////////////////////////////////
00426 //     Function: NodePath::output
00427 //       Access: Published
00428 //  Description: Writes a sensible description of the NodePath to the
00429 //               indicated output stream.
00430 ////////////////////////////////////////////////////////////////////
00431 void NodePath::
00432 output(ostream &out) const {
00433   uncollapse_head();
00434 
00435   switch (_error_type) {
00436   case ET_not_found:
00437     out << "**not found**";
00438     return;
00439   case ET_removed:
00440     out << "**removed**";
00441     return;
00442   case ET_fail:
00443     out << "**error**";
00444     return;
00445   default:
00446     break;
00447   }
00448 
00449   if (_head == (NodePathComponent *)NULL) {
00450     out << "(empty)";
00451   } else {
00452     _head->output(out);
00453   }
00454 }
00455 
00456 ////////////////////////////////////////////////////////////////////
00457 //     Function: NodePath::get_state
00458 //       Access: Published
00459 //  Description: Returns the state changes that must be made to
00460 //               transition from the render state of this node to the
00461 //               render state of the other node.
00462 ////////////////////////////////////////////////////////////////////
00463 CPT(RenderState) NodePath::
00464 get_state(const NodePath &other) const {
00465   if (is_empty()) {
00466     return other.get_net_state();
00467   }
00468   if (other.is_empty()) {
00469     return get_net_state()->invert_compose(RenderState::make_empty());
00470   }
00471     
00472   nassertr(verify_complete(), RenderState::make_empty());
00473   nassertr(other.verify_complete(), RenderState::make_empty());
00474 
00475   int a_count, b_count;
00476   find_common_ancestor(*this, other, a_count, b_count);
00477 
00478   CPT(RenderState) a_state = r_get_partial_state(_head, a_count);
00479   CPT(RenderState) b_state = r_get_partial_state(other._head, b_count);
00480   return a_state->invert_compose(b_state);
00481 }
00482 
00483 ////////////////////////////////////////////////////////////////////
00484 //     Function: NodePath::set_state
00485 //       Access: Published
00486 //  Description: Sets the state object on this node, relative to
00487 //               the other node.  This computes a new state object
00488 //               that has the indicated value when seen relative to
00489 //               the other node.
00490 ////////////////////////////////////////////////////////////////////
00491 void NodePath::
00492 set_state(const NodePath &other, const RenderState *state) const {
00493   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
00494   nassertv_always(!is_empty());
00495 
00496   // First, we perform a wrt to the parent, to get the conversion.
00497   NodePath parent = get_parent();
00498   CPT(RenderState) rel_state = parent.get_state(other);
00499 
00500   CPT(RenderState) new_state = rel_state->compose(state);
00501   set_state(new_state);
00502 }
00503 
00504 ////////////////////////////////////////////////////////////////////
00505 //     Function: NodePath::get_transform
00506 //       Access: Published
00507 //  Description: Returns the relative transform to this node from the
00508 //               other node; i.e. the transformation of this node
00509 //               as seen from the other node.
00510 ////////////////////////////////////////////////////////////////////
00511 CPT(TransformState) NodePath::
00512 get_transform(const NodePath &other) const {
00513   if (other.is_empty()) {
00514     return get_net_transform();
00515   }
00516   if (is_empty()) {
00517     return other.get_net_transform()->invert_compose(TransformState::make_identity());
00518   }
00519     
00520   nassertr(verify_complete(), TransformState::make_identity());
00521   nassertr(other.verify_complete(), TransformState::make_identity());
00522 
00523   int a_count, b_count;
00524   find_common_ancestor(*this, other, a_count, b_count);
00525 
00526   CPT(TransformState) a_transform = r_get_partial_transform(_head, a_count);
00527   CPT(TransformState) b_transform = r_get_partial_transform(other._head, b_count);
00528   return b_transform->invert_compose(a_transform);
00529 }
00530 
00531 ////////////////////////////////////////////////////////////////////
00532 //     Function: NodePath::set_transform
00533 //       Access: Published
00534 //  Description: Sets the transform object on this node, relative to
00535 //               the other node.  This computes a new transform object
00536 //               that will have the indicated value when seen from the
00537 //               other node.
00538 ////////////////////////////////////////////////////////////////////
00539 void NodePath::
00540 set_transform(const NodePath &other, const TransformState *transform) const {
00541   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
00542   nassertv_always(!is_empty());
00543 
00544   // First, we perform a wrt to the parent, to get the conversion.
00545   CPT(TransformState) rel_trans;
00546   if (has_parent()) {
00547     rel_trans = other.get_transform(get_parent());
00548   } else {
00549     rel_trans = other.get_transform(NodePath());
00550   }
00551 
00552   CPT(TransformState) new_trans = rel_trans->compose(transform);
00553   set_transform(new_trans);
00554 }
00555 
00556 ////////////////////////////////////////////////////////////////////
00557 //     Function: NodePath::set_pos
00558 //       Access: Published
00559 //  Description: Sets the translation component of the transform,
00560 //               leaving rotation and scale untouched.
00561 ////////////////////////////////////////////////////////////////////
00562 void NodePath::
00563 set_pos(const LVecBase3f &pos) {
00564   nassertv_always(!is_empty());
00565   set_transform(get_transform()->set_pos(pos));
00566 }
00567 
00568 void NodePath::
00569 set_x(float x) {
00570   nassertv_always(!is_empty());
00571   LPoint3f pos = get_pos();
00572   pos[0] = x;
00573   set_pos(pos);
00574 }
00575 
00576 void NodePath::
00577 set_y(float y) {
00578   nassertv_always(!is_empty());
00579   LPoint3f pos = get_pos();
00580   pos[1] = y;
00581   set_pos(pos);
00582 }
00583 
00584 void NodePath::
00585 set_z(float z) {
00586   nassertv_always(!is_empty());
00587   LPoint3f pos = get_pos();
00588   pos[2] = z;
00589   set_pos(pos);
00590 }
00591 
00592 ////////////////////////////////////////////////////////////////////
00593 //     Function: NodePath::get_pos
00594 //       Access: Published
00595 //  Description: Retrieves the translation component of the transform.
00596 ////////////////////////////////////////////////////////////////////
00597 LPoint3f NodePath::
00598 get_pos() const {
00599   nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
00600   return get_transform()->get_pos();
00601 }
00602 
00603 ////////////////////////////////////////////////////////////////////
00604 //     Function: NodePath::set_hpr
00605 //       Access: Published
00606 //  Description: Sets the rotation component of the transform,
00607 //               leaving translation and scale untouched.
00608 ////////////////////////////////////////////////////////////////////
00609 void NodePath::
00610 set_hpr(const LVecBase3f &hpr) {
00611   nassertv_always(!is_empty());
00612   CPT(TransformState) transform = get_transform();
00613   nassertv(transform->has_hpr());
00614   set_transform(transform->set_hpr(hpr));
00615 }
00616 
00617 void NodePath::
00618 set_h(float h) {
00619   nassertv_always(!is_empty());
00620   CPT(TransformState) transform = get_transform();
00621   nassertv(transform->has_hpr());
00622   LVecBase3f hpr = transform->get_hpr();
00623   hpr[0] = h;
00624   set_transform(transform->set_hpr(hpr));
00625 }
00626 
00627 void NodePath::
00628 set_p(float p) {
00629   nassertv_always(!is_empty());
00630   CPT(TransformState) transform = get_transform();
00631   nassertv(transform->has_hpr());
00632   LVecBase3f hpr = transform->get_hpr();
00633   hpr[1] = p;
00634   set_transform(transform->set_hpr(hpr));
00635 }
00636 
00637 void NodePath::
00638 set_r(float r) {
00639   nassertv_always(!is_empty());
00640   CPT(TransformState) transform = get_transform();
00641   nassertv(transform->has_hpr());
00642   LVecBase3f hpr = transform->get_hpr();
00643   hpr[2] = r;
00644   set_transform(transform->set_hpr(hpr));
00645 }
00646 
00647 ////////////////////////////////////////////////////////////////////
00648 //     Function: NodePath::get_hpr
00649 //       Access: Published
00650 //  Description: Retrieves the rotation component of the transform.
00651 ////////////////////////////////////////////////////////////////////
00652 LVecBase3f NodePath::
00653 get_hpr() const {
00654   nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
00655   CPT(TransformState) transform = get_transform();
00656   nassertr(transform->has_hpr(), LVecBase3f(0.0f, 0.0f, 0.0f));
00657   return transform->get_hpr();
00658 }
00659 
00660 ////////////////////////////////////////////////////////////////////
00661 //     Function: NodePath::get_hpr
00662 //       Access: Published
00663 //  Description: Retrieves the rotation component of the transform.
00664 ////////////////////////////////////////////////////////////////////
00665 LVecBase3f NodePath::
00666 get_hpr(float roll) const {
00667   // This function is deprecated.  It used to be a hack to work around
00668   // a problem with decomposing Euler angles, but since we no longer
00669   // depend on decomposing these, we shouldn't need this any more.
00670   return get_hpr();
00671 }
00672 
00673 ////////////////////////////////////////////////////////////////////
00674 //     Function: NodePath::set_quat
00675 //       Access: Published
00676 //  Description: Sets the rotation component of the transform,
00677 //               leaving translation and scale untouched.
00678 ////////////////////////////////////////////////////////////////////
00679 void NodePath::
00680 set_quat(const LQuaternionf &quat) {
00681   nassertv_always(!is_empty());
00682   CPT(TransformState) transform = get_transform();
00683   set_transform(transform->set_quat(quat));
00684 }
00685 
00686 ////////////////////////////////////////////////////////////////////
00687 //     Function: NodePath::get_quat
00688 //       Access: Published
00689 //  Description: Retrieves the rotation component of the transform.
00690 ////////////////////////////////////////////////////////////////////
00691 LQuaternionf NodePath::
00692 get_quat() const {
00693   nassertr_always(!is_empty(), LQuaternionf::ident_quat());
00694   CPT(TransformState) transform = get_transform();
00695   return transform->get_quat();
00696 }
00697 
00698 ////////////////////////////////////////////////////////////////////
00699 //     Function: NodePath::set_scale
00700 //       Access: Published
00701 //  Description: Sets the scale component of the transform,
00702 //               leaving translation and rotation untouched.
00703 ////////////////////////////////////////////////////////////////////
00704 void NodePath::
00705 set_scale(const LVecBase3f &scale) {
00706   nassertv_always(!is_empty());
00707   CPT(TransformState) transform = get_transform();
00708   set_transform(transform->set_scale(scale));
00709 }
00710 
00711 void NodePath::
00712 set_sx(float sx) {
00713   nassertv_always(!is_empty());
00714   CPT(TransformState) transform = get_transform();
00715   LVecBase3f scale = transform->get_scale();
00716   scale[0] = sx;
00717   set_transform(transform->set_scale(scale));
00718 }
00719 
00720 void NodePath::
00721 set_sy(float sy) {
00722   nassertv_always(!is_empty());
00723   CPT(TransformState) transform = get_transform();
00724   LVecBase3f scale = transform->get_scale();
00725   scale[1] = sy;
00726   set_transform(transform->set_scale(scale));
00727 }
00728 
00729 void NodePath::
00730 set_sz(float sz) {
00731   nassertv_always(!is_empty());
00732   CPT(TransformState) transform = get_transform();
00733   LVecBase3f scale = transform->get_scale();
00734   scale[2] = sz;
00735   set_transform(transform->set_scale(scale));
00736 }
00737 
00738 ////////////////////////////////////////////////////////////////////
00739 //     Function: NodePath::get_scale
00740 //       Access: Published
00741 //  Description: Retrieves the scale component of the transform.
00742 ////////////////////////////////////////////////////////////////////
00743 LVecBase3f NodePath::
00744 get_scale() const {
00745   nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
00746   CPT(TransformState) transform = get_transform();
00747   return transform->get_scale();
00748 }
00749 
00750 ////////////////////////////////////////////////////////////////////
00751 //     Function: NodePath::set_pos_hpr
00752 //       Access: Published
00753 //  Description: Sets the translation and rotation component of the
00754 //               transform, leaving scale untouched.
00755 ////////////////////////////////////////////////////////////////////
00756 void NodePath::
00757 set_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) {
00758   nassertv_always(!is_empty());
00759   CPT(TransformState) transform = get_transform();
00760   transform = TransformState::make_pos_hpr_scale
00761     (pos, hpr, transform->get_scale());
00762   set_transform(transform);
00763 }
00764 
00765 ////////////////////////////////////////////////////////////////////
00766 //     Function: NodePath::set_hpr_scale
00767 //       Access: Published
00768 //  Description: Sets the rotation and scale components of the
00769 //               transform, leaving translation untouched.
00770 ////////////////////////////////////////////////////////////////////
00771 void NodePath::
00772 set_hpr_scale(const LVecBase3f &hpr, const LVecBase3f &scale) {
00773   nassertv_always(!is_empty());
00774   CPT(TransformState) transform = get_transform();
00775   transform = TransformState::make_pos_hpr_scale
00776     (transform->get_pos(), hpr, scale);
00777   set_transform(transform);
00778 }
00779 
00780 ////////////////////////////////////////////////////////////////////
00781 //     Function: NodePath::set_pos_hpr_scale
00782 //       Access: Published
00783 //  Description: Completely replaces the transform with new
00784 //               translation, rotation, and scale components.
00785 ////////////////////////////////////////////////////////////////////
00786 void NodePath::
00787 set_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
00788                   const LVecBase3f &scale) {
00789   nassertv_always(!is_empty());
00790   set_transform(TransformState::make_pos_hpr_scale
00791                 (pos, hpr, scale));
00792 }
00793 
00794 ////////////////////////////////////////////////////////////////////
00795 //     Function: NodePath::set_pos_quat_scale
00796 //       Access: Published
00797 //  Description: Completely replaces the transform with new
00798 //               translation, rotation, and scale components.
00799 ////////////////////////////////////////////////////////////////////
00800 void NodePath::
00801 set_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat,
00802                    const LVecBase3f &scale) {
00803   nassertv_always(!is_empty());
00804   set_transform(TransformState::make_pos_quat_scale
00805                 (pos, quat, scale));
00806 }
00807 
00808 ////////////////////////////////////////////////////////////////////
00809 //     Function: NodePath::set_mat
00810 //       Access: Published
00811 //  Description: Directly sets an arbitrary 4x4 transform matrix.
00812 ////////////////////////////////////////////////////////////////////
00813 void NodePath::
00814 set_mat(const LMatrix4f &mat) {
00815   nassertv_always(!is_empty());
00816   set_transform(TransformState::make_mat(mat));
00817 }
00818 
00819 ////////////////////////////////////////////////////////////////////
00820 //     Function: NodePath::has_color_scale
00821 //       Access: Published
00822 //  Description: Returns true if a color scale has been applied
00823 //               to the referenced node, false otherwise.  It is still
00824 //               possible that color at this node might have been
00825 //               scaled by an ancestor node.
00826 ////////////////////////////////////////////////////////////////////
00827 bool NodePath::
00828 has_color_scale() const {
00829   nassertr_always(!is_empty(), false);
00830   return node()->has_attrib(ColorScaleAttrib::get_class_type());
00831 }
00832 
00833 ////////////////////////////////////////////////////////////////////
00834 //     Function: NodePath::clear_color_scale
00835 //       Access: Published
00836 //  Description: Completely removes any color scale from the
00837 //               referenced node.  This is preferable to simply
00838 //               setting the color scale to identity, as it also
00839 //               removes the overhead associated with having a color
00840 //               scale at all.
00841 ////////////////////////////////////////////////////////////////////
00842 void NodePath::
00843 clear_color_scale() {
00844   nassertv_always(!is_empty());
00845   node()->clear_attrib(ColorScaleAttrib::get_class_type());
00846 }
00847 
00848 ////////////////////////////////////////////////////////////////////
00849 //     Function: NodePath::set_color_scale
00850 //       Access: Published
00851 //  Description: Sets the color scale component of the transform,
00852 //               leaving translation and rotation untouched.
00853 ////////////////////////////////////////////////////////////////////
00854 void NodePath::
00855 set_color_scale(const LVecBase4f &scale) {
00856   nassertv_always(!is_empty());
00857   node()->set_attrib(ColorScaleAttrib::make(scale));
00858 }
00859 
00860 ////////////////////////////////////////////////////////////////////
00861 //     Function: NodePath::get_color_scale
00862 //       Access: Published
00863 //  Description: Returns the complete color scale vector that has been
00864 //               applied to the bottom node, or all 1's (identity) if
00865 //               no scale has been applied.
00866 ////////////////////////////////////////////////////////////////////
00867 const LVecBase4f &NodePath::
00868 get_color_scale() const {
00869   static const LVecBase4f ident_scale(1.0f, 1.0f, 1.0f, 1.0f);
00870   nassertr_always(!is_empty(), ident_scale);
00871   const RenderAttrib *attrib =
00872     node()->get_attrib(ColorScaleAttrib::get_class_type());
00873   if (attrib != (const RenderAttrib *)NULL) {
00874     const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
00875     return csa->get_scale();
00876   }
00877 
00878   return ident_scale;
00879 }
00880 
00881 ////////////////////////////////////////////////////////////////////
00882 //     Function: NodePath::look_at
00883 //       Access: Published
00884 //  Description: Sets the hpr on this NodePath so that it
00885 //               rotates to face the indicated point in space.
00886 ////////////////////////////////////////////////////////////////////
00887 void NodePath::
00888 look_at(const LPoint3f &point, const LVector3f &up) {
00889   nassertv_always(!is_empty());
00890 
00891   LPoint3f pos = get_pos();
00892 
00893   LQuaternionf quat;
00894   ::look_at(quat, point - pos, up);
00895   set_quat(quat);
00896 }
00897 
00898 ////////////////////////////////////////////////////////////////////
00899 //     Function: NodePath::heads_up
00900 //       Access: Published
00901 //  Description: Behaves like look_at(), but with a strong preference
00902 //               to keeping the up vector oriented in the indicated
00903 //               "up" direction.
00904 ////////////////////////////////////////////////////////////////////
00905 void NodePath::
00906 heads_up(const LPoint3f &point, const LVector3f &up) {
00907   nassertv_always(!is_empty());
00908 
00909   LPoint3f pos = get_pos();
00910 
00911   LQuaternionf quat;
00912   ::heads_up(quat, point - pos, up);
00913   set_quat(quat);
00914 }
00915 
00916 ////////////////////////////////////////////////////////////////////
00917 //     Function: NodePath::set_pos
00918 //       Access: Published
00919 //  Description: Sets the translation component of the transform,
00920 //               relative to the other node.
00921 ////////////////////////////////////////////////////////////////////
00922 void NodePath::
00923 set_pos(const NodePath &other, const LVecBase3f &pos) {
00924   nassertv_always(!is_empty());
00925   CPT(TransformState) rel_transform = get_transform(other);
00926 
00927   CPT(TransformState) orig_transform = get_transform();
00928   if (orig_transform->has_components()) {
00929     // If we had a componentwise transform before we started, we
00930     // should be careful to preserve the other two components.  We
00931     // wouldn't need to do this, except for the possibility of
00932     // numerical error or decompose ambiguity.
00933     const LVecBase3f &orig_hpr = orig_transform->get_hpr();
00934     const LVecBase3f &orig_scale = orig_transform->get_scale();
00935 
00936     set_transform(other, rel_transform->set_pos(pos));
00937     set_pos_hpr_scale(get_transform()->get_pos(), orig_hpr, orig_scale);
00938 
00939   } else {
00940     // If we didn't have a componentwise transform already, never
00941     // mind.
00942     set_transform(other, rel_transform->set_pos(pos));
00943   }
00944 }
00945 
00946 void NodePath::
00947 set_x(const NodePath &other, float x) {
00948   nassertv_always(!is_empty());
00949   LPoint3f pos = get_pos(other);
00950   pos[0] = x;
00951   set_pos(other, pos);
00952 }
00953 
00954 void NodePath::
00955 set_y(const NodePath &other, float y) {
00956   nassertv_always(!is_empty());
00957   LPoint3f pos = get_pos(other);
00958   pos[1] = y;
00959   set_pos(other, pos);
00960 }
00961 
00962 void NodePath::
00963 set_z(const NodePath &other, float z) {
00964   nassertv_always(!is_empty());
00965   LPoint3f pos = get_pos(other);
00966   pos[2] = z;
00967   set_pos(other, pos);
00968 }
00969 
00970 ////////////////////////////////////////////////////////////////////
00971 //     Function: NodePath::get_pos
00972 //       Access: Published
00973 //  Description: Returns the relative position of the referenced node
00974 //               as seen from the other node.
00975 ////////////////////////////////////////////////////////////////////
00976 LPoint3f NodePath::
00977 get_pos(const NodePath &other) const {
00978   nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
00979   return get_transform(other)->get_pos();
00980 }
00981 
00982 ////////////////////////////////////////////////////////////////////
00983 //     Function: NodePath::set_hpr
00984 //       Access: Published
00985 //  Description: Sets the rotation component of the transform,
00986 //               relative to the other node.
00987 ////////////////////////////////////////////////////////////////////
00988 void NodePath::
00989 set_hpr(const NodePath &other, const LVecBase3f &hpr) {
00990   nassertv_always(!is_empty());
00991   CPT(TransformState) rel_transform = get_transform(other);
00992   nassertv(rel_transform->has_hpr());
00993 
00994   CPT(TransformState) orig_transform = get_transform();
00995   if (orig_transform->has_components()) {
00996     // If we had a componentwise transform before we started, we
00997     // should be careful to preserve the other two components.  We
00998     // wouldn't need to do this, except for the possibility of
00999     // numerical error or decompose ambiguity.
01000     const LVecBase3f &orig_pos = orig_transform->get_pos();
01001     const LVecBase3f &orig_scale = orig_transform->get_scale();
01002 
01003     set_transform(other, rel_transform->set_hpr(hpr));
01004     const TransformState *new_transform = get_transform();
01005     if (new_transform->has_components()) {
01006       set_pos_hpr_scale(orig_pos, new_transform->get_hpr(), orig_scale);
01007     }
01008 
01009   } else {
01010     // If we didn't have a componentwise transform already, never
01011     // mind.
01012     set_transform(other, rel_transform->set_hpr(hpr));
01013   }
01014 }
01015 
01016 void NodePath::
01017 set_h(const NodePath &other, float h) {
01018   nassertv_always(!is_empty());
01019   LVecBase3f hpr = get_hpr(other);
01020   hpr[0] = h;
01021   set_hpr(other, hpr);
01022 }
01023 
01024 void NodePath::
01025 set_p(const NodePath &other, float p) {
01026   nassertv_always(!is_empty());
01027   LVecBase3f hpr = get_hpr(other);
01028   hpr[1] = p;
01029   set_hpr(other, hpr);
01030 }
01031 
01032 void NodePath::
01033 set_r(const NodePath &other, float r) {
01034   nassertv_always(!is_empty());
01035   LVecBase3f hpr = get_hpr(other);
01036   hpr[2] = r;
01037   set_hpr(other, hpr);
01038 }
01039 
01040 ////////////////////////////////////////////////////////////////////
01041 //     Function: NodePath::get_hpr
01042 //       Access: Published
01043 //  Description: Returns the relative orientation of the bottom node
01044 //               as seen from the other node.
01045 ////////////////////////////////////////////////////////////////////
01046 LVecBase3f NodePath::
01047 get_hpr(const NodePath &other) const {
01048   nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
01049   CPT(TransformState) transform = get_transform(other);
01050   nassertr(transform->has_hpr(), LVecBase3f(0.0f, 0.0f, 0.0f));
01051   return transform->get_hpr();
01052 }
01053 
01054 ////////////////////////////////////////////////////////////////////
01055 //     Function: NodePath::get_hpr
01056 //       Access: Published
01057 //  Description: Returns the relative orientation of the bottom node
01058 //               as seen from the other node.
01059 ////////////////////////////////////////////////////////////////////
01060 LVecBase3f NodePath::
01061 get_hpr(const NodePath &other, float roll) const {
01062   // This is still doing it the dumb way, with a decomposition.  This
01063   // function is deprecated anyway.
01064   LMatrix4f mat = get_mat(other);
01065   LVector3f scale, hpr, pos;
01066   decompose_matrix(mat, scale, hpr, pos, roll);
01067   return hpr;
01068 }
01069 
01070 ////////////////////////////////////////////////////////////////////
01071 //     Function: NodePath::set_quat
01072 //       Access: Published
01073 //  Description: Sets the rotation component of the transform,
01074 //               relative to the other node.
01075 ////////////////////////////////////////////////////////////////////
01076 void NodePath::
01077 set_quat(const NodePath &other, const LQuaternionf &quat) {
01078   nassertv_always(!is_empty());
01079   CPT(TransformState) rel_transform = get_transform(other);
01080 
01081   CPT(TransformState) orig_transform = get_transform();
01082   if (orig_transform->has_components()) {
01083     // If we had a componentwise transform before we started, we
01084     // should be careful to preserve the other two components.  We
01085     // wouldn't need to do this, except for the possibility of
01086     // numerical error or decompose ambiguity.
01087     const LVecBase3f &orig_pos = orig_transform->get_pos();
01088     const LVecBase3f &orig_scale = orig_transform->get_scale();
01089 
01090     set_transform(other, rel_transform->set_quat(quat));
01091     const TransformState *new_transform = get_transform();
01092     if (new_transform->has_components()) {
01093       set_pos_quat_scale(orig_pos, new_transform->get_quat(), orig_scale);
01094     }
01095 
01096   } else {
01097     // If we didn't have a componentwise transform already, never
01098     // mind.
01099     set_transform(other, rel_transform->set_quat(quat));
01100   }
01101 }
01102 
01103 ////////////////////////////////////////////////////////////////////
01104 //     Function: NodePath::get_quat
01105 //       Access: Published
01106 //  Description: Returns the relative orientation of the bottom node
01107 //               as seen from the other node.
01108 ////////////////////////////////////////////////////////////////////
01109 LQuaternionf NodePath::
01110 get_quat(const NodePath &other) const {
01111   nassertr_always(!is_empty(), LQuaternionf::ident_quat());
01112   CPT(TransformState) transform = get_transform(other);
01113   return transform->get_quat();
01114 }
01115 
01116 ////////////////////////////////////////////////////////////////////
01117 //     Function: NodePath::set_scale
01118 //       Access: Published
01119 //  Description: Sets the scale component of the transform,
01120 //               relative to the other node.
01121 ////////////////////////////////////////////////////////////////////
01122 void NodePath::
01123 set_scale(const NodePath &other, const LVecBase3f &scale) {
01124   nassertv_always(!is_empty());
01125   CPT(TransformState) rel_transform = get_transform(other);
01126 
01127   CPT(TransformState) orig_transform = get_transform();
01128   if (orig_transform->has_components()) {
01129     // If we had a componentwise transform before we started, we
01130     // should be careful to preserve the other two components.  We
01131     // wouldn't need to do this, except for the possibility of
01132     // numerical error or decompose ambiguity.
01133     const LVecBase3f &orig_pos = orig_transform->get_pos();
01134     const LVecBase3f &orig_hpr = orig_transform->get_hpr();
01135 
01136     set_transform(other, rel_transform->set_scale(scale));
01137     const TransformState *new_transform = get_transform();
01138     if (new_transform->has_components()) {
01139       set_pos_hpr_scale(orig_pos, orig_hpr, new_transform->get_scale());
01140     }
01141 
01142   } else {
01143     // If we didn't have a componentwise transform already, never
01144     // mind.
01145     set_transform(other, rel_transform->set_scale(scale));
01146   }
01147 }
01148 
01149 void NodePath::
01150 set_sx(const NodePath &other, float sx) {
01151   nassertv_always(!is_empty());
01152   LVecBase3f scale = get_scale(other);
01153   scale[0] = sx;
01154   set_scale(other, scale);
01155 }
01156 
01157 void NodePath::
01158 set_sy(const NodePath &other, float sy) {
01159   nassertv_always(!is_empty());
01160   LVecBase3f scale = get_scale(other);
01161   scale[1] = sy;
01162   set_scale(other, scale);
01163 }
01164 
01165 void NodePath::
01166 set_sz(const NodePath &other, float sz) {
01167   nassertv_always(!is_empty());
01168   LVecBase3f scale = get_scale(other);
01169   scale[2] = sz;
01170   set_scale(other, scale);
01171 }
01172 
01173 ////////////////////////////////////////////////////////////////////
01174 //     Function: NodePath::get_scale
01175 //       Access: Published
01176 //  Description: Returns the relative scale of the bottom node
01177 //               as seen from the other node.
01178 ////////////////////////////////////////////////////////////////////
01179 LVecBase3f NodePath::
01180 get_scale(const NodePath &other) const {
01181   nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
01182   CPT(TransformState) transform = get_transform(other);
01183   return transform->get_scale();
01184 }
01185 
01186 ////////////////////////////////////////////////////////////////////
01187 //     Function: NodePath::set_pos_hpr
01188 //       Access: Published
01189 //  Description: Sets the translation and rotation component of the
01190 //               transform, relative to the other node.
01191 ////////////////////////////////////////////////////////////////////
01192 void NodePath::
01193 set_pos_hpr(const NodePath &other, const LVecBase3f &pos,
01194             const LVecBase3f &hpr) {
01195   nassertv_always(!is_empty());
01196   CPT(TransformState) rel_transform = get_transform(other);
01197 
01198   CPT(TransformState) orig_transform = get_transform();
01199   if (orig_transform->has_components()) {
01200     // If we had a componentwise transform before we started, we
01201     // should be careful to preserve the other two components.  We
01202     // wouldn't need to do this, except for the possibility of
01203     // numerical error or decompose ambiguity.
01204     const LVecBase3f &orig_scale = orig_transform->get_scale();
01205 
01206     set_transform(other, TransformState::make_pos_hpr_scale
01207                   (pos, hpr, rel_transform->get_scale()));
01208     const TransformState *new_transform = get_transform();
01209     if (new_transform->has_components()) {
01210       set_pos_hpr_scale(new_transform->get_pos(), new_transform->get_hpr(),
01211                         orig_scale);
01212     }
01213 
01214   } else {
01215     // If we didn't have a componentwise transform already, never
01216     // mind.
01217     set_transform(other, TransformState::make_pos_hpr_scale
01218                   (pos, hpr, rel_transform->get_scale()));
01219   }
01220 }
01221 
01222 ////////////////////////////////////////////////////////////////////
01223 //     Function: NodePath::set_hpr_scale
01224 //       Access: Published
01225 //  Description: Sets the rotation and scale components of the
01226 //               transform, leaving translation untouched.  This, or
01227 //               set_pos_hpr_scale, is the preferred way to update a
01228 //               transform when both hpr and scale are to be changed.
01229 ////////////////////////////////////////////////////////////////////
01230 void NodePath::
01231 set_hpr_scale(const NodePath &other, const LVecBase3f &hpr, const LVecBase3f &scale) {
01232   // We don't bother trying very hard to preserve pos across this
01233   // operation, unlike the work we do above to preserve hpr or scale,
01234   // since it generally doesn't matter that much if pos is off by a
01235   // few thousandths.
01236   nassertv_always(!is_empty());
01237   CPT(TransformState) transform = get_transform(other);
01238   transform = TransformState::make_pos_hpr_scale
01239     (transform->get_pos(), hpr, scale);
01240   set_transform(other, transform);
01241 }
01242 
01243 ////////////////////////////////////////////////////////////////////
01244 //     Function: NodePath::set_pos_hpr_scale
01245 //       Access: Published
01246 //  Description: Completely replaces the transform with new
01247 //               translation, rotation, and scale components, relative
01248 //               to the other node.
01249 ////////////////////////////////////////////////////////////////////
01250 void NodePath::
01251 set_pos_hpr_scale(const NodePath &other,
01252                   const LVecBase3f &pos, const LVecBase3f &hpr,
01253                   const LVecBase3f &scale) {
01254   nassertv_always(!is_empty());
01255   set_transform(other, TransformState::make_pos_hpr_scale
01256                 (pos, hpr, scale));
01257 }
01258 
01259 ////////////////////////////////////////////////////////////////////
01260 //     Function: NodePath::set_pos_quat_scale
01261 //       Access: Published
01262 //  Description: Completely replaces the transform with new
01263 //               translation, rotation, and scale components, relative
01264 //               to the other node.
01265 ////////////////////////////////////////////////////////////////////
01266 void NodePath::
01267 set_pos_quat_scale(const NodePath &other,
01268                    const LVecBase3f &pos, const LQuaternionf &quat,
01269                    const LVecBase3f &scale) {
01270   nassertv_always(!is_empty());
01271   set_transform(other, TransformState::make_pos_quat_scale
01272                 (pos, quat, scale));
01273 }
01274 
01275 ////////////////////////////////////////////////////////////////////
01276 //     Function: NodePath::get_mat
01277 //       Access: Published
01278 //  Description: Returns the matrix that describes the coordinate
01279 //               space of the bottom node, relative to the other
01280 //               path's bottom node's coordinate space.
01281 ////////////////////////////////////////////////////////////////////
01282 const LMatrix4f &NodePath::
01283 get_mat(const NodePath &other) const {
01284   CPT(TransformState) transform = get_transform(other);
01285   // We can safely assume the transform won't go away when the
01286   // function returns, since its reference count is also held in the
01287   // cache.  This assumption allows us to return a reference to the
01288   // matrix, instead of having to return a matrix on the stack.
01289   nassertr(transform->get_ref_count() > 1, LMatrix4f::ident_mat());
01290   return transform->get_mat();
01291 }
01292 
01293 ////////////////////////////////////////////////////////////////////
01294 //     Function: NodePath::set_mat
01295 //       Access: Published
01296 //  Description: Converts the indicated matrix from the other's
01297 //               coordinate space to the local coordinate space, and
01298 //               applies it to the node.
01299 ////////////////////////////////////////////////////////////////////
01300 void NodePath::
01301 set_mat(const NodePath &other, const LMatrix4f &mat) {
01302   nassertv_always(!is_empty());
01303   set_transform(other, TransformState::make_mat(mat));
01304 }
01305 
01306 ////////////////////////////////////////////////////////////////////
01307 //     Function: NodePath::get_relative_point
01308 //       Access: Published
01309 //  Description: Given that the indicated point is in the coordinate
01310 //               system of the other node, returns the same point in
01311 //               this node's coordinate system.
01312 ////////////////////////////////////////////////////////////////////
01313 LPoint3f NodePath::
01314 get_relative_point(const NodePath &other, const LVecBase3f &point) {
01315   LPoint3f rel_point = LPoint3f(point) * other.get_mat(*this);
01316   return rel_point;
01317 }
01318 
01319 ////////////////////////////////////////////////////////////////////
01320 //     Function: NodePath::look_at
01321 //       Access: Published
01322 //  Description: Sets the transform on this NodePath so that it
01323 //               rotates to face the indicated point in space, which
01324 //               is relative to the other NodePath.
01325 ////////////////////////////////////////////////////////////////////
01326 void NodePath::
01327 look_at(const NodePath &other, const LPoint3f &point, const LVector3f &up) {
01328   nassertv_always(!is_empty());
01329 
01330   NodePath parent = get_parent();
01331   LPoint3f rel_point = point * other.get_mat(parent);
01332 
01333   LPoint3f pos = get_pos();
01334 
01335   LQuaternionf quat;
01336   ::look_at(quat, rel_point - pos, up);
01337   set_quat(quat);
01338 }
01339 
01340 ////////////////////////////////////////////////////////////////////
01341 //     Function: NodePath::heads_up
01342 //       Access: Published
01343 //  Description: Behaves like look_at(), but with a strong preference
01344 //               to keeping the up vector oriented in the indicated
01345 //               "up" direction.
01346 ////////////////////////////////////////////////////////////////////
01347 void NodePath::
01348 heads_up(const NodePath &other, const LPoint3f &point, const LVector3f &up) {
01349   nassertv_always(!is_empty());
01350 
01351   NodePath parent = get_parent();
01352   LPoint3f rel_point = point * other.get_mat(parent);
01353 
01354   LPoint3f pos = get_pos();
01355 
01356   LQuaternionf quat;
01357   ::heads_up(quat, rel_point - pos, up);
01358   set_quat(quat);
01359 }
01360 
01361 ////////////////////////////////////////////////////////////////////
01362 //     Function: NodePath::set_color
01363 //       Access: Published
01364 //  Description: Applies a scene-graph color to the referenced node.
01365 //               This color will apply to all geometry at this level
01366 //               and below (that does not specify a new color or a
01367 //               set_color_off()).
01368 ////////////////////////////////////////////////////////////////////
01369 void NodePath::
01370 set_color(float r, float g, float b, float a,
01371           int priority) {
01372   set_color(Colorf(r, g, b, a), priority);
01373 }
01374 
01375 ////////////////////////////////////////////////////////////////////
01376 //     Function: NodePath::set_color
01377 //       Access: Published
01378 //  Description: Applies a scene-graph color to the referenced node.
01379 //               This color will apply to all geometry at this level
01380 //               and below (that does not specify a new color or a
01381 //               set_color_off()).
01382 ////////////////////////////////////////////////////////////////////
01383 void NodePath::
01384 set_color(const Colorf &color, int priority) {
01385   nassertv_always(!is_empty());
01386   node()->set_attrib(ColorAttrib::make_flat(color), priority);
01387 }
01388 
01389 ////////////////////////////////////////////////////////////////////
01390 //     Function: NodePath::set_color_off
01391 //       Access: Published
01392 //  Description: Sets the geometry at this level and below to render
01393 //               using the geometry color.  This is normally the
01394 //               default, but it may be useful to use this to
01395 //               contradict set_color() at a higher node level (or,
01396 //               with a priority, to override a set_color() at a lower
01397 //               level).
01398 ////////////////////////////////////////////////////////////////////
01399 void NodePath::
01400 set_color_off(int priority) {
01401   nassertv_always(!is_empty());
01402   node()->set_attrib(ColorAttrib::make_vertex(), priority);
01403 }
01404 
01405 ////////////////////////////////////////////////////////////////////
01406 //     Function: NodePath::clear_color
01407 //       Access: Published
01408 //  Description: Completely removes any color adjustment from the node.
01409 //               This allows the natural color of the geometry, or
01410 //               whatever color transitions might be otherwise
01411 //               affecting the geometry, to show instead.
01412 ////////////////////////////////////////////////////////////////////
01413 void NodePath::
01414 clear_color() {
01415   nassertv_always(!is_empty());
01416   node()->clear_attrib(ColorAttrib::get_class_type());
01417 }
01418 
01419 ////////////////////////////////////////////////////////////////////
01420 //     Function: NodePath::has_color
01421 //       Access: Published
01422 //  Description: Returns true if a color has been applied to the given
01423 //               node, false otherwise.
01424 ////////////////////////////////////////////////////////////////////
01425 bool NodePath::
01426 has_color() const {
01427   nassertr_always(!is_empty(), false);
01428   return node()->has_attrib(ColorAttrib::get_class_type());
01429 }
01430 
01431 ////////////////////////////////////////////////////////////////////
01432 //     Function: NodePath::get_color
01433 //       Access: Published
01434 //  Description: Returns the color that has been assigned to the node,
01435 //               or black if no color has been assigned.
01436 ////////////////////////////////////////////////////////////////////
01437 Colorf NodePath::
01438 get_color() const {
01439   nassertr_always(!is_empty(), false);
01440   const RenderAttrib *attrib =
01441     node()->get_attrib(ColorAttrib::get_class_type());
01442   if (attrib != (const RenderAttrib *)NULL) {
01443     const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
01444     if (ca->get_color_type() == ColorAttrib::T_flat) {
01445       return ca->get_color();
01446     }
01447   }
01448 
01449   pgraph_cat.warning()
01450     << "get_color() called on " << *this << " which has no color set.\n";
01451 
01452   return Colorf(1.0f, 1.0f, 1.0f, 1.0f);
01453 }
01454 
01455 ////////////////////////////////////////////////////////////////////
01456 //     Function: NodePath::set_bin
01457 //       Access: Published
01458 //  Description: Assigns the geometry at this level and below to the
01459 //               named rendering bin.  It is the user's responsibility
01460 //               to ensure that such a bin already exists, either via
01461 //               the cull-bin Configrc variable, or by explicitly
01462 //               creating a GeomBin of the appropriate type at
01463 //               runtime.
01464 //
01465 //               There are two default bins created when Panda is
01466 //               started: "default" and "fixed".  Normally, all
01467 //               geometry is assigned to "default" unless specified
01468 //               otherwise.  This bin renders opaque geometry in
01469 //               state-sorted order, followed by transparent geometry
01470 //               sorted back-to-front.  If any geometry is assigned to
01471 //               "fixed", this will be rendered following all the
01472 //               geometry in "default", in the order specified by
01473 //               draw_order for each piece of geometry so assigned.
01474 //
01475 //               The draw_order parameter is meaningful only for
01476 //               GeomBinFixed type bins, e.g. "fixed".  Other kinds of
01477 //               bins ignore it.
01478 ////////////////////////////////////////////////////////////////////
01479 void NodePath::
01480 set_bin(const string &bin_name, int draw_order, int priority) {
01481   nassertv_always(!is_empty());
01482   node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority);
01483 }
01484 
01485 ////////////////////////////////////////////////////////////////////
01486 //     Function: NodePath::clear_bin
01487 //       Access: Published
01488 //  Description: Completely removes any bin adjustment that may have
01489 //               been set via set_bin() from this particular node.
01490 ////////////////////////////////////////////////////////////////////
01491 void NodePath::
01492 clear_bin() {
01493   nassertv_always(!is_empty());
01494   node()->clear_attrib(CullBinAttrib::get_class_type());
01495 }
01496 
01497 ////////////////////////////////////////////////////////////////////
01498 //     Function: NodePath::has_bin
01499 //       Access: Published
01500 //  Description: Returns true if the node has been assigned to the a
01501 //               particular rendering bin via set_bin(), false
01502 //               otherwise.
01503 ////////////////////////////////////////////////////////////////////
01504 bool NodePath::
01505 has_bin() const {
01506   nassertr_always(!is_empty(), false);
01507   return node()->has_attrib(CullBinAttrib::get_class_type());
01508 }
01509 
01510 ////////////////////////////////////////////////////////////////////
01511 //     Function: NodePath::get_bin_name
01512 //       Access: Published
01513 //  Description: Returns the name of the bin that this particular node
01514 //               was assigned to via set_bin(), or the empty string if
01515 //               no bin was assigned.  See set_bin() and has_bin().
01516 ////////////////////////////////////////////////////////////////////
01517 string NodePath::
01518 get_bin_name() const {
01519   nassertr_always(!is_empty(), string());
01520   const RenderAttrib *attrib =
01521     node()->get_attrib(CullBinAttrib::get_class_type());
01522   if (attrib != (const RenderAttrib *)NULL) {
01523     const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
01524     return ba->get_bin_name();
01525   }
01526 
01527   return string();
01528 }
01529 
01530 ////////////////////////////////////////////////////////////////////
01531 //     Function: NodePath::get_bin_draw_order
01532 //       Access: Published
01533 //  Description: Returns the drawing order associated with the bin
01534 //               that this particular node was assigned to via
01535 //               set_bin(), or 0 if no bin was assigned.  See
01536 //               set_bin() and has_bin().
01537 ////////////////////////////////////////////////////////////////////
01538 int NodePath::
01539 get_bin_draw_order() const {
01540   nassertr_always(!is_empty(), false);
01541   const RenderAttrib *attrib =
01542     node()->get_attrib(CullBinAttrib::get_class_type());
01543   if (attrib != (const RenderAttrib *)NULL) {
01544     const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
01545     return ba->get_draw_order();
01546   }
01547 
01548   return 0;
01549 }
01550 
01551 ////////////////////////////////////////////////////////////////////
01552 //     Function: NodePath::set_texture
01553 //       Access: Published
01554 //  Description: Sets the geometry at this level and below to render
01555 //               using the indicated texture.
01556 ////////////////////////////////////////////////////////////////////
01557 void NodePath::
01558 set_texture(Texture *tex, int priority) {
01559   nassertv_always(!is_empty());
01560   node()->set_attrib(TextureAttrib::make(tex), priority);
01561 }
01562 
01563 ////////////////////////////////////////////////////////////////////
01564 //     Function: NodePath::set_texture_off
01565 //       Access: Published
01566 //  Description: Sets the geometry at this level and below to render
01567 //               using no texture.  This is normally the default, but
01568 //               it may be useful to use this to contradict
01569 //               set_texture() at a higher node level (or, with a
01570 //               priority, to override a set_texture() at a lower
01571 //               level).
01572 ////////////////////////////////////////////////////////////////////
01573 void NodePath::
01574 set_texture_off(int priority) {
01575   nassertv_always(!is_empty());
01576   node()->set_attrib(TextureAttrib::make_off(), priority);
01577 }
01578 
01579 ////////////////////////////////////////////////////////////////////
01580 //     Function: NodePath::clear_texture
01581 //       Access: Published
01582 //  Description: Completely removes any texture adjustment that may
01583 //               have been set via set_texture() or set_texture_off()
01584 //               from this particular node.  This allows whatever
01585 //               textures might be otherwise affecting the geometry to
01586 //               show instead.
01587 ////////////////////////////////////////////////////////////////////
01588 void NodePath::
01589 clear_texture() {
01590   nassertv_always(!is_empty());
01591   node()->clear_attrib(TextureAttrib::get_class_type());
01592 }
01593 
01594 ////////////////////////////////////////////////////////////////////
01595 //     Function: NodePath::has_texture
01596 //       Access: Published
01597 //  Description: Returns true if a texture has been applied to this
01598 //               particular node via set_texture(), false otherwise.
01599 //               This is not the same thing as asking whether the
01600 //               geometry at this node will be rendered with
01601 //               texturing, as there may be a texture in effect from a
01602 //               higher or lower level.
01603 ////////////////////////////////////////////////////////////////////
01604 bool NodePath::
01605 has_texture() const {
01606   nassertr_always(!is_empty(), false);
01607   const RenderAttrib *attrib =
01608     node()->get_attrib(TextureAttrib::get_class_type());
01609   if (attrib != (const RenderAttrib *)NULL) {
01610     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
01611     return !ta->is_off();
01612   }
01613 
01614   return false;
01615 }
01616 
01617 ////////////////////////////////////////////////////////////////////
01618 //     Function: NodePath::has_texture_off
01619 //       Access: Published
01620 //  Description: Returns true if a texture has been specifically
01621 //               disabled on this particular node via
01622 //               set_texture_off(), false otherwise.  This is not the
01623 //               same thing as asking whether the geometry at this
01624 //               node will be rendered untextured, as there may be a
01625 //               texture in effect from a higher or lower level.
01626 ////////////////////////////////////////////////////////////////////
01627 bool NodePath::
01628 has_texture_off() const {
01629   nassertr_always(!is_empty(), false);
01630   const RenderAttrib *attrib =
01631     node()->get_attrib(ColorAttrib::get_class_type());
01632   if (attrib != (const RenderAttrib *)NULL) {
01633     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
01634     return ta->is_off();
01635   }
01636 
01637   return false;
01638 }
01639 
01640 ////////////////////////////////////////////////////////////////////
01641 //     Function: NodePath::get_texture
01642 //       Access: Published
01643 //  Description: Returns the texture that has been set on this
01644 //               particular node, or NULL if no texture has been set.
01645 //               This is not necessarily the texture that will be
01646 //               applied to the geometry at or below this level, as
01647 //               another texture at a higher or lower level may
01648 //               override.
01649 //
01650 //               See also find_texture().
01651 ////////////////////////////////////////////////////////////////////
01652 Texture *NodePath::
01653 get_texture() const {
01654   nassertr_always(!is_empty(), NULL);
01655   const RenderAttrib *attrib =
01656     node()->get_attrib(TextureAttrib::get_class_type());
01657   if (attrib != (const RenderAttrib *)NULL) {
01658     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
01659     return ta->get_texture();
01660   }
01661 
01662   return NULL;
01663 }
01664 
01665 ////////////////////////////////////////////////////////////////////
01666 //     Function: NodePath::find_texture
01667 //       Access: Published
01668 //  Description: Returns the first texture found applied to geometry
01669 //               at this node or below that matches the indicated name
01670 //               (which may contain wildcards).  Returns the texture
01671 //               if it is found, or NULL if it is not.
01672 ////////////////////////////////////////////////////////////////////
01673 Texture *NodePath::
01674 find_texture(const string &name) const {
01675   GlobPattern glob(name);
01676   return r_find_texture(node(), get_net_state(), glob);
01677 }
01678 
01679 ////////////////////////////////////////////////////////////////////
01680 //     Function: NodePath::find_all_textures
01681 //       Access: Published
01682 //  Description: Returns a list of a textures applied to geometry at
01683 //               this node and below.
01684 ////////////////////////////////////////////////////////////////////
01685 TextureCollection NodePath::
01686 find_all_textures() const {
01687   Textures textures;
01688   r_find_all_textures(node(), get_net_state(), textures);
01689 
01690   TextureCollection tc;
01691   Textures::iterator ti;
01692   for (ti = textures.begin(); ti != textures.end(); ++ti) {
01693     tc.add_texture(*ti);
01694   }
01695   return tc;
01696 }
01697 
01698 ////////////////////////////////////////////////////////////////////
01699 //     Function: NodePath::find_all_textures
01700 //       Access: Published
01701 //  Description: Returns a list of a textures applied to geometry at
01702 //               this node and below that match the indicated name
01703 //               (which may contain wildcard characters).
01704 ////////////////////////////////////////////////////////////////////
01705 TextureCollection NodePath::
01706 find_all_textures(const string &name) const {
01707   Textures textures;
01708   r_find_all_textures(node(), get_net_state(), textures);
01709 
01710   GlobPattern glob(name);
01711 
01712   TextureCollection tc;
01713   Textures::iterator ti;
01714   for (ti = textures.begin(); ti != textures.end(); ++ti) {
01715     Texture *texture = (*ti);
01716     if (glob.matches(texture->get_name())) {
01717       tc.add_texture(texture);
01718     }
01719   }
01720   return tc;
01721 }
01722 
01723 ////////////////////////////////////////////////////////////////////
01724 //     Function: NodePath::set_material
01725 //       Access: Published
01726 //  Description: Sets the geometry at this level and below to render
01727 //               using the indicated material.
01728 //
01729 //               This operation copies the given material pointer.  If
01730 //               the material structure is changed later, it must be
01731 //               reapplied via another call to set_material().
01732 ////////////////////////////////////////////////////////////////////
01733 void NodePath::
01734 set_material(Material *mat, int priority) {
01735   nassertv_always(!is_empty());
01736   nassertv(mat != NULL);
01737 
01738   // We create a temporary Material pointer, a copy of the one we are
01739   // given, to allow the user to monkey with the material and set it
01740   // again later, with the desired effect.  If we stored the user's
01741   // pointer directly, it would be bad if the user later modified the
01742   // values within the Material.
01743   PT(Material) temp = new Material(*mat);
01744   const Material *mp = MaterialPool::get_material(temp);
01745 
01746   node()->set_attrib(MaterialAttrib::make(mp), priority);
01747 }
01748 
01749 ////////////////////////////////////////////////////////////////////
01750 //     Function: NodePath::set_material_off
01751 //       Access: Published
01752 //  Description: Sets the geometry at this level and below to render
01753 //               using no material.  This is normally the default, but
01754 //               it may be useful to use this to contradict
01755 //               set_material() at a higher node level (or, with a
01756 //               priority, to override a set_material() at a lower
01757 //               level).
01758 ////////////////////////////////////////////////////////////////////
01759 void NodePath::
01760 set_material_off(int priority) {
01761   nassertv_always(!is_empty());
01762   node()->set_attrib(MaterialAttrib::make_off(), priority);
01763 }
01764 
01765 ////////////////////////////////////////////////////////////////////
01766 //     Function: NodePath::clear_material
01767 //       Access: Published
01768 //  Description: Completely removes any material adjustment that may
01769 //               have been set via set_material() from this particular
01770 //               node.
01771 ////////////////////////////////////////////////////////////////////
01772 void NodePath::
01773 clear_material() {
01774   nassertv_always(!is_empty());
01775   node()->clear_attrib(MaterialAttrib::get_class_type());
01776 }
01777 
01778 ////////////////////////////////////////////////////////////////////
01779 //     Function: NodePath::has_material
01780 //       Access: Published
01781 //  Description: Returns true if a material has been applied to this
01782 //               particular node via set_material(), false otherwise.
01783 ////////////////////////////////////////////////////////////////////
01784 bool NodePath::
01785 has_material() const {
01786   nassertr_always(!is_empty(), false);
01787   const RenderAttrib *attrib =
01788     node()->get_attrib(MaterialAttrib::get_class_type());
01789   if (attrib != (const RenderAttrib *)NULL) {
01790     const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
01791     return !ma->is_off();
01792   }
01793 
01794   return false;
01795 }
01796 
01797 ////////////////////////////////////////////////////////////////////
01798 //     Function: NodePath::get_material
01799 //       Access: Published
01800 //  Description: Returns the material that has been set on this
01801 //               particular node, or NULL if no material has been set.
01802 //               This is not necessarily the material that will be
01803 //               applied to the geometry at or below this level, as
01804 //               another material at a higher or lower level may
01805 //               override.
01806 //
01807 //               This function returns a copy of the given material,
01808 //               to allow changes, if desired.  Once changes are made,
01809 //               they should be reapplied via set_material().
01810 ////////////////////////////////////////////////////////////////////
01811 PT(Material) NodePath::
01812 get_material() const {
01813   nassertr_always(!is_empty(), NULL);
01814   const RenderAttrib *attrib =
01815     node()->get_attrib(MaterialAttrib::get_class_type());
01816   if (attrib != (const RenderAttrib *)NULL) {
01817     const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
01818     return new Material(*ma->get_material());
01819   }
01820 
01821   return NULL;
01822 }
01823 
01824 ////////////////////////////////////////////////////////////////////
01825 //     Function: NodePath::set_fog
01826 //       Access: Published
01827 //  Description: Sets the geometry at this level and below to render
01828 //               using the indicated fog.
01829 ////////////////////////////////////////////////////////////////////
01830 void NodePath::
01831 set_fog(Fog *fog, int priority) {
01832   nassertv_always(!is_empty());
01833   node()->set_attrib(FogAttrib::make(fog), priority);
01834 }
01835 
01836 ////////////////////////////////////////////////////////////////////
01837 //     Function: NodePath::set_fog_off
01838 //       Access: Published
01839 //  Description: Sets the geometry at this level and below to render
01840 //               using no fog.  This is normally the default, but
01841 //               it may be useful to use this to contradict
01842 //               set_fog() at a higher node level (or, with a
01843 //               priority, to override a set_fog() at a lower
01844 //               level).
01845 ////////////////////////////////////////////////////////////////////
01846 void NodePath::
01847 set_fog_off(int priority) {
01848   nassertv_always(!is_empty());
01849   node()->set_attrib(FogAttrib::make_off(), priority);
01850 }
01851 
01852 ////////////////////////////////////////////////////////////////////
01853 //     Function: NodePath::clear_fog
01854 //       Access: Published
01855 //  Description: Completely removes any fog adjustment that may
01856 //               have been set via set_fog() or set_fog_off()
01857 //               from this particular node.  This allows whatever
01858 //               fogs might be otherwise affecting the geometry to
01859 //               show instead.
01860 ////////////////////////////////////////////////////////////////////
01861 void NodePath::
01862 clear_fog() {
01863   nassertv_always(!is_empty());
01864   node()->clear_attrib(FogAttrib::get_class_type());
01865 }
01866 
01867 ////////////////////////////////////////////////////////////////////
01868 //     Function: NodePath::has_fog
01869 //       Access: Published
01870 //  Description: Returns true if a fog has been applied to this
01871 //               particular node via set_fog(), false otherwise.
01872 //               This is not the same thing as asking whether the
01873 //               geometry at this node will be rendered with
01874 //               fog, as there may be a fog in effect from a higher or
01875 //               lower level.
01876 ////////////////////////////////////////////////////////////////////
01877 bool NodePath::
01878 has_fog() const {
01879   nassertr_always(!is_empty(), false);
01880   const RenderAttrib *attrib =
01881     node()->get_attrib(FogAttrib::get_class_type());
01882   if (attrib != (const RenderAttrib *)NULL) {
01883     const FogAttrib *fa = DCAST(FogAttrib, attrib);
01884     return !fa->is_off();
01885   }
01886 
01887   return false;
01888 }
01889 
01890 ////////////////////////////////////////////////////////////////////
01891 //     Function: NodePath::has_fog_off
01892 //       Access: Published
01893 //  Description: Returns true if a fog has been specifically
01894 //               disabled on this particular node via
01895 //               set_fog_off(), false otherwise.  This is not the
01896 //               same thing as asking whether the geometry at this
01897 //               node will be rendered unfogged, as there may be a
01898 //               fog in effect from a higher or lower level.
01899 ////////////////////////////////////////////////////////////////////
01900 bool NodePath::
01901 has_fog_off() const {
01902   nassertr_always(!is_empty(), false);
01903   const RenderAttrib *attrib =
01904     node()->get_attrib(FogAttrib::get_class_type());
01905   if (attrib != (const RenderAttrib *)NULL) {
01906     const FogAttrib *fa = DCAST(FogAttrib, attrib);
01907     return fa->is_off();
01908   }
01909 
01910   return false;
01911 }
01912 
01913 ////////////////////////////////////////////////////////////////////
01914 //     Function: NodePath::get_fog
01915 //       Access: Published
01916 //  Description: Returns the fog that has been set on this
01917 //               particular node, or NULL if no fog has been set.
01918 //               This is not necessarily the fog that will be
01919 //               applied to the geometry at or below this level, as
01920 //               another fog at a higher or lower level may
01921 //               override.
01922 ////////////////////////////////////////////////////////////////////
01923 Fog *NodePath::
01924 get_fog() const {
01925   nassertr_always(!is_empty(), NULL);
01926   const RenderAttrib *attrib =
01927     node()->get_attrib(FogAttrib::get_class_type());
01928   if (attrib != (const RenderAttrib *)NULL) {
01929     const FogAttrib *fa = DCAST(FogAttrib, attrib);
01930     return fa->get_fog();
01931   }
01932 
01933   return NULL;
01934 }
01935 
01936 ////////////////////////////////////////////////////////////////////
01937 //     Function: NodePath::set_render_mode_wireframe
01938 //       Access: Published
01939 //  Description: Sets up the geometry at this level and below (unless
01940 //               overridden) to render in wireframe mode.
01941 ////////////////////////////////////////////////////////////////////
01942 void NodePath::
01943 set_render_mode_wireframe(int priority) {
01944   nassertv_always(!is_empty());
01945   node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe), priority);
01946 }
01947 
01948 ////////////////////////////////////////////////////////////////////
01949 //     Function: NodePath::set_render_mode_filled
01950 //       Access: Published
01951 //  Description: Sets up the geometry at this level and below (unless
01952 //               overridden) to render in filled (i.e. not wireframe)
01953 //               mode.
01954 ////////////////////////////////////////////////////////////////////
01955 void NodePath::
01956 set_render_mode_filled(int priority) {
01957   nassertv_always(!is_empty());
01958   node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled), priority);
01959 }
01960 
01961 ////////////////////////////////////////////////////////////////////
01962 //     Function: NodePath::clear_render_mode
01963 //       Access: Published
01964 //  Description: Completely removes any render mode adjustment that
01965 //               may have been set on this node via
01966 //               set_render_mode_wireframe() or
01967 //               set_render_mode_filled().
01968 ////////////////////////////////////////////////////////////////////
01969 void NodePath::
01970 clear_render_mode() {
01971   nassertv_always(!is_empty());
01972   node()->clear_attrib(RenderModeAttrib::get_class_type());
01973 }
01974 
01975 ////////////////////////////////////////////////////////////////////
01976 //     Function: NodePath::has_render_mode
01977 //       Access: Published
01978 //  Description: Returns true if a render mode has been explicitly set
01979 //               on this particular node via
01980 //               set_render_mode_wireframe() or
01981 //               set_render_mode_filled(), false otherwise.
01982 ////////////////////////////////////////////////////////////////////
01983 bool NodePath::
01984 has_render_mode() const {
01985   nassertr_always(!is_empty(), false);
01986   return node()->has_attrib(RenderModeAttrib::get_class_type());
01987 }
01988 
01989 ////////////////////////////////////////////////////////////////////
01990 //     Function: NodePath::set_two_sided
01991 //       Access: Published
01992 //  Description: Specifically sets or disables two-sided rendering
01993 //               mode on this particular node.  If no other nodes
01994 //               override, this will cause backfacing polygons to be
01995 //               drawn (in two-sided mode, true) or culled (in
01996 //               one-sided mode, false).
01997 ////////////////////////////////////////////////////////////////////
01998 void NodePath::
01999 set_two_sided(bool two_sided, int priority) {
02000   nassertv_always(!is_empty());
02001 
02002   CullFaceAttrib::Mode mode =
02003     two_sided ?
02004     CullFaceAttrib::M_cull_none :
02005     CullFaceAttrib::M_cull_clockwise;
02006 
02007   node()->set_attrib(CullFaceAttrib::make(mode), priority);
02008 }
02009 
02010 ////////////////////////////////////////////////////////////////////
02011 //     Function: NodePath::clear_two_sided
02012 //       Access: Published
02013 //  Description: Completely removes any two-sided adjustment that
02014 //               may have been set on this node via set_two_sided().
02015 //               The geometry at this level and below will
02016 //               subsequently be rendered either two-sided or
02017 //               one-sided, according to whatever other nodes may have
02018 //               had set_two_sided() on it, or according to the
02019 //               initial state otherwise.
02020 ////////////////////////////////////////////////////////////////////
02021 void NodePath::
02022 clear_two_sided() {
02023   nassertv_always(!is_empty());
02024   node()->clear_attrib(CullFaceAttrib::get_class_type());
02025 }
02026 
02027 ////////////////////////////////////////////////////////////////////
02028 //     Function: NodePath::has_two_sided
02029 //       Access: Published
02030 //  Description: Returns true if a two-sided adjustment has been
02031 //               explicitly set on this particular node via
02032 //               set_two_sided().  If this returns true, then
02033 //               get_two_sided() may be called to determine which has
02034 //               been set.
02035 ////////////////////////////////////////////////////////////////////
02036 bool NodePath::
02037 has_two_sided() const {
02038   nassertr_always(!is_empty(), false);
02039   return node()->has_attrib(CullFaceAttrib::get_class_type());
02040 }
02041 
02042 ////////////////////////////////////////////////////////////////////
02043 //     Function: NodePath::get_two_sided
02044 //       Access: Published
02045 //  Description: Returns true if two-sided rendering has been
02046 //               specifically set on this node via set_two_sided(), or
02047 //               false if one-sided rendering has been specifically
02048 //               set, or if nothing has been specifically set.  See
02049 //               also has_two_sided().  This does not necessarily
02050 //               imply that the geometry will or will not be rendered
02051 //               two-sided, as there may be other nodes that override.
02052 ////////////////////////////////////////////////////////////////////
02053 bool NodePath::
02054 get_two_sided() const {
02055   nassertr_always(!is_empty(), false);
02056   const RenderAttrib *attrib =
02057     node()->get_attrib(CullFaceAttrib::get_class_type());
02058   if (attrib != (const RenderAttrib *)NULL) {
02059     const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib);
02060     return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none);
02061   }
02062 
02063   return false;
02064 }
02065 
02066 #if 0
02067 // programmers prolly wont need alpha-test control
02068 ////////////////////////////////////////////////////////////////////
02069 //     Function: NodePath::set_alpha_test
02070 //       Access: Published
02071 //  Description: Specifically sets or disables the testing of the
02072 //               alpha buffer on this particular node.  This is
02073 //               normally on in the 3-d scene graph and off in the 2-d
02074 //               scene graph; it should be on for rendering most 3-d
02075 //               objects properly.
02076 ////////////////////////////////////////////////////////////////////
02077 void NodePath::
02078 set_alpha_test(RenderAttrib::PandaCompareFunc alpha_test_mode,float reference_alpha, int priority) {
02079   nassertv_always(!is_empty());
02080   node()->set_attrib(AlphaTestAttrib::make(alpha_test_mode,reference_alpha), priority);
02081 }
02082 
02083 ////////////////////////////////////////////////////////////////////
02084 //     Function: NodePath::clear_alpha_test
02085 //       Access: Published
02086 //  Description: Completely removes any alpha-test adjustment that
02087 //               may have been set on this node via set_alpha_test().
02088 ////////////////////////////////////////////////////////////////////
02089 void NodePath::
02090 clear_alpha_test() {
02091   nassertv_always(!is_empty());
02092   node()->clear_attrib(AlphaTestAttrib::get_class_type());
02093 }
02094 
02095 ////////////////////////////////////////////////////////////////////
02096 //     Function: NodePath::has_alpha_test
02097 //       Access: Published
02098 //  Description: Returns true if a alpha-test adjustment has been
02099 //               explicitly set on this particular node via
02100 //               set_alpha_test().  If this returns true, then
02101 //               get_alpha_test() may be called to determine which has
02102 //               been set.
02103 ////////////////////////////////////////////////////////////////////
02104 bool NodePath::
02105 has_alpha_test() const {
02106   nassertr_always(!is_empty(), false);
02107   return node()->has_attrib(AlphaTestAttrib::get_class_type());
02108 }
02109 
02110 ////////////////////////////////////////////////////////////////////
02111 //     Function: NodePath::get_alpha_test
02112 //       Access: Published
02113 //  Description: Returns true if alpha-test rendering has been
02114 //               specifically set on this node via set_alpha_test(), or
02115 //               false if alpha-test rendering has been specifically
02116 //               disabled, or if nothing has been specifically set.  See
02117 //               also has_alpha_test().
02118 ////////////////////////////////////////////////////////////////////
02119 bool NodePath::
02120 get_alpha_test() const {
02121   nassertr_always(!is_empty(), false);
02122   const RenderAttrib *attrib =
02123     node()->get_attrib(AlphaTestAttrib::get_class_type());
02124   if (attrib != (const RenderAttrib *)NULL) {
02125     const AlphaTestAttrib *dta = DCAST(AlphaTestAttrib, attrib);
02126     return (dta->get_mode() != AlphaTestAttrib::M_none);
02127   }
02128 
02129   return false;
02130 }
02131 #endif
02132 ////////////////////////////////////////////////////////////////////
02133 //     Function: NodePath::set_depth_test
02134 //       Access: Published
02135 //  Description: Specifically sets or disables the testing of the
02136 //               depth buffer on this particular node.  This is
02137 //               normally on in the 3-d scene graph and off in the 2-d
02138 //               scene graph; it should be on for rendering most 3-d
02139 //               objects properly.
02140 ////////////////////////////////////////////////////////////////////
02141 void NodePath::
02142 set_depth_test(bool depth_test, int priority) {
02143   nassertv_always(!is_empty());
02144 
02145   DepthTestAttrib::PandaCompareFunc mode =
02146     depth_test ?
02147     DepthTestAttrib::M_less :
02148     DepthTestAttrib::M_none;
02149 
02150   node()->set_attrib(DepthTestAttrib::make(mode), priority);
02151 }
02152 
02153 ////////////////////////////////////////////////////////////////////
02154 //     Function: NodePath::clear_depth_test
02155 //       Access: Published
02156 //  Description: Completely removes any depth-test adjustment that
02157 //               may have been set on this node via set_depth_test().
02158 ////////////////////////////////////////////////////////////////////
02159 void NodePath::
02160 clear_depth_test() {
02161   nassertv_always(!is_empty());
02162   node()->clear_attrib(DepthTestAttrib::get_class_type());
02163 }
02164 
02165 ////////////////////////////////////////////////////////////////////
02166 //     Function: NodePath::has_depth_test
02167 //       Access: Published
02168 //  Description: Returns true if a depth-test adjustment has been
02169 //               explicitly set on this particular node via
02170 //               set_depth_test().  If this returns true, then
02171 //               get_depth_test() may be called to determine which has
02172 //               been set.
02173 ////////////////////////////////////////////////////////////////////
02174 bool NodePath::
02175 has_depth_test() const {
02176   nassertr_always(!is_empty(), false);
02177   return node()->has_attrib(DepthTestAttrib::get_class_type());
02178 }
02179 
02180 ////////////////////////////////////////////////////////////////////
02181 //     Function: NodePath::get_depth_test
02182 //       Access: Published
02183 //  Description: Returns true if depth-test rendering has been
02184 //               specifically set on this node via set_depth_test(), or
02185 //               false if depth-test rendering has been specifically
02186 //               disabled, or if nothing has been specifically set.  See
02187 //               also has_depth_test().
02188 ////////////////////////////////////////////////////////////////////
02189 bool NodePath::
02190 get_depth_test() const {
02191   nassertr_always(!is_empty(), false);
02192   const RenderAttrib *attrib =
02193     node()->get_attrib(DepthTestAttrib::get_class_type());
02194   if (attrib != (const RenderAttrib *)NULL) {
02195     const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib);
02196     return (dta->get_mode() != DepthTestAttrib::M_none);
02197   }
02198 
02199   return false;
02200 }
02201 
02202 ////////////////////////////////////////////////////////////////////
02203 //     Function: NodePath::set_depth_write
02204 //       Access: Published
02205 //  Description: Specifically sets or disables the writing to the
02206 //               depth buffer on this particular node.  This is
02207 //               normally on in the 3-d scene graph and off in the 2-d
02208 //               scene graph; it should be on for rendering most 3-d
02209 //               objects properly.
02210 ////////////////////////////////////////////////////////////////////
02211 void NodePath::
02212 set_depth_write(bool depth_write, int priority) {
02213   nassertv_always(!is_empty());
02214 
02215   DepthWriteAttrib::Mode mode =
02216     depth_write ?
02217     DepthWriteAttrib::M_on :
02218     DepthWriteAttrib::M_off;
02219 
02220   node()->set_attrib(DepthWriteAttrib::make(mode), priority);
02221 }
02222 
02223 ////////////////////////////////////////////////////////////////////
02224 //     Function: NodePath::clear_depth_write
02225 //       Access: Published
02226 //  Description: Completely removes any depth-write adjustment that
02227 //               may have been set on this node via set_depth_write().
02228 ////////////////////////////////////////////////////////////////////
02229 void NodePath::
02230 clear_depth_write() {
02231   nassertv_always(!is_empty());
02232   node()->clear_attrib(DepthWriteAttrib::get_class_type());
02233 }
02234 
02235 ////////////////////////////////////////////////////////////////////
02236 //     Function: NodePath::has_depth_write
02237 //       Access: Published
02238 //  Description: Returns true if a depth-write adjustment has been
02239 //               explicitly set on this particular node via
02240 //               set_depth_write().  If this returns true, then
02241 //               get_depth_write() may be called to determine which has
02242 //               been set.
02243 ////////////////////////////////////////////////////////////////////
02244 bool NodePath::
02245 has_depth_write() const {
02246   nassertr_always(!is_empty(), false);
02247   return node()->has_attrib(DepthWriteAttrib::get_class_type());
02248 }
02249 
02250 ////////////////////////////////////////////////////////////////////
02251 //     Function: NodePath::get_depth_write
02252 //       Access: Published
02253 //  Description: Returns true if depth-write rendering has been
02254 //               specifically set on this node via set_depth_write(), or
02255 //               false if depth-write rendering has been specifically
02256 //               disabled, or if nothing has been specifically set.  See
02257 //               also has_depth_write().
02258 ////////////////////////////////////////////////////////////////////
02259 bool NodePath::
02260 get_depth_write() const {
02261   nassertr_always(!is_empty(), false);
02262   const RenderAttrib *attrib =
02263     node()->get_attrib(DepthWriteAttrib::get_class_type());
02264   if (attrib != (const RenderAttrib *)NULL) {
02265     const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib);
02266     return (dta->get_mode() != DepthWriteAttrib::M_off);
02267   }
02268 
02269   return false;
02270 }
02271 
02272 ////////////////////////////////////////////////////////////////////
02273 //     Function: NodePath::do_billboard_axis
02274 //       Access: Published
02275 //  Description: Performs a billboard-type rotate to the indicated
02276 //               camera node, one time only, and leaves the object
02277 //               rotated.  This is similar in principle to heads_up().
02278 ////////////////////////////////////////////////////////////////////
02279 void NodePath::
02280 do_billboard_axis(const NodePath &camera, float offset) {
02281   nassertv_always(!is_empty());
02282 
02283   NodePath parent = get_parent();
02284   LMatrix4f rel_mat = camera.get_mat(parent);
02285 
02286   LVector3f up = LVector3f::up();
02287   LVector3f rel_pos = -rel_mat.get_row3(3);
02288 
02289   LQuaternionf quat;
02290   ::heads_up(quat, rel_pos, up);
02291   set_quat(quat);
02292 
02293   // Also slide the geometry towards the camera according to the
02294   // offset factor.
02295   if (offset != 0.0f) {
02296     LVector3f translate = rel_mat.get_row3(3);
02297     translate.normalize();
02298     translate *= offset;
02299     set_pos(translate);
02300   }
02301 }
02302 
02303 ////////////////////////////////////////////////////////////////////
02304 //     Function: NodePath::do_billboard_point_eye
02305 //       Access: Published
02306 //  Description: Performs a billboard-type rotate to the indicated
02307 //               camera node, one time only, and leaves the object
02308 //               rotated.  This is similar in principle to look_at(),
02309 //               although the point_eye billboard effect cannot be
02310 //               achieved using the ordinary look_at() call.
02311 ////////////////////////////////////////////////////////////////////
02312 void NodePath::
02313 do_billboard_point_eye(const NodePath &camera, float offset) {
02314   nassertv_always(!is_empty());
02315 
02316   NodePath parent = get_parent();
02317   LMatrix4f rel_mat = camera.get_mat(parent);
02318 
02319   LVector3f up = LVector3f::up() * rel_mat;
02320   LVector3f rel_pos = LVector3f::forward() * rel_mat;
02321 
02322   LQuaternionf quat;
02323   ::look_at(quat, rel_pos, up);
02324   set_quat(quat);
02325 
02326   // Also slide the geometry towards the camera according to the
02327   // offset factor.
02328   if (offset != 0.0f) {
02329     LVector3f translate = rel_mat.get_row3(3);
02330     translate.normalize();
02331     translate *= offset;
02332     set_pos(translate);
02333   }
02334 }
02335 
02336 ////////////////////////////////////////////////////////////////////
02337 //     Function: NodePath::do_billboard_point_world
02338 //       Access: Published
02339 //  Description: Performs a billboard-type rotate to the indicated
02340 //               camera node, one time only, and leaves the object
02341 //               rotated.  This is similar in principle to look_at().
02342 ////////////////////////////////////////////////////////////////////
02343 void NodePath::
02344 do_billboard_point_world(const NodePath &camera, float offset) {
02345   nassertv_always(!is_empty());
02346 
02347   NodePath parent = get_parent();
02348   LMatrix4f rel_mat = camera.get_mat(parent);
02349 
02350   LVector3f up = LVector3f::up();
02351   LVector3f rel_pos = -rel_mat.get_row3(3);
02352 
02353   LQuaternionf quat;
02354   ::look_at(quat, rel_pos, up);
02355   set_quat(quat);
02356 
02357   // Also slide the geometry towards the camera according to the
02358   // offset factor.
02359   if (offset != 0.0f) {
02360     LVector3f translate = rel_mat.get_row3(3);
02361     translate.normalize();
02362     translate *= offset;
02363     set_pos(translate);
02364   }
02365 }
02366 
02367 ////////////////////////////////////////////////////////////////////
02368 //     Function: NodePath::set_billboard_axis
02369 //       Access: Published
02370 //  Description: Puts a billboard transition on the node such that it
02371 //               will rotate in two dimensions around the up axis,
02372 //               towards a specified "camera" instead of to the
02373 //               viewing camera.
02374 ////////////////////////////////////////////////////////////////////
02375 void NodePath::
02376 set_billboard_axis(const NodePath &camera, float offset) {
02377   nassertv_always(!is_empty());
02378   CPT(RenderEffect) billboard = BillboardEffect::make
02379     (LVector3f::up(), false, true, 
02380      offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
02381   node()->set_effect(billboard);
02382 }
02383 
02384 ////////////////////////////////////////////////////////////////////
02385 //     Function: NodePath::set_billboard_point_eye
02386 //       Access: Published
02387 //  Description: Puts a billboard transition on the node such that it
02388 //               will rotate in three dimensions about the origin,
02389 //               keeping its up vector oriented to the top of the
02390 //               camera, towards a specified "camera" instead of to
02391 //               the viewing camera.
02392 ////////////////////////////////////////////////////////////////////
02393 void NodePath::
02394 set_billboard_point_eye(const NodePath &camera, float offset) {
02395   nassertv_always(!is_empty());
02396   CPT(RenderEffect) billboard = BillboardEffect::make
02397     (LVector3f::up(), true, false,
02398      offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
02399   node()->set_effect(billboard);
02400 }
02401 
02402 ////////////////////////////////////////////////////////////////////
02403 //     Function: NodePath::set_billboard_point_world
02404 //       Access: Published
02405 //  Description: Puts a billboard transition on the node such that it
02406 //               will rotate in three dimensions about the origin,
02407 //               keeping its up vector oriented to the sky, towards a
02408 //               specified "camera" instead of to the viewing camera.
02409 ////////////////////////////////////////////////////////////////////
02410 void NodePath::
02411 set_billboard_point_world(const NodePath &camera, float offset) {
02412   nassertv_always(!is_empty());
02413   CPT(RenderEffect) billboard = BillboardEffect::make
02414     (LVector3f::up(), false, false,
02415      offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
02416   node()->set_effect(billboard);
02417 }
02418 
02419 ////////////////////////////////////////////////////////////////////
02420 //     Function: NodePath::clear_billboard
02421 //       Access: Published
02422 //  Description: Removes any billboard effect from the node.
02423 ////////////////////////////////////////////////////////////////////
02424 void NodePath::
02425 clear_billboard() {
02426   nassertv_always(!is_empty());
02427   node()->clear_effect(BillboardEffect::get_class_type());
02428 }
02429 
02430 ////////////////////////////////////////////////////////////////////
02431 //     Function: NodePath::has_billboard
02432 //       Access: Published
02433 //  Description: Returns true if there is any billboard effect on
02434 //               the node.
02435 ////////////////////////////////////////////////////////////////////
02436 bool NodePath::
02437 has_billboard() const {
02438   nassertr_always(!is_empty(), false);
02439   return node()->has_effect(BillboardEffect::get_class_type());
02440 }
02441 
02442 ////////////////////////////////////////////////////////////////////
02443 //     Function: NodePath::set_compass
02444 //       Access: Published
02445 //  Description: Puts a compass effect on the node, so that it will
02446 //               retain a fixed rotation relative to the reference
02447 //               node (or render if the reference node is empty)
02448 //               regardless of the transforms above it.
02449 ////////////////////////////////////////////////////////////////////
02450 void NodePath::
02451 set_compass(const NodePath &reference) {
02452   nassertv_always(!is_empty());
02453   node()->set_effect(CompassEffect::make(reference));
02454 }
02455 
02456 ////////////////////////////////////////////////////////////////////
02457 //     Function: NodePath::clear_compass
02458 //       Access: Published
02459 //  Description: Removes any compass effect from the node.
02460 ////////////////////////////////////////////////////////////////////
02461 void NodePath::
02462 clear_compass() {
02463   nassertv_always(!is_empty());
02464   node()->clear_effect(CompassEffect::get_class_type());
02465 }
02466 
02467 ////////////////////////////////////////////////////////////////////
02468 //     Function: NodePath::has_compass
02469 //       Access: Published
02470 //  Description: Returns true if there is any compass effect on
02471 //               the node.
02472 ////////////////////////////////////////////////////////////////////
02473 bool NodePath::
02474 has_compass() const {
02475   nassertr_always(!is_empty(), false);
02476   return node()->has_effect(CompassEffect::get_class_type());
02477 }
02478 
02479 ////////////////////////////////////////////////////////////////////
02480 //     Function: NodePath::set_transparency
02481 //       Access: Published
02482 //  Description: Specifically sets or disables transparent rendering
02483 //               mode on this particular node.  If no other nodes
02484 //               override, this will cause items with a non-1 value
02485 //               for alpha color to be rendered partially transparent.
02486 ////////////////////////////////////////////////////////////////////
02487 void NodePath::
02488 set_transparency(bool transparency, int priority) {
02489   nassertv_always(!is_empty());
02490 
02491   TransparencyAttrib::Mode mode =
02492     transparency ?
02493     TransparencyAttrib::M_alpha :
02494     TransparencyAttrib::M_none;
02495 
02496   node()->set_attrib(TransparencyAttrib::make(mode), priority);
02497 }
02498 
02499 ////////////////////////////////////////////////////////////////////
02500 //     Function: NodePath::clear_transparency
02501 //       Access: Published
02502 //  Description: Completely removes any transparency adjustment that
02503 //               may have been set on this node via set_transparency().
02504 //               The geometry at this level and below will
02505 //               subsequently be rendered either transparent or not,
02506 //               to whatever other nodes may have had
02507 //               set_transparency() on them.
02508 ////////////////////////////////////////////////////////////////////
02509 void NodePath::
02510 clear_transparency() {
02511   nassertv_always(!is_empty());
02512   node()->clear_attrib(TransparencyAttrib::get_class_type());
02513 }
02514 
02515 ////////////////////////////////////////////////////////////////////
02516 //     Function: NodePath::has_transparency
02517 //       Access: Published
02518 //  Description: Returns true if a transparent-rendering adjustment
02519 //               has been explicitly set on this particular node via
02520 //               set_transparency().  If this returns true, then
02521 //               get_transparency() may be called to determine whether
02522 //               transparency has been explicitly enabled or
02523 //               explicitly disabled for this node.
02524 ////////////////////////////////////////////////////////////////////
02525 bool NodePath::
02526 has_transparency() const {
02527   nassertr_always(!is_empty(), false);
02528   return node()->has_attrib(TransparencyAttrib::get_class_type());
02529 }
02530 
02531 ////////////////////////////////////////////////////////////////////
02532 //     Function: NodePath::get_transparency
02533 //       Access: Published
02534 //  Description: Returns true if transparent rendering has been
02535 //               specifically set on this node via set_transparency(), or
02536 //               false if nontransparent rendering has been specifically
02537 //               set, or if nothing has been specifically set.  See
02538 //               also has_transparency().  This does not necessarily
02539 //               imply that the geometry will or will not be rendered
02540 //               transparent, as there may be other nodes that override.
02541 ////////////////////////////////////////////////////////////////////
02542 bool NodePath::
02543 get_transparency() const {
02544   nassertr_always(!is_empty(), false);
02545   const RenderAttrib *attrib =
02546     node()->get_attrib(TransparencyAttrib::get_class_type());
02547   if (attrib != (const RenderAttrib *)NULL) {
02548     const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib);
02549     return (ta->get_mode() != TransparencyAttrib::M_none);
02550   }
02551 
02552   return false;
02553 }
02554 
02555 
02556 ////////////////////////////////////////////////////////////////////
02557 //     Function: NodePath::get_hidden_ancestor
02558 //       Access: Published
02559 //  Description: Returns the NodePath at or above the referenced node
02560 //               that is hidden to the indicated camera(s), or an
02561 //               empty NodePath if no ancestor of the referenced node
02562 //               is hidden (and the node should be visible).
02563 ////////////////////////////////////////////////////////////////////
02564 NodePath NodePath::
02565 get_hidden_ancestor(DrawMask camera_mask) const {
02566   NodePathComponent *comp;
02567   for (comp = _head; 
02568        comp != (NodePathComponent *)NULL; 
02569        comp = comp->get_next()) {
02570     PandaNode *node = comp->get_node();
02571     if ((node->get_draw_mask() & camera_mask).is_zero()) {
02572       NodePath result;
02573       result._head = comp;
02574       return result;
02575     }
02576   }
02577 
02578   return not_found();
02579 }
02580 
02581 ////////////////////////////////////////////////////////////////////
02582 //     Function: NodePath::get_stashed_ancestor
02583 //       Access: Published
02584 //  Description: Returns the NodePath at or above the referenced node
02585 //               that is stashed, or an empty NodePath if no ancestor
02586 //               of the referenced node is stashed (and the node should
02587 //               be visible).
02588 ////////////////////////////////////////////////////////////////////
02589 NodePath NodePath::
02590 get_stashed_ancestor() const {
02591   NodePathComponent *comp = _head;
02592   if (comp != (NodePathComponent *)NULL) {
02593     NodePathComponent *next = comp->get_next();
02594 
02595     while (next != (NodePathComponent *)NULL) {
02596       PandaNode *node = comp->get_node();
02597       PandaNode *parent_node = next->get_node();
02598 
02599       if (parent_node->find_stashed(node) >= 0) {
02600         NodePath result;
02601         result._head = comp;
02602         return result;
02603       }
02604 
02605       comp = next;
02606       next = next->get_next();
02607     }
02608   }
02609 
02610   return not_found();
02611 }
02612 
02613 ////////////////////////////////////////////////////////////////////
02614 //     Function: NodePath::verify_complete
02615 //       Access: Published
02616 //  Description: Returns true if all of the nodes described in the
02617 //               NodePath are connected and the top node is the top
02618 //               of the graph, or false otherwise.
02619 ////////////////////////////////////////////////////////////////////
02620 bool NodePath::
02621 verify_complete() const {
02622   if (is_empty()) {
02623     return true;
02624   }
02625 
02626   uncollapse_head();
02627   const NodePathComponent *comp = _head;
02628   nassertr(comp != (const NodePathComponent *)NULL, false);
02629 
02630   PandaNode *node = comp->get_node();
02631   nassertr(node != (const PandaNode *)NULL, false);
02632   int length = comp->get_length();
02633 
02634   comp = comp->get_next();
02635   length--;
02636   while (comp != (const NodePathComponent *)NULL) {
02637     PandaNode *next_node = comp->get_node();
02638     nassertr(next_node != (const PandaNode *)NULL, false);
02639 
02640     if (node->find_parent(next_node) < 0) {
02641       pgraph_cat.warning()
02642         << *this << " is incomplete; " << *node << " is not a child of "
02643         << *next_node << "\n";
02644       return false;
02645     }
02646 
02647     if (comp->get_length() != length) {
02648       pgraph_cat.warning()
02649         << *this << " is incomplete; length at " << *next_node
02650         << " indicates " << comp->get_length() << " while length at "
02651         << *node << " indicates " << length << "\n";
02652       return false;
02653     }
02654 
02655     node = next_node;
02656     comp = comp->get_next();
02657     length--;
02658   }
02659 
02660   // Now that we've reached the top, we should have no parents.
02661   if (length == 0 && node->get_num_parents() == 0) {
02662     return true;
02663   }
02664 
02665   pgraph_cat.warning()
02666     << *this << " is incomplete; top node " << *node << " indicates length "
02667     << length << " with " << node->get_num_parents() << " parents.\n";
02668   return false;
02669 }
02670 
02671 ////////////////////////////////////////////////////////////////////
02672 //     Function: NodePath::prepare_scene
02673 //       Access: Published
02674 //  Description: Walks through the scene graph beginning at the bottom
02675 //               node, and does whatever initialization is required to
02676 //               render the scene properly with the indicated GSG.  It
02677 //               is not strictly necessary to call this, since the GSG
02678 //               will initialize itself when the scene is rendered,
02679 //               but this may take some of the overhead away from that
02680 //               process.
02681 //
02682 //               If force_retained_mode is true, retained mode is set
02683 //               on the geometry encountered, regardless of the
02684 //               setting of the retained-mode Config variable.
02685 //               Otherwise, retained mode is set only if the
02686 //               retained-mode Config variable is true.
02687 ////////////////////////////////////////////////////////////////////
02688 void NodePath::
02689 prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode) {
02690   nassertv_always(!is_empty());
02691 
02692   CPT(RenderState) net_state = get_net_state();
02693   r_prepare_scene(node(), net_state, gsg, 
02694                   retained_mode || force_retained_mode);
02695 }
02696 
02697 ////////////////////////////////////////////////////////////////////
02698 //     Function: NodePath::show_bounds
02699 //       Access: Published
02700 //  Description: Causes the bounding volume of the bottom node and all
02701 //               of its descendants (that is, the bounding volume
02702 //               associated with the the bottom arc) to be rendered,
02703 //               if possible.  The rendering method is less than
02704 //               optimal; this is intended primarily for debugging.
02705 ////////////////////////////////////////////////////////////////////
02706 void NodePath::
02707 show_bounds() {
02708   nassertv_always(!is_empty());
02709   node()->set_effect(ShowBoundsEffect::make());
02710 }
02711 
02712 ////////////////////////////////////////////////////////////////////
02713 //     Function: NodePath::hide_bounds
02714 //       Access: Published
02715 //  Description: Stops the rendering of the bounding volume begun with
02716 //               show_bounds().
02717 ////////////////////////////////////////////////////////////////////
02718 void NodePath::
02719 hide_bounds() {
02720   nassertv_always(!is_empty());
02721   node()->clear_effect(ShowBoundsEffect::get_class_type());
02722 }
02723 
02724 ////////////////////////////////////////////////////////////////////
02725 //     Function: NodePath::get_bounds
02726 //       Access: Published
02727 //  Description: Returns a newly-allocated bounding volume containing
02728 //               the bottom node and all of its descendants.  This is
02729 //               the bounding volume on the bottom arc, converted to
02730 //               the local coordinate space of the node.
02731 ////////////////////////////////////////////////////////////////////
02732 PT(BoundingVolume) NodePath::
02733 get_bounds() const {
02734   nassertr_always(!is_empty(), new BoundingSphere);
02735   return node()->get_bound().make_copy();
02736 }
02737 
02738 ////////////////////////////////////////////////////////////////////
02739 //     Function: NodePath::force_recompute_bounds
02740 //       Access: Published
02741 //  Description: Forces the recomputing of all the bounding volumes at
02742 //               every node in the subgraph beginning at this node and
02743 //               below.
02744 //
02745 //               This should not normally need to be called, since the
02746 //               bounding volumes are supposed to be recomputed
02747 //               automatically when necessary.  It may be useful when
02748 //               debugging, to verify that the bounding volumes have
02749 //               not become inadvertently stale; it may also be useful
02750 //               to force animated characters to update their bounding
02751 //               volumes (which does not presently happen
02752 //               automatically).
02753 ////////////////////////////////////////////////////////////////////
02754 void NodePath::
02755 force_recompute_bounds() {
02756   nassertv_always(!is_empty());
02757   r_force_recompute_bounds(node());
02758 }
02759 
02760 ////////////////////////////////////////////////////////////////////
02761 //     Function: NodePath::write_bounds
02762 //       Access: Published
02763 //  Description: Writes a description of the bounding volume
02764 //               containing the bottom node and all of its descendants
02765 //               to the indicated output stream.
02766 ////////////////////////////////////////////////////////////////////
02767 void NodePath::
02768 write_bounds(ostream &out) const {
02769   get_bounds()->write(out);
02770 }
02771 
02772 ////////////////////////////////////////////////////////////////////
02773 //     Function: NodePath::calc_tight_bounds
02774 //       Access: Published
02775 //  Description: Calculates the minimum and maximum vertices of all
02776 //               Geoms at this NodePath's bottom node and below.  This
02777 //               is a tight bounding box; it will generally be tighter
02778 //               than the bounding volume returned by get_bounds()
02779 //               (but it is more expensive to compute).
02780 //
02781 //               The return value is true if any points are within the
02782 //               bounding volume, or false if none are.
02783 ////////////////////////////////////////////////////////////////////
02784 bool NodePath::
02785 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) {
02786   min_point.set(0.0f, 0.0f, 0.0f);
02787   max_point.set(0.0f, 0.0f, 0.0f);
02788   nassertr_always(!is_empty(), false);
02789 
02790   bool found_any = false;
02791   node()->calc_tight_bounds(min_point, max_point, found_any, 
02792                             TransformState::make_identity());
02793 
02794   return found_any;
02795 }
02796 
02797 ////////////////////////////////////////////////////////////////////
02798 //     Function: NodePath::flatten_light
02799 //       Access: Published
02800 //  Description: Lightly flattens out the hierarchy below this node by
02801 //               applying transforms, colors, and texture matrices
02802 //               from the arcs onto the vertices, but does not remove
02803 //               any nodes.
02804 //
02805 //               This can result in improved rendering performance
02806 //               because there will be fewer transforms in the
02807 //               resulting scene graph, but the number of nodes will
02808 //               remain the same.
02809 //
02810 //               Particularly, any NodePaths that reference nodes
02811 //               within this hierarchy will not be damaged.  However,
02812 //               since this operation will remove transforms from the
02813 //               scene graph, it may be dangerous to apply to arcs
02814 //               where you expect to dynamically modify the transform,
02815 //               or where you expect the geometry to remain in a
02816 //               particular local coordinate system.
02817 //
02818 //               The return value is always 0, since flatten_light
02819 //               does not remove any arcs.
02820 ////////////////////////////////////////////////////////////////////
02821 int NodePath::
02822 flatten_light() {
02823   nassertr_always(!is_empty(), 0);
02824   SceneGraphReducer gr;
02825   gr.apply_attribs(node());
02826 
02827   return 0;
02828 }
02829 
02830 ////////////////////////////////////////////////////////////////////
02831 //     Function: NodePath::flatten_medium
02832 //       Access: Published
02833 //  Description: A more thorough flattening than flatten_light(), this
02834 //               first applies all the transforms, colors, and texture
02835 //               matrices from the arcs onto the vertices, and then
02836 //               removes unneeded grouping nodes--nodes that have
02837 //               exactly one child, for instance, but have no special
02838 //               properties in themselves.
02839 //
02840 //               This results in improved perforamance over
02841 //               flatten_light() because the number of nodes in the
02842 //               scene graph is reduced.
02843 //
02844 //               If max_children is specified, it represents the
02845 //               maximum number of children a node is allowed to have
02846 //               and still be flattened.  Normally, this is 1; we
02847 //               don't typically want to flatten a node that has
02848 //               multiple children.  However, sometimes this may be
02849 //               desirable; set this parameter to control the limit.
02850 //               If this is set to -1, there is no limit.
02851 //
02852 //               The return value is the number of arcs removed.
02853 ////////////////////////////////////////////////////////////////////
02854 int NodePath::
02855 flatten_medium() {
02856   nassertr_always(!is_empty(), 0);
02857   SceneGraphReducer gr;
02858   gr.apply_attribs(node());
02859   int num_removed = gr.flatten(node(), false);
02860 
02861   return num_removed;
02862 }
02863 
02864 ////////////////////////////////////////////////////////////////////
02865 //     Function: NodePath::flatten_strong
02866 //       Access: Published
02867 //  Description: The strongest possible flattening.  This first
02868 //               applies all of the transforms to the vertices, as in
02869 //               flatten_medium(), but then it will combine sibling
02870 //               nodes together when possible, in addition to removing
02871 //               unnecessary parent-child nodes.  This can result in
02872 //               substantially fewer nodes, but any nicely-grouped
02873 //               hierachical bounding volumes may be lost.
02874 //
02875 //               It is generally a good idea to apply this kind of
02876 //               flattening only to nodes that will be culled largely
02877 //               as a single unit, like a car.  Applying this to an
02878 //               entire scene may result in overall poorer performance
02879 //               because of less-effective culling.
02880 ////////////////////////////////////////////////////////////////////
02881 int NodePath::
02882 flatten_strong() {
02883   nassertr_always(!is_empty(), 0);
02884   SceneGraphReducer gr;
02885   gr.apply_attribs(node());
02886   int num_removed = gr.flatten(node(), true);
02887 
02888   return num_removed;
02889 }
02890 
02891 ////////////////////////////////////////////////////////////////////
02892 //     Function: NodePath::write_bam_file
02893 //       Access: Published
02894 //  Description: Writes the contents of this node and below out to a
02895 //               bam file with the indicated filename.  This file may
02896 //               then be read in again, as is, at some later point.
02897 //               Returns true if successful, false on some kind of
02898 //               error.
02899 ////////////////////////////////////////////////////////////////////
02900 bool NodePath::
02901 write_bam_file(const string &filename) const {
02902   nassertr_always(!is_empty(), false);
02903 
02904   BamFile bam_file;
02905 
02906   bool okflag = false;
02907 
02908   if (bam_file.open_write(filename)) {
02909     if (bam_file.write_object(node())) {
02910       okflag = true;
02911     }
02912     bam_file.close();
02913   }
02914   return okflag;
02915 }
02916 
02917 ////////////////////////////////////////////////////////////////////
02918 //     Function: NodePath::uncollapse_head
02919 //       Access: Private
02920 //  Description: Quietly and transparently uncollapses the _head
02921 //               pointer if it needs it.  This can happen only when
02922 //               two distinct NodePaths are collapsed into the same
02923 //               path after the removal of an instance somewhere
02924 //               higher up the chain.
02925 ////////////////////////////////////////////////////////////////////
02926 void NodePath::
02927 uncollapse_head() const {
02928   if (_head != (NodePathComponent *)NULL && _head->is_collapsed()) {
02929     ((NodePath *)this)->_head = _head->uncollapse();
02930   }
02931 }
02932 
02933 ////////////////////////////////////////////////////////////////////
02934 //     Function: NodePath::find_common_ancestor
02935 //       Access: Private, Static
02936 //  Description: Walks up from both NodePaths to find the first node
02937 //               that both have in common, if any.  Fills a_count and
02938 //               b_count with the number of nodes below the common
02939 //               node in each path.
02940 ////////////////////////////////////////////////////////////////////
02941 void NodePath::
02942 find_common_ancestor(const NodePath &a, const NodePath &b,
02943                      int &a_count, int &b_count) {
02944   nassertv(!a.is_empty() && !b.is_empty());
02945   a.uncollapse_head();
02946   b.uncollapse_head();
02947 
02948   NodePathComponent *ac = a._head;
02949   NodePathComponent *bc = b._head;
02950   a_count = 0;
02951   b_count = 0;
02952 
02953   // Shorten up the longer one until they are the same length.
02954   while (ac->get_length() > bc->get_length()) {
02955     nassertv(ac != (NodePathComponent *)NULL);
02956     ac = ac->get_next();
02957     a_count++;
02958   }
02959   while (bc->get_length() > ac->get_length()) {
02960     nassertv(bc != (NodePathComponent *)NULL);
02961     bc = bc->get_next();
02962     b_count++;
02963   }
02964 
02965   // Now shorten them both up until we reach the same component.
02966   while (ac != bc) {
02967     // These shouldn't go to NULL unless they both go there together. 
02968     nassertv(ac != (NodePathComponent *)NULL);
02969     nassertv(bc != (NodePathComponent *)NULL);
02970     ac = ac->get_next();
02971     a_count++;
02972     bc = bc->get_next();
02973     b_count++;
02974   }
02975 }
02976 
02977 ////////////////////////////////////////////////////////////////////
02978 //     Function: NodePath::r_get_net_state
02979 //       Access: Private
02980 //  Description: Recursively determines the net state chnages to the
02981 //               indicated component node from the root of the graph.
02982 ////////////////////////////////////////////////////////////////////
02983 CPT(RenderState) NodePath::
02984 r_get_net_state(NodePathComponent *comp) const {
02985   if (comp == (NodePathComponent *)NULL) {
02986     return RenderState::make_empty();
02987   } else {
02988     CPT(RenderState) state = comp->get_node()->get_state();
02989     return r_get_net_state(comp->get_next())->compose(state);
02990   }
02991 }
02992 
02993 ////////////////////////////////////////////////////////////////////
02994 //     Function: NodePath::r_get_partial_state
02995 //       Access: Private
02996 //  Description: Recursively determines the net state changes to the
02997 //               indicated component node from the nth node above it.
02998 //               If n exceeds the length of the path, this returns the
02999 //               net transform from the root of the graph.
03000 ////////////////////////////////////////////////////////////////////
03001 CPT(RenderState) NodePath::
03002 r_get_partial_state(NodePathComponent *comp, int n) const {
03003   if (n == 0 || comp == (NodePathComponent *)NULL) {
03004     return RenderState::make_empty();
03005   } else {
03006     CPT(RenderState) state = comp->get_node()->get_state();
03007     return r_get_partial_state(comp->get_next(), n - 1)->compose(state);
03008   }
03009 }
03010 
03011 ////////////////////////////////////////////////////////////////////
03012 //     Function: NodePath::r_get_net_transform
03013 //       Access: Private
03014 //  Description: Recursively determines the net transform to the
03015 //               indicated component node from the root of the graph.
03016 ////////////////////////////////////////////////////////////////////
03017 CPT(TransformState) NodePath::
03018 r_get_net_transform(NodePathComponent *comp) const {
03019   if (comp == (NodePathComponent *)NULL) {
03020     return TransformState::make_identity();
03021   } else {
03022     CPT(TransformState) transform = comp->get_node()->get_transform();
03023     return r_get_net_transform(comp->get_next())->compose(transform);
03024   }
03025 }
03026 
03027 ////////////////////////////////////////////////////////////////////
03028 //     Function: NodePath::r_get_partial_transform
03029 //       Access: Private
03030 //  Description: Recursively determines the net transform to the
03031 //               indicated component node from the nth node above it.
03032 //               If n exceeds the length of the path, this returns the
03033 //               net transform from the root of the graph.
03034 ////////////////////////////////////////////////////////////////////
03035 CPT(TransformState) NodePath::
03036 r_get_partial_transform(NodePathComponent *comp, int n) const {
03037   if (n == 0 || comp == (NodePathComponent *)NULL) {
03038     return TransformState::make_identity();
03039   } else {
03040     CPT(TransformState) transform = comp->get_node()->get_transform();
03041     return r_get_partial_transform(comp->get_next(), n - 1)->compose(transform);
03042   }
03043 }
03044 
03045 ////////////////////////////////////////////////////////////////////
03046 //     Function: NodePath::find_matches
03047 //       Access: Private
03048 //  Description: Finds up to max_matches matches against the given
03049 //               path string from this node and deeper.  The
03050 //               max_matches count indicates the maximum number of
03051 //               matches to return, or -1 not to limit the number
03052 //               returned.
03053 ////////////////////////////////////////////////////////////////////
03054 void NodePath::
03055 find_matches(NodePathCollection &result, const string &path,
03056              int max_matches) const {
03057   if (is_empty()) {
03058     pgraph_cat.warning()
03059       << "Attempt to extend an empty NodePath by '" << path
03060       << "'.\n";
03061     return;
03062   }
03063   FindApproxPath approx_path;
03064   if (approx_path.add_string(path)) {
03065     find_matches(result, approx_path, max_matches);
03066   }
03067 }
03068 
03069 ////////////////////////////////////////////////////////////////////
03070 //     Function: NodePath::find_matches
03071 //       Access: Private
03072 //  Description: Finds up to max_matches matches against the given
03073 //               approx_path from this node and deeper.  The
03074 //               max_matches count indicates the maximum number of
03075 //               matches to return, or -1 not to limit the number
03076 //               returned.
03077 ////////////////////////////////////////////////////////////////////
03078 void NodePath::
03079 find_matches(NodePathCollection &result, FindApproxPath &approx_path,
03080              int max_matches) const {
03081   if (is_empty()) {
03082     pgraph_cat.warning()
03083       << "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
03084     return;
03085   }
03086   FindApproxLevelEntry start(WorkingNodePath(*this), approx_path);
03087   nassertv(start._node_path.is_valid());
03088   FindApproxLevel level;
03089   level.add_entry(start);
03090   r_find_matches(result, level, max_matches, _max_search_depth);
03091 }
03092 
03093 ////////////////////////////////////////////////////////////////////
03094 //     Function: NodePath::r_find_matches
03095 //       Access: Private
03096 //  Description: The recursive implementation of find_matches.
03097 ////////////////////////////////////////////////////////////////////
03098 void NodePath::
03099 r_find_matches(NodePathCollection &result,
03100                const FindApproxLevel &level,
03101                int max_matches, int num_levels_remaining) const {
03102   // Go on to the next level.  If we exceeded the requested maximum
03103   // depth, stop.
03104   if (num_levels_remaining <= 0) {
03105     return;
03106   }
03107   num_levels_remaining--;
03108 
03109   FindApproxLevel next_level;
03110   bool okflag = true;
03111 
03112   // For each node in the current level, build up the set of possible
03113   // matches in the next level.
03114   FindApproxLevel::Vec::const_iterator li;
03115   for (li = level._v.begin(); li != level._v.end() && okflag; ++li) {
03116     const FindApproxLevelEntry &entry = (*li);
03117 
03118     if (entry.is_solution(0)) {
03119       // Does this entry already represent a solution?
03120       result.add_path(entry._node_path.get_node_path());
03121     } else {
03122       entry.consider_node(result, next_level, max_matches, 0);
03123     }
03124 
03125     if (max_matches > 0 && result.get_num_paths() >= max_matches) {
03126       // Really, we just want to return here.  But returning from
03127       // within the conditional within the for loop seems to sometimes
03128       // cause a compiler fault in GCC.  We'll use a semaphore
03129       // variable instead.
03130       okflag = false;
03131     }
03132   }
03133 
03134   // Now recurse on the next level.
03135   if (okflag) {
03136     r_find_matches(result, next_level, max_matches, num_levels_remaining);
03137   }
03138 }
03139 
03140 ////////////////////////////////////////////////////////////////////
03141 //     Function: NodePath::r_adjust_all_priorities
03142 //       Access: Private
03143 //  Description: The recursive implementation of
03144 //               adjust_all_priorities().  This walks through the
03145 //               subgraph defined by the indicated node and below.
03146 ////////////////////////////////////////////////////////////////////
03147 void NodePath::
03148 r_adjust_all_priorities(PandaNode *node, int adjustment) {
03149   node->set_state(node->get_state()->adjust_all_priorities(adjustment));
03150   if (node->is_geom_node()) {
03151     GeomNode *gnode;
03152     DCAST_INTO_V(gnode, node);
03153 
03154     int num_geoms = gnode->get_num_geoms();
03155     for (int i = 0; i < num_geoms; i++) {
03156       gnode->set_geom_state(i, gnode->get_geom_state(i)->adjust_all_priorities(adjustment));
03157     }
03158   }
03159 
03160   PandaNode::Children cr = node->get_children();
03161   int num_children = cr.get_num_children();
03162   for (int i = 0; i < num_children; i++) {
03163     r_adjust_all_priorities(cr.get_child(i), adjustment);
03164   }
03165 }
03166 
03167 ////////////////////////////////////////////////////////////////////
03168 //     Function: NodePath::r_force_recompute_bounds
03169 //       Access: Private
03170 //  Description: 
03171 ////////////////////////////////////////////////////////////////////
03172 void NodePath::
03173 r_force_recompute_bounds(PandaNode *node) {
03174   if (node->is_geom_node()) {
03175     GeomNode *gnode;
03176     DCAST_INTO_V(gnode, node);
03177 
03178     int num_geoms = gnode->get_num_geoms();
03179     for (int i = 0; i < num_geoms; i++) {
03180       gnode->get_geom(i)->mark_bound_stale();
03181     }
03182   }
03183 
03184   node->mark_bound_stale();
03185 
03186   // Now consider children.
03187   PandaNode::Children cr = node->get_children();
03188   int num_children = cr.get_num_children();
03189   for (int i = 0; i < num_children; i++) {
03190     r_force_recompute_bounds(cr.get_child(i));
03191   }
03192 }
03193 
03194 ////////////////////////////////////////////////////////////////////
03195 //     Function: NodePath::r_find_texture
03196 //       Access: Private
03197 //  Description: 
03198 ////////////////////////////////////////////////////////////////////
03199 Texture * NodePath::
03200 r_find_texture(PandaNode *node, const RenderState *state,
03201                const GlobPattern &glob) const {
03202   if (node->is_geom_node()) {
03203     GeomNode *gnode;
03204     DCAST_INTO_R(gnode, node, NULL);
03205 
03206     int num_geoms = gnode->get_num_geoms();
03207     for (int i = 0; i < num_geoms; i++) {
03208       CPT(RenderState) geom_state = 
03209         state->compose(gnode->get_geom_state(i));
03210 
03211       // Look for a TextureAttrib on the state.
03212       const RenderAttrib *attrib =
03213         geom_state->get_attrib(TextureAttrib::get_class_type());
03214       if (attrib != (const RenderAttrib *)NULL) {
03215         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03216         Texture *texture = ta->get_texture();
03217         if (texture != (Texture *)NULL) {
03218           if (glob.matches(texture->get_name())) {
03219             return texture;
03220           }
03221         }
03222       }
03223     }
03224   }
03225 
03226   // Now consider children.
03227   PandaNode::Children cr = node->get_children();
03228   int num_children = cr.get_num_children();
03229   for (int i = 0; i < num_children; i++) {
03230     PandaNode *child = cr.get_child(i);
03231     CPT(RenderState) next_state = state->compose(child->get_state());
03232 
03233     Texture *result = r_find_texture(child, next_state, glob);
03234     if (result != (Texture *)NULL) {
03235       return result;
03236     }
03237   }
03238 
03239   return NULL;
03240 }
03241 
03242 ////////////////////////////////////////////////////////////////////
03243 //     Function: NodePath::r_find_all_textures
03244 //       Access: Private
03245 //  Description: 
03246 ////////////////////////////////////////////////////////////////////
03247 void NodePath::
03248 r_find_all_textures(PandaNode *node, const RenderState *state,
03249                     NodePath::Textures &textures) const {
03250   if (node->is_geom_node()) {
03251     GeomNode *gnode;
03252     DCAST_INTO_V(gnode, node);
03253 
03254     int num_geoms = gnode->get_num_geoms();
03255     for (int i = 0; i < num_geoms; i++) {
03256       CPT(RenderState) geom_state = 
03257         state->compose(gnode->get_geom_state(i));
03258 
03259       // Look for a TextureAttrib on the state.
03260       const RenderAttrib *attrib =
03261         geom_state->get_attrib(TextureAttrib::get_class_type());
03262       if (attrib != (const RenderAttrib *)NULL) {
03263         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03264         Texture *texture = ta->get_texture();
03265         if (texture != (Texture *)NULL) {
03266           textures.insert(texture);
03267         }
03268       }
03269     }
03270   }
03271 
03272   // Now consider children.
03273   PandaNode::Children cr = node->get_children();
03274   int num_children = cr.get_num_children();
03275   for (int i = 0; i < num_children; i++) {
03276     PandaNode *child = cr.get_child(i);
03277     CPT(RenderState) next_state = state->compose(child->get_state());
03278     r_find_all_textures(child, next_state, textures);
03279   }
03280 }
03281 
03282 ////////////////////////////////////////////////////////////////////
03283 //     Function: NodePath::r_prepare_scene
03284 //       Access: Private
03285 //  Description: The recursive implementation of prepare_scene.
03286 ////////////////////////////////////////////////////////////////////
03287 void NodePath::
03288 r_prepare_scene(PandaNode *node, const RenderState *state,
03289                 GraphicsStateGuardianBase *gsg, bool do_retained_mode) {
03290   if (node->is_geom_node()) {
03291     GeomNode *gnode;
03292     DCAST_INTO_V(gnode, node);
03293 
03294     /* 
03295        Not implemented yet in pgraph.  Maybe we don't need this anyway.
03296     if (do_retained_mode) {
03297       gnode->prepare(gsg);
03298     }
03299     */
03300 
03301     int num_geoms = gnode->get_num_geoms();
03302     for (int i = 0; i < num_geoms; i++) {
03303       CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i));
03304       const RenderAttrib *attrib = 
03305         geom_state->get_attrib(TextureAttrib::get_class_type());
03306       if (attrib != (const RenderAttrib *)NULL) {
03307         const TextureAttrib *ta;
03308         DCAST_INTO_V(ta, attrib);
03309         Texture *texture = ta->get_texture();
03310         if (texture != (Texture *)NULL) {
03311           texture->prepare(gsg);
03312         }
03313       }
03314     }
03315   }
03316 
03317   int num_children = node->get_num_children();
03318   for (int i = 0; i < num_children; i++) {
03319     PandaNode *child = node->get_child(i);
03320     CPT(RenderState) child_state = state->compose(child->get_state());
03321     r_prepare_scene(child, child_state, gsg, do_retained_mode);
03322   }
03323 }

Generated on Fri May 2 00:41:57 2003 for Panda by doxygen1.3