mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
add -zero, etc.
This commit is contained in:
parent
c37f62fd9a
commit
6b7baa43d7
@ -30,6 +30,7 @@
|
||||
#include "string_utils.h"
|
||||
#include "dcast.h"
|
||||
#include "pset.h"
|
||||
#include "compose_matrix.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -76,6 +77,14 @@ EggOptchar() {
|
||||
"and objects can be parented to it. This implies -keep.",
|
||||
&EggOptchar::dispatch_vector_string_comma, NULL, &_expose_components);
|
||||
|
||||
add_option
|
||||
("zero", "joint[,hprxyzijk]", 0,
|
||||
"Zeroes out the animation channels for the named joint. If "
|
||||
"a subset of the component letters hprxyzijk is included, the "
|
||||
"operation is restricted to just those components; otherwise the "
|
||||
"entire transform is cleared.",
|
||||
&EggOptchar::dispatch_name_components, NULL, &_zero_channels);
|
||||
|
||||
add_option
|
||||
("keepall", "", 0,
|
||||
"Keep all joints and sliders in the character.",
|
||||
@ -117,6 +126,10 @@ run() {
|
||||
do_reparent();
|
||||
}
|
||||
|
||||
if (!_zero_channels.empty()) {
|
||||
zero_channels();
|
||||
}
|
||||
|
||||
int num_characters = _collection->get_num_characters();
|
||||
int ci;
|
||||
|
||||
@ -150,6 +163,7 @@ run() {
|
||||
// The meat of the program: determine which joints are to be
|
||||
// removed, and then actually remove them.
|
||||
determine_removed_components();
|
||||
move_vertices();
|
||||
if (process_joints()) {
|
||||
do_reparent();
|
||||
}
|
||||
@ -215,6 +229,55 @@ dispatch_vector_string_pair(const string &opt, const string &arg, void *var) {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ProgramBase::dispatch_name_components
|
||||
// Access: Protected, Static
|
||||
// Description: Accepts a name optionally followed by a comma and some
|
||||
// of the nine standard component letters,
|
||||
//
|
||||
// The data pointer is to StringPairs vector; the pair
|
||||
// will be pushed onto the end of the vector.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggOptchar::
|
||||
dispatch_name_components(const string &opt, const string &arg, void *var) {
|
||||
StringPairs *ip = (StringPairs *)var;
|
||||
|
||||
vector_string words;
|
||||
tokenize(arg, words, ",");
|
||||
|
||||
StringPair sp;
|
||||
if (words.size() == 1) {
|
||||
sp._a = words[0];
|
||||
|
||||
} else if (words.size() == 2) {
|
||||
sp._a = words[0];
|
||||
sp._b = words[1];
|
||||
|
||||
} else {
|
||||
nout << "-" << opt
|
||||
<< " requires a pair of strings separated by a comma.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sp._b.empty()) {
|
||||
sp._b = matrix_components;
|
||||
} else {
|
||||
for (string::const_iterator si = sp._b.begin(); si != sp._b.end(); ++si) {
|
||||
if (strchr(matrix_components, *si) == NULL) {
|
||||
nout << "Not a standard matrix component: \"" << *si << "\"\n"
|
||||
<< "-" << opt << " requires a joint name followed by a set "
|
||||
<< "of component names. The standard component names are \""
|
||||
<< matrix_components << "\".\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ip->push_back(sp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggOptchar::determine_removed_components
|
||||
// Access: Private
|
||||
@ -284,6 +347,43 @@ determine_removed_components() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggOptchar::move_vertices
|
||||
// Access: Private
|
||||
// Description: Moves the vertices from joints that are about to be
|
||||
// removed into the first suitable parent. This might
|
||||
// result in fewer joints being removed (because
|
||||
// the parent might suddenly no longer be empty).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggOptchar::
|
||||
move_vertices() {
|
||||
int num_characters = _collection->get_num_characters();
|
||||
for (int ci = 0; ci < num_characters; ci++) {
|
||||
EggCharacterData *char_data = _collection->get_character(ci);
|
||||
int num_joints = char_data->get_num_joints();
|
||||
|
||||
for (int i = 0; i < num_joints; i++) {
|
||||
EggJointData *joint_data = char_data->get_joint(i);
|
||||
EggOptcharUserData *user_data =
|
||||
DCAST(EggOptcharUserData, joint_data->get_user_data());
|
||||
|
||||
if ((user_data->_flags & EggOptcharUserData::F_empty) == 0 &&
|
||||
(user_data->_flags & EggOptcharUserData::F_remove) != 0) {
|
||||
// This joint has vertices, but is scheduled to be removed;
|
||||
// find a suitable home for its vertices.
|
||||
EggJointData *best_joint = find_best_vertex_joint(joint_data->get_parent());
|
||||
joint_data->move_vertices_to(best_joint);
|
||||
|
||||
// Now we can't remove the joint.
|
||||
EggOptcharUserData *best_user_data =
|
||||
DCAST(EggOptcharUserData, best_joint->get_user_data());
|
||||
best_user_data->_flags &= ~(EggOptcharUserData::F_empty | EggOptcharUserData::F_remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggOptchar::process_joints
|
||||
// Access: Private
|
||||
@ -310,16 +410,10 @@ process_joints() {
|
||||
EggOptcharUserData *user_data =
|
||||
DCAST(EggOptcharUserData, joint_data->get_user_data());
|
||||
|
||||
EggJointData *best_parent = find_best_parent(joint_data->get_parent());
|
||||
|
||||
if ((user_data->_flags & EggOptcharUserData::F_remove) != 0) {
|
||||
// This joint will be removed, so reparent it to nothing.
|
||||
joint_data->reparent_to((EggJointData *)NULL);
|
||||
|
||||
// Move the vertices associated with this joint into its
|
||||
// parent.
|
||||
joint_data->move_vertices_to(best_parent);
|
||||
|
||||
// Determine what kind of node it is we're removing, for the
|
||||
// user's information.
|
||||
if ((user_data->_flags & EggOptcharUserData::F_identity) != 0) {
|
||||
@ -334,6 +428,7 @@ process_joints() {
|
||||
} else {
|
||||
// This joint will be preserved, but maybe its parent will
|
||||
// change.
|
||||
EggJointData *best_parent = find_best_parent(joint_data->get_parent());
|
||||
joint_data->reparent_to(best_parent);
|
||||
if ((user_data->_flags & EggOptcharUserData::F_expose) != 0) {
|
||||
joint_data->expose();
|
||||
@ -348,7 +443,7 @@ process_joints() {
|
||||
} else {
|
||||
nout << char_data->get_name() << ": of " << num_joints
|
||||
<< " joints, removing " << num_identity << " identity, "
|
||||
<< num_static << " static, and " << num_empty
|
||||
<< num_static << " unanimated, and " << num_empty
|
||||
<< " empty joints, leaving " << num_kept << ".\n";
|
||||
}
|
||||
}
|
||||
@ -359,7 +454,7 @@ process_joints() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggOptchar::find_best_parent
|
||||
// Access: Private
|
||||
// Description: Searches for this first joint at this level or above
|
||||
// Description: Searches for the first joint at this level or above
|
||||
// that is not scheduled to be removed. This is the
|
||||
// joint that the first child of this joint should be
|
||||
// reparented to.
|
||||
@ -371,9 +466,33 @@ find_best_parent(EggJointData *joint_data) const {
|
||||
|
||||
if ((user_data->_flags & EggOptcharUserData::F_remove) != 0) {
|
||||
// Keep going.
|
||||
nassertr(joint_data->get_parent() != (EggJointData *)NULL, NULL);
|
||||
if (joint_data->get_parent() != (EggJointData *)NULL) {
|
||||
return find_best_parent(joint_data->get_parent());
|
||||
}
|
||||
}
|
||||
|
||||
// This is the one!
|
||||
return joint_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggOptchar::find_best_vertex_joint
|
||||
// Access: Private
|
||||
// Description: Searches for the first joint at this level or above
|
||||
// that is not static. This is the joint that the
|
||||
// vertices of this joint should be moved into.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EggJointData *EggOptchar::
|
||||
find_best_vertex_joint(EggJointData *joint_data) const {
|
||||
EggOptcharUserData *user_data =
|
||||
DCAST(EggOptcharUserData, joint_data->get_user_data());
|
||||
|
||||
if ((user_data->_flags & EggOptcharUserData::F_static) != 0) {
|
||||
// Keep going.
|
||||
if (joint_data->get_parent() != (EggJointData *)NULL) {
|
||||
return find_best_vertex_joint(joint_data->get_parent());
|
||||
}
|
||||
}
|
||||
|
||||
// This is the one!
|
||||
return joint_data;
|
||||
@ -419,6 +538,41 @@ apply_user_reparents() {
|
||||
return did_anything;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggOptchar::zero_channels
|
||||
// Access: Private
|
||||
// Description: Zeroes out the channels specified by the user on the
|
||||
// command line.
|
||||
//
|
||||
// Returns true if any operation was performed, false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggOptchar::
|
||||
zero_channels() {
|
||||
bool did_anything = false;
|
||||
int num_characters = _collection->get_num_characters();
|
||||
|
||||
StringPairs::const_iterator spi;
|
||||
for (spi = _zero_channels.begin(); spi != _zero_channels.end(); ++spi) {
|
||||
const StringPair &p = (*spi);
|
||||
|
||||
for (int ci = 0; ci < num_characters; ci++) {
|
||||
EggCharacterData *char_data = _collection->get_character(ci);
|
||||
EggJointData *joint_data = char_data->find_joint(p._a);
|
||||
|
||||
if (joint_data == (EggJointData *)NULL) {
|
||||
nout << "No joint named " << p._a << " in " << char_data->get_name()
|
||||
<< ".\n";
|
||||
} else {
|
||||
joint_data->zero_channels(p._b);
|
||||
did_anything = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return did_anything;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggOptchar::analyze_joints
|
||||
// Access: Private
|
||||
@ -458,7 +612,7 @@ analyze_joints(EggJointData *joint_data) {
|
||||
|
||||
} else {
|
||||
// This is a second or later matrix.
|
||||
if (!mat.almost_equal(user_data->_static_mat)) {
|
||||
if (!mat.almost_equal(user_data->_static_mat, 0.0001)) {
|
||||
// It's different than the first one.
|
||||
different_mat = true;
|
||||
}
|
||||
@ -472,7 +626,7 @@ analyze_joints(EggJointData *joint_data) {
|
||||
user_data->_flags |= EggOptcharUserData::F_static;
|
||||
|
||||
if (num_mats == 0 ||
|
||||
user_data->_static_mat.almost_equal(LMatrix4d::ident_mat())) {
|
||||
user_data->_static_mat.almost_equal(LMatrix4d::ident_mat(), 0.0001)) {
|
||||
// It's not only static, but it's the identity matrix.
|
||||
user_data->_flags |= EggOptcharUserData::F_identity;
|
||||
}
|
||||
@ -531,7 +685,7 @@ analyze_sliders(EggCharacterData *char_data) {
|
||||
|
||||
} else {
|
||||
// This is a second or later value.
|
||||
if (!IS_NEARLY_EQUAL(value, user_data->_static_value)) {
|
||||
if (!IS_THRESHOLD_EQUAL(value, user_data->_static_value, 0.0001)) {
|
||||
// It's different than the first one.
|
||||
different_value = true;
|
||||
}
|
||||
@ -544,7 +698,7 @@ analyze_sliders(EggCharacterData *char_data) {
|
||||
// All the values are the same for this slider.
|
||||
user_data->_flags |= EggOptcharUserData::F_static;
|
||||
|
||||
if (num_values == 0 || IS_NEARLY_EQUAL(user_data->_static_value, 0.0)) {
|
||||
if (num_values == 0 || IS_THRESHOLD_ZERO(user_data->_static_value, 0.0001)) {
|
||||
// It's not only static, but it's the identity value.
|
||||
user_data->_flags |= EggOptcharUserData::F_identity;
|
||||
}
|
||||
|
@ -51,12 +51,16 @@ protected:
|
||||
|
||||
private:
|
||||
static bool dispatch_vector_string_pair(const string &opt, const string &arg, void *var);
|
||||
static bool dispatch_name_components(const string &opt, const string &arg, void *var);
|
||||
|
||||
void determine_removed_components();
|
||||
void move_vertices();
|
||||
bool process_joints();
|
||||
EggJointData *find_best_parent(EggJointData *joint_data) const;
|
||||
EggJointData *find_best_vertex_joint(EggJointData *joint_data) const;
|
||||
|
||||
bool apply_user_reparents();
|
||||
bool zero_channels();
|
||||
void analyze_joints(EggJointData *joint_data);
|
||||
void analyze_sliders(EggCharacterData *char_data);
|
||||
void list_joints(EggJointData *joint_data, int indent_level);
|
||||
@ -80,6 +84,7 @@ private:
|
||||
};
|
||||
typedef pvector<StringPair> StringPairs;
|
||||
StringPairs _reparent_joints;
|
||||
StringPairs _zero_channels;
|
||||
|
||||
vector_string _keep_components;
|
||||
vector_string _expose_components;
|
||||
|
@ -175,8 +175,13 @@ do_reparent() {
|
||||
// hierarchy.
|
||||
if (joint_data->get_parent() != (EggJointData *)NULL) {
|
||||
nout << "Warning: reparenting " << joint_data->get_name()
|
||||
<< " to " << joint_data->get_parent()->get_name()
|
||||
<< " results in a skew transform.\n";
|
||||
<< " to ";
|
||||
if (joint_data->get_parent() == _root_joint) {
|
||||
nout << "the root";
|
||||
} else {
|
||||
nout << joint_data->get_parent()->get_name();
|
||||
}
|
||||
nout << " results in a skew transform.\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +224,31 @@ expose(EggGroup::DCSType dcs_type) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::zero_channels
|
||||
// Access: Public
|
||||
// Description: Calls zero_channels() on all models, and recursively on
|
||||
// all joints at this node and below.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggJointData::
|
||||
zero_channels(const string &components) {
|
||||
BackPointers::iterator bpi;
|
||||
for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) {
|
||||
EggBackPointer *back = (*bpi);
|
||||
if (back != (EggBackPointer *)NULL) {
|
||||
EggJointPointer *joint;
|
||||
DCAST_INTO_V(joint, back);
|
||||
joint->zero_channels(components);
|
||||
}
|
||||
}
|
||||
|
||||
Children::iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
EggJointData *child = (*ci);
|
||||
child->zero_channels(components);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::add_back_pointer
|
||||
// Access: Public, Virtual
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
bool do_rebuild();
|
||||
void optimize();
|
||||
void expose(EggGroup::DCSType dcs_type = EggGroup::DC_default);
|
||||
void zero_channels(const string &components);
|
||||
|
||||
virtual void add_back_pointer(int model_index, EggObject *egg_object);
|
||||
virtual void write(ostream &out, int indent_level = 0) const;
|
||||
|
@ -115,3 +115,13 @@ optimize() {
|
||||
void EggJointPointer::
|
||||
expose(EggGroup::DCSType) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::zero_channels
|
||||
// Access: Public, Virtual
|
||||
// Description: Zeroes out the named components of the transform in
|
||||
// the animation frames.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggJointPointer::
|
||||
zero_channels(const string &) {
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ public:
|
||||
|
||||
virtual void optimize();
|
||||
virtual void expose(EggGroup::DCSType dcs_type);
|
||||
virtual void zero_channels(const string &components);
|
||||
|
||||
protected:
|
||||
typedef pvector<LMatrix4d> RebuildFrames;
|
||||
|
@ -200,3 +200,27 @@ optimize() {
|
||||
_xform->optimize();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggMatrixTablePointer::zero_channels
|
||||
// Access: Public, Virtual
|
||||
// Description: Zeroes out the named components of the transform in
|
||||
// the animation frames.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggMatrixTablePointer::
|
||||
zero_channels(const string &components) {
|
||||
if (_xform == (EggXfmSAnim *)NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is particularly easy: we only have to remove children from
|
||||
// the _xform object whose name is listed in the components.
|
||||
string::const_iterator si;
|
||||
for (si = components.begin(); si != components.end(); ++si) {
|
||||
string table_name(1, *si);
|
||||
EggNode *child = _xform->find_child(table_name);
|
||||
if (child != (EggNode *)NULL) {
|
||||
_xform->remove_child(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
virtual bool do_rebuild();
|
||||
|
||||
virtual void optimize();
|
||||
virtual void zero_channels(const string &components);
|
||||
|
||||
private:
|
||||
PT(EggTable) _table;
|
||||
|
Loading…
x
Reference in New Issue
Block a user