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