15 #include "eggCharacterCollection.h"
16 #include "eggCharacterData.h"
17 #include "eggJointData.h"
18 #include "eggSliderData.h"
23 #include "eggPrimitive.h"
24 #include "eggVertex.h"
25 #include "eggVertexUV.h"
26 #include "eggMorphList.h"
27 #include "eggSAnimData.h"
28 #include "indirectCompareNames.h"
39 EggCharacterCollection::
40 EggCharacterCollection() {
41 _next_model_index = 0;
49 EggCharacterCollection::
50 ~EggCharacterCollection() {
51 Characters::iterator ci;
53 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
74 _top_egg_nodes.clear();
76 if (!scan_hierarchy(egg)) {
80 int egg_index = _eggs.size();
82 EggInfo &egg_info = _eggs.back();
84 egg_info._first_model_index = 0;
88 TopEggNodesByName::iterator tni;
89 for (tni = _top_egg_nodes.begin(); tni != _top_egg_nodes.end(); ++tni) {
90 string character_name = (*tni).first;
95 TopEggNodes::iterator ti;
96 for (ti = top_nodes.begin(); ti != top_nodes.end(); ++ti) {
97 EggNode *model_root = (*ti).first;
98 ModelDescription &desc = (*ti).second;
100 int model_index = _next_model_index++;
101 if (egg_info._models.empty()) {
102 egg_info._first_model_index = model_index;
104 egg_info._models.push_back(model_root);
106 char_data->
add_model(model_index, model_root, egg);
107 nassertr(model_index == (
int)_characters_by_model_index.size(), -1);
108 _characters_by_model_index.push_back(char_data);
111 match_egg_nodes(char_data, root_joint, desc._top_nodes,
112 egg_index, model_index);
114 scan_for_morphs(model_root, model_index, char_data);
115 scan_for_sliders(model_root, model_index, char_data);
130 Characters::const_iterator ci;
131 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
133 if (char_data->get_name() == character_name) {
195 Characters::iterator ci;
196 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
198 if (char_data->get_name() == character_name) {
205 char_data->set_name(character_name);
206 _characters.push_back(char_data);
222 bool EggCharacterCollection::
223 scan_hierarchy(
EggNode *egg_node) {
224 if (egg_node->
is_of_type(EggGroup::get_class_type())) {
226 if (group->get_dart_type() != EggGroup::DT_none) {
228 scan_for_top_joints(group, group, group->get_name());
232 }
else if (egg_node->
is_of_type(EggTable::get_class_type())) {
234 if (table->get_table_type() == EggTable::TT_bundle) {
236 scan_for_top_tables(table, table, table->get_name());
241 bool character_found =
false;
242 if (egg_node->
is_of_type(EggGroupNode::get_class_type())) {
244 EggGroupNode::iterator gi;
245 for (gi = group->begin(); gi != group->end(); ++gi) {
246 if (scan_hierarchy(*gi)) {
247 character_found =
true;
252 return character_found;
262 void EggCharacterCollection::
264 const string &character_name) {
265 if (egg_node->
is_of_type(EggGroup::get_class_type())) {
268 if (group->has_lod()) {
274 if (group->get_group_type() == EggGroup::GT_joint) {
276 ModelDescription &desc = _top_egg_nodes[character_name][model_root];
277 desc._root_node = model_root;
278 desc._top_nodes.push_back(group);
283 if (egg_node->
is_of_type(EggGroupNode::get_class_type())) {
285 EggGroupNode::iterator gi;
286 for (gi = group->begin(); gi != group->end(); ++gi) {
287 scan_for_top_joints(*gi, model_root, character_name);
299 void EggCharacterCollection::
301 const string &character_name) {
304 EggGroupNode::iterator gi;
305 for (gi = bundle->begin(); gi != bundle->end(); ++gi) {
307 if (child->
is_of_type(EggTable::get_class_type())) {
309 if (table->get_name() ==
"<skeleton>") {
312 ModelDescription &desc = _top_egg_nodes[character_name][model_root];
313 desc._root_node = table;
315 EggGroupNode::iterator cgi;
316 for (cgi = table->begin(); cgi != table->end(); ++cgi) {
318 if (grandchild->
is_of_type(EggTable::get_class_type())) {
319 desc._top_nodes.push_back(grandchild);
333 void EggCharacterCollection::
334 scan_for_morphs(
EggNode *egg_node,
int model_index,
336 if (egg_node->
is_of_type(EggPrimitive::get_class_type())) {
339 add_morph_back_pointers(prim, prim, model_index, char_data);
342 EggPrimitive::const_iterator vi;
343 for (vi = prim->begin(); vi != prim->end(); ++vi) {
346 add_morph_back_pointers(vertex, vertex, model_index, char_data);
347 add_morph_back_pointers_vertex(vertex, vertex, model_index, char_data);
349 EggMorphVertexList::const_iterator mvi;
350 for (mvi = vertex->_dxyzs.begin();
351 mvi != vertex->_dxyzs.end();
354 char_data->
make_slider(morph.get_name())->add_back_pointer(model_index, vertex);
359 if (egg_node->
is_of_type(EggGroupNode::get_class_type())) {
361 EggGroupNode::iterator gi;
362 for (gi = group->begin(); gi != group->end(); ++gi) {
363 scan_for_morphs(*gi, model_index, char_data);
374 void EggCharacterCollection::
375 scan_for_sliders(
EggNode *egg_node,
int model_index,
377 if (egg_node->
is_of_type(EggTable::get_class_type())) {
386 EggGroupNode::iterator gi;
387 for (gi = bundle->begin(); gi != bundle->end(); ++gi) {
389 if (child->
is_of_type(EggTable::get_class_type())) {
391 if (table->get_name() ==
"morph") {
395 EggGroupNode::iterator cgi;
396 for (cgi = table->begin(); cgi != table->end(); ++cgi) {
398 if (grandchild->
is_of_type(EggSAnimData::get_class_type())) {
399 char_data->
make_slider(grandchild->get_name())->add_back_pointer(model_index, grandchild);
414 void EggCharacterCollection::
417 EggMorphNormalList::const_iterator mni;
418 for (mni = attrib->_dnormals.begin();
419 mni != attrib->_dnormals.end();
422 char_data->
make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
425 EggMorphColorList::const_iterator mci;
426 for (mci = attrib->_drgbas.begin();
427 mci != attrib->_drgbas.end();
430 char_data->
make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
440 void EggCharacterCollection::
446 EggMorphTexCoordList::const_iterator mti;
447 for (mti = vert_uv->_duvs.begin();
448 mti != vert_uv->_duvs.end();
451 char_data->
make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
466 void EggCharacterCollection::
468 EggNodeList &egg_nodes,
int egg_index,
int model_index) {
473 if (joint_data->_children.empty()) {
476 EggNodeList::iterator ei;
477 for (ei = egg_nodes.begin(); ei != egg_nodes.end(); ++ei) {
480 joint_data->_children.push_back(data);
481 char_data->_joints.push_back(data);
482 char_data->_components.push_back(data);
483 data->_parent = joint_data;
484 data->_new_parent = joint_data;
485 found_egg_match(char_data, data, egg_node, egg_index, model_index);
492 EggNodeList extra_egg_nodes;
495 EggNodeList::iterator ei;
496 EggJointData::Children::iterator di;
498 ei = egg_nodes.begin();
499 di = joint_data->_children.begin();
501 while (ei != egg_nodes.end() && di != joint_data->_children.end()) {
505 if (egg_node->get_name() < data->get_name()) {
507 extra_egg_nodes.push_back(egg_node);
510 }
else if (data->get_name() < egg_node->get_name()) {
512 extra_data.push_back(data);
517 found_egg_match(char_data, data, egg_node, egg_index, model_index);
523 while (ei != egg_nodes.end()) {
527 extra_egg_nodes.push_back(egg_node);
531 while (di != joint_data->_children.end()) {
535 extra_data.push_back(data);
539 if (!extra_egg_nodes.empty()) {
545 EggNodeList more_egg_nodes;
547 for (ei = extra_egg_nodes.begin(); ei != extra_egg_nodes.end(); ++ei) {
549 bool matched =
false;
550 for (di = extra_data.begin(); di != extra_data.end(); ++di) {
553 found_egg_match(char_data, data, egg_node, egg_index, model_index);
554 extra_data.erase(di);
562 more_egg_nodes.push_back(egg_node);
565 extra_egg_nodes.swap(more_egg_nodes);
568 if (!extra_egg_nodes.empty()) {
571 if (extra_egg_nodes.size() == extra_data.size()) {
574 for (i = 0; i < extra_egg_nodes.size(); i++) {
575 EggNode *egg_node = extra_egg_nodes[i];
577 found_egg_match(char_data, data, egg_node, egg_index, model_index);
582 EggNodeList::iterator ei;
583 for (ei = extra_egg_nodes.begin(); ei != extra_egg_nodes.end(); ++ei) {
586 joint_data->_children.push_back(data);
587 char_data->_joints.push_back(data);
588 char_data->_components.push_back(data);
589 data->_parent = joint_data;
590 data->_new_parent = joint_data;
591 found_egg_match(char_data, data, egg_node, egg_index, model_index);
599 sort(joint_data->_children.begin(), joint_data->_children.end(),
610 void EggCharacterCollection::
612 EggNode *egg_node,
int egg_index,
int model_index) {
614 joint_data->
add_name(egg_node->get_name(), char_data->_component_names);
616 egg_node->set_name(joint_data->get_name());
619 if (egg_node->
is_of_type(EggGroupNode::get_class_type())) {
624 EggNodeList egg_nodes;
629 if (egg_node->
is_of_type(EggGroup::get_class_type())) {
631 EggGroupNode::iterator gi;
632 for (gi = group_node->begin(); gi != group_node->end(); ++gi) {
634 if (child->
is_of_type(EggGroup::get_class_type())) {
636 if (group->get_group_type() == EggGroup::GT_joint) {
637 egg_nodes.push_back(group);
644 EggGroupNode::iterator gi;
645 for (gi = group_node->begin(); gi != group_node->end(); ++gi) {
647 if (child->
is_of_type(EggTable::get_class_type())) {
649 if (!(table->get_name() ==
"xform")) {
650 egg_nodes.push_back(table);
656 if (!egg_nodes.empty()) {
657 match_egg_nodes(char_data, joint_data, egg_nodes,
658 egg_index, model_index);
672 nassertv(i >= 0 && i < (
int)_characters.size());
675 if (char_data->get_name() != name) {
677 char_data->rename_char(name);
686 void EggCharacterCollection::
687 write(ostream &out,
int indent_level)
const {
688 Characters::const_iterator ci;
690 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
692 char_data->write(out, indent_level);
712 Characters::const_iterator ci;
713 for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
716 for (
int j = 0; j < num_joints; j++) {
719 if (force_initial_rest_frame) {
721 out <<
"Forced rest frames the same for " << joint_data->get_name()
724 out <<
"Warning: rest frames for " << joint_data->get_name()
731 for (
int mi = 0; mi < num_models; mi++) {
734 out <<
"Warning: animation from "
736 <<
" had an inconsistent number of frames.\n";
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
The set of UV's that may or may not be assigned to a vertex.
virtual EggCharacterData * make_character_data()
Allocates and returns a new EggCharacterData structure.
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
EggSliderData * make_slider(const string &name)
Returns the slider matching the indicated name.
This is our own Panda specialization on the default STL map.
bool rest_frames_differ() const
Returns true if the rest frames for different models differ in their initial value.
int get_num_models() const
Returns the total number of models associated with this character.
bool check_num_frames(int model_index)
Walks through each component and ensures that all have the same number of frames of animation (except...
bool matches_name(const string &name) const
Returns true if the indicated name matches any name that was ever matched with this particular joint...
A base class for nodes in the hierarchy that are not leaf nodes.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
int get_num_joints() const
Returns the total number of joints in the character joint hierarchy.
This corresponds to a single morph slider control.
int add_egg(EggData *egg)
Adds a new egg file to the list of models and animation files for this particular character...
A single <Dxyz> or <Duv> or some such entry.
This is the primary interface into all the egg data, and the root of the egg file structure...
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
const_uv_iterator uv_begin() const
Returns an iterator that allows walking through the complete set of named UV's on the vertex...
const_uv_iterator uv_end() const
Returns an iterator that allows walking through the complete set of named UV's on the vertex...
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
The set of attributes that may be applied to vertices as well as polygons, such as surface normal and...
int get_model_index(int n) const
Returns the model_index of the nth model associated with this character.
EggCharacterData * make_character(const string &character_name)
Allocates and returns a new EggCharacterData object representing the named character, if there is not already a character by that name.
EggJointData * get_root_joint() const
Returns the root joint of the character hierarchy.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
EggCharacterData * get_character_by_name(const string &character_name) const
Returns the Character with the indicated name, if it exists in the collection, or NULL if it does not...
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
Represents a single character, as read and collected from several models and animation files...
void rename_char(int i, const string &name)
Renames the ith character to the indicated name.
This is one node of a hierarchy of EggJointData nodes, each of which represents a single joint of the...
string get_basename() const
Returns the basename part of the filename.
virtual void add_back_pointer(int model_index, EggObject *egg_object)
Adds the indicated model joint or anim table to the data.
virtual EggSliderData * make_slider_data(EggCharacterData *char_data)
Allocates and returns a new EggSliderData structure for the given character.
A base class for things that may be directly added into the egg hierarchy.
void force_initial_rest_frame()
Forces all of the joints to have the same rest frame value as the first joint read in...
void add_name(const string &name, NameUniquifier &uniquifier)
Adds the indicated name to the set of names that this component can be identified with...
EggJointData * get_joint(int n) const
Returns the nth joint in the character joint hierarchy.
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...
const Filename & get_egg_filename() const
Returns the directory in which the egg file is considered to reside.
void check_errors(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...
The highest-level base class in the egg directory.
EggData * get_egg_data(int n) const
Returns the EggData representing the egg file that defined this particular model. ...
virtual EggJointData * make_joint_data(EggCharacterData *char_data)
Allocates and returns a new EggJointData structure for the given character.