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[]) {
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggJointData * get_root_joint() const
Returns the root joint of the character hierarchy.
int get_num_frames(int model_index) const
Returns the number of frames of animation of the indicated model.
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_...
int get_num_models() const
Returns the maximum number of back pointers this component may have.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
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...
This is a base class for EggJointNodePointer and EggMatrixTablePointer.
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,...
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.
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...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void adjust_transform(LMatrix4d &mat) const
Adjust the transform extracted from the "top" joint according to the -s and -i/-n options,...
A base class for things that may be directly added into the egg hierarchy.
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 is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
bool do_rebuild_all(EggCharacterDb &db)
Calls do_rebuild() on all models, and recursively on all joints at this node and below.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
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.
int get_model_index(int n) const
Returns the model_index of the nth model associated with this character.