Browse Source

support blend shapes

David Rose 22 years ago
parent
commit
aa297d26ee

+ 1 - 0
pandatool/src/mayaegg/Sources.pp

@@ -17,6 +17,7 @@
   #define SOURCES \
   #define SOURCES \
     config_mayaegg.cxx config_mayaegg.h \
     config_mayaegg.cxx config_mayaegg.h \
     mayaEggGroupUserData.cxx mayaEggGroupUserData.I mayaEggGroupUserData.h \
     mayaEggGroupUserData.cxx mayaEggGroupUserData.I mayaEggGroupUserData.h \
+    mayaBlendDesc.cxx mayaBlendDesc.h \
     mayaNodeDesc.cxx mayaNodeDesc.h \
     mayaNodeDesc.cxx mayaNodeDesc.h \
     mayaNodeTree.cxx mayaNodeTree.h \
     mayaNodeTree.cxx mayaNodeTree.h \
     mayaToEggConverter.cxx mayaToEggConverter.h
     mayaToEggConverter.cxx mayaToEggConverter.h

+ 2 - 0
pandatool/src/mayaegg/config_mayaegg.cxx

@@ -19,6 +19,7 @@
 #include "config_mayaegg.h"
 #include "config_mayaegg.h"
 #include "mayaEggGroupUserData.h"
 #include "mayaEggGroupUserData.h"
 #include "mayaNodeDesc.h"
 #include "mayaNodeDesc.h"
+#include "mayaBlendDesc.h"
 
 
 #include "dconfig.h"
 #include "dconfig.h"
 
 
@@ -60,6 +61,7 @@ init_libmayaegg() {
 
 
   MayaEggGroupUserData::init_type();
   MayaEggGroupUserData::init_type();
   MayaNodeDesc::init_type();
   MayaNodeDesc::init_type();
+  MayaBlendDesc::init_type();
 
 
   // For some reason, static init is not reliably running when this is
   // For some reason, static init is not reliably running when this is
   // loaded as a plug-in of a plug-in.  Initialize these explicitly
   // loaded as a plug-in of a plug-in.  Initialize these explicitly

+ 80 - 0
pandatool/src/mayaegg/mayaBlendDesc.cxx

@@ -0,0 +1,80 @@
+// Filename: mayaBlendDesc.cxx
+// Created by:  drose (10Feb04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "mayaBlendDesc.h"
+
+TypeHandle MayaBlendDesc::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaBlendDesc::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+MayaBlendDesc::
+MayaBlendDesc(MFnBlendShapeDeformer deformer, int weight_index) :
+  _deformer(deformer),
+  _weight_index(weight_index)
+{
+  ostringstream strm;
+  strm << _deformer.name().asChar() << "." << _weight_index;
+  set_name(strm.str());
+
+  _anim = (EggSAnimData *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaBlendDesc::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+MayaBlendDesc::
+~MayaBlendDesc() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaBlendDesc::set_slider
+//       Access: Public
+//  Description: Moves the Maya slider associated with this blend
+//               shape to the indicated value.  This will move all the
+//               affected vertices.
+////////////////////////////////////////////////////////////////////
+void MayaBlendDesc::
+set_slider(float value) {
+  _deformer.setWeight(_weight_index, value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaBlendDesc::get_slider
+//       Access: Public
+//  Description: Returns the current position of the Maya slider
+//               associated with this blend shape.
+////////////////////////////////////////////////////////////////////
+float MayaBlendDesc::
+get_slider() const {
+  return _deformer.weight(_weight_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaBlendDesc::clear_egg
+//       Access: Private
+//  Description: Clears the egg pointers from this blend desc.
+////////////////////////////////////////////////////////////////////
+void MayaBlendDesc::
+clear_egg() {
+  _anim = (EggSAnimData *)NULL;
+}

+ 81 - 0
pandatool/src/mayaegg/mayaBlendDesc.h

@@ -0,0 +1,81 @@
+// Filename: mayaBlendDesc.h
+// Created by:  drose (10Feb04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MAYABLENDDESC_H
+#define MAYABLENDDESC_H
+
+#include "pandatoolbase.h"
+
+#include "referenceCount.h"
+#include "pointerTo.h"
+#include "namable.h"
+
+#include "pre_maya_include.h"
+#include <maya/MFnBlendShapeDeformer.h>
+#include "post_maya_include.h"
+
+class EggTable;
+class EggSAnimData;
+
+////////////////////////////////////////////////////////////////////
+//       Class : MayaBlendDesc
+// Description : A handle to a Maya blend shape description.  This is
+//               just one target of a Maya BlendShape object, and
+//               thus corresponds more or less one-to-one with a
+//               single Egg morph target.  (We don't attempt to
+//               support Maya's chained target shapes here; should we
+//               need to later, it would mean breaking each of those
+//               target shapes on the one continuous Maya slider into
+//               a separate MayaBlendDesc object, and synthesizing the
+//               egg slider values appropriately.)
+////////////////////////////////////////////////////////////////////
+class MayaBlendDesc : public ReferenceCount, public Namable {
+public:
+  MayaBlendDesc(MFnBlendShapeDeformer deformer, int weight_index);
+  ~MayaBlendDesc();
+
+  void set_slider(float value);
+  float get_slider() const;
+
+private:
+  void clear_egg();
+
+  MFnBlendShapeDeformer _deformer;
+  int _weight_index;
+
+  EggSAnimData *_anim;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    ReferenceCount::init_type();
+    Namable::init_type();
+    register_type(_type_handle, "MayaBlendDesc",
+                  ReferenceCount::get_class_type(),
+                  Namable::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class MayaNodeTree;
+};
+
+#endif

+ 110 - 2
pandatool/src/mayaegg/mayaNodeDesc.cxx

@@ -17,8 +17,17 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "mayaNodeDesc.h"
 #include "mayaNodeDesc.h"
+#include "mayaNodeTree.h"
+#include "mayaBlendDesc.h"
 #include "maya_funcs.h"
 #include "maya_funcs.h"
 
 
+#include "pre_maya_include.h"
+#include <maya/MFnBlendShapeDeformer.h>
+#include <maya/MItDependencyGraph.h>
+#include <maya/MFnNurbsSurface.h>
+#include <maya/MFnMesh.h>
+#include "post_maya_include.h"
+
 TypeHandle MayaNodeDesc::_type_handle;
 TypeHandle MayaNodeDesc::_type_handle;
 
 
 // This is a list of the names of Maya connections that count as a
 // This is a list of the names of Maya connections that count as a
@@ -41,8 +50,9 @@ static const int num_transform_connections = sizeof(transform_connections) / siz
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 MayaNodeDesc::
 MayaNodeDesc::
-MayaNodeDesc(MayaNodeDesc *parent, const string &name) :
+MayaNodeDesc(MayaNodeTree *tree, MayaNodeDesc *parent, const string &name) :
   Namable(name),
   Namable(name),
+  _tree(tree),
   _parent(parent)
   _parent(parent)
 {
 {
   _dag_path = (MDagPath *)NULL;
   _dag_path = (MDagPath *)NULL;
@@ -73,11 +83,13 @@ MayaNodeDesc::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MayaNodeDesc::from_dag_path
 //     Function: MayaNodeDesc::from_dag_path
 //       Access: Public
 //       Access: Public
-//  Description: Indicates an associated between the MayaNodeDesc and
+//  Description: Indicates an association between the MayaNodeDesc and
 //               some Maya instance.
 //               some Maya instance.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MayaNodeDesc::
 void MayaNodeDesc::
 from_dag_path(const MDagPath &dag_path) {
 from_dag_path(const MDagPath &dag_path) {
+  MStatus status;
+
   if (_dag_path == (MDagPath *)NULL) {
   if (_dag_path == (MDagPath *)NULL) {
     _dag_path = new MDagPath(dag_path);
     _dag_path = new MDagPath(dag_path);
 
 
@@ -113,6 +125,18 @@ from_dag_path(const MDagPath &dag_path) {
         }
         }
       }
       }
     }
     }
+
+    if (dag_path.hasFn(MFn::kNurbsSurface)) {
+      MFnNurbsSurface surface(dag_path, &status);
+      if (status) {
+        check_blend_shapes(surface, "create");
+      }
+    } else if (dag_path.hasFn(MFn::kMesh)) {
+      MFnMesh mesh(dag_path, &status);
+      if (status) {
+        check_blend_shapes(mesh, "inMesh");
+      }
+    }
   }
   }
 }
 }
 
 
@@ -140,6 +164,30 @@ get_dag_path() const {
   return *_dag_path;
   return *_dag_path;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MayaNodeDesc::get_num_blend_descs
+//       Access: Public
+//  Description: Returns the number of unique MayaBlendDesc objects
+//               (and hence the number of morph sliders) that affect
+//               the geometry in this node.
+////////////////////////////////////////////////////////////////////
+int MayaNodeDesc::
+get_num_blend_descs() const {
+  return _blend_descs.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaNodeDesc::get_blend_desc
+//       Access: Public
+//  Description: Returns the nth MayaBlendDesc object that affects the
+//               geometry in this node.
+////////////////////////////////////////////////////////////////////
+MayaBlendDesc *MayaNodeDesc::
+get_blend_desc(int n) const {
+  nassertr(n >= 0 && n < (int)_blend_descs.size(), NULL);
+  return _blend_descs[n];
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MayaNodeDesc::is_joint
 //     Function: MayaNodeDesc::is_joint
 //       Access: Public
 //       Access: Public
@@ -296,3 +344,63 @@ check_pseudo_joints(bool joint_above) {
     }
     }
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaNodeDesc::check_blend_shapes
+//       Access: Private
+//  Description: Looks for blend shapes on a NURBS surface or polygon
+//               mesh and records any blend shapes found.  This is
+//               similar to MayaToEggConverter::get_vertex_weights(),
+//               which checks for membership of vertices to joints;
+//               Maya stores the blend shape table in the same place.
+//               See the comments in get_vertex_weights() for a more
+//               in-depth description of the iteration process here.
+////////////////////////////////////////////////////////////////////
+void MayaNodeDesc::
+check_blend_shapes(const MFnDagNode &node, const string &attrib_name) {
+  MStatus status;
+
+  MObject attr = node.attribute(attrib_name.c_str()); 
+  
+  MPlug history(node.object(), attr); 
+  MItDependencyGraph it(history, MFn::kDependencyNode, 
+                        MItDependencyGraph::kUpstream, 
+                        MItDependencyGraph::kDepthFirst, 
+                        MItDependencyGraph::kNodeLevel);
+
+  while (!it.isDone()) {
+    MObject c_node = it.thisNode(); 
+
+    if (c_node.hasFn(MFn::kBlendShape)) {
+      MFnBlendShapeDeformer blends(c_node, &status);
+      if (!status) {
+        status.perror("MFnBlendShapeDeformer constructor");
+      } else {
+        MObjectArray base_objects;
+        status = blends.getBaseObjects(base_objects);
+        if (!status) {
+          status.perror("MFnBlendShapeDeformer::getBaseObjects");
+        } else {
+          for (unsigned int oi = 0; oi < base_objects.length(); oi++) {
+            MObject base_object = base_objects[oi];
+
+            MIntArray index_list;
+            status = blends.weightIndexList(index_list);
+            if (!status) {
+              status.perror("MFnBlendShapeDeformer::weightIndexList");
+            } else {
+              for (unsigned int i = 0; i < index_list.length(); i++) {
+                int wi = index_list[i];
+                PT(MayaBlendDesc) blend_desc = new MayaBlendDesc(blends, wi);
+                blend_desc = _tree->add_blend_desc(blend_desc);
+                _blend_descs.push_back(blend_desc);
+              }
+            }
+          }
+        }
+      }
+    }
+
+    it.next();
+  }
+}

+ 14 - 1
pandatool/src/mayaegg/mayaNodeDesc.h

@@ -21,14 +21,17 @@
 
 
 #include "pandatoolbase.h"
 #include "pandatoolbase.h"
 
 
+#include "mayaBlendDesc.h"
 #include "referenceCount.h"
 #include "referenceCount.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "namable.h"
 #include "namable.h"
 
 
 #include "pre_maya_include.h"
 #include "pre_maya_include.h"
 #include <maya/MDagPath.h>
 #include <maya/MDagPath.h>
+#include <maya/MFnDagNode.h>
 #include "post_maya_include.h"
 #include "post_maya_include.h"
 
 
+class MayaNodeTree;
 class EggGroup;
 class EggGroup;
 class EggTable;
 class EggTable;
 class EggXfmSAnim;
 class EggXfmSAnim;
@@ -42,18 +45,23 @@ class EggXfmSAnim;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class MayaNodeDesc : public ReferenceCount, public Namable {
 class MayaNodeDesc : public ReferenceCount, public Namable {
 public:
 public:
-  MayaNodeDesc(MayaNodeDesc *parent = NULL, const string &name = string());
+  MayaNodeDesc(MayaNodeTree *tree,
+               MayaNodeDesc *parent = NULL, const string &name = string());
   ~MayaNodeDesc();
   ~MayaNodeDesc();
 
 
   void from_dag_path(const MDagPath &dag_path);
   void from_dag_path(const MDagPath &dag_path);
   bool has_dag_path() const;
   bool has_dag_path() const;
   const MDagPath &get_dag_path() const;
   const MDagPath &get_dag_path() const;
 
 
+  int get_num_blend_descs() const;
+  MayaBlendDesc *get_blend_desc(int n) const;
+
   bool is_joint() const;
   bool is_joint() const;
   bool is_joint_parent() const;
   bool is_joint_parent() const;
 
 
   bool is_tagged() const;
   bool is_tagged() const;
 
 
+  MayaNodeTree *_tree;
   MayaNodeDesc *_parent;
   MayaNodeDesc *_parent;
   typedef pvector< PT(MayaNodeDesc) > Children;
   typedef pvector< PT(MayaNodeDesc) > Children;
   Children _children;
   Children _children;
@@ -65,6 +73,8 @@ private:
   void clear_egg();
   void clear_egg();
   void mark_joint_parent();
   void mark_joint_parent();
   void check_pseudo_joints(bool joint_above);
   void check_pseudo_joints(bool joint_above);
+  void check_blend_shapes(const MFnDagNode &node, 
+                          const string &attrib_name);
 
 
   MDagPath *_dag_path;
   MDagPath *_dag_path;
 
 
@@ -72,6 +82,9 @@ private:
   EggTable *_egg_table;
   EggTable *_egg_table;
   EggXfmSAnim *_anim;
   EggXfmSAnim *_anim;
 
 
+  typedef pvector< PT(MayaBlendDesc) > BlendDescs;
+  BlendDescs _blend_descs;
+
   enum JointType {
   enum JointType {
     JT_none,         // Not a joint.
     JT_none,         // Not a joint.
     JT_joint,        // An actual joint in Maya.
     JT_joint,        // An actual joint in Maya.

+ 96 - 4
pandatool/src/mayaegg/mayaNodeTree.cxx

@@ -17,12 +17,14 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "mayaNodeTree.h"
 #include "mayaNodeTree.h"
+#include "mayaBlendDesc.h"
 #include "mayaEggGroupUserData.h"
 #include "mayaEggGroupUserData.h"
 #include "config_mayaegg.h"
 #include "config_mayaegg.h"
 #include "maya_funcs.h"
 #include "maya_funcs.h"
 #include "eggGroup.h"
 #include "eggGroup.h"
 #include "eggTable.h"
 #include "eggTable.h"
 #include "eggXfmSAnim.h"
 #include "eggXfmSAnim.h"
+#include "eggSAnimData.h"
 #include "eggData.h"
 #include "eggData.h"
 #include "dcast.h"
 #include "dcast.h"
 
 
@@ -40,11 +42,12 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 MayaNodeTree::
 MayaNodeTree::
 MayaNodeTree() {
 MayaNodeTree() {
-  _root = new MayaNodeDesc;
+  _root = new MayaNodeDesc(this);
   _fps = 0.0;
   _fps = 0.0;
   _egg_data = (EggData *)NULL;
   _egg_data = (EggData *)NULL;
   _egg_root = (EggGroupNode *)NULL;
   _egg_root = (EggGroupNode *)NULL;
   _skeleton_node = (EggGroupNode *)NULL;
   _skeleton_node = (EggGroupNode *)NULL;
+  _morph_node = (EggGroupNode *)NULL;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -235,11 +238,12 @@ get_node(int n) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MayaNodeTree::
 void MayaNodeTree::
 clear() {
 clear() {
-  _root = new MayaNodeDesc;
+  _root = new MayaNodeDesc(this);
   _fps = 0.0;
   _fps = 0.0;
   _egg_data = (EggData *)NULL;
   _egg_data = (EggData *)NULL;
   _egg_root = (EggGroupNode *)NULL;
   _egg_root = (EggGroupNode *)NULL;
   _skeleton_node = (EggGroupNode *)NULL;
   _skeleton_node = (EggGroupNode *)NULL;
+  _morph_node = (EggGroupNode *)NULL;
   _nodes_by_path.clear();
   _nodes_by_path.clear();
   _nodes.clear();
   _nodes.clear();
 }
 }
@@ -253,11 +257,17 @@ clear() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MayaNodeTree::
 void MayaNodeTree::
 clear_egg(EggData *egg_data, EggGroupNode *egg_root, 
 clear_egg(EggData *egg_data, EggGroupNode *egg_root, 
-          EggGroupNode *skeleton_node) {
+          EggGroupNode *skeleton_node, EggGroupNode *morph_node) {
   _root->clear_egg();
   _root->clear_egg();
+  BlendDescs::iterator bi;
+  for (bi = _blend_descs.begin(); bi != _blend_descs.end(); ++bi) {
+    (*bi)->clear_egg();
+  }
+
   _egg_data = egg_data;
   _egg_data = egg_data;
   _egg_root = egg_root;
   _egg_root = egg_root;
   _skeleton_node = skeleton_node;
   _skeleton_node = skeleton_node;
+  _morph_node = morph_node;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -428,6 +438,88 @@ get_egg_anim(MayaNodeDesc *node_desc) {
   return node_desc->_anim;
   return node_desc->_anim;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MayaNodeTree::get_egg_slider
+//       Access: Public
+//  Description: Returns the anim table corresponding to the slider
+//               for the indicated blend.  Creates the table node if it
+//               has not already been created.
+////////////////////////////////////////////////////////////////////
+EggSAnimData *MayaNodeTree::
+get_egg_slider(MayaBlendDesc *blend_desc) {
+  nassertr(_morph_node != (EggGroupNode *)NULL, NULL);
+
+  if (blend_desc->_anim == (EggSAnimData *)NULL) {
+    // We need to make a new anim table.
+    EggSAnimData *egg_anim = new EggSAnimData(blend_desc->get_name());
+    egg_anim->set_fps(_fps);
+    _morph_node->add_child(egg_anim);
+
+    blend_desc->_anim = egg_anim;
+  }
+
+  return blend_desc->_anim;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaNodeTree::add_blend_desc
+//       Access: Public
+//  Description: Adds the indicated MayaBlendDesc object to the list
+//               of blends collected so far.  If a MayaBlendDesc
+//               object with the same name is already part of the
+//               tree, the supplied object is discarded and the
+//               previously-added object is returned; otherwise, the
+//               supplied object is added to the tree and the same
+//               object is returned.
+//
+//               In either case, the return value is the MayaBlendDesc
+//               that should be used henceforth.
+////////////////////////////////////////////////////////////////////
+MayaBlendDesc *MayaNodeTree::
+add_blend_desc(MayaBlendDesc *blend_desc) {
+  BlendDescs::iterator bi = _blend_descs.insert(blend_desc).first;
+
+  return (*bi);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaNodeTree::get_num_blend_descs
+//       Access: Public
+//  Description: Returns the number of unique MayaBlendDesc objects
+//               (and hence the number of morph sliders) discovered in
+//               the tree.
+////////////////////////////////////////////////////////////////////
+int MayaNodeTree::
+get_num_blend_descs() const {
+  return _blend_descs.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaNodeTree::get_blend_desc
+//       Access: Public
+//  Description: Returns the nth MayaBlendDesc object discovered in
+//               the tree.
+////////////////////////////////////////////////////////////////////
+MayaBlendDesc *MayaNodeTree::
+get_blend_desc(int n) const {
+  nassertr(n >= 0 && n < (int)_blend_descs.size(), NULL);
+  return _blend_descs[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaNodeTree::reset_sliders
+//       Access: Public
+//  Description: Resets all of the sliders associated with all blend
+//               shapes down to 0.
+////////////////////////////////////////////////////////////////////
+void MayaNodeTree::
+reset_sliders() {
+  BlendDescs::iterator bi;
+  for (bi = _blend_descs.begin(); bi != _blend_descs.end(); ++bi) {
+    (*bi)->set_slider(0.0);
+  }
+}
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MayaNodeTree::r_build_node
 //     Function: MayaNodeTree::r_build_node
@@ -465,7 +557,7 @@ r_build_node(const string &path) {
     }
     }
 
 
     MayaNodeDesc *parent_node_desc = r_build_node(parent_path);
     MayaNodeDesc *parent_node_desc = r_build_node(parent_path);
-    node_desc = new MayaNodeDesc(parent_node_desc, local_name);
+    node_desc = new MayaNodeDesc(this, parent_node_desc, local_name);
     _nodes.push_back(node_desc);
     _nodes.push_back(node_desc);
   }
   }
 
 

+ 21 - 3
pandatool/src/mayaegg/mayaNodeTree.h

@@ -22,10 +22,16 @@
 #include "pandatoolbase.h"
 #include "pandatoolbase.h"
 
 
 #include "mayaNodeDesc.h"
 #include "mayaNodeDesc.h"
+#include "mayaBlendDesc.h"
 #include "globPattern.h"
 #include "globPattern.h"
+#include "indirectCompareNames.h"
+#include "ordered_vector.h"
 
 
 class EggData;
 class EggData;
 class EggGroupNode;
 class EggGroupNode;
+class EggTable;
+class EggXfmSAnim;
+class EggSAnimData;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : MayaNodeTree
 //       Class : MayaNodeTree
@@ -47,26 +53,38 @@ public:
 
 
   void clear();
   void clear();
   void clear_egg(EggData *egg_data, EggGroupNode *egg_root, 
   void clear_egg(EggData *egg_data, EggGroupNode *egg_root, 
-                 EggGroupNode *skeleton_node);
+                 EggGroupNode *skeleton_node, EggGroupNode *morph_node);
   EggGroup *get_egg_group(MayaNodeDesc *node_desc);
   EggGroup *get_egg_group(MayaNodeDesc *node_desc);
   EggTable *get_egg_table(MayaNodeDesc *node_desc);
   EggTable *get_egg_table(MayaNodeDesc *node_desc);
   EggXfmSAnim *get_egg_anim(MayaNodeDesc *node_desc);
   EggXfmSAnim *get_egg_anim(MayaNodeDesc *node_desc);
+  EggSAnimData *get_egg_slider(MayaBlendDesc *blend_desc);
 
 
+  MayaBlendDesc *add_blend_desc(MayaBlendDesc *blend_desc);
+  int get_num_blend_descs() const;
+  MayaBlendDesc *get_blend_desc(int n) const;
+
+  void reset_sliders();
+
+public:
   PT(MayaNodeDesc) _root;
   PT(MayaNodeDesc) _root;
   float _fps;
   float _fps;
 
 
 private:
 private:
+  MayaNodeDesc *r_build_node(const string &path);
+
   EggData *_egg_data;
   EggData *_egg_data;
   EggGroupNode *_egg_root;
   EggGroupNode *_egg_root;
   EggGroupNode *_skeleton_node;
   EggGroupNode *_skeleton_node;
-
-  MayaNodeDesc *r_build_node(const string &path);
+  EggGroupNode *_morph_node;
 
 
   typedef pmap<string, MayaNodeDesc *> NodesByPath;
   typedef pmap<string, MayaNodeDesc *> NodesByPath;
   NodesByPath _nodes_by_path;
   NodesByPath _nodes_by_path;
 
 
   typedef pvector<MayaNodeDesc *> Nodes;
   typedef pvector<MayaNodeDesc *> Nodes;
   Nodes _nodes;
   Nodes _nodes;
+
+  typedef ov_set<PT(MayaBlendDesc), IndirectCompareNames<MayaBlendDesc> > BlendDescs;
+  BlendDescs _blend_descs;
 };
 };
 
 
 #endif
 #endif

+ 92 - 8
pandatool/src/mayaegg/mayaToEggConverter.cxx

@@ -34,6 +34,7 @@
 #include "eggTexture.h"
 #include "eggTexture.h"
 #include "eggTextureCollection.h"
 #include "eggTextureCollection.h"
 #include "eggXfmSAnim.h"
 #include "eggXfmSAnim.h"
+#include "eggSAnimData.h"
 #include "string_utils.h"
 #include "string_utils.h"
 #include "dcast.h"
 #include "dcast.h"
 
 
@@ -71,6 +72,7 @@
 #include <maya/MFnSkinCluster.h>
 #include <maya/MFnSkinCluster.h>
 #include <maya/MFnSingleIndexedComponent.h>
 #include <maya/MFnSingleIndexedComponent.h>
 #include <maya/MFnDoubleIndexedComponent.h>
 #include <maya/MFnDoubleIndexedComponent.h>
+#include <maya/MFnBlendShapeDeformer.h>
 #include <maya/MItDependencyGraph.h>
 #include <maya/MItDependencyGraph.h>
 #include <maya/MDagPathArray.h>
 #include <maya/MDagPathArray.h>
 #include <maya/MSelectionList.h>
 #include <maya/MSelectionList.h>
@@ -503,6 +505,11 @@ convert_char_model() {
     MGlobal::viewFrame(frame);
     MGlobal::viewFrame(frame);
   }
   }
 
 
+  // It's also important for us to reset all the blend shape sliders
+  // to 0 before we get out the model.  Otherwise, the model we
+  // convert will have the current positions of the sliders baked in.
+  _tree.reset_sliders();
+
   EggGroup *char_node = new EggGroup(_character_name);
   EggGroup *char_node = new EggGroup(_character_name);
   get_egg_data().add_child(char_node);
   get_egg_data().add_child(char_node);
   char_node->set_dart_type(EggGroup::DT_default);
   char_node->set_dart_type(EggGroup::DT_default);
@@ -529,11 +536,13 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc,
   root_table_node->add_child(bundle_node);
   root_table_node->add_child(bundle_node);
   EggTable *skeleton_node = new EggTable("<skeleton>");
   EggTable *skeleton_node = new EggTable("<skeleton>");
   bundle_node->add_child(skeleton_node);
   bundle_node->add_child(skeleton_node);
+  EggTable *morph_node = new EggTable("morph");
+  bundle_node->add_child(morph_node);
 
 
   // Set the frame rate before we start asking for anim tables to be
   // Set the frame rate before we start asking for anim tables to be
   // created.
   // created.
   _tree._fps = output_frame_rate;
   _tree._fps = output_frame_rate;
-  _tree.clear_egg(&get_egg_data(), NULL, skeleton_node);
+  _tree.clear_egg(&get_egg_data(), NULL, skeleton_node, morph_node);
 
 
   // Now we can get the animation data by walking through all of the
   // Now we can get the animation data by walking through all of the
   // frames, one at a time, and getting the joint angles at each
   // frames, one at a time, and getting the joint angles at each
@@ -544,6 +553,7 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc,
   PT(EggGroup) tgroup = new EggGroup;
   PT(EggGroup) tgroup = new EggGroup;
 
 
   int num_nodes = _tree.get_num_nodes();
   int num_nodes = _tree.get_num_nodes();
+  int num_sliders = _tree.get_num_blend_descs();
   int i;
   int i;
 
 
   MTime frame(start_frame, MTime::uiUnit());
   MTime frame(start_frame, MTime::uiUnit());
@@ -576,6 +586,16 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc,
       }
       }
     }
     }
 
 
+    for (i = 0; i < num_sliders; i++) {
+      MayaBlendDesc *blend_desc = _tree.get_blend_desc(i);
+      if (mayaegg_cat.is_spam()) {
+        mayaegg_cat.spam()
+          << "slider " << blend_desc->get_name() << "\n";
+      }
+      EggSAnimData *anim = _tree.get_egg_slider(blend_desc);
+      anim->add_data(blend_desc->get_slider());
+    }
+
     frame += frame_inc;
     frame += frame_inc;
   }
   }
 
 
@@ -589,6 +609,12 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc,
     }
     }
   }
   }
 
 
+  for (i = 0; i < num_sliders; i++) {
+    MayaBlendDesc *blend_desc = _tree.get_blend_desc(i);
+    EggSAnimData *anim = _tree.get_egg_slider(blend_desc);
+    anim->optimize();
+  }
+  
   mayaegg_cat.info(false)
   mayaegg_cat.info(false)
     << "\n";
     << "\n";
 
 
@@ -605,7 +631,7 @@ bool MayaToEggConverter::
 convert_hierarchy(EggGroupNode *egg_root) {
 convert_hierarchy(EggGroupNode *egg_root) {
   int num_nodes = _tree.get_num_nodes();
   int num_nodes = _tree.get_num_nodes();
 
 
-  _tree.clear_egg(&get_egg_data(), egg_root, NULL);
+  _tree.clear_egg(&get_egg_data(), egg_root, NULL, NULL);
   for (int i = 0; i < num_nodes; i++) {
   for (int i = 0; i < num_nodes; i++) {
     MayaNodeDesc *node = _tree.get_node(i);
     MayaNodeDesc *node = _tree.get_node(i);
     if (!process_model_node(node)) {
     if (!process_model_node(node)) {
@@ -637,7 +663,7 @@ process_model_node(MayaNodeDesc *node_desc) {
   MFnDagNode dag_node(dag_path, &status);
   MFnDagNode dag_node(dag_path, &status);
   if (!status) {
   if (!status) {
     status.perror("MFnDagNode constructor");
     status.perror("MFnDagNode constructor");
-    mayaegg_cat.error() << dag_path.fullPathName() << "\n";
+    mayaegg_cat.error() << dag_path.fullPathName().asChar() << "\n";
     return false;
     return false;
   }
   }
 
 
@@ -701,7 +727,7 @@ process_model_node(MayaNodeDesc *node_desc) {
           << ":\n"
           << ":\n"
           << "  it appears to have a NURBS surface, but does not.\n";
           << "  it appears to have a NURBS surface, but does not.\n";
       } else {
       } else {
-        make_nurbs_surface(dag_path, surface, egg_group);
+        make_nurbs_surface(node_desc, dag_path, surface, egg_group);
       }
       }
     }
     }
 
 
@@ -943,8 +969,8 @@ get_joint_transform(const MDagPath &dag_path, EggGroup *egg_group) {
 //               indicated egg group.
 //               indicated egg group.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MayaToEggConverter::
 void MayaToEggConverter::
-make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface,
-                   EggGroup *egg_group) {
+make_nurbs_surface(MayaNodeDesc *node_desc, const MDagPath &dag_path,
+                   MFnNurbsSurface &surface, EggGroup *egg_group) {
   MStatus status;
   MStatus status;
   string name = surface.name().asChar();
   string name = surface.name().asChar();
 
 
@@ -1022,6 +1048,31 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface,
     status.perror("MFnNurbsSurface::getCVs");
     status.perror("MFnNurbsSurface::getCVs");
     return;
     return;
   }
   }
+
+  // Also get out all the alternate blend shapes for the surface by
+  // applying each morph slider one at a time.
+  pvector<MPointArray> morph_cvs;
+  if (_animation_convert == AC_model) {
+    int num_sliders = node_desc->get_num_blend_descs();
+    morph_cvs.reserve(num_sliders);
+    for (int i = 0; i < num_sliders; i++) {
+      MayaBlendDesc *blend_desc = node_desc->get_blend_desc(i);
+
+      // Temporarily push the slider up to 1.0 so we can see what the
+      // surface looks like at that value.
+      blend_desc->set_slider(1.0);
+      MPointArray cv_array;
+      status = surface.getCVs(cv_array, MSpace::kWorld);
+      blend_desc->set_slider(0.0);
+
+      if (!status) {
+        status.perror("MFnNurbsSurface::getCVs");
+        return;
+      }
+      morph_cvs.push_back(cv_array);
+    }
+  }
+
   MDoubleArray u_knot_array, v_knot_array;
   MDoubleArray u_knot_array, v_knot_array;
   status = surface.getKnotsInU(u_knot_array);
   status = surface.getKnotsInU(u_knot_array);
   if (!status) {
   if (!status) {
@@ -1044,7 +1095,7 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface,
   int v_cvs = surface.numCVsInV();
   int v_cvs = surface.numCVsInV();
 
 
   // Maya repeats CVS at the end for a periodic surface, and doesn't
   // Maya repeats CVS at the end for a periodic surface, and doesn't
-  // count them in the weighted array, below.
+  // count them in the joint weight array, below.
   int maya_u_cvs = (u_form == MFnNurbsSurface::kPeriodic) ? u_cvs - u_degree : u_cvs;
   int maya_u_cvs = (u_form == MFnNurbsSurface::kPeriodic) ? u_cvs - u_degree : u_cvs;
   int maya_v_cvs = (v_form == MFnNurbsSurface::kPeriodic) ? v_cvs - v_degree : v_cvs;
   int maya_v_cvs = (v_form == MFnNurbsSurface::kPeriodic) ? v_cvs - v_degree : v_cvs;
 
 
@@ -1081,9 +1132,10 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface,
   for (i = 0; i < egg_nurbs->get_num_cvs(); i++) {
   for (i = 0; i < egg_nurbs->get_num_cvs(); i++) {
     int ui = egg_nurbs->get_u_index(i);
     int ui = egg_nurbs->get_u_index(i);
     int vi = egg_nurbs->get_v_index(i);
     int vi = egg_nurbs->get_v_index(i);
+    int maya_vi = v_cvs * ui + vi;
 
 
     double v[4];
     double v[4];
-    MStatus status = cv_array[v_cvs * ui + vi].get(v);
+    status = cv_array[maya_vi].get(v);
     if (!status) {
     if (!status) {
       status.perror("MPoint::get");
       status.perror("MPoint::get");
     } else {
     } else {
@@ -1092,6 +1144,28 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface,
       p4d = p4d * vertex_frame_inv;
       p4d = p4d * vertex_frame_inv;
       vert->set_pos(p4d);
       vert->set_pos(p4d);
 
 
+      // Now generate the morph targets for the vertex.
+      if (!morph_cvs.empty()) {
+        // Morph deltas are given in 3-d space, not in 4-d homogenous
+        // space.
+        LPoint3d p3d(v[0] / v[3], v[1] / v[3], v[2] / v[3]);
+
+        for (unsigned int si = 0; si < morph_cvs.size(); si++) {
+          MayaBlendDesc *blend_desc = node_desc->get_blend_desc(si);
+          status = morph_cvs[si][maya_vi].get(v);
+          if (!status) {
+            status.perror("MPoint::get");
+          } else {
+            LPoint3d m3d(v[0] / v[3], v[1] / v[3], v[2] / v[3]);
+            LVector3d delta = m3d - p3d;
+            if (!delta.almost_equal(LVector3d::zero())) {
+              EggMorphVertex dxyz(blend_desc->get_name(), delta);
+              vert->_dxyzs.insert(dxyz);
+            }
+          }
+        }
+      }
+
       egg_nurbs->add_vertex(vert);
       egg_nurbs->add_vertex(vert);
     }
     }
   }
   }
@@ -1630,6 +1704,16 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh,
     pi.next();
     pi.next();
   }
   }
 
 
+  // TODO: We also need to compute the vertex morphs for the polyset,
+  // based on whatever blend shapes may be present.  This should be
+  // similar to the code in make_nurbs_surface(), except that since we
+  // don't have a one-to-one relationship of egg vertices to Maya
+  // vertices, we probably have to get the morphs down here, after we
+  // have added all of the egg vertices.  I'll be happy to make this
+  // work as soon as someone gives me a sample Maya file that
+  // demonstrates blend shapes with polygon meshes.
+
+
   // Now that we've added all the polygons (and created all the
   // Now that we've added all the polygons (and created all the
   // vertices), go back through the vertex pool and set up the
   // vertices), go back through the vertex pool and set up the
   // appropriate joint membership for each of the vertices.
   // appropriate joint membership for each of the vertices.

+ 2 - 1
pandatool/src/mayaegg/mayaToEggConverter.h

@@ -104,7 +104,8 @@ private:
   // I ran into core dumps trying to pass around a MFnMesh object by
   // I ran into core dumps trying to pass around a MFnMesh object by
   // value.  From now on, all MFn* objects will be passed around by
   // value.  From now on, all MFn* objects will be passed around by
   // reference.
   // reference.
-  void make_nurbs_surface(const MDagPath &dag_path, 
+  void make_nurbs_surface(MayaNodeDesc *node_desc,
+                          const MDagPath &dag_path, 
                           MFnNurbsSurface &surface,
                           MFnNurbsSurface &surface,
                           EggGroup *group);
                           EggGroup *group);
   EggNurbsCurve *make_trim_curve(const MFnNurbsCurve &curve,
   EggNurbsCurve *make_trim_curve(const MFnNurbsCurve &curve,