Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
cdc10dcd48

+ 3 - 1
panda/src/builder/builder.cxx

@@ -179,7 +179,9 @@ build(const string &default_name) {
     }
 
     // Only reparent the geom_node if it has no parent already.
-    if (geom_node->_parents.empty()) {
+    int num_parents = 
+      geom_node->get_num_parents(RenderRelation::get_class_type());
+    if (num_parents == 0) {
       if (geom_node->get_num_geoms() == 0) {
 	// If there was nothing added, never mind.
 	delete geom_node;

+ 73 - 130
panda/src/graph/Sources.pp

@@ -7,116 +7,81 @@
     putil mathutil
 
   #define SOURCES \  
-	allAttributesWrapper.I        nodeAttributes.cxx  \
-	allAttributesWrapper.T        nodeAttributes.h  \
-	allAttributesWrapper.cxx      nodeRelation.I  \
-	allAttributesWrapper.h        nodeRelation.N  \
-	allTransitionsWrapper.I       nodeRelation.T  \
-	allTransitionsWrapper.T       nodeRelation.cxx  \
-	allTransitionsWrapper.cxx     nodeRelation.h  \
-	allTransitionsWrapper.h       nodeTransition.I  \
-	arcChain.I                    nodeTransition.N  \
-	arcChain.cxx                  nodeTransition.cxx  \
-	arcChain.h                    nodeTransition.h  \
-	bitMask32Transition.cxx       nodeTransitionCache.I  \
-	bitMask32Transition.h         nodeTransitionCache.cxx  \
-	bitMaskAttribute.T            nodeTransitionCache.h  \
-	bitMaskAttribute.h            nodeTransitionCacheEntry.I  \
-	bitMaskTransition.T           nodeTransitionCacheEntry.cxx  \
-	bitMaskTransition.h           nodeTransitionCacheEntry.h  \
-	boundedObject.I               nodeTransitionWrapper.I  \
-	boundedObject.N               nodeTransitionWrapper.T  \
-	boundedObject.cxx             nodeTransitionWrapper.cxx  \
-	boundedObject.h               nodeTransitionWrapper.h  \
-	config_graph.cxx              nodeTransitions.I  \
-	config_graph.h                nodeTransitions.T  \
-	dftraverser.T                 nodeTransitions.cxx  \
-	dftraverser.h                 nodeTransitions.h  \
-	graphReducer.cxx              nullAttributeWrapper.I  \
-	graphReducer.h                nullAttributeWrapper.cxx  \
-	immediateAttribute.cxx        nullAttributeWrapper.h  \
-	immediateAttribute.h          nullLevelState.cxx  \
-	immediateTransition.I         nullLevelState.h  \
-	immediateTransition.cxx       nullTransitionWrapper.I  \
-	immediateTransition.h         nullTransitionWrapper.cxx  \
-	lmatrix4fTransition.cxx       nullTransitionWrapper.h  \
-	lmatrix4fTransition.h         onAttribute.cxx  \
-	matrixAttribute.T             onAttribute.h  \
-	matrixAttribute.h             onOffAttribute.I  \
-	matrixTransition.T            onOffAttribute.cxx  \
-	matrixTransition.h            onOffAttribute.h  \
-	multiAttribute.T              onOffTransition.I  \
-	multiAttribute.h              onOffTransition.cxx  \
-	multiNodeAttribute.cxx        onOffTransition.h  \
-	multiNodeAttribute.h          onTransition.I  \
-	multiNodeTransition.cxx       onTransition.cxx  \
-	multiNodeTransition.h         onTransition.h  \
-	multiTransition.T             pointerNameClass.h  \
-	multiTransition.h             pt_NamedNode.N  \
-	multiTransitionHelpers.I      pt_NamedNode.cxx  \
-	multiTransitionHelpers.h      pt_NamedNode.h  \
-	namedNode.I                   pt_Node.N  \
-	namedNode.cxx                 pt_Node.cxx  \
-	namedNode.h                   pt_Node.h  \
-	node.I                        setTransitionHelpers.T  \
-	node.cxx                      setTransitionHelpers.h  \
-	node.h                          \
-	nodeAttribute.I                 \
-	nodeAttribute.N                 \
-	nodeAttribute.cxx             transitionDirection.h  \
-	nodeAttribute.h               traverserVisitor.T  \
-	nodeAttributeWrapper.I        traverserVisitor.h  \
-	nodeAttributeWrapper.T        vector_PT_Node.cxx  \
-	nodeAttributeWrapper.cxx      vector_PT_Node.h  \
-	nodeAttributeWrapper.h        wrt.I  \
-	nodeAttributes.I              wrt.cxx  \
-	nodeAttributes.N              wrt.h  \
-	nodeAttributes.T  
+    allAttributesWrapper.I allAttributesWrapper.T  \
+    allAttributesWrapper.cxx allAttributesWrapper.h \
+    allTransitionsWrapper.I allTransitionsWrapper.T \
+    allTransitionsWrapper.cxx allTransitionsWrapper.h arcChain.I \
+    arcChain.cxx arcChain.h bitMask32Transition.cxx \
+    bitMask32Transition.h bitMaskAttribute.T bitMaskAttribute.h \
+    bitMaskTransition.T bitMaskTransition.h boundedObject.I \
+    boundedObject.N boundedObject.cxx boundedObject.h config_graph.cxx \
+    config_graph.h dftraverser.T dftraverser.h graphReducer.cxx \
+    graphReducer.h immediateAttribute.cxx immediateAttribute.h \
+    immediateTransition.I immediateTransition.cxx \
+    immediateTransition.h lmatrix4fTransition.cxx \
+    lmatrix4fTransition.h matrixAttribute.T matrixAttribute.h \
+    matrixTransition.T matrixTransition.h multiAttribute.T \
+    multiAttribute.h multiNodeAttribute.cxx multiNodeAttribute.h \
+    multiNodeTransition.cxx multiNodeTransition.h multiTransition.T \
+    multiTransition.h multiTransitionHelpers.I \
+    multiTransitionHelpers.h namedNode.I namedNode.cxx namedNode.h \
+    node.I node.cxx node.h nodeAttribute.I nodeAttribute.N \
+    nodeAttribute.cxx nodeAttribute.h nodeAttributeWrapper.I \
+    nodeAttributeWrapper.T nodeAttributeWrapper.cxx \
+    nodeAttributeWrapper.h nodeAttributes.I nodeAttributes.N \
+    nodeAttributes.T nodeAttributes.cxx nodeAttributes.h \
+    nodeConnection.I nodeConnection.cxx nodeConnection.h \
+    nodeRelation.I nodeRelation.N nodeRelation.T nodeRelation.cxx \
+    nodeRelation.h nodeTransition.I nodeTransition.N \
+    nodeTransition.cxx nodeTransition.h nodeTransitionCache.I \
+    nodeTransitionCache.cxx nodeTransitionCache.h \
+    nodeTransitionCacheEntry.I nodeTransitionCacheEntry.cxx \
+    nodeTransitionCacheEntry.h nodeTransitionWrapper.I \
+    nodeTransitionWrapper.T nodeTransitionWrapper.cxx \
+    nodeTransitionWrapper.h nodeTransitions.I nodeTransitions.T \
+    nodeTransitions.cxx nodeTransitions.h nullAttributeWrapper.I \
+    nullAttributeWrapper.cxx nullAttributeWrapper.h nullLevelState.cxx \
+    nullLevelState.h nullTransitionWrapper.I nullTransitionWrapper.cxx \
+    nullTransitionWrapper.h onAttribute.cxx onAttribute.h \
+    onOffAttribute.I onOffAttribute.cxx onOffAttribute.h \
+    onOffTransition.I onOffTransition.cxx onOffTransition.h \
+    onTransition.I onTransition.cxx onTransition.h pointerNameClass.h \
+    pt_NamedNode.N pt_NamedNode.cxx pt_NamedNode.h pt_Node.N \
+    pt_Node.cxx pt_Node.h setTransitionHelpers.T \
+    setTransitionHelpers.h transitionDirection.h traverserVisitor.T \
+    traverserVisitor.h vector_PT_Node.cxx vector_PT_Node.h wrt.I \
+    wrt.cxx wrt.h
 
   #define INSTALL_HEADERS \
-	allAttributesWrapper.I      nodeAttributeWrapper.h  \
-	allAttributesWrapper.T      nodeAttributes.I  \
-	allAttributesWrapper.h      nodeAttributes.T  \
-	allTransitionsWrapper.I     nodeAttributes.h  \
-	allTransitionsWrapper.T     nodeRelation.I  \
-	allTransitionsWrapper.h     nodeRelation.T  \
-	arcChain.I                  nodeRelation.h  \
-	arcChain.h                  nodeTransition.I  \
-	bitMask32Transition.h       nodeTransition.h  \
-	bitMaskAttribute.T          nodeTransitionCache.I  \
-	bitMaskAttribute.h          nodeTransitionCache.h  \
-	bitMaskTransition.T         nodeTransitionCacheEntry.I  \
-	bitMaskTransition.h         nodeTransitionCacheEntry.h  \
-	boundedObject.I             nodeTransitionWrapper.I  \
-	boundedObject.h             nodeTransitionWrapper.T  \
-	config_graph.h              nodeTransitionWrapper.h  \
-	dftraverser.T               nodeTransitions.I  \
-	dftraverser.h               nodeTransitions.T  \
-	graphReducer.h              nodeTransitions.h  \
-	immediateAttribute.h        nullAttributeWrapper.I  \
-	immediateTransition.I       nullAttributeWrapper.h  \
-	immediateTransition.h       nullLevelState.h  \
-	lmatrix4fTransition.h       nullTransitionWrapper.I  \
-	matrixAttribute.T           nullTransitionWrapper.h  \
-	matrixAttribute.h           onAttribute.h  \
-	matrixTransition.T          onOffAttribute.I  \
-	matrixTransition.h          onOffAttribute.h  \
-	multiAttribute.T            onOffTransition.I  \
-	multiAttribute.h            onOffTransition.h  \
-	multiNodeAttribute.h        onTransition.I  \
-	multiNodeTransition.h       onTransition.h  \
-	multiTransition.T           pointerNameClass.h  \
-	multiTransition.h           pt_NamedNode.h  \
-	multiTransitionHelpers.I    pt_Node.h  \
-	multiTransitionHelpers.h    setTransitionHelpers.T  \
-	namedNode.I                 setTransitionHelpers.h  \
-	namedNode.h                 transitionDirection.h  \
-	node.I                      traverserVisitor.T  \
-	node.h                      traverserVisitor.h  \
-	nodeAttribute.I             vector_PT_Node.h  \
-	nodeAttribute.h             wrt.I  \
-	nodeAttributeWrapper.I      wrt.h  \
-	nodeAttributeWrapper.T
+    allAttributesWrapper.I allAttributesWrapper.T \
+    allAttributesWrapper.h allTransitionsWrapper.I \
+    allTransitionsWrapper.T allTransitionsWrapper.h arcChain.I \
+    arcChain.h bitMask32Transition.h bitMaskAttribute.T \
+    bitMaskAttribute.h bitMaskTransition.T bitMaskTransition.h \
+    boundedObject.I boundedObject.h config_graph.h dftraverser.T \
+    dftraverser.h graphReducer.h immediateAttribute.h \
+    immediateTransition.I immediateTransition.h lmatrix4fTransition.h \
+    matrixAttribute.T matrixAttribute.h matrixTransition.T \
+    matrixTransition.h multiAttribute.T multiAttribute.h \
+    multiNodeAttribute.h multiNodeTransition.h multiTransition.T \
+    multiTransition.h multiTransitionHelpers.I \
+    multiTransitionHelpers.h namedNode.I namedNode.h node.I node.h \
+    nodeAttribute.I nodeAttribute.h nodeAttributeWrapper.I \
+    nodeAttributeWrapper.T nodeAttributeWrapper.h nodeAttributes.I \
+    nodeAttributes.T nodeAttributes.h nodeConnection.I \
+    nodeConnection.h nodeRelation.I nodeRelation.T nodeRelation.h \
+    nodeTransition.I nodeTransition.h nodeTransitionCache.I \
+    nodeTransitionCache.h nodeTransitionCacheEntry.I \
+    nodeTransitionCacheEntry.h nodeTransitionWrapper.I \
+    nodeTransitionWrapper.T nodeTransitionWrapper.h nodeTransitions.I \
+    nodeTransitions.T nodeTransitions.h nullAttributeWrapper.I \
+    nullAttributeWrapper.h nullLevelState.h nullTransitionWrapper.I \
+    nullTransitionWrapper.h onAttribute.h onOffAttribute.I \
+    onOffAttribute.h onOffTransition.I onOffTransition.h \
+    onTransition.I onTransition.h pointerNameClass.h pt_NamedNode.h \
+    pt_Node.h setTransitionHelpers.T setTransitionHelpers.h \
+    transitionDirection.h traverserVisitor.T traverserVisitor.h \
+    vector_PT_Node.h wrt.I wrt.h
 
   #define IGATESCAN all
 
@@ -133,25 +98,3 @@
 
 #end test_bin_target
 
-#begin test_bin_target
-  #define TARGET test_graphRead
-  #define LOCAL_LIBS \
-    putil graph
-  #define OTHER_LIBS $[OTHER_LIBS] pystub
-
-  #define SOURCES \
-    test_graphRead.cxx
-
-#end test_bin_target
-
-#begin test_bin_target
-  #define TARGET test_graphWrite
-  #define LOCAL_LIBS \
-    graph putil
-  #define OTHER_LIBS $[OTHER_LIBS] pystub
-
-  #define SOURCES \
-    test_graphWrite.cxx
-
-#end test_bin_target
-

+ 6 - 10
panda/src/graph/dftraverser.T

@@ -84,17 +84,13 @@ traverse(Node *node, AttributeWrapper &state, LevelState &level_state) {
   if (_visitor.reached_node(node, state, level_state)) {
 
     // Look for further children of the given NodeRelation.
-    DownRelations::const_iterator dri;
-    dri = node->_children.find(_graph_type);
-    if (dri != node->_children.end()) {
-      // Here are some!
-      const DownRelationPointers &drp = (*dri).second;
+    const DownRelationPointers &drp = 
+      node->find_connection(_graph_type).get_down();
 
-      // Now visit each of the children in turn.
-      DownRelationPointers::const_iterator drpi;
-      for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-	traverse(*drpi, state, level_state);
-      }
+    // Now visit each of the children in turn.
+    DownRelationPointers::const_iterator drpi;
+    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
+      traverse(*drpi, state, level_state);
     }
   }
 }

+ 38 - 49
panda/src/graph/graphReducer.cxx

@@ -61,21 +61,18 @@ flatten(Node *root, bool combine_siblings) {
   do {
     num_pass_nodes = 0;
 
-    DownRelations::const_iterator dri;
-    dri = root->_children.find(_graph_type);
-    if (dri != root->_children.end()) {
-      const DownRelationPointers &drp = (*dri).second;
+    const DownRelationPointers &drp = 
+      root->find_connection(_graph_type).get_down();
       
-      // Get a copy of the children list, so we don't have to worry
-      // about self-modifications.
-      DownRelationPointers drp_copy = drp;
+    // Get a copy of the children list, so we don't have to worry
+    // about self-modifications.
+    DownRelationPointers drp_copy = drp;
       
-      // Now visit each of the children in turn.
-      DownRelationPointers::const_iterator drpi;
-      for (drpi = drp_copy.begin(); drpi != drp_copy.end(); ++drpi) {
-	NodeRelation *arc = (*drpi);
-	num_pass_nodes += r_flatten(arc->get_child(), combine_siblings);
-      }
+    // Now visit each of the children in turn.
+    DownRelationPointers::const_iterator drpi;
+    for (drpi = drp_copy.begin(); drpi != drp_copy.end(); ++drpi) {
+      NodeRelation *arc = (*drpi);
+      num_pass_nodes += r_flatten(arc->get_child(), combine_siblings);
     }
 
     num_total_nodes += num_pass_nodes;
@@ -100,33 +97,30 @@ int GraphReducer::
 r_flatten(Node *root, bool combine_siblings) {
   int num_nodes = 0;
 
-  DownRelations::const_iterator dri;
-  dri = root->_children.find(_graph_type);
-  if (dri != root->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
+  const DownRelationPointers &drp = 
+    root->find_connection(_graph_type).get_down();
 
-    // Get a copy of the children list, so we don't have to worry
-    // about self-modifications.
-    DownRelationPointers drp_copy = drp;
+  // Get a copy of the children list, so we don't have to worry
+  // about self-modifications.
+  DownRelationPointers drp_copy = drp;
 
-    // Now visit each of the children in turn.
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp_copy.begin(); drpi != drp_copy.end(); ++drpi) {
-      NodeRelation *arc = (*drpi);
-      num_nodes += r_flatten(arc->get_child(), combine_siblings);
-    }
-
-    if (combine_siblings && drp.size() >= 2) {
-      num_nodes += flatten_siblings(root);
-    }
-
-    if (drp.size() == 1) {
-      // If we have exactly one child, consider flattening it.
-      NodeRelation *arc = *drp.begin();
-      if (consider_arc(arc)) {
-	if (flatten_arc(arc)) {
-	  num_nodes++;
-	}
+  // Now visit each of the children in turn.
+  DownRelationPointers::const_iterator drpi;
+  for (drpi = drp_copy.begin(); drpi != drp_copy.end(); ++drpi) {
+    NodeRelation *arc = (*drpi);
+    num_nodes += r_flatten(arc->get_child(), combine_siblings);
+  }
+  
+  if (combine_siblings && drp.size() >= 2) {
+    num_nodes += flatten_siblings(root);
+  }
+  
+  if (drp.size() == 1) {
+    // If we have exactly one child, consider flattening it.
+    NodeRelation *arc = *drp.begin();
+    if (consider_arc(arc)) {
+      if (flatten_arc(arc)) {
+	num_nodes++;
       }
     }
   }
@@ -161,17 +155,12 @@ flatten_siblings(Node *root) {
   typedef map<NodeRelation *, list<NodeRelation *>, SortByTransitions> Children;
   Children children;
 
-  DownRelations::const_iterator dri;
-  dri = root->_children.find(_graph_type);
-  if (dri != root->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      NodeRelation *arc = (*drpi);
-
-      children[arc].push_back(arc);
-    }
+  const DownRelationPointers &drp = 
+    root->find_connection(_graph_type).get_down();
+  DownRelationPointers::const_iterator drpi;
+  for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
+    NodeRelation *arc = (*drpi);
+    children[arc].push_back(arc);
   }
 
   // Now visit each of those groups and try to collapse them together.

+ 41 - 0
panda/src/graph/node.I

@@ -6,6 +6,47 @@
 #include <notify.h>
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Node::find_connection
+//       Access: Public
+//  Description: Returns a const reference to the NodeConnection of
+//               the indicated graph type, if one exists, or a const
+//               reference to an empty NodeConnection if a connection
+//               of the indicated type does not exist.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH const NodeConnection &Node::
+find_connection(TypeHandle graph_type) const {
+  if (_connections[0].get_graph_type() == graph_type) {
+    return _connections[0];
+  }
+  if (max_node_graphs > 1) {
+    return p_find_connection(graph_type);
+  } else {
+    return _empty_connection;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Node::update_connection
+//       Access: Public
+//  Description: Returns a non-const pointer to the NodeConnection of
+//               the indicated graph type, if one exists.  If a
+//               NodeConnection of the indicated type does not already
+//               exist, creates one if possible and returns its
+//               pointer.  Otherwise, returns NULL.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH NodeConnection *Node::
+update_connection(TypeHandle graph_type) {
+  if (_connections[0].get_graph_type() == graph_type) {
+    return &_connections[0];
+  }
+  if (max_node_graphs > 1) {
+    return p_update_connection(graph_type);
+  } else {
+    return (NodeConnection *)NULL;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: remove_child
 //  Description: Finds the arc that connects the indicated nodes and

+ 181 - 123
panda/src/graph/node.cxx

@@ -11,9 +11,11 @@
 #include <datagram.h>
 #include <indent.h>
 
+NodeConnection Node::_empty_connection;
 TypeHandle Node::_type_handle;
 Node* const Node::Null = (Node*)0L;
 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Node::Constructor
 //       Access: Public
@@ -26,7 +28,11 @@ Node() {
 ////////////////////////////////////////////////////////////////////
 //     Function: Node::Copy Constructor
 //       Access: Public
-//  Description: 
+//  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 &copy) :
@@ -59,22 +65,23 @@ 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.
-  UpRelations::iterator uri;
-  for (uri = _parents.begin(); uri != _parents.end(); ++uri) {
-    nassertv((*uri).second.empty());
+  int i;
+  for (i = 0; i < max_node_graphs; i++) {
+    UpRelationPointers &urp = _connections[i].get_up();
+    nassertv(urp.empty());
   }
 
-  DownRelations::iterator dri;
-  for (dri = _children.begin(); dri != _children.end(); ++dri) {
-    DownRelationPointers &drp = (*dri).second;
+  // 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) {
-      PT(NodeRelation) relation = (*drpi);
+      NodeRelation *arc = (*drpi);
 
       // This deletes the arc and anything below it through the magic
       // of reference-counting.
-      relation->detach_below();
+      arc->detach_below();
     }
   }
 }
@@ -168,12 +175,8 @@ transform_changed(NodeRelation *) {
 ////////////////////////////////////////////////////////////////////
 int Node::
 get_num_parents(TypeHandle type) const {
-  UpRelations::const_iterator uri;
-  uri = _parents.find(type);
-  if (uri == _parents.end()) {
-    return 0;
-  }
-  return (*uri).second.size();
+  const UpRelationPointers &urp = find_connection(type).get_up();
+  return urp.size();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -185,12 +188,10 @@ get_num_parents(TypeHandle type) const {
 ////////////////////////////////////////////////////////////////////
 NodeRelation *Node::
 get_parent(TypeHandle type, int index) const {
-  UpRelations::const_iterator uri;
-  uri = _parents.find(type);
-  nassertr(uri != _parents.end(), (NodeRelation *)NULL);
-  nassertr(index >= 0 && index < (int)(*uri).second.size(),
+  const UpRelationPointers &urp = find_connection(type).get_up();
+  nassertr(index >= 0 && index < (int)urp.size(),
 	   (NodeRelation *)NULL);
-  return (*uri).second[index];
+  return urp[index];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -202,12 +203,8 @@ get_parent(TypeHandle type, int index) const {
 ////////////////////////////////////////////////////////////////////
 int Node::
 get_num_children(TypeHandle type) const {
-  DownRelations::const_iterator dri;
-  dri = _children.find(type);
-  if (dri == _children.end()) {
-    return 0;
-  }
-  return (*dri).second.size();
+  const DownRelationPointers &drp = find_connection(type).get_down();
+  return drp.size();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -219,12 +216,10 @@ get_num_children(TypeHandle type) const {
 ////////////////////////////////////////////////////////////////////
 NodeRelation *Node::
 get_child(TypeHandle type, int index) const {
-  DownRelations::const_iterator dri;
-  dri = _children.find(type);
-  nassertr(dri != _children.end(), (NodeRelation *)NULL);
-  nassertr(index >= 0 && index < (int)(*dri).second.size(), 
+  const DownRelationPointers &drp = find_connection(type).get_down();
+  nassertr(index >= 0 && index < (int)drp.size(),
 	   (NodeRelation *)NULL);
-  return (*dri).second[index];
+  return drp[index];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -274,6 +269,49 @@ write(ostream &out, int indent_level) const {
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     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
@@ -284,10 +322,8 @@ write(ostream &out, int indent_level) const {
 void Node::
 propagate_stale_bound() {
   // Mark all of our parent arcs, in all graphs, stale as well.
-  UpRelations::const_iterator uri;
-  for (uri = _parents.begin(); uri != _parents.end(); ++uri) {
-    const UpRelationPointers &urp = (*uri).second;
-    
+  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();
@@ -324,10 +360,10 @@ r_copy_subgraph(TypeHandle graph_type, Node::InstanceMap &inst_map) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: Node::r_copy_children
 //       Access: Protected, Virtual
-//  Description: This is called by r_deep_copy(); 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.
+//  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
@@ -339,39 +375,35 @@ r_copy_subgraph(TypeHandle graph_type, Node::InstanceMap &inst_map) const {
 void Node::
 r_copy_children(const Node *from, TypeHandle graph_type, 
 		Node::InstanceMap &inst_map) {
-  DownRelations::const_iterator dri;
-  dri = from->_children.find(graph_type);
-  if (dri != from->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
+  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);
     
-    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);
+    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);
   }
 }
 
@@ -389,18 +421,29 @@ write_datagram(BamWriter *manager, Datagram &me) {
   // write out all of the UpRelations then writing any node in a graph
   // would cause the entire graph to be written out.
 
-  me.add_uint16(_children.size());
+  // 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);
 
-  DownRelations::iterator dri;
-  for (dri = _children.begin(); dri != _children.end(); ++dri) {
-    manager->write_handle(me, (*dri).first);
+  // 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());
 
-    DownRelationPointers &drp = (*dri).second;
-    me.add_uint16(drp.size());
-    DownRelationPointers::iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      NodeRelation *relation = (*drpi);
-      manager->write_pointer(me, relation);
+      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);
+      }
     }
   }
 }
@@ -420,28 +463,37 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
     // the arcs are completely responsible for adding themselves to
     // our list); we only need to return the number of pointers we
     // expected to receive.
-    return _num_pointers;
+
+    // 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 i = 0;
+  int count = 0;
 
-  DownRelations::iterator dri;
-  for (dri = _children.begin(); dri != _children.end(); ++dri) {
-    DownRelationPointers &drp = (*dri).second;
+  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) {
-      nassertr(i < _num_pointers, _num_pointers);
-      (*drpi) = DCAST(NodeRelation, plist[i]);
-      i++;
+      DownRelationPointers::iterator drpi;
+      for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
+	(*drpi) = DCAST(NodeRelation, plist[count]);
+	count++;
+      }
     }
   }
 
-  nassertr(i == _num_pointers, _num_pointers);
-  return _num_pointers;
+  return count;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -450,8 +502,7 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 //  Description: Factory method to generate a node object
 ////////////////////////////////////////////////////////////////////
 TypedWriteable* Node::
-make_Node(const FactoryParams &params)
-{
+make_Node(const FactoryParams &params) {
   Node *me = new Node;
   BamReader *manager;
   Datagram packet;
@@ -477,14 +528,12 @@ fillin(DatagramIterator &scan, BamReader *manager) {
     // 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.
-    _num_pointers = 0;
     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_pointers++;
 	num_arcs--;
       }
       num_types--;
@@ -494,24 +543,38 @@ fillin(DatagramIterator &scan, BamReader *manager) {
     // 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, rather than depending on
-    // _num_pointers.
-
-    _num_pointers = 0;
-    int num_types = scan.get_uint16();
-
-    while (num_types > 0) {
+    // 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 = _children[type];
-      int num_arcs = scan.get_uint16();
-      while (num_arcs > 0) {
-	manager->read_pointer(scan, this);
-	drp.push_back((NodeRelation *)NULL);
-	_num_pointers++;
-	num_arcs--;
+	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--;
+	}
       }
-      num_types--;
     }
   }
 }
@@ -522,8 +585,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 //  Description: Factory method to generate a node object
 ////////////////////////////////////////////////////////////////////
 void Node::
-register_with_read_factory(void)
-{
+register_with_read_factory(void) {
   BamReader::get_factory()->register_factory(get_class_type(), make_Node);
 }
 
@@ -540,16 +602,12 @@ find_arc(Node *parent, Node *child, TypeHandle graph_type) {
   // the parent arc, on the assumption there are likely to be fewer
   // parents than children.
 
-  UpRelations::const_iterator uri = child->_parents.find(graph_type);
-
-  if (uri != child->_parents.end()) {
-    const UpRelationPointers &urp = (*uri).second;
-    UpRelationPointers::const_iterator urpi;
-    for (urpi = urp.begin(); urpi != urp.end(); ++urpi) {
-      if ((*urpi)->get_parent() == parent && 
-	  (*urpi)->get_child() == child) {
-	return (*urpi);
-      }
+  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;
     }
   }
 

+ 14 - 13
panda/src/graph/node.h

@@ -9,6 +9,7 @@
 
 #include "nodeRelation.h"
 #include "boundedObject.h"
+#include "nodeConnection.h"
 
 #include <typedWriteable.h>
 #include <referenceCount.h>
@@ -23,6 +24,10 @@ class BamReader;
 class Datagram;
 class DatagramIterator;
 
+// This is the maximum number of graph types a node may simultaneously
+// exist in.
+static const int max_node_graphs = 2;
+
 ////////////////////////////////////////////////////////////////////
 // 	 Class : Node
 // Description : The base class for all scene graph nodes.  A Node may
@@ -77,6 +82,7 @@ PUBLISHED:
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
 
+public:
   // We reference-count the child pointer, but not the parent pointer,
   // to avoid circular reference counting.
 
@@ -84,9 +90,15 @@ PUBLISHED:
   // through the scene graph when necessary, but beware!  It is not
   // safe to access these members directly outside of PANDA.DLL.
   // Instead, use the get_parent()/get_child() interface, above.
+  INLINE_GRAPH const NodeConnection &find_connection(TypeHandle graph_type) const;
+  INLINE_GRAPH NodeConnection *update_connection(TypeHandle graph_type);
+
+  NodeConnection _connections[max_node_graphs];
 
-  UpRelations _parents;
-  DownRelations _children;
+private:
+  const NodeConnection &p_find_connection(TypeHandle graph_type) const;
+  NodeConnection *p_update_connection(TypeHandle graph_type);
+  static NodeConnection _empty_connection;
 
 protected:
   virtual void propagate_stale_bound();
@@ -108,17 +120,6 @@ public:
 protected:
   void fillin(DatagramIterator& scan, BamReader* manager);
 
-private:
-  //This variable is set inside fillin to the number of pointers
-  //that are "read" by Node.  This needs to be set, even though
-  //node does nothing in complete_pointers, because it needs to
-  //return the number of pointer requests that it made.  This 
-  //is necessary because the vector of pointers to TypedWriteables
-  //that is given to it by BamReader, will be filled with those requests
-  //and any children of Node, need to be able to ignore those as well.
-  //So complete_pointers must return the correct number read
-  int _num_pointers;
-
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 127 - 0
panda/src/graph/nodeConnection.I

@@ -0,0 +1,127 @@
+// Filename: nodeConnection.I
+// Created by:  drose (07May01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH NodeConnection::
+NodeConnection(TypeHandle graph_type) : _graph_type(graph_type) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH NodeConnection::
+~NodeConnection() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::Copy Constructor
+//       Access: Private
+//  Description: The copy constructor is private.  Copying
+//               NodeConnections is not a good idea.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH NodeConnection::
+NodeConnection(const NodeConnection &copy) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::Copy Assignment Operator
+//       Access: Private
+//  Description: The assignment constructor is private.  Copying
+//               NodeConnections is not a good idea.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH void NodeConnection::
+operator = (const NodeConnection &copy) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::is_empty
+//       Access: Public
+//  Description: Returns true if the NodeConnection has no arcs, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH bool NodeConnection::
+is_empty() const {
+  return _up.empty() && _down.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::get_graph_type
+//       Access: Public
+//  Description: Returns the type of graph represented by this
+//               NodeConnection.  A node can coexist simultaneously in
+//               several different graphs of different types; each
+//               type requires a NodeConnection object to be stored
+//               with the node.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH TypeHandle NodeConnection::
+get_graph_type() const {
+  return _graph_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::set_graph_type
+//       Access: Public
+//  Description: Changes the type of graph represented by this
+//               NodeConnection.  It is legal to do this only when the
+//               NodeConnection is empty, i.e. is_empty() returns
+//               true.
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH void NodeConnection::
+set_graph_type(TypeHandle graph_type) {
+  nassertv(is_empty());
+  _graph_type = graph_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::get_up
+//       Access: Public
+//  Description: Returns the list of arcs pointing to the node's
+//               parent(s).
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH UpRelationPointers &NodeConnection::
+get_up() {
+  return _up;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::get_up
+//       Access: Public
+//  Description: Returns the list of arcs pointing to the node's
+//               parent(s).
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH const UpRelationPointers &NodeConnection::
+get_up() const {
+  return _up;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::get_down
+//       Access: Public
+//  Description: Returns the list of arcs pointing to the node's
+//               child(ren).
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH DownRelationPointers &NodeConnection::
+get_down() {
+  return _down;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConnection::get_down
+//       Access: Public
+//  Description: Returns the list of arcs pointing to the node's
+//               child(ren).
+////////////////////////////////////////////////////////////////////
+INLINE_GRAPH const DownRelationPointers &NodeConnection::
+get_down() const {
+  return _down;
+}

+ 7 - 0
panda/src/graph/nodeConnection.cxx

@@ -0,0 +1,7 @@
+// Filename: nodeConnection.cxx
+// Created by:  drose (07May01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "node.h"
+#include "nodeConnection.h"

+ 57 - 0
panda/src/graph/nodeConnection.h

@@ -0,0 +1,57 @@
+// Filename: nodeConnection.h
+// Created by:  drose (07May01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef NODECONNECTION_H
+#define NODECONNECTION_H
+
+#include <pandabase.h>
+
+#include "nodeRelation.h"
+#include "config_graph.h"
+
+
+///////////////////////////////////////////////////////////////////
+// 	 Class : NodeConnection
+// Description : This class represents the table, stored within each
+//               Node, of all the connected NodeRelations (arcs) of a
+//               particular graph type.
+//
+//               Node that this class is not exported from PANDA.DLL.
+//               You should use the get_parent()/get_child() interface
+//               to Node for code outside of PANDA.DLL.
+////////////////////////////////////////////////////////////////////
+class NodeConnection {
+public:
+  INLINE_GRAPH NodeConnection(TypeHandle graph_type = TypeHandle::none());
+  INLINE_GRAPH ~NodeConnection();
+
+private:
+  INLINE_GRAPH NodeConnection(const NodeConnection &copy);
+  INLINE_GRAPH void operator = (const NodeConnection &copy);
+
+public:
+  INLINE_GRAPH bool is_empty() const;
+
+  INLINE_GRAPH TypeHandle get_graph_type() const;
+  INLINE_GRAPH void set_graph_type(TypeHandle graph_type);
+
+  INLINE_GRAPH UpRelationPointers &get_up();
+  INLINE_GRAPH const UpRelationPointers &get_up() const;
+
+  INLINE_GRAPH DownRelationPointers &get_down();
+  INLINE_GRAPH const DownRelationPointers &get_down() const;
+
+private:
+  TypeHandle _graph_type;
+  UpRelationPointers _up;
+  DownRelationPointers _down;
+};
+
+#ifndef DONT_INLINE_GRAPH
+#include "nodeConnection.I"
+#endif
+
+#endif
+

+ 69 - 59
panda/src/graph/nodeRelation.cxx

@@ -49,16 +49,16 @@ init_last_graph_update() {
 
 // Following are a handful of local template functions that provide
 // support for manipulating the list of arcs on nodes.  They are
-// template functions because they work as well on UpRelationArcs as
-// as they do on DownRelationArcs, which are slightly different things
-// (DownRelationArcs are reference-counting).
+// template functions because they work as well on UpRelationPointers
+// as as they do on DownRelationPointers, which are slightly different
+// things (DownRelationPointers are reference-counting).
 
 ////////////////////////////////////////////////////////////////////
 //     Function: verify_arc_list
 //  Description: A local template function that verifies that the list
-//               of arcs (either UpRelationArcs or DownRelationArcs)
-//               is correctly sorted, if paranoid_graph is set.
-//               Otherwise, it does nothing.
+//               of arcs (either UpRelationPointers or
+//               DownRelationPointers) is correctly sorted, if
+//               paranoid_graph is set.  Otherwise, it does nothing.
 ////////////////////////////////////////////////////////////////////
 #ifdef NDEBUG
 template<class Iterator>
@@ -87,9 +87,9 @@ verify_arc_list(Iterator begin, Iterator end) {
 ////////////////////////////////////////////////////////////////////
 //     Function: find_insert_position
 //  Description: A local template function that performs a binary
-//               search on the arcs list (either UpRelationArcs or
-//               DownRelationArcs) and finds the place to insert the
-//               indicated arc.
+//               search on the arcs list (either UpRelationPointers or
+//               DownRelationPointers) and finds the place to insert
+//               the indicated arc.
 //
 //               This place will be at the end of the similarly-sorted
 //               arcs.
@@ -141,10 +141,10 @@ find_insert_position(Iterator begin, Iterator end, NodeRelation *arc) {
 ////////////////////////////////////////////////////////////////////
 //     Function: find_arc
 //  Description: A local template function that performs a binary
-//               search on the arcs list (either UpRelationArcs or
-//               DownRelationArcs) and finds the arc's position within
-//               the list.  It returns end if the arc is not within
-//               the list.
+//               search on the arcs list (either UpRelationPointers or
+//               DownRelationPointers) and finds the arc's position
+//               within the list.  It returns end if the arc is not
+//               within the list.
 ////////////////////////////////////////////////////////////////////
 template<class Iterator>
 static Iterator
@@ -609,13 +609,25 @@ attach() {
   nassertv(_child != (Node*)NULL);
   nassertv(!_attached);
 
-  _attached = true;
-  if (_parent_ref != 0) {
-    _parent->ref();
+  NodeConnection *parent_connection = _parent->update_connection(_graph_type);
+  NodeConnection *child_connection = _child->update_connection(_graph_type);
+
+  if (parent_connection == (NodeConnection *)NULL) {
+    graph_cat.error()
+      << "Attempt to attach " << _parent << " simultaneously to more than " 
+      << max_node_graphs << " different graph types.\n";
+    nassertv(false);
   }
 
-  DownRelationPointers &parent_list = _parent->_children[_graph_type];
-  UpRelationPointers &child_list = _child->_parents[_graph_type];
+  if (child_connection == (NodeConnection *)NULL) {
+    graph_cat.error()
+      << "Attempt to attach " << _child << " simultaneously to more than " 
+      << max_node_graphs << " different graph types.\n";
+    nassertv(false);
+  }
+
+  DownRelationPointers &parent_list = parent_connection->get_down();
+  UpRelationPointers &child_list = child_connection->get_up();
   
   bool inserted_one = internal_insert_arc(parent_list, this);
   bool inserted_two = internal_insert_arc(child_list, this);
@@ -634,6 +646,11 @@ attach() {
     child_list[1]->_last_update = _last_update;
   }
 
+  _attached = true;
+  if (_parent_ref != 0) {
+    _parent->ref();
+  }
+
   _parent->force_bound_stale();
   mark_bound_stale();
 }
@@ -664,8 +681,16 @@ detach() {
 
   force_bound_stale();
 
-  DownRelationPointers &parent_list = _parent->_children[_graph_type];
-  UpRelationPointers &child_list = _child->_parents[_graph_type];
+  NodeConnection *parent_connection = _parent->update_connection(_graph_type);
+  NodeConnection *child_connection = _child->update_connection(_graph_type);
+
+  // These should never be NULL, because we're already attached, after
+  // all.
+  nassertr(parent_connection != (NodeConnection *)NULL &&
+	   child_connection != (NodeConnection *)NULL, result);
+
+  DownRelationPointers &parent_list = parent_connection->get_down();
+  UpRelationPointers &child_list = child_connection->get_up();
 
   bool removed_one = internal_remove_arc(parent_list, this);
   bool removed_two = internal_remove_arc(child_list, this);
@@ -690,16 +715,6 @@ detach() {
     child_list[0]->_last_update = _last_update;
   }
 
-  // If we have completely emptied the parent or child lists, remove
-  // the entry for this graph type from the node, as a small render
-  // optimization.
-  if (parent_list.empty()) {
-    _parent->_children.erase(_graph_type);
-  }
-  if (child_list.empty()) {
-    _child->_parents.erase(_graph_type);
-  }
-
   return result;
 }
 
@@ -721,7 +736,11 @@ detach_below() {
 
   force_bound_stale();
 
-  bool removed = internal_remove_arc(_child->_parents[_graph_type], this);
+  NodeConnection *child_connection = _child->update_connection(_graph_type);
+  nassertr(child_connection != (NodeConnection *)NULL, result);
+
+  UpRelationPointers &child_list = child_connection->get_up();
+  bool removed = internal_remove_arc(child_list, this);
 
   nassertr(removed, result);
 
@@ -767,15 +786,10 @@ propagate_stale_bound() {
   Node *node = _parent;
   nassertv(node != (Node*)NULL);
 
-  UpRelations::const_iterator uri;
-  uri = node->_parents.find(_graph_type);
-  if (uri != node->_parents.end()) {
-    const UpRelationPointers &urp = (*uri).second;
-    
-    UpRelationPointers::const_iterator urpi;
-    for (urpi = urp.begin(); urpi != urp.end(); ++urpi) {
-      (*urpi)->mark_bound_stale();
-    }
+  const UpRelationPointers &urp = node->find_connection(_graph_type).get_up();
+  UpRelationPointers::const_iterator urpi;
+  for (urpi = urp.begin(); urpi != urp.end(); ++urpi) {
+    (*urpi)->mark_bound_stale();
   }
 }
 
@@ -800,15 +814,11 @@ recompute_bound() {
 
   child_volumes.push_back(&node->get_bound());
 
-  DownRelations::const_iterator dri;
-  dri = node->_children.find(_graph_type);
-  if (dri != node->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-    
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      child_volumes.push_back(&(*drpi)->get_bound());
-    }
+  const DownRelationPointers &drp = 
+    node->find_connection(_graph_type).get_down();
+  DownRelationPointers::const_iterator drpi;
+  for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
+    child_volumes.push_back(&(*drpi)->get_bound());
   }
 
   bool success = 
@@ -855,8 +865,7 @@ write_datagram(BamWriter *manager, Datagram &me)
   //Now write out all the Transitions on this arc
   me.add_uint16(_transitions.size());
   NodeTransitions::iterator ci;
-  for(ci = _transitions.begin(); ci != _transitions.end(); ci++)
-  {
+  for(ci = _transitions.begin(); ci != _transitions.end(); ci++) {
     manager->write_pointer(me, (*ci).second);
   }
 }
@@ -865,13 +874,12 @@ write_datagram(BamWriter *manager, Datagram &me)
 ////////////////////////////////////////////////////////////////////
 //     Function: NodeRelation::complete_pointers
 //       Access: Public
-//  Description: Takes in a vector of pointes to TypedWriteable
+//  Description: Takes in a vector of pointers to TypedWriteable
 //               objects that correspond to all the requests for 
 //               pointers that this object made to BamReader.
 ////////////////////////////////////////////////////////////////////
 int NodeRelation::
-complete_pointers(vector_typedWriteable &plist, BamReader *manager)
-{
+complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
   nassertr(plist[0] != TypedWriteable::Null &&
 	   plist[1] != TypedWriteable::Null, 0);
   _parent = DCAST(Node, plist[0]);
@@ -889,10 +897,13 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager)
 
     // We must explicitly add the arc to its child node, but not to
     // its parent node.
-    UpRelationPointers &child_list = _child->_parents[_graph_type];
-    bool inserted = internal_insert_arc(child_list, this);
-    nassertr(inserted, _num_transitions + 2);
-    _attached = true;
+    NodeConnection *child_connection = _child->update_connection(_graph_type);
+    if (child_connection != (NodeConnection *)NULL) {
+      UpRelationPointers &child_list = child_connection->get_up();
+      bool inserted = internal_insert_arc(child_list, this);
+      nassertr(inserted, _num_transitions + 2);
+      _attached = true;
+    }
   }
 
   //The rest of this is the list of Transitions
@@ -1072,4 +1083,3 @@ clear_transition(TypeHandle handle) {
   changed_transition(handle);
   return old_trans;
 }
-

+ 0 - 3
panda/src/graph/nodeRelation.h

@@ -223,10 +223,7 @@ EXPCL_PANDA INLINE_GRAPH ostream &
 operator << (ostream &out, const NodeRelation &arc);
 
 typedef vector< PT(NodeRelation) > DownRelationPointers;
-typedef map<TypeHandle, DownRelationPointers> DownRelations;
-
 typedef vector<NodeRelation *> UpRelationPointers;
-typedef map<TypeHandle, UpRelationPointers> UpRelations;
 
 #include "nodeRelation.T"
 

+ 3 - 2
panda/src/graph/nodeTransitionCache.cxx

@@ -73,8 +73,9 @@ is_identity() const {
 ////////////////////////////////////////////////////////////////////
 int NodeTransitionCache::
 compare_to(const NodeTransitionCache &other) const {
-  return tmap_compare_cache(_cache.begin(), _cache.end(),
-			    other._cache.begin(), other._cache.end());
+   int result = tmap_compare_cache(_cache.begin(), _cache.end(),
+				   other._cache.begin(), other._cache.end());
+   return result;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 0 - 49
panda/src/graph/test_graphRead.cxx

@@ -1,49 +0,0 @@
-// Filename: test_graphRead.cxx
-// Created by:  jason (15Jun00)
-
-#include "nodeRelation.h"
-#include "namedNode.h"
-#include "pt_NamedNode.h"
-#include <bamWriter.h>
-#include <ipc_file.h>
-
-#include <indent.h>
-
-int main() {
-  string test_file = "graphTest.out";
-  datagram_file stream(test_file);
-  BamReader manager(&stream);
-  stream.open(file::FILE_READ);
-  
-  manager.init();
-  
-  PT_NamedNode r = DCAST(NamedNode, manager.read_object());
-  PT_NamedNode a = DCAST(NamedNode, manager.read_object());
-  PT_NamedNode b = DCAST(NamedNode, manager.read_object());
-  PT_NamedNode aa = DCAST(NamedNode, manager.read_object());
-  PT_NamedNode ab = DCAST(NamedNode, manager.read_object());
-  PT_NamedNode ba = DCAST(NamedNode, manager.read_object());
-  
-  NodeRelation *r_a = DCAST(NodeRelation, manager.read_object());
-  NodeRelation *r_b = DCAST(NodeRelation, manager.read_object());
-  NodeRelation *a_aa = DCAST(NodeRelation, manager.read_object());
-  NodeRelation *a_ab = DCAST(NodeRelation, manager.read_object());
-  NodeRelation *b_ba = DCAST(NodeRelation, manager.read_object());
-  
-  manager.resolve();
-
-  r_a->output(nout);
-  nout << endl;
-  r_b->output(nout);
-  nout << endl;
-  a_aa->output(nout);
-  nout << endl;
-  a_ab->output(nout);
-  nout << endl;
-  b_ba->output(nout);
-  nout << endl;
-
-  stream.close();
-
-  return 0;
-}

+ 0 - 68
panda/src/graph/test_graphWrite.cxx

@@ -1,68 +0,0 @@
-// Filename: test_graphWrite.cxx
-// Created by:  jason (15Jun00)
-
-#include "nodeRelation.h"
-#include "namedNode.h"
-#include "pt_NamedNode.h"
-#include <bamWriter.h>
-#include <ipc_file.h>
-
-#include <indent.h>
-
-int main() {
-  string test_file = "graphTest.out";
-  datagram_file stream(test_file);
-  BamWriter manager(&stream);
-  stream.open(file::FILE_WRITE);
-  
-  PT_NamedNode r = new NamedNode("r");
-
-  PT_NamedNode a = new NamedNode("a");
-  PT_NamedNode b = new NamedNode("b");
-
-  PT_NamedNode aa = new NamedNode("aa");
-  PT_NamedNode ab = new NamedNode("ab");
-  PT_NamedNode ba = new NamedNode("ba");
-
-  NodeRelation *r_a =
-    new NodeRelation(r, a, 0, NodeRelation::get_class_type());
-  NodeRelation *r_b =
-    new NodeRelation(r, b, 0, NodeRelation::get_class_type());
-
-  NodeRelation *a_aa =
-    new NodeRelation(a, aa, 0, NodeRelation::get_class_type());
-  NodeRelation *a_ab =
-    new NodeRelation(a, ab, 0, NodeRelation::get_class_type());
-  NodeRelation *b_ba =
-    new NodeRelation(b, ba, 0, NodeRelation::get_class_type());
-  
-  r_a->output(nout);
-  nout << endl;
-  r_b->output(nout);
-  nout << endl;
-  a_aa->output(nout);
-  nout << endl;
-  a_ab->output(nout);
-  nout << endl;
-  b_ba->output(nout);
-  nout << endl;
-
-  if (manager.init())
-  {
-    manager.write_object(r);
-    manager.write_object(a);
-    manager.write_object(b);
-    manager.write_object(aa);
-    manager.write_object(ab);
-    manager.write_object(ba);
-
-    manager.write_object(r_a);
-    manager.write_object(r_b);
-    manager.write_object(a_aa);
-    manager.write_object(a_ab);
-    manager.write_object(b_ba);
-  }
-
-  stream.close();
-  return 0;
-}

+ 45 - 84
panda/src/graph/wrt.I

@@ -15,18 +15,20 @@ void
 describe_ambiguous_wrt(const Node *node,
 		       InputIterator arc_list_begin, 
 		       InputIterator arc_list_end,
-		       const UpRelationPointers &urp) {
+		       TypeHandle graph_type) {
   if (wrt_cat.is_warning()) {
+    int num_parents = node->get_num_parents(graph_type);
     wrt_cat.warning()
-      << *node << " has " << urp.size() << " parents; wrt() ambiguous.\n"
+      << *node << " has " << num_parents << " parents; wrt() ambiguous.\n"
       << "  parents are: ";
-    UpRelationPointers::const_iterator urpi;
-    urpi = urp.begin();
-    wrt_cat.warning(false) << *(*urpi)->get_parent();
-    urpi++;
-    while (urpi != urp.end()) {  
-      wrt_cat.warning(false) << ", " << *(*urpi)->get_parent();
-      urpi++;
+    nassertv(num_parents > 1);
+
+    NodeRelation *parent_arc = node->get_parent(graph_type, 0);
+    wrt_cat.warning(false) << *parent_arc->get_parent();
+    for (int i = 1; i < num_parents; i++) {
+      parent_arc = node->get_parent(graph_type, 0);
+      wrt_cat.warning(false) 
+	<< ", " << *node->get_parent(graph_type, i)->get_parent();
     }
     wrt_cat.warning(false) << "\n";
     
@@ -129,16 +131,15 @@ get_cached_net_transition(NodeRelation *arc, Node *&root,
     // Get the node above the arc.
     Node *node = arc->get_parent();
 
-    UpRelations::const_iterator uri;
-    uri = node->_parents.find(graph_type);
+    int num_parents = node->get_num_parents(graph_type);
 
-    if (uri == node->_parents.end() || (*uri).second.size() != 1) {
+    if (num_parents != 1) {
       // The node has zero or multiple parents.  It's thus either the
       // top of the scene graph, or it's the first ancestor with
       // multiple parents; in either case, it's as far as we can take
       // the caching.  Stop here.
 
-      if (uri == node->_parents.end() || (*uri).second.empty()) {
+      if (num_parents == 0) {
 	// The node is the very top of the scene graph.  We'll treat
 	// this as a special case by setting the node to NULL.  This
 	// will tell our calling function that there's no need to look
@@ -154,8 +155,8 @@ get_cached_net_transition(NodeRelation *arc, Node *&root,
     } else {
       // The node has exactly one parent.  Carry on.
 
-      NodeRelation *parent = *(*uri).second.begin();
-      get_cached_net_transition(parent, root, as_of, now, net, graph_type);
+      NodeRelation *parent_arc = node->get_parent(graph_type, 0);
+      get_cached_net_transition(parent_arc, root, as_of, now, net, graph_type);
 
       // Now recompute our own cache.
       TransitionWrapper cur_value = TransitionWrapper::init_from(net);
@@ -222,27 +223,19 @@ get_cached_net_transition(const Node *node,
     return;
   }
 
-  UpRelations::const_iterator uri;
-  uri = node->_parents.find(graph_type);
+  int num_parents = node->get_num_parents(graph_type);
 
-  if (uri == node->_parents.end()) {
-    // This node has no parents.  Stop here.
-    result.make_identity();
+  const NodeRelation *parent_arc = (const NodeRelation *)NULL;
 
-#ifndef NDEBUG
-    if (wrt_cat.is_debug()) {
-      wrt_cat.debug()
-	<< "get_cached_net_transition(" << *node << ") has no parents.\n";
-    }
-#endif
-    return;
-  }
+  if (num_parents == 1) {
+    // There is only one parent, so there's no doubt as to which arc
+    // to choose.
+    parent_arc = node->get_parent(graph_type, 0);
 
-  const UpRelationPointers &urp = (*uri).second;
-  if (urp.empty()) {
-    // Again, this node has no parents.
+  } else if (num_parents == 0) {
+    // This node has no parents.  Stop here.
     result.make_identity();
-
+    
 #ifndef NDEBUG
     if (wrt_cat.is_debug()) {
       wrt_cat.debug()
@@ -250,14 +243,6 @@ get_cached_net_transition(const Node *node,
     }
 #endif
     return;
-  }
-
-  const NodeRelation *parent_arc = (const NodeRelation *)NULL;
-
-  if (urp.size() == 1) {
-    // There is only one parent, so there's no doubt as to which arc
-    // to choose.
-    parent_arc = *(urp.begin());
 
   } else {
     // The node has multiple parents, and we have a list of arcs in
@@ -275,9 +260,9 @@ get_cached_net_transition(const Node *node,
 #ifndef NDEBUG
       // No, it wasn't mentioned.  Issue a warning and use the first
       // one.
-      describe_ambiguous_wrt(node, arc_list_begin, arc_list_end, urp);
+      describe_ambiguous_wrt(node, arc_list_begin, arc_list_end, graph_type);
 #endif
-      parent_arc = *(urp.begin());
+      parent_arc = node->get_parent(graph_type, 0);
     }
   }
 
@@ -332,36 +317,23 @@ get_uncached_net_transition(const Node *node,
     return;
   }
 
-  UpRelations::const_iterator uri;
-  uri = node->_parents.find(graph_type);
+  int num_parents = node->get_num_parents(graph_type);
 
-  if (uri == node->_parents.end()) {
-    // This node has no parents.  Stop here.
-    if (wrt_cat.is_spam()) {
-      wrt_cat.spam()
-	<< "get_uncached_net_transition(" << *node << ") has no parents.\n";
-    }
-    result.make_identity();
-    return;
-  }
+  const NodeRelation *parent_arc = (const NodeRelation *)NULL;
 
-  const UpRelationPointers &urp = (*uri).second;
-  if (urp.empty()) {
-    // Again, this node has no parents.
+  if (num_parents == 1) {
+    // There is only one parent, so there's no doubt as to which arc
+    // to choose.
+    parent_arc = node->get_parent(graph_type, 0);
+
+  } else if (num_parents == 0) {
+    // This node has no parents.  Stop here.
     if (wrt_cat.is_spam()) {
       wrt_cat.spam()
 	<< "get_uncached_net_transition(" << *node << ") has no parents.\n";
     }
     result.make_identity();
     return;
-  }
-
-  const NodeRelation *parent_arc = (const NodeRelation *)NULL;
-
-  if (urp.size() == 1) {
-    // There is only one parent, so there's no doubt as to which arc
-    // to choose.
-    parent_arc = *(urp.begin());
 
   } else {
     // The node has multiple parents, and we have a list of arcs in
@@ -379,9 +351,9 @@ get_uncached_net_transition(const Node *node,
 #ifndef NDEBUG
       // No, it wasn't mentioned.  Issue a warning and use the first
       // one. 
-      describe_ambiguous_wrt(node, arc_list_begin, arc_list_end, urp);
+      describe_ambiguous_wrt(node, arc_list_begin, arc_list_end, graph_type);
 #endif
-      parent_arc = *(urp.begin());
+      parent_arc = node->get_parent(graph_type, 0);
     }
   }
 
@@ -404,7 +376,7 @@ get_uncached_net_transition(const Node *node,
     }
     
     wrt_cat.spam(false)
-      << "), " << urp.size() << " parents, is:\n";
+      << "), " << num_parents << " parents, is:\n";
     result.write(wrt_cat.spam(false), 2);
   }
 }
@@ -647,22 +619,11 @@ Node *
 get_uncached_wrt_subtree(Node *node, Node *to, TransitionWrapper &result, 
 			 TypeHandle graph_type) {
   nassertr(node != (Node *)NULL, to);
-  UpRelations::const_iterator uri;
-  uri = node->_parents.find(graph_type);
 
-  if (uri == node->_parents.end()) {
-    // This node has no parents.  Stop here.
-    if (wrt_cat.is_spam()) {
-      wrt_cat.spam()
-	<< "get_uncached_wrt_subtree(" << *node << ") has no parents.\n";
-    }
-    result.make_identity();
-    return (Node *)NULL;
-  }
+  int num_parents = node->get_num_parents(graph_type);
 
-  const UpRelationPointers &urp = (*uri).second;
-  if (urp.empty()) {
-    // Again, no parents.  Stop here.
+  if (num_parents == 0) {
+    // This node has no parents.  Stop here.
     if (wrt_cat.is_spam()) {
       wrt_cat.spam()
 	<< "get_uncached_wrt_subtree(" << *node << ") has no parents.\n";
@@ -671,11 +632,11 @@ get_uncached_wrt_subtree(Node *node, Node *to, TransitionWrapper &result,
     return (Node *)NULL;
   }
 
-  if (urp.size() != 1) {
+  if (num_parents != 1) {
     // There are multiple parents, so stop here.
     if (wrt_cat.is_spam()) {
       wrt_cat.spam()
-	<< "get_uncached_wrt_subtree(" << *node << ") has " << urp.size()
+	<< "get_uncached_wrt_subtree(" << *node << ") has " << num_parents
 	<< " parents.\n";
     }
     result.make_identity();
@@ -706,7 +667,7 @@ get_uncached_wrt_subtree(Node *node, Node *to, TransitionWrapper &result,
     }
   }
 
-  const NodeRelation *parent_arc = *(urp.begin());
+  const NodeRelation *parent_arc = node->get_parent(graph_type, 0);
 
   Node *stop = 
     get_uncached_wrt_subtree(parent_arc->get_parent(), to,

+ 23 - 9
panda/src/putil/bamReader.cxx

@@ -283,15 +283,16 @@ read_pointer(DatagramIterator& scan, TypedWriteable* forWhom)
 {
   PN_uint16 objId = scan.get_uint16();
   _deferred_pointers[forWhom].push_back(objId);
-  //This is safe since we have already read the full datagram
-  //for the object requesting this object.  So there can be
-  //no collision on that front. 
-  //IMPORTANT NOTE:  This does make the assumption that
-  //that objects are requested by other objects in the same 
-  //order that they wrote them originally.
-
-  //Don't queue a read of a null pointer 
-  //or if the object has already been read
+  // This is safe since we have already read the full datagram for the
+  // object requesting this object.  So there can be no collision on
+  // that front.
+
+  // IMPORTANT NOTE: This does make the assumption that objects are
+  // requested by other objects in the same order that they wrote them
+  // originally.
+
+  // Don't queue a read of a null pointer or if the object has already
+  // been read
   if ((objId != 0) && (_created_objs.find(objId) == _created_objs.end()))
     queue(objId);
 }
@@ -310,6 +311,19 @@ read_pointers(DatagramIterator &scan, TypedWriteable *forWhom, int count) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BamReader::skip_pointer
+//       Access: Public
+//  Description: Reads and discards a pointer value from the Bam file.
+//               This pointer will not be counted among the pointers
+//               read for a given object, and will not be in the list
+//               of pointers passed to complete_pointers().
+////////////////////////////////////////////////////////////////////
+void BamReader::
+skip_pointer(DatagramIterator &scan) {
+  scan.get_uint16();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::register_finalize
 //       Access: Public

+ 1 - 0
panda/src/putil/bamReader.h

@@ -66,6 +66,7 @@ public:
   //can register in itself for later "fixing"
   void read_pointer(DatagramIterator &scan, TypedWriteable* forWhom);
   void read_pointers(DatagramIterator &scan, TypedWriteable* forWhom, int count);
+  void skip_pointer(DatagramIterator &scan);
 
   //At any time you can call this function to try and resolve all
   //outstanding pointer requests.  Will resolve all requests that

+ 8 - 13
panda/src/sgmanip/findApproxLevel.cxx

@@ -68,19 +68,14 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
   if (next_is_stashed()) {
     next_graph_type = NodeRelation::get_stashed_type();
   }
-  
-  DownRelations::const_iterator dri;
-  dri = bottom_node->_children.find(next_graph_type);
-  if (dri != bottom_node->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-    
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      NodeRelation *arc = (*drpi);
-      consider_next_step(result, arc, next_level, max_matches, graph_type);
-      if (max_matches > 0 && result.get_num_paths() >= max_matches) {
-	return;
-      }
+
+  int num_children = bottom_node->get_num_children(next_graph_type);
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *child_arc = bottom_node->get_child(next_graph_type, i);
+
+    consider_next_step(result, child_arc, next_level, max_matches, graph_type);
+    if (max_matches > 0 && result.get_num_paths() >= max_matches) {
+      return;
     }
   }
 }

+ 42 - 67
panda/src/sgmanip/nodePath.cxx

@@ -263,18 +263,13 @@ get_children() const {
   nassertr(!is_empty(), result);
 
   Node *bottom_node = node();
-  DownRelations::const_iterator dri;
-  dri = bottom_node->_children.find(_graph_type);
-  if (dri != bottom_node->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-    
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      NodeRelation *arc = (*drpi);
-      NodePath child(*this);
-      child.extend_by(arc);
-      result.add_path(child);
-    }
+
+  int num_children = bottom_node->get_num_children(_graph_type);
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *child_arc = bottom_node->get_child(_graph_type, i);
+    NodePath child(*this);
+    child.extend_by(child_arc);
+    result.add_path(child);
   }
 
   return result;
@@ -297,19 +292,15 @@ get_siblings() const {
   parent.shorten(1);
 
   Node *parent_node = parent.node();
-  DownRelations::const_iterator dri;
-  dri = parent_node->_children.find(_graph_type);
-  if (dri != parent_node->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-    
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      NodeRelation *arc = (*drpi);
-      if (arc != my_arc) {
-	NodePath sib(parent);
-	sib.extend_by(arc);
-	result.add_path(sib);
-      }
+
+  int num_children = parent_node->get_num_children(_graph_type);
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *child_arc = parent_node->get_child(_graph_type, i);
+
+    if (child_arc != my_arc) {
+      NodePath sib(parent);
+      sib.extend_by(child_arc);
+      result.add_path(sib);
     }
   }
 
@@ -2710,27 +2701,21 @@ r_list_descendants(ostream &out, int indent_level) const {
   Node *bottom_node = node();
   nassertv(bottom_node != (Node *)NULL);
   indent(out, indent_level) << *bottom_node << "\n";
-  
-  DownRelations::const_iterator dri;
-  dri = bottom_node->_children.find(_graph_type);
-  if (dri != bottom_node->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-    
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      NodeRelation *arc = (*drpi);
-      NodePath next(*this);
-      next.extend_by(arc);
-      next.r_list_descendants(out, indent_level + 2);
-    }
+
+  int num_children = bottom_node->get_num_children(_graph_type);
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *child_arc = bottom_node->get_child(_graph_type, i);
+
+    NodePath next(*this);
+    next.extend_by(child_arc);
+    next.r_list_descendants(out, indent_level + 2);
   }
 
   if (_graph_type != NodeRelation::get_stashed_type()) {
     // Also report the number of stashed nodes at this level.
-    dri = bottom_node->_children.find(NodeRelation::get_stashed_type());
-    if (dri != bottom_node->_children.end()) {
-      const DownRelationPointers &drp = (*dri).second;
-      indent(out, indent_level) << "(" << drp.size() << " stashed)\n";
+    int num_stashed = bottom_node->get_num_children(NodeRelation::get_stashed_type());
+    if (num_stashed != 0) {
+      indent(out, indent_level) << "(" << num_stashed << " stashed)\n";
     }
   }
 }
@@ -2747,22 +2732,16 @@ r_list_transitions(ostream &out, int indent_level) const {
 
   out << "\n+";
   indent(out, indent_level + 1) << *bottom_node << "\n\n";
-  
-  DownRelations::const_iterator dri;
-  dri = bottom_node->_children.find(_graph_type);
-  if (dri != bottom_node->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-    
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      NodeRelation *arc = (*drpi);
-      NodePath next(*this);
-      next.extend_by(arc);
-
-      indent(out, indent_level + 2) << *arc << ":\n";
-      arc->write_transitions(out, indent_level + 2);
-      next.r_list_transitions(out, indent_level + 2);
-    }
+
+  int num_children = bottom_node->get_num_children(_graph_type);
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *child_arc = bottom_node->get_child(_graph_type, i);
+    NodePath next(*this);
+    next.extend_by(child_arc);
+
+    indent(out, indent_level + 2) << *child_arc << ":\n";
+    child_arc->write_transitions(out, indent_level + 2);
+    next.r_list_transitions(out, indent_level + 2);
   }
 }
 
@@ -2778,14 +2757,10 @@ r_adjust_all_priorities(NodeRelation *arc, int adjustment) {
   arc->adjust_all_priorities(adjustment);
 
   Node *dnode = arc->get_child();
-  DownRelations::const_iterator dri;
-  dri = dnode->_children.find(_graph_type);
-  if (dri != dnode->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-    
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-      r_adjust_all_priorities(*drpi, adjustment);
-    }
+
+  int num_children = dnode->get_num_children(_graph_type);
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *child_arc = dnode->get_child(_graph_type, i);
+    r_adjust_all_priorities(child_arc, adjustment);
   }
 }

+ 7 - 11
panda/src/sgraphutil/frustumCullTraverser.I

@@ -233,17 +233,13 @@ traverse(Node *node, AttributeWrapper &render_state, LevelState &level_state,
   if (_visitor.reached_node(node, render_state, level_state)) {
 
     // Look for further children of the given NodeRelation.
-    DownRelations::const_iterator dri;
-    dri = node->_children.find(_graph_type);
-    if (dri != node->_children.end()) {
-      // Here are some!
-      const DownRelationPointers &drp = (*dri).second;
-
-      // Now visit each of the children in turn.
-      DownRelationPointers::const_iterator drpi;
-      for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-	traverse(*drpi, render_state, level_state, local_frustum, all_in);
-      }
+    const DownRelationPointers &drp = 
+      node->find_connection(_graph_type).get_down();
+
+    // Now visit each of the children in turn.
+    DownRelationPointers::const_iterator drpi;
+    for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
+      traverse(*drpi, render_state, level_state, local_frustum, all_in);
     }
   }
 }

+ 7 - 11
panda/src/sgraphutil/sceneGraphReducer.cxx

@@ -261,18 +261,14 @@ r_apply_transitions(NodeRelation *arc, int transition_types,
     }
   }
   
-  DownRelations::const_iterator dri;
-  dri = node->_children.find(_graph_type);
-  if (dri != node->_children.end()) {
-    const DownRelationPointers &drp = (*dri).second;
-    DownRelationPointers drp_copy = drp;
+  const DownRelationPointers &drp = 
+    node->find_connection(_graph_type).get_down();
+  DownRelationPointers drp_copy = drp;
 
-    DownRelationPointers::const_iterator drpi;
-    for (drpi = drp_copy.begin(); drpi != drp_copy.end(); ++drpi) {
-      NodeRelation *child_arc = (*drpi);
-
-      r_apply_transitions(child_arc, transition_types, trans, duplicate);
-    }
+  DownRelationPointers::const_iterator drpi;
+  for (drpi = drp_copy.begin(); drpi != drp_copy.end(); ++drpi) {
+    NodeRelation *child_arc = (*drpi);
+    r_apply_transitions(child_arc, transition_types, trans, duplicate);
   }
 }
 

+ 11 - 18
panda/src/text/textFont.cxx

@@ -242,15 +242,12 @@ find_character_gsets(Node *root, Geom *&ch, GeomPoint *&dot,
     return found;
     
   } else {
-    DownRelations::const_iterator dri;
-    dri = root->_children.find(RenderRelation::get_class_type());
-    if (dri != root->_children.end()) {
-      const DownRelationPointers &drp = (*dri).second;
-      DownRelationPointers::const_iterator drpi;
-      for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-        if (find_character_gsets((*drpi)->get_child(), ch, dot, trans)) {
-	  trans.extract_from(*drpi);
-	}
+    TypeHandle graph_type = RenderRelation::get_class_type();
+    int num_children = root->get_num_children(graph_type);
+    for (int i = 0; i < num_children; i++) {
+      NodeRelation *child_arc = root->get_child(graph_type, i);
+      if (find_character_gsets(child_arc->get_child(), ch, dot, trans)) {
+	trans.extract_from(child_arc);
       }
     }
     return false;
@@ -328,15 +325,11 @@ find_characters(Node *root) {
     }
 
   } else {
-    DownRelations::const_iterator dri;
-    dri = root->_children.find(RenderRelation::get_class_type());
-    if (dri != root->_children.end()) {
-      const DownRelationPointers &drp = (*dri).second;
-      DownRelationPointers::const_iterator drpi;
-      for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
-	Node *node = (*drpi)->get_child();
-	find_characters(node);
-      }
+    TypeHandle graph_type = RenderRelation::get_class_type();
+    int num_children = root->get_num_children(graph_type);
+    for (int i = 0; i < num_children; i++) {
+      NodeRelation *child_arc = root->get_child(graph_type, i);
+      find_characters(child_arc->get_child());
     }
   }
 }

+ 4 - 3
panda/src/text/textNode.cxx

@@ -212,12 +212,13 @@ generate() {
   _lr3d.set(0.0, 0.0, 0.0);
   _num_rows = 0;
 
+  // Now build a new sub-tree for all the text components.
+  PT_Node root = new NamedNode(_text);
+
   if (_text.empty() || _font.is_null()) {
-    return (Node *)NULL;
+    return root;
   }
 
-  // Now build a new sub-tree for all the text components.
-  PT_Node root = new NamedNode(_text);
   PT_Node sub_root = new NamedNode();
   RenderRelation *root_arc = new RenderRelation(root, sub_root);