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  */
38 void DataNode::
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  */
104 void DataNode::
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  */
118 void DataNode::
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  */
132 void DataNode::
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  */
308 void DataNode::
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 }
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
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
The fundamental type of node for the data graph.
Definition: dataNode.h:52
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
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:3589
An optional parameter associated with an event.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_parents
Returns the number of parent nodes this node has.
Definition: pandaNode.h:118
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
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Definition: dataNode.cxx:29
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
get_parent
Returns the nth parent node of this node.
Definition: pandaNode.h:118
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:28
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:81
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
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
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
Encapsulates the data generated from (or sent into) any particular DataNode.
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
This object supervises the traversal of the data graph and the moving of data from one DataNode to it...