Browse Source

add egg-optchar -qa

David Rose 21 years ago
parent
commit
b8ade26846

+ 112 - 7
pandatool/src/egg-optchar/eggOptchar.cxx

@@ -149,11 +149,24 @@ EggOptchar() {
   add_option
     ("q", "quantum", 0,
      "Quantize joint membership values to the given unit.  This is "
-     "the smallest significant change in joint membership.  The "
-     "default is 0.01; specifying 0 means to preserve the original "
-     "values.",
+     "the smallest significant change in joint membership.  There can "
+     "be a significant performance (and memory utilization) runtime "
+     "benefit for eliminating small differences in joint memberships "
+     "between neighboring vertices.  The default is 0.01; specifying "
+     "0 means to preserve the original values.",
      &EggOptchar::dispatch_double, NULL, &_vref_quantum);
 
+  add_option
+    ("qa", "quantum[,hprxyzijkabc]", 0,
+     "Quantizes animation channels to the given unit.  This rounds each "
+     "of the named components of all joints to the nearest multiple of unit.  "
+     "There is no performance benefit, and little compression benefit, "
+     "for doing this; and this may introduce visible artifacts to the "
+     "animation.  However, sometimes it is a useful tool for animation "
+     "analysis and comparison.  This option may be repeated several times "
+     "to quantize different channels by a different amount.",
+     &EggOptchar::dispatch_double_components, NULL, &_quantize_anims);
+
   _optimal_hierarchy = false;
   _vref_quantum = 0.01;
 }
@@ -218,15 +231,18 @@ run() {
       do_reparent();
     }
 
+    // We currently do not implement optimizing morph sliders.  Need
+    // to add this at some point; it's quite easy.  Identity and empty
+    // morph sliders can simply be removed, while static sliders need
+    // to be applied to the vertices and then removed.
+
     // Quantize the vertex memberships.  We call this even if
     // _vref_quantum is 0, because this also normalizes the vertex
     // memberships.
     quantize_vertices();
 
-    // We currently do not implement optimizing morph sliders.  Need
-    // to add this at some point; it's quite easy.  Identity and empty
-    // morph sliders can simply be removed, while static sliders need
-    // to be applied to the vertices and then removed.
+    // Also quantize the animation channels, if the user so requested.
+    quantize_channels();
 
     // Finally, flag all the groups as the user requested.
     if (!_flag_groups.empty()) {
@@ -336,6 +352,63 @@ dispatch_name_components(const string &opt, const string &arg, void *var) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ProgramBase::dispatch_double_components
+//       Access: Protected, Static
+//  Description: Accepts a double value optionally followed by a comma
+//               and some of the nine standard component letters,
+//
+//               The data pointer is to a DoubleStrings vector; the
+//               pair will be pushed onto the end of the vector.
+////////////////////////////////////////////////////////////////////
+bool EggOptchar::
+dispatch_double_components(const string &opt, const string &arg, void *var) {
+  DoubleStrings *ip = (DoubleStrings *)var;
+
+  vector_string words;
+  tokenize(arg, words, ",");
+
+  bool valid_double = false;
+
+  DoubleString sp;
+  if (words.size() == 1) {
+    valid_double = string_to_double(words[0], sp._a);
+
+  } else if (words.size() == 2) {
+    valid_double = string_to_double(words[0], sp._a);
+    sp._b = words[1];
+
+  } else {
+    nout << "-" << opt
+         << " requires a numeric value followed by a string.\n";
+    return false;
+  }
+
+  if (!valid_double) {
+    nout << "-" << opt
+         << " requires a numeric value followed by a string.\n";
+    return false;
+  }
+
+  if (sp._b.empty()) {
+    sp._b = matrix_component_letters;
+  } else {
+    for (string::const_iterator si = sp._b.begin(); si != sp._b.end(); ++si) {
+      if (strchr(matrix_component_letters, *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_component_letters << "\".\n";
+        return false;
+      }
+    }
+  }
+
+  ip->push_back(sp);
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ProgramBase::dispatch_flag_groups
 //       Access: Protected, Static
@@ -775,6 +848,38 @@ zero_channels() {
   return did_anything;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggOptchar::quantize_channels
+//       Access: Private
+//  Description: Quantizes the channels specified by the user on the
+//               command line.
+//
+//               Returns true if any operation was performed, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool EggOptchar::
+quantize_channels() {
+  bool did_anything = false;
+  int num_characters = _collection->get_num_characters();
+
+  DoubleStrings::const_iterator spi;
+  for (spi = _quantize_anims.begin(); spi != _quantize_anims.end(); ++spi) {
+    const DoubleString &p = (*spi);
+
+    for (int ci = 0; ci < num_characters; ci++) {
+      EggCharacterData *char_data = _collection->get_character(ci);
+      EggJointData *joint_data = char_data->get_root_joint();
+
+      if (joint_data != (EggJointData *)NULL) {
+        joint_data->quantize_channels(p._b, p._a);
+        did_anything = true;
+      }
+    }
+  }
+
+  return did_anything;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggOptchar::analyze_joints
 //       Access: Private

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

@@ -54,6 +54,7 @@ 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);
+  static bool dispatch_double_components(const string &opt, const string &arg, void *var);
   static bool dispatch_flag_groups(const string &opt, const string &arg, void *var);
 
   void determine_removed_components();
@@ -64,6 +65,7 @@ private:
 
   bool apply_user_reparents();
   bool zero_channels();
+  bool quantize_channels();
   void analyze_joints(EggJointData *joint_data, int level);
   void analyze_sliders(EggCharacterData *char_data);
   void list_joints(EggJointData *joint_data, int indent_level, bool verbose);
@@ -99,6 +101,14 @@ private:
   vector_string _drop_components;
   vector_string _expose_components;
 
+  class DoubleString {
+  public:
+    double _a;
+    string _b;
+  };
+  typedef pvector<DoubleString> DoubleStrings;
+  DoubleStrings _quantize_anims;
+
   typedef pvector<GlobPattern> Globs;
 
   class FlagGroupsEntry {

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

@@ -400,6 +400,31 @@ zero_channels(const string &components) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggJointData::quantize_channels
+//       Access: Public
+//  Description: Calls quantize_channels() on all models for this joint,
+//               and then recurses downwards to all joints below.
+////////////////////////////////////////////////////////////////////
+void EggJointData::
+quantize_channels(const string &components, double quantum) {
+  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->quantize_channels(components, quantum);
+    }
+  }
+
+  Children::iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    EggJointData *child = (*ci);
+    child->quantize_channels(components, quantum);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggJointData::add_back_pointer
 //       Access: Public, Virtual

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

@@ -61,6 +61,7 @@ public:
   void optimize();
   void expose(EggGroup::DCSType dcs_type = EggGroup::DC_default);
   void zero_channels(const string &components);
+  void quantize_channels(const string &components, double quantum);
 
   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

@@ -125,3 +125,13 @@ expose(EggGroup::DCSType) {
 void EggJointPointer::
 zero_channels(const string &) {
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggJointPointer::quantize_channels
+//       Access: Public, Virtual
+//  Description: Rounds the named components of the transform to the
+//               nearest multiple of quantum.
+////////////////////////////////////////////////////////////////////
+void EggJointPointer::
+quantize_channels(const string &, double) {
+}

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

@@ -63,6 +63,7 @@ public:
   virtual void optimize();
   virtual void expose(EggGroup::DCSType dcs_type);
   virtual void zero_channels(const string &components);
+  virtual void quantize_channels(const string &components, double quantum);
 
   virtual EggJointPointer *make_new_joint(const string &name)=0;
 

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

@@ -250,6 +250,32 @@ zero_channels(const string &components) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggMatrixTablePointer::quantize_channels
+//       Access: Public, Virtual
+//  Description: Rounds the named components of the transform to the
+//               nearest multiple of quantum.
+////////////////////////////////////////////////////////////////////
+void EggMatrixTablePointer::
+quantize_channels(const string &components, double quantum) {
+  if (_xform == (EggXfmSAnim *)NULL) {
+    return;
+  }
+
+  // This is similar to the above: we quantize children of 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 && 
+        child->is_of_type(EggSAnimData::get_class_type())) {
+      EggSAnimData *anim = DCAST(EggSAnimData, child);
+      anim->quantize(quantum);
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMatrixTablePointer::make_new_joint
 //       Access: Public, Virtual

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

@@ -50,6 +50,7 @@ public:
 
   virtual void optimize();
   virtual void zero_channels(const string &components);
+  virtual void quantize_channels(const string &components, double quantum);
 
   virtual EggJointPointer *make_new_joint(const string &name);