mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
add egg-optchar -new joint,parent
This commit is contained in:
parent
3e2948ec8c
commit
36638ab984
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,7 @@ private:
|
||||
string _b;
|
||||
};
|
||||
typedef pvector<StringPair> StringPairs;
|
||||
StringPairs _new_joints;
|
||||
StringPairs _reparent_joints;
|
||||
StringPairs _zero_channels;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -63,6 +63,7 @@ find_joint(const string &name) {
|
||||
return joint;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggJointData::has_rest_frame
|
||||
// Access: Public
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -47,6 +47,8 @@ public:
|
||||
|
||||
virtual bool has_vertices() const;
|
||||
|
||||
virtual EggJointPointer *make_new_joint(const string &name);
|
||||
|
||||
private:
|
||||
PT(EggGroup) _joint;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user