mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
add -optimal to egg-optchar
This commit is contained in:
parent
89659d9e78
commit
0c2a4f1550
@ -32,6 +32,7 @@
|
||||
#include "dcast.h"
|
||||
#include "pset.h"
|
||||
#include "compose_matrix.h"
|
||||
#include "fftCompressor.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -119,6 +120,21 @@ EggOptchar() {
|
||||
"is not affected (the effect is similar to NodePath::wrt_reparent_to).",
|
||||
&EggOptchar::dispatch_vector_string_pair, NULL, &_reparent_joints);
|
||||
|
||||
if (FFTCompressor::is_compression_available()) {
|
||||
add_option
|
||||
("optimal", "", 0,
|
||||
"Computes the optimal joint hierarchy for the character by analyzing "
|
||||
"all of the joint animation and reparenting joints to minimize "
|
||||
"transformations. This can repair skeletons that have been flattened "
|
||||
"or whose hierarchy was otherwise damaged in conversion; it can also "
|
||||
"detect joints that are constrained to follow other joints and should "
|
||||
"therefore be parented to the master joints. The result is a file "
|
||||
"from which more joints may be successfully removed, that generally "
|
||||
"compresses better and with fewer artifacts. However, this is a "
|
||||
"fairly expensive operation.",
|
||||
&EggOptchar::dispatch_none, &_optimal_hierarchy);
|
||||
}
|
||||
|
||||
add_option
|
||||
("q", "quantum", 0,
|
||||
"Quantize joint membership values to the given unit. This is "
|
||||
@ -127,6 +143,7 @@ EggOptchar() {
|
||||
"values.",
|
||||
&EggOptchar::dispatch_double, NULL, &_vref_quantum);
|
||||
|
||||
_optimal_hierarchy = false;
|
||||
_vref_quantum = 0.01;
|
||||
}
|
||||
|
||||
@ -174,7 +191,8 @@ run() {
|
||||
for (ci = 0; ci < num_characters; ci++) {
|
||||
EggCharacterData *char_data = _collection->get_character(ci);
|
||||
nout << "Character: " << char_data->get_name() << "\n";
|
||||
list_joints_p(char_data->get_root_joint());
|
||||
int col = 0;
|
||||
list_joints_p(char_data->get_root_joint(), col);
|
||||
// A newline to cout is needed after the above call.
|
||||
cout << "\n";
|
||||
nout << char_data->get_num_joints() << " joints.\n";
|
||||
@ -390,10 +408,14 @@ determine_removed_components() {
|
||||
for (int ci = 0; ci < num_characters; ci++) {
|
||||
EggCharacterData *char_data = _collection->get_character(ci);
|
||||
int num_components = char_data->get_num_components();
|
||||
cerr << char_data->get_name() << " has " << num_components << " components.\n";
|
||||
for (int i = 0; i < num_components; i++) {
|
||||
EggComponentData *comp_data = char_data->get_component(i);
|
||||
nassertv(comp_data != (EggComponentData *)NULL);
|
||||
|
||||
EggOptcharUserData *user_data =
|
||||
DCAST(EggOptcharUserData, comp_data->get_user_data());
|
||||
nassertv(user_data != (EggOptcharUserData *)NULL);
|
||||
|
||||
const string &name = comp_data->get_name();
|
||||
if (_keep_all || keep_names.find(name) != keep_names.end()) {
|
||||
@ -469,9 +491,11 @@ move_vertices() {
|
||||
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);
|
||||
if (best_joint != (EggJointData *)NULL) {
|
||||
EggOptcharUserData *best_user_data =
|
||||
DCAST(EggOptcharUserData, best_joint->get_user_data());
|
||||
best_user_data->_flags &= ~(EggOptcharUserData::F_empty | EggOptcharUserData::F_remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -488,6 +512,7 @@ move_vertices() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggOptchar::
|
||||
process_joints() {
|
||||
cerr << "process_joints\n";
|
||||
bool removed_any = false;
|
||||
int num_characters = _collection->get_num_characters();
|
||||
for (int ci = 0; ci < num_characters; ci++) {
|
||||
@ -594,14 +619,16 @@ find_best_parent(EggJointData *joint_data) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EggJointData *EggOptchar::
|
||||
find_best_vertex_joint(EggJointData *joint_data) const {
|
||||
if (joint_data == (EggJointData *)NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
return find_best_vertex_joint(joint_data->get_parent());
|
||||
}
|
||||
|
||||
// This is the one!
|
||||
@ -618,6 +645,7 @@ find_best_vertex_joint(EggJointData *joint_data) const {
|
||||
bool EggOptchar::
|
||||
apply_user_reparents() {
|
||||
bool did_anything = false;
|
||||
|
||||
int num_characters = _collection->get_num_characters();
|
||||
|
||||
StringPairs::const_iterator spi;
|
||||
@ -645,6 +673,18 @@ apply_user_reparents() {
|
||||
}
|
||||
}
|
||||
|
||||
if (_optimal_hierarchy) {
|
||||
did_anything = true;
|
||||
for (int ci = 0; ci < num_characters; ci++) {
|
||||
EggCharacterData *char_data = _collection->get_character(ci);
|
||||
nout << "Computing optimal hierarchy for "
|
||||
<< char_data->get_name() << ".\n";
|
||||
char_data->choose_optimal_hierarchy();
|
||||
nout << "Done computing optimal hierarchy for "
|
||||
<< char_data->get_name() << ".\n";
|
||||
}
|
||||
}
|
||||
|
||||
return did_anything;
|
||||
}
|
||||
|
||||
@ -849,19 +889,34 @@ list_joints(EggJointData *joint_data, int indent_level, bool verbose) {
|
||||
// -p joint,parent commands.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggOptchar::
|
||||
list_joints_p(EggJointData *joint_data) {
|
||||
list_joints_p(EggJointData *joint_data, int &col) {
|
||||
// As above, don't list the root joint.
|
||||
|
||||
int num_children = joint_data->get_num_children();
|
||||
static const int max_col = 72;
|
||||
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
EggJointData *child_data = joint_data->get_child(i);
|
||||
// We send output to cout instead of nout to avoid the
|
||||
// word-wrapping, and also to allow the user to redirect this
|
||||
// easily to a file.
|
||||
cout << " -p " << child_data->get_name() << ","
|
||||
<< joint_data->get_name();
|
||||
|
||||
list_joints_p(child_data);
|
||||
string text = string(" -p ") + child_data->get_name() +
|
||||
string(",") + joint_data->get_name();
|
||||
if (col == 0) {
|
||||
cout << " " << text;
|
||||
col = 4 + text.length();
|
||||
} else {
|
||||
col += text.length();
|
||||
if (col >= max_col) {
|
||||
cout << " \\\n " << text;
|
||||
col = 4 + text.length();
|
||||
} else {
|
||||
cout << text;
|
||||
}
|
||||
}
|
||||
|
||||
list_joints_p(child_data, col);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ private:
|
||||
void analyze_joints(EggJointData *joint_data);
|
||||
void analyze_sliders(EggCharacterData *char_data);
|
||||
void list_joints(EggJointData *joint_data, int indent_level, bool verbose);
|
||||
void list_joints_p(EggJointData *joint_data);
|
||||
void list_joints_p(EggJointData *joint_data, int &col);
|
||||
void list_scalars(EggCharacterData *char_data, bool verbose);
|
||||
void describe_component(EggComponentData *comp_data, int indent_level,
|
||||
bool verbose);
|
||||
@ -108,6 +108,7 @@ private:
|
||||
typedef pvector<FlagGroupsEntry> FlagGroups;
|
||||
FlagGroups _flag_groups;
|
||||
|
||||
bool _optimal_hierarchy;
|
||||
double _vref_quantum;
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
eggbase progbase
|
||||
#define OTHER_LIBS \
|
||||
egg:c panda:m
|
||||
#define USE_PACKAGES zlib
|
||||
|
||||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx
|
||||
|
||||
|
@ -238,6 +238,61 @@ do_reparent() {
|
||||
return invalid_set.empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggCharacterData::choose_optimal_hierarchy
|
||||
// Access: Public
|
||||
// Description: Chooses the best possible parent joint for each of
|
||||
// the joints in the hierarchy, based on the score
|
||||
// computed by EggJointData::score_reparent_to(). This
|
||||
// is a fairly expensive operation that involves lots of
|
||||
// recomputing of transforms across the hierarchy.
|
||||
//
|
||||
// The joints are not actually reparented yet, but the
|
||||
// new_parent of each joint is set. Call do_reparent()
|
||||
// to actually perform the suggested reparenting
|
||||
// operation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggCharacterData::
|
||||
choose_optimal_hierarchy() {
|
||||
Joints::const_iterator ji, jj;
|
||||
for (ji = _joints.begin(); ji != _joints.end(); ++ji) {
|
||||
EggJointData *joint_data = (*ji);
|
||||
|
||||
EggJointData *best_parent = joint_data->get_parent();
|
||||
int best_score = joint_data->score_reparent_to(best_parent);
|
||||
|
||||
for (jj = _joints.begin(); jj != _joints.end(); ++jj) {
|
||||
EggJointData *possible_parent = (*jj);
|
||||
if (possible_parent != joint_data && possible_parent != best_parent &&
|
||||
!joint_data->is_new_ancestor(possible_parent)) {
|
||||
|
||||
int score = joint_data->score_reparent_to(possible_parent);
|
||||
if (score >= 0 && (best_score < 0 || score < best_score)) {
|
||||
best_parent = possible_parent;
|
||||
best_score = score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also consider reparenting the node to the root.
|
||||
EggJointData *possible_parent = get_root_joint();
|
||||
if (possible_parent != best_parent) {
|
||||
int score = joint_data->score_reparent_to(possible_parent);
|
||||
if (score >= 0 && (best_score < 0 || score < best_score)) {
|
||||
best_parent = possible_parent;
|
||||
best_score = score;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_parent != (EggJointData *)NULL &&
|
||||
best_parent != joint_data->_parent) {
|
||||
nout << "best parent for " << joint_data->get_name() << " is "
|
||||
<< best_parent->get_name() << "\n";
|
||||
joint_data->reparent_to(best_parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggCharacterData::find_slider
|
||||
// Access: Public
|
||||
|
@ -79,6 +79,7 @@ public:
|
||||
INLINE int get_num_joints() const;
|
||||
INLINE EggJointData *get_joint(int n) const;
|
||||
bool do_reparent();
|
||||
void choose_optimal_hierarchy();
|
||||
|
||||
INLINE int get_num_sliders() const;
|
||||
INLINE EggSliderData *get_slider(int n) const;
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "eggGroup.h"
|
||||
#include "eggTable.h"
|
||||
#include "indent.h"
|
||||
#include "fftCompressor.h"
|
||||
#include "zStream.h"
|
||||
|
||||
TypeHandle EggJointData::_type_handle;
|
||||
|
||||
@ -73,11 +75,61 @@ get_frame(int model_index, int n) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LMatrix4d EggJointData::
|
||||
get_net_frame(int model_index, int n) const {
|
||||
LMatrix4d mat = get_frame(model_index, n);
|
||||
if (_parent != (EggJointData *)NULL) {
|
||||
mat = mat * _parent->get_net_frame(model_index, n);
|
||||
EggBackPointer *back = get_model(model_index);
|
||||
if (back == (EggBackPointer *)NULL) {
|
||||
return LMatrix4d::ident_mat();
|
||||
}
|
||||
return mat;
|
||||
|
||||
EggJointPointer *joint;
|
||||
DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
|
||||
|
||||
if (joint->get_num_net_frames() < n) {
|
||||
// Recursively get the previous frame's net, so we have a place to
|
||||
// stuff this frame's value.
|
||||
get_net_frame(model_index, n - 1);
|
||||
}
|
||||
|
||||
if (joint->get_num_net_frames() == n) {
|
||||
// Compute this frame's net, and stuff it in.
|
||||
LMatrix4d mat = get_frame(model_index, n);
|
||||
if (_parent != (EggJointData *)NULL) {
|
||||
mat = mat * _parent->get_net_frame(model_index, n);
|
||||
}
|
||||
joint->add_net_frame(mat);
|
||||
}
|
||||
|
||||
return joint->get_net_frame(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::get_net_frame_inv
|
||||
// Access: Public
|
||||
// Description: Returns the inverse of get_net_frame().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LMatrix4d EggJointData::
|
||||
get_net_frame_inv(int model_index, int n) const {
|
||||
EggBackPointer *back = get_model(model_index);
|
||||
if (back == (EggBackPointer *)NULL) {
|
||||
return LMatrix4d::ident_mat();
|
||||
}
|
||||
|
||||
EggJointPointer *joint;
|
||||
DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
|
||||
|
||||
if (joint->get_num_net_frame_invs() < n) {
|
||||
// Recursively get the previous frame's net, so we have a place to
|
||||
// stuff this frame's value.
|
||||
get_net_frame_inv(model_index, n - 1);
|
||||
}
|
||||
|
||||
if (joint->get_num_net_frame_invs() == n) {
|
||||
// Compute this frame's net inverse, and stuff it in.
|
||||
LMatrix4d mat = get_net_frame(model_index, n);
|
||||
mat.invert_in_place();
|
||||
joint->add_net_frame_inv(mat);
|
||||
}
|
||||
|
||||
return joint->get_net_frame_inv(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -117,16 +169,140 @@ force_initial_rest_frame() {
|
||||
void EggJointData::
|
||||
move_vertices_to(EggJointData *new_owner) {
|
||||
int num_models = get_num_models();
|
||||
for (int model_index = 0; model_index < num_models; model_index++) {
|
||||
if (has_model(model_index) && new_owner->has_model(model_index)) {
|
||||
EggJointPointer *joint, *new_joint;
|
||||
DCAST_INTO_V(joint, get_model(model_index));
|
||||
DCAST_INTO_V(new_joint, new_owner->get_model(model_index));
|
||||
joint->move_vertices_to(new_joint);
|
||||
|
||||
if (new_owner == (EggJointData *)NULL) {
|
||||
for (int model_index = 0; model_index < num_models; model_index++) {
|
||||
if (has_model(model_index)) {
|
||||
EggJointPointer *joint;
|
||||
DCAST_INTO_V(joint, get_model(model_index));
|
||||
joint->move_vertices_to((EggJointPointer *)NULL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int model_index = 0; model_index < num_models; model_index++) {
|
||||
if (has_model(model_index) && new_owner->has_model(model_index)) {
|
||||
EggJointPointer *joint, *new_joint;
|
||||
DCAST_INTO_V(joint, get_model(model_index));
|
||||
DCAST_INTO_V(new_joint, new_owner->get_model(model_index));
|
||||
joint->move_vertices_to(new_joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::score_reparent
|
||||
// Access: Public
|
||||
// Description: Computes a score >= 0 reflecting the similarity of
|
||||
// the current joint's animation (in world space) to
|
||||
// that of the indicated potential parent joint (in
|
||||
// world space). The lower the number, the more similar
|
||||
// the motion, and the more suitable is the proposed
|
||||
// parent-child relationship. Returns -1 if there is an
|
||||
// error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int EggJointData::
|
||||
score_reparent_to(EggJointData *new_parent) {
|
||||
if (!FFTCompressor::is_compression_available()) {
|
||||
// If we don't have compression compiled in, we can't meaningfully
|
||||
// score the joints.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// First, build up a big array of the new transforms this joint
|
||||
// would receive in all frames of all models, were it reparented to
|
||||
// the indicated joint.
|
||||
vector_float i, j, k, a, b, c, x, y, z;
|
||||
vector_LVecBase3f hprs;
|
||||
int num_rows = 0;
|
||||
|
||||
int num_models = get_num_models();
|
||||
for (int model_index = 0; model_index < num_models; model_index++) {
|
||||
EggBackPointer *back = get_model(model_index);
|
||||
if (back != (EggBackPointer *)NULL) {
|
||||
EggJointPointer *joint;
|
||||
DCAST_INTO_R(joint, back, false);
|
||||
|
||||
int num_frames = get_num_frames(model_index);
|
||||
for (int n = 0; n < num_frames; n++) {
|
||||
LMatrix4d transform;
|
||||
if (_parent == new_parent) {
|
||||
// We already have this parent.
|
||||
transform = LMatrix4d::ident_mat();
|
||||
|
||||
} else if (_parent == (EggJointData *)NULL) {
|
||||
// We are moving from outside the joint hierarchy to within it.
|
||||
transform = new_parent->get_net_frame_inv(model_index, n);
|
||||
|
||||
} else if (new_parent == (EggJointData *)NULL) {
|
||||
// We are moving from within the hierarchy to outside it.
|
||||
transform = _parent->get_net_frame(model_index, n);
|
||||
|
||||
} else {
|
||||
// We are changing parents within the hierarchy.
|
||||
transform =
|
||||
_parent->get_net_frame(model_index, n) *
|
||||
new_parent->get_net_frame_inv(model_index, n);
|
||||
}
|
||||
|
||||
transform = joint->get_frame(n) * transform;
|
||||
LVecBase3d scale, shear, hpr, translate;
|
||||
if (!decompose_matrix(transform, scale, shear, hpr, translate)) {
|
||||
// Invalid transform.
|
||||
return -1;
|
||||
}
|
||||
i.push_back(scale[0]);
|
||||
j.push_back(scale[1]);
|
||||
k.push_back(scale[2]);
|
||||
a.push_back(shear[0]);
|
||||
b.push_back(shear[1]);
|
||||
c.push_back(shear[2]);
|
||||
hprs.push_back(LCAST(float, hpr));
|
||||
x.push_back(translate[0]);
|
||||
y.push_back(translate[1]);
|
||||
z.push_back(translate[2]);
|
||||
num_rows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_rows == 0) {
|
||||
// No data, no score.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Now, we derive a score, by the simple expedient of using the
|
||||
// FFTCompressor to compress the generated transforms, and measuring
|
||||
// the length of the resulting bitstream.
|
||||
FFTCompressor compressor;
|
||||
Datagram dg;
|
||||
compressor.write_reals(dg, &i[0], num_rows);
|
||||
compressor.write_reals(dg, &j[0], num_rows);
|
||||
compressor.write_reals(dg, &k[0], num_rows);
|
||||
compressor.write_reals(dg, &a[0], num_rows);
|
||||
compressor.write_reals(dg, &b[0], num_rows);
|
||||
compressor.write_reals(dg, &c[0], num_rows);
|
||||
compressor.write_hprs(dg, &hprs[0], num_rows);
|
||||
compressor.write_reals(dg, &x[0], num_rows);
|
||||
compressor.write_reals(dg, &y[0], num_rows);
|
||||
compressor.write_reals(dg, &z[0], num_rows);
|
||||
|
||||
|
||||
#ifndef HAVE_ZLIB
|
||||
return dg.get_length();
|
||||
|
||||
#else
|
||||
// The FFTCompressor does minimal run-length encoding, but to really
|
||||
// get an accurate measure we should zlib-compress the resulting
|
||||
// stream.
|
||||
ostringstream sstr;
|
||||
OCompressStream zstr(&sstr, false);
|
||||
zstr.write((const char *)dg.get_data(), dg.get_length());
|
||||
zstr.flush();
|
||||
return sstr.str().length();
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::do_rebuild
|
||||
// Access: Public
|
||||
@ -363,12 +539,12 @@ do_compute_reparent(int model_index, int n) {
|
||||
|
||||
} else if (_new_parent == (EggJointData *)NULL) {
|
||||
// We are moving from within the hierarchy to outside it.
|
||||
transform = _parent->get_new_net_frame(model_index, n);
|
||||
transform = _parent->get_net_frame(model_index, n);
|
||||
|
||||
} else {
|
||||
// We are changing parents within the hierarchy.
|
||||
transform =
|
||||
_parent->get_new_net_frame(model_index, n) *
|
||||
_parent->get_net_frame(model_index, n) *
|
||||
_new_parent->get_new_net_frame_inv(model_index, n);
|
||||
}
|
||||
|
||||
@ -401,6 +577,7 @@ do_finish_reparent() {
|
||||
EggJointPointer *joint;
|
||||
DCAST_INTO_R(joint, get_model(model_index), false);
|
||||
joint->do_finish_reparent(parent_joint);
|
||||
joint->clear_net_frames();
|
||||
if (!joint->do_rebuild()) {
|
||||
all_ok = false;
|
||||
}
|
||||
@ -462,6 +639,27 @@ find_joint_matches(const string &name) {
|
||||
return (EggJointData *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::is_new_ancestor
|
||||
// Access: Protected
|
||||
// Description: Returns true if this joint is an ancestor of the
|
||||
// indicated joint, in the "new" hierarchy (that is, the
|
||||
// one defined by _new_parent, as set by reparent_to()
|
||||
// before do_finish_reparent() is called).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggJointData::
|
||||
is_new_ancestor(EggJointData *child) const {
|
||||
if (child == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (child->_new_parent == (EggJointData *)NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_new_ancestor(child->_new_parent);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::get_new_net_frame
|
||||
// Access: Private
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
|
||||
LMatrix4d get_frame(int model_index, int n) const;
|
||||
LMatrix4d get_net_frame(int model_index, int n) const;
|
||||
LMatrix4d get_net_frame_inv(int model_index, int n) const;
|
||||
|
||||
INLINE bool has_rest_frame() const;
|
||||
INLINE bool rest_frames_differ() const;
|
||||
@ -53,6 +54,7 @@ public:
|
||||
|
||||
INLINE void reparent_to(EggJointData *new_parent);
|
||||
void move_vertices_to(EggJointData *new_owner);
|
||||
int score_reparent_to(EggJointData *new_parent);
|
||||
|
||||
bool do_rebuild();
|
||||
void optimize();
|
||||
@ -72,6 +74,7 @@ private:
|
||||
EggJointData *find_joint_exact(const string &name);
|
||||
EggJointData *find_joint_matches(const string &name);
|
||||
|
||||
bool is_new_ancestor(EggJointData *child) const;
|
||||
const LMatrix4d &get_new_net_frame(int model_index, int n);
|
||||
const LMatrix4d &get_new_net_frame_inv(int model_index, int n);
|
||||
LMatrix4d get_new_frame(int model_index, int n);
|
||||
|
@ -128,10 +128,15 @@ do_finish_reparent(EggJointPointer *new_parent) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggJointNodePointer::
|
||||
move_vertices_to(EggJointPointer *new_joint) {
|
||||
EggJointNodePointer *new_node;
|
||||
DCAST_INTO_V(new_node, new_joint);
|
||||
if (new_joint == (EggJointPointer *)NULL) {
|
||||
_joint->unref_all_vertices();
|
||||
|
||||
new_node->_joint->steal_vrefs(_joint);
|
||||
} else {
|
||||
EggJointNodePointer *new_node;
|
||||
DCAST_INTO_V(new_node, new_joint);
|
||||
|
||||
new_node->_joint->steal_vrefs(_joint);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -39,3 +39,93 @@ get_rebuild_frame(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_rebuild_frames.size(), LMatrix4d::ident_mat());
|
||||
return _rebuild_frames[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::clear_net_frames
|
||||
// Access: Public
|
||||
// Description: Resets the cache of net frames for this joint.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggJointPointer::
|
||||
clear_net_frames() {
|
||||
_net_frames.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::add_net_frame
|
||||
// Access: Public, Virtual
|
||||
// Description: Adds a new frame to the set of net frames. This is
|
||||
// used to cache the net transform from the root for
|
||||
// this particular joint.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggJointPointer::
|
||||
add_net_frame(const LMatrix4d &mat) {
|
||||
_net_frames.push_back(mat);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::get_num_net_frames
|
||||
// Access: Public
|
||||
// Description: Returns the number of net frames that have been
|
||||
// added so far.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int EggJointPointer::
|
||||
get_num_net_frames() const {
|
||||
return _net_frames.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::get_net_frame
|
||||
// Access: Public
|
||||
// Description: Returns the nth matrix that has been added to the set
|
||||
// of net frames.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LMatrix4d &EggJointPointer::
|
||||
get_net_frame(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_net_frames.size(), LMatrix4d::ident_mat());
|
||||
return _net_frames[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::clear_net_frame_invs
|
||||
// Access: Public
|
||||
// Description: Resets the cache of net_inv frames for this joint.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggJointPointer::
|
||||
clear_net_frame_invs() {
|
||||
_net_frame_invs.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::add_net_frame_inv
|
||||
// Access: Public, Virtual
|
||||
// Description: Adds a new frame to the set of net_inv frames. This is
|
||||
// used to cache the inverse net transform from the root
|
||||
// for this particular joint.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggJointPointer::
|
||||
add_net_frame_inv(const LMatrix4d &mat) {
|
||||
_net_frame_invs.push_back(mat);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::get_num_net_frame_invs
|
||||
// Access: Public
|
||||
// Description: Returns the number of net_inv frames that have been
|
||||
// added so far.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int EggJointPointer::
|
||||
get_num_net_frame_invs() const {
|
||||
return _net_frame_invs.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointPointer::get_net_frame_inv
|
||||
// Access: Public
|
||||
// Description: Returns the nth matrix that has been added to the set
|
||||
// of net_inv frames.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LMatrix4d &EggJointPointer::
|
||||
get_net_frame_inv(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_net_frame_invs.size(), LMatrix4d::ident_mat());
|
||||
return _net_frame_invs[n];
|
||||
}
|
||||
|
@ -50,6 +50,16 @@ public:
|
||||
INLINE const LMatrix4d &get_rebuild_frame(int n) const;
|
||||
virtual bool do_rebuild();
|
||||
|
||||
INLINE void clear_net_frames();
|
||||
INLINE void add_net_frame(const LMatrix4d &mat);
|
||||
INLINE int get_num_net_frames() const;
|
||||
INLINE const LMatrix4d &get_net_frame(int n) const;
|
||||
|
||||
INLINE void clear_net_frame_invs();
|
||||
INLINE void add_net_frame_inv(const LMatrix4d &mat);
|
||||
INLINE int get_num_net_frame_invs() const;
|
||||
INLINE const LMatrix4d &get_net_frame_inv(int n) const;
|
||||
|
||||
virtual void optimize();
|
||||
virtual void expose(EggGroup::DCSType dcs_type);
|
||||
virtual void zero_channels(const string &components);
|
||||
@ -57,6 +67,8 @@ public:
|
||||
protected:
|
||||
typedef pvector<LMatrix4d> RebuildFrames;
|
||||
RebuildFrames _rebuild_frames;
|
||||
RebuildFrames _net_frames;
|
||||
RebuildFrames _net_frame_invs;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user