Panda3D
Loading...
Searching...
No Matches
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"
27
28using std::min;
29
30/**
31 *
32 */
33AnimBundleMaker::
34AnimBundleMaker(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 */
65AnimBundleNode *AnimBundleMaker::
66make_node() {
67 return new AnimBundleNode(_root->get_name(), make_bundle());
68}
69
70/**
71 *
72 */
73AnimBundle *AnimBundleMaker::
74make_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 */
94void AnimBundleMaker::
95inspect_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 */
170void AnimBundleMaker::
171build_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 */
216AnimChannelScalarTable *AnimBundleMaker::
217create_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 */
240AnimChannelMatrixXfmTable *AnimBundleMaker::
241create_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 */
264AnimChannelMatrixXfmTable *AnimBundleMaker::
265create_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.
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 a node that contains a pointer to an AnimBundle.
This is the root of an AnimChannel hierarchy.
Definition animBundle.h:29
An animation channel that issues a matrix each frame, read from a table such as might have been read ...
set_table
Assigns the indicated table.
has_table
Returns true if the indicated subtable has been assigned.
static bool is_valid_id(char table_id)
Returns true if the given letter is one of the nine valid table id's.
An animation channel that issues a scalar each frame, read from a table such as might have been read ...
set_table
Assigns the data table.
This is the base class for AnimChannel and AnimBundle.
Definition animGroup.h:33
void sort_descendants()
Sorts the children nodes at each level of the hierarchy into alphabetical order.
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
A base class for nodes in the hierarchy that are not leaf nodes.
A base class for things that may be directly added into the egg hierarchy.
Definition eggNode.h:36
Corresponding to an entry, this stores a single column of numbers, for instance for a morph target,...
double get_value(int row) const
Returns the value at the indicated row.
int get_num_rows() const
Returns the number of rows in the table.
This corresponds to a.
Definition eggTable.h:27
Corresponding to an <Xfm$Anim> entry, this stores a two-dimensional table with up to nine columns,...
int get_num_rows() const
Returns the number of rows in the table.
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine entries that specify...
Definition eggXfmSAnim.h:28
void optimize_to_standard_order()
Optimizes the table by collapsing redundant sub-tables, and simultaneously ensures that the order str...
double get_fps() const
This is only valid if has_fps() returns true.
Definition eggXfmSAnim.I:82
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.