Panda3D
|
00001 // Filename: pandaNode.cxx 00002 // Created by: drose (20Feb02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pandaNode.h" 00016 #include "config_pgraph.h" 00017 #include "nodePathComponent.h" 00018 #include "bamReader.h" 00019 #include "bamWriter.h" 00020 #include "indent.h" 00021 #include "geometricBoundingVolume.h" 00022 #include "sceneGraphReducer.h" 00023 #include "accumulatedAttribs.h" 00024 #include "clipPlaneAttrib.h" 00025 #include "boundingSphere.h" 00026 #include "boundingBox.h" 00027 #include "pStatTimer.h" 00028 #include "config_mathutil.h" 00029 #include "lightReMutexHolder.h" 00030 #include "graphicsStateGuardianBase.h" 00031 #include "py_panda.h" 00032 00033 // This category is just temporary for debugging convenience. 00034 NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH); 00035 NotifyCategoryDef(drawmask, ""); 00036 00037 TypeHandle PandaNode::BamReaderAuxDataDown::_type_handle; 00038 00039 PandaNode::SceneRootFunc *PandaNode::_scene_root_func; 00040 00041 PandaNodeChain PandaNode::_dirty_prev_transforms; 00042 DrawMask PandaNode::_overall_bit = DrawMask::bit(31); 00043 00044 PStatCollector PandaNode::_reset_prev_pcollector("App:Collisions:Reset"); 00045 PStatCollector PandaNode::_update_bounds_pcollector("*:Bounds"); 00046 00047 TypeHandle PandaNode::_type_handle; 00048 TypeHandle PandaNode::CData::_type_handle; 00049 TypeHandle PandaNodePipelineReader::_type_handle; 00050 00051 // 00052 // There are two different interfaces here for making and breaking 00053 // parent-child connections: the fundamental PandaNode interface, via 00054 // add_child() and remove_child() (and related functions), and the 00055 // NodePath support interface, via attach(), detach(), and reparent(). 00056 // They both do essentially the same thing, but with slightly 00057 // different inputs. The PandaNode interfaces try to guess which 00058 // NodePaths should be updated as a result of the scene graph change, 00059 // while the NodePath interfaces already know. 00060 // 00061 // The NodePath support interface functions are strictly called from 00062 // within the NodePath class, and are used to implement 00063 // NodePath::reparent_to() and NodePath::remove_node(), etc. The 00064 // fundamental interface, on the other hand, is intended to be called 00065 // directly by the user. 00066 // 00067 // The fundamental interface has a slightly lower overhead because it 00068 // does not need to create a NodePathComponent chain where one does 00069 // not already exist; however, the NodePath support interface is more 00070 // useful when the NodePath already does exist, because it ensures 00071 // that the particular NodePath calling it is kept appropriately 00072 // up-to-date. 00073 // 00074 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: PandaNode::Constructor 00078 // Access: Published 00079 // Description: 00080 //////////////////////////////////////////////////////////////////// 00081 PandaNode:: 00082 PandaNode(const string &name) : 00083 Namable(name), 00084 _paths_lock("PandaNode::_paths_lock"), 00085 _dirty_prev_transform(false) 00086 { 00087 if (pgraph_cat.is_debug()) { 00088 pgraph_cat.debug() 00089 << "Constructing " << (void *)this << ", " << get_name() << "\n"; 00090 } 00091 #ifndef NDEBUG 00092 _unexpected_change_flags = 0; 00093 #endif // !NDEBUG 00094 00095 #ifdef DO_MEMORY_USAGE 00096 MemoryUsage::update_type(this, this); 00097 #endif 00098 } 00099 00100 //////////////////////////////////////////////////////////////////// 00101 // Function: PandaNode::Destructor 00102 // Access: Published, Virtual 00103 // Description: 00104 //////////////////////////////////////////////////////////////////// 00105 PandaNode:: 00106 ~PandaNode() { 00107 if (pgraph_cat.is_debug()) { 00108 pgraph_cat.debug() 00109 << "Destructing " << (void *)this << ", " << get_name() << "\n"; 00110 } 00111 clear_dirty_prev_transform(); 00112 00113 // We shouldn't have any parents left by the time we destruct, or 00114 // there's a refcount fault somewhere. 00115 00116 // Actually, that's not necessarily true anymore, since we might be 00117 // updating a node dynamically via the bam reader, which doesn't 00118 // necessarily keep related pairs of nodes in sync with each other. 00119 /* 00120 #ifndef NDEBUG 00121 { 00122 CDReader cdata(_cycler); 00123 nassertv(cdata->get_up()->empty()); 00124 } 00125 #endif // NDEBUG 00126 */ 00127 00128 remove_all_children(); 00129 } 00130 00131 //////////////////////////////////////////////////////////////////// 00132 // Function: PandaNode::Copy Constructor 00133 // Access: Protected 00134 // Description: Do not call the copy constructor directly; instead, 00135 // use make_copy() or copy_subgraph() to make a copy of 00136 // a node. 00137 //////////////////////////////////////////////////////////////////// 00138 PandaNode:: 00139 PandaNode(const PandaNode ©) : 00140 ReferenceCount(copy), 00141 TypedWritable(copy), 00142 Namable(copy), 00143 _paths_lock("PandaNode::_paths_lock"), 00144 _dirty_prev_transform(false) 00145 { 00146 if (pgraph_cat.is_debug()) { 00147 pgraph_cat.debug() 00148 << "Copying " << (void *)this << ", " << get_name() << "\n"; 00149 } 00150 #ifdef DO_MEMORY_USAGE 00151 MemoryUsage::update_type(this, this); 00152 #endif 00153 // Copying a node does not copy its children. 00154 #ifndef NDEBUG 00155 _unexpected_change_flags = 0; 00156 #endif // !NDEBUG 00157 00158 // Copy the other node's state. 00159 { 00160 CDReader copy_cdata(copy._cycler); 00161 CDWriter cdata(_cycler, true); 00162 cdata->_state = copy_cdata->_state; 00163 cdata->_transform = copy_cdata->_transform; 00164 cdata->_prev_transform = copy_cdata->_prev_transform; 00165 if (cdata->_transform != cdata->_prev_transform) { 00166 set_dirty_prev_transform(); 00167 } 00168 00169 cdata->_effects = copy_cdata->_effects; 00170 cdata->_tag_data = copy_cdata->_tag_data; 00171 cdata->_draw_control_mask = copy_cdata->_draw_control_mask; 00172 cdata->_draw_show_mask = copy_cdata->_draw_show_mask; 00173 cdata->_into_collide_mask = copy_cdata->_into_collide_mask; 00174 cdata->_bounds_type = copy_cdata->_bounds_type; 00175 cdata->_user_bounds = copy_cdata->_user_bounds; 00176 cdata->_internal_bounds = NULL; 00177 cdata->_internal_bounds_computed = UpdateSeq::initial(); 00178 cdata->_internal_bounds_mark = UpdateSeq::initial(); 00179 ++cdata->_internal_bounds_mark; 00180 cdata->_final_bounds = copy_cdata->_final_bounds; 00181 cdata->_fancy_bits = copy_cdata->_fancy_bits; 00182 00183 #ifdef HAVE_PYTHON 00184 // Copy and increment all of the Python objects held by the other 00185 // node. 00186 cdata->_python_tag_data = copy_cdata->_python_tag_data; 00187 cdata->inc_py_refs(); 00188 #endif // HAVE_PYTHON 00189 } 00190 } 00191 00192 //////////////////////////////////////////////////////////////////// 00193 // Function: PandaNode::Copy Assignment Operator 00194 // Access: Private 00195 // Description: Do not call the copy assignment operator at all. Use 00196 // make_copy() or copy_subgraph() to make a copy of a 00197 // node. 00198 //////////////////////////////////////////////////////////////////// 00199 void PandaNode:: 00200 operator = (const PandaNode ©) { 00201 nassertv(false); 00202 } 00203 00204 //////////////////////////////////////////////////////////////////// 00205 // Function: PandaNode::as_reference_count 00206 // Access: Public, Virtual 00207 // Description: Returns the pointer cast to a ReferenceCount pointer, 00208 // if it is in fact of that type. 00209 //////////////////////////////////////////////////////////////////// 00210 ReferenceCount *PandaNode:: 00211 as_reference_count() { 00212 return this; 00213 } 00214 00215 //////////////////////////////////////////////////////////////////// 00216 // Function: PandaNode::dupe_for_flatten 00217 // Access: Public, Virtual 00218 // Description: This is similar to make_copy(), but it makes a copy 00219 // for the specific purpose of flatten. Typically, this 00220 // will be a new PandaNode with a new pointer, but all 00221 // of the internal data will always be shared with the 00222 // original; whereas the new node returned by 00223 // make_copy() might not share the internal data. 00224 //////////////////////////////////////////////////////////////////// 00225 PandaNode *PandaNode:: 00226 dupe_for_flatten() const { 00227 return make_copy(); 00228 } 00229 00230 //////////////////////////////////////////////////////////////////// 00231 // Function: PandaNode::safe_to_flatten 00232 // Access: Public, Virtual 00233 // Description: Returns true if it is generally safe to flatten out 00234 // this particular kind of PandaNode by duplicating 00235 // instances (by calling dupe_for_flatten()), false 00236 // otherwise (for instance, a Camera cannot be safely 00237 // flattened, because the Camera pointer itself is 00238 // meaningful). 00239 //////////////////////////////////////////////////////////////////// 00240 bool PandaNode:: 00241 safe_to_flatten() const { 00242 return true; 00243 } 00244 00245 //////////////////////////////////////////////////////////////////// 00246 // Function: PandaNode::safe_to_transform 00247 // Access: Public, Virtual 00248 // Description: Returns true if it is generally safe to transform 00249 // this particular kind of PandaNode by calling the 00250 // xform() method, false otherwise. 00251 //////////////////////////////////////////////////////////////////// 00252 bool PandaNode:: 00253 safe_to_transform() const { 00254 return true; 00255 } 00256 00257 //////////////////////////////////////////////////////////////////// 00258 // Function: PandaNode::safe_to_modify_transform 00259 // Access: Public, Virtual 00260 // Description: Returns true if it is safe to automatically adjust 00261 // the transform on this kind of node. Usually, this is 00262 // only a bad idea if the user expects to find a 00263 // particular transform on the node. 00264 // 00265 // ModelNodes with the preserve_transform flag set are 00266 // presently the only kinds of nodes that should not 00267 // have their transform even adjusted. 00268 //////////////////////////////////////////////////////////////////// 00269 bool PandaNode:: 00270 safe_to_modify_transform() const { 00271 return true; 00272 } 00273 00274 //////////////////////////////////////////////////////////////////// 00275 // Function: PandaNode::safe_to_combine 00276 // Access: Public, Virtual 00277 // Description: Returns true if it is generally safe to combine this 00278 // particular kind of PandaNode with other kinds of 00279 // PandaNodes of compatible type, adding children or 00280 // whatever. For instance, an LODNode should not be 00281 // combined with any other PandaNode, because its set of 00282 // children is meaningful. 00283 //////////////////////////////////////////////////////////////////// 00284 bool PandaNode:: 00285 safe_to_combine() const { 00286 return true; 00287 } 00288 00289 //////////////////////////////////////////////////////////////////// 00290 // Function: PandaNode::safe_to_combine_children 00291 // Access: Public, Virtual 00292 // Description: Returns true if it is generally safe to combine the 00293 // children of this PandaNode with each other. For 00294 // instance, an LODNode's children should not be 00295 // combined with each other, because the set of children 00296 // is meaningful. 00297 //////////////////////////////////////////////////////////////////// 00298 bool PandaNode:: 00299 safe_to_combine_children() const { 00300 return true; 00301 } 00302 00303 //////////////////////////////////////////////////////////////////// 00304 // Function: PandaNode::safe_to_flatten_below 00305 // Access: Public, Virtual 00306 // Description: Returns true if a flatten operation may safely 00307 // continue past this node, or false if nodes below this 00308 // node may not be molested. 00309 //////////////////////////////////////////////////////////////////// 00310 bool PandaNode:: 00311 safe_to_flatten_below() const { 00312 return true; 00313 } 00314 00315 //////////////////////////////////////////////////////////////////// 00316 // Function: PandaNode::preserve_name 00317 // Access: Public, Virtual 00318 // Description: Returns true if the node's name has extrinsic meaning 00319 // and must be preserved across a flatten operation, 00320 // false otherwise. 00321 //////////////////////////////////////////////////////////////////// 00322 bool PandaNode:: 00323 preserve_name() const { 00324 return false; 00325 } 00326 00327 //////////////////////////////////////////////////////////////////// 00328 // Function: PandaNode::get_unsafe_to_apply_attribs 00329 // Access: Public, Virtual 00330 // Description: Returns the union of all attributes from 00331 // SceneGraphReducer::AttribTypes that may not safely be 00332 // applied to the vertices of this node. If this is 00333 // nonzero, these attributes must be dropped at this 00334 // node as a state change. 00335 // 00336 // This is a generalization of safe_to_transform(). 00337 //////////////////////////////////////////////////////////////////// 00338 int PandaNode:: 00339 get_unsafe_to_apply_attribs() const { 00340 return 0; 00341 } 00342 00343 //////////////////////////////////////////////////////////////////// 00344 // Function: PandaNode::apply_attribs_to_vertices 00345 // Access: Public, Virtual 00346 // Description: Applies whatever attributes are specified in the 00347 // AccumulatedAttribs object (and by the attrib_types 00348 // bitmask) to the vertices on this node, if 00349 // appropriate. If this node uses geom arrays like a 00350 // GeomNode, the supplied GeomTransformer may be used to 00351 // unify shared arrays across multiple different nodes. 00352 // 00353 // This is a generalization of xform(). 00354 //////////////////////////////////////////////////////////////////// 00355 void PandaNode:: 00356 apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, 00357 GeomTransformer &transformer) { 00358 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) { 00359 const LMatrix4f &mat = attribs._transform->get_mat(); 00360 xform(mat); 00361 00362 Thread *current_thread = Thread::get_current_thread(); 00363 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00364 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00365 cdata->_effects = cdata->_effects->xform(mat); 00366 cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty()); 00367 } 00368 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00369 } 00370 mark_bam_modified(); 00371 } 00372 00373 //////////////////////////////////////////////////////////////////// 00374 // Function: PandaNode::xform 00375 // Access: Public, Virtual 00376 // Description: Transforms the contents of this PandaNode by the 00377 // indicated matrix, if it means anything to do so. For 00378 // most kinds of PandaNodes, this does nothing. 00379 //////////////////////////////////////////////////////////////////// 00380 void PandaNode:: 00381 xform(const LMatrix4f &) { 00382 } 00383 00384 //////////////////////////////////////////////////////////////////// 00385 // Function: PandaNode::combine_with 00386 // Access: Public, Virtual 00387 // Description: Collapses this PandaNode with the other PandaNode, if 00388 // possible, and returns a pointer to the combined 00389 // PandaNode, or NULL if the two PandaNodes cannot 00390 // safely be combined. 00391 // 00392 // The return value may be this, other, or a new 00393 // PandaNode altogether. 00394 // 00395 // This function is called from GraphReducer::flatten(), 00396 // and need not deal with children; its job is just to 00397 // decide whether to collapse the two PandaNodes and 00398 // what the collapsed PandaNode should look like. 00399 //////////////////////////////////////////////////////////////////// 00400 PandaNode *PandaNode:: 00401 combine_with(PandaNode *other) { 00402 // An unadorned PandaNode always combines with any other PandaNodes by 00403 // yielding completely. However, if we are actually some fancy PandaNode 00404 // type that derives from PandaNode but didn't redefine this function, we 00405 // should refuse to combine. 00406 if (is_exact_type(get_class_type())) { 00407 // No, we're an ordinary PandaNode. 00408 return other; 00409 00410 } else if (other->is_exact_type(get_class_type())) { 00411 // We're not an ordinary PandaNode, but the other one is. 00412 return this; 00413 } 00414 00415 // We're something other than an ordinary PandaNode. Don't combine. 00416 return (PandaNode *)NULL; 00417 } 00418 00419 //////////////////////////////////////////////////////////////////// 00420 // Function: PandaNode::calc_tight_bounds 00421 // Access: Public, Virtual 00422 // Description: This is used to support 00423 // NodePath::calc_tight_bounds(). It is not intended to 00424 // be called directly, and it has nothing to do with the 00425 // normal Panda bounding-volume computation. 00426 // 00427 // If the node contains any geometry, this updates 00428 // min_point and max_point to enclose its bounding box. 00429 // found_any is to be set true if the node has any 00430 // geometry at all, or left alone if it has none. This 00431 // method may be called over several nodes, so it may 00432 // enter with min_point, max_point, and found_any 00433 // already set. 00434 // 00435 // This function is recursive, and the return value is 00436 // the transform after it has been modified by this 00437 // node's transform. 00438 //////////////////////////////////////////////////////////////////// 00439 CPT(TransformState) PandaNode:: 00440 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, 00441 const TransformState *transform, Thread *current_thread) const { 00442 CPT(TransformState) next_transform = transform->compose(get_transform()); 00443 00444 Children cr = get_children(current_thread); 00445 int num_children = cr.get_num_children(); 00446 for (int i = 0; i < num_children; i++) { 00447 cr.get_child(i)->calc_tight_bounds(min_point, max_point, 00448 found_any, next_transform, 00449 current_thread); 00450 } 00451 00452 return next_transform; 00453 } 00454 00455 //////////////////////////////////////////////////////////////////// 00456 // Function: PandaNode::cull_callback 00457 // Access: Public, Virtual 00458 // Description: This function will be called during the cull 00459 // traversal to perform any additional operations that 00460 // should be performed at cull time. This may include 00461 // additional manipulation of render state or additional 00462 // visible/invisible decisions, or any other arbitrary 00463 // operation. 00464 // 00465 // Note that this function will *not* be called unless 00466 // set_cull_callback() is called in the constructor of 00467 // the derived class. It is necessary to call 00468 // set_cull_callback() to indicated that we require 00469 // cull_callback() to be called. 00470 // 00471 // By the time this function is called, the node has 00472 // already passed the bounding-volume test for the 00473 // viewing frustum, and the node's transform and state 00474 // have already been applied to the indicated 00475 // CullTraverserData object. 00476 // 00477 // The return value is true if this node should be 00478 // visible, or false if it should be culled. 00479 //////////////////////////////////////////////////////////////////// 00480 bool PandaNode:: 00481 cull_callback(CullTraverser *, CullTraverserData &) { 00482 return true; 00483 } 00484 00485 //////////////////////////////////////////////////////////////////// 00486 // Function: PandaNode::has_selective_visibility 00487 // Access: Public, Virtual 00488 // Description: Should be overridden by derived classes to return 00489 // true if this kind of node has some restrictions on 00490 // the set of children that should be rendered. Node 00491 // with this property include LODNodes, SwitchNodes, and 00492 // SequenceNodes. 00493 // 00494 // If this function returns true, 00495 // get_first_visible_child() and 00496 // get_next_visible_child() will be called to walk 00497 // through the list of children during cull, instead of 00498 // iterating through the entire list. This method is 00499 // called after cull_callback(), so cull_callback() may 00500 // be responsible for the decisions as to which children 00501 // are visible at the moment. 00502 //////////////////////////////////////////////////////////////////// 00503 bool PandaNode:: 00504 has_selective_visibility() const { 00505 return false; 00506 } 00507 00508 //////////////////////////////////////////////////////////////////// 00509 // Function: PandaNode::get_first_visible_child 00510 // Access: Public, Virtual 00511 // Description: Returns the index number of the first visible child 00512 // of this node, or a number >= get_num_children() if 00513 // there are no visible children of this node. This is 00514 // called during the cull traversal, but only if 00515 // has_selective_visibility() has already returned true. 00516 // See has_selective_visibility(). 00517 //////////////////////////////////////////////////////////////////// 00518 int PandaNode:: 00519 get_first_visible_child() const { 00520 return 0; 00521 } 00522 00523 //////////////////////////////////////////////////////////////////// 00524 // Function: PandaNode::get_next_visible_child 00525 // Access: Public, Virtual 00526 // Description: Returns the index number of the next visible child 00527 // of this node following the indicated child, or a 00528 // number >= get_num_children() if there are no more 00529 // visible children of this node. See 00530 // has_selective_visibility() and 00531 // get_first_visible_child(). 00532 //////////////////////////////////////////////////////////////////// 00533 int PandaNode:: 00534 get_next_visible_child(int n) const { 00535 return n + 1; 00536 } 00537 00538 //////////////////////////////////////////////////////////////////// 00539 // Function: PandaNode::has_single_child_visibility 00540 // Access: Public, Virtual 00541 // Description: Should be overridden by derived classes to return 00542 // true if this kind of node has the special property 00543 // that just one of its children is visible at any given 00544 // time, and furthermore that the particular visible 00545 // child can be determined without reference to any 00546 // external information (such as a camera). At present, 00547 // only SequenceNodes and SwitchNodes fall into this 00548 // category. 00549 // 00550 // If this function returns true, get_visible_child() 00551 // can be called to return the index of the 00552 // currently-visible child. 00553 //////////////////////////////////////////////////////////////////// 00554 bool PandaNode:: 00555 has_single_child_visibility() const { 00556 return false; 00557 } 00558 00559 //////////////////////////////////////////////////////////////////// 00560 // Function: PandaNode::get_visible_child 00561 // Access: Public, Virtual 00562 // Description: Returns the index number of the currently visible 00563 // child of this node. This is only meaningful if 00564 // has_single_child_visibility() has returned true. 00565 //////////////////////////////////////////////////////////////////// 00566 int PandaNode:: 00567 get_visible_child() const { 00568 return 0; 00569 } 00570 00571 //////////////////////////////////////////////////////////////////// 00572 // Function: PandaNode::is_renderable 00573 // Access: Public, Virtual 00574 // Description: Returns true if there is some value to visiting this 00575 // particular node during the cull traversal for any 00576 // camera, false otherwise. This will be used to 00577 // optimize the result of get_net_draw_show_mask(), so 00578 // that any subtrees that contain only nodes for which 00579 // is_renderable() is false need not be visited. 00580 //////////////////////////////////////////////////////////////////// 00581 bool PandaNode:: 00582 is_renderable() const { 00583 return false; 00584 } 00585 00586 //////////////////////////////////////////////////////////////////// 00587 // Function: PandaNode::add_for_draw 00588 // Access: Public, Virtual 00589 // Description: Adds the node's contents to the CullResult we are 00590 // building up during the cull traversal, so that it 00591 // will be drawn at render time. For most nodes other 00592 // than GeomNodes, this is a do-nothing operation. 00593 //////////////////////////////////////////////////////////////////// 00594 void PandaNode:: 00595 add_for_draw(CullTraverser *, CullTraverserData &) { 00596 } 00597 00598 //////////////////////////////////////////////////////////////////// 00599 // Function: PandaNode::make_copy 00600 // Access: Published, Virtual 00601 // Description: Returns a newly-allocated PandaNode that is a shallow 00602 // copy of this one. It will be a different pointer, 00603 // but its internal data may or may not be shared with 00604 // that of the original PandaNode. No children will be 00605 // copied. 00606 //////////////////////////////////////////////////////////////////// 00607 PandaNode *PandaNode:: 00608 make_copy() const { 00609 return new PandaNode(*this); 00610 } 00611 00612 //////////////////////////////////////////////////////////////////// 00613 // Function: PandaNode::copy_subgraph 00614 // Access: Published 00615 // Description: Allocates and returns a complete copy of this 00616 // PandaNode and the entire scene graph rooted at this 00617 // PandaNode. Some data may still be shared from the 00618 // original (e.g. vertex index tables), but nothing that 00619 // will impede normal use of the PandaNode. 00620 //////////////////////////////////////////////////////////////////// 00621 PT(PandaNode) PandaNode:: 00622 copy_subgraph(Thread *current_thread) const { 00623 InstanceMap inst_map; 00624 return r_copy_subgraph(inst_map, current_thread); 00625 } 00626 00627 #ifdef HAVE_PYTHON 00628 //////////////////////////////////////////////////////////////////// 00629 // Function: PandaNode::__copy__ 00630 // Access: Published 00631 // Description: A special Python method that is invoked by 00632 // copy.copy(node). Unlike the PandaNode copy 00633 // constructor, which creates a new node without 00634 // children, this shares child pointers (essentially 00635 // making every child an instance). This is intended to 00636 // simulate the behavior of copy.copy() for other 00637 // objects. 00638 //////////////////////////////////////////////////////////////////// 00639 PT(PandaNode) PandaNode:: 00640 __copy__() const { 00641 Thread *current_thread = Thread::get_current_thread(); 00642 00643 PT(PandaNode) node_dupe = make_copy(); 00644 00645 Children children = get_children(current_thread); 00646 int num_children = children.get_num_children(); 00647 00648 for (int i = 0; i < num_children; ++i) { 00649 PandaNode *child = children.get_child(i); 00650 node_dupe->add_child(children.get_child(i), children.get_child_sort(i)); 00651 } 00652 00653 return node_dupe; 00654 } 00655 #endif // HAVE_PYTHON 00656 00657 #ifdef HAVE_PYTHON 00658 //////////////////////////////////////////////////////////////////// 00659 // Function: PandaNode::__deepcopy__ 00660 // Access: Published 00661 // Description: A special Python method that is invoked by 00662 // copy.deepcopy(node). This calls copy_subgraph() 00663 // unless the node is already present in the provided 00664 // dictionary. 00665 //////////////////////////////////////////////////////////////////// 00666 PyObject *PandaNode:: 00667 __deepcopy__(PyObject *self, PyObject *memo) const { 00668 IMPORT_THIS struct Dtool_PyTypedObject Dtool_PandaNode; 00669 00670 // Borrowed reference. 00671 PyObject *dupe = PyDict_GetItem(memo, self); 00672 if (dupe != NULL) { 00673 // Already in the memo dictionary. 00674 Py_INCREF(dupe); 00675 return dupe; 00676 } 00677 00678 PT(PandaNode) node_dupe = copy_subgraph(); 00679 00680 // DTool_CreatePyInstanceTyped() steals a C++ reference. 00681 node_dupe->ref(); 00682 dupe = DTool_CreatePyInstanceTyped 00683 ((void *)node_dupe.p(), Dtool_PandaNode, true, false, 00684 node_dupe->get_type_index()); 00685 00686 if (PyDict_SetItem(memo, self, dupe) != 0) { 00687 Py_DECREF(dupe); 00688 return NULL; 00689 } 00690 00691 return dupe; 00692 } 00693 #endif // HAVE_PYTHON 00694 00695 //////////////////////////////////////////////////////////////////// 00696 // Function: PandaNode::count_num_descendants 00697 // Access: Published 00698 // Description: Returns the number of nodes at and below this level. 00699 //////////////////////////////////////////////////////////////////// 00700 int PandaNode:: 00701 count_num_descendants() const { 00702 int count = 1; 00703 Children children = get_children(); 00704 int num_children = children.get_num_children(); 00705 00706 for (int i = 0; i < num_children; ++i) { 00707 PandaNode *child = children.get_child(i); 00708 count += child->count_num_descendants(); 00709 } 00710 00711 return count; 00712 } 00713 00714 //////////////////////////////////////////////////////////////////// 00715 // Function: PandaNode::add_child 00716 // Access: Published 00717 // Description: Adds a new child to the node. The child is added in 00718 // the relative position indicated by sort; if all 00719 // children have the same sort index, the child is added 00720 // at the end. 00721 // 00722 // If the same child is added to a node more than once, 00723 // the previous instance is first removed. 00724 //////////////////////////////////////////////////////////////////// 00725 void PandaNode:: 00726 add_child(PandaNode *child_node, int sort, Thread *current_thread) { 00727 nassertv(child_node != (PandaNode *)NULL); 00728 00729 if (!verify_child_no_cycles(child_node)) { 00730 // Whoops, adding this child node would introduce a cycle in the 00731 // scene graph. 00732 return; 00733 } 00734 00735 // Ensure the child_node is not deleted while we do this. 00736 PT(PandaNode) keep_child = child_node; 00737 remove_child(child_node); 00738 00739 // Apply this operation to the current stage as well as to all 00740 // upstream stages. 00741 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00742 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00743 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread); 00744 00745 cdata->modify_down()->insert(DownConnection(child_node, sort)); 00746 cdata_child->modify_up()->insert(UpConnection(this)); 00747 } 00748 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00749 00750 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) { 00751 new_connection(this, child_node, pipeline_stage, current_thread); 00752 } 00753 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler); 00754 00755 force_bounds_stale(); 00756 00757 children_changed(); 00758 child_node->parents_changed(); 00759 mark_bam_modified(); 00760 child_node->mark_bam_modified(); 00761 } 00762 00763 //////////////////////////////////////////////////////////////////// 00764 // Function: PandaNode::remove_child 00765 // Access: Published 00766 // Description: Removes the nth child from the node. 00767 //////////////////////////////////////////////////////////////////// 00768 void PandaNode:: 00769 remove_child(int child_index, Thread *current_thread) { 00770 int pipeline_stage = current_thread->get_pipeline_stage(); 00771 nassertv(pipeline_stage == 0); 00772 00773 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00774 PT(Down) down = cdata->modify_down(); 00775 nassertv(child_index >= 0 && child_index < (int)down->size()); 00776 00777 PT(PandaNode) child_node = (*down)[child_index].get_child(); 00778 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, 00779 current_thread); 00780 PT(Up) up = cdata_child->modify_up(); 00781 00782 down->erase(down->begin() + child_index); 00783 int num_erased = up->erase(UpConnection(this)); 00784 nassertv(num_erased == 1); 00785 00786 sever_connection(this, child_node, pipeline_stage, current_thread); 00787 force_bounds_stale(pipeline_stage, current_thread); 00788 00789 children_changed(); 00790 child_node->parents_changed(); 00791 mark_bam_modified(); 00792 child_node->mark_bam_modified(); 00793 } 00794 00795 //////////////////////////////////////////////////////////////////// 00796 // Function: PandaNode::remove_child 00797 // Access: Published 00798 // Description: Removes the indicated child from the node. Returns 00799 // true if the child was removed, false if it was not 00800 // already a child of the node. This will also 00801 // successfully remove the child if it had been stashed. 00802 //////////////////////////////////////////////////////////////////// 00803 bool PandaNode:: 00804 remove_child(PandaNode *child_node, Thread *current_thread) { 00805 nassertr(child_node != (PandaNode *)NULL, false); 00806 00807 // Make sure the child node is not destructed during the execution 00808 // of this method. 00809 PT(PandaNode) keep_child = child_node; 00810 00811 // We have to do this for each upstream pipeline stage. 00812 bool any_removed = false; 00813 00814 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) { 00815 if (stage_remove_child(child_node, pipeline_stage, current_thread)) { 00816 any_removed = true; 00817 00818 sever_connection(this, child_node, pipeline_stage, current_thread); 00819 force_bounds_stale(pipeline_stage, current_thread); 00820 } 00821 } 00822 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler); 00823 00824 if (any_removed) { 00825 // Call callback hooks. 00826 children_changed(); 00827 child_node->parents_changed(); 00828 } 00829 00830 return any_removed; 00831 } 00832 00833 //////////////////////////////////////////////////////////////////// 00834 // Function: PandaNode::replace_child 00835 // Access: Published 00836 // Description: Searches for the orig_child node in the node's list 00837 // of children, and replaces it with the new_child 00838 // instead. Returns true if the replacement is made, or 00839 // false if the node is not a child or if there is some 00840 // other problem. 00841 //////////////////////////////////////////////////////////////////// 00842 bool PandaNode:: 00843 replace_child(PandaNode *orig_child, PandaNode *new_child, 00844 Thread *current_thread) { 00845 nassertr(orig_child != (PandaNode *)NULL, false); 00846 nassertr(new_child != (PandaNode *)NULL, false); 00847 00848 if (orig_child == new_child) { 00849 // Trivial no-op. 00850 return true; 00851 } 00852 00853 if (!verify_child_no_cycles(new_child)) { 00854 // Whoops, adding this child node would introduce a cycle in the 00855 // scene graph. 00856 return false; 00857 } 00858 00859 // Make sure the orig_child node is not destructed during the 00860 // execution of this method. 00861 PT(PandaNode) keep_orig_child = orig_child; 00862 00863 // We have to do this for each upstream pipeline stage. 00864 bool any_replaced = false; 00865 00866 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 00867 if (stage_replace_child(orig_child, new_child, pipeline_stage, current_thread)) { 00868 any_replaced = true; 00869 } 00870 } 00871 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 00872 00873 if (any_replaced) { 00874 children_changed(); 00875 orig_child->parents_changed(); 00876 new_child->parents_changed(); 00877 } 00878 00879 return any_replaced; 00880 } 00881 00882 00883 //////////////////////////////////////////////////////////////////// 00884 // Function: PandaNode::stash_child 00885 // Access: Published 00886 // Description: Stashes the indicated child node. This removes the 00887 // child from the list of active children and puts it on 00888 // a special list of stashed children. This child node 00889 // no longer contributes to the bounding volume of the 00890 // PandaNode, and is not visited in normal traversals. 00891 // It is invisible and uncollidable. The child may 00892 // later be restored by calling unstash_child(). 00893 // 00894 // This can only be called from the top pipeline stage 00895 // (i.e. from App). 00896 //////////////////////////////////////////////////////////////////// 00897 void PandaNode:: 00898 stash_child(int child_index, Thread *current_thread) { 00899 int pipeline_stage = current_thread->get_pipeline_stage(); 00900 nassertv(pipeline_stage == 0); 00901 nassertv(child_index >= 0 && child_index < get_num_children()); 00902 00903 // Save a reference count for ourselves. 00904 PT(PandaNode) self = this; 00905 00906 PT(PandaNode) child_node = get_child(child_index); 00907 int sort = get_child_sort(child_index); 00908 00909 remove_child(child_index); 00910 00911 { 00912 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 00913 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread); 00914 00915 cdata->modify_stashed()->insert(DownConnection(child_node, sort)); 00916 cdata_child->modify_up()->insert(UpConnection(this)); 00917 } 00918 00919 new_connection(this, child_node, pipeline_stage, current_thread); 00920 force_bounds_stale(pipeline_stage, current_thread); 00921 00922 children_changed(); 00923 child_node->parents_changed(); 00924 mark_bam_modified(); 00925 child_node->mark_bam_modified(); 00926 } 00927 00928 //////////////////////////////////////////////////////////////////// 00929 // Function: PandaNode::unstash_child 00930 // Access: Published 00931 // Description: Returns the indicated stashed node to normal child 00932 // status. This removes the child from the list of 00933 // stashed children and puts it on the normal list of 00934 // active children. This child node once again 00935 // contributes to the bounding volume of the PandaNode, 00936 // and will be visited in normal traversals. It is 00937 // visible and collidable. 00938 // 00939 // This can only be called from the top pipeline stage 00940 // (i.e. from App). 00941 //////////////////////////////////////////////////////////////////// 00942 void PandaNode:: 00943 unstash_child(int stashed_index, Thread *current_thread) { 00944 int pipeline_stage = current_thread->get_pipeline_stage(); 00945 nassertv(pipeline_stage == 0); 00946 nassertv(stashed_index >= 0 && stashed_index < get_num_stashed()); 00947 00948 // Save a reference count for ourselves. I don't think this should 00949 // be necessary, but there are occasional crashes in stash() during 00950 // furniture moving mode. Perhaps this will eliminate those 00951 // crashes. 00952 PT(PandaNode) self = this; 00953 00954 PT(PandaNode) child_node = get_stashed(stashed_index); 00955 int sort = get_stashed_sort(stashed_index); 00956 00957 remove_stashed(stashed_index); 00958 00959 { 00960 CDWriter cdata(_cycler); 00961 CDWriter cdata_child(child_node->_cycler); 00962 00963 cdata->modify_down()->insert(DownConnection(child_node, sort)); 00964 cdata_child->modify_up()->insert(UpConnection(this)); 00965 } 00966 00967 new_connection(this, child_node, pipeline_stage, current_thread); 00968 00969 force_bounds_stale(); 00970 children_changed(); 00971 child_node->parents_changed(); 00972 mark_bam_modified(); 00973 child_node->mark_bam_modified(); 00974 } 00975 00976 //////////////////////////////////////////////////////////////////// 00977 // Function: PandaNode::add_stashed 00978 // Access: Published 00979 // Description: Adds a new child to the node, directly as a stashed 00980 // child. The child is not added in the normal sense, 00981 // but will be revealed if unstash_child() is called on 00982 // it later. 00983 // 00984 // If the same child is added to a node more than once, 00985 // the previous instance is first removed. 00986 // 00987 // This can only be called from the top pipeline stage 00988 // (i.e. from App). 00989 //////////////////////////////////////////////////////////////////// 00990 void PandaNode:: 00991 add_stashed(PandaNode *child_node, int sort, Thread *current_thread) { 00992 int pipeline_stage = current_thread->get_pipeline_stage(); 00993 nassertv(pipeline_stage == 0); 00994 00995 if (!verify_child_no_cycles(child_node)) { 00996 // Whoops, adding this child node would introduce a cycle in the 00997 // scene graph. 00998 return; 00999 } 01000 01001 // Ensure the child_node is not deleted while we do this. 01002 PT(PandaNode) keep_child = child_node; 01003 remove_child(child_node); 01004 01005 { 01006 CDWriter cdata(_cycler); 01007 CDWriter cdata_child(child_node->_cycler); 01008 01009 cdata->modify_stashed()->insert(DownConnection(child_node, sort)); 01010 cdata_child->modify_up()->insert(UpConnection(this)); 01011 } 01012 01013 new_connection(this, child_node, pipeline_stage, current_thread); 01014 01015 // Call callback hooks. 01016 children_changed(); 01017 child_node->parents_changed(); 01018 mark_bam_modified(); 01019 child_node->mark_bam_modified(); 01020 } 01021 01022 //////////////////////////////////////////////////////////////////// 01023 // Function: PandaNode::remove_stashed 01024 // Access: Published 01025 // Description: Removes the nth stashed child from the node. 01026 //////////////////////////////////////////////////////////////////// 01027 void PandaNode:: 01028 remove_stashed(int child_index, Thread *current_thread) { 01029 int pipeline_stage = current_thread->get_pipeline_stage(); 01030 nassertv(pipeline_stage == 0); 01031 01032 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01033 Down &stashed = *cdata->modify_stashed(); 01034 nassertv(child_index >= 0 && child_index < (int)stashed.size()); 01035 01036 PT(PandaNode) child_node = stashed[child_index].get_child(); 01037 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread); 01038 01039 stashed.erase(stashed.begin() + child_index); 01040 int num_erased = cdata_child->modify_up()->erase(UpConnection(this)); 01041 nassertv(num_erased == 1); 01042 01043 sever_connection(this, child_node, pipeline_stage, current_thread); 01044 force_bounds_stale(pipeline_stage, current_thread); 01045 01046 children_changed(); 01047 child_node->parents_changed(); 01048 mark_bam_modified(); 01049 child_node->mark_bam_modified(); 01050 } 01051 01052 //////////////////////////////////////////////////////////////////// 01053 // Function: PandaNode::remove_all_children 01054 // Access: Published 01055 // Description: Removes all the children from the node at once, 01056 // including stashed children. 01057 // 01058 // This can only be called from the top pipeline stage 01059 // (i.e. from App). 01060 //////////////////////////////////////////////////////////////////// 01061 void PandaNode:: 01062 remove_all_children(Thread *current_thread) { 01063 // We have to do this for each upstream pipeline stage. 01064 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01065 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01066 PT(Down) down = cdata->modify_down(); 01067 Down::iterator di; 01068 for (di = down->begin(); di != down->end(); ++di) { 01069 PT(PandaNode) child_node = (*di).get_child(); 01070 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, 01071 current_thread); 01072 cdata_child->modify_up()->erase(UpConnection(this)); 01073 01074 sever_connection(this, child_node, pipeline_stage, current_thread); 01075 child_node->parents_changed(); 01076 child_node->mark_bam_modified(); 01077 } 01078 down->clear(); 01079 01080 Down &stashed = *cdata->modify_stashed(); 01081 for (di = stashed.begin(); di != stashed.end(); ++di) { 01082 PT(PandaNode) child_node = (*di).get_child(); 01083 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, 01084 current_thread); 01085 cdata_child->modify_up()->erase(UpConnection(this)); 01086 01087 sever_connection(this, child_node, pipeline_stage, current_thread); 01088 child_node->parents_changed(); 01089 child_node->mark_bam_modified(); 01090 } 01091 stashed.clear(); 01092 } 01093 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01094 01095 force_bounds_stale(); 01096 children_changed(); 01097 mark_bam_modified(); 01098 } 01099 01100 //////////////////////////////////////////////////////////////////// 01101 // Function: PandaNode::steal_children 01102 // Access: Published 01103 // Description: Moves all the children from the other node onto this 01104 // node. 01105 // 01106 // Any NodePaths to child nodes of the other node are 01107 // truncated, rather than moved to the new parent. 01108 //////////////////////////////////////////////////////////////////// 01109 void PandaNode:: 01110 steal_children(PandaNode *other, Thread *current_thread) { 01111 if (other == this) { 01112 // Trivial. 01113 return; 01114 } 01115 01116 // We do this through the high-level interface for convenience. 01117 // This could begin to be a problem if we have a node with hundreds 01118 // of children to copy; this could break down the ov_set.insert() 01119 // method, which is an O(n^2) operation. If this happens, we should 01120 // rewrite this to do a simpler add_child() operation that involves 01121 // push_back() instead of insert(), and then sort the down list at 01122 // the end. 01123 01124 int num_children = other->get_num_children(); 01125 int i; 01126 for (i = 0; i < num_children; i++) { 01127 PandaNode *child_node = other->get_child(i); 01128 int sort = other->get_child_sort(i); 01129 add_child(child_node, sort, current_thread); 01130 } 01131 int num_stashed = other->get_num_stashed(); 01132 for (i = 0; i < num_stashed; i++) { 01133 PandaNode *child_node = other->get_stashed(i); 01134 int sort = other->get_stashed_sort(i); 01135 add_stashed(child_node, sort, current_thread); 01136 } 01137 01138 other->remove_all_children(current_thread); 01139 } 01140 01141 //////////////////////////////////////////////////////////////////// 01142 // Function: PandaNode::copy_children 01143 // Access: Published 01144 // Description: Makes another instance of all the children of the 01145 // other node, copying them to this node. 01146 //////////////////////////////////////////////////////////////////// 01147 void PandaNode:: 01148 copy_children(PandaNode *other, Thread *current_thread) { 01149 if (other == this) { 01150 // Trivial. 01151 return; 01152 } 01153 Children children = other->get_children(current_thread); 01154 Stashed stashed = other->get_stashed(current_thread); 01155 int num_children = children.get_num_children(); 01156 int i; 01157 for (i = 0; i < num_children; i++) { 01158 PandaNode *child_node = children.get_child(i); 01159 int sort = children.get_child_sort(i); 01160 add_child(child_node, sort, current_thread); 01161 } 01162 int num_stashed = stashed.get_num_stashed(); 01163 for (i = 0; i < num_stashed; i++) { 01164 PandaNode *child_node = stashed.get_stashed(i); 01165 int sort = stashed.get_stashed_sort(i); 01166 add_stashed(child_node, sort, current_thread); 01167 } 01168 } 01169 01170 //////////////////////////////////////////////////////////////////// 01171 // Function: PandaNode::set_attrib 01172 // Access: Published 01173 // Description: Adds the indicated render attribute to the scene 01174 // graph on this node. This attribute will now apply to 01175 // this node and everything below. If there was already 01176 // an attribute of the same type, it is replaced. 01177 //////////////////////////////////////////////////////////////////// 01178 void PandaNode:: 01179 set_attrib(const RenderAttrib *attrib, int override) { 01180 // Apply this operation to the current stage as well as to all 01181 // upstream stages. 01182 bool any_changed = false; 01183 Thread *current_thread = Thread::get_current_thread(); 01184 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01185 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01186 01187 CPT(RenderState) new_state = cdata->_state->set_attrib(attrib, override); 01188 if (cdata->_state != new_state) { 01189 cdata->_state = new_state; 01190 cdata->set_fancy_bit(FB_state, true); 01191 any_changed = true; 01192 } 01193 } 01194 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01195 01196 // Maybe we changed a ClipPlaneAttrib. 01197 if (any_changed) { 01198 mark_bounds_stale(current_thread); 01199 state_changed(); 01200 mark_bam_modified(); 01201 } 01202 } 01203 01204 //////////////////////////////////////////////////////////////////// 01205 // Function: PandaNode::clear_attrib 01206 // Access: Published 01207 // Description: Removes the render attribute of the given type from 01208 // this node. This node, and the subgraph below, will 01209 // now inherit the indicated render attribute from the 01210 // nodes above this one. 01211 //////////////////////////////////////////////////////////////////// 01212 void PandaNode:: 01213 clear_attrib(int slot) { 01214 bool any_changed = false; 01215 01216 Thread *current_thread = Thread::get_current_thread(); 01217 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01218 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01219 01220 CPT(RenderState) new_state = cdata->_state->remove_attrib(slot); 01221 if (cdata->_state != new_state) { 01222 cdata->_state = new_state; 01223 cdata->set_fancy_bit(FB_state, !new_state->is_empty()); 01224 any_changed = true; 01225 } 01226 } 01227 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01228 01229 // We mark the bounds stale when the state changes, in case 01230 // we have changed a ClipPlaneAttrib. 01231 if (any_changed) { 01232 mark_bounds_stale(current_thread); 01233 state_changed(); 01234 mark_bam_modified(); 01235 } 01236 } 01237 01238 //////////////////////////////////////////////////////////////////// 01239 // Function: PandaNode::set_effect 01240 // Access: Published 01241 // Description: Adds the indicated render effect to the scene 01242 // graph on this node. If there was already an effect 01243 // of the same type, it is replaced. 01244 //////////////////////////////////////////////////////////////////// 01245 void PandaNode:: 01246 set_effect(const RenderEffect *effect) { 01247 // Apply this operation to the current stage as well as to all 01248 // upstream stages. 01249 Thread *current_thread = Thread::get_current_thread(); 01250 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01251 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01252 cdata->_effects = cdata->_effects->add_effect(effect); 01253 cdata->set_fancy_bit(FB_effects, true); 01254 } 01255 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01256 mark_bam_modified(); 01257 } 01258 01259 //////////////////////////////////////////////////////////////////// 01260 // Function: PandaNode::clear_effect 01261 // Access: Published 01262 // Description: Removes the render effect of the given type from 01263 // this node. 01264 //////////////////////////////////////////////////////////////////// 01265 void PandaNode:: 01266 clear_effect(TypeHandle type) { 01267 Thread *current_thread = Thread::get_current_thread(); 01268 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01269 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01270 cdata->_effects = cdata->_effects->remove_effect(type); 01271 cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty()); 01272 } 01273 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01274 mark_bam_modified(); 01275 } 01276 01277 //////////////////////////////////////////////////////////////////// 01278 // Function: PandaNode::set_state 01279 // Access: Published 01280 // Description: Sets the complete RenderState that will be applied to 01281 // all nodes at this level and below. (The actual state 01282 // that will be applied to lower nodes is based on the 01283 // composition of RenderStates from above this node as 01284 // well). This completely replaces whatever has been 01285 // set on this node via repeated calls to set_attrib(). 01286 //////////////////////////////////////////////////////////////////// 01287 void PandaNode:: 01288 set_state(const RenderState *state, Thread *current_thread) { 01289 // Apply this operation to the current stage as well as to all 01290 // upstream stages. 01291 bool any_changed = false; 01292 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01293 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01294 if (cdata->_state != state) { 01295 cdata->_state = state; 01296 cdata->set_fancy_bit(FB_state, !state->is_empty()); 01297 any_changed = true; 01298 } 01299 } 01300 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01301 01302 // Maybe we have changed a ClipPlaneAttrib. 01303 if (any_changed) { 01304 mark_bounds_stale(current_thread); 01305 state_changed(); 01306 mark_bam_modified(); 01307 } 01308 } 01309 01310 //////////////////////////////////////////////////////////////////// 01311 // Function: PandaNode::set_effects 01312 // Access: Published 01313 // Description: Sets the complete RenderEffects that will be applied 01314 // this node. This completely replaces whatever has 01315 // been set on this node via repeated calls to 01316 // set_attrib(). 01317 //////////////////////////////////////////////////////////////////// 01318 void PandaNode:: 01319 set_effects(const RenderEffects *effects, Thread *current_thread) { 01320 // Apply this operation to the current stage as well as to all 01321 // upstream stages. 01322 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01323 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01324 cdata->_effects = effects; 01325 cdata->set_fancy_bit(FB_effects, !effects->is_empty()); 01326 } 01327 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01328 mark_bam_modified(); 01329 } 01330 01331 //////////////////////////////////////////////////////////////////// 01332 // Function: PandaNode::set_transform 01333 // Access: Published 01334 // Description: Sets the transform that will be applied to this node 01335 // and below. This defines a new coordinate space at 01336 // this point in the scene graph and below. 01337 //////////////////////////////////////////////////////////////////// 01338 void PandaNode:: 01339 set_transform(const TransformState *transform, Thread *current_thread) { 01340 // Apply this operation to the current stage as well as to all 01341 // upstream stages. 01342 bool any_changed = false; 01343 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01344 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01345 if (cdata->_transform != transform) { 01346 cdata->_transform = transform; 01347 cdata->set_fancy_bit(FB_transform, !transform->is_identity()); 01348 any_changed = true; 01349 01350 if (pipeline_stage == 0) { 01351 if (cdata->_transform != cdata->_prev_transform) { 01352 set_dirty_prev_transform(); 01353 } 01354 } 01355 } 01356 } 01357 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01358 01359 if (any_changed) { 01360 mark_bounds_stale(current_thread); 01361 transform_changed(); 01362 mark_bam_modified(); 01363 } 01364 } 01365 01366 //////////////////////////////////////////////////////////////////// 01367 // Function: PandaNode::set_prev_transform 01368 // Access: Published 01369 // Description: Sets the transform that represents this node's 01370 // "previous" position, one frame ago, for the purposes 01371 // of detecting motion for accurate collision 01372 // calculations. 01373 //////////////////////////////////////////////////////////////////// 01374 void PandaNode:: 01375 set_prev_transform(const TransformState *transform, Thread *current_thread) { 01376 // Apply this operation to the current stage as well as to all 01377 // upstream stages. 01378 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01379 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01380 cdata->_prev_transform = transform; 01381 if (pipeline_stage == 0) { 01382 if (cdata->_transform != cdata->_prev_transform) { 01383 set_dirty_prev_transform(); 01384 } else { 01385 clear_dirty_prev_transform(); 01386 } 01387 } 01388 } 01389 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01390 mark_bam_modified(); 01391 } 01392 01393 //////////////////////////////////////////////////////////////////// 01394 // Function: PandaNode::reset_prev_transform 01395 // Access: Published 01396 // Description: Resets the transform that represents this node's 01397 // "previous" position to the same as the current 01398 // transform. This is not the same thing as clearing it 01399 // to identity. 01400 //////////////////////////////////////////////////////////////////// 01401 void PandaNode:: 01402 reset_prev_transform(Thread *current_thread) { 01403 // Apply this operation to the current stage as well as to all 01404 // upstream stages. 01405 clear_dirty_prev_transform(); 01406 01407 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01408 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01409 cdata->_prev_transform = cdata->_transform; 01410 } 01411 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01412 mark_bam_modified(); 01413 } 01414 01415 //////////////////////////////////////////////////////////////////// 01416 // Function: PandaNode::reset_all_prev_transform 01417 // Access: Published, Static 01418 // Description: Visits all nodes in the world with the 01419 // _dirty_prev_transform flag--that is, all nodes whose 01420 // _prev_transform is different from the _transform in 01421 // pipeline stage 0--and resets the _prev_transform to 01422 // be the same as _transform. 01423 //////////////////////////////////////////////////////////////////// 01424 void PandaNode:: 01425 reset_all_prev_transform(Thread *current_thread) { 01426 nassertv(current_thread->get_pipeline_stage() == 0); 01427 01428 PStatTimer timer(_reset_prev_pcollector, current_thread); 01429 LightMutexHolder holder(_dirty_prev_transforms._lock); 01430 01431 LinkedListNode *list_node = _dirty_prev_transforms._next; 01432 while (list_node != &_dirty_prev_transforms) { 01433 PandaNode *panda_node = (PandaNode *)list_node; 01434 nassertv(panda_node->_dirty_prev_transform); 01435 panda_node->_dirty_prev_transform = false; 01436 01437 CDStageWriter cdata(panda_node->_cycler, 0, current_thread); 01438 cdata->_prev_transform = cdata->_transform; 01439 01440 list_node = panda_node->_next; 01441 #ifndef NDEBUG 01442 panda_node->_prev = NULL; 01443 panda_node->_next = NULL; 01444 #endif // NDEBUG 01445 panda_node->mark_bam_modified(); 01446 } 01447 01448 _dirty_prev_transforms._prev = &_dirty_prev_transforms; 01449 _dirty_prev_transforms._next = &_dirty_prev_transforms; 01450 } 01451 01452 //////////////////////////////////////////////////////////////////// 01453 // Function: PandaNode::set_tag 01454 // Access: Published 01455 // Description: Associates a user-defined value with a user-defined 01456 // key which is stored on the node. This value has no 01457 // meaning to Panda; but it is stored indefinitely on 01458 // the node until it is requested again. 01459 // 01460 // Each unique key stores a different string value. 01461 // There is no effective limit on the number of 01462 // different keys that may be stored or on the length of 01463 // any one key's value. 01464 //////////////////////////////////////////////////////////////////// 01465 void PandaNode:: 01466 set_tag(const string &key, const string &value, Thread *current_thread) { 01467 // Apply this operation to the current stage as well as to all 01468 // upstream stages. 01469 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01470 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01471 cdata->_tag_data[key] = value; 01472 cdata->set_fancy_bit(FB_tag, true); 01473 } 01474 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01475 mark_bam_modified(); 01476 } 01477 01478 //////////////////////////////////////////////////////////////////// 01479 // Function: PandaNode::clear_tag 01480 // Access: Published 01481 // Description: Removes the value defined for this key on this 01482 // particular node. After a call to clear_tag(), 01483 // has_tag() will return false for the indicated key. 01484 //////////////////////////////////////////////////////////////////// 01485 void PandaNode:: 01486 clear_tag(const string &key, Thread *current_thread) { 01487 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01488 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 01489 cdata->_tag_data.erase(key); 01490 cdata->set_fancy_bit(FB_tag, !cdata->_tag_data.empty()); 01491 } 01492 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01493 mark_bam_modified(); 01494 } 01495 01496 #ifdef HAVE_PYTHON 01497 //////////////////////////////////////////////////////////////////// 01498 // Function: PandaNode::set_python_tag 01499 // Access: Published 01500 // Description: Associates an arbitrary Python object with a 01501 // user-defined key which is stored on the node. This 01502 // is similar to set_tag(), except it can store any 01503 // Python object instead of just a string. However, the 01504 // Python object is not recorded to a bam file. 01505 // 01506 // Each unique key stores a different string value. 01507 // There is no effective limit on the number of 01508 // different keys that may be stored or on the length of 01509 // any one key's value. 01510 //////////////////////////////////////////////////////////////////// 01511 void PandaNode:: 01512 set_python_tag(const string &key, PyObject *value) { 01513 Thread *current_thread = Thread::get_current_thread(); 01514 int pipeline_stage = current_thread->get_pipeline_stage(); 01515 nassertv(pipeline_stage == 0); 01516 01517 CDWriter cdata(_cycler); 01518 Py_XINCREF(value); 01519 01520 pair<PythonTagData::iterator, bool> result; 01521 result = cdata->_python_tag_data.insert(PythonTagData::value_type(key, value)); 01522 01523 if (!result.second) { 01524 // The insert was unsuccessful; that means the key was already 01525 // present in the map. In this case, we should decrement the 01526 // original value's reference count and replace it with the new 01527 // object. 01528 PythonTagData::iterator ti = result.first; 01529 PyObject *old_value = (*ti).second; 01530 Py_XDECREF(old_value); 01531 (*ti).second = value; 01532 } 01533 01534 // Even though the python tag isn't recorded in the bam stream? 01535 mark_bam_modified(); 01536 } 01537 #endif // HAVE_PYTHON 01538 01539 #ifdef HAVE_PYTHON 01540 //////////////////////////////////////////////////////////////////// 01541 // Function: PandaNode::get_python_tag 01542 // Access: Published 01543 // Description: Retrieves the Python object that was previously 01544 // set on this node for the particular key, if any. If 01545 // no value has been previously set, returns None. 01546 //////////////////////////////////////////////////////////////////// 01547 PyObject *PandaNode:: 01548 get_python_tag(const string &key) const { 01549 CDReader cdata(_cycler); 01550 PythonTagData::const_iterator ti; 01551 ti = cdata->_python_tag_data.find(key); 01552 if (ti != cdata->_python_tag_data.end()) { 01553 PyObject *result = (*ti).second; 01554 Py_XINCREF(result); 01555 return result; 01556 } 01557 Py_INCREF(Py_None); 01558 return Py_None; 01559 } 01560 #endif // HAVE_PYTHON 01561 01562 #ifdef HAVE_PYTHON 01563 //////////////////////////////////////////////////////////////////// 01564 // Function: PandaNode::has_python_tag 01565 // Access: Published 01566 // Description: Returns true if a Python object has been defined on 01567 // this node for the particular key (even if that object 01568 // is None), or false if no object has been set. 01569 //////////////////////////////////////////////////////////////////// 01570 bool PandaNode:: 01571 has_python_tag(const string &key) const { 01572 CDReader cdata(_cycler); 01573 PythonTagData::const_iterator ti; 01574 ti = cdata->_python_tag_data.find(key); 01575 return (ti != cdata->_python_tag_data.end()); 01576 } 01577 #endif // HAVE_PYTHON 01578 01579 #ifdef HAVE_PYTHON 01580 //////////////////////////////////////////////////////////////////// 01581 // Function: PandaNode::clear_python_tag 01582 // Access: Published 01583 // Description: Removes the Python object defined for this key on 01584 // this particular node. After a call to 01585 // clear_python_tag(), has_python_tag() will return 01586 // false for the indicated key. 01587 //////////////////////////////////////////////////////////////////// 01588 void PandaNode:: 01589 clear_python_tag(const string &key) { 01590 Thread *current_thread = Thread::get_current_thread(); 01591 int pipeline_stage = current_thread->get_pipeline_stage(); 01592 nassertv(pipeline_stage == 0); 01593 01594 CDWriter cdata(_cycler, current_thread); 01595 PythonTagData::iterator ti; 01596 ti = cdata->_python_tag_data.find(key); 01597 if (ti != cdata->_python_tag_data.end()) { 01598 PyObject *value = (*ti).second; 01599 Py_XDECREF(value); 01600 cdata->_python_tag_data.erase(ti); 01601 } 01602 01603 // Even though the python tag isn't recorded in the bam stream? 01604 mark_bam_modified(); 01605 } 01606 #endif // HAVE_PYTHON 01607 01608 //////////////////////////////////////////////////////////////////// 01609 // Function: PandaNode::copy_tags 01610 // Access: Published 01611 // Description: Copies all of the tags stored on the other node onto 01612 // this node. If a particular tag exists on both nodes, 01613 // the contents of this node's value is replaced by that 01614 // of the other. 01615 //////////////////////////////////////////////////////////////////// 01616 void PandaNode:: 01617 copy_tags(PandaNode *other) { 01618 if (other == this) { 01619 // Trivial. 01620 return; 01621 } 01622 01623 // Apply this operation to the current stage as well as to all 01624 // upstream stages. 01625 Thread *current_thread = Thread::get_current_thread(); 01626 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01627 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread); 01628 CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread); 01629 01630 TagData::const_iterator ti; 01631 for (ti = cdatar->_tag_data.begin(); 01632 ti != cdatar->_tag_data.end(); 01633 ++ti) { 01634 cdataw->_tag_data[(*ti).first] = (*ti).second; 01635 } 01636 cdataw->set_fancy_bit(FB_tag, !cdataw->_tag_data.empty()); 01637 01638 #ifdef HAVE_PYTHON 01639 PythonTagData::const_iterator pti; 01640 for (pti = cdatar->_python_tag_data.begin(); 01641 pti != cdatar->_python_tag_data.end(); 01642 ++pti) { 01643 const string &key = (*pti).first; 01644 PyObject *value = (*pti).second; 01645 Py_XINCREF(value); 01646 01647 pair<PythonTagData::iterator, bool> result; 01648 result = cdataw->_python_tag_data.insert(PythonTagData::value_type(key, value)); 01649 01650 if (!result.second) { 01651 // The insert was unsuccessful; that means the key was already 01652 // present in the map. In this case, we should decrement the 01653 // original value's reference count and replace it with the new 01654 // object. 01655 PythonTagData::iterator wpti = result.first; 01656 PyObject *old_value = (*wpti).second; 01657 Py_XDECREF(old_value); 01658 (*wpti).second = value; 01659 } 01660 } 01661 #endif // HAVE_PYTHON 01662 } 01663 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01664 mark_bam_modified(); 01665 } 01666 01667 //////////////////////////////////////////////////////////////////// 01668 // Function: PandaNode::list_tags 01669 // Access: Published 01670 // Description: Writes a list of all the tag keys assigned to the 01671 // node to the indicated stream. Writes one instance of 01672 // the separator following each key (but does not write 01673 // a terminal separator). The value associated with 01674 // each key is not written. 01675 // 01676 // This is mainly for the benefit of the realtime user, 01677 // to see the list of all of the associated tag keys. 01678 //////////////////////////////////////////////////////////////////// 01679 void PandaNode:: 01680 list_tags(ostream &out, const string &separator) const { 01681 CDReader cdata(_cycler); 01682 if (!cdata->_tag_data.empty()) { 01683 TagData::const_iterator ti = cdata->_tag_data.begin(); 01684 out << (*ti).first; 01685 ++ti; 01686 while (ti != cdata->_tag_data.end()) { 01687 out << separator << (*ti).first; 01688 ++ti; 01689 } 01690 } 01691 01692 #ifdef HAVE_PYTHON 01693 if (!cdata->_python_tag_data.empty()) { 01694 if (!cdata->_tag_data.empty()) { 01695 out << separator; 01696 } 01697 PythonTagData::const_iterator ti = cdata->_python_tag_data.begin(); 01698 out << (*ti).first; 01699 ++ti; 01700 while (ti != cdata->_python_tag_data.end()) { 01701 out << separator << (*ti).first; 01702 ++ti; 01703 } 01704 } 01705 #endif // HAVE_PYTHON 01706 } 01707 01708 //////////////////////////////////////////////////////////////////// 01709 // Function: PandaNode::compare_tags 01710 // Access: Published 01711 // Description: Returns a number less than 0, 0, or greater than 0, 01712 // to indicate the similarity of tags between this node 01713 // and the other one. If this returns 0, the tags are 01714 // identical. If it returns other than 0, then the tags 01715 // are different; and the nodes may be sorted into a 01716 // consistent (but arbitrary) ordering based on this 01717 // number. 01718 //////////////////////////////////////////////////////////////////// 01719 int PandaNode:: 01720 compare_tags(const PandaNode *other) const { 01721 CDReader cdata(_cycler); 01722 CDReader cdata_other(other->_cycler); 01723 01724 TagData::const_iterator ati = cdata->_tag_data.begin(); 01725 TagData::const_iterator bti = cdata_other->_tag_data.begin(); 01726 while (ati != cdata->_tag_data.end() && 01727 bti != cdata_other->_tag_data.end()) { 01728 int cmp = strcmp((*ati).first.c_str(), (*bti).first.c_str()); 01729 if (cmp != 0) { 01730 return cmp; 01731 } 01732 01733 cmp = strcmp((*ati).second.c_str(), (*bti).second.c_str()); 01734 if (cmp != 0) { 01735 return cmp; 01736 } 01737 01738 ++ati; 01739 ++bti; 01740 } 01741 if (ati != cdata->_tag_data.end()) { 01742 // list A is longer. 01743 return 1; 01744 } 01745 if (bti != cdata_other->_tag_data.end()) { 01746 // list B is longer. 01747 return -1; 01748 } 01749 01750 #ifdef HAVE_PYTHON 01751 PythonTagData::const_iterator api = cdata->_python_tag_data.begin(); 01752 PythonTagData::const_iterator bpi = cdata_other->_python_tag_data.begin(); 01753 while (api != cdata->_python_tag_data.end() && 01754 bpi != cdata_other->_python_tag_data.end()) { 01755 int cmp = strcmp((*api).first.c_str(), (*bpi).first.c_str()); 01756 if (cmp != 0) { 01757 return cmp; 01758 } 01759 01760 if (PyObject_Cmp((*api).second, (*bpi).second, &cmp) == -1) { 01761 // Unable to compare objects; just compare pointers. 01762 if ((*api).second != (*bpi).second) { 01763 cmp = (*api).second < (*bpi).second ? -1 : 1; 01764 } else { 01765 cmp = 0; 01766 } 01767 } 01768 if (cmp != 0) { 01769 return cmp; 01770 } 01771 01772 ++api; 01773 ++bpi; 01774 } 01775 if (api != cdata->_python_tag_data.end()) { 01776 // list A is longer. 01777 return 1; 01778 } 01779 if (bpi != cdata_other->_python_tag_data.end()) { 01780 // list B is longer. 01781 return -1; 01782 } 01783 #endif // HAVE_PYTHON 01784 01785 return 0; 01786 } 01787 01788 //////////////////////////////////////////////////////////////////// 01789 // Function: PandaNode::copy_all_properties 01790 // Access: Published 01791 // Description: Copies the TransformState, RenderState, 01792 // RenderEffects, tags, Python tags, and the show/hide 01793 // state from the other node onto this one. Typically 01794 // this is used to prepare a node to replace another 01795 // node in the scene graph (also see replace_node()). 01796 //////////////////////////////////////////////////////////////////// 01797 void PandaNode:: 01798 copy_all_properties(PandaNode *other) { 01799 if (other == this) { 01800 // Trivial. 01801 return; 01802 } 01803 01804 bool any_transform_changed = false; 01805 bool any_state_changed = false; 01806 bool any_draw_mask_changed = false; 01807 Thread *current_thread = Thread::get_current_thread(); 01808 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 01809 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread); 01810 CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread); 01811 01812 if (cdataw->_transform != cdatar->_transform) { 01813 any_transform_changed = true; 01814 } 01815 if (cdataw->_state != cdatar->_state) { 01816 any_state_changed = true; 01817 } 01818 if (cdataw->_draw_control_mask != cdatar->_draw_control_mask || 01819 cdataw->_draw_show_mask != cdatar->_draw_show_mask) { 01820 any_draw_mask_changed = true; 01821 } 01822 01823 cdataw->_transform = cdatar->_transform; 01824 cdataw->_prev_transform = cdatar->_prev_transform; 01825 cdataw->_state = cdatar->_state; 01826 cdataw->_effects = cdatar->_effects; 01827 cdataw->_draw_control_mask = cdatar->_draw_control_mask; 01828 cdataw->_draw_show_mask = cdatar->_draw_show_mask; 01829 01830 // The collide mask becomes the union of the two masks. This is 01831 // important to preserve properties such as the default GeomNode 01832 // bitmask. 01833 cdataw->_into_collide_mask |= cdatar->_into_collide_mask; 01834 01835 TagData::const_iterator ti; 01836 for (ti = cdatar->_tag_data.begin(); 01837 ti != cdatar->_tag_data.end(); 01838 ++ti) { 01839 cdataw->_tag_data[(*ti).first] = (*ti).second; 01840 } 01841 01842 #ifdef HAVE_PYTHON 01843 PythonTagData::const_iterator pti; 01844 for (pti = cdatar->_python_tag_data.begin(); 01845 pti != cdatar->_python_tag_data.end(); 01846 ++pti) { 01847 const string &key = (*pti).first; 01848 PyObject *value = (*pti).second; 01849 Py_XINCREF(value); 01850 01851 pair<PythonTagData::iterator, bool> result; 01852 result = cdataw->_python_tag_data.insert(PythonTagData::value_type(key, value)); 01853 01854 if (!result.second) { 01855 // The insert was unsuccessful; that means the key was already 01856 // present in the map. In this case, we should decrement the 01857 // original value's reference count and replace it with the new 01858 // object. 01859 PythonTagData::iterator wpti = result.first; 01860 PyObject *old_value = (*wpti).second; 01861 Py_XDECREF(old_value); 01862 (*wpti).second = value; 01863 } 01864 } 01865 #endif // HAVE_PYTHON 01866 01867 static const int change_bits = (FB_transform | FB_state | FB_effects | 01868 FB_tag | FB_draw_mask); 01869 cdataw->_fancy_bits = 01870 (cdataw->_fancy_bits & ~change_bits) | 01871 (cdatar->_fancy_bits & change_bits); 01872 01873 if (pipeline_stage == 0) { 01874 if (cdataw->_transform != cdataw->_prev_transform) { 01875 set_dirty_prev_transform(); 01876 } 01877 } 01878 } 01879 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 01880 01881 if (any_transform_changed || any_state_changed || any_draw_mask_changed) { 01882 mark_bounds_stale(current_thread); 01883 01884 if (any_transform_changed) { 01885 transform_changed(); 01886 } 01887 if (any_state_changed) { 01888 state_changed(); 01889 } 01890 if (any_draw_mask_changed) { 01891 draw_mask_changed(); 01892 } 01893 mark_bam_modified(); 01894 } 01895 } 01896 01897 //////////////////////////////////////////////////////////////////// 01898 // Function: PandaNode::replace_node 01899 // Access: Published 01900 // Description: Inserts this node into the scene graph in place of 01901 // the other one, and removes the other node. All scene 01902 // graph attributes (TransformState, RenderState, etc.) 01903 // are copied to this node. 01904 // 01905 // All children are moved to this node, and removed from 01906 // the old node. The new node is left in the same place 01907 // in the old node's parent's list of children. 01908 // 01909 // Even NodePaths that reference the old node are 01910 // updated in-place to reference the new node instead. 01911 // 01912 // This method is intended to be used to replace a node 01913 // of a given type in the scene graph with a node of a 01914 // different type. 01915 //////////////////////////////////////////////////////////////////// 01916 void PandaNode:: 01917 replace_node(PandaNode *other) { 01918 // nassertv(Thread::get_current_pipeline_stage() == 0); 01919 01920 if (other == this) { 01921 // Trivial. 01922 return; 01923 } 01924 01925 // Make sure the other node is not destructed during the 01926 // execution of this method. 01927 PT(PandaNode) keep_other = other; 01928 01929 // Get all the important scene graph properties. 01930 copy_all_properties(other); 01931 01932 // Fix up the NodePaths. 01933 { 01934 LightReMutexHolder holder1(other->_paths_lock); 01935 LightReMutexHolder holder2(_paths_lock); 01936 Paths::iterator pi; 01937 for (pi = other->_paths.begin(); pi != other->_paths.end(); ++pi) { 01938 (*pi)->_node = this; 01939 _paths.insert(*pi); 01940 } 01941 other->_paths.clear(); 01942 } 01943 01944 // Get the children. 01945 steal_children(other); 01946 01947 // Switch the parents. 01948 Thread *current_thread = Thread::get_current_thread(); 01949 Parents other_parents = other->get_parents(); 01950 for (int i = 0; i < other_parents.get_num_parents(); ++i) { 01951 PandaNode *parent = other_parents.get_parent(i); 01952 if (find_parent(parent) != -1) { 01953 // This node was already a child of this parent; don't change 01954 // it. 01955 parent->remove_child(other); 01956 } else { 01957 // This node was not yet a child of this parent; now it is. 01958 parent->replace_child(other, this, current_thread); 01959 } 01960 } 01961 } 01962 01963 //////////////////////////////////////////////////////////////////// 01964 // Function: PandaNode::set_unexpected_change 01965 // Access: Published 01966 // Description: Sets one or more of the PandaNode::UnexpectedChange 01967 // bits on, indicating that the corresponding property 01968 // should not change again on this node. Once one of 01969 // these bits has been set, if the property changes, an 01970 // assertion failure will be raised, which is designed 01971 // to assist the developer in identifying the 01972 // troublesome code that modified the property 01973 // unexpectedly. 01974 // 01975 // The input parameter is the union of bits that are to 01976 // be set. To clear these bits later, use 01977 // clear_unexpected_change(). 01978 // 01979 // Since this is a developer debugging tool only, this 01980 // function does nothing in a production (NDEBUG) build. 01981 //////////////////////////////////////////////////////////////////// 01982 void PandaNode:: 01983 set_unexpected_change(unsigned int flags) { 01984 #ifndef NDEBUG 01985 _unexpected_change_flags |= flags; 01986 #endif // !NDEBUG 01987 } 01988 01989 //////////////////////////////////////////////////////////////////// 01990 // Function: PandaNode::get_unexpected_change 01991 // Access: Published 01992 // Description: Returns nonzero if any of the bits in the input 01993 // parameter are set on this node, or zero if none of 01994 // them are set. More specifically, this returns the 01995 // particular set of bits (masked by the input 01996 // parameter) that have been set on this node. See 01997 // set_unexpected_change(). 01998 // 01999 // Since this is a developer debugging tool only, this 02000 // function always returns zero in a production (NDEBUG) 02001 // build. 02002 //////////////////////////////////////////////////////////////////// 02003 unsigned int PandaNode:: 02004 get_unexpected_change(unsigned int flags) const { 02005 #ifndef NDEBUG 02006 return _unexpected_change_flags & flags; 02007 #else 02008 return 0; 02009 #endif // !NDEBUG 02010 } 02011 02012 //////////////////////////////////////////////////////////////////// 02013 // Function: PandaNode::clear_unexpected_change 02014 // Access: Published 02015 // Description: Sets one or more of the PandaNode::UnexpectedChange 02016 // bits off, indicating that the corresponding property 02017 // may once again change on this node. See 02018 // set_unexpected_change(). 02019 // 02020 // The input parameter is the union of bits that are to 02021 // be cleared. 02022 // 02023 // Since this is a developer debugging tool only, this 02024 // function does nothing in a production (NDEBUG) build. 02025 //////////////////////////////////////////////////////////////////// 02026 void PandaNode:: 02027 clear_unexpected_change(unsigned int flags) { 02028 #ifndef NDEBUG 02029 _unexpected_change_flags &= ~flags; 02030 #endif // !NDEBUG 02031 } 02032 02033 //////////////////////////////////////////////////////////////////// 02034 // Function: PandaNode::adjust_draw_mask 02035 // Access: Published 02036 // Description: Adjusts the hide/show bits of this particular node. 02037 // 02038 // These three parameters can be used to adjust the 02039 // _draw_control_mask and _draw_show_mask independently, 02040 // which work together to provide per-camera visibility 02041 // for the node and its descendents. 02042 // 02043 // _draw_control_mask indicates the bits in 02044 // _draw_show_mask that are significant. Each different 02045 // bit corresponds to a different camera (and these bits 02046 // are assigned via Camera::set_camera_mask()). 02047 // 02048 // Where _draw_control_mask has a 1 bit, a 1 bit in 02049 // _draw_show_mask indicates the node is visible to that 02050 // camera, and a 0 bit indicates the node is hidden to 02051 // that camera. Where _draw_control_mask is 0, the node 02052 // is hidden only if a parent node is hidden. 02053 // 02054 // The meaning of the three parameters is as follows: 02055 // 02056 // * Wherever show_mask is 1, _draw_show_mask and 02057 // _draw_control_mask will be set 1. Thus, show_mask 02058 // indicates the set of cameras to which the node should 02059 // be shown. 02060 // 02061 // * Wherever hide_mask is 1, _draw_show_mask will be 02062 // set 0 and _draw_control_mask will be set 1. Thus, 02063 // hide_mask indicates the set of cameras from which the 02064 // node should be hidden. 02065 // 02066 // * Wherever clear_mask is 1, _draw_control_mask will 02067 // be set 0. Thus, clear_mask indicates the set of 02068 // cameras from which the hidden state should be 02069 // inherited from a parent. 02070 //////////////////////////////////////////////////////////////////// 02071 void PandaNode:: 02072 adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask) { 02073 bool any_changed = false; 02074 02075 Thread *current_thread = Thread::get_current_thread(); 02076 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 02077 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 02078 02079 DrawMask draw_control_mask = (cdata->_draw_control_mask | show_mask | hide_mask) & ~clear_mask; 02080 DrawMask draw_show_mask = (cdata->_draw_show_mask | show_mask) & ~hide_mask; 02081 // The uncontrolled bits are implicitly on. 02082 draw_show_mask |= ~draw_control_mask; 02083 02084 if (cdata->_draw_control_mask != draw_control_mask || 02085 cdata->_draw_show_mask != draw_show_mask) { 02086 cdata->_draw_control_mask = draw_control_mask; 02087 cdata->_draw_show_mask = draw_show_mask; 02088 any_changed = true; 02089 } 02090 cdata->set_fancy_bit(FB_draw_mask, !draw_control_mask.is_zero()); 02091 } 02092 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 02093 02094 if (any_changed) { 02095 mark_bounds_stale(current_thread); 02096 draw_mask_changed(); 02097 mark_bam_modified(); 02098 } 02099 } 02100 02101 //////////////////////////////////////////////////////////////////// 02102 // Function: PandaNode::get_net_draw_control_mask 02103 // Access: Published 02104 // Description: Returns the set of bits in get_net_draw_show_mask() 02105 // that have been explicitly set via adjust_draw_mask(), 02106 // rather than implicitly inherited. 02107 // 02108 // A 1 bit in any position of this mask indicates that 02109 // (a) this node has renderable children, and (b) some 02110 // child of this node has made an explicit hide() or 02111 // show_through() call for the corresponding bit. 02112 //////////////////////////////////////////////////////////////////// 02113 DrawMask PandaNode:: 02114 get_net_draw_control_mask() const { 02115 Thread *current_thread = Thread::get_current_thread(); 02116 int pipeline_stage = current_thread->get_pipeline_stage(); 02117 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); 02118 if (cdata->_last_update != cdata->_next_update) { 02119 // The cache is stale; it needs to be rebuilt. 02120 PStatTimer timer(_update_bounds_pcollector); 02121 CDStageWriter cdataw = 02122 ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 02123 return cdataw->_net_draw_control_mask; 02124 } 02125 return cdata->_net_draw_control_mask; 02126 } 02127 02128 //////////////////////////////////////////////////////////////////// 02129 // Function: PandaNode::get_net_draw_show_mask 02130 // Access: Published 02131 // Description: Returns the union of all draw_show_mask values--of 02132 // renderable nodes only--at this level and below. If 02133 // any bit in this mask is 0, there is no reason to 02134 // traverse below this node for a camera with the 02135 // corresponding camera_mask. 02136 // 02137 // The bits in this mask that do not correspond to a 1 02138 // bit in the net_draw_control_mask are meaningless (and 02139 // will be set to 1). For bits that *do* correspond to 02140 // a 1 bit in the net_draw_control_mask, a 1 bit 02141 // indicates that at least one child should be visible, 02142 // while a 0 bit indicates that all children are hidden. 02143 //////////////////////////////////////////////////////////////////// 02144 DrawMask PandaNode:: 02145 get_net_draw_show_mask() const { 02146 Thread *current_thread = Thread::get_current_thread(); 02147 int pipeline_stage = current_thread->get_pipeline_stage(); 02148 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); 02149 if (cdata->_last_update != cdata->_next_update) { 02150 // The cache is stale; it needs to be rebuilt. 02151 PStatTimer timer(_update_bounds_pcollector); 02152 CDStageWriter cdataw = 02153 ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 02154 return cdataw->_net_draw_show_mask; 02155 } 02156 return cdata->_net_draw_show_mask; 02157 } 02158 02159 //////////////////////////////////////////////////////////////////// 02160 // Function: PandaNode::set_into_collide_mask 02161 // Access: Published 02162 // Description: Sets the "into" CollideMask. 02163 // 02164 // This specifies the set of bits that must be shared 02165 // with a CollisionNode's "from" CollideMask in order 02166 // for the CollisionNode to detect a collision with this 02167 // particular node. 02168 // 02169 // The actual CollideMask that will be set is masked by 02170 // the return value from get_legal_collide_mask(). 02171 // Thus, the into_collide_mask cannot be set to anything 02172 // other than nonzero except for those types of nodes 02173 // that can be collided into, such as CollisionNodes and 02174 // GeomNodes. 02175 //////////////////////////////////////////////////////////////////// 02176 void PandaNode:: 02177 set_into_collide_mask(CollideMask mask) { 02178 mask &= get_legal_collide_mask(); 02179 02180 bool any_changed = false; 02181 Thread *current_thread = Thread::get_current_thread(); 02182 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 02183 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 02184 if (cdata->_into_collide_mask != mask) { 02185 cdata->_into_collide_mask = mask; 02186 any_changed = true; 02187 } 02188 } 02189 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 02190 02191 if (any_changed) { 02192 mark_bounds_stale(current_thread); 02193 mark_bam_modified(); 02194 } 02195 } 02196 02197 //////////////////////////////////////////////////////////////////// 02198 // Function: PandaNode::get_legal_collide_mask 02199 // Access: Published, Virtual 02200 // Description: Returns the subset of CollideMask bits that may be 02201 // set for this particular type of PandaNode. For most 02202 // nodes, this is 0; it doesn't make sense to set a 02203 // CollideMask for most kinds of nodes. 02204 // 02205 // For nodes that can be collided with, such as GeomNode 02206 // and CollisionNode, this returns all bits on. 02207 //////////////////////////////////////////////////////////////////// 02208 CollideMask PandaNode:: 02209 get_legal_collide_mask() const { 02210 return CollideMask::all_off(); 02211 } 02212 02213 //////////////////////////////////////////////////////////////////// 02214 // Function: PandaNode::get_net_collide_mask 02215 // Access: Published 02216 // Description: Returns the union of all into_collide_mask() values 02217 // set at CollisionNodes at this level and below. 02218 //////////////////////////////////////////////////////////////////// 02219 CollideMask PandaNode:: 02220 get_net_collide_mask(Thread *current_thread) const { 02221 int pipeline_stage = current_thread->get_pipeline_stage(); 02222 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); 02223 if (cdata->_last_update != cdata->_next_update) { 02224 // The cache is stale; it needs to be rebuilt. 02225 PStatTimer timer(_update_bounds_pcollector); 02226 CDStageWriter cdataw = 02227 ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 02228 return cdataw->_net_collide_mask; 02229 } 02230 return cdata->_net_collide_mask; 02231 } 02232 02233 //////////////////////////////////////////////////////////////////// 02234 // Function: PandaNode::get_off_clip_planes 02235 // Access: Published 02236 // Description: Returns a ClipPlaneAttrib which represents the union 02237 // of all of the clip planes that have been turned *off* 02238 // at this level and below. 02239 //////////////////////////////////////////////////////////////////// 02240 CPT(RenderAttrib) PandaNode:: 02241 get_off_clip_planes(Thread *current_thread) const { 02242 int pipeline_stage = current_thread->get_pipeline_stage(); 02243 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); 02244 if (cdata->_last_update != cdata->_next_update) { 02245 // The cache is stale; it needs to be rebuilt. 02246 PStatTimer timer(_update_bounds_pcollector); 02247 CDStageWriter cdataw = 02248 ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 02249 return cdataw->_off_clip_planes; 02250 } 02251 return cdata->_off_clip_planes; 02252 } 02253 02254 //////////////////////////////////////////////////////////////////// 02255 // Function: PandaNode::prepare_scene 02256 // Access: Published 02257 // Description: Walks through the scene graph beginning at this node, 02258 // and does whatever initialization is required to 02259 // render the scene properly with the indicated GSG. It 02260 // is not strictly necessary to call this, since the GSG 02261 // will initialize itself when the scene is rendered, 02262 // but this may take some of the overhead away from that 02263 // process. 02264 // 02265 // In particular, this will ensure that textures within 02266 // the scene are loaded in texture memory, and display 02267 // lists are built up from static geometry. 02268 //////////////////////////////////////////////////////////////////// 02269 void PandaNode:: 02270 prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *net_state) { 02271 Thread *current_thread = Thread::get_current_thread(); 02272 PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects(); 02273 r_prepare_scene(net_state, prepared_objects, current_thread); 02274 } 02275 02276 //////////////////////////////////////////////////////////////////// 02277 // Function: PandaNode::is_scene_root 02278 // Access: Published 02279 // Description: Returns true if this particular node is known to be 02280 // the render root of some active DisplayRegion 02281 // associated with the global GraphicsEngine, false 02282 // otherwise. 02283 //////////////////////////////////////////////////////////////////// 02284 bool PandaNode:: 02285 is_scene_root() const { 02286 // This function pointer has to be filled in when the global 02287 // GraphicsEngine is created, because we can't link with the 02288 // GraphicsEngine functions directly. 02289 if (_scene_root_func != (SceneRootFunc *)NULL) { 02290 return (*_scene_root_func)(this); 02291 } 02292 return false; 02293 } 02294 02295 //////////////////////////////////////////////////////////////////// 02296 // Function: PandaNode::is_under_scene_root 02297 // Access: Published 02298 // Description: Returns true if this particular node is in a live 02299 // scene graph: that is, it is a child or descendent of 02300 // a node that is itself a scene root. If this is true, 02301 // this node may potentially be traversed by the render 02302 // traverser. Stashed nodes don't count for this 02303 // purpose, but hidden nodes do. 02304 //////////////////////////////////////////////////////////////////// 02305 bool PandaNode:: 02306 is_under_scene_root() const { 02307 if (is_scene_root()) { 02308 return true; 02309 } 02310 02311 Parents parents = get_parents(); 02312 for (int i = 0; i < parents.get_num_parents(); ++i) { 02313 PandaNode *parent = parents.get_parent(i); 02314 if (parent->find_stashed((PandaNode *)this) == -1) { 02315 if (parent->is_under_scene_root()) { 02316 return true; 02317 } 02318 } 02319 } 02320 return false; 02321 } 02322 02323 //////////////////////////////////////////////////////////////////// 02324 // Function: PandaNode::output 02325 // Access: Published, Virtual 02326 // Description: 02327 //////////////////////////////////////////////////////////////////// 02328 void PandaNode:: 02329 output(ostream &out) const { 02330 out << get_type() << " " << get_name(); 02331 } 02332 02333 //////////////////////////////////////////////////////////////////// 02334 // Function: PandaNode::write 02335 // Access: Published, Virtual 02336 // Description: 02337 //////////////////////////////////////////////////////////////////// 02338 void PandaNode:: 02339 write(ostream &out, int indent_level) const { 02340 indent(out, indent_level) << *this; 02341 if (has_tags()) { 02342 out << " ["; 02343 list_tags(out, " "); 02344 out << "]"; 02345 } 02346 CPT(TransformState) transform = get_transform(); 02347 if (!transform->is_identity()) { 02348 out << " " << *transform; 02349 } 02350 CPT(RenderState) state = get_state(); 02351 if (!state->is_empty()) { 02352 out << " " << *state; 02353 } 02354 CPT(RenderEffects) effects = get_effects(); 02355 if (!effects->is_empty()) { 02356 out << " " << *effects; 02357 } 02358 DrawMask draw_control_mask = get_draw_control_mask(); 02359 if (!draw_control_mask.is_zero()) { 02360 DrawMask draw_show_mask = get_draw_show_mask(); 02361 if (!(draw_control_mask & _overall_bit).is_zero()) { 02362 if (!(draw_show_mask & _overall_bit).is_zero()) { 02363 out << " (show_through)"; 02364 } else { 02365 out << " (hidden)"; 02366 } 02367 } 02368 if (!(draw_control_mask & ~_overall_bit).is_zero()) { 02369 draw_control_mask &= ~_overall_bit; 02370 if (!(draw_show_mask & draw_control_mask).is_zero()) { 02371 out << " (per-camera show_through)"; 02372 } 02373 if (!(~draw_show_mask & draw_control_mask).is_zero()) { 02374 out << " (per-camera hidden)"; 02375 } 02376 } 02377 } 02378 out << "\n"; 02379 } 02380 02381 //////////////////////////////////////////////////////////////////// 02382 // Function: PandaNode::set_bounds_type 02383 // Access: Published 02384 // Description: Specifies the desired type of bounding volume that 02385 // will be created for this node. This is normally 02386 // BoundingVolume::BT_default, which means to set the 02387 // type according to the config variable "bounds-type". 02388 // 02389 // If this is BT_sphere or BT_box, a BoundingSphere or 02390 // BoundingBox is explicitly created. If it is BT_best, 02391 // the appropriate type to best enclose the node's 02392 // children is created. 02393 // 02394 // This affects the bounding volume returned by 02395 // get_bounds(), which is not exactly the same bounding 02396 // volume modified by set_bounds(), because a new 02397 // bounding volume has to be created that includes this 02398 // node and all of its children. 02399 //////////////////////////////////////////////////////////////////// 02400 void PandaNode:: 02401 set_bounds_type(BoundingVolume::BoundsType bounds_type) { 02402 Thread *current_thread = Thread::get_current_thread(); 02403 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 02404 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 02405 cdata->_bounds_type = bounds_type; 02406 mark_bounds_stale(pipeline_stage, current_thread); 02407 02408 // GeomNodes, CollisionNodes, and PGItems all have an internal 02409 // bounds that may need to be updated when the bounds_type 02410 // changes. 02411 mark_internal_bounds_stale(pipeline_stage, current_thread); 02412 mark_bam_modified(); 02413 } 02414 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 02415 } 02416 02417 //////////////////////////////////////////////////////////////////// 02418 // Function: PandaNode::get_bounds_type 02419 // Access: Published 02420 // Description: Returns the bounding volume type set with 02421 // set_bounds_type(). 02422 //////////////////////////////////////////////////////////////////// 02423 BoundingVolume::BoundsType PandaNode:: 02424 get_bounds_type() const { 02425 CDReader cdata(_cycler); 02426 return cdata->_bounds_type; 02427 } 02428 02429 //////////////////////////////////////////////////////////////////// 02430 // Function: PandaNode::set_bounds 02431 // Access: Published 02432 // Description: Resets the bounding volume so that it is the 02433 // indicated volume. When it is explicitly set, the 02434 // bounding volume will no longer be automatically 02435 // computed according to the contents of the node 02436 // itself, for nodes like GeomNodes and TextNodes that 02437 // contain substance (but the bounding volume will still 02438 // be automatically expanded to include its children). 02439 // 02440 // Call clear_bounds() if you would like to return the 02441 // bounding volume to its default behavior later. 02442 //////////////////////////////////////////////////////////////////// 02443 void PandaNode:: 02444 set_bounds(const BoundingVolume *volume) { 02445 Thread *current_thread = Thread::get_current_thread(); 02446 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 02447 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 02448 if (volume == NULL) { 02449 cdata->_user_bounds = NULL; 02450 } else { 02451 cdata->_user_bounds = volume->make_copy(); 02452 } 02453 mark_bounds_stale(pipeline_stage, current_thread); 02454 mark_bam_modified(); 02455 } 02456 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 02457 } 02458 02459 //////////////////////////////////////////////////////////////////// 02460 // Function: PandaNode::set_bound 02461 // Access: Published 02462 // Description: Deprecated. Use set_bounds() instead. 02463 //////////////////////////////////////////////////////////////////// 02464 void PandaNode:: 02465 set_bound(const BoundingVolume *volume) { 02466 pgraph_cat.warning() 02467 << "Deprecated PandaNode::set_bound() called. Use set_bounds() instead.\n"; 02468 set_bounds(volume); 02469 } 02470 02471 //////////////////////////////////////////////////////////////////// 02472 // Function: PandaNode::get_bounds 02473 // Access: Published 02474 // Description: Returns the external bounding volume of this node: a 02475 // bounding volume that contains the user bounding 02476 // volume, the internal bounding volume, and all of the 02477 // children's bounding volumes. 02478 //////////////////////////////////////////////////////////////////// 02479 CPT(BoundingVolume) PandaNode:: 02480 get_bounds(Thread *current_thread) const { 02481 int pipeline_stage = current_thread->get_pipeline_stage(); 02482 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); 02483 if (cdata->_last_update != cdata->_next_update) { 02484 // The cache is stale; it needs to be rebuilt. 02485 CPT(BoundingVolume) result; 02486 { 02487 PStatTimer timer(_update_bounds_pcollector); 02488 CDStageWriter cdataw = 02489 ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 02490 result = cdataw->_external_bounds; 02491 } 02492 return result; 02493 } 02494 return cdata->_external_bounds; 02495 } 02496 02497 //////////////////////////////////////////////////////////////////// 02498 // Function: PandaNode::get_bounds 02499 // Access: Published 02500 // Description: This flavor of get_bounds() return the external 02501 // bounding volume, and also fills in seq with the 02502 // bounding volume's current sequence number. When this 02503 // sequence number changes, it indicates that the 02504 // bounding volume might have changed, e.g. because some 02505 // nested child's bounding volume has changed. 02506 // 02507 // Although this might occasionally increment without 02508 // changing the bounding volume, the bounding volume 02509 // will never change without incrementing this counter, 02510 // so as long as this counter remains unchanged you can 02511 // be confident the bounding volume is also unchanged. 02512 //////////////////////////////////////////////////////////////////// 02513 CPT(BoundingVolume) PandaNode:: 02514 get_bounds(UpdateSeq &seq, Thread *current_thread) const { 02515 int pipeline_stage = current_thread->get_pipeline_stage(); 02516 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); 02517 if (cdata->_last_update != cdata->_next_update) { 02518 // The cache is stale; it needs to be rebuilt. 02519 CPT(BoundingVolume) result; 02520 { 02521 PStatTimer timer(_update_bounds_pcollector); 02522 CDStageWriter cdataw = 02523 ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 02524 result = cdataw->_external_bounds; 02525 seq = cdataw->_last_update; 02526 } 02527 return result; 02528 } 02529 seq = cdata->_last_update; 02530 return cdata->_external_bounds; 02531 } 02532 02533 //////////////////////////////////////////////////////////////////// 02534 // Function: PandaNode::get_nested_vertices 02535 // Access: Published 02536 // Description: Returns the total number of vertices that will be 02537 // rendered by this node and all of its descendents. 02538 // 02539 // This is not necessarily an accurate count of vertices 02540 // that will actually be rendered, since this will 02541 // include all vertices of all LOD's, and it will also 02542 // include hidden nodes. It may also omit or only 02543 // approximate certain kinds of dynamic geometry. 02544 // However, it will not include stashed nodes. 02545 //////////////////////////////////////////////////////////////////// 02546 int PandaNode:: 02547 get_nested_vertices(Thread *current_thread) const { 02548 int pipeline_stage = current_thread->get_pipeline_stage(); 02549 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); 02550 if (cdata->_last_update != cdata->_next_update) { 02551 // The cache is stale; it needs to be rebuilt. 02552 int result; 02553 { 02554 PStatTimer timer(_update_bounds_pcollector); 02555 CDStageWriter cdataw = 02556 ((PandaNode *)this)->update_bounds(pipeline_stage, cdata); 02557 result = cdataw->_nested_vertices; 02558 } 02559 return result; 02560 } 02561 return cdata->_nested_vertices; 02562 } 02563 02564 //////////////////////////////////////////////////////////////////// 02565 // Function: PandaNode::mark_bounds_stale 02566 // Access: Published 02567 // Description: Indicates that the bounding volume, or something that 02568 // influences the bounding volume (or any of the other 02569 // things stored in CData, like net_collide_mask), 02570 // may have changed for this node, and that it must be 02571 // recomputed. 02572 // 02573 // With no parameters, this means to iterate through all 02574 // stages including and upstream of the current pipeline 02575 // stage. 02576 // 02577 // This method is intended for internal use; usually it 02578 // is not necessary for a user to call this directly. 02579 // It will be called automatically by derived classes 02580 // when appropriate. 02581 //////////////////////////////////////////////////////////////////// 02582 void PandaNode:: 02583 mark_bounds_stale(Thread *current_thread) const { 02584 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) { 02585 mark_bounds_stale(pipeline_stage, current_thread); 02586 } 02587 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler); 02588 } 02589 02590 //////////////////////////////////////////////////////////////////// 02591 // Function: PandaNode::mark_internal_bounds_stale 02592 // Access: Published 02593 // Description: Should be called by a derived class to mark the 02594 // internal bounding volume stale, so that 02595 // compute_internal_bounds() will be called when the 02596 // bounding volume is next requested. 02597 // 02598 // With no parameters, this means to iterate through all 02599 // stages including and upstream of the current pipeline 02600 // stage. 02601 // 02602 // It is normally not necessary to call this method 02603 // directly; each node should be responsible for calling 02604 // it when its internals have changed. 02605 //////////////////////////////////////////////////////////////////// 02606 void PandaNode:: 02607 mark_internal_bounds_stale(Thread *current_thread) { 02608 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) { 02609 mark_internal_bounds_stale(pipeline_stage, current_thread); 02610 } 02611 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler); 02612 } 02613 02614 //////////////////////////////////////////////////////////////////// 02615 // Function: PandaNode::is_geom_node 02616 // Access: Published, Virtual 02617 // Description: A simple downcast check. Returns true if this kind 02618 // of node happens to inherit from GeomNode, false 02619 // otherwise. 02620 // 02621 // This is provided as a a faster alternative to calling 02622 // is_of_type(GeomNode::get_class_type()), since this 02623 // test is so important to rendering. 02624 //////////////////////////////////////////////////////////////////// 02625 bool PandaNode:: 02626 is_geom_node() const { 02627 return false; 02628 } 02629 02630 //////////////////////////////////////////////////////////////////// 02631 // Function: PandaNode::is_lod_node 02632 // Access: Published, Virtual 02633 // Description: A simple downcast check. Returns true if this kind 02634 // of node happens to inherit from LODNode, false 02635 // otherwise. 02636 // 02637 // This is provided as a a faster alternative to calling 02638 // is_of_type(LODNode::get_class_type()). 02639 //////////////////////////////////////////////////////////////////// 02640 bool PandaNode:: 02641 is_lod_node() const { 02642 return false; 02643 } 02644 02645 //////////////////////////////////////////////////////////////////// 02646 // Function: PandaNode::as_light 02647 // Access: Published, Virtual 02648 // Description: Cross-casts the node to a Light pointer, if it is one 02649 // of the four kinds of Light nodes, or returns NULL if 02650 // it is not. 02651 //////////////////////////////////////////////////////////////////// 02652 Light *PandaNode:: 02653 as_light() { 02654 return NULL; 02655 } 02656 02657 //////////////////////////////////////////////////////////////////// 02658 // Function: PandaNode::is_ambient_light 02659 // Access: Published, Virtual 02660 // Description: Returns true if this is an AmbientLight, false if it 02661 // is not a light, or it is some other kind of light. 02662 //////////////////////////////////////////////////////////////////// 02663 bool PandaNode:: 02664 is_ambient_light() const { 02665 return false; 02666 } 02667 02668 //////////////////////////////////////////////////////////////////// 02669 // Function: PandaNode::decode_from_bam_stream 02670 // Access: Published, Static 02671 // Description: Reads the string created by a previous call to 02672 // encode_to_bam_stream(), and extracts and returns the 02673 // single object on that string. Returns NULL on error. 02674 // 02675 // This method is intended to replace 02676 // decode_raw_from_bam_stream() when you know the stream 02677 // in question returns an object of type PandaNode, 02678 // allowing for easier reference count management. Note 02679 // that the caller is still responsible for maintaining 02680 // the reference count on the return value. 02681 //////////////////////////////////////////////////////////////////// 02682 PT(PandaNode) PandaNode:: 02683 decode_from_bam_stream(const string &data, BamReader *reader) { 02684 TypedWritable *object; 02685 ReferenceCount *ref_ptr; 02686 02687 if (!TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, data, reader)) { 02688 return NULL; 02689 } 02690 02691 return DCAST(PandaNode, object); 02692 } 02693 02694 //////////////////////////////////////////////////////////////////// 02695 // Function: PandaNode::get_internal_bounds 02696 // Access: Protected 02697 // Description: Returns the node's internal bounding volume. This is 02698 // the bounding volume around the node alone, without 02699 // including children. 02700 //////////////////////////////////////////////////////////////////// 02701 CPT(BoundingVolume) PandaNode:: 02702 get_internal_bounds(int pipeline_stage, Thread *current_thread) const { 02703 while (true) { 02704 UpdateSeq mark; 02705 { 02706 CDStageReader cdata(_cycler, pipeline_stage, current_thread); 02707 if (cdata->_user_bounds != (BoundingVolume *)NULL) { 02708 return cdata->_user_bounds; 02709 } 02710 02711 if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) { 02712 return cdata->_internal_bounds; 02713 } 02714 02715 mark = cdata->_internal_bounds_mark; 02716 } 02717 02718 // First, call compute_internal_bounds without acquiring the lock. 02719 // This avoids a deadlock condition. 02720 CPT(BoundingVolume) internal_bounds; 02721 int internal_vertices; 02722 compute_internal_bounds(internal_bounds, internal_vertices, 02723 pipeline_stage, current_thread); 02724 nassertr(!internal_bounds.is_null(), NULL); 02725 02726 // Now, acquire the lock, and apply the above-computed bounds. 02727 CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage); 02728 if (cdataw->_internal_bounds_mark == mark) { 02729 cdataw->_internal_bounds_computed = mark; 02730 cdataw->_internal_bounds = internal_bounds; 02731 cdataw->_internal_vertices = internal_vertices; 02732 ((PandaNode *)this)->mark_bam_modified(); 02733 return cdataw->_internal_bounds; 02734 } 02735 02736 // Dang, someone in another thread incremented 02737 // _internal_bounds_mark while we weren't holding the lock. That 02738 // means we need to go back and do it again. 02739 } 02740 } 02741 02742 //////////////////////////////////////////////////////////////////// 02743 // Function: PandaNode::get_internal_vertices 02744 // Access: Protected 02745 // Description: Returns the total number of vertices that will be 02746 // rendered by this particular node alone, not 02747 // accounting for its children. 02748 // 02749 // This may not include all vertices for certain dynamic 02750 // effects. 02751 //////////////////////////////////////////////////////////////////// 02752 int PandaNode:: 02753 get_internal_vertices(int pipeline_stage, Thread *current_thread) const { 02754 while (true) { 02755 UpdateSeq mark; 02756 { 02757 CDStageReader cdata(_cycler, pipeline_stage, current_thread); 02758 if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) { 02759 return cdata->_internal_vertices; 02760 } 02761 02762 mark = cdata->_internal_bounds_mark; 02763 } 02764 02765 // First, call compute_internal_bounds without acquiring the lock. 02766 // This avoids a deadlock condition. 02767 CPT(BoundingVolume) internal_bounds; 02768 int internal_vertices; 02769 compute_internal_bounds(internal_bounds, internal_vertices, 02770 pipeline_stage, current_thread); 02771 nassertr(!internal_bounds.is_null(), 0); 02772 02773 // Now, acquire the lock, and apply the above-computed bounds. 02774 CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage); 02775 if (cdataw->_internal_bounds_mark == mark) { 02776 cdataw->_internal_bounds_computed = mark; 02777 cdataw->_internal_bounds = internal_bounds; 02778 cdataw->_internal_vertices = internal_vertices; 02779 ((PandaNode *)this)->mark_bam_modified(); 02780 return cdataw->_internal_vertices; 02781 } 02782 02783 // Dang, someone in another thread incremented 02784 // _internal_bounds_mark while we weren't holding the lock. That 02785 // means we need to go back and do it again. 02786 } 02787 } 02788 02789 //////////////////////////////////////////////////////////////////// 02790 // Function: PandaNode::set_internal_bounds 02791 // Access: Protected 02792 // Description: This is provided as an alternate way for a node to 02793 // set its own internal bounds, rather than overloading 02794 // compute_internal_bounds(). If this method is called, 02795 // the internal bounding volume will immediately be set 02796 // to the indicated pointer. 02797 //////////////////////////////////////////////////////////////////// 02798 void PandaNode:: 02799 set_internal_bounds(const BoundingVolume *volume) { 02800 Thread *current_thread = Thread::get_current_thread(); 02801 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 02802 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread); 02803 cdataw->_internal_bounds = volume; 02804 cdataw->_internal_bounds_computed = cdataw->_internal_bounds_mark; 02805 } 02806 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 02807 mark_bounds_stale(current_thread); 02808 mark_bam_modified(); 02809 } 02810 02811 //////////////////////////////////////////////////////////////////// 02812 // Function: PandaNode::force_bounds_stale 02813 // Access: Protected 02814 // Description: Similar to mark_bounds_stale(), except that the 02815 // parents of this node marked stale even if this node 02816 // was already considered stale. 02817 // 02818 // With no parameters, this means to iterate through all 02819 // stages including and upstream of the current pipeline 02820 // stage. 02821 //////////////////////////////////////////////////////////////////// 02822 void PandaNode:: 02823 force_bounds_stale(Thread *current_thread) { 02824 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) { 02825 force_bounds_stale(pipeline_stage, current_thread); 02826 } 02827 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler); 02828 } 02829 02830 //////////////////////////////////////////////////////////////////// 02831 // Function: PandaNode::force_bounds_stale 02832 // Access: Protected 02833 // Description: Similar to mark_bounds_stale(), except that the 02834 // parents of this node marked stale even if this node 02835 // was already considered stale. 02836 //////////////////////////////////////////////////////////////////// 02837 void PandaNode:: 02838 force_bounds_stale(int pipeline_stage, Thread *current_thread) { 02839 { 02840 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 02841 ++cdata->_next_update; 02842 mark_bam_modified(); 02843 02844 // It is important that we allow this lock to be dropped before we 02845 // continue up the graph; otherwise, we risk deadlock from another 02846 // thread walking down the graph. 02847 } 02848 02849 // It is similarly important that we use get_parents() here to copy 02850 // the parents list, instead of keeping the lock open while we walk 02851 // through the parents list directly on the node. 02852 Parents parents; 02853 { 02854 CDStageReader cdata(_cycler, pipeline_stage, current_thread); 02855 parents = Parents(cdata); 02856 } 02857 int num_parents = parents.get_num_parents(); 02858 for (int i = 0; i < num_parents; ++i) { 02859 PandaNode *parent = parents.get_parent(i); 02860 parent->mark_bounds_stale(pipeline_stage, current_thread); 02861 } 02862 } 02863 02864 //////////////////////////////////////////////////////////////////// 02865 // Function: PandaNode::r_mark_geom_bounds_stale 02866 // Access: Protected, Virtual 02867 // Description: Recursively calls Geom::mark_bounds_stale() on every 02868 // Geom at this node and below. 02869 //////////////////////////////////////////////////////////////////// 02870 void PandaNode:: 02871 r_mark_geom_bounds_stale(Thread *current_thread) { 02872 Children children = get_children(current_thread); 02873 02874 int i; 02875 for (i = 0; i < children.get_num_children(); i++) { 02876 PandaNode *child = children.get_child(i); 02877 child->r_mark_geom_bounds_stale(current_thread); 02878 } 02879 02880 Stashed stashed = get_stashed(current_thread); 02881 for (i = 0; i < stashed.get_num_stashed(); i++) { 02882 PandaNode *child = stashed.get_stashed(i); 02883 child->r_mark_geom_bounds_stale(current_thread); 02884 } 02885 } 02886 02887 //////////////////////////////////////////////////////////////////// 02888 // Function: PandaNode::compute_internal_bounds 02889 // Access: Protected, Virtual 02890 // Description: Returns a newly-allocated BoundingVolume that 02891 // represents the internal contents of the node. Should 02892 // be overridden by PandaNode classes that contain 02893 // something internally. 02894 //////////////////////////////////////////////////////////////////// 02895 void PandaNode:: 02896 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, 02897 int &internal_vertices, 02898 int pipeline_stage, 02899 Thread *current_thread) const { 02900 internal_bounds = new BoundingSphere; 02901 internal_vertices = 0; 02902 } 02903 02904 //////////////////////////////////////////////////////////////////// 02905 // Function: PandaNode::parents_changed 02906 // Access: Protected, Virtual 02907 // Description: Called after a scene graph update that either adds or 02908 // remove parents from this node, this just provides a 02909 // hook for derived PandaNode objects that need to 02910 // update themselves based on the set of parents the 02911 // node has. 02912 //////////////////////////////////////////////////////////////////// 02913 void PandaNode:: 02914 parents_changed() { 02915 nassertv((_unexpected_change_flags & UC_parents) == 0); 02916 } 02917 02918 //////////////////////////////////////////////////////////////////// 02919 // Function: PandaNode::children_changed 02920 // Access: Protected, Virtual 02921 // Description: Called after a scene graph update that either adds or 02922 // remove children from this node, this just provides a 02923 // hook for derived PandaNode objects that need to 02924 // update themselves based on the set of children the 02925 // node has. 02926 //////////////////////////////////////////////////////////////////// 02927 void PandaNode:: 02928 children_changed() { 02929 nassertv((_unexpected_change_flags & UC_children) == 0); 02930 } 02931 02932 //////////////////////////////////////////////////////////////////// 02933 // Function: PandaNode::transform_changed 02934 // Access: Protected, Virtual 02935 // Description: Called after the node's transform has been changed 02936 // for any reason, this just provides a hook so derived 02937 // classes can do something special in this case. 02938 //////////////////////////////////////////////////////////////////// 02939 void PandaNode:: 02940 transform_changed() { 02941 nassertv((_unexpected_change_flags & UC_transform) == 0); 02942 } 02943 02944 //////////////////////////////////////////////////////////////////// 02945 // Function: PandaNode::state_changed 02946 // Access: Protected, Virtual 02947 // Description: Called after the node's RenderState has been changed 02948 // for any reason, this just provides a hook so derived 02949 // classes can do something special in this case. 02950 //////////////////////////////////////////////////////////////////// 02951 void PandaNode:: 02952 state_changed() { 02953 nassertv((_unexpected_change_flags & UC_state) == 0); 02954 } 02955 02956 //////////////////////////////////////////////////////////////////// 02957 // Function: PandaNode::draw_mask_changed 02958 // Access: Protected, Virtual 02959 // Description: Called after the node's DrawMask has been changed 02960 // for any reason, this just provides a hook so derived 02961 // classes can do something special in this case. 02962 //////////////////////////////////////////////////////////////////// 02963 void PandaNode:: 02964 draw_mask_changed() { 02965 nassertv((_unexpected_change_flags & UC_draw_mask) == 0); 02966 } 02967 02968 //////////////////////////////////////////////////////////////////// 02969 // Function: PandaNode::r_copy_subgraph 02970 // Access: Protected, Virtual 02971 // Description: This is the recursive implementation of copy_subgraph(). 02972 // It returns a copy of the entire subgraph rooted at 02973 // this node. 02974 // 02975 // Note that it includes the parameter inst_map, which 02976 // is a map type, and is not (and cannot be) exported 02977 // from PANDA.DLL. Thus, any derivative of PandaNode 02978 // that is not also a member of PANDA.DLL *cannot* 02979 // access this map. 02980 //////////////////////////////////////////////////////////////////// 02981 PT(PandaNode) PandaNode:: 02982 r_copy_subgraph(PandaNode::InstanceMap &inst_map, Thread *current_thread) const { 02983 PT(PandaNode) copy = make_copy(); 02984 nassertr(copy != (PandaNode *)NULL, NULL); 02985 if (copy->get_type() != get_type()) { 02986 pgraph_cat.warning() 02987 << "Don't know how to copy nodes of type " << get_type() << "\n"; 02988 02989 if (no_unsupported_copy) { 02990 nassertr(false, NULL); 02991 } 02992 } 02993 02994 copy->r_copy_children(this, inst_map, current_thread); 02995 return copy; 02996 } 02997 02998 //////////////////////////////////////////////////////////////////// 02999 // Function: PandaNode::r_copy_children 03000 // Access: Protected, Virtual 03001 // Description: This is called by r_copy_subgraph(); the copy has 03002 // already been made of this particular node (and this 03003 // is the copy); this function's job is to copy all of 03004 // the children from the original. 03005 // 03006 // Note that it includes the parameter inst_map, which 03007 // is a map type, and is not (and cannot be) exported 03008 // from PANDA.DLL. Thus, any derivative of PandaNode 03009 // that is not also a member of PANDA.DLL *cannot* 03010 // access this map, and probably should not even 03011 // override this function. 03012 //////////////////////////////////////////////////////////////////// 03013 void PandaNode:: 03014 r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map, 03015 Thread *current_thread) { 03016 CDReader from_cdata(from->_cycler, current_thread); 03017 CPT(Down) from_down = from_cdata->get_down(); 03018 Down::const_iterator di; 03019 for (di = from_down->begin(); di != from_down->end(); ++di) { 03020 int sort = (*di).get_sort(); 03021 PandaNode *source_child = (*di).get_child(); 03022 PT(PandaNode) dest_child; 03023 03024 // Check to see if we have already copied this child. If we 03025 // have, use the copy. In this way, a subgraph that contains 03026 // instances will be correctly duplicated into another subgraph 03027 // that also contains its own instances. 03028 InstanceMap::const_iterator ci; 03029 ci = inst_map.find(source_child); 03030 if (ci != inst_map.end()) { 03031 dest_child = (*ci).second; 03032 } else { 03033 dest_child = source_child->r_copy_subgraph(inst_map, current_thread); 03034 inst_map[source_child] = dest_child; 03035 } 03036 03037 quick_add_new_child(dest_child, sort, current_thread); 03038 } 03039 } 03040 03041 //////////////////////////////////////////////////////////////////// 03042 // Function: PandaNode::r_prepare_scene 03043 // Access: Public, Virtual 03044 // Description: The recursive implementation of prepare_scene(). 03045 // Don't call this directly; call 03046 // PandaNode::prepare_scene() or 03047 // NodePath::prepare_scene() instead. 03048 //////////////////////////////////////////////////////////////////// 03049 void PandaNode:: 03050 r_prepare_scene(const RenderState *state, 03051 PreparedGraphicsObjects *prepared_objects, 03052 Thread *current_thread) { 03053 Children children = get_children(current_thread); 03054 // We must call get_num_children() each time through the loop, in 03055 // case we're running SIMPLE_THREADS and we get interrupted. 03056 int i; 03057 for (i = 0; i < children.get_num_children(); i++) { 03058 PandaNode *child = children.get_child(i); 03059 CPT(RenderState) child_state = state->compose(child->get_state()); 03060 child->r_prepare_scene(child_state, prepared_objects, current_thread); 03061 } 03062 03063 Stashed stashed = get_stashed(current_thread); 03064 for (i = 0; i < stashed.get_num_stashed(); i++) { 03065 PandaNode *child = stashed.get_stashed(i); 03066 CPT(RenderState) child_state = state->compose(child->get_state()); 03067 child->r_prepare_scene(child_state, prepared_objects, current_thread); 03068 } 03069 } 03070 03071 //////////////////////////////////////////////////////////////////// 03072 // Function: PandaNode::set_cull_callback 03073 // Access: Protected 03074 // Description: Intended to be called in the constructor by any 03075 // subclass that defines cull_callback(), this sets up 03076 // the flags to indicate that the cullback needs to be 03077 // called. 03078 //////////////////////////////////////////////////////////////////// 03079 void PandaNode:: 03080 set_cull_callback() { 03081 Thread *current_thread = Thread::get_current_thread(); 03082 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 03083 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 03084 cdata->set_fancy_bit(FB_cull_callback, true); 03085 } 03086 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 03087 mark_bam_modified(); 03088 } 03089 03090 //////////////////////////////////////////////////////////////////// 03091 // Function: PandaNode::disable_cull_callback 03092 // Access: Protected 03093 // Description: disables the call back 03094 //////////////////////////////////////////////////////////////////// 03095 void PandaNode:: 03096 disable_cull_callback() { 03097 Thread *current_thread = Thread::get_current_thread(); 03098 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 03099 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 03100 cdata->set_fancy_bit(FB_cull_callback, false); 03101 } 03102 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 03103 mark_bam_modified(); 03104 } 03105 03106 //////////////////////////////////////////////////////////////////// 03107 // Function: PandaNode::stage_remove_child 03108 // Access: Private 03109 // Description: The private implementation of remove_child(), for a 03110 // particular pipeline stage. 03111 //////////////////////////////////////////////////////////////////// 03112 bool PandaNode:: 03113 stage_remove_child(PandaNode *child_node, int pipeline_stage, 03114 Thread *current_thread) { 03115 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 03116 03117 // First, look for the parent in the child's up list, to ensure the 03118 // child is known. 03119 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, 03120 current_thread); 03121 int parent_index = child_node->do_find_parent(this, cdata_child); 03122 if (parent_index < 0) { 03123 // Nope, no relation. 03124 return false; 03125 } 03126 03127 PT(Down) down = cdata->modify_down(); 03128 int child_index = do_find_child(child_node, down); 03129 if (child_index >= 0) { 03130 // The child exists; remove it. 03131 down->erase(down->begin() + child_index); 03132 int num_erased = cdata_child->modify_up()->erase(UpConnection(this)); 03133 nassertr(num_erased == 1, false); 03134 return true; 03135 } 03136 03137 PT(Down) stashed = cdata->modify_stashed(); 03138 int stashed_index = do_find_child(child_node, stashed); 03139 if (stashed_index >= 0) { 03140 // The child has been stashed; remove it. 03141 stashed->erase(stashed->begin() + stashed_index); 03142 int num_erased = cdata_child->modify_up()->erase(UpConnection(this)); 03143 nassertr(num_erased == 1, false); 03144 return true; 03145 } 03146 03147 // Never heard of this child. This shouldn't be possible, because 03148 // the parent was in the child's up list, above. Must be some 03149 // internal error. 03150 nassertr(false, false); 03151 return false; 03152 } 03153 03154 //////////////////////////////////////////////////////////////////// 03155 // Function: PandaNode::stage_replace_child 03156 // Access: Private 03157 // Description: The private implementation of replace_child(), for a 03158 // particular pipeline stage. 03159 //////////////////////////////////////////////////////////////////// 03160 bool PandaNode:: 03161 stage_replace_child(PandaNode *orig_child, PandaNode *new_child, 03162 int pipeline_stage, Thread *current_thread) { 03163 { 03164 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 03165 CDStageWriter cdata_orig_child(orig_child->_cycler, pipeline_stage, current_thread); 03166 CDStageWriter cdata_new_child(new_child->_cycler, pipeline_stage, current_thread); 03167 03168 // First, look for the parent in the child's up list, to ensure the 03169 // child is known. 03170 int parent_index = orig_child->do_find_parent(this, cdata_orig_child); 03171 if (parent_index < 0) { 03172 // Nope, no relation. 03173 return false; 03174 } 03175 03176 if (orig_child == new_child) { 03177 // Trivial no-op. 03178 return true; 03179 } 03180 03181 // Don't let orig_child be destructed yet. 03182 PT(PandaNode) keep_orig_child = orig_child; 03183 03184 // If we already have new_child as a child, remove it first. 03185 if (stage_remove_child(new_child, pipeline_stage, current_thread)) { 03186 sever_connection(this, new_child, pipeline_stage, current_thread); 03187 } 03188 03189 PT(Down) down = cdata->modify_down(); 03190 int child_index = do_find_child(orig_child, down); 03191 if (child_index >= 0) { 03192 // The child exists; replace it. 03193 DownConnection &dc = (*down)[child_index]; 03194 nassertr(dc.get_child() == orig_child, false); 03195 dc.set_child(new_child); 03196 03197 } else { 03198 PT(Down) stashed = cdata->modify_stashed(); 03199 int stashed_index = do_find_child(orig_child, stashed); 03200 if (stashed_index >= 0) { 03201 // The child has been stashed; remove it. 03202 DownConnection &dc = (*stashed)[stashed_index]; 03203 nassertr(dc.get_child() == orig_child, false); 03204 dc.set_child(new_child); 03205 03206 } else { 03207 // Never heard of this child. This shouldn't be possible, because 03208 // the parent was in the child's up list, above. Must be some 03209 // internal error. 03210 nassertr(false, false); 03211 return false; 03212 } 03213 } 03214 03215 // Now adjust the bookkeeping on both children. 03216 cdata_new_child->modify_up()->insert(UpConnection(this)); 03217 int num_erased = cdata_orig_child->modify_up()->erase(UpConnection(this)); 03218 nassertr(num_erased == 1, false); 03219 } 03220 03221 sever_connection(this, orig_child, pipeline_stage, current_thread); 03222 new_connection(this, new_child, pipeline_stage, current_thread); 03223 03224 force_bounds_stale(pipeline_stage, current_thread); 03225 orig_child->parents_changed(); 03226 new_child->parents_changed(); 03227 mark_bam_modified(); 03228 orig_child->mark_bam_modified(); 03229 new_child->mark_bam_modified(); 03230 03231 return true; 03232 } 03233 03234 //////////////////////////////////////////////////////////////////// 03235 // Function: PandaNode::quick_add_new_child 03236 // Access: Private 03237 // Description: Similar to add_child(), but performs fewer checks. 03238 // The purpose of this method is to add a child node 03239 // that was newly constructed, to a parent node that was 03240 // newly constructed, so we know we have to make fewer 03241 // sanity checks. This is a private method; do not call 03242 // it directly. 03243 //////////////////////////////////////////////////////////////////// 03244 void PandaNode:: 03245 quick_add_new_child(PandaNode *child_node, int sort, Thread *current_thread) { 03246 // Apply this operation to the current stage as well as to all 03247 // upstream stages. 03248 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { 03249 CDStageWriter cdata(_cycler, pipeline_stage, current_thread); 03250 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread); 03251 03252 cdata->modify_down()->insert(DownConnection(child_node, sort)); 03253 cdata_child->modify_up()->insert(UpConnection(this)); 03254 } 03255 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); 03256 } 03257 03258 //////////////////////////////////////////////////////////////////// 03259 // Function: PandaNode::report_cycle 03260 // Access: Private 03261 // Description: Raises an assertion when a graph cycle attempt is 03262 // detected (and aborted). 03263 //////////////////////////////////////////////////////////////////// 03264 void PandaNode:: 03265 report_cycle(PandaNode *child_node) { 03266 ostringstream strm; 03267 strm << "Detected attempt to create a cycle in the scene graph: " 03268 << NodePath::any_path(this) << " : " << *child_node; 03269 nassert_raise(strm.str()); 03270 } 03271 03272 //////////////////////////////////////////////////////////////////// 03273 // Function: PandaNode::find_node_above 03274 // Access: Private 03275 // Description: Returns true if the indicated node is this node, or 03276 // any ancestor of this node; or false if it is not in 03277 // this node's ancestry. 03278 //////////////////////////////////////////////////////////////////// 03279 bool PandaNode:: 03280 find_node_above(PandaNode *node) { 03281 if (node == this) { 03282 return true; 03283 } 03284 03285 Parents parents = get_parents(); 03286 for (int i = 0; i < parents.get_num_parents(); ++i) { 03287 PandaNode *parent = parents.get_parent(i); 03288 if (parent->find_node_above(node)) { 03289 return true; 03290 } 03291 } 03292 03293 return false; 03294 } 03295 03296 //////////////////////////////////////////////////////////////////// 03297 // Function: PandaNode::attach 03298 // Access: Private, Static 03299 // Description: Creates a new parent-child relationship, and returns 03300 // the new NodePathComponent. If the child was already 03301 // attached to the indicated parent, repositions it and 03302 // returns the original NodePathComponent. 03303 // 03304 // This operation is automatically propagated back up to 03305 // pipeline 0, from the specified pipeline stage. 03306 //////////////////////////////////////////////////////////////////// 03307 PT(NodePathComponent) PandaNode:: 03308 attach(NodePathComponent *parent, PandaNode *child_node, int sort, 03309 int pipeline_stage, Thread *current_thread) { 03310 if (parent == (NodePathComponent *)NULL) { 03311 // Attaching to NULL means to create a new "instance" with no 03312 // attachments, and no questions asked. 03313 PT(NodePathComponent) child = 03314 new NodePathComponent(child_node, (NodePathComponent *)NULL, 03315 pipeline_stage, current_thread); 03316 LightReMutexHolder holder(child_node->_paths_lock); 03317 child_node->_paths.insert(child); 03318 return child; 03319 } 03320 03321 // See if the child was already attached to the parent. If it was, 03322 // we'll use that same NodePathComponent. 03323 PT(NodePathComponent) child = get_component(parent, child_node, pipeline_stage, current_thread); 03324 03325 if (child == (NodePathComponent *)NULL) { 03326 // The child was not already attached to the parent, so get a new 03327 // component. 03328 child = get_top_component(child_node, true, pipeline_stage, current_thread); 03329 } 03330 03331 reparent(parent, child, sort, false, pipeline_stage, current_thread); 03332 03333 return child; 03334 } 03335 03336 //////////////////////////////////////////////////////////////////// 03337 // Function: PandaNode::detach 03338 // Access: Private, Static 03339 // Description: Breaks a parent-child relationship. 03340 // 03341 // This operation is automatically propagated back up to 03342 // pipeline 0, from the specified pipeline stage. 03343 //////////////////////////////////////////////////////////////////// 03344 void PandaNode:: 03345 detach(NodePathComponent *child, int pipeline_stage, Thread *current_thread) { 03346 nassertv(child != (NodePathComponent *)NULL); 03347 03348 for (int pipeline_stage_i = pipeline_stage; 03349 pipeline_stage_i >= 0; 03350 --pipeline_stage_i) { 03351 detach_one_stage(child, pipeline_stage_i, current_thread); 03352 } 03353 03354 child->get_node()->parents_changed(); 03355 } 03356 03357 //////////////////////////////////////////////////////////////////// 03358 // Function: PandaNode::detach_one_stage 03359 // Access: Private, Static 03360 // Description: Breaks a parent-child relationship. 03361 // 03362 // This operation is not automatically propagated 03363 // upstream. It is applied to the indicated pipeline 03364 // stage only. 03365 //////////////////////////////////////////////////////////////////// 03366 void PandaNode:: 03367 detach_one_stage(NodePathComponent *child, int pipeline_stage, 03368 Thread *current_thread) { 03369 nassertv(child != (NodePathComponent *)NULL); 03370 if (child->is_top_node(pipeline_stage, current_thread)) { 03371 return; 03372 } 03373 03374 PT(PandaNode) child_node = child->get_node(); 03375 PT(PandaNode) parent_node = child->get_next(pipeline_stage, current_thread)->get_node(); 03376 03377 CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread); 03378 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread); 03379 int parent_index = child_node->do_find_parent(parent_node, cdata_child); 03380 if (parent_index >= 0) { 03381 // Now look for the child and break the actual connection. 03382 03383 // First, look for and remove the parent node from the child's up 03384 // list. 03385 int num_erased = cdata_child->modify_up()->erase(UpConnection(parent_node)); 03386 nassertv(num_erased == 1); 03387 03388 // Now, look for and remove the child node from the parent's down 03389 // list. We also check in the stashed list, in case the child node 03390 // has been stashed. 03391 Down::iterator di; 03392 bool found = false; 03393 PT(Down) down = cdata_parent->modify_down(); 03394 for (di = down->begin(); di != down->end(); ++di) { 03395 if ((*di).get_child() == child_node) { 03396 down->erase(di); 03397 found = true; 03398 break; 03399 } 03400 } 03401 if (!found) { 03402 PT(Down) stashed = cdata_parent->modify_stashed(); 03403 for (di = stashed->begin(); di != stashed->end(); ++di) { 03404 if ((*di).get_child() == child_node) { 03405 stashed->erase(di); 03406 found = true; 03407 break; 03408 } 03409 } 03410 } 03411 nassertv(found); 03412 } 03413 03414 // Finally, break the NodePathComponent connection. 03415 sever_connection(parent_node, child_node, pipeline_stage, current_thread); 03416 03417 parent_node->force_bounds_stale(pipeline_stage, current_thread); 03418 parent_node->children_changed(); 03419 parent_node->mark_bam_modified(); 03420 } 03421 03422 //////////////////////////////////////////////////////////////////// 03423 // Function: PandaNode::reparent 03424 // Access: Private, Static 03425 // Description: Switches a node from one parent to another. Returns 03426 // true if the new connection is allowed, or false if it 03427 // conflicts with another instance (that is, another 03428 // instance of the child is already attached to the 03429 // indicated parent). 03430 // 03431 // This operation is automatically propagated back up to 03432 // pipeline 0, from the specified pipeline stage. 03433 //////////////////////////////////////////////////////////////////// 03434 bool PandaNode:: 03435 reparent(NodePathComponent *new_parent, NodePathComponent *child, int sort, 03436 bool as_stashed, int pipeline_stage, Thread *current_thread) { 03437 bool any_ok = false; 03438 03439 if (new_parent != (NodePathComponent *)NULL && 03440 !new_parent->get_node()->verify_child_no_cycles(child->get_node())) { 03441 // Whoops, adding this child node would introduce a cycle in the 03442 // scene graph. 03443 return false; 03444 } 03445 03446 for (int pipeline_stage_i = pipeline_stage; 03447 pipeline_stage_i >= 0; 03448 --pipeline_stage_i) { 03449 if (reparent_one_stage(new_parent, child, sort, as_stashed, 03450 pipeline_stage_i, current_thread)) { 03451 any_ok = true; 03452 } 03453 } 03454 03455 if (new_parent != (NodePathComponent *)NULL) { 03456 new_parent->get_node()->children_changed(); 03457 new_parent->get_node()->mark_bam_modified(); 03458 } 03459 child->get_node()->parents_changed(); 03460 child->get_node()->mark_bam_modified(); 03461 03462 return any_ok; 03463 } 03464 03465 //////////////////////////////////////////////////////////////////// 03466 // Function: PandaNode::reparent_one_stage 03467 // Access: Private, Static 03468 // Description: Switches a node from one parent to another. Returns 03469 // true if the new connection is allowed, or false if it 03470 // conflicts with another instance (that is, another 03471 // instance of the child is already attached to the 03472 // indicated parent). 03473 // 03474 // This operation is not automatically propagated 03475 // upstream. It is applied to the indicated pipeline 03476 // stage only. 03477 //////////////////////////////////////////////////////////////////// 03478 bool PandaNode:: 03479 reparent_one_stage(NodePathComponent *new_parent, NodePathComponent *child, 03480 int sort, bool as_stashed, int pipeline_stage, 03481 Thread *current_thread) { 03482 nassertr(child != (NodePathComponent *)NULL, false); 03483 03484 // Keep a reference count to the new parent, since detaching the 03485 // child might lose the count. 03486 PT(NodePathComponent) keep_parent = new_parent; 03487 03488 if (!child->is_top_node(pipeline_stage, current_thread)) { 03489 detach(child, pipeline_stage, current_thread); 03490 } 03491 03492 if (new_parent != (NodePathComponent *)NULL) { 03493 PandaNode *child_node = child->get_node(); 03494 PandaNode *parent_node = new_parent->get_node(); 03495 03496 { 03497 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread); 03498 int parent_index = child_node->do_find_parent(parent_node, cdata_child); 03499 03500 if (parent_index >= 0) { 03501 // Whoops, there's already another instance of the child there. 03502 return false; 03503 } 03504 } 03505 03506 // Redirect the connection to the indicated new parent. 03507 child->set_next(new_parent, pipeline_stage, current_thread); 03508 03509 // Now reattach the child node at the indicated sort position. 03510 { 03511 CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread); 03512 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread); 03513 03514 if (as_stashed) { 03515 cdata_parent->modify_stashed()->insert(DownConnection(child_node, sort)); 03516 } else { 03517 cdata_parent->modify_down()->insert(DownConnection(child_node, sort)); 03518 } 03519 cdata_child->modify_up()->insert(UpConnection(parent_node)); 03520 03521 #ifndef NDEBUG 03522 // The NodePathComponent should already be in the set. 03523 { 03524 LightReMutexHolder holder(child_node->_paths_lock); 03525 nassertr(child_node->_paths.find(child) != child_node->_paths.end(), false); 03526 } 03527 #endif // NDEBUG 03528 } 03529 03530 child_node->fix_path_lengths(pipeline_stage, current_thread); 03531 parent_node->force_bounds_stale(pipeline_stage, current_thread); 03532 } 03533 03534 return true; 03535 } 03536 03537 //////////////////////////////////////////////////////////////////// 03538 // Function: PandaNode::get_component 03539 // Access: Private, Static 03540 // Description: Returns the NodePathComponent based on the indicated 03541 // child of the given parent, or NULL if there is no 03542 // such parent-child relationship. 03543 //////////////////////////////////////////////////////////////////// 03544 PT(NodePathComponent) PandaNode:: 03545 get_component(NodePathComponent *parent, PandaNode *child_node, 03546 int pipeline_stage, Thread *current_thread) { 03547 nassertr(parent != (NodePathComponent *)NULL, (NodePathComponent *)NULL); 03548 PandaNode *parent_node = parent->get_node(); 03549 03550 LightReMutexHolder holder(child_node->_paths_lock); 03551 03552 // First, walk through the list of NodePathComponents we already 03553 // have on the child, looking for one that already exists, 03554 // referencing the indicated parent component. 03555 Paths::const_iterator pi; 03556 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) { 03557 if ((*pi)->get_next(pipeline_stage, current_thread) == parent) { 03558 // If we already have such a component, just return it. 03559 return (*pi); 03560 } 03561 } 03562 03563 // We don't already have a NodePathComponent referring to this 03564 // parent-child relationship. Are they actually related? 03565 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread); 03566 int parent_index = child_node->do_find_parent(parent_node, cdata_child); 03567 03568 if (parent_index >= 0) { 03569 // They are. Create and return a new one. 03570 PT(NodePathComponent) child = 03571 new NodePathComponent(child_node, parent, pipeline_stage, current_thread); 03572 child_node->_paths.insert(child); 03573 return child; 03574 } else { 03575 // They aren't related. Return NULL. 03576 return NULL; 03577 } 03578 } 03579 03580 //////////////////////////////////////////////////////////////////// 03581 // Function: PandaNode::get_top_component 03582 // Access: Private, Static 03583 // Description: Returns a NodePathComponent referencing the 03584 // indicated node as a singleton. It is invalid to call 03585 // this for a node that has parents, unless you are 03586 // about to create a new instance (and immediately 03587 // reconnect the NodePathComponent elsewhere). 03588 // 03589 // If force is true, this will always return something, 03590 // even if it needs to create a new top component; 03591 // otherwise, if force is false, it will return NULL if 03592 // there is not already a top component available. 03593 //////////////////////////////////////////////////////////////////// 03594 PT(NodePathComponent) PandaNode:: 03595 get_top_component(PandaNode *child_node, bool force, int pipeline_stage, 03596 Thread *current_thread) { 03597 LightReMutexHolder holder(child_node->_paths_lock); 03598 03599 // Walk through the list of NodePathComponents we already have on 03600 // the child, looking for one that already exists as a top node. 03601 Paths::const_iterator pi; 03602 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) { 03603 if ((*pi)->is_top_node(pipeline_stage, current_thread)) { 03604 // If we already have such a component, just return it. 03605 return (*pi); 03606 } 03607 } 03608 03609 if (!force) { 03610 // If we don't care to force the point, return NULL to indicate 03611 // there's not already a top component. 03612 return NULL; 03613 } 03614 03615 // We don't already have such a NodePathComponent; create and 03616 // return a new one. 03617 PT(NodePathComponent) child = 03618 new NodePathComponent(child_node, (NodePathComponent *)NULL, 03619 pipeline_stage, current_thread); 03620 child_node->_paths.insert(child); 03621 03622 return child; 03623 } 03624 03625 //////////////////////////////////////////////////////////////////// 03626 // Function: PandaNode::get_generic_component 03627 // Access: Private 03628 // Description: Returns a NodePathComponent referencing this node as 03629 // a path from the root. 03630 // 03631 // Unless accept_ambiguity is true, it is only valid to 03632 // call this if there is an unambiguous path from the 03633 // root; otherwise, a warning will be issued and one 03634 // path will be chosen arbitrarily. 03635 //////////////////////////////////////////////////////////////////// 03636 PT(NodePathComponent) PandaNode:: 03637 get_generic_component(bool accept_ambiguity, int pipeline_stage, 03638 Thread *current_thread) { 03639 bool ambiguity_detected = false; 03640 PT(NodePathComponent) result = 03641 r_get_generic_component(accept_ambiguity, ambiguity_detected, 03642 pipeline_stage, current_thread); 03643 03644 if (!accept_ambiguity && ambiguity_detected) { 03645 pgraph_cat.warning() 03646 << "Chose: " << *result << "\n"; 03647 nassertr(!unambiguous_graph, result); 03648 } 03649 03650 return result; 03651 } 03652 03653 //////////////////////////////////////////////////////////////////// 03654 // Function: PandaNode::r_get_generic_component 03655 // Access: Private 03656 // Description: The recursive implementation of 03657 // get_generic_component, this simply sets the flag when 03658 // the ambiguity is detected (so we can report the 03659 // bottom node that started the ambiguous search). 03660 //////////////////////////////////////////////////////////////////// 03661 PT(NodePathComponent) PandaNode:: 03662 r_get_generic_component(bool accept_ambiguity, bool &ambiguity_detected, 03663 int pipeline_stage, Thread *current_thread) { 03664 PT(PandaNode) parent_node; 03665 03666 { 03667 CDStageReader cdata(_cycler, pipeline_stage, current_thread); 03668 03669 int num_parents = cdata->get_up()->size(); 03670 if (num_parents == 0) { 03671 // No parents; no ambiguity. This is the root. 03672 return get_top_component(this, true, pipeline_stage, current_thread); 03673 } 03674 03675 PT(NodePathComponent) result; 03676 if (num_parents == 1) { 03677 // Only one parent; no ambiguity. 03678 PT(NodePathComponent) parent = 03679 get_parent(0)->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread); 03680 return get_component(parent, this, pipeline_stage, current_thread); 03681 } 03682 03683 // Oops, multiple parents; the NodePath is ambiguous. 03684 if (!accept_ambiguity) { 03685 pgraph_cat.warning() 03686 << *this << " has " << num_parents 03687 << " parents; choosing arbitrary path to root.\n"; 03688 } 03689 ambiguity_detected = true; 03690 CPT(Up) up = cdata->get_up(); 03691 parent_node = (*up)[0].get_parent(); 03692 } 03693 03694 // Now that the lock is released, it's safe to recurse. 03695 PT(NodePathComponent) parent = 03696 parent_node->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread); 03697 return get_component(parent, this, pipeline_stage, current_thread); 03698 } 03699 03700 //////////////////////////////////////////////////////////////////// 03701 // Function: PandaNode::delete_component 03702 // Access: Private 03703 // Description: Removes a NodePathComponent from the set prior to 03704 // its deletion. This should only be called by the 03705 // NodePathComponent destructor. 03706 //////////////////////////////////////////////////////////////////// 03707 void PandaNode:: 03708 delete_component(NodePathComponent *component) { 03709 LightReMutexHolder holder(_paths_lock); 03710 int num_erased = _paths.erase(component); 03711 nassertv(num_erased == 1); 03712 } 03713 03714 //////////////////////////////////////////////////////////////////// 03715 // Function: PandaNode::sever_connection 03716 // Access: Private, Static 03717 // Description: This is called internally when a parent-child 03718 // connection is broken to update the NodePathComponents 03719 // that reflected this connection. 03720 // 03721 // It severs any NodePathComponents on the child node 03722 // that reference the indicated parent node. These 03723 // components remain unattached; there may therefore be 03724 // multiple "instances" of a node that all have no 03725 // parent, even while there are other instances that do 03726 // have parents. 03727 // 03728 // This operation is not automatically propagated 03729 // upstream. It is applied to the indicated pipeline 03730 // stage only. 03731 //////////////////////////////////////////////////////////////////// 03732 void PandaNode:: 03733 sever_connection(PandaNode *parent_node, PandaNode *child_node, 03734 int pipeline_stage, Thread *current_thread) { 03735 { 03736 LightReMutexHolder holder(child_node->_paths_lock); 03737 Paths::iterator pi; 03738 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) { 03739 if (!(*pi)->is_top_node(pipeline_stage, current_thread) && 03740 (*pi)->get_next(pipeline_stage, current_thread)->get_node() == parent_node) { 03741 // Sever the component here. 03742 (*pi)->set_top_node(pipeline_stage, current_thread); 03743 } 03744 } 03745 } 03746 child_node->fix_path_lengths(pipeline_stage, current_thread); 03747 } 03748 03749 //////////////////////////////////////////////////////////////////// 03750 // Function: PandaNode::new_connection 03751 // Access: Private, Static 03752 // Description: This is called internally when a parent-child 03753 // connection is established to update the 03754 // NodePathComponents that might be involved. 03755 // 03756 // It adjusts any NodePathComponents the child has that 03757 // reference the child as a top node. Any other 03758 // components we can leave alone, because we are making 03759 // a new instance of the child. 03760 // 03761 // This operation is not automatically propagated 03762 // upstream. It is applied to the indicated pipeline 03763 // stage only. 03764 //////////////////////////////////////////////////////////////////// 03765 void PandaNode:: 03766 new_connection(PandaNode *parent_node, PandaNode *child_node, 03767 int pipeline_stage, Thread *current_thread) { 03768 { 03769 LightReMutexHolder holder(child_node->_paths_lock); 03770 Paths::iterator pi; 03771 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) { 03772 if ((*pi)->is_top_node(pipeline_stage, current_thread)) { 03773 (*pi)->set_next(parent_node->get_generic_component(false, pipeline_stage, current_thread), pipeline_stage, current_thread); 03774 } 03775 } 03776 } 03777 child_node->fix_path_lengths(pipeline_stage, current_thread); 03778 } 03779 03780 //////////////////////////////////////////////////////////////////// 03781 // Function: PandaNode::fix_path_lengths 03782 // Access: Private 03783 // Description: Recursively fixes the _length member of each 03784 // NodePathComponent at this level and below, after an 03785 // add or delete child operation that might have messed 03786 // these up. 03787 // 03788 // This operation is not automatically propagated 03789 // upstream. It is applied to the indicated pipeline 03790 // stage only. 03791 //////////////////////////////////////////////////////////////////// 03792 void PandaNode:: 03793 fix_path_lengths(int pipeline_stage, Thread *current_thread) { 03794 LightReMutexHolder holder(_paths_lock); 03795 03796 bool any_wrong = false; 03797 03798 Paths::const_iterator pi; 03799 for (pi = _paths.begin(); pi != _paths.end(); ++pi) { 03800 if ((*pi)->fix_length(pipeline_stage, current_thread)) { 03801 any_wrong = true; 03802 } 03803 } 03804 03805 // If any paths were updated, we have to recurse on all of our 03806 // children, since any one of those paths might be shared by any of 03807 // our child nodes. Don't hold any locks while we recurse. 03808 if (any_wrong) { 03809 Children children; 03810 Stashed stashed; 03811 { 03812 CDStageReader cdata(_cycler, pipeline_stage, current_thread); 03813 children = Children(cdata); 03814 stashed = Stashed(cdata); 03815 } 03816 03817 int num_children = children.get_num_children(); 03818 int i; 03819 for (i = 0; i < num_children; ++i) { 03820 PandaNode *child_node = children.get_child(i); 03821 child_node->fix_path_lengths(pipeline_stage, current_thread); 03822 } 03823 int num_stashed = stashed.get_num_stashed(); 03824 for (i = 0; i < num_stashed; ++i) { 03825 PandaNode *child_node = stashed.get_stashed(i); 03826 child_node->fix_path_lengths(pipeline_stage, current_thread); 03827 } 03828 } 03829 } 03830 03831 //////////////////////////////////////////////////////////////////// 03832 // Function: PandaNode::r_list_descendants 03833 // Access: Private 03834 // Description: The recursive implementation of ls(). 03835 //////////////////////////////////////////////////////////////////// 03836 void PandaNode:: 03837 r_list_descendants(ostream &out, int indent_level) const { 03838 write(out, indent_level); 03839 03840 Children children = get_children(); 03841 int num_children = children.get_num_children(); 03842 03843 for (int i = 0; i < num_children; ++i) { 03844 PandaNode *child = children.get_child(i); 03845 child->r_list_descendants(out, indent_level + 2); 03846 } 03847 03848 // Also report the number of stashed nodes at this level. 03849 int num_stashed = get_num_stashed(); 03850 if (num_stashed != 0) { 03851 indent(out, indent_level) << "(" << num_stashed << " stashed)\n"; 03852 } 03853 } 03854 03855 //////////////////////////////////////////////////////////////////// 03856 // Function: PandaNode::do_find_child 03857 // Access: Private 03858 // Description: The private implementation of find_child(). 03859 //////////////////////////////////////////////////////////////////// 03860 int PandaNode:: 03861 do_find_child(PandaNode *node, const PandaNode::Down *down) const { 03862 nassertr(node != (PandaNode *)NULL, -1); 03863 03864 // We have to search for the child by brute force, since we don't 03865 // know what sort index it was added as. 03866 Down::const_iterator di; 03867 for (di = down->begin(); di != down->end(); ++di) { 03868 if ((*di).get_child() == node) { 03869 return di - down->begin(); 03870 } 03871 } 03872 03873 return -1; 03874 } 03875 03876 //////////////////////////////////////////////////////////////////// 03877 // Function: PandaNode::update_bounds 03878 // Access: Private 03879 // Description: Updates the cached values of the node that are 03880 // dependent on its children, such as the 03881 // external bounding volume, the _net_collide_mask, and 03882 // the _off_clip_planes. 03883 // 03884 // The old value should be passed in; it will be 03885 // released. The new value is returned. 03886 //////////////////////////////////////////////////////////////////// 03887 PandaNode::CDStageWriter PandaNode:: 03888 update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) { 03889 // We might need to try this a couple of times, in case someone else 03890 // steps on our result. 03891 if (drawmask_cat.is_debug()) { 03892 drawmask_cat.debug(false) 03893 << *this << "::update_bounds() {\n"; 03894 } 03895 Thread *current_thread = cdata.get_current_thread(); 03896 03897 do { 03898 // Grab the last_update counter. 03899 UpdateSeq last_update = cdata->_last_update; 03900 UpdateSeq next_update = cdata->_next_update; 03901 nassertr(last_update != next_update, CDStageWriter(_cycler, pipeline_stage, cdata)); 03902 03903 // Start with a clean slate. 03904 CollideMask net_collide_mask = cdata->_into_collide_mask; 03905 DrawMask net_draw_control_mask, net_draw_show_mask; 03906 bool renderable = is_renderable(); 03907 03908 if (renderable) { 03909 // If this node is itself renderable, it contributes to the net 03910 // draw mask. 03911 net_draw_control_mask = cdata->_draw_control_mask; 03912 net_draw_show_mask = cdata->_draw_show_mask; 03913 } 03914 03915 if (drawmask_cat.is_debug()) { 03916 drawmask_cat.debug(false) 03917 << "net_draw_control_mask = " << net_draw_control_mask 03918 << "\nnet_draw_show_mask = " << net_draw_show_mask 03919 << "\n"; 03920 } 03921 CPT(RenderAttrib) off_clip_planes = cdata->_state->get_attrib(ClipPlaneAttrib::get_class_slot()); 03922 if (off_clip_planes == (RenderAttrib *)NULL) { 03923 off_clip_planes = ClipPlaneAttrib::make(); 03924 } 03925 03926 // Also get the list of the node's children. 03927 Children children(cdata); 03928 03929 int num_vertices = cdata->_internal_vertices; 03930 03931 // Now that we've got all the data we need from the node, we can 03932 // release the lock. 03933 _cycler.release_read_stage(pipeline_stage, cdata.take_pointer()); 03934 03935 int num_children = children.get_num_children(); 03936 03937 // We need to keep references to the bounding volumes, since in a 03938 // threaded environment the pointers might go away while we're 03939 // working (since we're not holding a lock on our set of children 03940 // right now). But we also need the regular pointers, to pass to 03941 // BoundingVolume::around(). 03942 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 03943 pvector<CPT(BoundingVolume) > child_volumes_ref; 03944 child_volumes_ref.reserve(num_children + 1); 03945 #endif 03946 const BoundingVolume **child_volumes = (const BoundingVolume **)alloca(sizeof(BoundingVolume *) * (num_children + 1)); 03947 int child_volumes_i = 0; 03948 03949 bool all_box = true; 03950 CPT(BoundingVolume) internal_bounds = 03951 get_internal_bounds(pipeline_stage, current_thread); 03952 03953 if (!internal_bounds->is_empty()) { 03954 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 03955 child_volumes_ref.push_back(internal_bounds); 03956 #endif 03957 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata)); 03958 child_volumes[child_volumes_i++] = internal_bounds; 03959 if (internal_bounds->as_bounding_box() == NULL) { 03960 all_box = false; 03961 } 03962 } 03963 03964 // Now expand those contents to include all of our children. 03965 03966 for (int i = 0; i < num_children; ++i) { 03967 PandaNode *child = children.get_child(i); 03968 03969 const ClipPlaneAttrib *orig_cp = DCAST(ClipPlaneAttrib, off_clip_planes); 03970 03971 CDLockedStageReader child_cdata(child->_cycler, pipeline_stage, current_thread); 03972 if (child_cdata->_last_update != child_cdata->_next_update) { 03973 // Child needs update. 03974 CDStageWriter child_cdataw = child->update_bounds(pipeline_stage, child_cdata); 03975 03976 net_collide_mask |= child_cdataw->_net_collide_mask; 03977 03978 if (drawmask_cat.is_debug()) { 03979 drawmask_cat.debug(false) 03980 << "\nchild update " << *child << ":\n"; 03981 } 03982 03983 DrawMask child_control_mask = child_cdataw->_net_draw_control_mask; 03984 DrawMask child_show_mask = child_cdataw->_net_draw_show_mask; 03985 if (!(child_control_mask | child_show_mask).is_zero()) { 03986 // This child includes a renderable node or subtree. Thus, 03987 // we should propagate its draw masks. 03988 renderable = true; 03989 03990 // For each bit position in the masks, we have assigned the 03991 // following semantic meaning. The number on the left 03992 // represents the pairing of the corresponding bit from the 03993 // control mask and from the show mask: 03994 03995 // 00 : not a renderable node (control 0, show 0) 03996 // 01 : a normally visible node (control 0, show 1) 03997 // 10 : a hidden node (control 1, show 0) 03998 // 11 : a show-through node (control 1, show 1) 03999 04000 // Now, when we accumulate these masks, we want to do so 04001 // according to the following table, for each bit position: 04002 04003 // 00 01 10 11 (child) 04004 // --------------------- 04005 // 00 | 00 01 10 11 04006 // 01 | 01 01 01* 11 04007 // 10 | 10 01* 10 11 04008 // 11 | 11 11 11 11 04009 // (parent) 04010 04011 // This table is almost the same as the union of both masks, 04012 // with one exception, marked with a * in the above table: 04013 // if one is 10 and the other is 01--that is, one is hidden 04014 // and the other is normally visible--then the result should 04015 // be 01, normally visible. This is because we only want to 04016 // propagate the hidden bit upwards if *all* renderable 04017 // nodes are hidden. 04018 04019 // Get the set of exception bits for which the above rule 04020 // applies. These are the bits for which both bits have 04021 // flipped, but which were not the same in the original. 04022 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask); 04023 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask); 04024 04025 if (drawmask_cat.is_debug()) { 04026 drawmask_cat.debug(false) 04027 << "exception_mask = " << exception_mask << "\n"; 04028 } 04029 04030 // Now compute the union, applying the above exception. 04031 net_draw_control_mask |= child_control_mask; 04032 net_draw_show_mask |= child_show_mask; 04033 04034 net_draw_control_mask &= ~exception_mask; 04035 net_draw_show_mask |= exception_mask; 04036 } 04037 04038 if (drawmask_cat.is_debug()) { 04039 drawmask_cat.debug(false) 04040 << "child_control_mask = " << child_control_mask 04041 << "\nchild_show_mask = " << child_show_mask 04042 << "\nnet_draw_control_mask = " << net_draw_control_mask 04043 << "\nnet_draw_show_mask = " << net_draw_show_mask 04044 << "\n"; 04045 } 04046 04047 off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes); 04048 if (!child_cdataw->_external_bounds->is_empty()) { 04049 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 04050 child_volumes_ref.push_back(child_cdataw->_external_bounds); 04051 #endif 04052 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata)); 04053 child_volumes[child_volumes_i++] = child_cdataw->_external_bounds; 04054 if (child_cdataw->_external_bounds->as_bounding_box() == NULL) { 04055 all_box = false; 04056 } 04057 } 04058 num_vertices += child_cdataw->_nested_vertices; 04059 04060 } else { 04061 // Child is good. 04062 net_collide_mask |= child_cdata->_net_collide_mask; 04063 04064 // See comments in similar block above. 04065 if (drawmask_cat.is_debug()) { 04066 drawmask_cat.debug(false) 04067 << "\nchild fresh " << *child << ":\n"; 04068 } 04069 DrawMask child_control_mask = child_cdata->_net_draw_control_mask; 04070 DrawMask child_show_mask = child_cdata->_net_draw_show_mask; 04071 if (!(child_control_mask | child_show_mask).is_zero()) { 04072 renderable = true; 04073 04074 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask); 04075 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask); 04076 04077 if (drawmask_cat.is_debug()) { 04078 drawmask_cat.debug(false) 04079 << "exception_mask = " << exception_mask << "\n"; 04080 } 04081 04082 // Now compute the union, applying the above exception. 04083 net_draw_control_mask |= child_control_mask; 04084 net_draw_show_mask |= child_show_mask; 04085 04086 net_draw_control_mask &= ~exception_mask; 04087 net_draw_show_mask |= exception_mask; 04088 } 04089 04090 if (drawmask_cat.is_debug()) { 04091 drawmask_cat.debug(false) 04092 << "child_control_mask = " << child_control_mask 04093 << "\nchild_show_mask = " << child_show_mask 04094 << "\nnet_draw_control_mask = " << net_draw_control_mask 04095 << "\nnet_draw_show_mask = " << net_draw_show_mask 04096 << "\n"; 04097 } 04098 04099 off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes); 04100 if (!child_cdata->_external_bounds->is_empty()) { 04101 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 04102 child_volumes_ref.push_back(child_cdata->_external_bounds); 04103 #endif 04104 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata)); 04105 child_volumes[child_volumes_i++] = child_cdata->_external_bounds; 04106 if (child_cdata->_external_bounds->as_bounding_box() == NULL) { 04107 all_box = false; 04108 } 04109 } 04110 num_vertices += child_cdata->_nested_vertices; 04111 } 04112 } 04113 04114 { 04115 // Now grab the write lock on this node. 04116 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread); 04117 if (last_update == cdataw->_last_update && 04118 next_update == cdataw->_next_update) { 04119 // Great, no one has monkeyed with these while we were computing 04120 // the cache. Safe to store the computed values and return. 04121 cdataw->_net_collide_mask = net_collide_mask; 04122 04123 if (renderable) { 04124 // Any explicit draw control mask on this node trumps anything 04125 // inherited from below, except a show-through. 04126 DrawMask draw_control_mask = cdataw->_draw_control_mask; 04127 DrawMask draw_show_mask = cdataw->_draw_show_mask; 04128 04129 DrawMask show_through_mask = net_draw_control_mask & net_draw_show_mask; 04130 04131 net_draw_control_mask |= draw_control_mask; 04132 net_draw_show_mask = (net_draw_show_mask & ~draw_control_mask) | (draw_show_mask & draw_control_mask); 04133 04134 net_draw_show_mask |= show_through_mask; 04135 04136 // There are renderable nodes below, so the implicit draw 04137 // bits are all on. 04138 cdataw->_net_draw_control_mask = net_draw_control_mask; 04139 cdataw->_net_draw_show_mask = net_draw_show_mask | ~net_draw_control_mask; 04140 if (drawmask_cat.is_debug()) { 04141 drawmask_cat.debug(false) 04142 << "renderable, set mask " << cdataw->_net_draw_show_mask << "\n"; 04143 } 04144 } else { 04145 // There are no renderable nodes below, so the implicit draw 04146 // bits are all off. Also, we don't care about the draw 04147 // mask on this particular node (since nothing below it is 04148 // renderable anyway). 04149 cdataw->_net_draw_control_mask = net_draw_control_mask; 04150 cdataw->_net_draw_show_mask = net_draw_show_mask; 04151 if (drawmask_cat.is_debug()) { 04152 drawmask_cat.debug(false) 04153 << "not renderable, set mask " << cdataw->_net_draw_show_mask << "\n"; 04154 } 04155 } 04156 04157 cdataw->_off_clip_planes = off_clip_planes; 04158 cdataw->_nested_vertices = num_vertices; 04159 04160 CPT(TransformState) transform = get_transform(current_thread); 04161 PT(GeometricBoundingVolume) gbv; 04162 04163 BoundingVolume::BoundsType btype = cdataw->_bounds_type; 04164 if (btype == BoundingVolume::BT_default) { 04165 btype = bounds_type; 04166 } 04167 04168 if (btype == BoundingVolume::BT_box || 04169 (btype != BoundingVolume::BT_sphere && all_box && transform->is_identity())) { 04170 // If all of the child volumes are a BoundingBox, and we 04171 // have no transform, then our volume is also a 04172 // BoundingBox. 04173 04174 gbv = new BoundingBox; 04175 } else { 04176 // Otherwise, it's a sphere. 04177 gbv = new BoundingSphere; 04178 } 04179 04180 if (child_volumes_i > 0) { 04181 const BoundingVolume **child_begin = &child_volumes[0]; 04182 const BoundingVolume **child_end = child_begin + child_volumes_i; 04183 ((BoundingVolume *)gbv)->around(child_begin, child_end); 04184 } 04185 04186 // If we have a transform, apply it to the bounding volume we 04187 // just computed. 04188 if (!transform->is_identity()) { 04189 gbv->xform(transform->get_mat()); 04190 } 04191 04192 cdataw->_external_bounds = gbv; 04193 cdataw->_last_update = next_update; 04194 04195 if (drawmask_cat.is_debug()) { 04196 drawmask_cat.debug(false) 04197 << "} " << *this << "::update_bounds();\n"; 04198 } 04199 04200 nassertr(cdataw->_last_update == cdataw->_next_update, cdataw); 04201 04202 // Even though implicit bounding volume is not (yet?) part of 04203 // the bam stream. 04204 mark_bam_modified(); 04205 return cdataw; 04206 } 04207 04208 if (cdataw->_last_update == cdataw->_next_update) { 04209 // Someone else has computed the cache for us. OK. 04210 return cdataw; 04211 } 04212 } 04213 04214 // We need to go around again. Release the write lock, and grab 04215 // the read lock back. 04216 cdata = CDLockedStageReader(_cycler, pipeline_stage, current_thread); 04217 04218 if (cdata->_last_update == cdata->_next_update) { 04219 // Someone else has computed the cache for us while we were 04220 // diddling with the locks. OK. 04221 return CDStageWriter(_cycler, pipeline_stage, cdata); 04222 } 04223 04224 } while (true); 04225 } 04226 04227 //////////////////////////////////////////////////////////////////// 04228 // Function: PandaNode::set_scene_root_func 04229 // Access: Public, Static 04230 // Description: This is used by the GraphicsEngine to hook in a 04231 // pointer to the scene_root_func(), the function to 04232 // determine whether the node is an active scene root. 04233 // This back-pointer is necessary because we can't make 04234 // calls directly into GraphicsEngine, which is in the 04235 // display module. 04236 //////////////////////////////////////////////////////////////////// 04237 void PandaNode:: 04238 set_scene_root_func(SceneRootFunc *func) { 04239 _scene_root_func = func; 04240 } 04241 04242 //////////////////////////////////////////////////////////////////// 04243 // Function: PandaNode::register_with_read_factory 04244 // Access: Public, Static 04245 // Description: Tells the BamReader how to create objects of type 04246 // PandaNode. 04247 //////////////////////////////////////////////////////////////////// 04248 void PandaNode:: 04249 register_with_read_factory() { 04250 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 04251 } 04252 04253 //////////////////////////////////////////////////////////////////// 04254 // Function: PandaNode::write_datagram 04255 // Access: Public, Virtual 04256 // Description: Writes the contents of this object to the datagram 04257 // for shipping out to a Bam file. 04258 //////////////////////////////////////////////////////////////////// 04259 void PandaNode:: 04260 write_datagram(BamWriter *manager, Datagram &dg) { 04261 TypedWritable::write_datagram(manager, dg); 04262 dg.add_string(get_name()); 04263 04264 manager->write_cdata(dg, _cycler); 04265 } 04266 04267 //////////////////////////////////////////////////////////////////// 04268 // Function: PandaNode::update_bam_nested 04269 // Access: Public, Virtual 04270 // Description: Called by the BamWriter when this object has not 04271 // itself been modified recently, but it should check 04272 // its nested objects for updates. 04273 //////////////////////////////////////////////////////////////////// 04274 void PandaNode:: 04275 update_bam_nested(BamWriter *manager) { 04276 CDReader cdata(_cycler); 04277 cdata->update_bam_nested(manager); 04278 } 04279 04280 //////////////////////////////////////////////////////////////////// 04281 // Function: PandaNode::write_recorder 04282 // Access: Public 04283 // Description: This method is provided for the benefit of classes 04284 // (like MouseRecorder) that inherit from PandaMode and 04285 // also RecorderBase. It's not virtual at this level 04286 // since it doesn't need to be (it's called up from the 04287 // derived class). 04288 // 04289 // This method acts very like write_datagram, but it 04290 // writes the node as appropriate for writing a 04291 // RecorderBase object as described in the beginning of 04292 // a session file, meaning it doesn't need to write 04293 // things such as children. It balances with 04294 // fillin_recorder(). 04295 //////////////////////////////////////////////////////////////////// 04296 void PandaNode:: 04297 write_recorder(BamWriter *, Datagram &dg) { 04298 dg.add_string(get_name()); 04299 } 04300 04301 //////////////////////////////////////////////////////////////////// 04302 // Function: PandaNode::make_from_bam 04303 // Access: Protected, Static 04304 // Description: This function is called by the BamReader's factory 04305 // when a new object of type PandaNode is encountered 04306 // in the Bam file. It should create the PandaNode 04307 // and extract its information from the file. 04308 //////////////////////////////////////////////////////////////////// 04309 TypedWritable *PandaNode:: 04310 make_from_bam(const FactoryParams ¶ms) { 04311 PandaNode *node = new PandaNode(""); 04312 DatagramIterator scan; 04313 BamReader *manager; 04314 04315 parse_params(params, scan, manager); 04316 node->fillin(scan, manager); 04317 04318 return node; 04319 } 04320 04321 //////////////////////////////////////////////////////////////////// 04322 // Function: PandaNode::fillin 04323 // Access: Protected 04324 // Description: This internal function is called by make_from_bam to 04325 // read in all of the relevant data from the BamFile for 04326 // the new PandaNode. 04327 //////////////////////////////////////////////////////////////////// 04328 void PandaNode:: 04329 fillin(DatagramIterator &scan, BamReader *manager) { 04330 TypedWritable::fillin(scan, manager); 04331 04332 string name = scan.get_string(); 04333 set_name(name); 04334 04335 manager->read_cdata(scan, _cycler); 04336 } 04337 04338 //////////////////////////////////////////////////////////////////// 04339 // Function: PandaNode::fillin_recorder 04340 // Access: Protected 04341 // Description: This internal function is called by make_recorder (in 04342 // classes derived from RecorderBase, such as 04343 // MouseRecorder) to read in all of the relevant data 04344 // from the session file. It balances with 04345 // write_recorder(). 04346 //////////////////////////////////////////////////////////////////// 04347 void PandaNode:: 04348 fillin_recorder(DatagramIterator &scan, BamReader *) { 04349 string name = scan.get_string(); 04350 set_name(name); 04351 } 04352 04353 //////////////////////////////////////////////////////////////////// 04354 // Function: PandaNode::CData::Constructor 04355 // Access: Public 04356 // Description: 04357 //////////////////////////////////////////////////////////////////// 04358 PandaNode::CData:: 04359 CData() : 04360 _state(RenderState::make_empty()), 04361 _transform(TransformState::make_identity()), 04362 _prev_transform(TransformState::make_identity()), 04363 04364 _effects(RenderEffects::make_empty()), 04365 _draw_control_mask(DrawMask::all_off()), 04366 _draw_show_mask(DrawMask::all_on()), 04367 _into_collide_mask(CollideMask::all_off()), 04368 _bounds_type(BoundingVolume::BT_default), 04369 _user_bounds(NULL), 04370 _final_bounds(false), 04371 _fancy_bits(0), 04372 04373 _net_collide_mask(CollideMask::all_off()), 04374 _net_draw_control_mask(DrawMask::all_off()), 04375 _net_draw_show_mask(DrawMask::all_off()), 04376 04377 _down(new PandaNode::Down(PandaNode::get_class_type())), 04378 _stashed(new PandaNode::Down(PandaNode::get_class_type())), 04379 _up(new PandaNode::Up(PandaNode::get_class_type())) 04380 { 04381 ++_next_update; 04382 } 04383 04384 //////////////////////////////////////////////////////////////////// 04385 // Function: PandaNode::CData::Copy Constructor 04386 // Access: Public 04387 // Description: 04388 //////////////////////////////////////////////////////////////////// 04389 PandaNode::CData:: 04390 CData(const PandaNode::CData ©) : 04391 BoundsData(copy), 04392 _state(copy._state), 04393 _transform(copy._transform), 04394 _prev_transform(copy._prev_transform), 04395 04396 _effects(copy._effects), 04397 _tag_data(copy._tag_data), 04398 _draw_control_mask(copy._draw_control_mask), 04399 _draw_show_mask(copy._draw_show_mask), 04400 _into_collide_mask(copy._into_collide_mask), 04401 _bounds_type(copy._bounds_type), 04402 _user_bounds(copy._user_bounds), 04403 _final_bounds(copy._final_bounds), 04404 _fancy_bits(copy._fancy_bits), 04405 04406 _net_collide_mask(copy._net_collide_mask), 04407 _net_draw_control_mask(copy._net_draw_control_mask), 04408 _net_draw_show_mask(copy._net_draw_show_mask), 04409 _off_clip_planes(copy._off_clip_planes), 04410 _nested_vertices(copy._nested_vertices), 04411 _external_bounds(copy._external_bounds), 04412 _last_update(copy._last_update), 04413 _next_update(copy._next_update), 04414 04415 _down(copy._down), 04416 _stashed(copy._stashed), 04417 _up(copy._up) 04418 { 04419 // Note that this copy constructor is not used by the PandaNode copy 04420 // constructor! Any elements that must be copied between nodes 04421 // should also be explicitly copied there. 04422 04423 #ifdef HAVE_PYTHON 04424 // Copy and increment all of the Python objects held by the other 04425 // node. 04426 _python_tag_data = _python_tag_data; 04427 inc_py_refs(); 04428 #endif // HAVE_PYTHON 04429 } 04430 04431 //////////////////////////////////////////////////////////////////// 04432 // Function: PandaNode::CData::Destructor 04433 // Access: Public, Virtual 04434 // Description: 04435 //////////////////////////////////////////////////////////////////// 04436 PandaNode::CData:: 04437 ~CData() { 04438 #ifdef HAVE_PYTHON 04439 // Free all of the Python objects held by this node. 04440 dec_py_refs(); 04441 #endif // HAVE_PYTHON 04442 } 04443 04444 //////////////////////////////////////////////////////////////////// 04445 // Function: PandaNode::CData::make_copy 04446 // Access: Public, Virtual 04447 // Description: 04448 //////////////////////////////////////////////////////////////////// 04449 CycleData *PandaNode::CData:: 04450 make_copy() const { 04451 return new CData(*this); 04452 } 04453 04454 //////////////////////////////////////////////////////////////////// 04455 // Function: PandaNode::CData::write_datagram 04456 // Access: Public, Virtual 04457 // Description: Writes the contents of this object to the datagram 04458 // for shipping out to a Bam file. 04459 //////////////////////////////////////////////////////////////////// 04460 void PandaNode::CData:: 04461 write_datagram(BamWriter *manager, Datagram &dg) const { 04462 manager->write_pointer(dg, _state); 04463 manager->write_pointer(dg, _transform); 04464 04465 // 04466 manager->write_pointer(dg, _effects); 04467 04468 dg.add_uint32(_draw_control_mask.get_word()); 04469 dg.add_uint32(_draw_show_mask.get_word()); 04470 dg.add_uint32(_into_collide_mask.get_word()); 04471 dg.add_uint8(_bounds_type); 04472 04473 dg.add_uint32(_tag_data.size()); 04474 TagData::const_iterator ti; 04475 for (ti = _tag_data.begin(); ti != _tag_data.end(); ++ti) { 04476 dg.add_string((*ti).first); 04477 dg.add_string((*ti).second); 04478 } 04479 04480 // 04481 write_up_list(*get_up(), manager, dg); 04482 write_down_list(*get_down(), manager, dg); 04483 write_down_list(*get_stashed(), manager, dg); 04484 } 04485 04486 //////////////////////////////////////////////////////////////////// 04487 // Function: PandaNode::CData::update_bam_nested 04488 // Access: Public 04489 // Description: Called by the BamWriter when this object has not 04490 // itself been modified recently, but it should check 04491 // its nested objects for updates. 04492 //////////////////////////////////////////////////////////////////// 04493 void PandaNode::CData:: 04494 update_bam_nested(BamWriter *manager) const { 04495 // No need to check the state pointers for updates, since they're 04496 // all immutable objects. 04497 //manager->consider_update(_state); 04498 //manager->consider_update(_transform); 04499 //manager->consider_update(_effects); 04500 04501 update_up_list(*get_up(), manager); 04502 update_down_list(*get_down(), manager); 04503 update_down_list(*get_stashed(), manager); 04504 } 04505 04506 //////////////////////////////////////////////////////////////////// 04507 // Function: PandaNode::CData::complete_pointers 04508 // Access: Public, Virtual 04509 // Description: Receives an array of pointers, one for each time 04510 // manager->read_pointer() was called in fillin(). 04511 // Returns the number of pointers processed. 04512 //////////////////////////////////////////////////////////////////// 04513 int PandaNode::CData:: 04514 complete_pointers(TypedWritable **p_list, BamReader *manager) { 04515 int pi = CycleData::complete_pointers(p_list, manager); 04516 04517 // Get the state and transform pointers. 04518 _state = DCAST(RenderState, p_list[pi++]); 04519 _transform = DCAST(TransformState, p_list[pi++]); 04520 _prev_transform = _transform; 04521 04522 // Finalize these pointers now to decrement their artificially-held 04523 // reference counts. We do this now, rather than later, in case 04524 // some other object reassigns them a little later on during 04525 // initialization, before they can finalize themselves normally (for 04526 // instance, the character may change the node's transform). If 04527 // that happens, the pointer may discover that no one else holds its 04528 // reference count when it finalizes, which will constitute a memory 04529 // leak (see the comments in TransformState::finalize(), etc.). 04530 manager->finalize_now((RenderState *)_state.p()); 04531 manager->finalize_now((TransformState *)_transform.p()); 04532 04533 // 04534 04535 // Get the effects pointer. 04536 _effects = DCAST(RenderEffects, p_list[pi++]); 04537 04538 // Finalize these pointers now to decrement their artificially-held 04539 // reference counts. We do this now, rather than later, in case 04540 // some other object reassigns them a little later on during 04541 // initialization, before they can finalize themselves normally (for 04542 // instance, the character may change the node's transform). If 04543 // that happens, the pointer may discover that no one else holds its 04544 // reference count when it finalizes, which will constitute a memory 04545 // leak (see the comments in TransformState::finalize(), etc.). 04546 manager->finalize_now((RenderEffects *)_effects.p()); 04547 04548 // 04549 04550 // Get the parent and child pointers. 04551 pi += complete_up_list(*modify_up(), "up", p_list + pi, manager); 04552 pi += complete_down_list(*modify_down(), "down", p_list + pi, manager); 04553 pi += complete_down_list(*modify_stashed(), "stashed", p_list + pi, manager); 04554 04555 // Since the _effects and _states members have been finalized by 04556 // now, this should be safe. 04557 set_fancy_bit(FB_transform, !_transform->is_identity()); 04558 set_fancy_bit(FB_state, !_state->is_empty()); 04559 set_fancy_bit(FB_effects, !_effects->is_empty()); 04560 set_fancy_bit(FB_tag, !_tag_data.empty()); 04561 04562 return pi; 04563 } 04564 04565 //////////////////////////////////////////////////////////////////// 04566 // Function: PandaNode::CData::fillin 04567 // Access: Public, Virtual 04568 // Description: This internal function is called by make_from_bam to 04569 // read in all of the relevant data from the BamFile for 04570 // the new PandaNode. 04571 //////////////////////////////////////////////////////////////////// 04572 void PandaNode::CData:: 04573 fillin(DatagramIterator &scan, BamReader *manager) { 04574 // Read the state and transform pointers. 04575 manager->read_pointer(scan); 04576 manager->read_pointer(scan); 04577 04578 // 04579 // Read the effects pointer. 04580 manager->read_pointer(scan); 04581 04582 if (manager->get_file_minor_ver() < 2) { 04583 DrawMask draw_mask; 04584 draw_mask.set_word(scan.get_uint32()); 04585 04586 if (draw_mask == DrawMask::all_off()) { 04587 // Hidden. 04588 _draw_control_mask = _overall_bit; 04589 _draw_show_mask = ~_overall_bit; 04590 04591 } else if (draw_mask == DrawMask::all_on()) { 04592 // Normally visible. 04593 _draw_control_mask = DrawMask::all_off(); 04594 _draw_show_mask = DrawMask::all_on(); 04595 04596 } else { 04597 // Some per-camera combination. 04598 draw_mask &= ~_overall_bit; 04599 _draw_control_mask = ~draw_mask; 04600 _draw_show_mask = draw_mask; 04601 } 04602 04603 } else { 04604 _draw_control_mask.set_word(scan.get_uint32()); 04605 _draw_show_mask.set_word(scan.get_uint32()); 04606 } 04607 04608 _into_collide_mask.set_word(scan.get_uint32()); 04609 04610 _bounds_type = BoundingVolume::BT_default; 04611 if (manager->get_file_minor_ver() >= 19) { 04612 _bounds_type = (BoundingVolume::BoundsType)scan.get_uint8(); 04613 } 04614 04615 // Read in the tag list. 04616 int num_tags = scan.get_uint32(); 04617 for (int i = 0; i < num_tags; i++) { 04618 string key = scan.get_string(); 04619 string value = scan.get_string(); 04620 _tag_data[key] = value; 04621 } 04622 04623 // 04624 fillin_up_list(*modify_up(), "up", scan, manager); 04625 fillin_down_list(*modify_down(), "down", scan, manager); 04626 fillin_down_list(*modify_stashed(), "stashed", scan, manager); 04627 } 04628 04629 #ifdef HAVE_PYTHON 04630 //////////////////////////////////////////////////////////////////// 04631 // Function: PandaNode::CData::inc_py_refs 04632 // Access: Public 04633 // Description: Increments the reference counts on all held Python 04634 // objects. 04635 //////////////////////////////////////////////////////////////////// 04636 void PandaNode::CData:: 04637 inc_py_refs() { 04638 PythonTagData::const_iterator ti; 04639 for (ti = _python_tag_data.begin(); 04640 ti != _python_tag_data.end(); 04641 ++ti) { 04642 PyObject *value = (*ti).second; 04643 Py_XINCREF(value); 04644 } 04645 } 04646 #endif // HAVE_PYTHON 04647 04648 #ifdef HAVE_PYTHON 04649 //////////////////////////////////////////////////////////////////// 04650 // Function: PandaNode::CData::dec_py_refs 04651 // Access: Public 04652 // Description: Decrements the reference counts on all held Python 04653 // objects. 04654 //////////////////////////////////////////////////////////////////// 04655 void PandaNode::CData:: 04656 dec_py_refs() { 04657 PythonTagData::const_iterator ti; 04658 for (ti = _python_tag_data.begin(); 04659 ti != _python_tag_data.end(); 04660 ++ti) { 04661 PyObject *value = (*ti).second; 04662 Py_XDECREF(value); 04663 } 04664 } 04665 #endif // HAVE_PYTHON 04666 04667 //////////////////////////////////////////////////////////////////// 04668 // Function: PandaNode::CData::write_up_list 04669 // Access: Public 04670 // Description: Writes the indicated list of parent node pointers to 04671 // the datagram. 04672 //////////////////////////////////////////////////////////////////// 04673 void PandaNode::CData:: 04674 write_up_list(const PandaNode::Up &up_list, 04675 BamWriter *manager, Datagram &dg) const { 04676 // When we write a PandaNode, we write out its complete list of 04677 // child node pointers, but we only write out the parent node 04678 // pointers that have already been added to the bam file by a 04679 // previous write operation. This is a bit of trickery that allows 04680 // us to write out just a subgraph (instead of the complete graph) 04681 // when we write out an arbitrary node in the graph, yet also allows 04682 // us to keep nodes completely in sync when we use the bam format 04683 // for streaming scene graph operations over the network. 04684 04685 int num_parents = 0; 04686 Up::const_iterator ui; 04687 for (ui = up_list.begin(); ui != up_list.end(); ++ui) { 04688 PandaNode *parent_node = (*ui).get_parent(); 04689 if (manager->has_object(parent_node)) { 04690 num_parents++; 04691 } 04692 } 04693 nassertv(num_parents == (int)(PN_uint16)num_parents); 04694 dg.add_uint16(num_parents); 04695 for (ui = up_list.begin(); ui != up_list.end(); ++ui) { 04696 PandaNode *parent_node = (*ui).get_parent(); 04697 if (manager->has_object(parent_node)) { 04698 manager->write_pointer(dg, parent_node); 04699 } 04700 } 04701 } 04702 04703 //////////////////////////////////////////////////////////////////// 04704 // Function: PandaNode::CData::write_down_list 04705 // Access: Public 04706 // Description: Writes the indicated list of child node pointers to 04707 // the datagram. 04708 //////////////////////////////////////////////////////////////////// 04709 void PandaNode::CData:: 04710 write_down_list(const PandaNode::Down &down_list, 04711 BamWriter *manager, Datagram &dg) const { 04712 int num_children = down_list.size(); 04713 nassertv(num_children == (int)(PN_uint16)num_children); 04714 dg.add_uint16(num_children); 04715 04716 // Should we smarten up the writing of the sort number? Most of the 04717 // time these will all be zero. 04718 Down::const_iterator di; 04719 for (di = down_list.begin(); di != down_list.end(); ++di) { 04720 PandaNode *child_node = (*di).get_child(); 04721 int sort = (*di).get_sort(); 04722 manager->write_pointer(dg, child_node); 04723 dg.add_int32(sort); 04724 } 04725 } 04726 04727 //////////////////////////////////////////////////////////////////// 04728 // Function: PandaNode::CData::update_up_list 04729 // Access: Public 04730 // Description: Calls consider_update on each node of the indicated 04731 // up list. 04732 //////////////////////////////////////////////////////////////////// 04733 void PandaNode::CData:: 04734 update_up_list(const PandaNode::Up &up_list, BamWriter *manager) const { 04735 Up::const_iterator ui; 04736 for (ui = up_list.begin(); ui != up_list.end(); ++ui) { 04737 PandaNode *parent_node = (*ui).get_parent(); 04738 if (manager->has_object(parent_node)) { 04739 manager->consider_update(parent_node); 04740 } 04741 } 04742 } 04743 04744 //////////////////////////////////////////////////////////////////// 04745 // Function: PandaNode::CData::update_down_list 04746 // Access: Public 04747 // Description: Calls consider_update on each node of the indicated 04748 // up list. 04749 //////////////////////////////////////////////////////////////////// 04750 void PandaNode::CData:: 04751 update_down_list(const PandaNode::Down &down_list, BamWriter *manager) const { 04752 Down::const_iterator di; 04753 for (di = down_list.begin(); di != down_list.end(); ++di) { 04754 PandaNode *child_node = (*di).get_child(); 04755 manager->consider_update(child_node); 04756 } 04757 } 04758 04759 //////////////////////////////////////////////////////////////////// 04760 // Function: PandaNode::CData::complete_up_list 04761 // Access: Public 04762 // Description: Calls complete_pointers() on the list of parent node 04763 // pointers. 04764 //////////////////////////////////////////////////////////////////// 04765 int PandaNode::CData:: 04766 complete_up_list(PandaNode::Up &up_list, const string &tag, 04767 TypedWritable **p_list, BamReader *manager) { 04768 int pi = 0; 04769 04770 int num_parents = manager->get_int_tag(tag); 04771 Up new_up_list(PandaNode::get_class_type()); 04772 new_up_list.reserve(num_parents); 04773 for (int i = 0; i < num_parents; i++) { 04774 PandaNode *parent_node = DCAST(PandaNode, p_list[pi++]); 04775 UpConnection connection(parent_node); 04776 new_up_list.push_back(connection); 04777 } 04778 04779 // Now we should sort the list, since the sorting is based on 04780 // pointer order, which might be different from one session to the 04781 // next. 04782 new_up_list.sort(); 04783 04784 // Make it permanent. 04785 up_list.swap(new_up_list); 04786 new_up_list.clear(); 04787 04788 return pi; 04789 } 04790 04791 //////////////////////////////////////////////////////////////////// 04792 // Function: PandaNode::CData::complete_down_list 04793 // Access: Public 04794 // Description: Calls complete_pointers() on the list of child node 04795 // pointers. 04796 //////////////////////////////////////////////////////////////////// 04797 int PandaNode::CData:: 04798 complete_down_list(PandaNode::Down &down_list, const string &tag, 04799 TypedWritable **p_list, BamReader *manager) { 04800 int pi = 0; 04801 04802 BamReaderAuxDataDown *aux; 04803 DCAST_INTO_R(aux, manager->get_aux_tag(tag), pi); 04804 04805 Down &new_down_list = aux->_down_list; 04806 for (Down::iterator di = new_down_list.begin(); 04807 di != new_down_list.end(); 04808 ++di) { 04809 PandaNode *child_node = DCAST(PandaNode, p_list[pi++]); 04810 (*di).set_child(child_node); 04811 } 04812 04813 // Unlike the up list, we should *not* sort the down list. The down 04814 // list is stored in a specific order, not related to pointer order; 04815 // and this order should be preserved from one session to the next. 04816 04817 // Make it permanent. 04818 down_list.swap(new_down_list); 04819 new_down_list.clear(); 04820 04821 return pi; 04822 } 04823 04824 //////////////////////////////////////////////////////////////////// 04825 // Function: PandaNode::CData::fillin_up_list 04826 // Access: Public 04827 // Description: Reads the indicated list parent node pointers from 04828 // the datagram (or at least calls read_pointer() for 04829 // each one). 04830 //////////////////////////////////////////////////////////////////// 04831 void PandaNode::CData:: 04832 fillin_up_list(PandaNode::Up &up_list, const string &tag, 04833 DatagramIterator &scan, BamReader *manager) { 04834 int num_parents = scan.get_uint16(); 04835 manager->set_int_tag(tag, num_parents); 04836 manager->read_pointers(scan, num_parents); 04837 } 04838 04839 //////////////////////////////////////////////////////////////////// 04840 // Function: PandaNode::CData::fillin_down_list 04841 // Access: Public 04842 // Description: Reads the indicated list child node pointers from 04843 // the datagram (or at least calls read_pointer() for 04844 // each one). 04845 //////////////////////////////////////////////////////////////////// 04846 void PandaNode::CData:: 04847 fillin_down_list(PandaNode::Down &down_list, const string &tag, 04848 DatagramIterator &scan, BamReader *manager) { 04849 int num_children = scan.get_uint16(); 04850 04851 // Create a temporary down_list, with the right number of elements, 04852 // but a NULL value for each pointer (we'll fill in the pointers 04853 // later). We need to do this to associate the sort values with 04854 // their pointers. 04855 Down new_down_list(PandaNode::get_class_type()); 04856 new_down_list.reserve(num_children); 04857 for (int i = 0; i < num_children; i++) { 04858 manager->read_pointer(scan); 04859 int sort = scan.get_int32(); 04860 DownConnection connection(NULL, sort); 04861 new_down_list.push_back(connection); 04862 } 04863 04864 // Now store the temporary down_list in the BamReader, so we can get 04865 // it during the call to complete_down_list(). 04866 PT(BamReaderAuxDataDown) aux = new BamReaderAuxDataDown; 04867 aux->_down_list.swap(new_down_list); 04868 manager->set_aux_tag(tag, aux); 04869 } 04870 04871 //////////////////////////////////////////////////////////////////// 04872 // Function: PandaNodePipelineReader::check_bounds 04873 // Access: Public 04874 // Description: Ensures that the bounding volume is properly computed 04875 // on this node. 04876 //////////////////////////////////////////////////////////////////// 04877 void PandaNodePipelineReader:: 04878 check_bounds() const { 04879 if (_cdata->_last_update != _cdata->_next_update) { 04880 // The cache is stale; it needs to be rebuilt. 04881 04882 // We'll need to get a fresh read pointer, since another thread 04883 // might already have modified the pointer on the object since we 04884 // queried it. 04885 #ifdef DO_PIPELINING 04886 node_unref_delete((CycleData *)_cdata); 04887 #endif // DO_PIPELINING 04888 ((PandaNodePipelineReader *)this)->_cdata = NULL; 04889 int pipeline_stage = _current_thread->get_pipeline_stage(); 04890 PandaNode::CDLockedStageReader fresh_cdata(_object->_cycler, pipeline_stage, _current_thread); 04891 if (fresh_cdata->_last_update == fresh_cdata->_next_update) { 04892 // What luck, some other thread has already freshened the 04893 // cache for us. Save the new pointer, and let the lock 04894 // release itself. 04895 if (_cdata != (const PandaNode::CData *)fresh_cdata) { 04896 ((PandaNodePipelineReader *)this)->_cdata = fresh_cdata; 04897 #ifdef DO_PIPELINING 04898 _cdata->node_ref(); 04899 #endif // DO_PIPELINING 04900 } 04901 04902 } else { 04903 // No, the cache is still stale. We have to do the work of 04904 // freshening it. 04905 PStatTimer timer(PandaNode::_update_bounds_pcollector); 04906 PandaNode::CDStageWriter cdataw = ((PandaNode *)_object)->update_bounds(pipeline_stage, fresh_cdata); 04907 nassertv(cdataw->_last_update == cdataw->_next_update); 04908 // As above, we save the new pointer, and then let the lock 04909 // release itself. 04910 if (_cdata != (const PandaNode::CData *)cdataw) { 04911 ((PandaNodePipelineReader *)this)->_cdata = cdataw; 04912 #ifdef DO_PIPELINING 04913 _cdata->node_ref(); 04914 #endif // DO_PIPELINING 04915 } 04916 } 04917 } 04918 04919 nassertv(_cdata->_last_update == _cdata->_next_update); 04920 }