Browse Source

add egg-optchar -new joint,parent

David Rose 22 years ago
parent
commit
36638ab984

+ 49 - 5
pandatool/src/egg-optchar/eggOptchar.cxx

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

+ 1 - 0
pandatool/src/egg-optchar/eggOptchar.h

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

+ 16 - 0
pandatool/src/eggcharbase/eggCharacterData.I

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

+ 27 - 2
pandatool/src/eggcharbase/eggCharacterData.cxx

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

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

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

+ 1 - 0
pandatool/src/eggcharbase/eggJointData.I

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

+ 67 - 1
pandatool/src/eggcharbase/eggJointData.cxx

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

+ 6 - 0
pandatool/src/eggcharbase/eggJointData.h

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

+ 14 - 0
pandatool/src/eggcharbase/eggJointNodePointer.cxx

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

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

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

+ 2 - 0
pandatool/src/eggcharbase/eggJointPointer.h

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

+ 21 - 0
pandatool/src/eggcharbase/eggMatrixTablePointer.cxx

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

+ 2 - 0
pandatool/src/eggcharbase/eggMatrixTablePointer.h

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