15 #include "eggTopstrip.h"
18 #include "eggJointData.h"
19 #include "eggCharacterCollection.h"
20 #include "eggCharacterData.h"
21 #include "eggCharacterDb.h"
22 #include "eggJointPointer.h"
24 #include "compose_matrix.h"
34 add_path_replace_options();
35 add_path_store_options();
37 set_program_brief(
"unapplies animation from a joint in an .egg file");
38 set_program_description
39 (
"egg-topstrip reads a character model and its associated animation "
40 "files, and unapplies the animation from one of the top joints. "
41 "This effectively freezes that particular joint, and makes the rest "
42 "of the character relative to that joint.\n\n"
44 "This is a particularly useful thing to do to generate character "
45 "models that can stack one on top of the other in a sensible way.");
49 "Specify the name of the 'top' joint, from which to draw the "
50 "animation channels which will be applied to the entire animation.",
51 &EggTopstrip::dispatch_string, NULL, &_top_joint_name);
55 "Invert the matrix before applying. This causes a subtractive "
56 "effect. This is the default unless -r is specified.",
57 &EggTopstrip::dispatch_true, &_got_invert_transform, &_invert_transform);
61 "Do not invert the matrix before applying. This causes an "
63 &EggTopstrip::dispatch_false, &_got_invert_transform, &_invert_transform);
66 (
"s",
"[ijkphrxyz]", 0,
67 "Specify the components of the transform that are to be applied. Use "
68 "any combination of the nine token letters: i, j, k represent the "
69 "three scale axes; h, p, r represent rotation; and x, y, z represent "
70 "translation. The default is everything: -s ijkphrxyz.",
71 &EggTopstrip::dispatch_string, NULL, &_transform_channels);
75 "Read the animation channel from the indicated egg file. If this "
76 "is not specified, each egg file will supply its own animation channel.",
77 &EggTopstrip::dispatch_filename, NULL, &_channel_filename);
79 _invert_transform =
true;
80 _transform_channels =
"ijkphrxyz";
91 nassertv(_collection->get_num_eggs() > 0);
97 int num_characters = _collection->get_num_characters();
103 if (!_channel_filename.empty()) {
106 PT(
EggData) channel_egg = read_egg(_channel_filename);
107 if (channel_egg == (
EggData *)NULL) {
108 nout <<
"Cannot read " << _channel_filename <<
"\n";
111 int channel_egg_index = _collection->add_egg(channel_egg);
112 if (channel_egg_index < 0) {
113 nout << _channel_filename
114 <<
" does not contain a character model or animation channel.\n";
118 from_model = _collection->get_first_model_index(channel_egg_index);
120 if (!_got_invert_transform) {
122 _invert_transform =
false;
130 for (ci = 0; ci < num_characters; ci++) {
132 nout <<
"Processing " << char_data->get_name() <<
"\n";
139 if (from_model != -1) {
140 from_char = _collection->get_character_by_model_index(from_model);
146 if (_top_joint_name.empty()) {
149 if (root_joint->get_num_children() == 0) {
150 nout <<
"Character " << from_char->get_name() <<
" has no joints.\n";
153 top_joint = root_joint->get_child(0);
155 top_joint = from_char->
find_joint(_top_joint_name);
157 nout <<
"Character " << from_char->get_name()
158 <<
" has no joint named " << _top_joint_name <<
"\n";
164 int num_children = root_joint->get_num_children();
165 for (
int i = 0; i < num_children; i++) {
167 strip_anim(char_data, joint_data, from_model, from_char, top_joint, db);
173 for (
int m = 0; m < num_models; m++) {
175 if (!node->
is_of_type(EggTable::get_class_type())) {
177 from_model, top_joint, db);
183 for (ci = 0; ci < num_characters; ci++) {
200 static string expected =
"ijkphrxyz";
201 static const int num_channels = 9;
202 bool has_each[num_channels];
203 memset(has_each, 0, num_channels *
sizeof(
bool));
205 for (
size_t p = 0; p < _transform_channels.size(); p++) {
206 int i = expected.find(_transform_channels[p]);
207 if (i == (
int)string::npos) {
208 nout <<
"Invalid letter for -s: " << _transform_channels[p] <<
"\n";
211 nassertv(i < num_channels);
215 _transform_channels =
"";
216 for (
int i = 0; i < num_channels; i++) {
218 _transform_channels += expected[i];
222 if (_transform_channels.empty()) {
223 nout <<
"No transform specified for -s.\n";
241 for (
int i = 0; i < num_models; i++) {
242 int model = (from_model < 0) ? i : from_model;
245 nout <<
"Warning: Joint " << top_joint->get_name()
246 <<
" is not defined in all models.\n";
253 int num_frames = max(num_into_frames, num_from_frames);
258 DCAST_INTO_V(joint, back);
263 for (f = 0; f < num_frames; f++) {
269 db.
set_matrix(joint, EggCharacterDb::TT_rebuild_frame,
285 int model = (from_model < 0) ? into_model : from_model;
287 nout <<
"Warning: Joint " << top_joint->get_name()
288 <<
" is not defined in all models.\n";
308 if (_transform_channels.length() != 9) {
313 bool result = decompose_matrix(mat, scale, hpr, translate, _coordinate_system);
315 nout <<
"Warning: skew transform in animation.\n";
321 for (
size_t i = 0; i < _transform_channels.size(); i++) {
322 switch (_transform_channels[i]) {
324 new_scale[0] = scale[0];
327 new_scale[1] = scale[1];
330 new_scale[2] = scale[2];
344 new_translate[0] = translate[0];
347 new_translate[1] = translate[1];
350 new_translate[2] = translate[2];
355 compose_matrix(mat, new_scale, new_hpr, new_translate, _coordinate_system);
358 if (_invert_transform) {
364 int main(
int argc,
char *argv[]) {
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...
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...
This is a 4-by-4 transform matrix.
int get_num_models() const
Returns the total number of models associated with this character.
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_...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
int get_num_models() const
Returns the maximum number of back pointers this component may have.
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...
EggNode * get_model_root(int n) const
Returns the model_root of the nth model associated with this character.
int get_model_index(int n) const
Returns the model_index of the nth model associated with this character.
void strip_anim_vertices(EggNode *egg_node, int into_model, int from_model, EggJointData *top_joint, EggCharacterDb &db)
Applies the channels from joint _top_joint in model from_model to the vertices at egg_node...
This class is used during joint optimization or restructuring to store the table of interim joint com...
EggJointData * get_root_joint() const
Returns the root joint of the character hierarchy.
bool invert_in_place()
Inverts the current matrix.
void set_matrix(const EggJointPointer *joint, TableType type, int frame, const LMatrix4d &mat)
Stores the matrix for the indicated joint, type, and frame in the database.
void transform_vertices_only(const LMatrix4d &mat)
Applies the indicated transformation only to vertices that appear in global space within vertex pools...
This is a base class for EggJointNodePointer and EggMatrixTablePointer.
Represents a set of characters, as read and collected from possibly several model and/or animation eg...
This is the base class for all three-component vectors and points.
void adjust_transform(LMatrix4d &mat) const
Adjust the transform extracted from the "top" joint according to the -s and -i/-n options...
Represents a single character, as read and collected from several models and animation files...
Reads a character model and/or animations and strips out the animation from one of the top joints fro...
void check_transform_channels()
Checks the _transform_channels string to ensure that it contains only the expected nine letters...
This is one node of a hierarchy of EggJointData nodes, each of which represents a single joint of the...
A base class for things that may be directly added into the egg hierarchy.
LMatrix4d get_net_frame(int model_index, int n, EggCharacterDb &db) const
Returns the complete transform from the root corresponding to this joint position in the nth frame in...
bool do_rebuild_all(EggCharacterDb &db)
Calls do_rebuild() on all models, and recursively on all joints at this node and below.
int get_num_frames(int model_index) const
Returns the number of frames of animation of the indicated model.
This stores a pointer from an EggJointData or EggSliderData object back to the referencing data in an...
EggJointData * find_joint(const string &name) const
Returns the first joint found with the indicated name, or NULL if no joint has that name...
void strip_anim(EggCharacterData *char_data, EggJointData *joint_data, int from_model, EggCharacterData *from_char, EggJointData *top_joint, EggCharacterDb &db)
Applies the channels from joint _top_joint in model from_model to the joint referenced by joint_data...