Panda3D
Loading...
Searching...
No Matches
eggCharacterCollection.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 eggCharacterCollection.cxx
10 * @author drose
11 * @date 2001-02-26
12 */
13
15#include "eggCharacterData.h"
16#include "eggJointData.h"
17#include "eggSliderData.h"
18
19#include "dcast.h"
20#include "eggGroup.h"
21#include "eggTable.h"
22#include "eggPrimitive.h"
23#include "eggVertex.h"
24#include "eggVertexUV.h"
25#include "eggMorphList.h"
26#include "eggSAnimData.h"
28#include "indent.h"
29
30#include <algorithm>
31
32using std::string;
33
34
35/**
36 *
37 */
38EggCharacterCollection::
39EggCharacterCollection() {
40 _next_model_index = 0;
41}
42
43/**
44 *
45 */
46EggCharacterCollection::
47~EggCharacterCollection() {
48 Characters::iterator ci;
49
50 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
51 delete (*ci);
52 }
53}
54
55/**
56 * Adds a new egg file to the list of models and animation files for this
57 * particular character.
58 *
59 * Returns the new egg_index if the file is successfully added, or -1 if there
60 * is some problem (for instance, it does not contain a character model or
61 * animation table).
62 *
63 * If the joint hierarchy does not match the existing joint hierarchy, a best
64 * match is attempted.
65 */
67add_egg(EggData *egg) {
68 _top_egg_nodes.clear();
69
70 if (!scan_hierarchy(egg)) {
71 return -1;
72 }
73
74 int egg_index = _eggs.size();
75 _eggs.push_back(EggInfo());
76 EggInfo &egg_info = _eggs.back();
77 egg_info._egg = egg;
78 egg_info._first_model_index = 0;
79
80 // Now, for each model, add an entry in the egg_info and match the joint
81 // hierarchy to the known joints.
82 TopEggNodesByName::iterator tni;
83 for (tni = _top_egg_nodes.begin(); tni != _top_egg_nodes.end(); ++tni) {
84 string character_name = (*tni).first;
85 TopEggNodes &top_nodes = (*tni).second;
86 EggCharacterData *char_data = make_character(character_name);
87 EggJointData *root_joint = char_data->get_root_joint();
88
89 TopEggNodes::iterator ti;
90 for (ti = top_nodes.begin(); ti != top_nodes.end(); ++ti) {
91 EggNode *model_root = (*ti).first;
92 ModelDescription &desc = (*ti).second;
93
94 int model_index = _next_model_index++;
95 if (egg_info._models.empty()) {
96 egg_info._first_model_index = model_index;
97 }
98 egg_info._models.push_back(model_root);
99
100 char_data->add_model(model_index, model_root, egg);
101 nassertr(model_index == (int)_characters_by_model_index.size(), -1);
102 _characters_by_model_index.push_back(char_data);
103 root_joint->add_back_pointer(model_index, desc._root_node);
104
105 match_egg_nodes(char_data, root_joint, desc._top_nodes,
106 egg_index, model_index);
107
108 scan_for_morphs(model_root, model_index, char_data);
109 scan_for_sliders(model_root, model_index, char_data);
110 }
111 }
112
113 return egg_index;
114}
115
116/**
117 * Returns the Character with the indicated name, if it exists in the
118 * collection, or NULL if it does not.
119 */
121get_character_by_name(const string &character_name) const {
122 Characters::const_iterator ci;
123 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
124 EggCharacterData *char_data = (*ci);
125 if (char_data->get_name() == character_name) {
126 return char_data;
127 }
128 }
129
130 return nullptr;
131}
132
133
134/**
135 * Allocates and returns a new EggCharacterData structure. This is primarily
136 * intended as a hook so derived classes can customize the type of
137 * EggCharacterData nodes used to represent the characters in this collection.
138 */
143
144/**
145 * Allocates and returns a new EggJointData structure for the given character.
146 * This is primarily intended as a hook so derived classes can customize the
147 * type of EggJointData nodes used to represent the joint hierarchy.
148 */
151 return new EggJointData(this, char_data);
152}
153
154/**
155 * Allocates and returns a new EggSliderData structure for the given
156 * character. This is primarily intended as a hook so derived classes can
157 * customize the type of EggSliderData nodes used to represent the slider
158 * list.
159 */
162 return new EggSliderData(this, char_data);
163}
164
165/**
166 * Allocates and returns a new EggCharacterData object representing the named
167 * character, if there is not already a character by that name.
168 */
170make_character(const string &character_name) {
171 // Does the named character exist yet?
172
173 Characters::iterator ci;
174 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
175 EggCharacterData *char_data = (*ci);
176 if (char_data->get_name() == character_name) {
177 return char_data;
178 }
179 }
180
181 // Define a new character.
183 char_data->set_name(character_name);
184 _characters.push_back(char_data);
185 return char_data;
186}
187
188/**
189 * Walks the given egg data's hierarchy, looking for either the start of an
190 * animation channel or the start of a character model. Returns true if
191 * either (or both) is found, false if the model appears to have nothing to do
192 * with characters.
193 *
194 * Fills up the _top_egg_nodes according to the nodes found.
195 */
196bool EggCharacterCollection::
197scan_hierarchy(EggNode *egg_node) {
198 if (egg_node->is_of_type(EggGroup::get_class_type())) {
199 EggGroup *group = DCAST(EggGroup, egg_node);
200 if (group->get_dart_type() != EggGroup::DT_none) {
201 // A group with a <Dart> flag begins a character model.
202 scan_for_top_joints(group, group, group->get_name());
203 return true;
204 }
205
206 } else if (egg_node->is_of_type(EggTable::get_class_type())) {
207 EggTable *table = DCAST(EggTable, egg_node);
208 if (table->get_table_type() == EggTable::TT_bundle) {
209 // A <Bundle> begins an animation table.
210 scan_for_top_tables(table, table, table->get_name());
211 return true;
212 }
213 }
214
215 bool character_found = false;
216 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
217 EggGroupNode *group = DCAST(EggGroupNode, egg_node);
218 EggGroupNode::iterator gi;
219 for (gi = group->begin(); gi != group->end(); ++gi) {
220 if (scan_hierarchy(*gi)) {
221 character_found = true;
222 }
223 }
224 }
225
226 return character_found;
227}
228
229/**
230 * Once a character model has been found, continue scanning the egg hierarchy
231 * to look for the topmost <Joint> nodes encountered.
232 */
233void EggCharacterCollection::
234scan_for_top_joints(EggNode *egg_node, EggNode *model_root,
235 const string &character_name) {
236 if (egg_node->is_of_type(EggGroup::get_class_type())) {
237 EggGroup *group = DCAST(EggGroup, egg_node);
238
239 if (group->has_lod()) {
240 // This group has an LOD specification; that indicates multiple skeleton
241 // hierarchies for this character, one for each LOD. We call each of
242 // these a separate model.
243 model_root = group;
244 }
245 if (group->get_group_type() == EggGroup::GT_joint) {
246 // A <Joint> node begins a model hierarchy.
247 ModelDescription &desc = _top_egg_nodes[character_name][model_root];
248 desc._root_node = model_root;
249 desc._top_nodes.push_back(group);
250 return;
251 }
252 }
253
254 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
255 EggGroupNode *group = DCAST(EggGroupNode, egg_node);
256 EggGroupNode::iterator gi;
257 for (gi = group->begin(); gi != group->end(); ++gi) {
258 scan_for_top_joints(*gi, model_root, character_name);
259 }
260 }
261}
262
263/**
264 * Once an animation has been found, continue scanning the egg hierarchy to
265 * look for the topmost <Table> nodes encountered.
266 */
267void EggCharacterCollection::
268scan_for_top_tables(EggTable *bundle, EggNode *model_root,
269 const string &character_name) {
270 // We really only need to check the immediate children of the bundle for a
271 // table node called "<skeleton>".
272 EggGroupNode::iterator gi;
273 for (gi = bundle->begin(); gi != bundle->end(); ++gi) {
274 EggNode *child = (*gi);
275 if (child->is_of_type(EggTable::get_class_type())) {
276 EggTable *table = DCAST(EggTable, child);
277 if (table->get_name() == "<skeleton>") {
278 // Here it is! Now the immediate children of this node are the top
279 // tables.
280 ModelDescription &desc = _top_egg_nodes[character_name][model_root];
281 desc._root_node = table;
282
283 EggGroupNode::iterator cgi;
284 for (cgi = table->begin(); cgi != table->end(); ++cgi) {
285 EggNode *grandchild = (*cgi);
286 if (grandchild->is_of_type(EggTable::get_class_type())) {
287 desc._top_nodes.push_back(grandchild);
288 }
289 }
290 }
291 }
292 }
293}
294
295/**
296 * Go back through a model's hierarchy and look for morph targets on the
297 * vertices and primitives.
298 */
299void EggCharacterCollection::
300scan_for_morphs(EggNode *egg_node, int model_index,
301 EggCharacterData *char_data) {
302 if (egg_node->is_of_type(EggPrimitive::get_class_type())) {
303 EggPrimitive *prim = DCAST(EggPrimitive, egg_node);
304 // Check for morphs on the primitive.
305 add_morph_back_pointers(prim, prim, model_index, char_data);
306
307 // Also check for morphs on each of the prim's vertices.
308 EggPrimitive::const_iterator vi;
309 for (vi = prim->begin(); vi != prim->end(); ++vi) {
310 EggVertex *vertex = (*vi);
311
312 add_morph_back_pointers(vertex, vertex, model_index, char_data);
313 add_morph_back_pointers_vertex(vertex, vertex, model_index, char_data);
314
315 EggMorphVertexList::const_iterator mvi;
316 for (mvi = vertex->_dxyzs.begin();
317 mvi != vertex->_dxyzs.end();
318 ++mvi) {
319 const EggMorphVertex &morph = (*mvi);
320 char_data->make_slider(morph.get_name())->add_back_pointer(model_index, vertex);
321 }
322 }
323 }
324
325 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
326 EggGroupNode *group = DCAST(EggGroupNode, egg_node);
327 EggGroupNode::iterator gi;
328 for (gi = group->begin(); gi != group->end(); ++gi) {
329 scan_for_morphs(*gi, model_index, char_data);
330 }
331 }
332}
333
334/**
335 * Go back to the animation tables and look for morph slider animation
336 * channels.
337 */
338void EggCharacterCollection::
339scan_for_sliders(EggNode *egg_node, int model_index,
340 EggCharacterData *char_data) {
341 if (egg_node->is_of_type(EggTable::get_class_type())) {
342 EggTable *bundle = DCAST(EggTable, egg_node);
343
344 // We really only need to check the immediate children of the bundle for a
345 // table node called "morph". This is a sibling of "<skeleton>", which we
346 // found a minute ago, but we weren't ready to scan for the morph sliders
347 // at the time, so we have to look again now.
348
349 EggGroupNode::iterator gi;
350 for (gi = bundle->begin(); gi != bundle->end(); ++gi) {
351 EggNode *child = (*gi);
352 if (child->is_of_type(EggTable::get_class_type())) {
353 EggTable *table = DCAST(EggTable, child);
354 if (table->get_name() == "morph") {
355 // Here it is! Now the immediate children of this node are all the
356 // slider channels.
357
358 EggGroupNode::iterator cgi;
359 for (cgi = table->begin(); cgi != table->end(); ++cgi) {
360 EggNode *grandchild = (*cgi);
361 if (grandchild->is_of_type(EggSAnimData::get_class_type())) {
362 char_data->make_slider(grandchild->get_name())->add_back_pointer(model_index, grandchild);
363 }
364 }
365 }
366 }
367 }
368 }
369}
370
371/**
372 * Adds the back pointers for the kinds of morphs we might find in an
373 * EggAttributes object.
374 */
375void EggCharacterCollection::
376add_morph_back_pointers(EggAttributes *attrib, EggObject *egg_object,
377 int model_index, EggCharacterData *char_data) {
378 EggMorphNormalList::const_iterator mni;
379 for (mni = attrib->_dnormals.begin();
380 mni != attrib->_dnormals.end();
381 ++mni) {
382 const EggMorphNormal &morph = (*mni);
383 char_data->make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
384 }
385
386 EggMorphColorList::const_iterator mci;
387 for (mci = attrib->_drgbas.begin();
388 mci != attrib->_drgbas.end();
389 ++mci) {
390 const EggMorphColor &morph = (*mci);
391 char_data->make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
392 }
393}
394
395/**
396 * Adds the back pointers for the kinds of morphs we might find in an
397 * EggVertex object.
398 */
399void EggCharacterCollection::
400add_morph_back_pointers_vertex(EggVertex *vertex, EggObject *egg_object,
401 int model_index, EggCharacterData *char_data) {
403 for (ui = vertex->uv_begin(); ui != vertex->uv_end(); ++ui) {
404 EggVertexUV *vert_uv = (*ui);
405 EggMorphTexCoordList::const_iterator mti;
406 for (mti = vert_uv->_duvs.begin();
407 mti != vert_uv->_duvs.end();
408 ++mti) {
409 const EggMorphTexCoord &morph = (*mti);
410 char_data->make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
411 }
412 }
413}
414
415/**
416 * Attempts to match up the indicated list of egg_nodes with the children of
417 * the given joint_data, by name if possible.
418 *
419 * Also recurses on each matched joint to build up the entire joint hierarchy.
420 */
421void EggCharacterCollection::
422match_egg_nodes(EggCharacterData *char_data, EggJointData *joint_data,
423 EggNodeList &egg_nodes, int egg_index, int model_index) {
424 // Sort the list of egg_nodes in order by name. This will make the matching
425 // up by names easier and more reliable.
426 sort(egg_nodes.begin(), egg_nodes.end(), IndirectCompareNames<Namable>());
427
428 if (joint_data->_children.empty()) {
429 // If the EggJointData has no children yet, we must be the first.
430 // Gleefully define all the joints.
431 EggNodeList::iterator ei;
432 for (ei = egg_nodes.begin(); ei != egg_nodes.end(); ++ei) {
433 EggNode *egg_node = (*ei);
434 EggJointData *data = make_joint_data(char_data);
435 joint_data->_children.push_back(data);
436 char_data->_joints.push_back(data);
437 char_data->_components.push_back(data);
438 data->_parent = joint_data;
439 data->_new_parent = joint_data;
440 found_egg_match(char_data, data, egg_node, egg_index, model_index);
441 }
442
443 } else {
444 // The EggJointData already has children; therefore, we have to match our
445 // joints up with the already-existing ones.
446
447 EggNodeList extra_egg_nodes;
448 EggJointData::Children extra_data;
449
450 EggNodeList::iterator ei;
451 EggJointData::Children::iterator di;
452
453 ei = egg_nodes.begin();
454 di = joint_data->_children.begin();
455
456 while (ei != egg_nodes.end() && di != joint_data->_children.end()) {
457 EggNode *egg_node = (*ei);
458 EggJointData *data = (*di);
459
460 if (egg_node->get_name() < data->get_name()) {
461 // Here's a joint in the egg file, unmatched in the data.
462 extra_egg_nodes.push_back(egg_node);
463 ++ei;
464
465 } else if (data->get_name() < egg_node->get_name()) {
466 // Here's a joint in the data, umatched by the egg file.
467 extra_data.push_back(data);
468 ++di;
469
470 } else {
471 // Hey, these two match! Hooray!
472 found_egg_match(char_data, data, egg_node, egg_index, model_index);
473 ++ei;
474 ++di;
475 }
476 }
477
478 while (ei != egg_nodes.end()) {
479 EggNode *egg_node = (*ei);
480
481 // Here's a joint in the egg file, unmatched in the data.
482 extra_egg_nodes.push_back(egg_node);
483 ++ei;
484 }
485
486 while (di != joint_data->_children.end()) {
487 EggJointData *data = (*di);
488
489 // Here's a joint in the data, umatched by the egg file.
490 extra_data.push_back(data);
491 ++di;
492 }
493
494 if (!extra_egg_nodes.empty()) {
495 // If we have some extra egg_nodes, we have to find a place to match
496 // them. (If we only had extra data, we don't care.)
497
498 // First, check to see if any of the names match any past-used name.
499 EggNodeList more_egg_nodes;
500
501 for (ei = extra_egg_nodes.begin(); ei != extra_egg_nodes.end(); ++ei) {
502 EggNode *egg_node = (*ei);
503 bool matched = false;
504 for (di = extra_data.begin(); di != extra_data.end(); ++di) {
505 EggJointData *data = (*di);
506 if (data->matches_name(egg_node->get_name())) {
507 found_egg_match(char_data, data, egg_node, egg_index, model_index);
508 extra_data.erase(di);
509 matched = true;
510 break;
511 }
512 }
513
514 if (!matched) {
515 // This joint name was never seen before.
516 more_egg_nodes.push_back(egg_node);
517 }
518 }
519 extra_egg_nodes.swap(more_egg_nodes);
520 }
521
522 if (!extra_egg_nodes.empty()) {
523 // Ok, we've still got to find a home for these remaining egg_nodes.
524 if (extra_egg_nodes.size() == extra_data.size()) {
525 // Match 'em up one-for-one.
526 size_t i;
527 for (i = 0; i < extra_egg_nodes.size(); i++) {
528 EggNode *egg_node = extra_egg_nodes[i];
529 EggJointData *data = extra_data[i];
530 found_egg_match(char_data, data, egg_node, egg_index, model_index);
531 }
532
533 } else {
534 // Just tack 'em on the end.
535 EggNodeList::iterator ei;
536 for (ei = extra_egg_nodes.begin(); ei != extra_egg_nodes.end(); ++ei) {
537 EggNode *egg_node = (*ei);
538 EggJointData *data = make_joint_data(char_data);
539 joint_data->_children.push_back(data);
540 char_data->_joints.push_back(data);
541 char_data->_components.push_back(data);
542 data->_parent = joint_data;
543 data->_new_parent = joint_data;
544 found_egg_match(char_data, data, egg_node, egg_index, model_index);
545 }
546 }
547 }
548 }
549
550 // Now sort the generated joint data hierarchy by name, just to be sure.
551 sort(joint_data->_children.begin(), joint_data->_children.end(),
553}
554
555/**
556 * Marks a one-to-one association between the indicated EggJointData and the
557 * indicated EggNode, and then recurses below.
558 */
559void EggCharacterCollection::
560found_egg_match(EggCharacterData *char_data, EggJointData *joint_data,
561 EggNode *egg_node, int egg_index, int model_index) {
562 if (egg_node->has_name()) {
563 joint_data->add_name(egg_node->get_name(), char_data->_component_names);
564 }
565 egg_node->set_name(joint_data->get_name());
566 joint_data->add_back_pointer(model_index, egg_node);
567
568 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
569 EggGroupNode *group_node = DCAST(EggGroupNode, egg_node);
570
571 // Now consider all the children of egg_node that are themselves joints or
572 // tables.
573 EggNodeList egg_nodes;
574
575 // Two approaches: either we are scanning a model with joints, or an
576 // animation bundle with tables.
577
578 if (egg_node->is_of_type(EggGroup::get_class_type())) {
579 // A model with joints.
580 EggGroupNode::iterator gi;
581 for (gi = group_node->begin(); gi != group_node->end(); ++gi) {
582 EggNode *child = (*gi);
583 if (child->is_of_type(EggGroup::get_class_type())) {
584 EggGroup *group = DCAST(EggGroup, child);
585 if (group->get_group_type() == EggGroup::GT_joint) {
586 egg_nodes.push_back(group);
587 }
588 }
589 }
590
591 } else {
592 // An animation bundle with tables.
593 EggGroupNode::iterator gi;
594 for (gi = group_node->begin(); gi != group_node->end(); ++gi) {
595 EggNode *child = (*gi);
596 if (child->is_of_type(EggTable::get_class_type())) {
597 EggTable *table = DCAST(EggTable, child);
598 if (!(table->get_name() == "xform")) {
599 egg_nodes.push_back(table);
600 }
601 }
602 }
603 }
604
605 if (!egg_nodes.empty()) {
606 match_egg_nodes(char_data, joint_data, egg_nodes,
607 egg_index, model_index);
608 }
609 }
610}
611
612/**
613 * Renames the ith character to the indicated name. This name must not
614 * already be used by another character in the collection.
615 */
617rename_char(int i, const string &name) {
618 nassertv(i >= 0 && i < (int)_characters.size());
619
620 EggCharacterData *char_data = _characters[i];
621 if (char_data->get_name() != name) {
622 nassertv(get_character_by_name(name) == nullptr);
623 char_data->rename_char(name);
624 }
625}
626
627/**
628 *
629 */
630void EggCharacterCollection::
631write(std::ostream &out, int indent_level) const {
632 Characters::const_iterator ci;
633
634 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
635 EggCharacterData *char_data = (*ci);
636 char_data->write(out, indent_level);
637 }
638}
639
640/**
641 * Can be called after the collection has been completely filled up with egg
642 * files to output any messages from warning conditions that have been
643 * detected, such as inconsistent animation tables.
644 *
645 * In addition to reporting this errors, calling this function will also
646 * ensure that they are all repaired. Pass force_initial_rest_frame as true
647 * to also force rest frames from different models to be the same if they are
648 * initially different.
649 */
651check_errors(std::ostream &out, bool force_initial_rest_frame) {
652 Characters::const_iterator ci;
653 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
654 EggCharacterData *char_data = (*ci);
655 int num_joints = char_data->get_num_joints();
656 for (int j = 0; j < num_joints; j++) {
657 EggJointData *joint_data = char_data->get_joint(j);
658 if (joint_data->rest_frames_differ()) {
659 if (force_initial_rest_frame) {
660 joint_data->force_initial_rest_frame();
661 out << "Forced rest frames the same for " << joint_data->get_name()
662 << ".\n";
663 } else {
664 out << "Warning: rest frames for " << joint_data->get_name()
665 << " differ.\n";
666 }
667 }
668 }
669
670 int num_models = char_data->get_num_models();
671 for (int mi = 0; mi < num_models; mi++) {
672 int model_index = char_data->get_model_index(mi);
673 if (!char_data->check_num_frames(model_index)) {
674 out << "Warning: animation from "
675 << char_data->get_egg_data(model_index)->get_egg_filename().get_basename()
676 << " had an inconsistent number of frames.\n";
677 }
678 }
679 }
680}
The set of attributes that may be applied to vertices as well as polygons, such as surface normal and...
EggCharacterData * make_character(const std::string &character_name)
Allocates and returns a new EggCharacterData object representing the named character,...
virtual EggSliderData * make_slider_data(EggCharacterData *char_data)
Allocates and returns a new EggSliderData structure for the given character.
int add_egg(EggData *egg)
Adds a new egg file to the list of models and animation files for this particular character.
virtual EggJointData * make_joint_data(EggCharacterData *char_data)
Allocates and returns a new EggJointData structure for the given character.
void check_errors(std::ostream &out, bool force_initial_rest_frame)
Can be called after the collection has been completely filled up with egg files to output any message...
void rename_char(int i, const std::string &name)
Renames the ith character to the indicated name.
virtual EggCharacterData * make_character_data()
Allocates and returns a new EggCharacterData structure.
EggCharacterData * get_character_by_name(const std::string &character_name) const
Returns the Character with the indicated name, if it exists in the collection, or NULL if it does not...
Represents a single character, as read and collected from several models and animation files.
EggJointData * get_root_joint() const
Returns the root joint of the character hierarchy.
int get_model_index(int n) const
Returns the model_index of the nth model associated with this character.
EggData * get_egg_data(int n) const
Returns the EggData representing the egg file that defined this particular model.
EggJointData * get_joint(int n) const
Returns the nth joint in the character joint hierarchy.
bool check_num_frames(int model_index)
Walks through each component and ensures that all have the same number of frames of animation (except...
EggSliderData * make_slider(const std::string &name)
Returns the slider matching the indicated name.
int get_num_models() const
Returns the total number of models associated with this character.
void add_model(int model_index, EggNode *model_root, EggData *egg_data)
Indicates that the given model_index (with the indicated model_root) is associated with this characte...
void rename_char(const std::string &name)
Renames all of the models in the character data to the indicated name.
int get_num_joints() const
Returns the total number of joints in the character joint hierarchy.
void add_name(const std::string &name, NameUniquifier &uniquifier)
Adds the indicated name to the set of names that this component can be identified with.
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
get_egg_filename
Returns the directory in which the egg file is considered to reside.
Definition eggData.h:74
A base class for nodes in the hierarchy that are not leaf nodes.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition eggGroup.h:34
This is one node of a hierarchy of EggJointData nodes, each of which represents a single joint of the...
virtual void add_back_pointer(int model_index, EggObject *egg_object)
Adds the indicated model joint or anim table to the data.
bool rest_frames_differ() const
Returns true if the rest frames for different models differ in their initial value.
void force_initial_rest_frame()
Forces all of the joints to have the same rest frame value as the first joint read in.
A single <Dxyz> or <Duv> or some such entry.
Definition eggMorph.h:30
A base class for things that may be directly added into the egg hierarchy.
Definition eggNode.h:36
The highest-level base class in the egg directory.
Definition eggObject.h:29
A base class for any of a number of kinds of geometry primitives: polygons, point lights,...
This corresponds to a single morph slider control.
This corresponds to a.
Definition eggTable.h:27
The set of UV's that may or may not be assigned to a vertex.
Definition eggVertexUV.h:29
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition eggVertex.h:39
const_uv_iterator uv_end() const
Returns an iterator that allows walking through the complete set of named UV's on the vertex.
Definition eggVertex.I:242
const_uv_iterator uv_begin() const
Returns an iterator that allows walking through the complete set of named UV's on the vertex.
Definition eggVertex.I:220
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition namable.I:44
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
This is our own Panda specialization on the default STL map.
Definition pmap.h:49
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
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.
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.