00001 // Filename: dataNode.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 "dataNode.h" 00020 #include "dataNodeTransmit.h" 00021 #include "config_dgraph.h" 00022 #include "dcast.h" 00023 00024 TypeHandle DataNode::_type_handle; 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: DataNode::make_copy 00028 // Access: Public, Virtual 00029 // Description: Returns a newly-allocated Node that is a shallow copy 00030 // of this one. It will be a different Node pointer, 00031 // but its internal data may or may not be shared with 00032 // that of the original Node. 00033 //////////////////////////////////////////////////////////////////// 00034 PandaNode *DataNode:: 00035 make_copy() const { 00036 return new DataNode(*this); 00037 } 00038 00039 //////////////////////////////////////////////////////////////////// 00040 // Function: DataNode::transmit_data 00041 // Access: Public 00042 // Description: Collects the data from all of the parent nodes and 00043 // puts it into one DataNodeTransmit object, for 00044 // processing; calls do_transmit_data() to read all the 00045 // inputs and put the result into the indicated output. 00046 //////////////////////////////////////////////////////////////////// 00047 void DataNode:: 00048 transmit_data(const DataNodeTransmit inputs[], 00049 DataNodeTransmit &output) { 00050 DataNodeTransmit new_input; 00051 new_input.reserve(get_num_inputs()); 00052 00053 DataConnections::const_iterator ci; 00054 for (ci = _data_connections.begin(); ci != _data_connections.end(); ++ci) { 00055 const DataConnection &connect = (*ci); 00056 const EventParameter &data = 00057 inputs[connect._parent_index].get_data(connect._output_index); 00058 new_input.set_data(connect._input_index, data); 00059 } 00060 00061 #ifndef NDEBUG 00062 if (dgraph_cat.is_spam()) { 00063 bool any_data = false; 00064 Wires::const_iterator wi; 00065 for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) { 00066 const string &name = (*wi).first; 00067 const WireDef &def = (*wi).second; 00068 if (new_input.has_data(def._index)) { 00069 if (!any_data) { 00070 dgraph_cat.spam() 00071 << *this << " receives:\n"; 00072 any_data = true; 00073 } 00074 dgraph_cat.spam(false) 00075 << " " << name << " = " << new_input.get_data(def._index) 00076 << "\n"; 00077 } 00078 } 00079 } 00080 #endif // NDEBUG 00081 00082 do_transmit_data(new_input, output); 00083 00084 #ifndef NDEBUG 00085 if (dgraph_cat.is_spam()) { 00086 bool any_data = false; 00087 Wires::const_iterator wi; 00088 for (wi = _output_wires.begin(); wi != _output_wires.end(); ++wi) { 00089 const string &name = (*wi).first; 00090 const WireDef &def = (*wi).second; 00091 if (output.has_data(def._index)) { 00092 if (!any_data) { 00093 dgraph_cat.spam() 00094 << *this << " transmits:\n"; 00095 any_data = true; 00096 } 00097 dgraph_cat.spam(false) 00098 << " " << name << " = " << output.get_data(def._index) 00099 << "\n"; 00100 } 00101 } 00102 } 00103 #endif // NDEBUG 00104 } 00105 00106 //////////////////////////////////////////////////////////////////// 00107 // Function: DataNode::write_inputs 00108 // Access: Published 00109 // Description: Writes to the indicated ostream a list of all the 00110 // inputs this DataNode might expect to receive. 00111 //////////////////////////////////////////////////////////////////// 00112 void DataNode:: 00113 write_inputs(ostream &out) const { 00114 Wires::const_iterator wi; 00115 for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) { 00116 const string &name = (*wi).first; 00117 const WireDef &def = (*wi).second; 00118 out << name << " " << def._data_type << "\n"; 00119 } 00120 } 00121 00122 //////////////////////////////////////////////////////////////////// 00123 // Function: DataNode::write_outputs 00124 // Access: Published 00125 // Description: Writes to the indicated ostream a list of all the 00126 // outputs this DataNode might generate. 00127 //////////////////////////////////////////////////////////////////// 00128 void DataNode:: 00129 write_outputs(ostream &out) const { 00130 Wires::const_iterator wi; 00131 for (wi = _output_wires.begin(); wi != _output_wires.end(); ++wi) { 00132 const string &name = (*wi).first; 00133 const WireDef &def = (*wi).second; 00134 out << name << " " << def._data_type << "\n"; 00135 } 00136 } 00137 00138 //////////////////////////////////////////////////////////////////// 00139 // Function: DataNode::write_connections 00140 // Access: Published 00141 // Description: Writes to the indicated ostream a list of all the 00142 // connections currently showing between this DataNode 00143 // and its parent(s). 00144 //////////////////////////////////////////////////////////////////// 00145 void DataNode:: 00146 write_connections(ostream &out) const { 00147 DataConnections::const_iterator ci; 00148 for (ci = _data_connections.begin(); ci != _data_connections.end(); ++ci) { 00149 const DataConnection &connect = (*ci); 00150 nassertv(connect._parent_index >= 0 && connect._parent_index < get_num_parents()); 00151 00152 // Now we have to search exhaustively for the input with the 00153 // matching index number. 00154 Wires::const_iterator wi; 00155 bool found = false; 00156 for (wi = _input_wires.begin(); wi != _input_wires.end() && !found; ++wi) { 00157 const string &name = (*wi).first; 00158 const WireDef &def = (*wi).second; 00159 if (def._index == connect._input_index) { 00160 out << name << " " << def._data_type << " from " 00161 << *get_parent(connect._parent_index) << "\n"; 00162 found = true; 00163 } 00164 } 00165 nassertv(found); 00166 } 00167 } 00168 00169 //////////////////////////////////////////////////////////////////// 00170 // Function: DataNode::define_input 00171 // Access: Protected 00172 // Description: Adds a new input wire with the given name and the 00173 // indicated data type. The data type should be the 00174 // TypeHandle for some type that derives from 00175 // TypedReferenceCount, e.g. EventStoreInt, 00176 // EventStoreDouble, or some fancier data type like 00177 // Texture. 00178 // 00179 // If there is already an input wire defined with the 00180 // indicated name, its type is changed. 00181 // 00182 // The return value is the index into the "input" 00183 // parameter to do_transmit_data() that can be used to 00184 // access the input data. 00185 //////////////////////////////////////////////////////////////////// 00186 int DataNode:: 00187 define_input(const string &name, TypeHandle data_type) { 00188 // We shouldn't already be connected. 00189 nassertr(_data_connections.empty(), 0); 00190 00191 Wires::iterator wi; 00192 wi = _input_wires.find(name); 00193 if (wi != _input_wires.end()) { 00194 // This wire already existed; modify it and return the original 00195 // index. 00196 WireDef &def = (*wi).second; 00197 def._data_type = data_type; 00198 return def._index; 00199 } 00200 00201 // This wire did not already exist; add it. 00202 WireDef &def = _input_wires[name]; 00203 def._data_type = data_type; 00204 def._index = _input_wires.size() - 1; 00205 return def._index; 00206 } 00207 00208 //////////////////////////////////////////////////////////////////// 00209 // Function: DataNode::define_output 00210 // Access: Protected 00211 // Description: Adds a new output wire with the given name and the 00212 // indicated data type. The data type should be the 00213 // TypeHandle for some type that derives from 00214 // TypedReferenceCount, e.g. EventStoreInt, 00215 // EventStoreDouble, or some fancier data type like 00216 // Texture. 00217 // 00218 // If there is already an output wire defined with the 00219 // indicated name, its type is changed. 00220 // 00221 // The return value is the index into the "output" 00222 // parameter to do_transmit_data() where the output data 00223 // should be stored. 00224 //////////////////////////////////////////////////////////////////// 00225 int DataNode:: 00226 define_output(const string &name, TypeHandle data_type) { 00227 // We shouldn't already be connected. 00228 nassertr(_data_connections.empty(), 0); 00229 00230 Wires::iterator wi; 00231 wi = _output_wires.find(name); 00232 if (wi != _output_wires.end()) { 00233 // This wire already existed; modify it and return the original 00234 // index. 00235 WireDef &def = (*wi).second; 00236 def._data_type = data_type; 00237 return def._index; 00238 } 00239 00240 // This wire did not already exist; add it. 00241 WireDef &def = _output_wires[name]; 00242 def._data_type = data_type; 00243 def._index = _output_wires.size() - 1; 00244 return def._index; 00245 } 00246 00247 //////////////////////////////////////////////////////////////////// 00248 // Function: DataNode::parents_changed 00249 // Access: Protected, Virtual 00250 // Description: Called after a scene graph update that either adds or 00251 // remove parents from this node, this just provides a 00252 // hook for derived PandaNode objects that need to 00253 // update themselves based on the set of parents the 00254 // node has. 00255 //////////////////////////////////////////////////////////////////// 00256 void DataNode:: 00257 parents_changed() { 00258 reconnect(); 00259 } 00260 00261 //////////////////////////////////////////////////////////////////// 00262 // Function: DataNode::do_transmit_data 00263 // Access: Protected, Virtual 00264 // Description: The virtual implementation of transmit_data(). This 00265 // function receives an array of input parameters and 00266 // should generate an array of output parameters. The 00267 // input parameters may be accessed with the index 00268 // numbers returned by the define_input() calls that 00269 // were made earlier (presumably in the constructor); 00270 // likewise, the output parameters should be set with 00271 // the index numbers returned by the define_output() 00272 // calls. 00273 //////////////////////////////////////////////////////////////////// 00274 void DataNode:: 00275 do_transmit_data(const DataNodeTransmit &, DataNodeTransmit &) { 00276 } 00277 00278 //////////////////////////////////////////////////////////////////// 00279 // Function: DataNode::reconnect 00280 // Access: Private 00281 // Description: Establishes the input(s) that this DataNode has in 00282 // common with its parents' output(s). Builds up the 00283 // _data_connections list correspondingly. 00284 //////////////////////////////////////////////////////////////////// 00285 void DataNode:: 00286 reconnect() { 00287 int num_parents = get_num_parents(); 00288 _data_connections.clear(); 00289 // Look for each input among one of the parents. 00290 int num_datanode_parents = 0; 00291 00292 Wires::const_iterator wi; 00293 for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) { 00294 const string &name = (*wi).first; 00295 const WireDef &input_def = (*wi).second; 00296 00297 int num_found = 0; 00298 for (int i = 0; i < num_parents; i++) { 00299 PandaNode *parent_node = get_parent(i); 00300 if (parent_node->is_of_type(DataNode::get_class_type())) { 00301 DataNode *data_node = DCAST(DataNode, parent_node); 00302 num_datanode_parents++; 00303 Wires::const_iterator pi; 00304 pi = data_node->_output_wires.find(name); 00305 if (pi != data_node->_output_wires.end()) { 00306 const WireDef &output_def = (*pi).second; 00307 num_found++; 00308 if (output_def._data_type != input_def._data_type) { 00309 dgraph_cat.warning() 00310 << "Ignoring mismatched type for connection " << name 00311 << " between " << *data_node << " and " << *this << "\n"; 00312 } else if (num_found == 1) { 00313 DataConnection dc; 00314 dc._parent_index = i; 00315 dc._output_index = output_def._index; 00316 dc._input_index = input_def._index; 00317 _data_connections.push_back(dc); 00318 } 00319 } 00320 } 00321 } 00322 00323 if (num_found > 1) { 00324 dgraph_cat.warning() 00325 << "Multiple connections found for " << name << " into " << *this 00326 << "\n"; 00327 } 00328 } 00329 00330 if (_data_connections.empty() && get_num_inputs() != 0 && 00331 num_datanode_parents != 0) { 00332 dgraph_cat.warning() 00333 << "No data connected to " << *this << "\n"; 00334 } 00335 }