00001 // Filename: dataGraphTraverser.cxx 00002 // Created by: drose (11Mar02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "dataGraphTraverser.h" 00020 #include "dataNode.h" 00021 #include "config_dgraph.h" 00022 #include "dcast.h" 00023 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: DataGraphTraverser::CollectedData::set_data 00027 // Access: Public 00028 // Description: Sets the data associated with the indicated parent of 00029 // this CollectedData object's node. 00030 //////////////////////////////////////////////////////////////////// 00031 void DataGraphTraverser::CollectedData:: 00032 set_data(int parent_index, const DataNodeTransmit &data) { 00033 if ((int)_data.size() <= parent_index) { 00034 _data.reserve(parent_index + 1); 00035 while ((int)_data.size() <= parent_index) { 00036 _data.push_back(DataNodeTransmit()); 00037 } 00038 } 00039 00040 nassertv(parent_index >= 0 && parent_index < (int)_data.size()); 00041 _data[parent_index] = data; 00042 } 00043 00044 //////////////////////////////////////////////////////////////////// 00045 // Function: DataGraphTraverser::Constructor 00046 // Access: Public 00047 // Description: 00048 //////////////////////////////////////////////////////////////////// 00049 DataGraphTraverser:: 00050 DataGraphTraverser() { 00051 } 00052 00053 //////////////////////////////////////////////////////////////////// 00054 // Function: DataGraphTraverser::Destructor 00055 // Access: Public 00056 // Description: 00057 //////////////////////////////////////////////////////////////////// 00058 DataGraphTraverser:: 00059 ~DataGraphTraverser() { 00060 } 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Function: DataGraphTraverser::traverse 00064 // Access: Public 00065 // Description: Starts the traversal of the data graph at the 00066 // indicated root node. 00067 //////////////////////////////////////////////////////////////////// 00068 void DataGraphTraverser:: 00069 traverse(PandaNode *node) { 00070 if (node->is_of_type(DataNode::get_class_type())) { 00071 DataNode *data_node = DCAST(DataNode, node); 00072 int num_parents = data_node->get_num_parents(); 00073 // We must start the traversal at the root of the graph. 00074 nassertv(num_parents == 0); 00075 00076 r_transmit(data_node, (DataNodeTransmit *)NULL); 00077 00078 } else { 00079 traverse_below(node, DataNodeTransmit()); 00080 } 00081 00082 collect_leftovers(); 00083 } 00084 00085 //////////////////////////////////////////////////////////////////// 00086 // Function: DataGraphTraverser::traverse_below 00087 // Access: Public 00088 // Description: Continues the traversal to all the children of the 00089 // indicated node, passing in the given data, without 00090 // actually calling transmit_data() on the given node. 00091 //////////////////////////////////////////////////////////////////// 00092 void DataGraphTraverser:: 00093 traverse_below(PandaNode *node, const DataNodeTransmit &output) { 00094 PandaNode::Children cr = node->get_children(); 00095 int num_children = cr.get_num_children(); 00096 00097 for (int i = 0; i < num_children; i++) { 00098 PandaNode *child_node = cr.get_child(i); 00099 if (child_node->is_of_type(DataNode::get_class_type())) { 00100 DataNode *data_node = DCAST(DataNode, child_node); 00101 // If it's a DataNode-type child, we need to pass it the data. 00102 // Maybe it has only one parent, and can accept the data 00103 // immediately. 00104 int num_parents = data_node->get_num_parents(); 00105 if (num_parents == 1) { 00106 // The easy, common case: only one parent. We make our output 00107 // into a one-element array of inputs by turning it into a 00108 // pointer. 00109 r_transmit(data_node, &output); 00110 } else { 00111 // A more difficult case: multiple parents. We must collect 00112 // instances together, meaning we must hold onto this node 00113 // until we have reached it through all paths. 00114 CollectedData &collected_data = _multipass_data[data_node]; 00115 int parent_index = data_node->find_parent(node); 00116 nassertv(parent_index != -1); 00117 00118 collected_data.set_data(parent_index, output); 00119 collected_data._num_parents++; 00120 nassertv(collected_data._num_parents <= num_parents); 00121 if (collected_data._num_parents == num_parents) { 00122 // Now we've got all the data; go into the child. 00123 r_transmit(data_node, &collected_data._data[0]); 00124 _multipass_data.erase(data_node); 00125 } 00126 } 00127 } else { 00128 // The child node is not a DataNode-type child. We continue the 00129 // traversal, but data does not pass through this node, and 00130 // instances are not collected together. (Although we appear to 00131 // be passing the data through here, it doesn't do any good 00132 // anyway, since the child nodes of this node will not know how 00133 // to interpret the data from a non-DataNode parent.) 00134 traverse_below(child_node, output); 00135 } 00136 } 00137 } 00138 00139 //////////////////////////////////////////////////////////////////// 00140 // Function: DataGraphTraverser::collect_leftovers 00141 // Access: Public 00142 // Description: Pick up any nodes that didn't get completely 00143 // traversed. These must be nodes that have multiple 00144 // parents, with at least one parent completely outside 00145 // of the data graph. 00146 //////////////////////////////////////////////////////////////////// 00147 void DataGraphTraverser:: 00148 collect_leftovers() { 00149 while (!_multipass_data.empty()) { 00150 MultipassData::iterator mi = _multipass_data.begin(); 00151 DataNode *data_node = (*mi).first; 00152 const CollectedData &collected_data = (*mi).second; 00153 00154 dgraph_cat.warning() 00155 << *data_node << " improperly parented partly outside of data graph.\n"; 00156 00157 r_transmit(data_node, &collected_data._data[0]); 00158 _multipass_data.erase(mi); 00159 } 00160 } 00161 00162 //////////////////////////////////////////////////////////////////// 00163 // Function: DataGraphTraverser::r_transmit 00164 // Access: Private 00165 // Description: Part of the recursive implementation of traverse(). 00166 // This transmits the given data into the indicated 00167 // DataNode, and then sends the output data to each of 00168 // the node's children. 00169 //////////////////////////////////////////////////////////////////// 00170 void DataGraphTraverser:: 00171 r_transmit(DataNode *data_node, const DataNodeTransmit inputs[]) { 00172 DataNodeTransmit output; 00173 output.reserve(data_node->get_num_outputs()); 00174 data_node->transmit_data(inputs, output); 00175 00176 traverse_below(data_node, output); 00177 }