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[]) {
int string_to_int(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
void reparent_to(EggJointData *new_parent)
Indicates an intention to change the parent of this joint to the indicated joint, or NULL to remove i...
GroupRef::size_type gref_size() const
Returns the number of elements between gref_begin() and gref_end().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static DartType string_dart_type(const std::string &strval)
Returns the DartType value associated with the given string representation, or DT_none if the string ...
int get_num_frames(int model_index) const
Returns the number of frames of animation for this particular component in the indicated model.
GroupRef::const_iterator gref_end() const
Returns an iterator that can, in conjunction with gref_begin(), be used to traverse the entire set of...
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_num_joints() const
Returns the total number of joints in the character joint hierarchy.
double string_to_double(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
EggJointData * get_root_joint() const
Returns the root joint of the character hierarchy.
bool do_reparent()
Begins the process of restructuring the joint hierarchy according to the previous calls to reparent_t...
int get_num_frames(int model_index) const
Returns the number of frames of animation of the indicated model.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
A base class for nodes in the hierarchy that are not leaf nodes.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
void add_normals_options()
Adds -no, -np, etc.
int get_num_models() const
Returns the maximum number of back pointers this component may have.
virtual void set_name(const std::string &name)
Applies the indicated name change to the egg file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GroupRef::const_iterator gref_begin() const
Returns an iterator that can, in conjunction with gref_end(), be used to traverse the entire set of g...
This corresponds to a single morph slider control.
int get_num_models() const
Returns the total number of models associated with this character.
EggBackPointer * get_model(int model_index) const
Returns the back pointer to an egg file for the indicated model if it exists, or NULL if it does not.
This is the primary interface into all the egg data, and the root of the egg file structure.
EggJointData * make_new_joint(const std::string &name, EggJointData *parent)
Creates a new joint as a child of the indicated joint and returns it.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
iterator end() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
EggData * get_egg_data(int n) const
Returns the EggData representing the egg file that defined this particular model.
This is the base class of both EggJointData and EggSliderData.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool has_vertices() const
Returns true if there are any vertices referenced by the node this points to, false otherwise.
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 our own Panda specialization on the default STL vector.
iterator begin() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
void apply_default_pose(int source_model, int frame)
Applies the pose from the indicated frame of the indicated source model_index as the initial pose for...
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
The name of a file, such as a texture file or an Egg file.
This corresponds to an <AnimPreload> entry.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggSliderData * get_slider(int n) const
Returns the nth slider in the character slider list.
Performs basic optimizations of a character model and its associated animations, by analyzing the ani...
EggComponentData * get_component(int n) const
Returns the nth joint or slider in the character.
EggUserData * get_user_data() const
Returns the user data pointer most recently stored on this object, or NULL if nothing was previously ...
void move_vertices_to(EggJointData *new_owner)
Moves the vertices assigned to this joint into the indicated joint, without changing their weight ass...
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
This class contains extra user data which is piggybacked onto EggGroup objects for the purpose of the...
string trim(const string &str)
Returns a new string representing the contents of the given string with both leading and trailing whi...
bool has_model(int model_index) const
Returns true if the component has a back pointer to an egg file somewhere for the indicated model,...
int get_num_components() const
Returns the total number of joints and sliders in the character.
void choose_optimal_hierarchy()
Chooses the best possible parent joint for each of the joints in the hierarchy, based on the score co...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggNode * get_model_root(int n) const
Returns the model_root of the nth model associated with this character.
Represents a single character, as read and collected from several models and animation files.
This class is used to help EggOptchar quantize the membership of one vertex among its various groups.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_user_data(EggUserData *user_data)
Sets the user data associated with this object.
void tokenize(const string &str, vector_string &words, const string &delimiters, bool discard_repeated_delimiters)
Chops the source string up into pieces delimited by any of the characters specified in delimiters.
This is one node of a hierarchy of EggJointData nodes, each of which represents a single joint of the...
EggJointData * find_joint(const std::string &name) const
Returns the first joint found with the indicated name, or NULL if no joint has that name.
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
EggJointData * get_joint(int n) const
Returns the nth joint in the character joint hierarchy.
A base class for things that may be directly added into the egg hierarchy.
int get_num_sliders() const
Returns the number of sliders in the character slider list.
LMatrix4d get_frame(int model_index, int n) const
Returns the local transform matrix corresponding to this joint position in the nth frame in the indic...
void add_transform_options()
Adds -TS, -TT, etc.
void zero_channels(const std::string &components)
Calls zero_channels() on all models for this joint, but does not recurse downwards.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void quantize_channels(const std::string &components, double quantum)
Calls quantize_channels() on all models for this joint, and then recurses downwards to all joints bel...
double get_frame(int model_index, int n) const
Returns the value corresponding to this slider position in the nth frame in the indicated model.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
This is our own Panda specialization on the default STL set.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double get_frame_rate(int model_index) const
Returns the stated frame rate of the specified model.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This stores a pointer from an EggJointData or EggSliderData object back to the referencing data in an...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void expose(EggGroup::DCSType dcs_type=EggGroup::DC_default)
Calls expose() on all models for this joint, but does not recurse downwards.
A collection of vertices.
static bool is_compression_available()
Returns true if the FFTW library is compiled in, so that this class is actually capable of doing usef...
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
int get_model_index(int n) const
Returns the model_index of the nth model associated with this character.