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