Browse Source

reduce memory usage for egg-optchar

David Rose 19 years ago
parent
commit
9b67ed9caf

+ 9 - 3
pandatool/src/eggcharbase/Sources.pp

@@ -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 \

+ 51 - 7
pandatool/src/eggcharbase/eggCharacterData.cxx

@@ -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

+ 4 - 1
pandatool/src/eggcharbase/eggCharacterData.h

@@ -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:

+ 47 - 0
pandatool/src/eggcharbase/eggCharacterDb.I

@@ -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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     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;
+}

+ 143 - 0
pandatool/src/eggcharbase/eggCharacterDb.cxx

@@ -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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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);
+}

+ 93 - 0
pandatool/src/eggcharbase/eggCharacterDb.h

@@ -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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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
+
+

+ 76 - 73
pandatool/src/eggcharbase/eggJointData.cxx

@@ -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;
 }

+ 12 - 10
pandatool/src/eggcharbase/eggJointData.h

@@ -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;

+ 8 - 24
pandatool/src/eggcharbase/eggJointNodePointer.cxx

@@ -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;
 }
 

+ 1 - 2
pandatool/src/eggcharbase/eggJointNodePointer.h

@@ -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;

+ 0 - 113
pandatool/src/eggcharbase/eggJointPointer.I

@@ -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];
-}

+ 2 - 35
pandatool/src/eggcharbase/eggJointPointer.cxx

@@ -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;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 22
pandatool/src/eggcharbase/eggJointPointer.h

@@ -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;

+ 13 - 6
pandatool/src/eggcharbase/eggMatrixTablePointer.cxx

@@ -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)) {
+  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;
 }
 

+ 1 - 1
pandatool/src/eggcharbase/eggMatrixTablePointer.h

@@ -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);

+ 1 - 0
pandatool/src/eggcharbase/eggcharbase_composite1.cxx

@@ -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"

+ 10 - 9
pandatool/src/eggprogs/eggRetargetAnim.cxx

@@ -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);
   }
 }
 

+ 3 - 1
pandatool/src/eggprogs/eggRetargetAnim.h

@@ -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;

+ 12 - 17
pandatool/src/eggprogs/eggTopstrip.cxx

@@ -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);

+ 4 - 2
pandatool/src/eggprogs/eggTopstrip.h

@@ -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;