animBundleMaker.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 animBundleMaker.cxx
10  * @author drose
11  * @date 1999-02-22
12  */
13 
14 #include "animBundleMaker.h"
15 #include "config_egg2pg.h"
16 
17 #include "eggTable.h"
18 #include "eggAnimData.h"
19 #include "eggSAnimData.h"
20 #include "eggXfmAnimData.h"
21 #include "eggXfmSAnim.h"
22 #include "eggGroupNode.h"
23 #include "animBundle.h"
24 #include "animBundleNode.h"
26 #include "animChannelScalarTable.h"
27 
28 /**
29  *
30  */
31 AnimBundleMaker::
32 AnimBundleMaker(EggTable *root) : _root(root) {
33  _fps = 0.0f;
34  _num_frames = 1;
35 
36  _ok_fps = true;
37  _ok_num_frames = true;
38 
39  inspect_tree(root);
40 
41  if (!_ok_fps) {
42  egg2pg_cat.warning()
43  << "AnimBundle " << _root->get_name()
44  << " specifies contradictory frame rates.\n";
45  } else if (_fps == 0.0f) {
46  egg2pg_cat.warning()
47  << "AnimBundle " << _root->get_name()
48  << " does not specify a frame rate.\n";
49  _fps = 24.0f;
50  }
51 
52  if (!_ok_num_frames) {
53  egg2pg_cat.warning()
54  << "AnimBundle " << _root->get_name()
55  << " specifies contradictory number of frames.\n";
56  }
57 }
58 
59 
60 /**
61  *
62  */
63 AnimBundleNode *AnimBundleMaker::
64 make_node() {
65  return new AnimBundleNode(_root->get_name(), make_bundle());
66 }
67 
68 /**
69  *
70  */
71 AnimBundle *AnimBundleMaker::
72 make_bundle() {
73  AnimBundle *bundle = new AnimBundle(_root->get_name(), _fps, _num_frames);
74 
75  EggTable::const_iterator ci;
76  for (ci = _root->begin(); ci != _root->end(); ++ci) {
77  if ((*ci)->is_of_type(EggTable::get_class_type())) {
78  EggTable *child = DCAST(EggTable, *ci);
79  build_hierarchy(child, bundle);
80  }
81  }
82 
83  bundle->sort_descendants();
84 
85  return bundle;
86 }
87 
88 
89 /**
90  * Walks the egg tree, getting out the fps and the number of frames.
91  */
92 void AnimBundleMaker::
93 inspect_tree(EggNode *egg_node) {
94  if (egg_node->is_of_type(EggAnimData::get_class_type())) {
95  // Check frame rate.
96  EggAnimData *egg_anim = DCAST(EggAnimData, egg_node);
97  if (egg_anim->has_fps()) {
98  if (_fps == 0.0f) {
99  _fps = egg_anim->get_fps();
100  } else if (_fps != egg_anim->get_fps()) {
101  // Whoops! This table differs in opinion from the other tables.
102  _fps = min(_fps, (PN_stdfloat)egg_anim->get_fps());
103  _ok_fps = false;
104  }
105  }
106  }
107 
108  if (egg_node->is_of_type(EggXfmSAnim::get_class_type())) {
109  // Check frame rate.
110  EggXfmSAnim *egg_anim = DCAST(EggXfmSAnim, egg_node);
111  if (egg_anim->has_fps()) {
112  if (_fps == 0.0f) {
113  _fps = egg_anim->get_fps();
114  } else if (_fps != egg_anim->get_fps()) {
115  // Whoops! This table differs in opinion from the other tables.
116  _fps = min(_fps, (PN_stdfloat)egg_anim->get_fps());
117  _ok_fps = false;
118  }
119  }
120  }
121 
122  if (egg_node->is_of_type(EggSAnimData::get_class_type())) {
123  // Check number of frames.
124  EggSAnimData *egg_anim = DCAST(EggSAnimData, egg_node);
125  int num_frames = egg_anim->get_num_rows();
126 
127  if (num_frames > 1) {
128  if (_num_frames == 1) {
129  _num_frames = num_frames;
130  } else if (_num_frames != num_frames) {
131  // Whoops! Another disagreement.
132  _num_frames = min(_num_frames, num_frames);
133  _ok_num_frames = false;
134  }
135  }
136  }
137 
138  if (egg_node->is_of_type(EggXfmAnimData::get_class_type())) {
139  // Check number of frames.
140  EggXfmAnimData *egg_anim = DCAST(EggXfmAnimData, egg_node);
141  int num_frames = egg_anim->get_num_rows();
142 
143  if (num_frames > 1) {
144  if (_num_frames == 1) {
145  _num_frames = num_frames;
146  } else if (_num_frames != num_frames) {
147  // Whoops! Another disagreement.
148  _num_frames = min(_num_frames, num_frames);
149  _ok_num_frames = false;
150  }
151  }
152  }
153 
154  if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
155  // Now recurse.
156  EggGroupNode *group = DCAST(EggGroupNode, egg_node);
157  EggGroupNode::const_iterator ci;
158  for (ci = group->begin(); ci != group->end(); ++ci) {
159  inspect_tree(*ci);
160  }
161  }
162 }
163 
164 
165 /**
166  * Walks the egg tree again, creating the AnimChannels as appropriate.
167  */
168 void AnimBundleMaker::
169 build_hierarchy(EggTable *egg_table, AnimGroup *parent) {
170  AnimGroup *this_node = NULL;
171 
172  // First, scan the children of egg_table for anim data tables. If any of
173  // them is named "xform", it's a special case--this one stands for the
174  // egg_table node itself. Don't ask me why.
175 
176  EggTable::const_iterator ci;
177  for (ci = egg_table->begin(); ci != egg_table->end(); ++ci) {
178  if ((*ci)->get_name() == "xform") {
179  if (this_node == NULL) {
180  this_node = create_xfm_channel((*ci), egg_table->get_name(), parent);
181  } else {
182  egg2pg_cat.warning()
183  << "Duplicate xform table under node "
184  << egg_table->get_name() << "\n";
185  }
186  }
187  }
188 
189  // If none of them were named "xform", just create a plain old AnimGroup.
190  if (this_node == NULL) {
191  this_node = new AnimGroup(parent, egg_table->get_name());
192  }
193 
194  // Now walk the children again, creating any leftover tables, and recursing.
195  for (ci = egg_table->begin(); ci != egg_table->end(); ++ci) {
196  if ((*ci)->get_name() == "xform") {
197  // Skip this one. We already got it.
198  } else if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
199  EggSAnimData *egg_anim = DCAST(EggSAnimData, *ci);
200  create_s_channel(egg_anim, egg_anim->get_name(), this_node);
201 
202  } else if ((*ci)->is_of_type(EggTable::get_class_type())) {
203  EggTable *child = DCAST(EggTable, *ci);
204  build_hierarchy(child, this_node);
205  }
206  }
207 }
208 
209 
210 /**
211  * Creates an AnimChannelScalarTable corresponding to the given EggSAnimData
212  * structure.
213  */
214 AnimChannelScalarTable *AnimBundleMaker::
215 create_s_channel(EggSAnimData *egg_anim, const string &name,
216  AnimGroup *parent) {
218  = new AnimChannelScalarTable(parent, name);
219 
220  // First we have to copy the table data from PTA_double to PTA_stdfloat.
221  PTA_stdfloat new_data = PTA_stdfloat::empty_array(egg_anim->get_num_rows(),
222  table->get_class_type());
223  for (int i = 0; i < egg_anim->get_num_rows(); i++) {
224  new_data[i] = (PN_stdfloat)egg_anim->get_value(i);
225  }
226 
227  // Now we can assign the table.
228  table->set_table(new_data);
229 
230  return table;
231 }
232 
233 
234 /**
235  * Creates an AnimChannelMatrixXfmTable corresponding to the given EggNode
236  * structure, if possible.
237  */
238 AnimChannelMatrixXfmTable *AnimBundleMaker::
239 create_xfm_channel(EggNode *egg_node, const string &name,
240  AnimGroup *parent) {
241  if (egg_node->is_of_type(EggXfmAnimData::get_class_type())) {
242  EggXfmAnimData *egg_anim = DCAST(EggXfmAnimData, egg_node);
243  EggXfmSAnim new_anim(*egg_anim);
244  return create_xfm_channel(&new_anim, name, parent);
245 
246  } else if (egg_node->is_of_type(EggXfmSAnim::get_class_type())) {
247  EggXfmSAnim *egg_anim = DCAST(EggXfmSAnim, egg_node);
248  return create_xfm_channel(egg_anim, name, parent);
249  }
250 
251  egg2pg_cat.warning()
252  << "Inappropriate node named xform under node "
253  << name << "\n";
254  return NULL;
255 }
256 
257 
258 /**
259  * Creates an AnimChannelMatrixXfmTable corresponding to the given EggXfmSAnim
260  * structure.
261  */
262 AnimChannelMatrixXfmTable *AnimBundleMaker::
263 create_xfm_channel(EggXfmSAnim *egg_anim, const string &name,
264  AnimGroup *parent) {
265  // Ensure that the anim table is optimal and that it is standard order.
266  egg_anim->optimize_to_standard_order();
267 
269  = new AnimChannelMatrixXfmTable(parent, name);
270 
271  // The EggXfmSAnim structure has a number of children which are EggSAnimData
272  // tables. Each of these represents a separate component of the transform
273  // data, and will be added to the table.
274 
275  EggXfmSAnim::const_iterator ci;
276  for (ci = egg_anim->begin(); ci != egg_anim->end(); ++ci) {
277  if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
278  EggSAnimData *child = DCAST(EggSAnimData, *ci);
279 
280  if (child->get_name().empty()) {
281  egg2pg_cat.warning()
282  << "Unnamed subtable of <Xfm$Anim_S$> " << name
283  << "\n";
284  } else {
285  char table_id = child->get_name()[0];
286 
287  if (child->get_name().length() > 1 ||
288  !table->is_valid_id(table_id)) {
289  egg2pg_cat.warning()
290  << "Unexpected table name " << child->get_name()
291  << ", child of " << name << "\n";
292 
293  } else if (table->has_table(table_id)) {
294  egg2pg_cat.warning()
295  << "Duplicate table definition for " << table_id
296  << " under " << name << "\n";
297 
298  } else {
299 
300  // Now we have to copy the table data from PTA_double to
301  // PTA_stdfloat.
302  PTA_stdfloat new_data=PTA_stdfloat::empty_array(child->get_num_rows(),
303  table->get_class_type());
304  for (int i = 0; i < child->get_num_rows(); i++) {
305  new_data[i] = (PN_stdfloat)child->get_value(i);
306  }
307 
308  // Now we can assign the table.
309  table->set_table(table_id, new_data);
310  }
311  }
312  }
313  }
314 
315  return table;
316 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
static bool is_valid_id(char table_id)
Returns true if the given letter is one of the nine valid table id&#39;s.
void optimize_to_standard_order()
Optimizes the table by collapsing redundant sub-tables, and simultaneously ensures that the order str...
Definition: eggXfmSAnim.cxx:99
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This corresponds to an &lt;Xfm$Anim_S$&gt; entry, which is a collection of up to nine &lt;S$Anim&gt; entries that...
Definition: eggXfmSAnim.h:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
int get_num_rows() const
Returns the number of rows in the table.
Definition: eggSAnimData.I:46
A base class for EggSAnimData and EggXfmAnimData, which contain rows and columns of numbers...
Definition: eggAnimData.h:30
double get_fps() const
This is only valid if has_fps() returns true.
Definition: eggAnimData.I:79
void sort_descendants()
Sorts the children nodes at each level of the hierarchy into alphabetical order.
Definition: animGroup.cxx:158
An animation channel that issues a matrix each frame, read from a table such as might have been read ...
Corresponding to an &lt;S$Anim&gt; entry, this stores a single column of numbers, for instance for a morph ...
Definition: eggSAnimData.h:25
PT(AnimBundle) AnimBundle return DCAST(AnimBundle, group.p())
Returns a full copy of the bundle and its entire tree of nested AnimGroups.
Corresponding to an &lt;Xfm$Anim&gt; entry, this stores a two-dimensional table with up to nine columns...
void set_table(char table_id, const CPTA_stdfloat &table)
Assigns the indicated table.
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
int get_num_rows() const
Returns the number of rows in the table.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the base class for AnimChannel and AnimBundle.
Definition: animGroup.h:33
void set_table(const CPTA_stdfloat &table)
Assigns the data table.
This is the root of an AnimChannel hierarchy.
Definition: animBundle.h:29
double get_fps() const
This is only valid if has_fps() returns true.
Definition: eggXfmSAnim.I:82
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An animation channel that issues a scalar each frame, read from a table such as might have been read ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This corresponds to a.
Definition: eggTable.h:27
This is a node that contains a pointer to an AnimBundle.
bool has_table(char table_id) const
Returns true if the indicated subtable has been assigned.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double get_value(int row) const
Returns the value at the indicated row.
Definition: eggSAnimData.I:56