Panda3D

maya_funcs.cxx

00001 // Filename: maya_funcs.cxx
00002 // Created by:  drose (16Feb00)
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 "maya_funcs.h"
00016 
00017 #include "pre_maya_include.h"
00018 #include <maya/MObject.h>
00019 #include <maya/MAngle.h>
00020 #include <maya/MFnDependencyNode.h>
00021 #include <maya/MStatus.h>
00022 #include <maya/MFnStringData.h>
00023 #include <maya/MFnNumericData.h>
00024 #include <maya/MPlugArray.h>
00025 #include <maya/MPlug.h>
00026 #include <maya/MFnAttribute.h>
00027 #include <maya/MFnTypedAttribute.h>
00028 #include <maya/MFnNumericAttribute.h>
00029 #include <maya/MFnEnumAttribute.h>
00030 #include <maya/MFnCompoundAttribute.h>
00031 #include <maya/MFnMatrixData.h>
00032 #include <maya/MMatrix.h>
00033 #include "post_maya_include.h"
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: get_maya_plug
00037 //  Description: Gets the named MPlug associated, if any.
00038 ////////////////////////////////////////////////////////////////////
00039 bool
00040 get_maya_plug(MObject &node, const string &attribute_name, MPlug &plug) {
00041   MStatus status;
00042   MFnDependencyNode node_fn(node, &status);
00043   if (!status) {
00044     maya_cat.error()
00045       << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
00046     return false;
00047   }
00048 
00049   MObject attr = node_fn.attribute(attribute_name.c_str(), &status);
00050   if (!status) {
00051     return false;
00052   }
00053 
00054   MFnAttribute attr_fn(attr, &status);
00055   if (!status) {
00056     maya_cat.error()
00057       << "Attribute " << attribute_name << " on " << node_fn.name().asChar()
00058       << " is a " << attr.apiTypeStr() << ", not an Attribute.\n";
00059     return false;
00060   }
00061 
00062   plug = MPlug(node, attr);
00063   return true;
00064 }
00065 
00066 ////////////////////////////////////////////////////////////////////
00067 //     Function: is_connected
00068 //  Description: Returns true if the named connection exists on the
00069 //               node and is connected to anything, false otherwise.
00070 ////////////////////////////////////////////////////////////////////
00071 bool
00072 is_connected(MObject &node, const string &attribute_name) {
00073   MPlug plug;
00074   if (!get_maya_plug(node, attribute_name, plug)) {
00075     return false;
00076   }
00077 
00078   return plug.isConnected();
00079 }
00080 
00081 ////////////////////////////////////////////////////////////////////
00082 //     Function: has_attribute
00083 //  Description: Returns true if the node has the indicated attribute,
00084 //               false otherwise.
00085 ////////////////////////////////////////////////////////////////////
00086 bool
00087 has_attribute(MObject &node, const string &attribute_name) { 
00088   MStatus status;
00089   MFnDependencyNode node_fn(node, &status);
00090   if (!status) {
00091     maya_cat.error()
00092       << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
00093     return false;
00094   }
00095 
00096   node_fn.attribute(attribute_name.c_str(), &status);
00097   if (!status) {
00098     // No such attribute.
00099     return false;
00100   }
00101   return true;
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: remove_attribute
00106 //  Description: Removes the named attribute from the indicated Maya
00107 //               node.  Returns true if successful, false otherwise.
00108 ////////////////////////////////////////////////////////////////////
00109 bool
00110 remove_attribute(MObject &node, const string &attribute_name) {
00111   MStatus status;
00112   MFnDependencyNode node_fn(node, &status);
00113   if (!status) {
00114     maya_cat.error()
00115       << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
00116     return false;
00117   }
00118 
00119   MObject attr = node_fn.attribute(attribute_name.c_str(), &status);
00120   if (!status) {
00121     return false;
00122   }
00123 
00124   {
00125     // Just to prove the the attr is, in fact, an Attribute.
00126     // According to the Maya docs, we shouldn't leave the MFnAttribute
00127     // object around while we remove the attribute, though.
00128     MFnAttribute attr_fn(attr, &status);
00129     if (!status) {
00130       maya_cat.error()
00131         << "Attribute " << attribute_name << " on " << node_fn.name().asChar()
00132         << " is a " << attr.apiTypeStr() << ", not an Attribute.\n";
00133       return false;
00134     }
00135   }
00136 
00137   MFnDependencyNode::MAttrClass type = node_fn.attributeClass(attr, &status);
00138   if (!status) {
00139     maya_cat.error()
00140       << "Couldn't get class of attribute " << attribute_name << " on "
00141       << node_fn.name().asChar() << ".\n";
00142     return false;
00143   }
00144 
00145   status = node_fn.removeAttribute(attr, type);
00146   if (!status) {
00147     maya_cat.error()
00148       << "Couldn't remove attribute " << attribute_name << " from "
00149       << node_fn.name().asChar() << ".\n";
00150     return false;
00151   }
00152 
00153   return true;
00154 }
00155 
00156 ////////////////////////////////////////////////////////////////////
00157 //     Function: get_bool_attribute
00158 //  Description: Extracts the named boolean attribute from the
00159 //               MObject.
00160 ////////////////////////////////////////////////////////////////////
00161 bool
00162 get_bool_attribute(MObject &node, const string &attribute_name,
00163                    bool &value) {
00164   if (!has_attribute(node, attribute_name)) {
00165     // For bool attributes only, we assume if the attribute is absent
00166     // it's the same thing as being false.
00167     return false;
00168   }
00169 
00170   if (!get_maya_attribute(node, attribute_name, value)) {
00171     maya_cat.warning()
00172       << "Attribute " << attribute_name
00173       << " does not have a bool value.\n";
00174     describe_maya_attribute(node, attribute_name);
00175     return false;
00176   }
00177   return true;
00178 }
00179 
00180 ////////////////////////////////////////////////////////////////////
00181 //     Function: get_bool_attribute
00182 //  Description: Extracts the named angle in degrees from the
00183 //               MObject.
00184 ////////////////////////////////////////////////////////////////////
00185 bool
00186 get_angle_attribute(MObject &node, const string &attribute_name,
00187                     double &value) {
00188   MAngle maya_value;
00189   if (!get_maya_attribute(node, attribute_name, maya_value)) {
00190     maya_cat.warning()
00191       << "Attribute " << attribute_name
00192       << " does not have an angle value.\n";
00193     describe_maya_attribute(node, attribute_name);
00194     return false;
00195   }
00196   value = maya_value.asDegrees();
00197   return true;
00198 }
00199 
00200 ////////////////////////////////////////////////////////////////////
00201 //     Function: get_vec2_attribute
00202 //  Description: Extracts the named two-component vector from the
00203 //               MObject.
00204 ////////////////////////////////////////////////////////////////////
00205 bool
00206 get_vec2_attribute(MObject &node, const string &attribute_name,
00207                     LVecBase2 &value) {
00208   MStatus status;
00209 
00210   MObject vec2_object;
00211   if (!get_maya_attribute(node, attribute_name, vec2_object)) {
00212     maya_cat.warning()
00213       << "Attribute " << attribute_name
00214       << " does not have a vec2 object value.\n";
00215     describe_maya_attribute(node, attribute_name);
00216     return false;
00217   }
00218 
00219   MFnNumericData data(vec2_object, &status);
00220   if (!status) {
00221     maya_cat.warning()
00222       << "Attribute " << attribute_name << " is of type "
00223       << vec2_object.apiTypeStr() << ", not a NumericData.\n";
00224     return false;
00225   }
00226 
00227   status = data.getData(value[0], value[1]);
00228   if (!status) {
00229     maya_cat.warning()
00230       << "Unable to extract 2 floats from " << attribute_name
00231       << ", of type " << vec2_object.apiTypeStr() << "\n";
00232   }
00233 
00234   return true;
00235 }
00236 
00237 ////////////////////////////////////////////////////////////////////
00238 //     Function: get_vec3_attribute
00239 //  Description: Extracts the named three-component vector from the
00240 //               MObject.
00241 ////////////////////////////////////////////////////////////////////
00242 bool
00243 get_vec3_attribute(MObject &node, const string &attribute_name,
00244                     LVecBase3 &value) {
00245   MStatus status;
00246 
00247   MObject vec3_object;
00248   if (!get_maya_attribute(node, attribute_name, vec3_object)) {
00249     maya_cat.warning()
00250       << "Attribute " << attribute_name
00251       << " does not have a vec3 object value.\n";
00252     describe_maya_attribute(node, attribute_name);
00253     return false;
00254   }
00255 
00256   MFnNumericData data(vec3_object, &status);
00257   if (!status) {
00258     maya_cat.warning()
00259       << "Attribute " << attribute_name << " is of type "
00260       << vec3_object.apiTypeStr() << ", not a NumericData.\n";
00261     return false;
00262   }
00263 
00264   status = data.getData(value[0], value[1], value[2]);
00265   if (!status) {
00266     maya_cat.warning()
00267       << "Unable to extract 3 floats from " << attribute_name
00268       << ", of type " << vec3_object.apiTypeStr() << "\n";
00269   }
00270 
00271   return true;
00272 }
00273 
00274 ////////////////////////////////////////////////////////////////////
00275 //     Function: get_vec2d_attribute
00276 //  Description: Extracts the named two-component vector from the
00277 //               MObject.
00278 ////////////////////////////////////////////////////////////////////
00279 bool
00280 get_vec2d_attribute(MObject &node, const string &attribute_name,
00281                     LVecBase2d &value) {
00282   MStatus status;
00283 
00284   MObject vec2d_object;
00285   if (!get_maya_attribute(node, attribute_name, vec2d_object)) {
00286     maya_cat.warning()
00287       << "Attribute " << attribute_name
00288       << " does not have a vec2d object value.\n";
00289     describe_maya_attribute(node, attribute_name);
00290     return false;
00291   }
00292 
00293   MFnNumericData data(vec2d_object, &status);
00294   if (!status) {
00295     maya_cat.warning()
00296       << "Attribute " << attribute_name << " is of type "
00297       << vec2d_object.apiTypeStr() << ", not a NumericData.\n";
00298     return false;
00299   }
00300 
00301   status = data.getData(value[0], value[1]);
00302   if (!status) {
00303     maya_cat.warning()
00304       << "Unable to extract 2 doubles from " << attribute_name
00305       << ", of type " << vec2d_object.apiTypeStr() << "\n";
00306   }
00307 
00308   return true;
00309 }
00310 
00311 ////////////////////////////////////////////////////////////////////
00312 //     Function: get_vec3d_attribute
00313 //  Description: Extracts the named three-component vector from the
00314 //               MObject.
00315 ////////////////////////////////////////////////////////////////////
00316 bool
00317 get_vec3d_attribute(MObject &node, const string &attribute_name,
00318                     LVecBase3d &value) {
00319   MStatus status;
00320 
00321   MObject vec3d_object;
00322   if (!get_maya_attribute(node, attribute_name, vec3d_object)) {
00323     maya_cat.warning()
00324       << "Attribute " << attribute_name
00325       << " does not have a vec3d object value.\n";
00326     describe_maya_attribute(node, attribute_name);
00327     return false;
00328   }
00329 
00330   MFnNumericData data(vec3d_object, &status);
00331   if (!status) {
00332     maya_cat.warning()
00333       << "Attribute " << attribute_name << " is of type "
00334       << vec3d_object.apiTypeStr() << ", not a NumericData.\n";
00335     return false;
00336   }
00337 
00338   status = data.getData(value[0], value[1], value[2]);
00339   if (!status) {
00340     maya_cat.warning()
00341       << "Unable to extract 3 doubles from " << attribute_name
00342       << ", of type " << vec3d_object.apiTypeStr() << "\n";
00343   }
00344 
00345   return true;
00346 }
00347 
00348 ////////////////////////////////////////////////////////////////////
00349 //     Function: get_mat4d_attribute
00350 //  Description: Extracts the named 4x4 matrix from the MObject.
00351 ////////////////////////////////////////////////////////////////////
00352 bool
00353 get_mat4d_attribute(MObject &node, const string &attribute_name,
00354                     LMatrix4d &value) {
00355   MStatus status;
00356   MObject matrix;
00357   if (!get_maya_attribute(node, attribute_name, matrix)) {
00358     return false;
00359   }
00360 
00361   MFnMatrixData matrix_data(matrix, &status);
00362   if (!status) {
00363     maya_cat.warning()
00364       << "Attribute " << attribute_name << " is of type "
00365       << node.apiTypeStr() << ", not a Matrix.\n";
00366     return false;
00367   }
00368     
00369   const MMatrix &mat = matrix_data.matrix();
00370   for (int i = 0; i < 4; i++) {
00371     for (int j = 0; j < 4; j++) {
00372       value(i, j) = mat(i, j);
00373     }
00374   }
00375   return true;
00376 }
00377 
00378 ////////////////////////////////////////////////////////////////////
00379 //     Function: get_tag_attribute_names
00380 //  Description: artists should be able to set arbitrary tags.
00381 //               Query all the attributes on this object and return
00382 //               the lists of attribute names that has "tag" prefix
00383 ////////////////////////////////////////////////////////////////////
00384 void
00385 get_tag_attribute_names(MObject &node, pvector<string> &tag_names) {
00386   MStatus status;
00387   MFnDependencyNode node_fn(node, &status);
00388   if (!status) {
00389     maya_cat.warning()
00390       << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
00391     return;
00392   }
00393 
00394   string name = node_fn.name().asChar();
00395   unsigned i;
00396 
00397   for (i = 0; i < node_fn.attributeCount(); i++) {
00398     MObject attr = node_fn.attribute(i, &status);
00399     if (status) {
00400       MFnAttribute attrib(attr, &status);
00401       if (status) {
00402         string attribute_name = attrib.name().asChar();
00403         if (attribute_name.find("tag", 0) != string::npos) {
00404           maya_cat.info() << ":" << name << ":" << " is tagged with <" 
00405                           << attribute_name << ">" << endl;
00406           tag_names.push_back(attribute_name);
00407         }
00408       }
00409     }
00410   }
00411 }
00412 ////////////////////////////////////////////////////////////////////
00413 //     Function: get_enum_attribute
00414 //  Description: Extracts the enum attribute from the MObject as a
00415 //               string value.
00416 ////////////////////////////////////////////////////////////////////
00417 bool
00418 get_enum_attribute(MObject &node, const string &attribute_name,
00419                    string &value) {
00420   MStatus status;
00421 
00422   MPlug plug;
00423   if (!get_maya_plug(node, attribute_name.c_str(), plug)) {
00424     return false;
00425   }
00426 
00427   MObject attrib = plug.attribute();
00428   MFnEnumAttribute enum_attrib(attrib, &status);
00429   if (!status) {
00430     maya_cat.warning()
00431       << "Not an enum attribute: " << attribute_name << "\n";
00432     return false;
00433   }
00434 
00435   short index;
00436   status = plug.getValue(index);
00437   if (!status) {
00438     maya_cat.warning()
00439       << "Could not get numeric value of " << attribute_name << "\n";
00440     status.perror("MPlug::getValue(short)");
00441     return false;
00442   }
00443 
00444   MString name = enum_attrib.fieldName(index, &status);
00445   if (!status) {
00446     maya_cat.warning()
00447       << "Invalid value for " << attribute_name << ": " << index << "\n";
00448     status.perror("MFnEnumAttribute::fieldName()");
00449     return false;
00450   }
00451 
00452   value = name.asChar();
00453   return true;
00454 }
00455 
00456 ////////////////////////////////////////////////////////////////////
00457 //     Function: get_string_attribute
00458 //  Description: Extracts the named string attribute from the
00459 //               MObject.
00460 ////////////////////////////////////////////////////////////////////
00461 bool
00462 get_string_attribute(MObject &node, const string &attribute_name,
00463                      string &value) {
00464   MStatus status;
00465 
00466   MObject string_object;
00467   if (!get_maya_attribute(node, attribute_name, string_object)) {
00468     maya_cat.warning()
00469       << "Attribute " << attribute_name
00470       << " does not have an string object value.\n";
00471     describe_maya_attribute(node, attribute_name);
00472     return false;
00473   }
00474 
00475   MFnStringData data(string_object, &status);
00476   if (!status) {
00477     maya_cat.warning()
00478       << "Attribute " << attribute_name << " is of type "
00479       << string_object.apiTypeStr() << ", not a StringData.\n";
00480     return false;
00481   }
00482 
00483   value = data.string().asChar();
00484   return true;
00485 }
00486 
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: set_string_attribute
00489 //  Description: Sets the named string attribute on the
00490 //               MObject.
00491 ////////////////////////////////////////////////////////////////////
00492 bool
00493 set_string_attribute(MObject &node, const string &attribute_name,
00494                      const string &value) {
00495   MStatus status;
00496 
00497   // First, we get the string_object, then we set its string.
00498   MObject string_object;
00499   if (!get_maya_attribute(node, attribute_name, string_object)) {
00500     maya_cat.warning()
00501       << "Attribute " << attribute_name
00502       << " does not have a string object value.\n";
00503     describe_maya_attribute(node, attribute_name);
00504     return false;
00505   }
00506 
00507   MFnStringData data(string_object, &status);
00508   if (!status) {
00509     maya_cat.warning()
00510       << "Attribute " << attribute_name << " is of type "
00511       << string_object.apiTypeStr() << ", not a StringData.\n";
00512     return false;
00513   }
00514 
00515   MString mstring_value(value.data(), value.length());
00516   status = data.set(mstring_value);
00517   if (!status) {
00518     status.perror(attribute_name.c_str());
00519     return false;
00520   }
00521 
00522   // And it appears we now need to set the string object back.
00523   if (!set_maya_attribute(node, attribute_name, string_object)) {
00524     maya_cat.warning()
00525       << "Attribute " << attribute_name
00526       << " suddenly does not have a string object value.\n";
00527     return false;
00528   }
00529 
00530   return true;
00531 }
00532 
00533 ////////////////////////////////////////////////////////////////////
00534 //     Function: describe_compound_attribute
00535 //  Description: Extracts the children of this attribute from the
00536 //               MObject. test for now
00537 ////////////////////////////////////////////////////////////////////
00538 bool 
00539 describe_compound_attribute(MObject &node) {
00540   MStatus status;
00541   
00542   MFnCompoundAttribute comp_attr(node, &status);
00543 
00544   maya_cat.info() << "comp_attr has:" << comp_attr.numChildren() << " children" << endl;
00545   for (size_t i = 0; i < comp_attr.numChildren(); i++) {
00546     MObject child = comp_attr.child(i, &status);
00547     if (child.apiType() == MFn::kAttribute3Float){
00548       LRGBColor color;
00549       /*
00550       if (get_vec3_attribute(child, "color", color)) {
00551         maya_cat.info() << "color: " << color << endl;
00552       }
00553       */
00554     }
00555     else if (child.apiType() == MFn::kNumericAttribute) {
00556       MFnNumericAttribute numeric(child, &status);
00557       if (status) {
00558         switch(numeric.unitType()) {
00559         case MFnNumericData::kFloat :
00560           PN_stdfloat alpha;
00561           status = numeric.getDefault(alpha);
00562           maya_cat.info() << "found a float :" << alpha << endl;
00563           break;
00564         case MFnNumericData::kBoolean :
00565           bool v;
00566           status = numeric.getDefault(v);
00567           maya_cat.info() << "found a bool :" << v << endl;
00568         default:
00569           maya_cat.info() << numeric.unitType() << endl;
00570         }
00571       }
00572     }
00573     else if (child.apiType() == MFn::kEnumAttribute) {
00574       MFnEnumAttribute enu(child, &status);
00575       if (status) {
00576         MString blah;
00577         status = enu.getDefault(blah);
00578         maya_cat.info() << "found a string :" << blah.asChar() << endl;
00579         MPlug plug = MPlug(node, child);
00580         maya_cat.info() << "plug name" << plug.name().asChar() << endl;
00581       }
00582     }
00583   }
00584   return true;
00585 }
00586 
00587 ////////////////////////////////////////////////////////////////////
00588 //     Function: describe_maya_attribute
00589 //  Description: Writes some warning output about the indicated Maya
00590 //               attribute.
00591 ////////////////////////////////////////////////////////////////////
00592 void
00593 describe_maya_attribute(MObject &node, const string &attribute_name) {
00594   MStatus status;
00595   MFnDependencyNode node_fn(node, &status);
00596   if (!status) {
00597     maya_cat.warning()
00598       << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
00599     return;
00600   }
00601 
00602   MObject attr = node_fn.attribute(attribute_name.c_str(), &status);
00603   if (!status) {
00604     maya_cat.warning()
00605       << "Object " << node_fn.name().asChar() << " does not support attribute "
00606       << attribute_name << "\n";
00607     return;
00608   }
00609 
00610   maya_cat.warning()
00611     << "Attribute " << attribute_name << " on object "
00612     << node_fn.name().asChar() << " has type " << attr.apiTypeStr() << "\n";
00613 }
00614 
00615 string
00616 string_mfndata_type(MFnData::Type type) {
00617   switch (type) {
00618   case MFnData::kInvalid:
00619     return "kInvalid";
00620 
00621   case MFnData::kNumeric:
00622     return "kNumeric";
00623 
00624   case MFnData::kPlugin:
00625     return "kPlugin";
00626 
00627   case MFnData::kPluginGeometry:
00628     return "kPluginGeometry";
00629 
00630   case MFnData::kString:
00631     return "kString";
00632 
00633   case MFnData::kMatrix:
00634     return "kMatrix";
00635 
00636   case MFnData::kStringArray:
00637     return "kStringArray";
00638 
00639   case MFnData::kDoubleArray:
00640     return "kDoubleArray";
00641 
00642   case MFnData::kIntArray:
00643     return "kIntArray";
00644 
00645   case MFnData::kPointArray:
00646     return "kPointArray";
00647 
00648   case MFnData::kVectorArray:
00649     return "kVectorArray";
00650 
00651   case MFnData::kComponentList:
00652     return "kComponentList";
00653 
00654   case MFnData::kMesh:
00655     return "kMesh";
00656 
00657   case MFnData::kLattice:
00658     return "kLattice";
00659 
00660   case MFnData::kNurbsCurve:
00661     return "kNurbsCurve";
00662 
00663   case MFnData::kNurbsSurface:
00664     return "kNurbsSurface";
00665 
00666   case MFnData::kSphere:
00667     return "kSphere";
00668 
00669   case MFnData::kDynArrayAttrs:
00670     return "kDynArrayAttrs";
00671 
00672   case MFnData::kDynSweptGeometry:
00673     return "kDynSweptGeometry";
00674 
00675   case MFnData::kSubdSurface:
00676     return "kSubdSurface";
00677 
00678   case MFnData::kLast:
00679     return "kLast";
00680   }
00681 
00682   return "**invalid**";
00683 }
00684 
00685 ////////////////////////////////////////////////////////////////////
00686 //     Function: list_maya_attributes
00687 //  Description: Writes some info output showing all the attributes on
00688 //               the given dependency node.  Primarily useful during
00689 //               development, to figure out where the heck Maya hides
00690 //               some of the connected properties.
00691 ////////////////////////////////////////////////////////////////////
00692 void
00693 list_maya_attributes(MObject &node) {
00694   MStatus status;
00695   MFnDependencyNode node_fn(node, &status);
00696   if (!status) {
00697     maya_cat.warning()
00698       << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
00699     return;
00700   }
00701 
00702   string name = node_fn.name().asChar();
00703   unsigned i;
00704 
00705   MPlugArray connections;
00706   status = node_fn.getConnections(connections);
00707   if (!status) {
00708     status.perror("MFnDependencyNode::getConnections");
00709 
00710   } else {
00711     maya_cat.info()
00712       << name << " has " << connections.length() << " connections.\n";
00713     for (i = 0; i < connections.length(); i++) {
00714       MPlug plug = connections[i];
00715 
00716       maya_cat.info(false)
00717         << "  " << i << ". " << plug.name().asChar() << ", "
00718         << plug.attribute().apiTypeStr() << ", " 
00719         << plug.node().apiTypeStr();
00720       if (plug.attribute().apiType() == MFn::kCompoundAttribute) {
00721         //maya_cat.info() << plug.info();
00722         //describe_compound_attribute(plug.attribute());
00723       }
00724       if (plug.isConnected()) {
00725         maya_cat.info(false)
00726           << " (*)";
00727       }
00728       maya_cat.info(false)
00729         << "\n";
00730     }
00731   }
00732 
00733   maya_cat.info()
00734     << name << " has " << node_fn.attributeCount() << " attributes.\n";
00735   for (i = 0; i < node_fn.attributeCount(); i++) {
00736     MObject attr = node_fn.attribute(i, &status);
00737     if (status) {
00738       MFnTypedAttribute typed_attrib(attr, &status);
00739       if (status) {
00740         // It's a typed attrib.
00741           maya_cat.info(false) 
00742             << "  " << i << ". " << typed_attrib.name().asChar()
00743             << " [" << attr.apiTypeStr() << ", "
00744             << string_mfndata_type(typed_attrib.attrType()) << "]\n";
00745       } else {
00746         MFnAttribute attrib(attr, &status);
00747         if (status) {
00748           // It's a generic attrib.
00749           maya_cat.info(false) 
00750             << "  " << i << ". " << attrib.name().asChar()
00751             << " [" << attr.apiTypeStr() << "]\n";
00752         } else {
00753           // Don't know what it is.
00754           maya_cat.info(false)
00755             << "  " << i << ". [" << attr.apiTypeStr() << "]\n";
00756         }
00757       }
00758     }
00759   }
00760 }
00761 
 All Classes Functions Variables Enumerations