add egg-optchar -new joint,parent

This commit is contained in:
David Rose 2003-10-21 04:08:56 +00:00
parent 3e2948ec8c
commit 36638ab984
13 changed files with 210 additions and 9 deletions

View File

@ -124,6 +124,12 @@ EggOptchar() {
"is not affected (the effect is similar to NodePath::wrt_reparent_to).",
&EggOptchar::dispatch_vector_string_pair, NULL, &_reparent_joints);
add_option
("new", "joint,source", 0,
"Creates a new joint under the named parent joint. The new "
"joint will inherit the same net transform as its parent.",
&EggOptchar::dispatch_vector_string_pair, NULL, &_new_joints);
if (FFTCompressor::is_compression_available()) {
add_option
("optimal", "", 0,
@ -652,7 +658,37 @@ apply_user_reparents() {
int num_characters = _collection->get_num_characters();
// First, get the new joints.
StringPairs::const_iterator spi;
for (spi = _new_joints.begin(); spi != _new_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_b == (EggJointData *)NULL) {
nout << "No joint named " << p._b << " in " << char_data->get_name()
<< ".\n";
} else if (node_a != (EggJointData *)NULL) {
nout << "Joint " << p._a << " already exists in "
<< char_data->get_name() << ".\n";
} else {
nout << "Creating new joint " << p._a << " in "
<< char_data->get_name() << ".\n";
node_a = char_data->make_new_joint(p._a, node_b);
did_anything = true;
}
}
}
// Now get the user reparents.
for (spi = _reparent_joints.begin(); spi != _reparent_joints.end(); ++spi) {
const StringPair &p = (*spi);
@ -664,12 +700,12 @@ apply_user_reparents() {
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) {
if (node_b == (EggJointData *)NULL) {
nout << "No joint named " << p._b << " in " << char_data->get_name()
<< ".\n";
} else if (node_a == (EggJointData *)NULL) {
nout << "No joint named " << p._a << " in " << char_data->get_name()
<< ".\n";
} else {
node_a->reparent_to(node_b);
did_anything = true;
@ -973,10 +1009,18 @@ describe_component(EggComponentData *comp_data, int indent_level,
////////////////////////////////////////////////////////////////////
void EggOptchar::
do_reparent() {
bool all_ok = true;
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();
if (!char_data->do_reparent()) {
all_ok = false;
}
}
if (!all_ok) {
exit(1);
}
}

View File

@ -91,6 +91,7 @@ private:
string _b;
};
typedef pvector<StringPair> StringPairs;
StringPairs _new_joints;
StringPairs _reparent_joints;
StringPairs _zero_channels;

View File

@ -107,6 +107,22 @@ find_joint(const string &name) const {
return _root_joint->find_joint(name);
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::make_new_joint
// Access: Public
// Description: Creates a new joint as a child of the indicated joint
// and returns it. The new joint will be initialized to
// the identity transform, so that in inherits the
// net transform of the indicated parent joint.
////////////////////////////////////////////////////////////////////
INLINE EggJointData *EggCharacterData::
make_new_joint(const string &name, EggJointData *parent) {
EggJointData *joint = parent->make_new_joint(name);
_joints.push_back(joint);
_components.push_back(joint);
return joint;
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::get_num_joints
// Access: Public

View File

@ -20,9 +20,20 @@
#include "eggCharacterCollection.h"
#include "eggJointData.h"
#include "eggSliderData.h"
#include "indent.h"
#include <algorithm>
// An STL function object to sort the joint list in order from highest
// to lowest in the new hierarchy. Used in do_reparent().
class OrderJointsByNewDepth {
public:
bool operator()(const EggJointData *a, const EggJointData *b) const {
return a->_new_parent_depth < b->_new_parent_depth;
}
};
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::Constructor
// Access: Public
@ -165,7 +176,7 @@ do_reparent() {
typedef pset<EggJointData *> InvalidSet;
InvalidSet invalid_set;
// First, make sure the list of new_children is accurate.
// To begin, 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);
@ -176,6 +187,20 @@ do_reparent() {
// finish_reparent) applied to it.
_root_joint->do_begin_reparent();
// Now, check for cycles in the new parenting hierarchy, and also
// sort the joints in order from top to bottom in the new hierarchy.
for (ji = _joints.begin(); ji != _joints.end(); ++ji) {
EggJointData *joint_data = (*ji);
pset<EggJointData *> chain;
if (joint_data->calc_new_parent_depth(chain)) {
nout << "Cycle detected in parent chain for " << joint_data->get_name()
<< "!\n";
return false;
}
}
sort(_joints.begin(), _joints.end(), OrderJointsByNewDepth());
// 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

View File

@ -76,6 +76,7 @@ public:
INLINE EggJointData *get_root_joint() const;
INLINE EggJointData *find_joint(const string &name) const;
INLINE EggJointData *make_new_joint(const string &name, EggJointData *parent);
INLINE int get_num_joints() const;
INLINE EggJointData *get_joint(int n) const;
bool do_reparent();
@ -91,7 +92,7 @@ public:
virtual void write(ostream &out, int indent_level = 0) const;
protected:
private:
class Model {
public:
int _model_index;

View File

@ -63,6 +63,7 @@ find_joint(const string &name) {
return joint;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::has_rest_frame
// Access: Public

View File

@ -191,7 +191,7 @@ move_vertices_to(EggJointData *new_owner) {
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::score_reparent
// Function: EggJointData::score_reparent_to
// Access: Public
// Description: Computes a score >= 0 reflecting the similarity of
// the current joint's animation (in world space) to
@ -470,6 +470,7 @@ write(ostream &out, int indent_level) const {
////////////////////////////////////////////////////////////////////
void EggJointData::
do_begin_reparent() {
_got_new_parent_depth = false;
_children.clear();
int num_models = get_num_models();
@ -482,6 +483,42 @@ do_begin_reparent() {
}
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::calc_new_parent_depth
// Access: Protected
// Description: Calculates the number of joints above this joint in its
// intended position, as specified by a recent call to
// reparent_to(), and also checks for a cycle in the new
// parent chain. Returns true if a cycle is detected,
// and false otherwise. If a cycle is not detected,
// _new_parent_depth can be consulted for the depth in
// the new hierarchy.
//
// This is used by EggCharacterData::do_reparent() to
// determine the order in which to apply the reparent
// operations. It should be called after
// do_begin_reparent().
////////////////////////////////////////////////////////////////////
bool EggJointData::
calc_new_parent_depth(pset<EggJointData *> &chain) {
if (_got_new_parent_depth) {
return false;
}
if (_new_parent == (EggJointData *)NULL) {
// Here's the top of the new hierarchy.
_got_new_parent_depth = true;
_new_parent_depth = 0;
return false;
}
if (!chain.insert(this).second) {
// We've already visited this joint; that means there's a cycle.
return true;
}
bool cycle = _new_parent->calc_new_parent_depth(chain);
_new_parent_depth = _new_parent->_new_parent_depth + 1;
return cycle;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::do_begin_compute_reparent
// Access: Protected
@ -592,6 +629,35 @@ do_finish_reparent() {
return all_ok;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::make_new_joint
// Access: Private
// Description: Creates a new joint as a child of this joint and
// returns it. This is intended to be called only from
// EggCharacterData::make_new_joint().
////////////////////////////////////////////////////////////////////
EggJointData *EggJointData::
make_new_joint(const string &name) {
EggJointData *child = new EggJointData(_collection, _char_data);
child->set_name(name);
child->_parent = this;
child->_new_parent = this;
_children.push_back(child);
// Also create new back pointers in each of the models.
int num_models = get_num_models();
for (int i = 0; i < num_models; i++) {
if (has_model(i)) {
EggJointPointer *joint;
DCAST_INTO_R(joint, get_model(i), NULL);
EggJointPointer *new_joint = joint->make_new_joint(name);
child->set_model(i, new_joint);
}
}
return child;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::find_joint_exact
// Access: Private

View File

@ -24,6 +24,7 @@
#include "eggComponentData.h"
#include "eggGroup.h"
#include "luse.h"
#include "pset.h"
////////////////////////////////////////////////////////////////////
// Class : EggJointData
@ -66,11 +67,13 @@ public:
protected:
void do_begin_reparent();
bool calc_new_parent_depth(pset<EggJointData *> &chain);
void do_begin_compute_reparent();
bool do_compute_reparent(int model_index, int n);
bool do_finish_reparent();
private:
EggJointData *make_new_joint(const string &name);
EggJointData *find_joint_exact(const string &name);
EggJointData *find_joint_matches(const string &name);
@ -95,6 +98,8 @@ protected:
Children _children;
EggJointData *_parent;
EggJointData *_new_parent;
int _new_parent_depth;
bool _got_new_parent_depth;
public:
@ -116,6 +121,7 @@ private:
friend class EggCharacterCollection;
friend class EggCharacterData;
friend class OrderJointsByNewDepth;
};
#include "eggJointData.I"

View File

@ -213,3 +213,17 @@ has_vertices() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointNodePointer::make_new_joint
// Access: Public, Virtual
// Description: Creates a new child of the current joint in the
// egg data, and returns a pointer to it.
////////////////////////////////////////////////////////////////////
EggJointPointer *EggJointNodePointer::
make_new_joint(const string &name) {
EggGroup *new_joint = new EggGroup(name);
new_joint->set_group_type(EggGroup::GT_joint);
_joint->add_child(new_joint);
return new EggJointNodePointer(new_joint);
}

View File

@ -47,6 +47,8 @@ public:
virtual bool has_vertices() const;
virtual EggJointPointer *make_new_joint(const string &name);
private:
PT(EggGroup) _joint;

View File

@ -64,6 +64,8 @@ public:
virtual void expose(EggGroup::DCSType dcs_type);
virtual void zero_channels(const string &components);
virtual EggJointPointer *make_new_joint(const string &name)=0;
protected:
typedef pvector<LMatrix4d> RebuildFrames;
RebuildFrames _rebuild_frames;

View File

@ -249,3 +249,24 @@ zero_channels(const string &components) {
}
}
}
////////////////////////////////////////////////////////////////////
// Function: EggMatrixTablePointer::make_new_joint
// Access: Public, Virtual
// Description: Creates a new child of the current joint in the
// egg data, and returns a pointer to it.
////////////////////////////////////////////////////////////////////
EggJointPointer *EggMatrixTablePointer::
make_new_joint(const string &name) {
EggTable *new_table = new EggTable(name);
_table->add_child(new_table);
CoordinateSystem cs = CS_default;
if (_xform != (EggXfmSAnim *)NULL) {
cs = _xform->get_coordinate_system();
}
EggXfmSAnim *new_xform = new EggXfmSAnim("xform", cs);
new_table->add_child(new_xform);
new_xform->add_data(LMatrix4d::ident_mat());
return new EggMatrixTablePointer(new_table);
}

View File

@ -51,6 +51,8 @@ public:
virtual void optimize();
virtual void zero_channels(const string &components);
virtual EggJointPointer *make_new_joint(const string &name);
private:
PT(EggTable) _table;
PT(EggXfmSAnim) _xform;