Panda3D
dataNode.cxx
1 // Filename: dataNode.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 "dataNode.h"
16 #include "dataNodeTransmit.h"
17 #include "config_dgraph.h"
18 #include "dcast.h"
19 
20 TypeHandle DataNode::_type_handle;
21 
22 ////////////////////////////////////////////////////////////////////
23 // Function: DataNode::make_copy
24 // Access: Public, Virtual
25 // Description: Returns a newly-allocated Node that is a shallow copy
26 // of this one. It will be a different Node pointer,
27 // but its internal data may or may not be shared with
28 // that of the original Node.
29 ////////////////////////////////////////////////////////////////////
31 make_copy() const {
32  return new DataNode(*this);
33 }
34 
35 ////////////////////////////////////////////////////////////////////
36 // Function: DataNode::transmit_data
37 // Access: Public
38 // Description: Collects the data from all of the parent nodes and
39 // puts it into one DataNodeTransmit object, for
40 // processing; calls do_transmit_data() to read all the
41 // inputs and put the result into the indicated output.
42 ////////////////////////////////////////////////////////////////////
43 void DataNode::
45  const DataNodeTransmit inputs[],
46  DataNodeTransmit &output) {
47  DataNodeTransmit new_input;
48  new_input.reserve(get_num_inputs());
49 
50  DataConnections::const_iterator ci;
51  for (ci = _data_connections.begin(); ci != _data_connections.end(); ++ci) {
52  const DataConnection &connect = (*ci);
53  const EventParameter &data =
54  inputs[connect._parent_index].get_data(connect._output_index);
55  if (!data.is_empty()) {
56  new_input.set_data(connect._input_index, data);
57  }
58  }
59 
60  #ifndef NDEBUG
61  if (dgraph_cat.is_spam()) {
62  bool any_data = false;
63  Wires::const_iterator wi;
64  for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) {
65  const string &name = (*wi).first;
66  const WireDef &def = (*wi).second;
67  if (new_input.has_data(def._index)) {
68  if (!any_data) {
69  dgraph_cat.spam()
70  << *this << " receives:\n";
71  any_data = true;
72  }
73  dgraph_cat.spam(false)
74  << " " << name << " = " << new_input.get_data(def._index)
75  << "\n";
76  }
77  }
78  }
79  #endif // NDEBUG
80 
81  do_transmit_data(trav, new_input, output);
82 
83  #ifndef NDEBUG
84  if (dgraph_cat.is_spam()) {
85  bool any_data = false;
86  Wires::const_iterator wi;
87  for (wi = _output_wires.begin(); wi != _output_wires.end(); ++wi) {
88  const string &name = (*wi).first;
89  const WireDef &def = (*wi).second;
90  if (output.has_data(def._index)) {
91  if (!any_data) {
92  dgraph_cat.spam()
93  << *this << " transmits:\n";
94  any_data = true;
95  }
96  dgraph_cat.spam(false)
97  << " " << name << " = " << output.get_data(def._index)
98  << "\n";
99  }
100  }
101  }
102  #endif // NDEBUG
103 }
104 
105 ////////////////////////////////////////////////////////////////////
106 // Function: DataNode::write_inputs
107 // Access: Published
108 // Description: Writes to the indicated ostream a list of all the
109 // inputs this DataNode might expect to receive.
110 ////////////////////////////////////////////////////////////////////
111 void DataNode::
112 write_inputs(ostream &out) const {
113  Wires::const_iterator wi;
114  for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) {
115  const string &name = (*wi).first;
116  const WireDef &def = (*wi).second;
117  out << name << " " << def._data_type << "\n";
118  }
119 }
120 
121 ////////////////////////////////////////////////////////////////////
122 // Function: DataNode::write_outputs
123 // Access: Published
124 // Description: Writes to the indicated ostream a list of all the
125 // outputs this DataNode might generate.
126 ////////////////////////////////////////////////////////////////////
127 void DataNode::
128 write_outputs(ostream &out) const {
129  Wires::const_iterator wi;
130  for (wi = _output_wires.begin(); wi != _output_wires.end(); ++wi) {
131  const string &name = (*wi).first;
132  const WireDef &def = (*wi).second;
133  out << name << " " << def._data_type << "\n";
134  }
135 }
136 
137 ////////////////////////////////////////////////////////////////////
138 // Function: DataNode::write_connections
139 // Access: Published
140 // Description: Writes to the indicated ostream a list of all the
141 // connections currently showing between this DataNode
142 // and its parent(s).
143 ////////////////////////////////////////////////////////////////////
144 void DataNode::
145 write_connections(ostream &out) const {
146  DataConnections::const_iterator ci;
147  for (ci = _data_connections.begin(); ci != _data_connections.end(); ++ci) {
148  const DataConnection &connect = (*ci);
149  nassertv(connect._parent_index >= 0 && connect._parent_index < get_num_parents());
150 
151  // Now we have to search exhaustively for the input with the
152  // matching index number.
153  Wires::const_iterator wi;
154  bool found = false;
155  for (wi = _input_wires.begin(); wi != _input_wires.end() && !found; ++wi) {
156  const string &name = (*wi).first;
157  const WireDef &def = (*wi).second;
158  if (def._index == connect._input_index) {
159  out << name << " " << def._data_type << " from "
160  << *get_parent(connect._parent_index) << "\n";
161  found = true;
162  }
163  }
164  nassertv(found);
165  }
166 }
167 
168 ////////////////////////////////////////////////////////////////////
169 // Function: DataNode::define_input
170 // Access: Protected
171 // Description: Adds a new input wire with the given name and the
172 // indicated data type. The data type should be the
173 // TypeHandle for some type that derives from
174 // TypedReferenceCount, e.g. EventStoreInt,
175 // EventStoreDouble, or some fancier data type like
176 // Texture.
177 //
178 // If there is already an input wire defined with the
179 // indicated name, its type is changed.
180 //
181 // The return value is the index into the "input"
182 // parameter to do_transmit_data() that can be used to
183 // access the input data.
184 ////////////////////////////////////////////////////////////////////
185 int DataNode::
186 define_input(const string &name, TypeHandle data_type) {
187  // We shouldn't already be connected.
188  nassertr(_data_connections.empty(), 0);
189 
190  Wires::iterator wi;
191  wi = _input_wires.find(name);
192  if (wi != _input_wires.end()) {
193  // This wire already existed; modify it and return the original
194  // index.
195  WireDef &def = (*wi).second;
196  def._data_type = data_type;
197  return def._index;
198  }
199 
200  // This wire did not already exist; add it.
201  WireDef &def = _input_wires[name];
202  def._data_type = data_type;
203  def._index = _input_wires.size() - 1;
204  return def._index;
205 }
206 
207 ////////////////////////////////////////////////////////////////////
208 // Function: DataNode::define_output
209 // Access: Protected
210 // Description: Adds a new output wire with the given name and the
211 // indicated data type. The data type should be the
212 // TypeHandle for some type that derives from
213 // TypedReferenceCount, e.g. EventStoreInt,
214 // EventStoreDouble, or some fancier data type like
215 // Texture.
216 //
217 // If there is already an output wire defined with the
218 // indicated name, its type is changed.
219 //
220 // The return value is the index into the "output"
221 // parameter to do_transmit_data() where the output data
222 // should be stored.
223 ////////////////////////////////////////////////////////////////////
224 int DataNode::
225 define_output(const string &name, TypeHandle data_type) {
226  // We shouldn't already be connected.
227  nassertr(_data_connections.empty(), 0);
228 
229  Wires::iterator wi;
230  wi = _output_wires.find(name);
231  if (wi != _output_wires.end()) {
232  // This wire already existed; modify it and return the original
233  // index.
234  WireDef &def = (*wi).second;
235  def._data_type = data_type;
236  return def._index;
237  }
238 
239  // This wire did not already exist; add it.
240  WireDef &def = _output_wires[name];
241  def._data_type = data_type;
242  def._index = _output_wires.size() - 1;
243  return def._index;
244 }
245 
246 ////////////////////////////////////////////////////////////////////
247 // Function: DataNode::parents_changed
248 // Access: Protected, Virtual
249 // Description: Called after a scene graph update that either adds or
250 // remove parents from this node, this just provides a
251 // hook for derived PandaNode objects that need to
252 // update themselves based on the set of parents the
253 // node has.
254 ////////////////////////////////////////////////////////////////////
255 void DataNode::
256 parents_changed() {
257  PandaNode::parents_changed();
258  reconnect();
259 }
260 
261 ////////////////////////////////////////////////////////////////////
262 // Function: DataNode::do_transmit_data
263 // Access: Protected, Virtual
264 // Description: The virtual implementation of transmit_data(). This
265 // function receives an array of input parameters and
266 // should generate an array of output parameters. The
267 // input parameters may be accessed with the index
268 // numbers returned by the define_input() calls that
269 // were made earlier (presumably in the constructor);
270 // likewise, the output parameters should be set with
271 // the index numbers returned by the define_output()
272 // calls.
273 ////////////////////////////////////////////////////////////////////
274 void DataNode::
275 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
276  DataNodeTransmit &) {
277 }
278 
279 ////////////////////////////////////////////////////////////////////
280 // Function: DataNode::reconnect
281 // Access: Private
282 // Description: Establishes the input(s) that this DataNode has in
283 // common with its parents' output(s). Builds up the
284 // _data_connections list correspondingly.
285 ////////////////////////////////////////////////////////////////////
286 void DataNode::
287 reconnect() {
288  int num_parents = get_num_parents();
289  _data_connections.clear();
290  // Look for each input among one of the parents.
291  int num_datanode_parents = 0;
292 
293  Wires::const_iterator wi;
294  for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) {
295  const string &name = (*wi).first;
296  const WireDef &input_def = (*wi).second;
297 
298  int num_found = 0;
299  for (int i = 0; i < num_parents; i++) {
300  PandaNode *parent_node = get_parent(i);
301  if (parent_node->is_of_type(DataNode::get_class_type())) {
302  DataNode *data_node = DCAST(DataNode, parent_node);
303  num_datanode_parents++;
304  Wires::const_iterator pi;
305  pi = data_node->_output_wires.find(name);
306  if (pi != data_node->_output_wires.end()) {
307  const WireDef &output_def = (*pi).second;
308  num_found++;
309  if (output_def._data_type != input_def._data_type) {
310  dgraph_cat.warning()
311  << "Ignoring mismatched type for connection " << name
312  << " between " << *data_node << " and " << *this << "\n";
313  } else {
314  DataConnection dc;
315  dc._parent_index = i;
316  dc._output_index = output_def._index;
317  dc._input_index = input_def._index;
318  _data_connections.push_back(dc);
319  }
320  }
321  }
322  }
323 
324  if (num_found > 1) {
325  if (dgraph_cat.is_debug()) {
326  dgraph_cat.debug()
327  << "Multiple connections found for " << name << " into " << *this
328  << "\n";
329  }
330  }
331  }
332 
333  if (_data_connections.empty() && get_num_inputs() != 0 &&
334  num_datanode_parents != 0) {
335  dgraph_cat.warning()
336  << "No data connected to " << *this << "\n";
337  }
338 }
339 
340 ////////////////////////////////////////////////////////////////////
341 // Function: DataNode::write_datagram
342 // Access: Public, Virtual
343 // Description: Writes the contents of this object to the datagram
344 // for shipping out to a Bam file.
345 ////////////////////////////////////////////////////////////////////
346 void DataNode::
348  PandaNode::write_datagram(manager, dg);
349 }
350 
351 ////////////////////////////////////////////////////////////////////
352 // Function: DataNode::fillin
353 // Access: Protected
354 // Description: This internal function is called by make_from_bam to
355 // read in all of the relevant data from the BamFile for
356 // the new Lens.
357 ////////////////////////////////////////////////////////////////////
358 void DataNode::
359 fillin(DatagramIterator &scan, BamReader *manager) {
360  PandaNode::fillin(scan, manager);
361 }
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: dataNode.cxx:347
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
The fundamental type of node for the data graph.
Definition: dataNode.h:64
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: pandaNode.cxx:4164
An optional parameter associated with an event.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
void write_inputs(ostream &out) const
Writes to the indicated ostream a list of all the inputs this DataNode might expect to receive...
Definition: dataNode.cxx:112
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Definition: dataNode.cxx:31
bool is_empty() const
Returns true if the EventParameter is the empty parameter, storing nothing, or false otherwise...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
void write_connections(ostream &out) const
Writes to the indicated ostream a list of all the connections currently showing between this DataNode...
Definition: dataNode.cxx:145
bool has_data(int index) const
Returns true if the indicated parameter has been stored, false otherwise.
void reserve(int num_wires)
Tells the DataNodeTransmit object how many wires it is expected to store data for.
void set_data(int index, const EventParameter &data)
Sets the data for the indicated parameter.
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
PandaNode * get_parent(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth parent node of this node.
Definition: pandaNode.I:40
void write_outputs(ostream &out) const
Writes to the indicated ostream a list of all the outputs this DataNode might generate.
Definition: dataNode.cxx:128
const EventParameter & get_data(int index) const
Extracts the data for the indicated index, if it has been stored, or the empty parameter if it has no...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
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
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
int get_num_inputs() const
Returns the number of different inputs that have been defined for this node using define_input()...
Definition: dataNode.I:48
Encapsulates the data generated from (or sent into) any particular DataNode.
This object supervises the traversal of the data graph and the moving of data from one DataNode to it...