mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
further progress on egg-optchar
This commit is contained in:
parent
ffbc370236
commit
986f3f8bdc
@ -7,12 +7,12 @@
|
|||||||
dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
|
dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
|
||||||
#define UNIX_SYS_LIBS m
|
#define UNIX_SYS_LIBS m
|
||||||
|
|
||||||
#begin test_bin_target
|
#begin bin_target
|
||||||
#define TARGET egg-optchar
|
#define TARGET egg-optchar-new
|
||||||
|
|
||||||
#define SOURCES \
|
#define SOURCES \
|
||||||
config_egg_optchar.cxx config_egg_optchar.h \
|
config_egg_optchar.cxx config_egg_optchar.h \
|
||||||
eggOptchar.cxx eggOptchar.h \
|
eggOptchar.cxx eggOptchar.h \
|
||||||
eggOptcharUserData.I eggOptcharUserData.cxx eggOptcharUserData.h
|
eggOptcharUserData.I eggOptcharUserData.cxx eggOptcharUserData.h
|
||||||
|
|
||||||
#end test_bin_target
|
#end bin_target
|
||||||
|
@ -17,16 +17,16 @@
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "eggOptchar.h"
|
#include "eggOptchar.h"
|
||||||
|
|
||||||
#include "eggOptcharUserData.h"
|
#include "eggOptcharUserData.h"
|
||||||
|
|
||||||
#include "dcast.h"
|
#include "dcast.h"
|
||||||
#include "eggJointData.h"
|
#include "eggJointData.h"
|
||||||
#include "eggSliderData.h"
|
#include "eggSliderData.h"
|
||||||
#include "eggCharacterCollection.h"
|
#include "eggCharacterCollection.h"
|
||||||
#include "eggCharacterData.h"
|
#include "eggCharacterData.h"
|
||||||
#include "eggJointPointer.h"
|
#include "eggBackPointer.h"
|
||||||
#include "eggTable.h"
|
#include "string_utils.h"
|
||||||
#include "compose_matrix.h"
|
#include "pset.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggOptchar::Constructor
|
// Function: EggOptchar::Constructor
|
||||||
@ -49,6 +49,38 @@ EggOptchar() {
|
|||||||
("ls", "", 0,
|
("ls", "", 0,
|
||||||
"List the joint hierarchy instead of performing any operations.",
|
"List the joint hierarchy instead of performing any operations.",
|
||||||
&EggOptchar::dispatch_none, &_list_hierarchy);
|
&EggOptchar::dispatch_none, &_list_hierarchy);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("lp", "", 0,
|
||||||
|
"List the existing joint hierarchy as a series of -p joint,parent "
|
||||||
|
"commands, suitable for pasting into an egg-optchar command line.",
|
||||||
|
&EggOptchar::dispatch_none, &_list_hierarchy_p);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("keep", "joint", 0,
|
||||||
|
"Keep the named joint (or slider) in the character, even if it does "
|
||||||
|
"not appear to be needed by the animation.",
|
||||||
|
&EggOptchar::dispatch_vector_string, NULL, &_keep_components);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("expose", "joint", 0,
|
||||||
|
"Expose the named joint by flagging it with a DCS attribute, so "
|
||||||
|
"it can be found in the scene graph when the character is loaded, and "
|
||||||
|
"objects can be parented to it. This implies -keep.",
|
||||||
|
&EggOptchar::dispatch_vector_string, NULL, &_expose_components);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("keepall", "", 0,
|
||||||
|
"Keep all joints and sliders in the character.",
|
||||||
|
&EggOptchar::dispatch_none, &_keep_all);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("p", "joint,parent", 0,
|
||||||
|
"Moves the named joint under the named parent joint. Use "
|
||||||
|
"\"-p joint,\" to reparent a joint to the root. The joint transform "
|
||||||
|
"is recomputed appropriately under its new parent so that the animation "
|
||||||
|
"is not affected (the effect is similar to NodePath::wrt_reparent_to).",
|
||||||
|
&EggOptchar::dispatch_vector_string_pair, NULL, &_reparent_joints);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -58,13 +90,22 @@ EggOptchar() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void EggOptchar::
|
void EggOptchar::
|
||||||
run() {
|
run() {
|
||||||
int num_characters = _collection->get_num_characters();
|
// We have to apply the user-specified reparent requests first,
|
||||||
|
// before we even analyze the joints. This is because reparenting
|
||||||
|
// the joints may change their properties.
|
||||||
|
if (apply_user_reparents()) {
|
||||||
|
cerr << "Reparenting hierarchy.\n";
|
||||||
|
// So we'll have to call do_reparent() twice. It seems wasteful,
|
||||||
|
// but it really is necessary, and it's not that bad.
|
||||||
|
do_reparent();
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_characters = _collection->get_num_characters();
|
||||||
int ci;
|
int ci;
|
||||||
|
|
||||||
|
// Now we can analyze the joints for their properties.
|
||||||
for (ci = 0; ci < num_characters; ci++) {
|
for (ci = 0; ci < num_characters; ci++) {
|
||||||
EggCharacterData *char_data = _collection->get_character(ci);
|
EggCharacterData *char_data = _collection->get_character(ci);
|
||||||
|
|
||||||
nout << "Processing " << char_data->get_name() << "\n";
|
|
||||||
analyze_joints(char_data->get_root_joint());
|
analyze_joints(char_data->get_root_joint());
|
||||||
analyze_sliders(char_data);
|
analyze_sliders(char_data);
|
||||||
}
|
}
|
||||||
@ -75,13 +116,25 @@ run() {
|
|||||||
nout << "Character: " << char_data->get_name() << "\n";
|
nout << "Character: " << char_data->get_name() << "\n";
|
||||||
list_joints(char_data->get_root_joint(), 0);
|
list_joints(char_data->get_root_joint(), 0);
|
||||||
list_scalars(char_data);
|
list_scalars(char_data);
|
||||||
|
nout << char_data->get_num_joints() << " joints.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (_list_hierarchy_p) {
|
||||||
|
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());
|
||||||
|
// A newline to cout is needed after the above call.
|
||||||
|
cout << "\n";
|
||||||
|
nout << char_data->get_num_joints() << " joints.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Now, trigger the actual rebuilding of all the joint data.
|
// The meat of the program: determine which joints are to be
|
||||||
for (ci = 0; ci < num_characters; ci++) {
|
// removed, and then actually remove them.
|
||||||
EggCharacterData *char_data = _collection->get_character(ci);
|
determine_removed_components();
|
||||||
char_data->get_root_joint()->do_rebuild();
|
if (remove_joints()) {
|
||||||
|
do_reparent();
|
||||||
}
|
}
|
||||||
|
|
||||||
write_eggs();
|
write_eggs();
|
||||||
@ -105,6 +158,236 @@ handle_args(ProgramBase::Args &args) {
|
|||||||
return EggCharacterFilter::handle_args(args);
|
return EggCharacterFilter::handle_args(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ProgramBase::dispatch_vector_string_pair
|
||||||
|
// Access: Protected, Static
|
||||||
|
// Description: Standard dispatch function for an option that takes
|
||||||
|
// a pair of string parameters. The data pointer is to
|
||||||
|
// StringPairs vector; the pair will be pushed onto the
|
||||||
|
// end of the vector.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool EggOptchar::
|
||||||
|
dispatch_vector_string_pair(const string &opt, const string &arg, void *var) {
|
||||||
|
StringPairs *ip = (StringPairs *)var;
|
||||||
|
|
||||||
|
vector_string words;
|
||||||
|
tokenize(arg, words, ",");
|
||||||
|
|
||||||
|
if (words.size() == 2) {
|
||||||
|
StringPair sp;
|
||||||
|
sp._a = words[0];
|
||||||
|
sp._b = words[1];
|
||||||
|
ip->push_back(sp);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
nout << "-" << opt
|
||||||
|
<< " requires a pair of strings separated by a comma.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggOptchar::determine_removed_components
|
||||||
|
// Access: Private
|
||||||
|
// Description: Flag all joints and sliders that should be removed
|
||||||
|
// for optimization purposes.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggOptchar::
|
||||||
|
determine_removed_components() {
|
||||||
|
typedef pset<string> Names;
|
||||||
|
Names keep_names;
|
||||||
|
Names expose_names;
|
||||||
|
Names names_used;
|
||||||
|
|
||||||
|
vector_string::const_iterator si;
|
||||||
|
for (si = _keep_components.begin(); si != _keep_components.end(); ++si) {
|
||||||
|
keep_names.insert(*si);
|
||||||
|
}
|
||||||
|
for (si = _expose_components.begin(); si != _expose_components.end(); ++si) {
|
||||||
|
keep_names.insert(*si);
|
||||||
|
expose_names.insert(*si);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We always keep the root joint, which has no name.
|
||||||
|
keep_names.insert("");
|
||||||
|
|
||||||
|
int num_characters = _collection->get_num_characters();
|
||||||
|
for (int ci = 0; ci < num_characters; ci++) {
|
||||||
|
EggCharacterData *char_data = _collection->get_character(ci);
|
||||||
|
int num_components = char_data->get_num_components();
|
||||||
|
for (int i = 0; i < num_components; i++) {
|
||||||
|
EggComponentData *comp_data = char_data->get_component(i);
|
||||||
|
EggOptcharUserData *user_data =
|
||||||
|
DCAST(EggOptcharUserData, comp_data->get_user_data());
|
||||||
|
|
||||||
|
const string &name = comp_data->get_name();
|
||||||
|
if (_keep_all || keep_names.find(name) != keep_names.end()) {
|
||||||
|
// Keep this component.
|
||||||
|
names_used.insert(name);
|
||||||
|
|
||||||
|
if (expose_names.find(name) != expose_names.end()) {
|
||||||
|
// In fact, expose it.
|
||||||
|
user_data->_flags |= EggOptcharUserData::F_expose;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Remove this component if it's unanimated or empty.
|
||||||
|
if ((user_data->_flags & (EggOptcharUserData::F_static | EggOptcharUserData::F_empty)) != 0) {
|
||||||
|
user_data->_flags |= EggOptcharUserData::F_remove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go back and tell the user about component names we didn't use,
|
||||||
|
// just to be helpful.
|
||||||
|
for (si = _keep_components.begin(); si != _keep_components.end(); ++si) {
|
||||||
|
const string &name = (*si);
|
||||||
|
if (names_used.find(name) == names_used.end()) {
|
||||||
|
nout << "No such joint: " << name << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (si = _expose_components.begin(); si != _expose_components.end(); ++si) {
|
||||||
|
const string &name = (*si);
|
||||||
|
if (names_used.find(name) == names_used.end()) {
|
||||||
|
nout << "No such joint: " << name << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggOptchar::remove_joints
|
||||||
|
// Access: Private
|
||||||
|
// Description: Effects the actual removal of joints flagged for
|
||||||
|
// removal by reparenting the hierarchy appropriately.
|
||||||
|
// Returns true if anything is done, false otherwise.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool EggOptchar::
|
||||||
|
remove_joints() {
|
||||||
|
bool did_anything = false;
|
||||||
|
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();
|
||||||
|
|
||||||
|
int num_static = 0;
|
||||||
|
int num_empty = 0;
|
||||||
|
int num_identity = 0;
|
||||||
|
int num_kept = 0;
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
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) {
|
||||||
|
num_identity++;
|
||||||
|
} else if ((user_data->_flags & EggOptcharUserData::F_static) != 0) {
|
||||||
|
num_static++;
|
||||||
|
} else if ((user_data->_flags & EggOptcharUserData::F_empty) != 0) {
|
||||||
|
num_empty++;
|
||||||
|
}
|
||||||
|
did_anything = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// This joint will be preserved, but maybe its parent will
|
||||||
|
// change.
|
||||||
|
joint_data->reparent_to(best_parent);
|
||||||
|
num_kept++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_joints == num_kept) {
|
||||||
|
nout << char_data->get_name() << ": keeping " << num_joints
|
||||||
|
<< " joints.\n";
|
||||||
|
} else {
|
||||||
|
nout << char_data->get_name() << ": of " << num_joints
|
||||||
|
<< " joints, removing " << num_identity << " identity, "
|
||||||
|
<< num_static << " static, and " << num_empty
|
||||||
|
<< " empty joints, leaving " << num_kept << ".\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return did_anything;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggOptchar::find_best_parent
|
||||||
|
// Access: Private
|
||||||
|
// Description: Searches for this 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.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
EggJointData *EggOptchar::
|
||||||
|
find_best_parent(EggJointData *joint_data) const {
|
||||||
|
EggOptcharUserData *user_data =
|
||||||
|
DCAST(EggOptcharUserData, joint_data->get_user_data());
|
||||||
|
|
||||||
|
if ((user_data->_flags & EggOptcharUserData::F_remove) != 0) {
|
||||||
|
// Keep going.
|
||||||
|
nassertr(joint_data->get_parent() != (EggJointData *)NULL, NULL);
|
||||||
|
return find_best_parent(joint_data->get_parent());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the one!
|
||||||
|
return joint_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggOptchar::apply_user_reparents
|
||||||
|
// Access: Private
|
||||||
|
// Description: Reparents all the joints that the user suggested on
|
||||||
|
// the command line. Returns true if any operations
|
||||||
|
// were performed, false otherwise.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool EggOptchar::
|
||||||
|
apply_user_reparents() {
|
||||||
|
bool did_anything = false;
|
||||||
|
int num_characters = _collection->get_num_characters();
|
||||||
|
|
||||||
|
StringPairs::const_iterator spi;
|
||||||
|
for (spi = _reparent_joints.begin(); spi != _reparent_joints.end(); ++spi) {
|
||||||
|
const StringPair &p = (*spi);
|
||||||
|
|
||||||
|
for (int ci = 0; ci < num_characters; ci++) {
|
||||||
|
EggCharacterData *char_data = _collection->get_character(ci);
|
||||||
|
EggJointData *node_a = char_data->find_joint(p._a);
|
||||||
|
EggJointData *node_b = char_data->get_root_joint();
|
||||||
|
if (!p._b.empty()) {
|
||||||
|
node_b = char_data->find_joint(p._b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_a == (EggJointData *)NULL) {
|
||||||
|
nout << "No joint named " << p._a << " in " << char_data->get_name()
|
||||||
|
<< ".\n";
|
||||||
|
} else if (node_b == (EggJointData *)NULL) {
|
||||||
|
nout << "No joint named " << p._b << " in " << char_data->get_name()
|
||||||
|
<< ".\n";
|
||||||
|
} else {
|
||||||
|
node_a->reparent_to(node_b);
|
||||||
|
did_anything = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return did_anything;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggOptchar::analyze_joints
|
// Function: EggOptchar::analyze_joints
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -263,6 +546,29 @@ list_joints(EggJointData *joint_data, int indent_level) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggOptchar::list_joints_p
|
||||||
|
// Access: Private
|
||||||
|
// Description: Outputs a list of the joint hierarchy as a series of
|
||||||
|
// -p joint,parent commands.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggOptchar::
|
||||||
|
list_joints_p(EggJointData *joint_data) {
|
||||||
|
// As above, don't list the root joint.
|
||||||
|
|
||||||
|
int num_children = joint_data->get_num_children();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggOptchar::list_scalars
|
// Function: EggOptchar::list_scalars
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -284,20 +590,36 @@ list_scalars(EggCharacterData *char_data) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void EggOptchar::
|
void EggOptchar::
|
||||||
describe_component(EggComponentData *comp_data, int indent_level) {
|
describe_component(EggComponentData *comp_data, int indent_level) {
|
||||||
indent(nout, indent_level)
|
// We use cout instead of nout so the user can easily redirect this
|
||||||
|
// to a file.
|
||||||
|
indent(cout, indent_level)
|
||||||
<< comp_data->get_name();
|
<< comp_data->get_name();
|
||||||
|
|
||||||
EggOptcharUserData *user_data =
|
EggOptcharUserData *user_data =
|
||||||
DCAST(EggOptcharUserData, comp_data->get_user_data());
|
DCAST(EggOptcharUserData, comp_data->get_user_data());
|
||||||
if (user_data->is_identity()) {
|
if (user_data->is_identity()) {
|
||||||
nout << " (identity)";
|
cout << " (identity)";
|
||||||
} else if (user_data->is_static()) {
|
} else if (user_data->is_static()) {
|
||||||
nout << " (static)";
|
cout << " (static)";
|
||||||
}
|
}
|
||||||
if (user_data->is_empty()) {
|
if (user_data->is_empty()) {
|
||||||
nout << " (empty)";
|
cout << " (empty)";
|
||||||
|
}
|
||||||
|
cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggOptchar::do_reparent
|
||||||
|
// Access: Private
|
||||||
|
// Description: Performs all of the queued up reparenting operations.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggOptchar::
|
||||||
|
do_reparent() {
|
||||||
|
int num_characters = _collection->get_num_characters();
|
||||||
|
for (int ci = 0; ci < num_characters; ci++) {
|
||||||
|
EggCharacterData *char_data = _collection->get_character(ci);
|
||||||
|
char_data->do_reparent();
|
||||||
}
|
}
|
||||||
nout << "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "luse.h"
|
#include "luse.h"
|
||||||
|
|
||||||
#include "pvector.h"
|
#include "pvector.h"
|
||||||
|
#include "vector_string.h"
|
||||||
|
|
||||||
class EggCharacterData;
|
class EggCharacterData;
|
||||||
class EggComponentData;
|
class EggComponentData;
|
||||||
@ -49,13 +50,35 @@ protected:
|
|||||||
virtual bool handle_args(Args &args);
|
virtual bool handle_args(Args &args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static bool dispatch_vector_string_pair(const string &opt, const string &arg, void *var);
|
||||||
|
|
||||||
|
void determine_removed_components();
|
||||||
|
bool remove_joints();
|
||||||
|
EggJointData *find_best_parent(EggJointData *joint_data) const;
|
||||||
|
|
||||||
|
bool apply_user_reparents();
|
||||||
void analyze_joints(EggJointData *joint_data);
|
void analyze_joints(EggJointData *joint_data);
|
||||||
void analyze_sliders(EggCharacterData *char_data);
|
void analyze_sliders(EggCharacterData *char_data);
|
||||||
void list_joints(EggJointData *joint_data, int indent_level);
|
void list_joints(EggJointData *joint_data, int indent_level);
|
||||||
|
void list_joints_p(EggJointData *joint_data);
|
||||||
void list_scalars(EggCharacterData *char_data);
|
void list_scalars(EggCharacterData *char_data);
|
||||||
void describe_component(EggComponentData *comp_data, int indent_level);
|
void describe_component(EggComponentData *comp_data, int indent_level);
|
||||||
|
void do_reparent();
|
||||||
|
|
||||||
bool _list_hierarchy;
|
bool _list_hierarchy;
|
||||||
|
bool _list_hierarchy_p;
|
||||||
|
bool _keep_all;
|
||||||
|
|
||||||
|
class StringPair {
|
||||||
|
public:
|
||||||
|
string _a;
|
||||||
|
string _b;
|
||||||
|
};
|
||||||
|
typedef pvector<StringPair> StringPairs;
|
||||||
|
StringPairs _reparent_joints;
|
||||||
|
|
||||||
|
vector_string _keep_components;
|
||||||
|
vector_string _expose_components;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -43,7 +43,8 @@ public:
|
|||||||
F_static = 0x0001,
|
F_static = 0x0001,
|
||||||
F_identity = 0x0002,
|
F_identity = 0x0002,
|
||||||
F_empty = 0x0004,
|
F_empty = 0x0004,
|
||||||
F_remove = 0x0008
|
F_remove = 0x0008,
|
||||||
|
F_expose = 0x0010,
|
||||||
};
|
};
|
||||||
int _flags;
|
int _flags;
|
||||||
LMatrix4d _static_mat;
|
LMatrix4d _static_mat;
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
eggCharacterCollection.h eggCharacterCollection.I \
|
eggCharacterCollection.h eggCharacterCollection.I \
|
||||||
eggCharacterData.h eggCharacterData.I eggCharacterFilter.h \
|
eggCharacterData.h eggCharacterData.I eggCharacterFilter.h \
|
||||||
eggComponentData.h eggComponentData.I eggJointData.h \
|
eggComponentData.h eggComponentData.I eggJointData.h \
|
||||||
eggJointData.I eggJointPointer.h eggJointNodePointer.h \
|
eggJointData.I eggJointPointer.h eggJointPointer.I \
|
||||||
|
eggJointNodePointer.h \
|
||||||
eggMatrixTablePointer.h eggScalarTablePointer.h \
|
eggMatrixTablePointer.h eggScalarTablePointer.h \
|
||||||
eggSliderData.h eggSliderData.I \
|
eggSliderData.h eggSliderData.I \
|
||||||
eggVertexPointer.h
|
eggVertexPointer.h
|
||||||
@ -32,7 +33,7 @@
|
|||||||
eggCharacterData.I eggCharacterData.h eggCharacterFilter.h \
|
eggCharacterData.I eggCharacterData.h eggCharacterFilter.h \
|
||||||
eggComponentData.I eggComponentData.h \
|
eggComponentData.I eggComponentData.h \
|
||||||
eggJointData.h eggJointData.I \
|
eggJointData.h eggJointData.I \
|
||||||
eggJointPointer.h \
|
eggJointPointer.h eggJointPointer.I \
|
||||||
eggJointNodePointer.h \
|
eggJointNodePointer.h \
|
||||||
eggMatrixTablePointer.h \
|
eggMatrixTablePointer.h \
|
||||||
eggScalarTablePointer.h \
|
eggScalarTablePointer.h \
|
||||||
|
@ -112,3 +112,13 @@ get_character_by_model_index(int model_index) const {
|
|||||||
(EggCharacterData *)NULL);
|
(EggCharacterData *)NULL);
|
||||||
return _characters_by_model_index[model_index];
|
return _characters_by_model_index[model_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggCharacterCollection::ModelDescription::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE EggCharacterCollection::ModelDescription::
|
||||||
|
ModelDescription() {
|
||||||
|
_root_node = (EggObject *)NULL;
|
||||||
|
}
|
||||||
|
@ -98,7 +98,7 @@ add_egg(EggData *egg) {
|
|||||||
TopEggNodes::iterator ti;
|
TopEggNodes::iterator ti;
|
||||||
for (ti = top_nodes.begin(); ti != top_nodes.end(); ++ti) {
|
for (ti = top_nodes.begin(); ti != top_nodes.end(); ++ti) {
|
||||||
EggNode *model_root = (*ti).first;
|
EggNode *model_root = (*ti).first;
|
||||||
EggNodeList &egg_nodes = (*ti).second;
|
ModelDescription &desc = (*ti).second;
|
||||||
|
|
||||||
int model_index = _next_model_index++;
|
int model_index = _next_model_index++;
|
||||||
if (egg_info._models.empty()) {
|
if (egg_info._models.empty()) {
|
||||||
@ -109,8 +109,9 @@ add_egg(EggData *egg) {
|
|||||||
char_data->add_model(model_index, model_root);
|
char_data->add_model(model_index, model_root);
|
||||||
nassertr(model_index == (int)_characters_by_model_index.size(), -1);
|
nassertr(model_index == (int)_characters_by_model_index.size(), -1);
|
||||||
_characters_by_model_index.push_back(char_data);
|
_characters_by_model_index.push_back(char_data);
|
||||||
|
root_joint->add_back_pointer(model_index, desc._root_node);
|
||||||
|
|
||||||
match_egg_nodes(char_data, root_joint, egg_nodes,
|
match_egg_nodes(char_data, root_joint, desc._top_nodes,
|
||||||
egg_index, model_index);
|
egg_index, model_index);
|
||||||
|
|
||||||
scan_for_morphs(model_root, model_index, char_data);
|
scan_for_morphs(model_root, model_index, char_data);
|
||||||
@ -268,12 +269,16 @@ scan_for_top_joints(EggNode *egg_node, EggNode *model_root,
|
|||||||
EggGroup *group = DCAST(EggGroup, egg_node);
|
EggGroup *group = DCAST(EggGroup, egg_node);
|
||||||
|
|
||||||
if (group->has_lod()) {
|
if (group->has_lod()) {
|
||||||
// This flag has an LOD specification.
|
// This group has an LOD specification; that indicates multiple
|
||||||
|
// skeleton hierarchies for this character, one for each LOD.
|
||||||
|
// We call each of these a separate model.
|
||||||
model_root = group;
|
model_root = group;
|
||||||
}
|
}
|
||||||
if (group->get_group_type() == EggGroup::GT_joint) {
|
if (group->get_group_type() == EggGroup::GT_joint) {
|
||||||
// A <Joint> node begins a model hierarchy.
|
// A <Joint> node begins a model hierarchy.
|
||||||
_top_egg_nodes[character_name][model_root].push_back(group);
|
ModelDescription &desc = _top_egg_nodes[character_name][model_root];
|
||||||
|
desc._root_node = model_root;
|
||||||
|
desc._top_nodes.push_back(group);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,12 +312,14 @@ scan_for_top_tables(EggTable *bundle, EggNode *model_root,
|
|||||||
if (table->get_name() == "<skeleton>") {
|
if (table->get_name() == "<skeleton>") {
|
||||||
// Here it is! Now the immediate children of this node are
|
// Here it is! Now the immediate children of this node are
|
||||||
// the top tables.
|
// the top tables.
|
||||||
|
ModelDescription &desc = _top_egg_nodes[character_name][model_root];
|
||||||
|
desc._root_node = table;
|
||||||
|
|
||||||
EggGroupNode::iterator cgi;
|
EggGroupNode::iterator cgi;
|
||||||
for (cgi = table->begin(); cgi != table->end(); ++cgi) {
|
for (cgi = table->begin(); cgi != table->end(); ++cgi) {
|
||||||
EggNode *grandchild = (*cgi);
|
EggNode *grandchild = (*cgi);
|
||||||
if (grandchild->is_of_type(EggTable::get_class_type())) {
|
if (grandchild->is_of_type(EggTable::get_class_type())) {
|
||||||
_top_egg_nodes[character_name][model_root].push_back(grandchild);
|
desc._top_nodes.push_back(grandchild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,8 +466,10 @@ match_egg_nodes(EggCharacterData *char_data, EggJointData *joint_data,
|
|||||||
EggNode *egg_node = (*ei);
|
EggNode *egg_node = (*ei);
|
||||||
EggJointData *data = make_joint_data(char_data);
|
EggJointData *data = make_joint_data(char_data);
|
||||||
joint_data->_children.push_back(data);
|
joint_data->_children.push_back(data);
|
||||||
|
char_data->_joints.push_back(data);
|
||||||
char_data->_components.push_back(data);
|
char_data->_components.push_back(data);
|
||||||
data->_parent = joint_data;
|
data->_parent = joint_data;
|
||||||
|
data->_new_parent = joint_data;
|
||||||
found_egg_match(char_data, data, egg_node, egg_index, model_index);
|
found_egg_match(char_data, data, egg_node, egg_index, model_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,8 +574,10 @@ match_egg_nodes(EggCharacterData *char_data, EggJointData *joint_data,
|
|||||||
EggNode *egg_node = (*ei);
|
EggNode *egg_node = (*ei);
|
||||||
EggJointData *data = make_joint_data(char_data);
|
EggJointData *data = make_joint_data(char_data);
|
||||||
joint_data->_children.push_back(data);
|
joint_data->_children.push_back(data);
|
||||||
|
char_data->_joints.push_back(data);
|
||||||
char_data->_components.push_back(data);
|
char_data->_components.push_back(data);
|
||||||
data->_parent = joint_data;
|
data->_parent = joint_data;
|
||||||
|
data->_new_parent = joint_data;
|
||||||
found_egg_match(char_data, data, egg_node, egg_index, model_index);
|
found_egg_match(char_data, data, egg_node, egg_index, model_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
#ifndef EGGCHARACTERCOLLECTION_H
|
#ifndef EGGCHARACTERCOLLECTION_H
|
||||||
#define EGGCHARACTERCOLLECTION_H
|
#define EGGCHARACTERCOLLECTION_H
|
||||||
|
|
||||||
#include <pandatoolbase.h>
|
#include "pandatoolbase.h"
|
||||||
|
|
||||||
#include "eggCharacterData.h"
|
#include "eggCharacterData.h"
|
||||||
|
|
||||||
#include <eggData.h>
|
#include "eggData.h"
|
||||||
#include <eggNode.h>
|
#include "eggNode.h"
|
||||||
#include <pointerTo.h>
|
#include "pointerTo.h"
|
||||||
|
|
||||||
class EggTable;
|
class EggTable;
|
||||||
class EggAttributes;
|
class EggAttributes;
|
||||||
@ -95,7 +95,14 @@ private:
|
|||||||
// The _top_egg_nodes member is only used temporarily, when adding
|
// The _top_egg_nodes member is only used temporarily, when adding
|
||||||
// each pre-existing egg file to the structure for the first time.
|
// each pre-existing egg file to the structure for the first time.
|
||||||
typedef pvector<EggNode *> EggNodeList;
|
typedef pvector<EggNode *> EggNodeList;
|
||||||
typedef pmap<EggNode *, EggNodeList> TopEggNodes;
|
class ModelDescription {
|
||||||
|
public:
|
||||||
|
INLINE ModelDescription();
|
||||||
|
EggNodeList _top_nodes;
|
||||||
|
EggObject *_root_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef pmap<EggNode *, ModelDescription> TopEggNodes;
|
||||||
typedef pmap<string, TopEggNodes> TopEggNodesByName;
|
typedef pmap<string, TopEggNodes> TopEggNodesByName;
|
||||||
TopEggNodesByName _top_egg_nodes;
|
TopEggNodesByName _top_egg_nodes;
|
||||||
|
|
||||||
|
@ -94,6 +94,30 @@ find_joint(const string &name) const {
|
|||||||
return _root_joint->find_joint(name);
|
return _root_joint->find_joint(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggCharacterData::get_num_joints
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the total number of joints in the character
|
||||||
|
// joint hierarchy.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE int EggCharacterData::
|
||||||
|
get_num_joints() const {
|
||||||
|
return _joints.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggCharacterData::get_joint
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the nth joint in the character joint
|
||||||
|
// hierarchy. This returns all of the joints in the
|
||||||
|
// hierarchy in an arbitrary ordering.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE EggJointData *EggCharacterData::
|
||||||
|
get_joint(int n) const {
|
||||||
|
nassertr(n >= 0 && n < (int)_joints.size(), NULL);
|
||||||
|
return _joints[n];
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggCharacterData::get_num_sliders
|
// Function: EggCharacterData::get_num_sliders
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -72,6 +72,117 @@ add_model(int model_index, EggNode *model_root) {
|
|||||||
_models.push_back(m);
|
_models.push_back(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggCharacterData::get_num_frames
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the number of frames of animation of the
|
||||||
|
// indicated model. This is more reliable than asking a
|
||||||
|
// particular joint or slider of the animation for its
|
||||||
|
// number of frames, since a particular joint may have
|
||||||
|
// only 1 frame (if it is unanimated), even though the
|
||||||
|
// overall animation has many frames.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int EggCharacterData::
|
||||||
|
get_num_frames(int model_index) const {
|
||||||
|
int max_num_frames = 0;
|
||||||
|
Components::const_iterator ci;
|
||||||
|
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
||||||
|
EggComponentData *component = (*ci);
|
||||||
|
int num_frames = component->get_num_frames(model_index);
|
||||||
|
if (num_frames > 1) {
|
||||||
|
// We have a winner. Assume all other components will be
|
||||||
|
// similar.
|
||||||
|
return num_frames;
|
||||||
|
}
|
||||||
|
max_num_frames = max(max_num_frames, num_frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every component had either 1 frame or 0 frames. Return the
|
||||||
|
// maximum of these.
|
||||||
|
return max_num_frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggCharacterData::do_reparent
|
||||||
|
// Access: Public
|
||||||
|
// Description: Begins the process of restructuring the joint
|
||||||
|
// hierarchy according to the previous calls to
|
||||||
|
// reparent_to() on various joints. This will reparent
|
||||||
|
// the joint hierachy in all models as requested, while
|
||||||
|
// adjusting the transforms as appropriate so that each
|
||||||
|
// joint retains the same net transform across all
|
||||||
|
// frames that it had before the operation. Returns
|
||||||
|
// true on success, false on failure.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool EggCharacterData::
|
||||||
|
do_reparent() {
|
||||||
|
typedef pset<EggJointData *> InvalidSet;
|
||||||
|
InvalidSet invalid_set;
|
||||||
|
|
||||||
|
// First, make sure the list of new_children is accurate.
|
||||||
|
Joints::const_iterator ji;
|
||||||
|
for (ji = _joints.begin(); ji != _joints.end(); ++ji) {
|
||||||
|
EggJointData *joint_data = (*ji);
|
||||||
|
joint_data->do_begin_reparent();
|
||||||
|
}
|
||||||
|
// We also need to clear the children on the root joint, but the
|
||||||
|
// root joint doesn't get any of the other operations (including
|
||||||
|
// finish_reparent) applied to it.
|
||||||
|
_root_joint->do_begin_reparent();
|
||||||
|
|
||||||
|
// Now compute the new transforms for the joints' new positions.
|
||||||
|
// This is done recursively through the new parent hierarchy, so we
|
||||||
|
// can take advantage of caching the net value for a particular
|
||||||
|
// frame.
|
||||||
|
Models::const_iterator mi;
|
||||||
|
for (mi = _models.begin(); mi != _models.end(); ++mi) {
|
||||||
|
int model_index = (*mi)._model_index;
|
||||||
|
int num_frames = get_num_frames(model_index);
|
||||||
|
for (int f = 0; f < num_frames; f++) {
|
||||||
|
// First, walk through all the joints and flush the computed net
|
||||||
|
// transforms from before.
|
||||||
|
for (ji = _joints.begin(); ji != _joints.end(); ++ji) {
|
||||||
|
EggJointData *joint_data = (*ji);
|
||||||
|
joint_data->do_begin_compute_reparent();
|
||||||
|
}
|
||||||
|
_root_joint->do_begin_compute_reparent();
|
||||||
|
|
||||||
|
// Now go back through and compute the reparented transforms,
|
||||||
|
// caching net transforms as necessary.
|
||||||
|
for (ji = _joints.begin(); ji != _joints.end(); ++ji) {
|
||||||
|
EggJointData *joint_data = (*ji);
|
||||||
|
if (!joint_data->do_compute_reparent(model_index, f)) {
|
||||||
|
// Oops, we got an invalid transform.
|
||||||
|
invalid_set.insert(joint_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now remove all of the old children and add in the new children.
|
||||||
|
for (ji = _joints.begin(); ji != _joints.end(); ++ji) {
|
||||||
|
EggJointData *joint_data = (*ji);
|
||||||
|
if (!joint_data->do_finish_reparent()) {
|
||||||
|
invalid_set.insert(joint_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InvalidSet::const_iterator si;
|
||||||
|
for (si = invalid_set.begin(); si != invalid_set.end(); ++si) {
|
||||||
|
EggJointData *joint_data = (*si);
|
||||||
|
// Don't bother reporting joints that no longer have a parent,
|
||||||
|
// since we don't care about joints that are now outside the
|
||||||
|
// 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return invalid_set.empty();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggCharacterData::find_slider
|
// Function: EggCharacterData::find_slider
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -68,9 +68,13 @@ public:
|
|||||||
INLINE int get_num_models() const;
|
INLINE int get_num_models() const;
|
||||||
INLINE int get_model_index(int n) const;
|
INLINE int get_model_index(int n) const;
|
||||||
INLINE EggNode *get_model_root(int n) const;
|
INLINE EggNode *get_model_root(int n) const;
|
||||||
|
int get_num_frames(int model_index) const;
|
||||||
|
|
||||||
INLINE EggJointData *get_root_joint() const;
|
INLINE EggJointData *get_root_joint() const;
|
||||||
INLINE EggJointData *find_joint(const string &name) const;
|
INLINE EggJointData *find_joint(const string &name) const;
|
||||||
|
INLINE int get_num_joints() const;
|
||||||
|
INLINE EggJointData *get_joint(int n) const;
|
||||||
|
bool do_reparent();
|
||||||
|
|
||||||
INLINE int get_num_sliders() const;
|
INLINE int get_num_sliders() const;
|
||||||
INLINE EggSliderData *get_slider(int n) const;
|
INLINE EggSliderData *get_slider(int n) const;
|
||||||
@ -100,6 +104,9 @@ protected:
|
|||||||
typedef pvector<EggSliderData *> Sliders;
|
typedef pvector<EggSliderData *> Sliders;
|
||||||
Sliders _sliders;
|
Sliders _sliders;
|
||||||
|
|
||||||
|
typedef pvector<EggJointData *> Joints;
|
||||||
|
Joints _joints;
|
||||||
|
|
||||||
typedef pvector<EggComponentData *> Components;
|
typedef pvector<EggComponentData *> Components;
|
||||||
Components _components;
|
Components _components;
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ public:
|
|||||||
void add_name(const string &name);
|
void add_name(const string &name);
|
||||||
bool matches_name(const string &name) const;
|
bool matches_name(const string &name) const;
|
||||||
|
|
||||||
|
virtual int get_num_frames(int model_index) const=0;
|
||||||
|
|
||||||
virtual void add_back_pointer(int model_index, EggObject *egg_object)=0;
|
virtual void add_back_pointer(int model_index, EggObject *egg_object)=0;
|
||||||
virtual void write(ostream &out, int indent_level = 0) const=0;
|
virtual void write(ostream &out, int indent_level = 0) const=0;
|
||||||
|
|
||||||
|
@ -47,3 +47,17 @@ get_child(int n) const {
|
|||||||
nassertr(n >= 0 && n < (int)_children.size(), (EggJointData *)NULL);
|
nassertr(n >= 0 && n < (int)_children.size(), (EggJointData *)NULL);
|
||||||
return _children[n];
|
return _children[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::reparent_to
|
||||||
|
// Access: Public
|
||||||
|
// Description: Indicates an intention to change the parent of this
|
||||||
|
// joint to the indicated joint, or NULL to remove it
|
||||||
|
// from the hierarchy. The joint is not reparented
|
||||||
|
// immediately, but rather all of the joints are
|
||||||
|
// reparented at once when do_reparent() is called.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE void EggJointData::
|
||||||
|
reparent_to(EggJointData *new_parent) {
|
||||||
|
_new_parent = new_parent;
|
||||||
|
}
|
||||||
|
@ -39,6 +39,7 @@ EggJointData(EggCharacterCollection *collection,
|
|||||||
EggComponentData(collection, char_data)
|
EggComponentData(collection, char_data)
|
||||||
{
|
{
|
||||||
_parent = (EggJointData *)NULL;
|
_parent = (EggJointData *)NULL;
|
||||||
|
_new_parent = (EggJointData *)NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -66,7 +67,7 @@ find_joint(const string &name) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggJointData::get_num_frames
|
// Function: EggJointData::get_num_frames
|
||||||
// Access: Public
|
// Access: Public, Virtual
|
||||||
// Description: Returns the number of frames of animation for this
|
// Description: Returns the number of frames of animation for this
|
||||||
// particular joint in the indicated model.
|
// particular joint in the indicated model.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -119,6 +120,26 @@ get_net_frame(int model_index, int n) const {
|
|||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::move_vertices_to
|
||||||
|
// Access: Public
|
||||||
|
// Description: Moves the vertices assigned to this joint into the
|
||||||
|
// indicated joint, without changing their weight
|
||||||
|
// assignments.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggJointData::do_rebuild
|
// Function: EggJointData::do_rebuild
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -186,6 +207,7 @@ optimize() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void EggJointData::
|
void EggJointData::
|
||||||
add_back_pointer(int model_index, EggObject *egg_object) {
|
add_back_pointer(int model_index, EggObject *egg_object) {
|
||||||
|
nassertv(egg_object != (EggObject *)NULL);
|
||||||
if (egg_object->is_of_type(EggGroup::get_class_type())) {
|
if (egg_object->is_of_type(EggGroup::get_class_type())) {
|
||||||
// It must be a <Joint>.
|
// It must be a <Joint>.
|
||||||
EggJointNodePointer *joint = new EggJointNodePointer(egg_object);
|
EggJointNodePointer *joint = new EggJointNodePointer(egg_object);
|
||||||
@ -226,3 +248,196 @@ write(ostream &out, int indent_level) const {
|
|||||||
|
|
||||||
indent(out, indent_level) << "}\n";
|
indent(out, indent_level) << "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::do_begin_reparent
|
||||||
|
// Access: Protected
|
||||||
|
// Description: Clears out the _children vector in preparation for
|
||||||
|
// refilling it from the _new_parent information.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggJointData::
|
||||||
|
do_begin_reparent() {
|
||||||
|
_children.clear();
|
||||||
|
|
||||||
|
int num_models = get_num_models();
|
||||||
|
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->begin_rebuild();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::do_begin_compute_reparent
|
||||||
|
// Access: Protected
|
||||||
|
// Description: Eliminates any cached values before beginning a walk
|
||||||
|
// through all the joints for do_compute_reparent(), for
|
||||||
|
// a given model/frame.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggJointData::
|
||||||
|
do_begin_compute_reparent() {
|
||||||
|
_got_new_net_frame = false;
|
||||||
|
_got_new_net_frame_inv = false;
|
||||||
|
_computed_reparent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::do_compute_reparent
|
||||||
|
// Access: Protected
|
||||||
|
// Description: Prepares the reparent operation by computing a new
|
||||||
|
// transform for each frame of each model, designed to
|
||||||
|
// keep the net transform the same when the joint is
|
||||||
|
// moved to its new parent. Returns true on success,
|
||||||
|
// false on failure.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool EggJointData::
|
||||||
|
do_compute_reparent(int model_index, int n) {
|
||||||
|
if (_computed_reparent) {
|
||||||
|
// We've already done this joint. This is possible because we
|
||||||
|
// have to recursively compute joints upwards, so we might visit
|
||||||
|
// the same joint more than once.
|
||||||
|
return _computed_ok;
|
||||||
|
}
|
||||||
|
_computed_reparent = true;
|
||||||
|
|
||||||
|
if (_parent == _new_parent) {
|
||||||
|
// Trivial (and most common) case: we are not moving the joint.
|
||||||
|
// No recomputation necessary.
|
||||||
|
_computed_ok = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EggBackPointer *back = get_model(model_index);
|
||||||
|
if (back == (EggBackPointer *)NULL) {
|
||||||
|
// This joint doesn't have any data to modify.
|
||||||
|
_computed_ok = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EggJointPointer *joint;
|
||||||
|
DCAST_INTO_R(joint, back, false);
|
||||||
|
|
||||||
|
LMatrix4d transform;
|
||||||
|
if (_parent == (EggJointData *)NULL) {
|
||||||
|
// We are moving from outside the joint hierarchy to within it.
|
||||||
|
transform = _new_parent->get_new_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_new_net_frame(model_index, n);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// We are changing parents within the hierarchy.
|
||||||
|
transform =
|
||||||
|
_parent->get_new_net_frame(model_index, n) *
|
||||||
|
_new_parent->get_new_net_frame_inv(model_index, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
nassertr(n == joint->get_num_rebuild_frames(), false);
|
||||||
|
|
||||||
|
_computed_ok = joint->add_rebuild_frame(joint->get_frame(n) * transform);
|
||||||
|
return _computed_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::do_finish_reparent
|
||||||
|
// Access: Protected
|
||||||
|
// Description: Performs the actual reparenting operation
|
||||||
|
// by removing all of the old children and replacing
|
||||||
|
// them with the set of new children. Returns true on
|
||||||
|
// success, false on failure.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool EggJointData::
|
||||||
|
do_finish_reparent() {
|
||||||
|
bool all_ok = true;
|
||||||
|
|
||||||
|
int num_models = get_num_models();
|
||||||
|
for (int model_index = 0; model_index < num_models; model_index++) {
|
||||||
|
EggJointPointer *parent_joint = NULL;
|
||||||
|
if (_new_parent != NULL && _new_parent->has_model(model_index)) {
|
||||||
|
DCAST_INTO_R(parent_joint, _new_parent->get_model(model_index), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_model(model_index)) {
|
||||||
|
EggJointPointer *joint;
|
||||||
|
DCAST_INTO_R(joint, get_model(model_index), false);
|
||||||
|
joint->do_finish_reparent(parent_joint);
|
||||||
|
if (!joint->do_rebuild()) {
|
||||||
|
all_ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent = _new_parent;
|
||||||
|
if (_parent != (EggJointData *)NULL) {
|
||||||
|
_parent->_children.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::get_new_net_frame
|
||||||
|
// Access: Private
|
||||||
|
// Description: Similar to get_net_frame(), but computed for the
|
||||||
|
// prospective new parentage of the node, before
|
||||||
|
// do_finish_reparent() is called. This is generally
|
||||||
|
// useful only when called within do_compute_reparent().
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
const LMatrix4d &EggJointData::
|
||||||
|
get_new_net_frame(int model_index, int n) {
|
||||||
|
if (!_got_new_net_frame) {
|
||||||
|
_new_net_frame = get_new_frame(model_index, n);
|
||||||
|
if (_new_parent != (EggJointData *)NULL) {
|
||||||
|
_new_net_frame = _new_net_frame * _new_parent->get_new_net_frame(model_index, n);
|
||||||
|
}
|
||||||
|
_got_new_net_frame = true;
|
||||||
|
}
|
||||||
|
return _new_net_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::get_new_net_frame_inv
|
||||||
|
// Access: Private
|
||||||
|
// Description: Returns the inverse of get_new_net_frame().
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
const LMatrix4d &EggJointData::
|
||||||
|
get_new_net_frame_inv(int model_index, int n) {
|
||||||
|
if (!_got_new_net_frame_inv) {
|
||||||
|
_new_net_frame_inv.invert_from(get_new_frame(model_index, n));
|
||||||
|
if (_new_parent != (EggJointData *)NULL) {
|
||||||
|
_new_net_frame_inv = _new_parent->get_new_net_frame_inv(model_index, n) * _new_net_frame_inv;
|
||||||
|
}
|
||||||
|
_got_new_net_frame_inv = true;
|
||||||
|
}
|
||||||
|
return _new_net_frame_inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointData::get_new_frame
|
||||||
|
// Access: Private
|
||||||
|
// Description: Returns the local transform matrix corresponding to
|
||||||
|
// this joint position in the nth frame in the indicated
|
||||||
|
// model, as it will be when do_finish_reparent() is
|
||||||
|
// called.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
LMatrix4d EggJointData::
|
||||||
|
get_new_frame(int model_index, int n) {
|
||||||
|
do_compute_reparent(model_index, n);
|
||||||
|
|
||||||
|
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_rebuild_frames() > 0) {
|
||||||
|
return joint->get_rebuild_frame(n);
|
||||||
|
} else {
|
||||||
|
return joint->get_frame(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,22 +43,42 @@ public:
|
|||||||
INLINE EggJointData *get_child(int n) const;
|
INLINE EggJointData *get_child(int n) const;
|
||||||
EggJointData *find_joint(const string &name);
|
EggJointData *find_joint(const string &name);
|
||||||
|
|
||||||
int get_num_frames(int model_index) const;
|
virtual int get_num_frames(int model_index) const;
|
||||||
LMatrix4d get_frame(int model_index, int n) const;
|
LMatrix4d get_frame(int model_index, int n) const;
|
||||||
LMatrix4d get_net_frame(int model_index, int n) const;
|
LMatrix4d get_net_frame(int model_index, int n) const;
|
||||||
|
|
||||||
|
INLINE void reparent_to(EggJointData *new_parent);
|
||||||
|
void move_vertices_to(EggJointData *new_owner);
|
||||||
|
|
||||||
bool do_rebuild();
|
bool do_rebuild();
|
||||||
void optimize();
|
void optimize();
|
||||||
|
|
||||||
virtual void add_back_pointer(int model_index, EggObject *egg_object);
|
virtual void add_back_pointer(int model_index, EggObject *egg_object);
|
||||||
virtual void write(ostream &out, int indent_level = 0) const;
|
virtual void write(ostream &out, int indent_level = 0) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void do_begin_reparent();
|
||||||
|
void do_begin_compute_reparent();
|
||||||
|
bool do_compute_reparent(int model_index, int n);
|
||||||
|
bool do_finish_reparent();
|
||||||
|
|
||||||
|
private:
|
||||||
|
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);
|
||||||
|
|
||||||
|
// These are used to cache the above results for optimizing
|
||||||
|
// do_compute_reparent().
|
||||||
|
LMatrix4d _new_net_frame, _new_net_frame_inv;
|
||||||
|
bool _got_new_net_frame, _got_new_net_frame_inv;
|
||||||
|
bool _computed_reparent;
|
||||||
|
bool _computed_ok;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef pvector<EggJointData *> Children;
|
typedef pvector<EggJointData *> Children;
|
||||||
Children _children;
|
Children _children;
|
||||||
EggJointData *_parent;
|
EggJointData *_parent;
|
||||||
|
EggJointData *_new_parent;
|
||||||
friend class EggCharacterCollection;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -77,6 +97,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static TypeHandle _type_handle;
|
static TypeHandle _type_handle;
|
||||||
|
|
||||||
|
friend class EggCharacterCollection;
|
||||||
|
friend class EggCharacterData;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "eggJointData.I"
|
#include "eggJointData.I"
|
||||||
|
@ -35,7 +35,7 @@ EggJointNodePointer::
|
|||||||
EggJointNodePointer(EggObject *object) {
|
EggJointNodePointer(EggObject *object) {
|
||||||
_joint = DCAST(EggGroup, object);
|
_joint = DCAST(EggGroup, object);
|
||||||
|
|
||||||
if (_joint != (EggGroup *)NULL) {
|
if (_joint != (EggGroup *)NULL && _joint->is_joint()) {
|
||||||
// Quietly insist that the joint has a transform, for neatness. If
|
// Quietly insist that the joint has a transform, for neatness. If
|
||||||
// it does not, give it the identity transform.
|
// it does not, give it the identity transform.
|
||||||
if (!_joint->has_transform()) {
|
if (!_joint->has_transform()) {
|
||||||
@ -94,6 +94,46 @@ set_frame(int n, const LMatrix4d &mat) {
|
|||||||
_joint->set_transform(mat);
|
_joint->set_transform(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointNodePointer::do_finish_reparent
|
||||||
|
// Access: Protected
|
||||||
|
// Description: Performs the actual reparenting operation
|
||||||
|
// by removing the node from its old parent and
|
||||||
|
// associating it with its new parent, if any.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggJointNodePointer::
|
||||||
|
do_finish_reparent(EggJointPointer *new_parent) {
|
||||||
|
if (new_parent == (EggJointPointer *)NULL) {
|
||||||
|
// No new parent; unparent the joint.
|
||||||
|
EggGroupNode *egg_parent = _joint->get_parent();
|
||||||
|
if (egg_parent != (EggGroupNode *)NULL) {
|
||||||
|
egg_parent->remove_child(_joint.p());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Reparent the joint to its new parent (implicitly unparenting it
|
||||||
|
// from its previous parent).
|
||||||
|
EggJointNodePointer *new_node = DCAST(EggJointNodePointer, new_parent);
|
||||||
|
if (new_node->_joint != _joint->get_parent()) {
|
||||||
|
new_node->_joint->add_child(_joint.p());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointNodePointer::move_vertices_to
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Moves the vertices assigned to this joint into the
|
||||||
|
// other joint (which should be of the same type).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggJointNodePointer::
|
||||||
|
move_vertices_to(EggJointPointer *new_joint) {
|
||||||
|
EggJointNodePointer *new_node;
|
||||||
|
DCAST_INTO_V(new_node, new_joint);
|
||||||
|
|
||||||
|
new_node->_joint->steal_vrefs(_joint);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggJointNodePointer::add_rebuild_frame
|
// Function: EggJointNodePointer::add_rebuild_frame
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
|
@ -38,6 +38,9 @@ public:
|
|||||||
virtual LMatrix4d get_frame(int n) const;
|
virtual LMatrix4d get_frame(int n) const;
|
||||||
virtual void set_frame(int n, const LMatrix4d &mat);
|
virtual void set_frame(int n, const LMatrix4d &mat);
|
||||||
|
|
||||||
|
virtual void do_finish_reparent(EggJointPointer *new_parent);
|
||||||
|
virtual void move_vertices_to(EggJointPointer *new_joint);
|
||||||
|
|
||||||
virtual bool add_rebuild_frame(const LMatrix4d &mat);
|
virtual bool add_rebuild_frame(const LMatrix4d &mat);
|
||||||
virtual bool do_rebuild();
|
virtual bool do_rebuild();
|
||||||
|
|
||||||
|
41
pandatool/src/eggcharbase/eggJointPointer.I
Normal file
41
pandatool/src/eggcharbase/eggJointPointer.I
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Filename: eggJointPointer.I
|
||||||
|
// Created by: drose (20Jul03)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://www.panda3d.org/license.txt .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d@yahoogroups.com .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointPointer::get_num_rebuild_frames
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the number of rebuild frames that have been
|
||||||
|
// added so far.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE int EggJointPointer::
|
||||||
|
get_num_rebuild_frames() const {
|
||||||
|
return _rebuild_frames.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointPointer::get_rebuild_frame
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the nth matrix that has been added to the set
|
||||||
|
// of rebuild frames.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE const LMatrix4d &EggJointPointer::
|
||||||
|
get_rebuild_frame(int n) const {
|
||||||
|
nassertr(n >= 0 && n < (int)_rebuild_frames.size(), LMatrix4d::ident_mat());
|
||||||
|
return _rebuild_frames[n];
|
||||||
|
}
|
@ -34,6 +34,16 @@ add_frame(const LMatrix4d &) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggJointPointer::move_vertices_to
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Moves the vertices assigned to this joint into the
|
||||||
|
// other joint (which should be of the same type).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggJointPointer::
|
||||||
|
move_vertices_to(EggJointPointer *) {
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggJointPointer::begin_rebuild
|
// Function: EggJointPointer::begin_rebuild
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -41,8 +41,13 @@ public:
|
|||||||
virtual void set_frame(int n, const LMatrix4d &mat)=0;
|
virtual void set_frame(int n, const LMatrix4d &mat)=0;
|
||||||
virtual bool add_frame(const LMatrix4d &mat);
|
virtual bool add_frame(const LMatrix4d &mat);
|
||||||
|
|
||||||
|
virtual void do_finish_reparent(EggJointPointer *new_parent)=0;
|
||||||
|
virtual void move_vertices_to(EggJointPointer *new_joint);
|
||||||
|
|
||||||
void begin_rebuild();
|
void begin_rebuild();
|
||||||
virtual bool add_rebuild_frame(const LMatrix4d &mat);
|
virtual bool add_rebuild_frame(const LMatrix4d &mat);
|
||||||
|
INLINE int get_num_rebuild_frames() const;
|
||||||
|
INLINE const LMatrix4d &get_rebuild_frame(int n) const;
|
||||||
virtual bool do_rebuild();
|
virtual bool do_rebuild();
|
||||||
|
|
||||||
virtual void optimize();
|
virtual void optimize();
|
||||||
@ -69,6 +74,8 @@ private:
|
|||||||
static TypeHandle _type_handle;
|
static TypeHandle _type_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "eggJointPointer.I"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,6 +86,10 @@ get_frame(int n) const {
|
|||||||
// If we have exactly one frame, then we have as many frames as we
|
// If we have exactly one frame, then we have as many frames as we
|
||||||
// want; just repeat the first frame.
|
// want; just repeat the first frame.
|
||||||
n = 0;
|
n = 0;
|
||||||
|
|
||||||
|
} else if (get_num_frames() == 0) {
|
||||||
|
// If we have no frames, we really have the identity matrix.
|
||||||
|
return LMatrix4d::ident_mat();
|
||||||
}
|
}
|
||||||
|
|
||||||
nassertr(n >= 0 && n < get_num_frames(), LMatrix4d::ident_mat());
|
nassertr(n >= 0 && n < get_num_frames(), LMatrix4d::ident_mat());
|
||||||
@ -122,6 +126,32 @@ add_frame(const LMatrix4d &mat) {
|
|||||||
return _xform->add_data(mat);
|
return _xform->add_data(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EggMatrixTablePointer::do_finish_reparent
|
||||||
|
// Access: Protected
|
||||||
|
// Description: Performs the actual reparenting operation
|
||||||
|
// by removing the node from its old parent and
|
||||||
|
// associating it with its new parent, if any.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EggMatrixTablePointer::
|
||||||
|
do_finish_reparent(EggJointPointer *new_parent) {
|
||||||
|
if (new_parent == (EggJointPointer *)NULL) {
|
||||||
|
// No new parent; unparent the joint.
|
||||||
|
EggGroupNode *egg_parent = _table->get_parent();
|
||||||
|
if (egg_parent != (EggGroupNode *)NULL) {
|
||||||
|
egg_parent->remove_child(_table.p());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Reparent the joint to its new parent (implicitly unparenting it
|
||||||
|
// from its previous parent).
|
||||||
|
EggMatrixTablePointer *new_node = DCAST(EggMatrixTablePointer, new_parent);
|
||||||
|
if (new_node->_table != _table->get_parent()) {
|
||||||
|
new_node->_table->add_child(_table.p());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggMatrixTablePointer::do_rebuild
|
// Function: EggMatrixTablePointer::do_rebuild
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
|
@ -43,6 +43,8 @@ public:
|
|||||||
virtual void set_frame(int n, const LMatrix4d &mat);
|
virtual void set_frame(int n, const LMatrix4d &mat);
|
||||||
virtual bool add_frame(const LMatrix4d &mat);
|
virtual bool add_frame(const LMatrix4d &mat);
|
||||||
|
|
||||||
|
virtual void do_finish_reparent(EggJointPointer *new_parent);
|
||||||
|
|
||||||
virtual bool do_rebuild();
|
virtual bool do_rebuild();
|
||||||
|
|
||||||
virtual void optimize();
|
virtual void optimize();
|
||||||
|
@ -42,7 +42,7 @@ EggSliderData(EggCharacterCollection *collection,
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EggSliderData::get_num_frames
|
// Function: EggSliderData::get_num_frames
|
||||||
// Access: Public
|
// Access: Public, Virtual
|
||||||
// Description: Returns the number of frames of animation for this
|
// Description: Returns the number of frames of animation for this
|
||||||
// particular slider in the indicated model.
|
// particular slider in the indicated model.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -37,7 +37,7 @@ public:
|
|||||||
EggSliderData(EggCharacterCollection *collection,
|
EggSliderData(EggCharacterCollection *collection,
|
||||||
EggCharacterData *char_data);
|
EggCharacterData *char_data);
|
||||||
|
|
||||||
int get_num_frames(int model_index) const;
|
virtual int get_num_frames(int model_index) const;
|
||||||
double get_frame(int model_index, int n) const;
|
double get_frame(int model_index, int n) const;
|
||||||
|
|
||||||
virtual void add_back_pointer(int model_index, EggObject *egg_object);
|
virtual void add_back_pointer(int model_index, EggObject *egg_object);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user