Panda3D
dataGraphTraverser.cxx
1 // Filename: dataGraphTraverser.cxx
2 // Created by: drose (11Mar02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "dataGraphTraverser.h"
16 #include "dataNode.h"
17 #include "config_dgraph.h"
18 #include "dcast.h"
19 
20 
21 ////////////////////////////////////////////////////////////////////
22 // Function: DataGraphTraverser::CollectedData::set_data
23 // Access: Public
24 // Description: Sets the data associated with the indicated parent of
25 // this CollectedData object's node.
26 ////////////////////////////////////////////////////////////////////
27 void DataGraphTraverser::CollectedData::
28 set_data(int parent_index, const DataNodeTransmit &data) {
29  if ((int)_data.size() <= parent_index) {
30  _data.reserve(parent_index + 1);
31  while ((int)_data.size() <= parent_index) {
32  _data.push_back(DataNodeTransmit());
33  }
34  }
35 
36  nassertv(parent_index >= 0 && parent_index < (int)_data.size());
37  _data[parent_index] = data;
38 }
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: DataGraphTraverser::Constructor
42 // Access: Public
43 // Description:
44 ////////////////////////////////////////////////////////////////////
45 DataGraphTraverser::
46 DataGraphTraverser(Thread *current_thread) : _current_thread(current_thread) {
47 }
48 
49 ////////////////////////////////////////////////////////////////////
50 // Function: DataGraphTraverser::Destructor
51 // Access: Public
52 // Description:
53 ////////////////////////////////////////////////////////////////////
54 DataGraphTraverser::
55 ~DataGraphTraverser() {
56 }
57 
58 ////////////////////////////////////////////////////////////////////
59 // Function: DataGraphTraverser::traverse
60 // Access: Public
61 // Description: Starts the traversal of the data graph at the
62 // indicated root node.
63 ////////////////////////////////////////////////////////////////////
66  if (node->is_of_type(DataNode::get_class_type())) {
67  DataNode *data_node = DCAST(DataNode, node);
68  // We must start the traversal at the root of the graph.
69  nassertv(data_node->get_num_parents(_current_thread) == 0);
70 
71  r_transmit(data_node, (DataNodeTransmit *)NULL);
72 
73  } else {
75  }
76 
78 }
79 
80 ////////////////////////////////////////////////////////////////////
81 // Function: DataGraphTraverser::traverse_below
82 // Access: Public
83 // Description: Continues the traversal to all the children of the
84 // indicated node, passing in the given data, without
85 // actually calling transmit_data() on the given node.
86 ////////////////////////////////////////////////////////////////////
88 traverse_below(PandaNode *node, const DataNodeTransmit &output) {
89  PandaNode::Children cr = node->get_children(_current_thread);
90  int num_children = cr.get_num_children();
91 
92  for (int i = 0; i < num_children; i++) {
93  PandaNode *child_node = cr.get_child(i);
94  if (child_node->is_of_type(DataNode::get_class_type())) {
95  DataNode *data_node = DCAST(DataNode, child_node);
96  // If it's a DataNode-type child, we need to pass it the data.
97  // Maybe it has only one parent, and can accept the data
98  // immediately.
99  int num_parents = data_node->get_num_parents(_current_thread);
100  if (num_parents == 1) {
101  // The easy, common case: only one parent. We make our output
102  // into a one-element array of inputs by turning it into a
103  // pointer.
104  r_transmit(data_node, &output);
105  } else {
106  // A more difficult case: multiple parents. We must collect
107  // instances together, meaning we must hold onto this node
108  // until we have reached it through all paths.
109  CollectedData &collected_data = _multipass_data[data_node];
110  int parent_index = data_node->find_parent(node, _current_thread);
111  nassertv(parent_index != -1);
112 
113  collected_data.set_data(parent_index, output);
114  collected_data._num_parents++;
115  nassertv(collected_data._num_parents <= num_parents);
116  if (collected_data._num_parents == num_parents) {
117  // Now we've got all the data; go into the child.
118  r_transmit(data_node, &collected_data._data[0]);
119  _multipass_data.erase(data_node);
120  }
121  }
122  } else {
123  // The child node is not a DataNode-type child. We continue the
124  // traversal, but data does not pass through this node, and
125  // instances are not collected together. (Although we appear to
126  // be passing the data through here, it doesn't do any good
127  // anyway, since the child nodes of this node will not know how
128  // to interpret the data from a non-DataNode parent.)
129  traverse_below(child_node, output);
130  }
131  }
132 }
133 
134 ////////////////////////////////////////////////////////////////////
135 // Function: DataGraphTraverser::collect_leftovers
136 // Access: Public
137 // Description: Pick up any nodes that didn't get completely
138 // traversed. These must be nodes that have multiple
139 // parents, with at least one parent completely outside
140 // of the data graph.
141 ////////////////////////////////////////////////////////////////////
144  while (!_multipass_data.empty()) {
145  MultipassData::iterator mi = _multipass_data.begin();
146  DataNode *data_node = (*mi).first;
147  const CollectedData &collected_data = (*mi).second;
148 
149  dgraph_cat.warning()
150  << *data_node << " improperly parented partly outside of data graph.\n";
151 
152  r_transmit(data_node, &collected_data._data[0]);
153  _multipass_data.erase(mi);
154  }
155 }
156 
157 ////////////////////////////////////////////////////////////////////
158 // Function: DataGraphTraverser::r_transmit
159 // Access: Private
160 // Description: Part of the recursive implementation of traverse().
161 // This transmits the given data into the indicated
162 // DataNode, and then sends the output data to each of
163 // the node's children.
164 ////////////////////////////////////////////////////////////////////
165 void DataGraphTraverser::
166 r_transmit(DataNode *data_node, const DataNodeTransmit inputs[]) {
167  DataNodeTransmit output;
168  output.reserve(data_node->get_num_outputs());
169  data_node->transmit_data(this, inputs, output);
170 
171  traverse_below(data_node, output);
172 }
int get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:1163
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
int get_num_outputs() const
Returns the number of different outputs that have been defined for this node using define_output()...
Definition: dataNode.I:61
The fundamental type of node for the data graph.
Definition: dataNode.h:64
void collect_leftovers()
Pick up any nodes that didn&#39;t get completely traversed.
void traverse_below(PandaNode *node, const DataNodeTransmit &output)
Continues the traversal to all the children of the indicated node, passing in the given data...
void reserve(int num_wires)
Tells the DataNodeTransmit object how many wires it is expected to store data for.
int find_parent(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated parent node, if it is a parent, or -1 if it is not...
Definition: pandaNode.I:54
int get_num_parents(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of parent nodes this node has.
Definition: pandaNode.I:26
Children get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.I:773
A thread; that is, a lightweight process.
Definition: thread.h:51
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
PandaNode * get_child(int n) const
Returns the nth child of the node.
Definition: pandaNode.I:1174
void transmit_data(DataGraphTraverser *trav, const DataNodeTransmit inputs[], DataNodeTransmit &output)
Collects the data from all of the parent nodes and puts it into one DataNodeTransmit object...
Definition: dataNode.cxx:44
Encapsulates the data generated from (or sent into) any particular DataNode.
void traverse(PandaNode *node)
Starts the traversal of the data graph at the indicated root node.