Panda3D
 All Classes Functions Variables Enumerations
mayaNodeDesc.cxx
00001 // Filename: mayaNodeDesc.cxx
00002 // Created by:  drose (06Jun03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "mayaNodeDesc.h"
00016 #include "mayaNodeTree.h"
00017 #include "mayaBlendDesc.h"
00018 #include "mayaToEggConverter.h"
00019 #include "maya_funcs.h"
00020 #include "eggGroup.h"
00021 #include "config_mayaegg.h"
00022 
00023 #include "pre_maya_include.h"
00024 #include <maya/MFnBlendShapeDeformer.h>
00025 #include <maya/MItDependencyGraph.h>
00026 #include <maya/MFnNurbsSurface.h>
00027 #include <maya/MFnMesh.h>
00028 #include "post_maya_include.h"
00029 
00030 TypeHandle MayaNodeDesc::_type_handle;
00031 
00032 // This is a list of the names of Maya connections that count as a
00033 // transform.
00034 static const char *transform_connections[] = {
00035   "translate",
00036   "translateX",
00037   "translateY",
00038   "translateZ",
00039   "rotate",
00040   "rotateX",
00041   "rotateY",
00042   "rotateZ",
00043 };
00044 static const int num_transform_connections = sizeof(transform_connections) / sizeof(const char *);
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: MayaNodeDesc::Constructor
00048 //       Access: Public
00049 //  Description: 
00050 ////////////////////////////////////////////////////////////////////
00051 MayaNodeDesc::
00052 MayaNodeDesc(MayaNodeTree *tree, MayaNodeDesc *parent, const string &name) :
00053   Namable(name),
00054   _tree(tree),
00055   _parent(parent)
00056 {
00057   _dag_path = (MDagPath *)NULL;
00058   _egg_group = (EggGroup *)NULL;
00059   _egg_table = (EggTable *)NULL;
00060   _anim = (EggXfmSAnim *)NULL;
00061   _joint_type = JT_none;
00062   _is_lod = false;
00063   _tagged = false;
00064   _joint_tagged = false;
00065 
00066   // Add ourselves to our parent.
00067   if (_parent != (MayaNodeDesc *)NULL) {
00068     _parent->_children.push_back(this);
00069   }
00070 }
00071 
00072 ////////////////////////////////////////////////////////////////////
00073 //     Function: MayaNodeDesc::Destructor
00074 //       Access: Public
00075 //  Description: 
00076 ////////////////////////////////////////////////////////////////////
00077 MayaNodeDesc::
00078 ~MayaNodeDesc() {
00079   if (_dag_path != (MDagPath *)NULL) {
00080     delete _dag_path;
00081   }
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: MayaNodeDesc::from_dag_path
00086 //       Access: Public
00087 //  Description: Indicates an association between the MayaNodeDesc and
00088 //               some Maya instance.
00089 ////////////////////////////////////////////////////////////////////
00090 void MayaNodeDesc::
00091 from_dag_path(const MDagPath &dag_path, MayaToEggConverter *converter) {
00092   MStatus status;
00093 
00094   if (_dag_path == (MDagPath *)NULL) {
00095     _dag_path = new MDagPath(dag_path);
00096 
00097     string name;
00098     MFnDagNode dag_node(dag_path, &status);
00099     if (!status) {
00100       status.perror("MFnDagNode constructor");
00101     } else {
00102       name = dag_node.name().asChar();
00103     }
00104 
00105     if (_dag_path->hasFn(MFn::kJoint) || converter->force_joint(name)) {
00106       // This node is a joint, or the user specifically asked to treat
00107       // it like a joint.
00108       _joint_type = JT_joint;
00109       if (_parent != (MayaNodeDesc *)NULL) {
00110         _parent->mark_joint_parent();
00111       }
00112 
00113     } else {
00114       // The node is not a joint, but maybe its transform is
00115       // controlled by connected inputs.  If so, we should treat it
00116       // like a joint.
00117       bool transform_connected = false;
00118 
00119       MStatus status;
00120       MObject node = dag_path.node(&status);
00121       if (status) {
00122         for (int i = 0; 
00123              i < num_transform_connections && !transform_connected;
00124              i++) {
00125           if (is_connected(node, transform_connections[i])) {
00126             transform_connected = true;
00127           }
00128         }
00129       }
00130       
00131       if (transform_connected) {
00132         _joint_type = JT_joint;
00133         if (_parent != (MayaNodeDesc *)NULL) {
00134           _parent->mark_joint_parent();
00135         }
00136       }
00137     }
00138 
00139     if (dag_path.hasFn(MFn::kNurbsSurface)) {
00140       MFnNurbsSurface surface(dag_path, &status);
00141       if (status) {
00142         check_blend_shapes(surface, "create");
00143       }
00144     } else if (dag_path.hasFn(MFn::kMesh)) {
00145       MFnMesh mesh(dag_path, &status);
00146       if (status) {
00147         check_blend_shapes(mesh, "inMesh");
00148       }
00149     }
00150   }
00151 }
00152 
00153 ////////////////////////////////////////////////////////////////////
00154 //     Function: MayaNodeDesc::has_dag_path
00155 //       Access: Public
00156 //  Description: Returns true if a Maya dag path has been associated
00157 //               with this node, false otherwise.
00158 ////////////////////////////////////////////////////////////////////
00159 bool MayaNodeDesc::
00160 has_dag_path() const {
00161   return (_dag_path != (MDagPath *)NULL);
00162 }
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: MayaNodeDesc::get_dag_path
00166 //       Access: Public
00167 //  Description: Returns the dag path associated with this node.  It
00168 //               is an error to call this unless has_dag_path()
00169 //               returned true.
00170 ////////////////////////////////////////////////////////////////////
00171 const MDagPath &MayaNodeDesc::
00172 get_dag_path() const {
00173   nassertr(_dag_path != (MDagPath *)NULL, *_dag_path);
00174   return *_dag_path;
00175 }
00176 
00177 ////////////////////////////////////////////////////////////////////
00178 //     Function: MayaNodeDesc::get_num_blend_descs
00179 //       Access: Public
00180 //  Description: Returns the number of unique MayaBlendDesc objects
00181 //               (and hence the number of morph sliders) that affect
00182 //               the geometry in this node.
00183 ////////////////////////////////////////////////////////////////////
00184 int MayaNodeDesc::
00185 get_num_blend_descs() const {
00186   return _blend_descs.size();
00187 }
00188 
00189 ////////////////////////////////////////////////////////////////////
00190 //     Function: MayaNodeDesc::get_blend_desc
00191 //       Access: Public
00192 //  Description: Returns the nth MayaBlendDesc object that affects the
00193 //               geometry in this node.
00194 ////////////////////////////////////////////////////////////////////
00195 MayaBlendDesc *MayaNodeDesc::
00196 get_blend_desc(int n) const {
00197   nassertr(n >= 0 && n < (int)_blend_descs.size(), NULL);
00198   return _blend_descs[n];
00199 }
00200 
00201 ////////////////////////////////////////////////////////////////////
00202 //     Function: MayaNodeDesc::is_joint
00203 //       Access: Public
00204 //  Description: Returns true if the node should be treated as a joint
00205 //               by the converter.
00206 ////////////////////////////////////////////////////////////////////
00207 bool MayaNodeDesc::
00208 is_joint() const {
00209   //return _joint_type == JT_joint || _joint_type == JT_pseudo_joint;
00210   return _joint_tagged && (_joint_type == JT_joint || _joint_type == JT_pseudo_joint);
00211 }
00212 
00213 ////////////////////////////////////////////////////////////////////
00214 //     Function: MayaNodeDesc::is_joint_parent
00215 //       Access: Public
00216 //  Description: Returns true if the node is the parent or ancestor of
00217 //               a joint.
00218 ////////////////////////////////////////////////////////////////////
00219 bool MayaNodeDesc::
00220 is_joint_parent() const {
00221   return _joint_type == JT_joint_parent;
00222   //return _joint_tagged && (_joint_type == JT_joint_parent);
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: MayaNodeDesc::is_joint_tagged
00227 //       Access: Public
00228 //  Description: Returns true if the node has been joint_tagged to be
00229 //               converted, false otherwise.
00230 ////////////////////////////////////////////////////////////////////
00231 bool MayaNodeDesc::
00232 is_joint_tagged() const {
00233   return _joint_tagged;
00234 }
00235 
00236 ////////////////////////////////////////////////////////////////////
00237 //     Function: MayaNodeDesc::tag_joint
00238 //       Access: Private
00239 //  Description: Tags this node for conversion, but does not tag child
00240 //               nodes.
00241 ////////////////////////////////////////////////////////////////////
00242 void MayaNodeDesc::
00243 tag_joint() {
00244   _joint_tagged = true;
00245 }
00246 
00247 ////////////////////////////////////////////////////////////////////
00248 //     Function: MayaNodeDesc::tag_joint_recursively
00249 //       Access: Private
00250 //  Description: Tags this node and all descendant nodes for
00251 //               conversion.
00252 ////////////////////////////////////////////////////////////////////
00253 void MayaNodeDesc::
00254 tag_joint_recursively() {
00255   _joint_tagged = true;
00256   //mayaegg_cat.info() << "tjr: " << get_name() << endl;
00257   Children::const_iterator ci;
00258   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00259     MayaNodeDesc *child = (*ci);
00260     child->tag_joint_recursively();
00261   }
00262 }
00263 
00264 ////////////////////////////////////////////////////////////////////
00265 //     Function: MayaNodeDesc::is_tagged
00266 //       Access: Public
00267 //  Description: Returns true if the node has been tagged to be
00268 //               converted, false otherwise.
00269 ////////////////////////////////////////////////////////////////////
00270 bool MayaNodeDesc::
00271 is_tagged() const {
00272   return _tagged;
00273 }
00274 
00275 ////////////////////////////////////////////////////////////////////
00276 //     Function: MayaNodeDesc::tag
00277 //       Access: Private
00278 //  Description: Tags this node for conversion, but does not tag child
00279 //               nodes.
00280 ////////////////////////////////////////////////////////////////////
00281 void MayaNodeDesc::
00282 tag() {
00283   _tagged = true;
00284 }
00285 
00286 ////////////////////////////////////////////////////////////////////
00287 //     Function: MayaNodeDesc::untag
00288 //       Access: Private
00289 //  Description: Un-tags this node for conversion, but does not tag child
00290 //               nodes.
00291 ////////////////////////////////////////////////////////////////////
00292 void MayaNodeDesc::
00293 untag() {
00294   _tagged = false;
00295 }
00296 
00297 ////////////////////////////////////////////////////////////////////
00298 //     Function: MayaNodeDesc::tag_recursively
00299 //       Access: Private
00300 //  Description: Tags this node and all descendant nodes for
00301 //               conversion.
00302 ////////////////////////////////////////////////////////////////////
00303 void MayaNodeDesc::
00304 tag_recursively() {
00305   _tagged = true;
00306 
00307   Children::const_iterator ci;
00308   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00309     MayaNodeDesc *child = (*ci);
00310     child->tag_recursively();
00311   }
00312 }
00313 
00314 ////////////////////////////////////////////////////////////////////
00315 //     Function: MayaNodeDesc::untag_recursively
00316 //       Access: Private
00317 //  Description: Un-tags this node and all descendant nodes for
00318 //               conversion.
00319 ////////////////////////////////////////////////////////////////////
00320 void MayaNodeDesc::
00321 untag_recursively() {
00322   _tagged = false;
00323 
00324   Children::const_iterator ci;
00325   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00326     MayaNodeDesc *child = (*ci);
00327     child->untag_recursively();
00328   }
00329 }
00330 
00331 ////////////////////////////////////////////////////////////////////
00332 //     Function: MayaNodeDesc::has_object_type
00333 //       Access: Public
00334 //  Description: Returns true if this node or any of its parent
00335 //               has_object_type of object_type.
00336 ////////////////////////////////////////////////////////////////////
00337 bool MayaNodeDesc::
00338 has_object_type(string object_type) const {
00339   bool ret = false;
00340   if ((_egg_group != (EggGroup*) NULL) 
00341       && _egg_group->has_object_type(object_type)) {
00342     return true;
00343   }
00344   if (_parent != (MayaNodeDesc *)NULL) {
00345     ret |= _parent->has_object_type(object_type);
00346   }
00347   return ret;
00348 }
00349 
00350 ////////////////////////////////////////////////////////////////////
00351 //     Function: MayaNodeDesc::clear_egg
00352 //       Access: Private
00353 //  Description: Recursively clears the egg pointers from this node
00354 //               and all children.
00355 ////////////////////////////////////////////////////////////////////
00356 void MayaNodeDesc::
00357 clear_egg() {
00358   _egg_group = (EggGroup *)NULL;
00359   _egg_table = (EggTable *)NULL;
00360   _anim = (EggXfmSAnim *)NULL;
00361 
00362   Children::const_iterator ci;
00363   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00364     MayaNodeDesc *child = (*ci);
00365     child->clear_egg();
00366   }
00367 }
00368 
00369 ////////////////////////////////////////////////////////////////////
00370 //     Function: MayaNodeDesc::mark_joint_parent
00371 //       Access: Private
00372 //  Description: Indicates that this node has at least one child that
00373 //               is a joint or a pseudo-joint.
00374 ////////////////////////////////////////////////////////////////////
00375 void MayaNodeDesc::
00376 mark_joint_parent() {
00377   if (_joint_type == JT_none) {
00378     _joint_type = JT_joint_parent;
00379     if (_parent != (MayaNodeDesc *)NULL) {
00380       _parent->mark_joint_parent();
00381     }
00382   }
00383 }
00384 
00385 ////////////////////////////////////////////////////////////////////
00386 //     Function: MayaNodeDesc::check_pseudo_joints
00387 //       Access: Private
00388 //  Description: Walks the hierarchy, looking for non-joint nodes that
00389 //               are both children and parents of a joint.  These
00390 //               nodes are deemed to be pseudo joints, since the
00391 //               converter must treat them as joints.
00392 ////////////////////////////////////////////////////////////////////
00393 void MayaNodeDesc::
00394 check_pseudo_joints(bool joint_above) {
00395   static PN_uint32 space_count = 0;
00396   string space;
00397   for (PN_uint32 idx=0; idx<space_count; ++idx) {
00398     space.append(" ");
00399   }
00400   if (mayaegg_cat.is_spam()) {
00401     mayaegg_cat.spam() << "cpj:" << space << get_name() << " joint_type: " << _joint_type << endl;
00402   }
00403   if (_joint_type == JT_joint_parent && joint_above) {
00404     // This is one such node: it is the parent of a joint
00405     // (JT_joint_parent is set), and it is the child of a joint
00406     // (joint_above is set).
00407     _joint_type = JT_pseudo_joint;
00408   }
00409 
00410   if (_joint_type == JT_joint) {
00411     // If this node is itself a joint, then joint_above is true for
00412     // all child nodes.
00413     joint_above = true;
00414   }
00415 
00416   // Don't bother traversing further if _joint_type is none, since
00417   // that means this node has no joint children.
00418   if (_joint_type != JT_none) {
00419 
00420     bool any_joints = false;
00421     Children::const_iterator ci;
00422     for (ci = _children.begin(); ci != _children.end(); ++ci) {
00423       MayaNodeDesc *child = (*ci);
00424       if (mayaegg_cat.is_spam()) {
00425         ++space_count;
00426       }
00427       child->check_pseudo_joints(joint_above);
00428       //if (child->is_joint()) {
00429       if (child->_joint_type == JT_joint || child->_joint_type == JT_pseudo_joint) {
00430         any_joints = true;
00431       }
00432     }
00433 
00434     // If any children qualify as joints, then any sibling nodes that
00435     // are parents of joints are also elevated to joints.
00436     if (any_joints) {
00437       bool all_joints = true;
00438       for (ci = _children.begin(); ci != _children.end(); ++ci) {
00439         MayaNodeDesc *child = (*ci);
00440         MStatus status;
00441         MFnDagNode dag_node(child->get_dag_path(), &status);
00442         if (!status) {
00443           status.perror("MFnDagNode constructor");
00444         }
00445         string type_name = dag_node.typeName().asChar();
00446         if (child->_joint_type == JT_joint_parent) {
00447           child->_joint_type = JT_pseudo_joint;
00448         } else if (child->_joint_type == JT_none) {
00449           if (mayaegg_cat.is_spam()) {
00450             mayaegg_cat.spam() << "cpj: " << space << "jt_none for " << child->get_name() << endl;
00451           }
00452           if (type_name.find("transform") == string::npos) {
00453             if (mayaegg_cat.is_spam()) {
00454               mayaegg_cat.spam() << "cpj: " << space << "all_joints false for " << get_name() << endl;
00455             }
00456             all_joints = false;
00457           }
00458         }
00459       }
00460 
00461       if (all_joints) {
00462         // Finally, if all children are joints, then we are too.
00463         if (_joint_type == JT_joint_parent) {
00464           if (!get_name().empty()) { // make sure parent of root is not a joint
00465             _joint_type = JT_pseudo_joint;
00466           }
00467         }
00468       }
00469     }
00470   }
00471   if (mayaegg_cat.is_spam()) {
00472     if (space_count > 0)
00473       --space_count;
00474   }
00475 }
00476 
00477 ////////////////////////////////////////////////////////////////////
00478 //     Function: MayaNodeDesc::check_blend_shapes
00479 //       Access: Private
00480 //  Description: Looks for blend shapes on a NURBS surface or polygon
00481 //               mesh and records any blend shapes found.  This is
00482 //               similar to MayaToEggConverter::get_vertex_weights(),
00483 //               which checks for membership of vertices to joints;
00484 //               Maya stores the blend shape table in the same place.
00485 //               See the comments in get_vertex_weights() for a more
00486 //               in-depth description of the iteration process here.
00487 ////////////////////////////////////////////////////////////////////
00488 void MayaNodeDesc::
00489 check_blend_shapes(const MFnDagNode &node, const string &attrib_name) {
00490   MStatus status;
00491 
00492   MObject attr = node.attribute(attrib_name.c_str()); 
00493   
00494   MPlug history(node.object(), attr); 
00495   MItDependencyGraph it(history, MFn::kDependencyNode, 
00496                         MItDependencyGraph::kUpstream, 
00497                         MItDependencyGraph::kDepthFirst, 
00498                         MItDependencyGraph::kNodeLevel);
00499 
00500   while (!it.isDone()) {
00501     MObject c_node = it.thisNode(); 
00502 
00503     if (c_node.hasFn(MFn::kBlendShape)) {
00504       MFnBlendShapeDeformer blends(c_node, &status);
00505       if (!status) {
00506         status.perror("MFnBlendShapeDeformer constructor");
00507 
00508       } else {
00509         // Check if the slider is a "parallel blender", which is a
00510         // construct created by Maya for Maya's internal purposes
00511         // only.  We don't want to fiddle with the parallel blenders.
00512         MPlug plug = blends.findPlug("pb");
00513         bool is_parallel_blender;
00514         status = plug.getValue(is_parallel_blender);
00515         if (!status) {
00516           status.perror("Could not get value of pb plug.");
00517           is_parallel_blender = false;
00518         }
00519 
00520         if (is_parallel_blender || 
00521             _tree->ignore_slider(blends.name().asChar())) {
00522           _tree->report_ignored_slider(blends.name().asChar());
00523 
00524         } else {
00525           MObjectArray base_objects;
00526           status = blends.getBaseObjects(base_objects);
00527           if (!status) {
00528             status.perror("MFnBlendShapeDeformer::getBaseObjects");
00529           } else {
00530             for (unsigned int oi = 0; oi < base_objects.length(); oi++) {
00531               MObject base_object = base_objects[oi];
00532               
00533               MIntArray index_list;
00534               status = blends.weightIndexList(index_list);
00535               if (!status) {
00536                 status.perror("MFnBlendShapeDeformer::weightIndexList");
00537               } else {
00538                 for (unsigned int i = 0; i < index_list.length(); i++) {
00539                   int wi = index_list[i];
00540                   PT(MayaBlendDesc) blend_desc = new MayaBlendDesc(blends, wi);
00541                   blend_desc = _tree->add_blend_desc(blend_desc);
00542                   _blend_descs.push_back(blend_desc);
00543                 }
00544               }
00545             }
00546           }
00547         }
00548       }
00549     }
00550 
00551     it.next();
00552   }
00553 }
00554 
00555 ////////////////////////////////////////////////////////////////////
00556 //     Function: MayaNodeDesc::check_lods
00557 //       Access: Private
00558 //  Description: Walks through the hierarchy again and checks for LOD
00559 //               specifications.  Any such specifications found are
00560 //               recorded on the child nodes of the lodGroups
00561 //               themselves: the nodes that actually switch in and
00562 //               out.  (This is the way they are recorded in an egg
00563 //               file.)
00564 ////////////////////////////////////////////////////////////////////
00565 void MayaNodeDesc::
00566 check_lods() {
00567   // Walk through the children first.  This makes it easier in the
00568   // below (we only have to return in the event of an error).
00569   Children::iterator ci;
00570   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00571     MayaNodeDesc *child = (*ci);
00572     child->check_lods();
00573   }
00574 
00575   // Now consider whether this node is an lodGroup.
00576   if (_dag_path != (MDagPath *)NULL &&
00577       _dag_path->hasFn(MFn::kLodGroup)) {
00578     // This node is a parent lodGroup; its children, therefore, are
00579     // LOD's.
00580     MStatus status;
00581     MFnDagNode dag_node(*_dag_path, &status);
00582     if (!status) {
00583       status.perror("Couldn't get node from dag path for lodGroup");
00584       return;
00585     }
00586 
00587     MPlug plug = dag_node.findPlug("threshold", &status);
00588     if (!status) {
00589       status.perror("Couldn't get threshold attributes on lodGroup");
00590       return;
00591     }
00592 
00593     // There ought to be the one fewer elements in the array than
00594     // there are children of the node.
00595     unsigned int num_elements = plug.numElements();
00596     unsigned int num_children = _children.size();
00597     if (num_elements + 1 != num_children) {
00598       mayaegg_cat.warning()
00599         << "Node " << get_name() << " has " << num_elements
00600         << " LOD entries, but " << num_children << " children.\n";
00601     }
00602 
00603     // Should we also consider cameraMatrix, to transform the LOD's
00604     // origin?  It's not clear precisely what this transform matrix
00605     // means in Maya, so we'll wait until we have a sample file that
00606     // demonstrates its use.
00607 
00608     double switch_out = 0.0;
00609     unsigned int i = 0;
00610     while (i < num_elements && i < num_children) {
00611       MPlug element = plug.elementByLogicalIndex(i);
00612       MayaNodeDesc *child = _children[i];
00613 
00614       double switch_in;
00615       status = element.getValue(switch_in);
00616       if (!status) {
00617         status.perror("Couldn't get double value from threshold.");
00618         return;
00619       }
00620 
00621       child->_is_lod = true;
00622       child->_switch_in = switch_in;
00623       child->_switch_out = switch_out;
00624 
00625       switch_out = switch_in;
00626       ++i;
00627     }
00628 
00629     while (i < num_children) {
00630       // Also set the last child(ren).  Maya wants this to switch in
00631       // at infinity, but Panda doesn't have such a concept; we'll
00632       // settle for four times the switch_out distance.
00633       MayaNodeDesc *child = _children[i];
00634       child->_is_lod = true;
00635       child->_switch_in = switch_out * 4.0;
00636       child->_switch_out = switch_out;
00637       
00638       ++i;
00639     }
00640   }
00641 }
 All Classes Functions Variables Enumerations