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 */
54 void DataGraphTraverser::
55 traverse(PandaNode *node) {
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 {
64 traverse_below(node, DataNodeTransmit());
65 }
66
67 collect_leftovers();
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 */
75 void DataGraphTraverser::
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 */
125 void DataGraphTraverser::
126 collect_leftovers() {
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 }
DataGraphTraverser::traverse_below
void traverse_below(PandaNode *node, const DataNodeTransmit &output)
Continues the traversal to all the children of the indicated node, passing in the given data,...
Definition: dataGraphTraverser.cxx:76
DataGraphTraverser::traverse
void traverse(PandaNode *node)
Starts the traversal of the data graph at the indicated root node.
Definition: dataGraphTraverser.cxx:55
DataGraphTraverser::collect_leftovers
void collect_leftovers()
Pick up any nodes that didn't get completely traversed.
Definition: dataGraphTraverser.cxx:126
DataNodeTransmit
Encapsulates the data generated from (or sent into) any particular DataNode.
Definition: dataNodeTransmit.h:32
DataNodeTransmit::reserve
void reserve(int num_wires)
Tells the DataNodeTransmit object how many wires it is expected to store data for.
Definition: dataNodeTransmit.I:43
DataNode
The fundamental type of node for the data graph.
Definition: dataNode.h:52
DataNode::get_num_outputs
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
DataNode::transmit_data
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
PandaNode::Children
Definition: pandaNode.h:706
PandaNode::Children::get_child
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition: pandaNode.I:962
PandaNode::Children::get_num_children
size_t get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:953
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
PandaNode::get_num_parents
get_num_parents
Returns the number of parent nodes this node has.
Definition: pandaNode.h:118
PandaNode::find_parent
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
PandaNode::get_children
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.h:782
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
config_dgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dataGraphTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dataNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcast.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.