//- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ // // File Name: animExportUtil.h // // Description: an animation export utility which illustrates how to // use the MAnimUtil animation helper class, as well as how to export // animation using the Maya .anim format // // // ***************************************************************************** // INCLUDED HEADER FILES #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "animExportUtil.h" #include "animFileExport.h" #if defined (OSMac_) using namespace std; extern "C" int strcasecmp (const char *, const char *); #endif // ***************************************************************************** // HELPER METHODS // ***************************************************************************** #ifndef min static inline double min (double a, double b) { return (a < b ? a : b); } #endif #ifndef max static inline double max (double a, double b) { return (a > b ? a : b); } #endif // ***************************************************************************** // PUBLIC MEMBER FUNCTIONS TanimExportUtil::TanimExportUtil() { } TanimExportUtil::~TanimExportUtil() { } MStatus TanimExportUtil::writer ( const MFileObject &file, const MString &/*options*/, FileAccessMode mode ) { // Create the export file // ofstream animFile (file.fullName().asChar()); // Create a selection list to hold the objects we want to export // MSelectionList list; if (mode == kExportActiveAccessMode) { // Use the active list // MGlobal::getActiveSelectionList (list); } else { // Create a selection list with all the objects in the world // // Add the top level dag objects // MItDag dagIt (MItDag::kBreadthFirst); for (dagIt.next(); !dagIt.isDone(); dagIt.next()) { MDagPath path; if (dagIt.getPath (path) != MS::kSuccess) { continue; } list.add (path); // We only want the top level objects (since we will walk // down the hierarchy later // dagIt.prune (); } // Gather the rest of the dependency nodes // MItDependencyNodes nodeIt; for (; !nodeIt.isDone(); nodeIt.next()) { MObject node = nodeIt.item(); if (node.isNull()) { continue; } // We have already saved the dag objects, so skip them here // if (node.hasFn (MFn::kDagNode)) { continue; } // Watch out for characters, and only write the top level // character // if (node.hasFn (MFn::kCharacter)) { // Find out which (if any) sets this node belongs to // // Get the message attribute // MFnDependencyNode fnNode (node); MObject aMessage = fnNode.attribute (MString ("message")); MPlug messagePlug (node, aMessage); // Now find what it is connected to as a source plug // MPlugArray srcPlugArray; messagePlug.connectedTo (srcPlugArray, false, true); // Now walk through each connection and see if any is to // another character // unsigned int numPlugs = srcPlugArray.length(); bool belongsToCharacter = false; for (unsigned int i = 0; (i < numPlugs) && !belongsToCharacter; i++) { const MPlug &plug = srcPlugArray[i]; if (!plug.node().hasFn (MFn::kCharacter)) { continue; } belongsToCharacter = true; } if (!belongsToCharacter) { list.add (node); } continue; } // A superfluous test to filter out unanimated objects, just to // show how to use MAnimUtil // if (!MAnimUtil::isAnimated (node)) { continue; } list.add (node); } } // The Maya .anim format needs to know the bounds of the animation // since it could be used in pasteKey operations (which support // scaling in time), so gather that information now // // Find all the plugs that are animated in our selection list // MPlugArray animatedPlugs; MAnimUtil::findAnimatedPlugs (list, animatedPlugs); unsigned int numPlugs = animatedPlugs.length(); bool hasTime = false; double startTime = 0.0; double endTime = 0.0; bool hasUnitless = false; double startUnitless = 0.0; double endUnitless = 0.0; unsigned int i; // For each animated plug, determine the bounds of the animation // for (i = 0; i < numPlugs; i++) { MPlug plug = animatedPlugs[i]; MObjectArray animation; // Find the animation curve(s) that animate this plug // if (!MAnimUtil::findAnimation (plug, animation)) { continue; } unsigned int numCurves = animation.length(); for (unsigned int j = 0; j < numCurves; j++) { MObject animCurveNode = animation[j]; if (!animCurveNode.hasFn (MFn::kAnimCurve)) { continue; } MFnAnimCurve animCurve (animCurveNode); unsigned int numKeys = animCurve.numKeys(); if (numKeys == 0) { continue; } if (animCurve.isUnitlessInput()) { if (!hasUnitless) { startUnitless = animCurve.unitlessInput (0); endUnitless = animCurve.unitlessInput (numKeys - 1); hasUnitless = true; } else { startUnitless = min (startUnitless, animCurve.unitlessInput (0)); endUnitless = max (endUnitless, animCurve.unitlessInput (numKeys - 1)); } } else { if (!hasTime) { startTime = animCurve.time (0).value(); endTime = animCurve.time (numKeys - 1).value(); hasTime = true; } else { startTime = min (startTime, animCurve.time (0).value()); endTime = max (endTime, animCurve.time (numKeys - 1).value()); } } } } // Write out the header information // animWriter writer; writer.writeHeader (animFile, startTime, endTime, startUnitless, endUnitless); // Now write out the animation for each object on the selection list // unsigned int numObjects = list.length(); for (i = 0; i < numObjects; i++) { MDagPath path; MObject node; if (list.getDagPath (i, path) == MS::kSuccess) { write (animFile, path); } else if (list.getDependNode (i, node) == MS::kSuccess) { write (animFile, node); } } animFile.flush(); animFile.close(); return (MS::kSuccess); } void TanimExportUtil::write (ofstream &animFile, const MDagPath &path) { // Walk through the dag breadth first // MItDag dagIt (MItDag::kDepthFirst); dagIt.reset (path, MItDag::kDepthFirst); for (; !dagIt.isDone(); dagIt.next()) { MDagPath thisPath; if (dagIt.getPath (thisPath) != MS::kSuccess) { continue; } // Find the animated plugs for this object // MPlugArray animatedPlugs; MObject node = thisPath.node(); MFnDependencyNode fnNode (node); MAnimUtil::findAnimatedPlugs (thisPath, animatedPlugs); unsigned int numPlugs = animatedPlugs.length(); if (numPlugs == 0) { // If the object is not animated, then write out place holder // information // animFile << "anim " << fnNode.name().asChar() << " " << dagIt.depth() << " " << thisPath.childCount() << " 0;\n"; } else { // Otherwise write out each animation curve // writeAnimatedPlugs (animFile, animatedPlugs, fnNode.name(), dagIt.depth(), thisPath.childCount()); } } } void TanimExportUtil::write (ofstream &animFile, const MObject &node) { // Watch out for characters and handle them a little differently // if (node.hasFn (MFn::kCharacter)) { MObjectArray characterList; characterList.append (node); MIntArray depths; depths.append (0); unsigned int current = 0; while (current < characterList.length()) { const MObject &thisNode = characterList[current]; int thisDepth = depths[current++]; // If this node is a character, then check for any immediate // subCharacters // MFnSet fnSet (thisNode); // Now find the set members // MSelectionList members; fnSet.getMembers (members, false); unsigned int childCount = 0; MItSelectionList iter (members, MFn::kCharacter); for (; !iter.isDone(); iter.next()) { MObject childNode; iter.getDependNode (childNode); characterList.insert (childNode, current + childCount); depths.insert (thisDepth + 1, current + childCount); childCount++; } // Find the animated plugs for this object // MPlugArray animatedPlugs; MAnimUtil::findAnimatedPlugs (thisNode, animatedPlugs); unsigned int numPlugs = animatedPlugs.length(); if (numPlugs == 0) { // If the object is not animated, then write out place holder // information // animFile << "anim " << fnSet.name().asChar() << " " << thisDepth << " " << childCount << " 0;\n"; } else { // Otherwise write out each animation curve // writeAnimatedPlugs (animFile, animatedPlugs, fnSet.name(), thisDepth, childCount); } } return; } // Find the animated plugs for this object // MPlugArray animatedPlugs; MFnDependencyNode fnNode (node); MAnimUtil::findAnimatedPlugs (node, animatedPlugs); unsigned int numPlugs = animatedPlugs.length(); if (numPlugs != 0) { // If the object is animated the write out each animation curve // writeAnimatedPlugs (animFile, animatedPlugs, fnNode.name(), 0, 0); } } void TanimExportUtil::writeAnimatedPlugs ( ofstream &animFile, const MPlugArray &animatedPlugs, const MString &nodeName, unsigned int depth, unsigned int childCount ) { // Walk through each animated plug and write out the animation curve(s) // unsigned int numPlugs = animatedPlugs.length(); for (unsigned int i = 0; i < numPlugs; i++) { MPlug plug = animatedPlugs[i]; MObjectArray animation; if (!MAnimUtil::findAnimation (plug, animation)) { continue; } // Write out the plugs' anim statement // animFile << "anim "; // build up the full attribute name // MPlug attrPlug (plug); MObject attrObj = attrPlug.attribute(); MFnAttribute fnAttr (attrObj); MString fullAttrName (fnAttr.name()); attrPlug = attrPlug.parent(); while (!attrPlug.isNull()) { attrObj = attrPlug.attribute(); MFnAttribute fnAttr2 (attrObj); fullAttrName = fnAttr2.name() + "." + fullAttrName; attrPlug = attrPlug.parent(); } attrObj = plug.attribute(); MFnAttribute fnLeafAttr (attrObj); animFile << fullAttrName.asChar() << " " << fnLeafAttr.name().asChar() << " " << nodeName.asChar() << " " << depth << " " << childCount << " " << i << ";\n"; unsigned int numCurves = animation.length(); // Write out each animation curve that animates the plug // for (unsigned int j = 0; j < numCurves; j++) { MObject animCurveNode = animation[j]; if (!animCurveNode.hasFn (MFn::kAnimCurve)) { continue; } animWriter writer; writer.writeAnimCurve (animFile, &animCurveNode); } } } bool TanimExportUtil::haveWriteMethod () const { return (true); } MString TanimExportUtil::defaultExtension () const { return (MString("anim")); } MPxFileTranslator::MFileKind TanimExportUtil::identifyFile ( const MFileObject &file, const char * /*buffer*/, short /*size*/ ) const { const char *name = file.name().asChar(); int nameLength = (int)strlen(name); if ((nameLength > 5) && !strcasecmp(name+nameLength-5, ".anim")) { return (kIsMyFileType); } return (kNotMyFileType); } /* static */ void * TanimExportUtil::creator () { return (new TanimExportUtil); } //-------------------------------------------------------------------------------- // Plugin management //-------------------------------------------------------------------------------- MStatus initializePlugin (MObject obj) { MStatus status; MFnPlugin plugin (obj, PLUGIN_COMPANY, "3.0"); status = plugin.registerFileTranslator ("animExportUtil", "", TanimExportUtil::creator); return (status); } MStatus uninitializePlugin (MObject obj) { MFnPlugin plugin (obj); plugin.deregisterFileTranslator ("animExportUtil"); return (MS::kSuccess); }