46 add_path_replace_options();
47 add_path_store_options();
52 set_program_brief(
"optimizes character models and animations in .egg files");
53 set_program_description
54 (
"egg-optchar performs basic optimizations of a character model "
55 "and its associated animations, primarily by analyzing the "
56 "animation tables and removing unneeded joints and/or morphs. "
57 "It can also perform basic restructuring operations on the "
58 "character hierarchy.");
62 "List the joint hierarchy instead of performing any operations.",
63 &EggOptchar::dispatch_none, &_list_hierarchy);
67 "List the joint hierarchy along with an indication of the properties "
69 &EggOptchar::dispatch_none, &_list_hierarchy_v);
73 "List the existing joint hierarchy as a series of -p joint,parent "
74 "commands, suitable for pasting into an egg-optchar command line.",
75 &EggOptchar::dispatch_none, &_list_hierarchy_p);
78 (
"keep",
"joint[,joint...]", 0,
79 "Keep the named joints (or sliders) in the character, even if they do "
80 "not appear to be needed by the animation.",
81 &EggOptchar::dispatch_vector_string_comma,
nullptr, &_keep_components);
84 (
"drop",
"joint[,joint...]", 0,
85 "Removes the named joints or sliders, even if they appear to be needed.",
86 &EggOptchar::dispatch_vector_string_comma,
nullptr, &_drop_components);
89 (
"expose",
"joint[,joint...]", 0,
90 "Expose the named joints by flagging them with a DCS attribute, so "
91 "each one can be found in the scene graph when the character is loaded, "
92 "and objects can be parented to it. This implies -keep.",
93 &EggOptchar::dispatch_vector_string_comma,
nullptr, &_expose_components);
96 (
"suppress",
"joint[,joint...]", 0,
97 "The opposite of suppress, this prevents the named joints from "
98 "being created with an implicit DCS attribute, even if they contain "
99 "rigid geometry. The default is to create an implicit node for any "
100 "joint that contains rigid geometry, to take advantage of display "
101 "list and/or vertex buffer caching. This does not imply -keep.",
102 &EggOptchar::dispatch_vector_string_comma,
nullptr, &_suppress_components);
105 (
"flag",
"node[,node...][=name]", 0,
106 "Assign the indicated name to the geometry within the given nodes. "
107 "This will make the geometry visible as a node in the resulting "
108 "character model when it is loaded in the scene graph (normally, "
109 "the node hierarchy is suppressed when loading characters). This "
110 "is different from -expose in that it reveals geometry rather than "
111 "joints; the revealed node can be hidden or its attributes changed "
112 "at runtime, but it will be animated by its vertices, not the node, so "
113 "objects parented to this node will not inherit its animation.",
114 &EggOptchar::dispatch_flag_groups,
nullptr, &_flag_groups);
117 (
"defpose",
"anim.egg,frame", 0,
118 "Specify the model's default pose. The pose is taken "
119 "from the indicated frame of the named animation file (which must "
120 "also be named separately on the command line). The "
121 "pose will be held by the model in "
122 "the absence of any animation, and need not be the same "
123 "pose in which the model was originally skinned.",
124 &EggOptchar::dispatch_string,
nullptr, &_defpose);
128 "Add an <AnimPreload> entry for each animation to the model file(s). "
129 "This can be used at runtime to support asynchronous "
130 "loading and binding of animation channels.",
131 &EggOptchar::dispatch_none, &_preload);
134 (
"zero",
"joint[,hprxyzijkabc]", 0,
135 "Zeroes out the animation channels for the named joint. If "
136 "a subset of the component letters hprxyzijkabc is included, the "
137 "operation is restricted to just those components; otherwise the "
138 "entire transform is cleared.",
139 &EggOptchar::dispatch_name_components,
nullptr, &_zero_channels);
143 "Keep all joints and sliders in the character, except those named "
144 "explicitly by -drop.",
145 &EggOptchar::dispatch_none, &_keep_all);
148 (
"p",
"joint,parent", 0,
149 "Moves the named joint under the named parent joint. Use "
150 "\"-p joint,\" to reparent a joint to the root. The joint transform "
151 "is recomputed appropriately under its new parent so that the animation "
152 "is not affected (the effect is similar to NodePath::wrt_reparent_to).",
153 &EggOptchar::dispatch_vector_string_pair,
nullptr, &_reparent_joints);
156 (
"new",
"joint,source", 0,
157 "Creates a new joint under the named parent joint. The new "
158 "joint will inherit the same net transform as its parent.",
159 &EggOptchar::dispatch_vector_string_pair,
nullptr, &_new_joints);
162 (
"rename",
"joint,newjoint", 0,
163 "Renames the indicated joint, if present, to the given name.",
164 &EggOptchar::dispatch_vector_string_pair,
nullptr, &_rename_joints);
169 "Computes the optimal joint hierarchy for the character by analyzing "
170 "all of the joint animation and reparenting joints to minimize "
171 "transformations. This can repair skeletons that have been flattened "
172 "or whose hierarchy was otherwise damaged in conversion; it can also "
173 "detect joints that are constrained to follow other joints and should "
174 "therefore be parented to the master joints. The result is a file "
175 "from which more joints may be successfully removed, that generally "
176 "compresses better and with fewer artifacts. However, this is a "
177 "fairly expensive operation.",
178 &EggOptchar::dispatch_none, &_optimal_hierarchy);
183 "Quantize joint membership values to the given unit. This is "
184 "the smallest significant change in joint membership. There can "
185 "be a significant performance (and memory utilization) runtime "
186 "benefit for eliminating small differences in joint memberships "
187 "between neighboring vertices. The default is 0.01; specifying "
188 "0 means to preserve the original values.",
189 &EggOptchar::dispatch_double,
nullptr, &_vref_quantum);
192 (
"qa",
"quantum[,hprxyzijkabc]", 0,
193 "Quantizes animation channels to the given unit. This rounds each "
194 "of the named components of all joints to the nearest multiple of unit. "
195 "There is no performance benefit, and little compression benefit, "
196 "for doing this; and this may introduce visible artifacts to the "
197 "animation. However, sometimes it is a useful tool for animation "
198 "analysis and comparison. This option may be repeated several times "
199 "to quantize different channels by a different amount.",
200 &EggOptchar::dispatch_double_components,
nullptr, &_quantize_anims);
203 (
"dart",
"[default, sync, nosync, or structured]", 0,
204 "change the dart value in the given eggs",
205 &EggOptchar::dispatch_string,
nullptr, &_dart_type);
208 _optimal_hierarchy =
false;
209 _vref_quantum = 0.01;
220 if (apply_user_reparents()) {
221 nout <<
"Reparenting hierarchy.\n";
227 if (!_zero_channels.empty()) {
231 int num_characters = _collection->get_num_characters();
235 for (ci = 0; ci < num_characters; ci++) {
238 analyze_sliders(char_data);
241 if (_list_hierarchy || _list_hierarchy_v) {
242 for (ci = 0; ci < num_characters; ci++) {
244 nout <<
"Character: " << char_data->get_name() <<
"\n";
246 list_scalars(char_data, _list_hierarchy_v);
250 }
else if (_list_hierarchy_p) {
251 for (ci = 0; ci < num_characters; ci++) {
253 nout <<
"Character: " << char_data->get_name() <<
"\n";
264 determine_removed_components();
266 if (process_joints()) {
285 if (!_flag_groups.empty()) {
287 for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
300 if (!_defpose.empty()) {
304 if (!_dart_type.empty()) {
306 for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
307 change_dart_type(*ei, _dart_type);
322 if (_list_hierarchy || _list_hierarchy_v || _list_hierarchy_p) {
326 return EggCharacterFilter::handle_args(args);
335 dispatch_vector_string_pair(
const string &opt,
const string &arg,
void *var) {
336 StringPairs *ip = (StringPairs *)var;
341 if (words.size() == 2) {
349 <<
" requires a pair of strings separated by a comma.\n";
364 dispatch_name_components(
const string &opt,
const string &arg,
void *var) {
365 StringPairs *ip = (StringPairs *)var;
371 if (words.size() == 1) {
374 }
else if (words.size() == 2) {
380 <<
" requires a pair of strings separated by a comma.\n";
385 sp._b = matrix_component_letters;
387 for (string::const_iterator si = sp._b.begin(); si != sp._b.end(); ++si) {
388 if (strchr(matrix_component_letters, *si) ==
nullptr) {
389 nout <<
"Not a standard matrix component: \"" << *si <<
"\"\n"
390 <<
"-" << opt <<
" requires a joint name followed by a set "
391 <<
"of component names. The standard component names are \""
392 << matrix_component_letters <<
"\".\n";
411 dispatch_double_components(
const string &opt,
const string &arg,
void *var) {
412 DoubleStrings *ip = (DoubleStrings *)var;
417 bool valid_double =
false;
420 if (words.size() == 1) {
423 }
else if (words.size() == 2) {
429 <<
" requires a numeric value followed by a string.\n";
435 <<
" requires a numeric value followed by a string.\n";
440 sp._b = matrix_component_letters;
442 for (string::const_iterator si = sp._b.begin(); si != sp._b.end(); ++si) {
443 if (strchr(matrix_component_letters, *si) ==
nullptr) {
444 nout <<
"Not a standard matrix component: \"" << *si <<
"\"\n"
445 <<
"-" << opt <<
" requires a joint name followed by a set "
446 <<
"of component names. The standard component names are \""
447 << matrix_component_letters <<
"\".\n";
465 dispatch_flag_groups(
const string &opt,
const string &arg,
void *var) {
466 FlagGroups *ip = (FlagGroups *)var;
474 <<
" requires a series of words separated by a comma.\n";
478 FlagGroupsEntry entry;
481 string &last_word = words.back();
482 size_t equals = last_word.rfind(
'=');
483 if (equals != string::npos) {
484 entry._name = last_word.substr(equals + 1);
485 last_word = last_word.substr(0, equals);
493 vector_string::const_iterator si;
494 for (si = words.begin(); si != words.end(); ++si) {
495 const string &word = (*si);
499 ip->push_back(entry);
509 determine_removed_components() {
514 Names suppress_names;
517 vector_string::const_iterator si;
518 for (si = _keep_components.begin(); si != _keep_components.end(); ++si) {
519 keep_names.insert(*si);
521 for (si = _drop_components.begin(); si != _drop_components.end(); ++si) {
522 drop_names.insert(*si);
524 for (si = _expose_components.begin(); si != _expose_components.end(); ++si) {
525 keep_names.insert(*si);
526 expose_names.insert(*si);
528 for (si = _suppress_components.begin(); si != _suppress_components.end(); ++si) {
529 suppress_names.insert(*si);
533 keep_names.insert(
"");
535 int num_characters = _collection->get_num_characters();
536 for (
int ci = 0; ci < num_characters; ci++) {
539 nout << char_data->get_name() <<
" has " << num_components <<
" components.\n";
540 for (
int i = 0; i < num_components; i++) {
542 nassertv(comp_data !=
nullptr);
546 nassertv(user_data !=
nullptr);
548 const string &name = comp_data->get_name();
549 if (suppress_names.find(name) != suppress_names.end()) {
552 names_used.insert(name);
553 user_data->_flags |= EggOptcharUserData::F_suppress;
556 if (drop_names.find(name) != drop_names.end()) {
558 names_used.insert(name);
559 user_data->_flags |= EggOptcharUserData::F_remove;
561 }
else if (_keep_all || keep_names.find(name) != keep_names.end()) {
563 names_used.insert(name);
565 if (expose_names.find(name) != expose_names.end()) {
567 user_data->_flags |= EggOptcharUserData::F_expose;
572 if ((user_data->_flags & (EggOptcharUserData::F_static | EggOptcharUserData::F_empty)) != 0) {
573 if ((user_data->_flags & (EggOptcharUserData::F_top | EggOptcharUserData::F_empty)) == EggOptcharUserData::F_top) {
583 user_data->_flags |= EggOptcharUserData::F_remove;
592 for (si = _keep_components.begin(); si != _keep_components.end(); ++si) {
593 const string &name = (*si);
594 if (names_used.find(name) == names_used.end()) {
595 nout <<
"No such component: " << name <<
"\n";
598 for (si = _drop_components.begin(); si != _drop_components.end(); ++si) {
599 const string &name = (*si);
600 if (names_used.find(name) == names_used.end()) {
601 nout <<
"No such component: " << name <<
"\n";
604 for (si = _expose_components.begin(); si != _expose_components.end(); ++si) {
605 const string &name = (*si);
606 if (names_used.find(name) == names_used.end()) {
607 nout <<
"No such component: " << name <<
"\n";
610 for (si = _suppress_components.begin(); si != _suppress_components.end(); ++si) {
611 const string &name = (*si);
612 if (names_used.find(name) == names_used.end()) {
613 nout <<
"No such component: " << name <<
"\n";
625 int num_characters = _collection->get_num_characters();
626 for (
int ci = 0; ci < num_characters; ci++) {
630 for (
int i = 0; i < num_joints; i++) {
635 if ((user_data->_flags & EggOptcharUserData::F_empty) == 0 &&
636 (user_data->_flags & EggOptcharUserData::F_remove) != 0) {
639 EggJointData *best_joint = find_best_vertex_joint(joint_data->get_parent());
643 if (best_joint !=
nullptr) {
646 best_user_data->_flags &= ~(EggOptcharUserData::F_empty | EggOptcharUserData::F_remove);
661 bool removed_any =
false;
662 int num_characters = _collection->get_num_characters();
663 for (
int ci = 0; ci < num_characters; ci++) {
669 int num_identity = 0;
673 for (
int i = 0; i < num_joints; i++) {
678 if ((user_data->_flags & EggOptcharUserData::F_remove) != 0) {
684 if ((user_data->_flags & EggOptcharUserData::F_identity) != 0) {
686 }
else if ((user_data->_flags & EggOptcharUserData::F_static) != 0) {
688 }
else if ((user_data->_flags & EggOptcharUserData::F_empty) != 0) {
697 EggJointData *best_parent = find_best_parent(joint_data->get_parent());
699 if ((user_data->_flags & EggOptcharUserData::F_expose) != 0) {
701 }
else if ((user_data->_flags & EggOptcharUserData::F_suppress) != 0) {
702 joint_data->
expose(EggGroup::DC_none);
708 if (num_joints == num_kept) {
709 nout << char_data->get_name() <<
": keeping " << num_joints
712 nout << setw(5) << num_joints
713 <<
" original joints in " << char_data->get_name()
715 if (num_identity != 0) {
716 nout << setw(5) << num_identity <<
" identity joints\n";
718 if (num_static != 0) {
719 nout << setw(5) << num_static <<
" unanimated joints\n";
721 if (num_empty != 0) {
722 nout << setw(5) << num_empty <<
" empty joints\n";
724 if (num_other != 0) {
725 nout << setw(5) << num_other <<
" other joints\n";
728 << setw(5) << num_kept <<
" joints remaining\n\n";
745 if ((user_data->_flags & EggOptcharUserData::F_remove) != 0) {
747 if (joint_data->get_parent() !=
nullptr) {
748 return find_best_parent(joint_data->get_parent());
761 find_best_vertex_joint(
EggJointData *joint_data)
const {
762 if (joint_data ==
nullptr) {
769 if ((user_data->_flags & EggOptcharUserData::F_static) != 0) {
771 return find_best_vertex_joint(joint_data->get_parent());
783 apply_user_reparents() {
784 bool did_anything =
false;
786 int num_characters = _collection->get_num_characters();
789 StringPairs::const_iterator spi;
790 for (spi = _new_joints.begin(); spi != _new_joints.end(); ++spi) {
791 const StringPair &p = (*spi);
793 for (
int ci = 0; ci < num_characters; ci++) {
801 if (node_b ==
nullptr) {
802 nout <<
"No joint named " << p._b <<
" in " << char_data->get_name()
805 }
else if (node_a !=
nullptr) {
806 nout <<
"Joint " << p._a <<
" already exists in "
807 << char_data->get_name() <<
".\n";
810 nout <<
"Creating new joint " << p._a <<
" in "
811 << char_data->get_name() <<
".\n";
819 for (spi = _reparent_joints.begin(); spi != _reparent_joints.end(); ++spi) {
820 const StringPair &p = (*spi);
822 for (
int ci = 0; ci < num_characters; ci++) {
830 if (node_b ==
nullptr) {
831 nout <<
"No joint named " << p._b <<
" in " << char_data->get_name()
833 }
else if (node_a ==
nullptr) {
834 nout <<
"No joint named " << p._a <<
" in " << char_data->get_name()
843 if (_optimal_hierarchy) {
845 for (
int ci = 0; ci < num_characters; ci++) {
847 nout <<
"Computing optimal hierarchy for "
848 << char_data->get_name() <<
".\n";
850 nout <<
"Done computing optimal hierarchy for "
851 << char_data->get_name() <<
".\n";
865 bool did_anything =
false;
866 int num_characters = _collection->get_num_characters();
868 StringPairs::const_iterator spi;
869 for (spi = _zero_channels.begin(); spi != _zero_channels.end(); ++spi) {
870 const StringPair &p = (*spi);
872 for (
int ci = 0; ci < num_characters; ci++) {
876 if (joint_data ==
nullptr) {
877 nout <<
"No joint named " << p._a <<
" in " << char_data->get_name()
895 quantize_channels() {
896 bool did_anything =
false;
897 int num_characters = _collection->get_num_characters();
899 DoubleStrings::const_iterator spi;
900 for (spi = _quantize_anims.begin(); spi != _quantize_anims.end(); ++spi) {
901 const DoubleString &p = (*spi);
903 for (
int ci = 0; ci < num_characters; ci++) {
907 if (joint_data !=
nullptr) {
930 user_data->_flags |= EggOptcharUserData::F_top;
937 bool different_mat =
false;
938 bool has_vertices =
false;
942 for (i = 0; i < num_models; i++) {
952 for (f = 0; f < num_frames && !different_mat; f++) {
953 LMatrix4d mat = joint_data->
get_frame(i, f);
957 user_data->_static_mat = mat;
961 if (!mat.almost_equal(user_data->_static_mat, 0.0001)) {
963 different_mat =
true;
970 if (!different_mat) {
972 user_data->_flags |= EggOptcharUserData::F_static;
975 user_data->_static_mat.almost_equal(LMatrix4d::ident_mat(), 0.0001)) {
977 user_data->_flags |= EggOptcharUserData::F_identity;
983 user_data->_flags |= EggOptcharUserData::F_empty;
986 int num_children = joint_data->get_num_children();
987 for (i = 0; i < num_children; i++) {
988 analyze_joints(joint_data->get_child(i), level + 1);
999 for (
int si = 0; si < num_sliders; si++) {
1009 bool different_value =
false;
1010 bool has_vertices =
false;
1013 for (
int i = 0; i < num_models; i++) {
1017 has_vertices =
true;
1023 for (f = 0; f < num_frames && !different_value; f++) {
1024 double value = slider_data->
get_frame(i, f);
1026 if (num_values == 1) {
1028 user_data->_static_value = value;
1032 if (!IS_THRESHOLD_EQUAL(value, user_data->_static_value, 0.0001)) {
1034 different_value =
true;
1041 if (!different_value) {
1043 user_data->_flags |= EggOptcharUserData::F_static;
1045 if (num_values == 0 || IS_THRESHOLD_ZERO(user_data->_static_value, 0.0001)) {
1047 user_data->_flags |= EggOptcharUserData::F_identity;
1051 if (!has_vertices) {
1053 user_data->_flags |= EggOptcharUserData::F_empty;
1062 list_joints(
EggJointData *joint_data,
int indent_level,
bool verbose) {
1066 int num_children = joint_data->get_num_children();
1067 for (
int i = 0; i < num_children; i++) {
1069 describe_component(child_data, indent_level, verbose);
1071 list_joints(child_data, indent_level + 2, verbose);
1083 int num_children = joint_data->get_num_children();
1084 static const int max_col = 72;
1086 for (
int i = 0; i < num_children; i++) {
1091 string text = string(
" -p ") + child_data->get_name() +
1092 string(
",") + joint_data->get_name();
1094 cout <<
" " << text;
1095 col = 4 + text.length();
1097 col += text.length();
1098 if (col >= max_col) {
1099 cout <<
" \\\n " << text;
1100 col = 4 + text.length();
1106 list_joints_p(child_data, col);
1116 for (
int si = 0; si < num_sliders; si++) {
1118 describe_component(slider_data, 0, verbose);
1130 indent(cout, indent_level)
1131 << comp_data->get_name();
1136 if (user_data->is_identity()) {
1137 cout <<
" (identity)";
1138 }
else if (user_data->is_static()) {
1139 cout <<
" (static)";
1141 if (user_data->is_empty()) {
1144 if (user_data->is_top()) {
1158 int num_characters = _collection->get_num_characters();
1159 for (
int ci = 0; ci < num_characters; ci++) {
1176 quantize_vertices() {
1178 for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
1179 quantize_vertices(*ei);
1188 quantize_vertices(
EggNode *egg_node) {
1189 if (egg_node->
is_of_type(EggVertexPool::get_class_type())) {
1192 for (vi = vpool->
begin(); vi != vpool->
end(); ++vi) {
1193 quantize_vertex(*vi);
1196 }
else if (egg_node->
is_of_type(EggGroupNode::get_class_type())) {
1198 EggGroupNode::iterator ci;
1199 for (ci = group->begin(); ci != group->end(); ++ci) {
1200 quantize_vertices(*ci);
1209 quantize_vertex(
EggVertex *egg_vertex) {
1217 EggVertex::GroupRef::const_iterator gi;
1218 double net_membership = 0.0;
1223 net_membership += membership;
1225 nassertv(net_membership != 0.0);
1229 double factor = 1.0 / net_membership;
1230 net_membership = 0.0;
1231 VertexMemberships::iterator mi;
1232 VertexMemberships::iterator largest = memberships.begin();
1234 for (mi = memberships.begin(); mi != memberships.end(); ++mi) {
1235 if ((*largest) < (*mi)) {
1241 double value = (*mi)._membership * factor;
1242 if (_vref_quantum != 0.0) {
1243 value = floor(value / _vref_quantum + 0.5) * _vref_quantum;
1245 (*mi)._membership = value;
1247 net_membership += value;
1252 (*largest)._membership += 1.0 - net_membership;
1255 for (mi = memberships.begin(); mi != memberships.end(); ++mi) {
1256 (*mi)._group->set_vertex_membership(egg_vertex, (*mi)._membership);
1267 bool matched =
false;
1269 FlagGroups::const_iterator fi;
1270 for (fi = _flag_groups.begin();
1271 fi != _flag_groups.end() && !matched;
1273 const FlagGroupsEntry &entry = (*fi);
1274 Globs::const_iterator si;
1275 for (si = entry._groups.begin();
1276 si != entry._groups.end() && !matched;
1278 if ((*si).matches(egg_group->get_name())) {
1280 if (!entry._name.empty()) {
1283 name = egg_group->get_name();
1293 rename_primitives(egg_group, name);
1297 EggGroupNode::iterator gi;
1298 for (gi = egg_group->begin(); gi != egg_group->end(); ++gi) {
1300 if (child->
is_of_type(EggGroupNode::get_class_type())) {
1302 do_flag_groups(group);
1312 for (StringPairs::iterator spi = _rename_joints.begin();
1313 spi != _rename_joints.end();
1315 const StringPair &sp = (*spi);
1316 int num_characters = _collection->get_num_characters();
1318 for (ci = 0; ci < num_characters; ++ci) {
1321 if (joint !=
nullptr) {
1322 nout <<
"Renaming joint " << sp._a <<
" to " << sp._b <<
"\n";
1323 joint->set_name(sp._b);
1326 for (
int mn = 0; mn < num_models; ++mn) {
1334 nout <<
"Couldn't find joint " << sp._a <<
"\n";
1345 change_dart_type(
EggGroupNode *egg_group,
const string &new_dart_type) {
1346 EggGroupNode::iterator gi;
1347 for (gi = egg_group->begin(); gi != egg_group->end(); ++gi) {
1349 if (child->
is_of_type(EggGroupNode::get_class_type())) {
1351 if (child->
is_of_type(EggGroup::get_class_type())) {
1353 EggGroup::DartType dt = gr->get_dart_type();
1354 if(dt != EggGroup::DT_none) {
1356 gr->set_dart_type(newDt);
1359 change_dart_type(group, new_dart_type);
1370 rename_primitives(
EggGroupNode *egg_group,
const string &name) {
1371 EggGroupNode::iterator gi;
1372 for (gi = egg_group->begin(); gi != egg_group->end(); ++gi) {
1375 if (child->
is_of_type(EggGroupNode::get_class_type())) {
1377 rename_primitives(group, name);
1379 }
else if (child->
is_of_type(EggPrimitive::get_class_type())) {
1380 child->set_name(name);
1394 int num_characters = _collection->get_num_characters();
1396 for (ci = 0; ci < num_characters; ++ci) {
1400 for (
int mn = 0; mn < num_models; ++mn) {
1402 if (root->
is_of_type(EggTable::get_class_type())) {
1405 string basename = data->get_egg_filename().get_basename_wo_extension();
1411 if (frame_rate != 0.0) {
1412 anim_preload->set_fps(frame_rate);
1415 anim_group->add_child(anim_preload);
1422 for (ci = 0; ci < num_characters; ++ci) {
1426 for (
int mn = 0; mn < num_models; ++mn) {
1428 if (root->
is_of_type(EggGroup::get_class_type())) {
1431 EggGroup::const_iterator ci;
1432 for (ci = anim_group->begin(); ci != anim_group->end(); ++ci) {
1435 model_root->
add_child(new_anim_preload);
1449 size_t comma = _defpose.find(
',');
1450 egg_filename = _defpose.substr(0, comma);
1453 if (comma != string::npos) {
1454 frame_str = _defpose.substr(comma + 1);
1456 frame_str =
trim(frame_str);
1458 if (!frame_str.empty()) {
1460 nout <<
"Invalid integer in -defpose: " << frame_str <<
"\n";
1467 int num_eggs = _collection->get_num_eggs();
1471 for (i = 0; i < num_eggs && egg_index == -1; ++i) {
1472 if (_collection->get_egg(i)->get_egg_filename() == egg_filename) {
1479 for (i = 0; i < num_eggs && egg_index == -1; ++i) {
1480 if (_collection->get_egg(i)->get_egg_filename().get_basename_wo_extension() == egg_basename) {
1485 if (egg_index == -1) {
1487 nout <<
"Egg file " << egg_filename <<
" named in -defpose, but does not appear on command line.\n";
1491 EggData *egg_data = _collection->get_egg(egg_index);
1493 if (_collection->get_num_models(egg_index) == 0) {
1494 nout <<
"Egg file " << egg_filename <<
" does not include any model or animation.\n";
1499 int mi = _collection->get_first_model_index(egg_index);
1503 int anim_index = -1;
1511 nassertv(anim_index != -1);
1517 int main(
int argc,
char *argv[]) {