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