// Filename: nodePathComponent.cxx // Created by: drose (25Feb02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license // along with this source code; you will also find a current copy of // the license at http://etc.cmu.edu/panda3d/docs/license/ . // // To contact the maintainers of this program write to // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// #include "nodePathComponent.h" #include "mutexHolder.h" // We start the key counters off at 1, since 0 is reserved for an // empty NodePath (and also for an unassigned key). int NodePathComponent::_next_key = 1; Mutex NodePathComponent::_key_lock("NodePathComponent::_key_lock"); TypeHandle NodePathComponent::_type_handle; //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::CData::make_copy // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// CycleData *NodePathComponent::CData:: make_copy() const { return new CData(*this); } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::Constructor // Access: Private // Description: Constructs a new NodePathComponent from the // indicated node. Don't try to call this directly; ask // the PandaNode to do it for you. //////////////////////////////////////////////////////////////////// NodePathComponent:: NodePathComponent(PandaNode *node, NodePathComponent *next, int pipeline_stage, Thread *current_thread) : _node(node), _key(0) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif for (int pipeline_stage_i = pipeline_stage; pipeline_stage_i >= 0; --pipeline_stage_i) { CDStageWriter cdata(_cycler, pipeline_stage_i, current_thread); cdata->_next = next; if (next != (NodePathComponent *)NULL) { cdata->_length = next->get_length(pipeline_stage_i, current_thread) + 1; } } } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::get_key // Access: Public // Description: Returns an index number that is guaranteed to be // unique for this particular NodePathComponent, and not // to be reused for the lifetime of the application // (barring integer overflow). //////////////////////////////////////////////////////////////////// int NodePathComponent:: get_key() const { MutexHolder holder(_key_lock); if (_key == 0) { // The first time someone asks for a particular component's key, // we make it up on the spot. This helps keep us from wasting // index numbers generating a unique number for *every* component // in the world (we only have 4.2 billion 32-bit integers, after // all) ((NodePathComponent *)this)->_key = _next_key++; } return _key; } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::is_top_node // Access: Public // Description: Returns true if this component represents the top // node in the path. //////////////////////////////////////////////////////////////////// bool NodePathComponent:: is_top_node(int pipeline_stage, Thread *current_thread) const { CDStageReader cdata(_cycler, pipeline_stage, current_thread); return (cdata->_next == (NodePathComponent *)NULL); } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::get_length // Access: Public // Description: Returns the length of the path to this node. //////////////////////////////////////////////////////////////////// int NodePathComponent:: get_length(int pipeline_stage, Thread *current_thread) const { CDStageReader cdata(_cycler, pipeline_stage, current_thread); return cdata->_length; } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::get_next // Access: Public // Description: Returns the next component in the path. //////////////////////////////////////////////////////////////////// NodePathComponent *NodePathComponent:: get_next(int pipeline_stage, Thread *current_thread) const { CDStageReader cdata(_cycler, pipeline_stage, current_thread); NodePathComponent *next = cdata->_next; return next; } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::fix_length // Access: Public // Description: Checks that the length indicated by the component is // one more than the length of its predecessor. If this // is broken, fixes it and returns true indicating the // component has been changed; otherwise, returns false. //////////////////////////////////////////////////////////////////// bool NodePathComponent:: fix_length(int pipeline_stage, Thread *current_thread) { CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); int length_should_be = 1; if (cdata->_next != (NodePathComponent *)NULL) { length_should_be = cdata->_next->get_length(pipeline_stage, current_thread) + 1; } if (cdata->_length == length_should_be) { return false; } CDStageWriter cdataw(_cycler, pipeline_stage, cdata); cdataw->_length = length_should_be; return true; } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::output // Access: Public // Description: The recursive implementation of NodePath::output(), // this writes the names of each node component in order // from beginning to end, by first walking to the end of // the linked list and then outputting from there. //////////////////////////////////////////////////////////////////// void NodePathComponent:: output(ostream &out) const { Thread *current_thread = Thread::get_current_thread(); int pipeline_stage = current_thread->get_pipeline_stage(); PandaNode *node = get_node(); NodePathComponent *next = get_next(pipeline_stage, current_thread); if (next != (NodePathComponent *)NULL) { // This is not the head of the list; keep going up. next->output(out); out << "/"; PandaNode *parent_node = next->get_node(); if (parent_node->find_stashed(node) >= 0) { // The node is stashed. out << "@@"; } else if (node->find_parent(parent_node) < 0) { // Oops, there's an error. This shouldn't happen. out << ".../"; } } // Now output this component. if (node->has_name()) { out << node->get_name(); } else { out << "-" << node->get_type(); } // out << "[" << this->get_length() << "]"; } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::set_next // Access: Private // Description: Sets the next pointer in the path. //////////////////////////////////////////////////////////////////// void NodePathComponent:: set_next(NodePathComponent *next, int pipeline_stage, Thread *current_thread) { nassertv(next != (NodePathComponent *)NULL); CDStageWriter cdata(_cycler, pipeline_stage, current_thread); cdata->_next = next; } //////////////////////////////////////////////////////////////////// // Function: NodePathComponent::set_top_node // Access: Private // Description: Severs any connection to the next pointer in the // path and makes this component a top node. //////////////////////////////////////////////////////////////////// void NodePathComponent:: set_top_node(int pipeline_stage, Thread *current_thread) { CDStageWriter cdata(_cycler, pipeline_stage, current_thread); cdata->_next = (NodePathComponent *)NULL; }