mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 18:03:56 -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
|
||||
#define UNIX_SYS_LIBS m
|
||||
|
||||
#begin test_bin_target
|
||||
#define TARGET egg-optchar
|
||||
#begin bin_target
|
||||
#define TARGET egg-optchar-new
|
||||
|
||||
#define SOURCES \
|
||||
config_egg_optchar.cxx config_egg_optchar.h \
|
||||
eggOptchar.cxx eggOptchar.h \
|
||||
eggOptcharUserData.I eggOptcharUserData.cxx eggOptcharUserData.h
|
||||
|
||||
#end test_bin_target
|
||||
#end bin_target
|
||||
|
@ -17,16 +17,16 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "eggOptchar.h"
|
||||
|
||||
#include "eggOptcharUserData.h"
|
||||
|
||||
#include "dcast.h"
|
||||
#include "eggJointData.h"
|
||||
#include "eggSliderData.h"
|
||||
#include "eggCharacterCollection.h"
|
||||
#include "eggCharacterData.h"
|
||||
#include "eggJointPointer.h"
|
||||
#include "eggTable.h"
|
||||
#include "compose_matrix.h"
|
||||
#include "eggBackPointer.h"
|
||||
#include "string_utils.h"
|
||||
#include "pset.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggOptchar::Constructor
|
||||
@ -49,6 +49,38 @@ EggOptchar() {
|
||||
("ls", "", 0,
|
||||
"List the joint hierarchy instead of performing any operations.",
|
||||
&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::
|
||||
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;
|
||||
|
||||
// Now we can analyze the joints for their properties.
|
||||
for (ci = 0; ci < num_characters; ci++) {
|
||||
EggCharacterData *char_data = _collection->get_character(ci);
|
||||
|
||||
nout << "Processing " << char_data->get_name() << "\n";
|
||||
analyze_joints(char_data->get_root_joint());
|
||||
analyze_sliders(char_data);
|
||||
}
|
||||
@ -75,15 +116,27 @@ run() {
|
||||
nout << "Character: " << char_data->get_name() << "\n";
|
||||
list_joints(char_data->get_root_joint(), 0);
|
||||
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 {
|
||||
// Now, trigger the actual rebuilding of all the joint data.
|
||||
for (ci = 0; ci < num_characters; ci++) {
|
||||
EggCharacterData *char_data = _collection->get_character(ci);
|
||||
char_data->get_root_joint()->do_rebuild();
|
||||
// The meat of the program: determine which joints are to be
|
||||
// removed, and then actually remove them.
|
||||
determine_removed_components();
|
||||
if (remove_joints()) {
|
||||
do_reparent();
|
||||
}
|
||||
|
||||
|
||||
write_eggs();
|
||||
}
|
||||
}
|
||||
@ -105,6 +158,236 @@ handle_args(ProgramBase::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
|
||||
// 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
|
||||
// Access: Private
|
||||
@ -284,20 +590,36 @@ list_scalars(EggCharacterData *char_data) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggOptchar::
|
||||
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();
|
||||
|
||||
EggOptcharUserData *user_data =
|
||||
DCAST(EggOptcharUserData, comp_data->get_user_data());
|
||||
if (user_data->is_identity()) {
|
||||
nout << " (identity)";
|
||||
cout << " (identity)";
|
||||
} else if (user_data->is_static()) {
|
||||
nout << " (static)";
|
||||
cout << " (static)";
|
||||
}
|
||||
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 "pvector.h"
|
||||
#include "vector_string.h"
|
||||
|
||||
class EggCharacterData;
|
||||
class EggComponentData;
|
||||
@ -49,13 +50,35 @@ protected:
|
||||
virtual bool handle_args(Args &args);
|
||||
|
||||
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_sliders(EggCharacterData *char_data);
|
||||
void list_joints(EggJointData *joint_data, int indent_level);
|
||||
void list_joints_p(EggJointData *joint_data);
|
||||
void list_scalars(EggCharacterData *char_data);
|
||||
void describe_component(EggComponentData *comp_data, int indent_level);
|
||||
void do_reparent();
|
||||
|
||||
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
|
||||
|
@ -43,7 +43,8 @@ public:
|
||||
F_static = 0x0001,
|
||||
F_identity = 0x0002,
|
||||
F_empty = 0x0004,
|
||||
F_remove = 0x0008
|
||||
F_remove = 0x0008,
|
||||
F_expose = 0x0010,
|
||||
};
|
||||
int _flags;
|
||||
LMatrix4d _static_mat;
|
||||
|
@ -12,7 +12,8 @@
|
||||
eggCharacterCollection.h eggCharacterCollection.I \
|
||||
eggCharacterData.h eggCharacterData.I eggCharacterFilter.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 \
|
||||
eggSliderData.h eggSliderData.I \
|
||||
eggVertexPointer.h
|
||||
@ -32,7 +33,7 @@
|
||||
eggCharacterData.I eggCharacterData.h eggCharacterFilter.h \
|
||||
eggComponentData.I eggComponentData.h \
|
||||
eggJointData.h eggJointData.I \
|
||||
eggJointPointer.h \
|
||||
eggJointPointer.h eggJointPointer.I \
|
||||
eggJointNodePointer.h \
|
||||
eggMatrixTablePointer.h \
|
||||
eggScalarTablePointer.h \
|
||||
|
@ -112,3 +112,13 @@ get_character_by_model_index(int model_index) const {
|
||||
(EggCharacterData *)NULL);
|
||||
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;
|
||||
for (ti = top_nodes.begin(); ti != top_nodes.end(); ++ti) {
|
||||
EggNode *model_root = (*ti).first;
|
||||
EggNodeList &egg_nodes = (*ti).second;
|
||||
ModelDescription &desc = (*ti).second;
|
||||
|
||||
int model_index = _next_model_index++;
|
||||
if (egg_info._models.empty()) {
|
||||
@ -109,8 +109,9 @@ add_egg(EggData *egg) {
|
||||
char_data->add_model(model_index, model_root);
|
||||
nassertr(model_index == (int)_characters_by_model_index.size(), -1);
|
||||
_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);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
if (group->get_group_type() == EggGroup::GT_joint) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@ -307,12 +312,14 @@ scan_for_top_tables(EggTable *bundle, EggNode *model_root,
|
||||
if (table->get_name() == "<skeleton>") {
|
||||
// Here it is! Now the immediate children of this node are
|
||||
// the top tables.
|
||||
ModelDescription &desc = _top_egg_nodes[character_name][model_root];
|
||||
desc._root_node = table;
|
||||
|
||||
EggGroupNode::iterator cgi;
|
||||
for (cgi = table->begin(); cgi != table->end(); ++cgi) {
|
||||
EggNode *grandchild = (*cgi);
|
||||
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);
|
||||
EggJointData *data = make_joint_data(char_data);
|
||||
joint_data->_children.push_back(data);
|
||||
char_data->_joints.push_back(data);
|
||||
char_data->_components.push_back(data);
|
||||
data->_parent = joint_data;
|
||||
data->_new_parent = joint_data;
|
||||
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);
|
||||
EggJointData *data = make_joint_data(char_data);
|
||||
joint_data->_children.push_back(data);
|
||||
char_data->_joints.push_back(data);
|
||||
char_data->_components.push_back(data);
|
||||
data->_parent = joint_data;
|
||||
data->_new_parent = joint_data;
|
||||
found_egg_match(char_data, data, egg_node, egg_index, model_index);
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,13 @@
|
||||
#ifndef EGGCHARACTERCOLLECTION_H
|
||||
#define EGGCHARACTERCOLLECTION_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
#include "pandatoolbase.h"
|
||||
|
||||
#include "eggCharacterData.h"
|
||||
|
||||
#include <eggData.h>
|
||||
#include <eggNode.h>
|
||||
#include <pointerTo.h>
|
||||
#include "eggData.h"
|
||||
#include "eggNode.h"
|
||||
#include "pointerTo.h"
|
||||
|
||||
class EggTable;
|
||||
class EggAttributes;
|
||||
@ -66,7 +66,7 @@ public:
|
||||
class EggInfo {
|
||||
public:
|
||||
PT(EggData) _egg;
|
||||
typedef pvector<PT(EggNode)> Models;
|
||||
typedef pvector< PT(EggNode) > Models;
|
||||
Models _models;
|
||||
int _first_model_index;
|
||||
};
|
||||
@ -95,7 +95,14 @@ private:
|
||||
// The _top_egg_nodes member is only used temporarily, when adding
|
||||
// each pre-existing egg file to the structure for the first time.
|
||||
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;
|
||||
TopEggNodesByName _top_egg_nodes;
|
||||
|
||||
|
@ -94,6 +94,30 @@ find_joint(const string &name) const {
|
||||
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
|
||||
// Access: Public
|
||||
|
@ -72,6 +72,117 @@ add_model(int model_index, EggNode *model_root) {
|
||||
_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
|
||||
// Access: Public
|
||||
|
@ -68,9 +68,13 @@ public:
|
||||
INLINE int get_num_models() const;
|
||||
INLINE int get_model_index(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 *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 EggSliderData *get_slider(int n) const;
|
||||
@ -100,6 +104,9 @@ protected:
|
||||
typedef pvector<EggSliderData *> Sliders;
|
||||
Sliders _sliders;
|
||||
|
||||
typedef pvector<EggJointData *> Joints;
|
||||
Joints _joints;
|
||||
|
||||
typedef pvector<EggComponentData *> Components;
|
||||
Components _components;
|
||||
|
||||
|
@ -45,6 +45,8 @@ public:
|
||||
void add_name(const string &name);
|
||||
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 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);
|
||||
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)
|
||||
{
|
||||
_parent = (EggJointData *)NULL;
|
||||
_new_parent = (EggJointData *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -66,7 +67,7 @@ find_joint(const string &name) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::get_num_frames
|
||||
// Access: Public
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the number of frames of animation for this
|
||||
// particular joint in the indicated model.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -119,6 +120,26 @@ get_net_frame(int model_index, int n) const {
|
||||
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
|
||||
// Access: Public
|
||||
@ -186,6 +207,7 @@ optimize() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggJointData::
|
||||
add_back_pointer(int model_index, EggObject *egg_object) {
|
||||
nassertv(egg_object != (EggObject *)NULL);
|
||||
if (egg_object->is_of_type(EggGroup::get_class_type())) {
|
||||
// It must be a <Joint>.
|
||||
EggJointNodePointer *joint = new EggJointNodePointer(egg_object);
|
||||
@ -226,3 +248,196 @@ write(ostream &out, int indent_level) const {
|
||||
|
||||
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;
|
||||
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_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();
|
||||
void optimize();
|
||||
|
||||
virtual void add_back_pointer(int model_index, EggObject *egg_object);
|
||||
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:
|
||||
typedef pvector<EggJointData *> Children;
|
||||
Children _children;
|
||||
EggJointData *_parent;
|
||||
|
||||
friend class EggCharacterCollection;
|
||||
EggJointData *_new_parent;
|
||||
|
||||
|
||||
public:
|
||||
@ -77,6 +97,9 @@ public:
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class EggCharacterCollection;
|
||||
friend class EggCharacterData;
|
||||
};
|
||||
|
||||
#include "eggJointData.I"
|
||||
|
@ -35,7 +35,7 @@ EggJointNodePointer::
|
||||
EggJointNodePointer(EggObject *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
|
||||
// it does not, give it the identity transform.
|
||||
if (!_joint->has_transform()) {
|
||||
@ -94,6 +94,46 @@ set_frame(int n, const LMatrix4d &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
|
||||
// Access: Public, Virtual
|
||||
|
@ -38,6 +38,9 @@ public:
|
||||
virtual LMatrix4d get_frame(int n) const;
|
||||
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 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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
// Access: Public
|
||||
|
@ -41,8 +41,13 @@ public:
|
||||
virtual void set_frame(int n, const LMatrix4d &mat)=0;
|
||||
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();
|
||||
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 void optimize();
|
||||
@ -69,6 +74,8 @@ private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "eggJointPointer.I"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -86,6 +86,10 @@ get_frame(int n) const {
|
||||
// If we have exactly one frame, then we have as many frames as we
|
||||
// want; just repeat the first frame.
|
||||
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());
|
||||
@ -122,6 +126,32 @@ add_frame(const LMatrix4d &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
|
||||
// Access: Public, Virtual
|
||||
|
@ -43,6 +43,8 @@ public:
|
||||
virtual void set_frame(int n, const LMatrix4d &mat);
|
||||
virtual bool add_frame(const LMatrix4d &mat);
|
||||
|
||||
virtual void do_finish_reparent(EggJointPointer *new_parent);
|
||||
|
||||
virtual bool do_rebuild();
|
||||
|
||||
virtual void optimize();
|
||||
|
@ -42,7 +42,7 @@ EggSliderData(EggCharacterCollection *collection,
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggSliderData::get_num_frames
|
||||
// Access: Public
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the number of frames of animation for this
|
||||
// particular slider in the indicated model.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
EggSliderData(EggCharacterCollection *collection,
|
||||
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;
|
||||
|
||||
virtual void add_back_pointer(int model_index, EggObject *egg_object);
|
||||
|
Loading…
x
Reference in New Issue
Block a user