Browse Source

add -zero, etc.

David Rose 22 years ago
parent
commit
6b7baa43d7

+ 168 - 14
pandatool/src/egg-optchar/eggOptchar.cxx

@@ -30,6 +30,7 @@
 #include "string_utils.h"
 #include "dcast.h"
 #include "pset.h"
+#include "compose_matrix.h"
 
 #include <algorithm>
 
@@ -76,6 +77,14 @@ EggOptchar() {
      "and objects can be parented to it.  This implies -keep.",
      &EggOptchar::dispatch_vector_string_comma, NULL, &_expose_components);
 
+  add_option
+    ("zero", "joint[,hprxyzijk]", 0,
+     "Zeroes out the animation channels for the named joint.  If "
+     "a subset of the component letters hprxyzijk is included, the "
+     "operation is restricted to just those components; otherwise the "
+     "entire transform is cleared.",
+     &EggOptchar::dispatch_name_components, NULL, &_zero_channels);
+
   add_option
     ("keepall", "", 0,
      "Keep all joints and sliders in the character.",
@@ -117,6 +126,10 @@ run() {
     do_reparent();
   }
 
+  if (!_zero_channels.empty()) {
+    zero_channels();
+  }
+
   int num_characters = _collection->get_num_characters();
   int ci;
 
@@ -150,6 +163,7 @@ run() {
     // The meat of the program: determine which joints are to be
     // removed, and then actually remove them.
     determine_removed_components();
+    move_vertices();
     if (process_joints()) {
       do_reparent();
     }
@@ -215,6 +229,55 @@ dispatch_vector_string_pair(const string &opt, const string &arg, void *var) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ProgramBase::dispatch_name_components
+//       Access: Protected, Static
+//  Description: Accepts a name optionally followed by a comma and some
+//               of the nine standard component letters,
+//
+//               The data pointer is to StringPairs vector; the pair
+//               will be pushed onto the end of the vector.
+////////////////////////////////////////////////////////////////////
+bool EggOptchar::
+dispatch_name_components(const string &opt, const string &arg, void *var) {
+  StringPairs *ip = (StringPairs *)var;
+
+  vector_string words;
+  tokenize(arg, words, ",");
+
+  StringPair sp;
+  if (words.size() == 1) {
+    sp._a = words[0];
+
+  } else if (words.size() == 2) {
+    sp._a = words[0];
+    sp._b = words[1];
+
+  } else {
+    nout << "-" << opt
+         << " requires a pair of strings separated by a comma.\n";
+    return false;
+  }
+
+  if (sp._b.empty()) {
+    sp._b = matrix_components;
+  } else {
+    for (string::const_iterator si = sp._b.begin(); si != sp._b.end(); ++si) {
+      if (strchr(matrix_components, *si) == NULL) {
+        nout << "Not a standard matrix component: \"" << *si << "\"\n"
+             << "-" << opt << " requires a joint name followed by a set "
+             << "of component names.  The standard component names are \"" 
+             << matrix_components << "\".\n";
+        return false;
+      }
+    }
+  }
+
+  ip->push_back(sp);
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggOptchar::determine_removed_components
 //       Access: Private
@@ -284,6 +347,43 @@ determine_removed_components() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggOptchar::move_vertices
+//       Access: Private
+//  Description: Moves the vertices from joints that are about to be
+//               removed into the first suitable parent.  This might
+//               result in fewer joints being removed (because
+//               the parent might suddenly no longer be empty).
+////////////////////////////////////////////////////////////////////
+void EggOptchar::
+move_vertices() {
+  int num_characters = _collection->get_num_characters();
+  for (int ci = 0; ci < num_characters; ci++) {
+    EggCharacterData *char_data = _collection->get_character(ci);
+    int num_joints = char_data->get_num_joints();
+    
+    for (int i = 0; i < num_joints; i++) {
+      EggJointData *joint_data = char_data->get_joint(i);
+      EggOptcharUserData *user_data = 
+        DCAST(EggOptcharUserData, joint_data->get_user_data());
+
+      if ((user_data->_flags & EggOptcharUserData::F_empty) == 0 &&
+          (user_data->_flags & EggOptcharUserData::F_remove) != 0) {
+        // This joint has vertices, but is scheduled to be removed;
+        // find a suitable home for its vertices.
+        EggJointData *best_joint = find_best_vertex_joint(joint_data->get_parent());
+        joint_data->move_vertices_to(best_joint);
+
+        // Now we can't remove the joint.
+        EggOptcharUserData *best_user_data = 
+          DCAST(EggOptcharUserData, best_joint->get_user_data());
+        best_user_data->_flags &= ~(EggOptcharUserData::F_empty | EggOptcharUserData::F_remove);
+      }
+    }
+  }
+}
+      
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggOptchar::process_joints
 //       Access: Private
@@ -310,16 +410,10 @@ process_joints() {
       EggOptcharUserData *user_data = 
         DCAST(EggOptcharUserData, joint_data->get_user_data());
       
-      EggJointData *best_parent = find_best_parent(joint_data->get_parent());
-      
       if ((user_data->_flags & EggOptcharUserData::F_remove) != 0) {
         // This joint will be removed, so reparent it to nothing.
         joint_data->reparent_to((EggJointData *)NULL);
         
-        // Move the vertices associated with this joint into its
-        // parent.
-        joint_data->move_vertices_to(best_parent);
-        
         // Determine what kind of node it is we're removing, for the
         // user's information.
         if ((user_data->_flags & EggOptcharUserData::F_identity) != 0) {
@@ -334,6 +428,7 @@ process_joints() {
       } else {
         // This joint will be preserved, but maybe its parent will
         // change.
+        EggJointData *best_parent = find_best_parent(joint_data->get_parent());
         joint_data->reparent_to(best_parent);
         if ((user_data->_flags & EggOptcharUserData::F_expose) != 0) {
           joint_data->expose();
@@ -348,7 +443,7 @@ process_joints() {
     } else {
       nout << char_data->get_name() << ": of " << num_joints 
            << " joints, removing " << num_identity << " identity, "
-           << num_static << " static, and " << num_empty
+           << num_static << " unanimated, and " << num_empty
            << " empty joints, leaving " << num_kept << ".\n";
     }
   }
@@ -359,7 +454,7 @@ process_joints() {
 ////////////////////////////////////////////////////////////////////
 //     Function: EggOptchar::find_best_parent
 //       Access: Private
-//  Description: Searches for this first joint at this level or above
+//  Description: Searches for the first joint at this level or above
 //               that is not scheduled to be removed.  This is the
 //               joint that the first child of this joint should be
 //               reparented to.
@@ -371,8 +466,32 @@ find_best_parent(EggJointData *joint_data) const {
 
   if ((user_data->_flags & EggOptcharUserData::F_remove) != 0) {
     // Keep going.
-    nassertr(joint_data->get_parent() != (EggJointData *)NULL, NULL);
-    return find_best_parent(joint_data->get_parent());
+    if (joint_data->get_parent() != (EggJointData *)NULL) {
+      return find_best_parent(joint_data->get_parent());
+    }
+  }
+
+  // This is the one!
+  return joint_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggOptchar::find_best_vertex_joint
+//       Access: Private
+//  Description: Searches for the first joint at this level or above
+//               that is not static.  This is the joint that the
+//               vertices of this joint should be moved into.
+////////////////////////////////////////////////////////////////////
+EggJointData *EggOptchar::
+find_best_vertex_joint(EggJointData *joint_data) const {
+  EggOptcharUserData *user_data = 
+    DCAST(EggOptcharUserData, joint_data->get_user_data());
+
+  if ((user_data->_flags & EggOptcharUserData::F_static) != 0) {
+    // Keep going.
+    if (joint_data->get_parent() != (EggJointData *)NULL) {
+      return find_best_vertex_joint(joint_data->get_parent());
+    }
   }
 
   // This is the one!
@@ -419,6 +538,41 @@ apply_user_reparents() {
   return did_anything;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggOptchar::zero_channels
+//       Access: Private
+//  Description: Zeroes out the channels specified by the user on the
+//               command line.
+//
+//               Returns true if any operation was performed, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool EggOptchar::
+zero_channels() {
+  bool did_anything = false;
+  int num_characters = _collection->get_num_characters();
+
+  StringPairs::const_iterator spi;
+  for (spi = _zero_channels.begin(); spi != _zero_channels.end(); ++spi) {
+    const StringPair &p = (*spi);
+
+    for (int ci = 0; ci < num_characters; ci++) {
+      EggCharacterData *char_data = _collection->get_character(ci);
+      EggJointData *joint_data = char_data->find_joint(p._a);
+
+      if (joint_data == (EggJointData *)NULL) {
+        nout << "No joint named " << p._a << " in " << char_data->get_name()
+             << ".\n";
+      } else {
+        joint_data->zero_channels(p._b);
+        did_anything = true;
+      }
+    }
+  }
+
+  return did_anything;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggOptchar::analyze_joints
 //       Access: Private
@@ -458,7 +612,7 @@ analyze_joints(EggJointData *joint_data) {
 
         } else {
           // This is a second or later matrix.
-          if (!mat.almost_equal(user_data->_static_mat)) {
+          if (!mat.almost_equal(user_data->_static_mat, 0.0001)) {
             // It's different than the first one.
             different_mat = true;
           }
@@ -472,7 +626,7 @@ analyze_joints(EggJointData *joint_data) {
     user_data->_flags |= EggOptcharUserData::F_static;
 
     if (num_mats == 0 || 
-        user_data->_static_mat.almost_equal(LMatrix4d::ident_mat())) {
+        user_data->_static_mat.almost_equal(LMatrix4d::ident_mat(), 0.0001)) {
       // It's not only static, but it's the identity matrix.
       user_data->_flags |= EggOptcharUserData::F_identity;
     }
@@ -531,7 +685,7 @@ analyze_sliders(EggCharacterData *char_data) {
             
           } else {
             // This is a second or later value.
-            if (!IS_NEARLY_EQUAL(value, user_data->_static_value)) {
+            if (!IS_THRESHOLD_EQUAL(value, user_data->_static_value, 0.0001)) {
               // It's different than the first one.
               different_value = true;
             }
@@ -544,7 +698,7 @@ analyze_sliders(EggCharacterData *char_data) {
       // All the values are the same for this slider.
       user_data->_flags |= EggOptcharUserData::F_static;
       
-      if (num_values == 0 || IS_NEARLY_EQUAL(user_data->_static_value, 0.0)) {
+      if (num_values == 0 || IS_THRESHOLD_ZERO(user_data->_static_value, 0.0001)) {
         // It's not only static, but it's the identity value.
         user_data->_flags |= EggOptcharUserData::F_identity;
       }

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

@@ -51,12 +51,16 @@ protected:
 
 private:
   static bool dispatch_vector_string_pair(const string &opt, const string &arg, void *var);
+  static bool dispatch_name_components(const string &opt, const string &arg, void *var);
 
   void determine_removed_components();
+  void move_vertices();
   bool process_joints();
   EggJointData *find_best_parent(EggJointData *joint_data) const;
+  EggJointData *find_best_vertex_joint(EggJointData *joint_data) const;
 
   bool apply_user_reparents();
+  bool zero_channels();
   void analyze_joints(EggJointData *joint_data);
   void analyze_sliders(EggCharacterData *char_data);
   void list_joints(EggJointData *joint_data, int indent_level);
@@ -80,6 +84,7 @@ private:
   };
   typedef pvector<StringPair> StringPairs;
   StringPairs _reparent_joints;
+  StringPairs _zero_channels;
 
   vector_string _keep_components;
   vector_string _expose_components;

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

@@ -175,8 +175,13 @@ do_reparent() {
     // hierarchy.
     if (joint_data->get_parent() != (EggJointData *)NULL) {
       nout << "Warning: reparenting " << joint_data->get_name()
-           << " to " << joint_data->get_parent()->get_name()
-           << " results in a skew transform.\n";
+           << " to ";
+      if (joint_data->get_parent() == _root_joint) {
+        nout << "the root";
+      } else {
+        nout << joint_data->get_parent()->get_name();
+      }
+      nout << " results in a skew transform.\n";
     }
   }
 

+ 25 - 0
pandatool/src/eggcharbase/eggJointData.cxx

@@ -224,6 +224,31 @@ expose(EggGroup::DCSType dcs_type) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggJointData::zero_channels
+//       Access: Public
+//  Description: Calls zero_channels() on all models, and recursively on
+//               all joints at this node and below.
+////////////////////////////////////////////////////////////////////
+void EggJointData::
+zero_channels(const string &components) {
+  BackPointers::iterator bpi;
+  for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) {
+    EggBackPointer *back = (*bpi);
+    if (back != (EggBackPointer *)NULL) {
+      EggJointPointer *joint;
+      DCAST_INTO_V(joint, back);
+      joint->zero_channels(components);
+    }
+  }
+
+  Children::iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    EggJointData *child = (*ci);
+    child->zero_channels(components);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggJointData::add_back_pointer
 //       Access: Public, Virtual

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

@@ -53,6 +53,7 @@ public:
   bool do_rebuild();
   void optimize();
   void expose(EggGroup::DCSType dcs_type = EggGroup::DC_default);
+  void zero_channels(const string &components);
 
   virtual void add_back_pointer(int model_index, EggObject *egg_object);
   virtual void write(ostream &out, int indent_level = 0) const;

+ 10 - 0
pandatool/src/eggcharbase/eggJointPointer.cxx

@@ -115,3 +115,13 @@ optimize() {
 void EggJointPointer::
 expose(EggGroup::DCSType) {
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggJointPointer::zero_channels
+//       Access: Public, Virtual
+//  Description: Zeroes out the named components of the transform in
+//               the animation frames.
+////////////////////////////////////////////////////////////////////
+void EggJointPointer::
+zero_channels(const string &) {
+}

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

@@ -52,6 +52,7 @@ public:
 
   virtual void optimize();
   virtual void expose(EggGroup::DCSType dcs_type);
+  virtual void zero_channels(const string &components);
 
 protected:
   typedef pvector<LMatrix4d> RebuildFrames;

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

@@ -200,3 +200,27 @@ optimize() {
     _xform->optimize();
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMatrixTablePointer::zero_channels
+//       Access: Public, Virtual
+//  Description: Zeroes out the named components of the transform in
+//               the animation frames.
+////////////////////////////////////////////////////////////////////
+void EggMatrixTablePointer::
+zero_channels(const string &components) {
+  if (_xform == (EggXfmSAnim *)NULL) {
+    return;
+  }
+
+  // This is particularly easy: we only have to remove children from
+  // the _xform object whose name is listed in the components.
+  string::const_iterator si;
+  for (si = components.begin(); si != components.end(); ++si) {
+    string table_name(1, *si);
+    EggNode *child = _xform->find_child(table_name);
+    if (child != (EggNode *)NULL) {
+      _xform->remove_child(child);
+    }
+  }
+}

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

@@ -48,6 +48,7 @@ public:
   virtual bool do_rebuild();
 
   virtual void optimize();
+  virtual void zero_channels(const string &components);
 
 private:
   PT(EggTable) _table;