// Filename: node.cxx // Created by: drose (27Oct98) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license // along with this source code; you will also find a current copy of // the license at http://www.panda3d.org/license.txt . // // To contact the maintainers of this program write to // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// #include "node.h" #include "nodeRelation.h" #include #include #include #include #include NodeConnection Node::_empty_connection; TypeHandle Node::_type_handle; Node* const Node::Null = (Node*)0L; //////////////////////////////////////////////////////////////////// // Function: Node::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// Node:: Node() { MemoryUsage::update_type(this, this); } //////////////////////////////////////////////////////////////////// // Function: Node::Copy Constructor // Access: Public // Description: The Node copy constructor does not copy children. // Use copy_subgraph() if you want a deep copy of the // node and all of its children. Also, you should use // make_copy() if you just want a typed copy of the Node // (without children). //////////////////////////////////////////////////////////////////// Node:: Node(const Node ©) : TypedWritable(copy), BoundedObject(copy), ReferenceCount(copy) { MemoryUsage::update_type(this, this); } //////////////////////////////////////////////////////////////////// // Function: Node::Copy Assignment Operator // Access: Public // Description: //////////////////////////////////////////////////////////////////// void Node:: operator = (const Node ©) { TypedWritable::operator = (copy); BoundedObject::operator = (copy); ReferenceCount::operator = (copy); } //////////////////////////////////////////////////////////////////// // Function: Node::Destructor // Access: Public, Virtual // Description: When a Node destructs, all of its arcs must be // deleted as well. //////////////////////////////////////////////////////////////////// Node:: ~Node() { // We'd better not have any arcs pointing into this node, since // we're destructing it now. If we do, the destructor was called in // error. int i; for (i = 0; i < max_node_graphs; i++) { UpRelationPointers &urp = _connections[i].get_up(); nassertv(urp.empty()); } // Now disconnect all the child arcs. for (i = 0; i < max_node_graphs; i++) { DownRelationPointers &drp = _connections[i].get_down(); DownRelationPointers::iterator drpi; for (drpi = drp.begin(); drpi != drp.end(); ++drpi) { NodeRelation *arc = (*drpi); nassertv(arc != (NodeRelation *)NULL); // This deletes the arc and anything below it through the magic // of reference-counting. arc->detach_below(); } } } //////////////////////////////////////////////////////////////////// // Function: Node::make_copy // Access: Public, Virtual // Description: Returns a newly-allocated Node that is a shallow copy // of this one. It will be a different Node pointer, // but its internal data may or may not be shared with // that of the original Node. No children will be // copied. //////////////////////////////////////////////////////////////////// Node *Node:: make_copy() const { return new Node(*this); } //////////////////////////////////////////////////////////////////// // Function: Node::copy_subgraph // Access: Public // Description: Allocates and returns a complete copy of this node // and the entire scene graph rooted at this node. Some // data may still be shared from the original // (e.g. vertex index tables), but nothing that will // impede normal use of the node. //////////////////////////////////////////////////////////////////// Node *Node:: copy_subgraph(TypeHandle graph_type) const { InstanceMap inst_map; return r_copy_subgraph(graph_type, inst_map); } //////////////////////////////////////////////////////////////////// // Function: Node::safe_to_flatten // Access: Public, Virtual // Description: Returns true if it is generally safe to flatten out // this particular kind of Node by duplicating // instances, false otherwise (for instance, a Camera // cannot be safely flattened, because the Camera // pointer itself is meaningful). //////////////////////////////////////////////////////////////////// bool Node:: safe_to_flatten() const { return true; } //////////////////////////////////////////////////////////////////// // Function: Node::safe_to_transform // Access: Public, Virtual // Description: Returns true if it is generally safe to transform // this particular kind of Node by calling the xform() // method, false otherwise. For instance, it's usually // a bad idea to attempt to xform a Character. //////////////////////////////////////////////////////////////////// bool Node:: safe_to_transform() const { return true; } //////////////////////////////////////////////////////////////////// // Function: Node::safe_to_combine // Access: Public, Virtual // Description: Returns true if it is generally safe to combine // this particular kind of Node with other kinds of // Nodes, adding children or whatever. For instance, an // LODNode should not be combined with any other node, // because its set of children is meaningful. //////////////////////////////////////////////////////////////////// bool Node:: safe_to_combine() const { return true; } //////////////////////////////////////////////////////////////////// // Function: Node::xform // Access: Public, Virtual // Description: Transforms the contents of this node by the indicated // matrix, if it means anything to do so. For most // kinds of nodes, this does nothing. //////////////////////////////////////////////////////////////////// void Node:: xform(const LMatrix4f &) { } //////////////////////////////////////////////////////////////////// // Function: Node::combine_with // Access: Public, Virtual // Description: Collapses this node with the other node, if possible, // and returns a pointer to the combined node, or NULL // if the two nodes cannot safely be combined. // // The return value may be this, other, or a new node // altogether. // // This function is called from GraphReducer::flatten(), // and need not deal with children; its job is just to // decide whether to collapse the two nodes and what the // collapsed node should look like. //////////////////////////////////////////////////////////////////// Node *Node:: combine_with(Node *other) { // An unadorned Node always combines with any other Nodes by // yielding completely. However, if we are actually some fancy Node // type that derives from Node but didn't redefine this function, we // should refuse to combine. if (is_exact_type(get_class_type())) { // No, we're an ordinary Node. return other; } else if (other->is_exact_type(get_class_type())) { // We're not an ordinary Node, but the other one is. return this; } // We're something other than an ordinary Node. Don't combine. return (Node *)NULL; } //////////////////////////////////////////////////////////////////// // Function: Node::transform_changed // Access: Public, Virtual // Description: Called whenever the transform matrix on one of the // arcs directly above this node has changed. This is // simply a hook so the node can do something // appropriate. It does not get called when arcs far // above the node change. //////////////////////////////////////////////////////////////////// void Node:: transform_changed(NodeRelation *) { } //////////////////////////////////////////////////////////////////// // Function: Node::get_num_parents // Access: Public // Description: Returns the number of parent arcs of the indicated // type (e.g. RenderRelation::get_class_type()) the node // has. //////////////////////////////////////////////////////////////////// int Node:: get_num_parents(TypeHandle type) const { const UpRelationPointers &urp = find_connection(type).get_up(); return urp.size(); } //////////////////////////////////////////////////////////////////// // Function: Node::get_parent // Access: Public // Description: Returns the nth parent arc of the indicated type the // node has. The index must be in the range 0 <= index // < get_num_parents(type). //////////////////////////////////////////////////////////////////// NodeRelation *Node:: get_parent(TypeHandle type, int index) const { const UpRelationPointers &urp = find_connection(type).get_up(); nassertr(index >= 0 && index < (int)urp.size(), (NodeRelation *)NULL); return urp[index]; } //////////////////////////////////////////////////////////////////// // Function: Node::get_num_children // Access: Public // Description: Returns the number of child arcs of the indicated // type (e.g. RenderRelation::get_class_type()) the node // has. //////////////////////////////////////////////////////////////////// int Node:: get_num_children(TypeHandle type) const { const DownRelationPointers &drp = find_connection(type).get_down(); return drp.size(); } //////////////////////////////////////////////////////////////////// // Function: Node::get_child // Access: Public // Description: Returns the nth child arc of the indicated type the // node has. The index must be in the range 0 <= index // < get_num_children(type). //////////////////////////////////////////////////////////////////// NodeRelation *Node:: get_child(TypeHandle type, int index) const { const DownRelationPointers &drp = find_connection(type).get_down(); nassertr(index >= 0 && index < (int)drp.size(), (NodeRelation *)NULL); return drp[index]; } //////////////////////////////////////////////////////////////////// // Function: Node::app_traverse // Access: Public, Virtual // Description: This hook function is called on each node visited // during the App traversal. The ArcChain passed in // represents the complete chain from the root of the // graph to this node, if it is known. //////////////////////////////////////////////////////////////////// void Node:: app_traverse(const ArcChain &) { } //////////////////////////////////////////////////////////////////// // Function: Node::draw_traverse // Access: Public, Virtual // Description: This hook function is called on each node visited // during the Draw traversal. The ArcChain passed in // represents the complete chain from the root of the // graph to this node, if it is known. //////////////////////////////////////////////////////////////////// void Node:: draw_traverse(const ArcChain &) { } //////////////////////////////////////////////////////////////////// // Function: Node::dgraph_traverse // Access: Public, Virtual // Description: This hook function is called on each node visited // during the data graph traversal. The ArcChain passed // in represents the complete chain from the root of the // graph to this node, if it is known. //////////////////////////////////////////////////////////////////// void Node:: dgraph_traverse(const ArcChain &) { } //////////////////////////////////////////////////////////////////// // Function: Node::sub_render // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// bool Node:: sub_render(const AllAttributesWrapper &, AllTransitionsWrapper &, RenderTraverser *) { return true; } //////////////////////////////////////////////////////////////////// // Function: Node::has_sub_render // Access: Public, Virtual // Description: Should be redefined to return true if the function // sub_render(), above, expects to be called during // traversal. //////////////////////////////////////////////////////////////////// bool Node:: has_sub_render() const { return false; } //////////////////////////////////////////////////////////////////// // Function: Node::output // Access: Public, Virtual // Description: Writes a brief description of the node to the // indicated output stream. This is invoked by the << // operator. It may be overridden in derived classes to // include some information relevant to the class. //////////////////////////////////////////////////////////////////// void Node:: output(ostream &out) const { out << get_type(); } //////////////////////////////////////////////////////////////////// // Function: Node::write // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// void Node:: write(ostream &out, int indent_level) const { indent(out, indent_level) << *this << "\n"; } //////////////////////////////////////////////////////////////////// // Function: Node::p_find_connection // Access: Private // Description: The non-inline implementation of find_connection(). //////////////////////////////////////////////////////////////////// const NodeConnection &Node:: p_find_connection(TypeHandle graph_type) const { // _connections[0] is already tested by the inline implementation. for (int i = 1; i < max_node_graphs; i++) { if (_connections[i].get_graph_type() == graph_type) { return _connections[i]; } } return _empty_connection; } //////////////////////////////////////////////////////////////////// // Function: Node::p_update_connection // Access: Private // Description: The non-inline implementation of update_connection(). //////////////////////////////////////////////////////////////////// NodeConnection *Node:: p_update_connection(TypeHandle graph_type) { // _connections[0] is already tested by the inline implementation. int i; for (i = 1; i < max_node_graphs; i++) { if (_connections[i].get_graph_type() == graph_type) { return &_connections[i]; } } // No such connection; can we create a new one? for (i = 0; i < max_node_graphs; i++) { if (_connections[i].is_empty()) { _connections[i].set_graph_type(graph_type); return &_connections[i]; } } // Too bad. return (NodeConnection *)NULL; } //////////////////////////////////////////////////////////////////// // Function: Node::propagate_stale_bound // Access: Protected, Virtual // Description: Called by BoundedObject::mark_bound_stale(), this // should make sure that all bounding volumes that // depend on this one are marked stale also. //////////////////////////////////////////////////////////////////// void Node:: propagate_stale_bound() { // Mark all of our parent arcs, in all graphs, stale as well. for (int i = 0; i < max_node_graphs; i++) { const UpRelationPointers &urp = _connections[i].get_up(); UpRelationPointers::const_iterator urpi; for (urpi = urp.begin(); urpi != urp.end(); ++urpi) { (*urpi)->mark_bound_stale(); } } } //////////////////////////////////////////////////////////////////// // Function: Node::r_copy_subgraph // Access: Protected, Virtual // Description: This is the recursive implementation of copy_subgraph(). // It returns a copy of the entire subgraph rooted at // this node. // // Note that it includes the parameter inst_map, which // is a map type, and is not (and cannot be) exported // from PANDA.DLL. Thus, any derivative of Node that is // not also a member of PANDA.DLL *cannot* access this // map. //////////////////////////////////////////////////////////////////// Node *Node:: r_copy_subgraph(TypeHandle graph_type, Node::InstanceMap &inst_map) const { Node *copy = make_copy(); nassertr(copy != (Node *)NULL, NULL); if (copy->get_type() != get_type()) { graph_cat.warning() << "Don't know how to copy nodes of type " << get_type() << "\n"; } copy->r_copy_children(this, graph_type, inst_map); return copy; } //////////////////////////////////////////////////////////////////// // Function: Node::r_copy_children // Access: Protected, Virtual // Description: This is called by r_copy_subgraph(); the copy has // already been made of this particular node (and this // is the copy); this function's job is to copy all of // the children from the original. // // Note that it includes the parameter inst_map, which // is a map type, and is not (and cannot be) exported // from PANDA.DLL. Thus, any derivative of Node that is // not also a member of PANDA.DLL *cannot* access this // map, and probably should not even override this // function. //////////////////////////////////////////////////////////////////// void Node:: r_copy_children(const Node *from, TypeHandle graph_type, Node::InstanceMap &inst_map) { const DownRelationPointers &drp = from->find_connection(graph_type).get_down(); DownRelationPointers::const_iterator drpi; for (drpi = drp.begin(); drpi != drp.end(); ++drpi) { NodeRelation *source_arc = (*drpi); Node *source_child = source_arc->get_child(); nassertv(source_child != (Node *)NULL); Node *dest_child; // Check to see if we have already copied this child. If we // have, use the copy. In this way, a subgraph that contains // instances will be correctly duplicated into another subgraph // that also contains its own instances. InstanceMap::const_iterator ci; ci = inst_map.find(source_child); if (ci != inst_map.end()) { dest_child = (*ci).second; } else { dest_child = source_child->r_copy_subgraph(graph_type, inst_map); inst_map[source_child] = dest_child; } NodeRelation *dest_arc = NodeRelation::create_typed_arc(graph_type, this, dest_child); nassertv(dest_arc != (NodeRelation *)NULL); nassertv(dest_arc->is_exact_type(graph_type)); dest_arc->copy_transitions_from(source_arc); } } //////////////////////////////////////////////////////////////////// // Function: Node::write_datagram // Access: Public // Description: Function to write the important information in // the particular object to a Datagram //////////////////////////////////////////////////////////////////// void Node:: write_datagram(BamWriter *manager, Datagram &me) { // A node should not write out its UpRelations. This is because if // a node is written out from the middle of the graph, then most // likely we only want to write it and its children. If we did // write out all of the UpRelations then writing any node in a graph // would cause the entire graph to be written out. // First, count up the number of NodeConnections that are nonempty. int num_connections = 0; int i; for (i = 0; i < max_node_graphs; i++) { if (!_connections[i].is_empty()) { num_connections++; } } me.add_uint16(num_connections); // Now write them out. for (i = 0; i < max_node_graphs; i++) { if (!_connections[i].is_empty()) { manager->write_handle(me, _connections[i].get_graph_type()); const DownRelationPointers &drp = _connections[i].get_down(); me.add_uint16(drp.size()); DownRelationPointers::const_iterator drpi; for (drpi = drp.begin(); drpi != drp.end(); ++drpi) { NodeRelation *relation = (*drpi); manager->write_pointer(me, relation); } } } } //////////////////////////////////////////////////////////////////// // Function: Node::complete_pointers // Access: Public // Description: Takes in a vector of pointers to TypedWritable // objects that correspond to all the requests for // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int Node:: complete_pointers(vector_typedWritable &p_list, BamReader *manager) { if (manager->get_file_minor_ver() < 3) { // In bam versions before 3.3, this function does nothing (since // the arcs are completely responsible for adding themselves to // our list); we only need to return the number of pointers we // expected to receive. // As of 5/7/01, we no longer store this number, as a memory // optimization. This means bams before 3.3 cannot be reliably // loaded. graph_cat.warning() << "Unable to reliably load bam version " << manager->get_file_major_ver() << "." << manager->get_file_minor_ver() << "\n"; return 0; } // Beginning at bam version 3.3, we are responsible for adding our // child arcs directly. int count = 0; for (int i = 0; i < max_node_graphs; i++) { if (!_connections[i].is_empty()) { DownRelationPointers &drp = _connections[i].get_down(); DownRelationPointers::iterator drpi; for (drpi = drp.begin(); drpi != drp.end(); ++drpi) { (*drpi) = DCAST(NodeRelation, p_list[count]); count++; } } } return count; } //////////////////////////////////////////////////////////////////// // Function: Node::make_Node // Access: Protected // Description: Factory method to generate a node object //////////////////////////////////////////////////////////////////// TypedWritable* Node:: make_Node(const FactoryParams ¶ms) { Node *me = new Node; DatagramIterator scan; BamReader *manager; parse_params(params, scan, manager); me->fillin(scan, manager); return me; } //////////////////////////////////////////////////////////////////// // Function: Node::fillin // Access: Protected // Description: Function that reads out of the datagram (or asks // manager to read) all of the data that is needed to // re-create this object and stores it in the appropiate // place //////////////////////////////////////////////////////////////////// void Node:: fillin(DatagramIterator &scan, BamReader *manager) { if (manager->get_file_minor_ver() < 3) { // In bam versions before 3.3, we only need to count up the total // number of arcs across all types, because we don't add the arc // pointers explicitly here. int num_types = scan.get_uint16(); while (num_types > 0) { int num_arcs = scan.get_uint16(); while (num_arcs > 0) { manager->read_pointer(scan, this); num_arcs--; } num_types--; } } else { // Beginning at bam version 3.3, we do all the reading of our // children arcs of all types, which means we need to record the // numbers of each type of children. We do this by recording a // series of NULL pointers in our NodeConnections. int num_connections = scan.get_uint16(); if (num_connections > max_node_graphs) { // Oops, too many graph types in this bam file. We'll have to // discard some. graph_cat.error() << "Bam file specifies " << num_connections << " graph types for " << *this << "; this version of Panda can only support " << max_node_graphs << " simultaneous graph types.\n"; } for (int i = 0; i < num_connections; i++) { TypeHandle type = manager->read_handle(scan); if (i < max_node_graphs) { _connections[i].set_graph_type(type); DownRelationPointers &drp = _connections[i].get_down(); int num_arcs = scan.get_uint16(); while (num_arcs > 0) { manager->read_pointer(scan, this); drp.push_back((NodeRelation *)NULL); num_arcs--; } } else { // Read and discard. int num_arcs = scan.get_uint16(); while (num_arcs > 0) { manager->skip_pointer(scan); num_arcs--; } } } } } //////////////////////////////////////////////////////////////////// // Function: Node::register_with_factory // Access: Public, Static // Description: Factory method to generate a node object //////////////////////////////////////////////////////////////////// void Node:: register_with_read_factory(void) { BamReader::get_factory()->register_factory(get_class_type(), make_Node); } //////////////////////////////////////////////////////////////////// // Function: find_arc // Description: Searches for the arc of the indicated type that // connects the two indicated nodes. Returns the arc if // it exists, or NULL if does not. //////////////////////////////////////////////////////////////////// NodeRelation * find_arc(Node *parent, Node *child, TypeHandle graph_type) { // We must now walk the RelationPointers list, looking for the // matching parent-child arc. We'll start in the child looking for // the parent arc, on the assumption there are likely to be fewer // parents than children. const UpRelationPointers &urp = child->find_connection(graph_type).get_up(); UpRelationPointers::const_iterator urpi; for (urpi = urp.begin(); urpi != urp.end(); ++urpi) { NodeRelation *arc = (*urpi); if (arc->get_parent() == parent && arc->get_child() == child) { return arc; } } // There is no matching arc. return (NodeRelation *)NULL; }