30 add_path_replace_options();
31 add_path_store_options();
33 set_program_brief(
"unapplies animation from a joint in an .egg file");
34 set_program_description
35 (
"egg-topstrip reads a character model and its associated animation "
36 "files, and unapplies the animation from one of the top joints. "
37 "This effectively freezes that particular joint, and makes the rest "
38 "of the character relative to that joint.\n\n"
40 "This is a particularly useful thing to do to generate character "
41 "models that can stack one on top of the other in a sensible way.");
45 "Specify the name of the 'top' joint, from which to draw the "
46 "animation channels which will be applied to the entire animation.",
47 &EggTopstrip::dispatch_string,
nullptr, &_top_joint_name);
51 "Invert the matrix before applying. This causes a subtractive "
52 "effect. This is the default unless -r is specified.",
53 &EggTopstrip::dispatch_true, &_got_invert_transform, &_invert_transform);
57 "Do not invert the matrix before applying. This causes an "
59 &EggTopstrip::dispatch_false, &_got_invert_transform, &_invert_transform);
62 (
"s",
"[ijkphrxyz]", 0,
63 "Specify the components of the transform that are to be applied. Use "
64 "any combination of the nine token letters: i, j, k represent the "
65 "three scale axes; h, p, r represent rotation; and x, y, z represent "
66 "translation. The default is everything: -s ijkphrxyz.",
67 &EggTopstrip::dispatch_string,
nullptr, &_transform_channels);
71 "Read the animation channel from the indicated egg file. If this "
72 "is not specified, each egg file will supply its own animation channel.",
73 &EggTopstrip::dispatch_filename,
nullptr, &_channel_filename);
75 _invert_transform =
true;
76 _transform_channels =
"ijkphrxyz";
84 nassertv(_collection !=
nullptr);
85 nassertv(_collection->get_num_eggs() > 0);
91 int num_characters = _collection->get_num_characters();
97 if (!_channel_filename.empty()) {
99 PT(
EggData) channel_egg = read_egg(_channel_filename);
100 if (channel_egg ==
nullptr) {
101 nout <<
"Cannot read " << _channel_filename <<
"\n";
104 int channel_egg_index = _collection->add_egg(channel_egg);
105 if (channel_egg_index < 0) {
106 nout << _channel_filename
107 <<
" does not contain a character model or animation channel.\n";
111 from_model = _collection->get_first_model_index(channel_egg_index);
113 if (!_got_invert_transform) {
115 _invert_transform =
false;
123 for (ci = 0; ci < num_characters; ci++) {
125 nout <<
"Processing " << char_data->get_name() <<
"\n";
132 if (from_model != -1) {
133 from_char = _collection->get_character_by_model_index(from_model);
138 if (_top_joint_name.empty()) {
141 if (root_joint->get_num_children() == 0) {
142 nout <<
"Character " << from_char->get_name() <<
" has no joints.\n";
145 top_joint = root_joint->get_child(0);
147 top_joint = from_char->
find_joint(_top_joint_name);
148 if (top_joint ==
nullptr) {
149 nout <<
"Character " << from_char->get_name()
150 <<
" has no joint named " << _top_joint_name <<
"\n";
156 int num_children = root_joint->get_num_children();
157 for (
int i = 0; i < num_children; i++) {
159 strip_anim(char_data, joint_data, from_model, from_char, top_joint, db);
164 for (
int m = 0; m < num_models; m++) {
166 if (!node->
is_of_type(EggTable::get_class_type())) {
168 from_model, top_joint, db);
174 for (ci = 0; ci < num_characters; ci++) {
188 static std::string expected =
"ijkphrxyz";
189 static const int num_channels = 9;
190 bool has_each[num_channels];
191 memset(has_each, 0, num_channels *
sizeof(
bool));
193 for (
size_t p = 0; p < _transform_channels.size(); p++) {
194 int i = expected.find(_transform_channels[p]);
195 if (i == (
int)std::string::npos) {
196 nout <<
"Invalid letter for -s: " << _transform_channels[p] <<
"\n";
199 nassertv(i < num_channels);
203 _transform_channels =
"";
204 for (
int i = 0; i < num_channels; i++) {
206 _transform_channels += expected[i];
210 if (_transform_channels.empty()) {
211 nout <<
"No transform specified for -s.\n";
226 for (
int i = 0; i < num_models; i++) {
227 int model = (from_model < 0) ? i : from_model;
230 nout <<
"Warning: Joint " << top_joint->get_name()
231 <<
" is not defined in all models.\n";
238 int num_frames = std::max(num_into_frames, num_from_frames);
241 nassertv(back !=
nullptr);
243 DCAST_INTO_V(joint, back);
248 for (f = 0; f < num_frames; f++) {
249 LMatrix4d into = joint_data->
get_frame(i, f % num_into_frames);
250 LMatrix4d from = top_joint->
get_net_frame(model, f % num_from_frames, db);
254 db.
set_matrix(joint, EggCharacterDb::TT_rebuild_frame,
268 int model = (from_model < 0) ? into_model : from_model;
270 nout <<
"Warning: Joint " << top_joint->get_name()
271 <<
" is not defined in all models.\n";
288 if (_transform_channels.length() != 9) {
292 LVecBase3d scale, hpr, translate;
293 bool result = decompose_matrix(mat, scale, hpr, translate, _coordinate_system);
295 nout <<
"Warning: skew transform in animation.\n";
297 LVecBase3d new_scale(1.0, 1.0, 1.0);
298 LVecBase3d new_hpr(0.0, 0.0, 0.0);
299 LVecBase3d new_translate(0.0, 0.0, 0.0);
301 for (
size_t i = 0; i < _transform_channels.size(); i++) {
302 switch (_transform_channels[i]) {
304 new_scale[0] = scale[0];
307 new_scale[1] = scale[1];
310 new_scale[2] = scale[2];
324 new_translate[0] = translate[0];
327 new_translate[1] = translate[1];
330 new_translate[2] = translate[2];
335 compose_matrix(mat, new_scale, new_hpr, new_translate, _coordinate_system);
338 if (_invert_transform) {
339 mat.invert_in_place();
344 int main(
int argc,
char *argv[]) {