reduce memory usage for egg-optchar

This commit is contained in:
David Rose 2006-10-06 22:57:43 +00:00
parent fa2e6e4992
commit 9b67ed9caf
20 changed files with 495 additions and 328 deletions

View File

@ -13,8 +13,11 @@
#define SOURCES \
config_eggcharbase.h eggBackPointer.h \
eggCharacterCollection.h eggCharacterCollection.I \
eggCharacterData.h eggCharacterData.I eggCharacterFilter.h \
eggComponentData.h eggComponentData.I eggJointData.h \
eggCharacterData.h eggCharacterData.I \
eggCharacterDb.I eggCharacterDb.h \
eggCharacterFilter.h \
eggComponentData.h eggComponentData.I \
eggJointData.h \
eggJointData.I eggJointPointer.h eggJointPointer.I \
eggJointNodePointer.h \
eggMatrixTablePointer.h eggScalarTablePointer.h \
@ -24,6 +27,7 @@
#define INCLUDED_SOURCES \
config_eggcharbase.cxx eggBackPointer.cxx \
eggCharacterCollection.cxx eggCharacterData.cxx \
eggCharacterDb.cxx \
eggCharacterFilter.cxx eggComponentData.cxx eggJointData.cxx \
eggJointPointer.cxx eggJointNodePointer.cxx \
eggMatrixTablePointer.cxx eggScalarTablePointer.cxx \
@ -34,7 +38,9 @@
#define INSTALL_HEADERS \
eggBackPointer.h \
eggCharacterCollection.I eggCharacterCollection.h \
eggCharacterData.I eggCharacterData.h eggCharacterFilter.h \
eggCharacterData.I eggCharacterData.h \
eggCharacterDb.I eggCharacterDb.h \
eggCharacterFilter.h \
eggComponentData.I eggComponentData.h \
eggJointData.h eggJointData.I \
eggJointPointer.h eggJointPointer.I \

View File

@ -18,6 +18,7 @@
#include "eggCharacterData.h"
#include "eggCharacterCollection.h"
#include "eggCharacterDb.h"
#include "eggJointData.h"
#include "eggSliderData.h"
#include "indent.h"
@ -227,8 +228,13 @@ do_reparent() {
// frame.
Models::const_iterator mi;
for (mi = _models.begin(); mi != _models.end(); ++mi) {
EggCharacterDb db;
int model_index = (*mi)._model_index;
int num_frames = get_num_frames(model_index);
nout << " computing " << (mi - _models.begin()) + 1
<< " of " << _models.size()
<< ": " << (*mi)._egg_data->get_egg_filename()
<< " (" << num_frames << " frames)\n";
for (int f = 0; f < num_frames; f++) {
// First, walk through all the joints and flush the computed net
// transforms from before.
@ -242,20 +248,26 @@ do_reparent() {
// 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)) {
if (!joint_data->do_compute_reparent(model_index, f, db)) {
// Oops, we got an invalid transform.
invalid_set.insert(joint_data);
}
}
}
// Finally, apply the computations to the joints.
for (ji = _joints.begin(); ji != _joints.end(); ++ji) {
EggJointData *joint_data = (*ji);
if (!joint_data->do_joint_rebuild(model_index, db)) {
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);
}
joint_data->do_finish_reparent();
}
// Report the set of joints that failed. It really shouldn't be
@ -299,19 +311,21 @@ do_reparent() {
////////////////////////////////////////////////////////////////////
void EggCharacterData::
choose_optimal_hierarchy() {
EggCharacterDb db;
Joints::const_iterator ji, jj;
for (ji = _joints.begin(); ji != _joints.end(); ++ji) {
EggJointData *joint_data = (*ji);
EggJointData *best_parent = joint_data->get_parent();
int best_score = joint_data->score_reparent_to(best_parent);
int best_score = joint_data->score_reparent_to(best_parent, db);
for (jj = _joints.begin(); jj != _joints.end(); ++jj) {
EggJointData *possible_parent = (*jj);
if (possible_parent != joint_data && possible_parent != best_parent &&
!joint_data->is_new_ancestor(possible_parent)) {
int score = joint_data->score_reparent_to(possible_parent);
int score = joint_data->score_reparent_to(possible_parent, db);
if (score >= 0 && (best_score < 0 || score < best_score)) {
best_parent = possible_parent;
best_score = score;
@ -322,7 +336,7 @@ choose_optimal_hierarchy() {
// Also consider reparenting the node to the root.
EggJointData *possible_parent = get_root_joint();
if (possible_parent != best_parent) {
int score = joint_data->score_reparent_to(possible_parent);
int score = joint_data->score_reparent_to(possible_parent, db);
if (score >= 0 && (best_score < 0 || score < best_score)) {
best_parent = possible_parent;
best_score = score;
@ -377,6 +391,36 @@ make_slider(const string &name) {
return slider;
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::estimate_db_size
// Access: Public
// Description: Returns the estimated amount of memory, in megabytes,
// that will be required to perform the do_reparent()
// operation. This is used mainly be EggCharacterDb to
// decide up front whether to store this data in-RAM or
// on-disk.
////////////////////////////////////////////////////////////////////
size_t EggCharacterData::
estimate_db_size() const {
// Count how much memory we will need to store the interim
// transforms. This is models * joints * frames * 3 *
// sizeof(LMatrix4d).
size_t mj_frames = 0;
Models::const_iterator mi;
for (mi = _models.begin(); mi != _models.end(); ++mi) {
int model_index = (*mi)._model_index;
size_t num_frames = (size_t)get_num_frames(model_index);
mj_frames += num_frames * _joints.size();
}
// We do this operation a bit carefully, to guard against integer
// overflow.
size_t mb_needed = ((mj_frames * 3 / 1024) * sizeof(LMatrix4d)) / 1024;
return mb_needed;
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterData::write
// Access: Public, Virtual

View File

@ -22,7 +22,6 @@
#include "pandatoolbase.h"
#include "eggJointData.h"
#include "eggNode.h"
#include "eggData.h"
#include "pointerTo.h"
@ -33,6 +32,7 @@
class EggCharacterCollection;
class EggSliderData;
class EggCharacterDb;
////////////////////////////////////////////////////////////////////
// Class : EggCharacterData
@ -81,6 +81,7 @@ public:
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();
void choose_optimal_hierarchy();
@ -92,6 +93,8 @@ public:
INLINE int get_num_components() const;
INLINE EggComponentData *get_component(int n) const;
size_t estimate_db_size() const;
virtual void write(ostream &out, int indent_level = 0) const;
private:

View File

@ -0,0 +1,47 @@
// Filename: eggCharacterDb.I
// Created by: drose (05Oct06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: EggCharacterDb::Key::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE EggCharacterDb::Key::
Key(const EggJointPointer *joint, TableType table_type, int frame) :
_joint(joint),
_table_type(table_type),
_frame(frame)
{
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterDb::Key::operator <
// Access: Public
// Description: Provides an arbitrary unique ordering for all keys.
////////////////////////////////////////////////////////////////////
INLINE bool EggCharacterDb::Key::
operator < (const EggCharacterDb::Key &other) const {
if (_joint != other._joint) {
return _joint < other._joint;
}
if (_table_type != other._table_type) {
return _table_type < other._table_type;
}
return _frame < other._frame;
}

View File

@ -0,0 +1,143 @@
// Filename: eggCharacterDb.cxx
// Created by: drose (05Oct06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "eggCharacterDb.h"
#include "eggCharacterData.h"
////////////////////////////////////////////////////////////////////
// Function: EggCharacterDb::Constructor
// Access: Public
// Description: Constructs a database for storing the interim work
// for the indicated EggCharacterData. The parameter
// max_ram_mb indicates the maximum amount of RAM (in
// MB) that the database should consume; if it the
// database would roughly fit within this limit, it will
// be stored in RAM; otherwise, it will be written to
// disk (if Berkeley DB is available).
////////////////////////////////////////////////////////////////////
EggCharacterDb::
EggCharacterDb() {
/*
#ifdef HAVE_BDB
_db = NULL;
_db = new Db(NULL, 0);
_db_filename = Filename::temporary("", "eggc_", ".db");
string os_db_filename = _db_filename.to_os_specific();
_db->open(NULL, os_db_filename.c_str(), NULL,
DB_BTREE, DB_CREATE | DB_EXCL, 0);
nout << "Using " << os_db_filename << " for rebuild database.\n";
#endif // HAVE_BDB
*/
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterDb::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
EggCharacterDb::
~EggCharacterDb() {
/*
#ifdef HAVE_BDB
if (_db != (Db *)NULL){
_db->close(0);
delete _db;
_db = NULL;
string os_db_filename = _db_filename.to_os_specific();
Db rmdb(NULL, 0);
rmdb.remove(os_db_filename.c_str(), NULL, 0);
}
#endif // HAVE_BDB
*/
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterDb::get_matrix
// Access: Public
// Description: Looks up the data for the indicated joint, type, and
// frame, and fills it in result (and returns true) if
// it is found. Returns false if this data has not been
// stored in the database.
////////////////////////////////////////////////////////////////////
bool EggCharacterDb::
get_matrix(const EggJointPointer *joint, TableType type,
int frame, LMatrix4d &mat) const {
Key key(joint, type, frame);
/*
#ifdef HAVE_BDB
if (_db != (Db *)NULL){
Dbt db_key(&key, sizeof(Key));
Dbt db_data(&mat, sizeof(LMatrix4d));
db_data.set_ulen(sizeof(LMatrix4d));
db_data.set_flags(DB_DBT_USERMEM);
int result = _db->get(NULL, &db_key, &db_data, 0);
if (result == DB_NOTFOUND) {
return false;
}
nassertr(result == 0, false);
return true;
}
#endif // HAVE_BDB
*/
Table::const_iterator ti;
ti = _table.find(key);
if (ti == _table.end()) {
return false;
}
mat = (*ti).second;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: EggCharacterDb::set_matrix
// Access: Public
// Description: Stores the matrix for the indicated joint, type, and
// frame in the database. It is an error to call this
// more than once for any given key combination (not for
// any technical reason, but because we don't expect
// this to happen).
////////////////////////////////////////////////////////////////////
void EggCharacterDb::
set_matrix(const EggJointPointer *joint, TableType type,
int frame, const LMatrix4d &mat) {
Key key(joint, type, frame);
/*
#ifdef HAVE_BDB
if (_db != (Db *)NULL){
Dbt db_key(&key, sizeof(Key));
Dbt db_data((void *)&mat, sizeof(LMatrix4d));
int result = _db->put(NULL, &db_key, &db_data, DB_NOOVERWRITE);
nassertv(result != DB_KEYEXIST);
nassertv(result == 0);
return;
}
#endif // HAVE_BDB
*/
bool inserted = _table.insert(Table::value_type(key, mat)).second;
nassertv(inserted);
}

View File

@ -0,0 +1,93 @@
// Filename: eggCharacterDb.h
// Created by: drose (05Oct06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef EGGCHARACTERDB_H
#define EGGCHARACTERDB_H
#include "pandatoolbase.h"
#include "pmap.h"
/*
#ifdef HAVE_BDB
// Apparently, we have to define this to make db_cxx files include the
// modern header files.
#define HAVE_CXX_STDHEADERS 1
#include <db_cxx.h>
#endif // HAVE_BDB
*/
class EggJointPointer;
////////////////////////////////////////////////////////////////////
// Class : EggCharacterDb
// Description : This class is used during joint optimization or
// restructuring to store the table of interim joint
// computations.
//
// That is to say, this class provides an temporary data
// store for three tables of matrices per each
// EggJointPointer per frame.
////////////////////////////////////////////////////////////////////
class EggCharacterDb {
public:
EggCharacterDb();
~EggCharacterDb();
enum TableType {
TT_rebuild_frame,
TT_net_frame,
TT_net_frame_inv,
};
bool get_matrix(const EggJointPointer *joint, TableType type,
int frame, LMatrix4d &mat) const;
void set_matrix(const EggJointPointer *joint, TableType type,
int frame, const LMatrix4d &mat);
private:
class Key {
public:
INLINE Key(const EggJointPointer *joint,
TableType table_type,
int frame);
INLINE bool operator < (const Key &other) const;
private:
const EggJointPointer *_joint;
TableType _table_type;
int _frame;
};
/*
#ifdef HAVE_BDB
Db *_db;
Filename _db_filename;
#endif // HAVE_BDB
*/
typedef pmap<Key, LMatrix4d> Table;
Table _table;
};
#include "eggCharacterDb.I"
#endif

View File

@ -74,7 +74,7 @@ get_frame(int model_index, int n) const {
// in the indicated model.
////////////////////////////////////////////////////////////////////
LMatrix4d EggJointData::
get_net_frame(int model_index, int n) const {
get_net_frame(int model_index, int n, EggCharacterDb &db) const {
EggBackPointer *back = get_model(model_index);
if (back == (EggBackPointer *)NULL) {
return LMatrix4d::ident_mat();
@ -82,23 +82,18 @@ get_net_frame(int model_index, int n) const {
EggJointPointer *joint;
DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
if (joint->get_num_net_frames() < n) {
// Recursively get the previous frame's net, so we have a place to
// stuff this frame's value.
get_net_frame(model_index, n - 1);
}
if (joint->get_num_net_frames() == n) {
LMatrix4d mat;
if (!db.get_matrix(joint, EggCharacterDb::TT_net_frame, n, mat)) {
// Compute this frame's net, and stuff it in.
LMatrix4d mat = get_frame(model_index, n);
mat = get_frame(model_index, n);
if (_parent != (EggJointData *)NULL) {
mat = mat * _parent->get_net_frame(model_index, n);
mat = mat * _parent->get_net_frame(model_index, n, db);
}
joint->add_net_frame(mat);
db.set_matrix(joint, EggCharacterDb::TT_net_frame, n, mat);
}
return joint->get_net_frame(n);
return mat;
}
////////////////////////////////////////////////////////////////////
@ -107,7 +102,7 @@ get_net_frame(int model_index, int n) const {
// Description: Returns the inverse of get_net_frame().
////////////////////////////////////////////////////////////////////
LMatrix4d EggJointData::
get_net_frame_inv(int model_index, int n) const {
get_net_frame_inv(int model_index, int n, EggCharacterDb &db) const {
EggBackPointer *back = get_model(model_index);
if (back == (EggBackPointer *)NULL) {
return LMatrix4d::ident_mat();
@ -116,20 +111,15 @@ get_net_frame_inv(int model_index, int n) const {
EggJointPointer *joint;
DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
if (joint->get_num_net_frame_invs() < n) {
// Recursively get the previous frame's net, so we have a place to
// stuff this frame's value.
get_net_frame_inv(model_index, n - 1);
}
if (joint->get_num_net_frame_invs() == n) {
LMatrix4d mat;
if (!db.get_matrix(joint, EggCharacterDb::TT_net_frame_inv, n, mat)) {
// Compute this frame's net inverse, and stuff it in.
LMatrix4d mat = get_net_frame(model_index, n);
LMatrix4d mat = get_net_frame(model_index, n, db);
mat.invert_in_place();
joint->add_net_frame_inv(mat);
db.set_matrix(joint, EggCharacterDb::TT_net_frame_inv, n, mat);
}
return joint->get_net_frame_inv(n);
return mat;
}
////////////////////////////////////////////////////////////////////
@ -202,7 +192,7 @@ move_vertices_to(EggJointData *new_owner) {
// error.
////////////////////////////////////////////////////////////////////
int EggJointData::
score_reparent_to(EggJointData *new_parent) {
score_reparent_to(EggJointData *new_parent, EggCharacterDb &db) {
if (!FFTCompressor::is_compression_available()) {
// If we don't have compression compiled in, we can't meaningfully
// score the joints.
@ -232,17 +222,17 @@ score_reparent_to(EggJointData *new_parent) {
} else if (_parent == (EggJointData *)NULL) {
// We are moving from outside the joint hierarchy to within it.
transform = new_parent->get_net_frame_inv(model_index, n);
transform = new_parent->get_net_frame_inv(model_index, n, db);
} else if (new_parent == (EggJointData *)NULL) {
// We are moving from within the hierarchy to outside it.
transform = _parent->get_net_frame(model_index, n);
transform = _parent->get_net_frame(model_index, n, db);
} else {
// We are changing parents within the hierarchy.
transform =
_parent->get_net_frame(model_index, n) *
new_parent->get_net_frame_inv(model_index, n);
_parent->get_net_frame(model_index, n, db) *
new_parent->get_net_frame_inv(model_index, n, db);
}
transform = joint->get_frame(n) * transform;
@ -304,14 +294,14 @@ score_reparent_to(EggJointData *new_parent) {
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::do_rebuild
// Function: EggJointData::do_rebuild_all
// Access: Public
// Description: Calls do_rebuild() on all models, and recursively on
// all joints at this node and below. Returns true if
// all models returned true, false otherwise.
////////////////////////////////////////////////////////////////////
bool EggJointData::
do_rebuild() {
do_rebuild_all(EggCharacterDb &db) {
bool all_ok = true;
BackPointers::iterator bpi;
@ -320,7 +310,7 @@ do_rebuild() {
if (back != (EggBackPointer *)NULL) {
EggJointPointer *joint;
DCAST_INTO_R(joint, back, false);
if (!joint->do_rebuild()) {
if (!joint->do_rebuild(db)) {
all_ok = false;
}
}
@ -329,7 +319,7 @@ do_rebuild() {
Children::iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
EggJointData *child = (*ci);
if (!child->do_rebuild()) {
if (!child->do_rebuild_all(db)) {
all_ok = false;
}
}
@ -497,15 +487,6 @@ void EggJointData::
do_begin_reparent() {
_got_new_parent_depth = false;
_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();
}
}
}
////////////////////////////////////////////////////////////////////
@ -568,7 +549,7 @@ do_begin_compute_reparent() {
// false on failure.
////////////////////////////////////////////////////////////////////
bool EggJointData::
do_compute_reparent(int model_index, int n) {
do_compute_reparent(int model_index, int n, EggCharacterDb &db) {
if (_computed_reparent) {
// We've already done this joint. This is possible because we
// have to recursively compute joints upwards, so we might visit
@ -597,52 +578,73 @@ do_compute_reparent(int model_index, int n) {
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);
transform = _new_parent->get_new_net_frame_inv(model_index, n, db);
} else if (_new_parent == (EggJointData *)NULL) {
// We are moving from within the hierarchy to outside it.
transform = _parent->get_net_frame(model_index, n);
transform = _parent->get_net_frame(model_index, n, db);
} else {
// We are changing parents within the hierarchy.
transform =
_parent->get_net_frame(model_index, n) *
_new_parent->get_new_net_frame_inv(model_index, n);
_parent->get_net_frame(model_index, n, db) *
_new_parent->get_new_net_frame_inv(model_index, n, db);
}
nassertr(n == joint->get_num_rebuild_frames(), false);
db.set_matrix(joint, EggCharacterDb::TT_rebuild_frame, n,
joint->get_frame(n) * transform);
_computed_ok = true;
_computed_ok = joint->add_rebuild_frame(joint->get_frame(n) * transform);
return _computed_ok;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointData::do_joint_rebuild
// Access: Protected
// Description: Calls do_rebuild() on the joint for the indicated
// model index. Returns true on success, false on
// failure (false shouldn't be possible).
////////////////////////////////////////////////////////////////////
bool EggJointData::
do_joint_rebuild(int model_index, EggCharacterDb &db) {
bool all_ok = true;
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);
if (!joint->do_rebuild(db)) {
all_ok = false;
}
}
return all_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.
// them with the set of new children.
////////////////////////////////////////////////////////////////////
bool EggJointData::
void 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);
DCAST_INTO_V(parent_joint, _new_parent->get_model(model_index));
}
if (has_model(model_index)) {
EggJointPointer *joint;
DCAST_INTO_R(joint, get_model(model_index), false);
DCAST_INTO_V(joint, get_model(model_index));
joint->do_finish_reparent(parent_joint);
joint->clear_net_frames();
if (!joint->do_rebuild()) {
all_ok = false;
}
}
}
@ -650,8 +652,6 @@ do_finish_reparent() {
if (_parent != (EggJointData *)NULL) {
_parent->_children.push_back(this);
}
return all_ok;
}
////////////////////////////////////////////////////////////////////
@ -760,11 +760,11 @@ is_new_ancestor(EggJointData *child) const {
// useful only when called within do_compute_reparent().
////////////////////////////////////////////////////////////////////
const LMatrix4d &EggJointData::
get_new_net_frame(int model_index, int n) {
get_new_net_frame(int model_index, int n, EggCharacterDb &db) {
if (!_got_new_net_frame) {
_new_net_frame = get_new_frame(model_index, n);
_new_net_frame = get_new_frame(model_index, n, db);
if (_new_parent != (EggJointData *)NULL) {
_new_net_frame = _new_net_frame * _new_parent->get_new_net_frame(model_index, n);
_new_net_frame = _new_net_frame * _new_parent->get_new_net_frame(model_index, n, db);
}
_got_new_net_frame = true;
}
@ -777,11 +777,11 @@ get_new_net_frame(int model_index, int n) {
// Description: Returns the inverse of get_new_net_frame().
////////////////////////////////////////////////////////////////////
const LMatrix4d &EggJointData::
get_new_net_frame_inv(int model_index, int n) {
get_new_net_frame_inv(int model_index, int n, EggCharacterDb &db) {
if (!_got_new_net_frame_inv) {
_new_net_frame_inv.invert_from(get_new_frame(model_index, n));
_new_net_frame_inv.invert_from(get_new_frame(model_index, n, db));
if (_new_parent != (EggJointData *)NULL) {
_new_net_frame_inv = _new_parent->get_new_net_frame_inv(model_index, n) * _new_net_frame_inv;
_new_net_frame_inv = _new_parent->get_new_net_frame_inv(model_index, n, db) * _new_net_frame_inv;
}
_got_new_net_frame_inv = true;
}
@ -797,8 +797,8 @@ get_new_net_frame_inv(int model_index, int n) {
// called.
////////////////////////////////////////////////////////////////////
LMatrix4d EggJointData::
get_new_frame(int model_index, int n) {
do_compute_reparent(model_index, n);
get_new_frame(int model_index, int n, EggCharacterDb &db) {
do_compute_reparent(model_index, n, db);
EggBackPointer *back = get_model(model_index);
if (back == (EggBackPointer *)NULL) {
@ -808,9 +808,12 @@ get_new_frame(int model_index, int n) {
EggJointPointer *joint;
DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
if (joint->get_num_rebuild_frames() > 0) {
return joint->get_rebuild_frame(n);
} else {
LMatrix4d mat;
if (!db.get_matrix(joint, EggCharacterDb::TT_rebuild_frame, n, mat)) {
// No rebuild frame; return the regular frame.
return joint->get_frame(n);
}
// Return the rebuild frame, as computed.
return mat;
}

View File

@ -20,12 +20,13 @@
#define EGGJOINTDATA_H
#include "pandatoolbase.h"
#include "eggComponentData.h"
#include "eggGroup.h"
#include "luse.h"
#include "pset.h"
class EggCharacterDb;
////////////////////////////////////////////////////////////////////
// Class : EggJointData
// Description : This is one node of a hierarchy of EggJointData
@ -45,8 +46,8 @@ public:
INLINE EggJointData *find_joint(const string &name);
LMatrix4d get_frame(int model_index, int n) const;
LMatrix4d get_net_frame(int model_index, int n) const;
LMatrix4d get_net_frame_inv(int model_index, int n) const;
LMatrix4d get_net_frame(int model_index, int n, EggCharacterDb &db) const;
LMatrix4d get_net_frame_inv(int model_index, int n, EggCharacterDb &db) const;
INLINE bool has_rest_frame() const;
INLINE bool rest_frames_differ() const;
@ -55,9 +56,9 @@ public:
INLINE void reparent_to(EggJointData *new_parent);
void move_vertices_to(EggJointData *new_owner);
int score_reparent_to(EggJointData *new_parent);
int score_reparent_to(EggJointData *new_parent, EggCharacterDb &db);
bool do_rebuild();
bool do_rebuild_all(EggCharacterDb &db);
void optimize();
void expose(EggGroup::DCSType dcs_type = EggGroup::DC_default);
void zero_channels(const string &components);
@ -70,8 +71,9 @@ 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();
bool do_compute_reparent(int model_index, int n, EggCharacterDb &db);
bool do_joint_rebuild(int model_index, EggCharacterDb &db);
void do_finish_reparent();
private:
EggJointData *make_new_joint(const string &name);
@ -79,9 +81,9 @@ private:
EggJointData *find_joint_matches(const string &name);
bool is_new_ancestor(EggJointData *child) const;
const LMatrix4d &get_new_net_frame(int model_index, int n);
const LMatrix4d &get_new_net_frame_inv(int model_index, int n);
LMatrix4d get_new_frame(int model_index, int n);
const LMatrix4d &get_new_net_frame(int model_index, int n, EggCharacterDb &db);
const LMatrix4d &get_new_net_frame_inv(int model_index, int n, EggCharacterDb &db);
LMatrix4d get_new_frame(int model_index, int n, EggCharacterDb &db);
bool _has_rest_frame;
bool _rest_frames_differ;

View File

@ -140,23 +140,6 @@ move_vertices_to(EggJointPointer *new_joint) {
}
}
////////////////////////////////////////////////////////////////////
// Function: EggJointNodePointer::add_rebuild_frame
// Access: Public, Virtual
// Description: Adds a new frame to the set of rebuild frames. See
// begin_rebuild() and do_rebuild(). Returns true if
// this is valid, false otherwise (e.g. adding multiple
// frames to a static joint).
////////////////////////////////////////////////////////////////////
bool EggJointNodePointer::
add_rebuild_frame(const LMatrix4d &mat) {
if (!_rebuild_frames.empty()) {
// Only one frame may be added to a <Joint>.
return false;
}
return EggJointPointer::add_rebuild_frame(mat);
}
////////////////////////////////////////////////////////////////////
// Function: EggJointNodePointer::do_rebuild
// Access: Public, Virtual
@ -171,17 +154,18 @@ add_rebuild_frame(const LMatrix4d &mat) {
// acceptable, or false if there is some problem.
////////////////////////////////////////////////////////////////////
bool EggJointNodePointer::
do_rebuild() {
if (_rebuild_frames.empty()) {
do_rebuild(EggCharacterDb &db) {
LMatrix4d mat;
if (!db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, 0, mat)) {
// No rebuild frame; this is OK.
return true;
}
if (_rebuild_frames.size() != 1) {
return false;
}
_joint->set_transform3d(mat);
_joint->set_transform3d(_rebuild_frames[0]);
_rebuild_frames.clear();
// We shouldn't have a frame 1.
nassertr(!db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, 1, mat), false);
return true;
}

View File

@ -41,8 +41,7 @@ public:
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();
virtual bool do_rebuild(EggCharacterDb &db);
virtual void expose(EggGroup::DCSType dcs_type);
virtual bool has_vertices() const;

View File

@ -16,116 +16,3 @@
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// 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];
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::clear_net_frames
// Access: Public
// Description: Resets the cache of net frames for this joint.
////////////////////////////////////////////////////////////////////
INLINE void EggJointPointer::
clear_net_frames() {
_net_frames.clear();
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::add_net_frame
// Access: Public, Virtual
// Description: Adds a new frame to the set of net frames. This is
// used to cache the net transform from the root for
// this particular joint.
////////////////////////////////////////////////////////////////////
INLINE void EggJointPointer::
add_net_frame(const LMatrix4d &mat) {
_net_frames.push_back(mat);
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::get_num_net_frames
// Access: Public
// Description: Returns the number of net frames that have been
// added so far.
////////////////////////////////////////////////////////////////////
INLINE int EggJointPointer::
get_num_net_frames() const {
return _net_frames.size();
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::get_net_frame
// Access: Public
// Description: Returns the nth matrix that has been added to the set
// of net frames.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4d &EggJointPointer::
get_net_frame(int n) const {
nassertr(n >= 0 && n < (int)_net_frames.size(), LMatrix4d::ident_mat());
return _net_frames[n];
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::clear_net_frame_invs
// Access: Public
// Description: Resets the cache of net_inv frames for this joint.
////////////////////////////////////////////////////////////////////
INLINE void EggJointPointer::
clear_net_frame_invs() {
_net_frame_invs.clear();
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::add_net_frame_inv
// Access: Public, Virtual
// Description: Adds a new frame to the set of net_inv frames. This is
// used to cache the inverse net transform from the root
// for this particular joint.
////////////////////////////////////////////////////////////////////
INLINE void EggJointPointer::
add_net_frame_inv(const LMatrix4d &mat) {
_net_frame_invs.push_back(mat);
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::get_num_net_frame_invs
// Access: Public
// Description: Returns the number of net_inv frames that have been
// added so far.
////////////////////////////////////////////////////////////////////
INLINE int EggJointPointer::
get_num_net_frame_invs() const {
return _net_frame_invs.size();
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::get_net_frame_inv
// Access: Public
// Description: Returns the nth matrix that has been added to the set
// of net_inv frames.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4d &EggJointPointer::
get_net_frame_inv(int n) const {
nassertr(n >= 0 && n < (int)_net_frame_invs.size(), LMatrix4d::ident_mat());
return _net_frame_invs[n];
}

View File

@ -44,35 +44,6 @@ void EggJointPointer::
move_vertices_to(EggJointPointer *) {
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::begin_rebuild
// Access: Public
// Description: Resets the set of rebuild frames in preparation for
// rebuilding the complete table of frames. Repeated
// calls to add_rebuild_frame() will build up the frames
// without changing the values returned by get_frame();
// the table will eventually be updated when do_rebuild
// is called.
////////////////////////////////////////////////////////////////////
void EggJointPointer::
begin_rebuild() {
_rebuild_frames.clear();
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::add_rebuild_frame
// Access: Public, Virtual
// Description: Adds a new frame to the set of rebuild frames. See
// begin_rebuild() and do_rebuild(). Returns true if
// this is valid, false otherwise (e.g. adding multiple
// frames to a static joint).
////////////////////////////////////////////////////////////////////
bool EggJointPointer::
add_rebuild_frame(const LMatrix4d &mat) {
_rebuild_frames.push_back(mat);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: EggJointPointer::do_rebuild
// Access: Public, Virtual
@ -87,12 +58,8 @@ add_rebuild_frame(const LMatrix4d &mat) {
// acceptable, or false if there is some problem.
////////////////////////////////////////////////////////////////////
bool EggJointPointer::
do_rebuild() {
if (_rebuild_frames.empty()) {
return true;
}
_rebuild_frames.clear();
return false;
do_rebuild(EggCharacterDb &db) {
return true;
}
////////////////////////////////////////////////////////////////////

View File

@ -20,11 +20,12 @@
#define EGGJOINTPOINTER_H
#include "pandatoolbase.h"
#include "eggBackPointer.h"
#include "eggGroup.h"
#include "luse.h"
class EggCharacterDb;
////////////////////////////////////////////////////////////////////
// Class : EggJointPointer
// Description : This is a base class for EggJointNodePointer and
@ -44,21 +45,7 @@ public:
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();
INLINE void clear_net_frames();
INLINE void add_net_frame(const LMatrix4d &mat);
INLINE int get_num_net_frames() const;
INLINE const LMatrix4d &get_net_frame(int n) const;
INLINE void clear_net_frame_invs();
INLINE void add_net_frame_inv(const LMatrix4d &mat);
INLINE int get_num_net_frame_invs() const;
INLINE const LMatrix4d &get_net_frame_inv(int n) const;
virtual bool do_rebuild(EggCharacterDb &db);
virtual void optimize();
virtual void expose(EggGroup::DCSType dcs_type);
@ -67,12 +54,6 @@ public:
virtual EggJointPointer *make_new_joint(const string &name)=0;
protected:
typedef pvector<LMatrix4d> RebuildFrames;
RebuildFrames _rebuild_frames;
RebuildFrames _net_frames;
RebuildFrames _net_frame_invs;
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -189,8 +189,10 @@ do_finish_reparent(EggJointPointer *new_parent) {
// acceptable, or false if there is some problem.
////////////////////////////////////////////////////////////////////
bool EggMatrixTablePointer::
do_rebuild() {
if (_rebuild_frames.empty()) {
do_rebuild(EggCharacterDb &db) {
LMatrix4d mat;
if (!db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, 0, mat)) {
// No rebuild frame; this is OK.
return true;
}
@ -201,14 +203,19 @@ do_rebuild() {
bool all_ok = true;
_xform->clear_data();
RebuildFrames::const_iterator fi;
for (fi = _rebuild_frames.begin(); fi != _rebuild_frames.end(); ++fi) {
if (!_xform->add_data(*fi)) {
all_ok = false;
}
if (!_xform->add_data(mat)) {
all_ok = false;
}
// Assume all frames will be contiguous.
int n = 1;
while (db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, n, mat)) {
if (!_xform->add_data(mat)) {
all_ok = false;
}
++n;
}
_rebuild_frames.clear();
return all_ok;
}

View File

@ -46,7 +46,7 @@ public:
virtual void do_finish_reparent(EggJointPointer *new_parent);
virtual bool do_rebuild();
virtual bool do_rebuild(EggCharacterDb &db);
virtual void optimize();
virtual void zero_channels(const string &components);

View File

@ -3,6 +3,7 @@
#include "eggBackPointer.cxx"
#include "eggCharacterCollection.cxx"
#include "eggCharacterData.cxx"
#include "eggCharacterDb.cxx"
#include "eggCharacterFilter.cxx"
#include "eggComponentData.cxx"
#include "eggJointData.cxx"

View File

@ -22,6 +22,7 @@
#include "eggJointData.h"
#include "eggCharacterCollection.h"
#include "eggCharacterData.h"
#include "eggCharacterDb.h"
#include "eggJointPointer.h"
#include "eggTable.h"
#include "compose_matrix.h"
@ -127,9 +128,10 @@ run() {
keep_names.insert(*si);
}
EggCharacterDb db;
EggJointData *root_joint = char_data->get_root_joint();
retarget_anim(char_data, root_joint, reference_model, keep_names);
root_joint->do_rebuild();
retarget_anim(char_data, root_joint, reference_model, keep_names, db);
root_joint->do_rebuild_all(db);
write_eggs();
}
@ -143,7 +145,8 @@ run() {
////////////////////////////////////////////////////////////////////
void EggRetargetAnim::
retarget_anim(EggCharacterData *char_data, EggJointData *joint_data,
int reference_model, const pset<string> &keep_names) {
int reference_model, const pset<string> &keep_names,
EggCharacterDb &db) {
if (keep_names.find(joint_data->get_name()) != keep_names.end()) {
// Don't retarget this joint; keep the translation and scale and whatever.
@ -176,11 +179,9 @@ retarget_anim(EggCharacterData *char_data, EggJointData *joint_data,
nout << "Could not decompose matrix for " << joint_data->get_name()
<< "\n";
}
if (!joint->add_rebuild_frame(mat)) {
nout << "Unable to combine animations.\n";
exit(1);
}
db.set_matrix(joint, EggCharacterDb::TT_rebuild_frame,
f, mat);
}
}
}
@ -190,7 +191,7 @@ retarget_anim(EggCharacterData *char_data, EggJointData *joint_data,
int num_children = joint_data->get_num_children();
for (int i = 0; i < num_children; i++) {
EggJointData *next_joint_data = joint_data->get_child(i);
retarget_anim(char_data, next_joint_data, reference_model, keep_names);
retarget_anim(char_data, next_joint_data, reference_model, keep_names, db);
}
}

View File

@ -28,6 +28,7 @@
class EggCharacterData;
class EggJointData;
class EggCharacterDb;
////////////////////////////////////////////////////////////////////
// Class : EggRetargetAnim
@ -43,7 +44,8 @@ public:
void run();
void retarget_anim(EggCharacterData *char_data, EggJointData *joint_data,
int reference_model, const pset<string> &keep_names);
int reference_model, const pset<string> &keep_names,
EggCharacterDb &db);
Filename _reference_filename;
vector_string _keep_joints;

View File

@ -22,6 +22,7 @@
#include "eggJointData.h"
#include "eggCharacterCollection.h"
#include "eggCharacterData.h"
#include "eggCharacterDb.h"
#include "eggJointPointer.h"
#include "eggTable.h"
#include "compose_matrix.h"
@ -125,6 +126,8 @@ run() {
}
// Now process each character.
EggCharacterDb db;
int ci;
for (ci = 0; ci < num_characters; ci++) {
EggCharacterData *char_data = _collection->get_character(ci);
@ -163,7 +166,7 @@ run() {
int num_children = root_joint->get_num_children();
for (int i = 0; i < num_children; i++) {
EggJointData *joint_data = root_joint->get_child(i);
strip_anim(char_data, joint_data, from_model, from_char, top_joint);
strip_anim(char_data, joint_data, from_model, from_char, top_joint, db);
}
// We also need to transform the vertices for any models involved
@ -173,7 +176,7 @@ run() {
EggNode *node = char_data->get_model_root(m);
if (!node->is_of_type(EggTable::get_class_type())) {
strip_anim_vertices(node, char_data->get_model_index(m),
from_model, top_joint);
from_model, top_joint, db);
}
}
}
@ -181,7 +184,7 @@ run() {
// 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();
char_data->get_root_joint()->do_rebuild_all(db);
}
write_eggs();
@ -235,11 +238,10 @@ check_transform_channels() {
void EggTopstrip::
strip_anim(EggCharacterData *char_data, EggJointData *joint_data,
int from_model, EggCharacterData *from_char,
EggJointData *top_joint) {
EggJointData *top_joint, EggCharacterDb &db) {
int num_models = joint_data->get_num_models();
for (int i = 0; i < num_models; i++) {
int model = (from_model < 0) ? i : from_model;
if (joint_data->has_model(i)) {
if (!top_joint->has_model(model)) {
nout << "Warning: Joint " << top_joint->get_name()
@ -258,23 +260,16 @@ strip_anim(EggCharacterData *char_data, EggJointData *joint_data,
DCAST_INTO_V(joint, back);
// Compute and apply the new transforms.
joint->begin_rebuild();
int f;
for (f = 0; f < num_frames; f++) {
LMatrix4d into = joint_data->get_frame(i, f % num_into_frames);
LMatrix4d from = top_joint->get_net_frame(model, f % num_from_frames);
LMatrix4d from = top_joint->get_net_frame(model, f % num_from_frames, db);
adjust_transform(from);
if (!joint->add_rebuild_frame(into * from)) {
nout <<
"Cannot apply multiple frames of animation to a model file.\n"
"In general, -r cannot be used when a model file is being "
"adjusted, unless the named source is a one-frame animation "
"file, or another model file.\n";
exit(1);
}
db.set_matrix(joint, EggCharacterDb::TT_rebuild_frame,
f, into * from);
}
}
}
@ -288,7 +283,7 @@ strip_anim(EggCharacterData *char_data, EggJointData *joint_data,
////////////////////////////////////////////////////////////////////
void EggTopstrip::
strip_anim_vertices(EggNode *egg_node, int into_model, int from_model,
EggJointData *top_joint) {
EggJointData *top_joint, EggCharacterDb &db) {
int model = (from_model < 0) ? into_model : from_model;
if (!top_joint->has_model(model)) {
nout << "Warning: Joint " << top_joint->get_name()
@ -296,7 +291,7 @@ strip_anim_vertices(EggNode *egg_node, int into_model, int from_model,
return;
}
LMatrix4d from = top_joint->get_net_frame(model, 0);
LMatrix4d from = top_joint->get_net_frame(model, 0, db);
adjust_transform(from);
egg_node->transform_vertices_only(from);

View File

@ -27,6 +27,7 @@
#include "pvector.h"
class EggCharacterData;
class EggCharacterDb;
class EggJointData;
class EggJointPointer;
@ -47,9 +48,10 @@ public:
void strip_anim(EggCharacterData *char_data, EggJointData *joint_data,
int from_model, EggCharacterData *from_char,
EggJointData *top_joint);
EggJointData *top_joint, EggCharacterDb &db);
void strip_anim_vertices(EggNode *egg_node, int into_model,
int from_model, EggJointData *top_joint);
int from_model, EggJointData *top_joint,
EggCharacterDb &db);
void adjust_transform(LMatrix4d &mat) const;