dagPoseInfoCmd.cpp

//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

//
// Description:
//   This is an example of a command that writes information about the
//   dag pose of selected joints out to a file.
//
//   To use the command, select the joints that you want data for and
//   then type the command, being sure to use the -f/-file flag to specify
//   the name of the file to write to.
//
//      dagPoseInfo -f <fileName>
//
//   For example:
//
//      dagPoseInfo -f "C:/temp/poseData"
//
//   The output format used is:
//      <jointName>
//      <poseName>
//      worldMatrix
//      1 0 0 0
//      0 1 0 0
//      0 0 1 0
//      0 0 0 1
//      matrix
//      1 0 0 0
//      0 1 0 0
//      0 0 1 0
//      0 0 0 1
// 
//   Note that the pose node stores the local matrix data in a transformation
//   matrix, so that if one wanted to extract only the rotation components
//   of the pose rather than the entire local matrix, one could do so using
//   the MTransformationMatrix function set.
//
//   Also note that if you want just the bindPose data, rather than data about
//   all of the poses on a joint, you could restrict the output to dagPose
//   nodes for which the "dagPose" attribute is true.
//

#include <math.h>
#include <maya/MPxCommand.h>
#include <maya/MStatus.h>
#include <maya/MArgList.h>
#include <maya/MFnPlugin.h>
#include <maya/MObject.h>
#include <maya/MGlobal.h>
#include <maya/MDagPath.h>
#include <maya/MDagPathArray.h>
#include <maya/MItSelectionList.h>
#include <maya/MSelectionList.h>
#include <maya/MPlug.h>
#include <maya/MPlugArray.h>
#include <maya/MTransformationMatrix.h>
#include <maya/MMatrix.h>
#include <maya/MFnMatrixData.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnAttribute.h>

#include <maya/MIOStream.h>

#define CheckError(stat,msg)        \
    if ( MS::kSuccess != stat ) {   \
        displayError(msg);          \
        continue;                   \
    }


class dagPoseInfo : public MPxCommand
{
public:
                dagPoseInfo();
    virtual     ~dagPoseInfo();

    MStatus     parseArgs( const MArgList& args );
    MStatus     doIt ( const MArgList& args );
    MStatus     redoIt ();
    MStatus     undoIt ();
    bool        isUndoable() const;

    static      void* creator();

private:
    void        printDagPoseInfo(MObject& dagPoseNode, unsigned index);
    bool        findDagPose(MObject& jointNode);
    FILE*       file;
};

dagPoseInfo::dagPoseInfo():
file(NULL)
{
}

dagPoseInfo::~dagPoseInfo() {}

void* dagPoseInfo::creator()
{
    return new dagPoseInfo;
}

bool dagPoseInfo::isUndoable() const
{
    return false;
}

MStatus dagPoseInfo::undoIt()
{
    return MS::kSuccess;
}

MStatus dagPoseInfo::parseArgs( const MArgList& args )
//
// There is one mandatory flag: -f/-file <filename>
//
{
    MStatus         stat;
    MString         arg;
    MString         fileName;
    const MString   fileFlag            ("-f");
    const MString   fileFlagLong        ("-file");

    // Parse the arguments.
    for ( unsigned int i = 0; i < args.length(); i++ ) {
        arg = args.asString( i, &stat );
        if (!stat)              
            continue;
                
        if ( arg == fileFlag || arg == fileFlagLong ) {
            // get the file name
            //
            if (i == args.length()-1) {
                arg += ": must specify a file name";
                displayError(arg);
                return MS::kFailure;
            }
            i++;
            args.get(i, fileName);
        }
        else {
            arg += ": unknown argument";
            displayError(arg);
            return MS::kFailure;
        }
    }

    file = fopen(fileName.asChar(),"wb");
    if (!file) {
        MString openError("Could not open: ");
        openError += fileName;
        displayError(openError);
        stat = MS::kFailure;
    }
    
    return stat;
}

void dagPoseInfo::printDagPoseInfo(MObject& dagPoseNode, unsigned index)
//
// Description:
//   Given a dagPose and an index corresponding to a joint, print out
//   the matrix info for the joint.
// Return:
//   None.
//
{
    MFnDependencyNode nDagPose(dagPoseNode);
    fprintf(file,"%s\n",nDagPose.name().asChar());

    // construct plugs for this joints world and local matrices
    //
    MObject aWorldMatrix = nDagPose.attribute("worldMatrix");
    MPlug pWorldMatrix(dagPoseNode,aWorldMatrix);
    pWorldMatrix.selectAncestorLogicalIndex(index,aWorldMatrix);
    
    MObject aMatrix = nDagPose.attribute("xformMatrix");
    MPlug pMatrix(dagPoseNode,aMatrix);
    pMatrix.selectAncestorLogicalIndex(index,aMatrix);

    // get and print the world matrix data
    //
    MObject worldMatrix, xformMatrix;
    MStatus status = pWorldMatrix.getValue(worldMatrix);
    if (MS::kSuccess != status) {
        displayError("Problem retrieving world matrix.");
    } else {
        bool foundMatrix = 0;
        MFnMatrixData dMatrix(worldMatrix);
        MMatrix wMatrix = dMatrix.matrix(&status);
        if (MS::kSuccess == status) {
            foundMatrix = 1;
            unsigned jj,kk;
            fprintf(file,"worldMatrix\n");
            for (jj = 0; jj < 4; ++jj) {
                for (kk = 0; kk < 4; ++kk) {
                    double val = wMatrix(jj,kk);
                    fprintf(file,"%f ",val);
                }
                fprintf(file,"\n");
            }
        }
        if (!foundMatrix) {
            displayError("Error getting world matrix data.");
        }
    }

    // get and print the local matrix data
    //
    status = pMatrix.getValue(xformMatrix);
    if (MS::kSuccess != status) {
        displayError("Problem retrieving xform matrix.");
    } else {
        bool foundMatrix = 0;
        MFnMatrixData dMatrix(xformMatrix);
        if (dMatrix.isTransformation()) {
            MTransformationMatrix xform = dMatrix.transformation(&status);
            if (MS::kSuccess == status) {
                foundMatrix = 1;
                MMatrix xformAsMatrix = xform.asMatrix();
                unsigned jj,kk;
                fprintf(file,"matrix\n");
                for (jj = 0; jj < 4; ++jj) {
                    for (kk = 0; kk < 4; ++kk) {
                        double val = xformAsMatrix(jj,kk);
                        fprintf(file,"%f ",val);
                    }
                    fprintf(file,"\n");
                }
            }
        }
        if (!foundMatrix) {
            displayError("Error getting local matrix data.");
        }
    }
}

bool dagPoseInfo::findDagPose(MObject& jointNode)
//
// Description:
//   Given a joint, check for connected dag pose nodes.
//   For each pose found, write out the pose info.
// Return:
//   If one or more poses is found, return true, else return false.
//
{
    bool rtn = 0; // return 1 if we find a pose

    MStatus status;
    MFnDependencyNode fnJoint(jointNode);
    MObject aBindPose = fnJoint.attribute("bindPose",&status);

    if (MS::kSuccess == status) {
        unsigned connLength = 0;
        MPlugArray connPlugs;
        MPlug pBindPose(jointNode,aBindPose);
        pBindPose.connectedTo(connPlugs,false,true);
        connLength = connPlugs.length();
        for (unsigned ii = 0; ii < connLength; ++ii) {
            if (connPlugs[ii].node().apiType() == MFn::kDagPose) {
                MObject aMember = connPlugs[ii].attribute();
                MFnAttribute fnAttr(aMember);
                if (fnAttr.name() == "worldMatrix") {
                    unsigned jointIndex = connPlugs[ii].logicalIndex();

                    fprintf(file,"%s\n",fnJoint.name().asChar());
                    MObject jointObject = connPlugs[ii].node();
                    printDagPoseInfo(jointObject,jointIndex);
                    rtn = 1;
                }
            }
        }
    }
    return rtn;
}

MStatus dagPoseInfo::doIt( const MArgList& args )
{
    // parse args to get the file name from the command-line
    //
    MStatus stat = parseArgs(args);
    if (stat != MS::kSuccess) {
        return stat;
    }
    
    unsigned int count = 0;

    // Get the selected joints/transforms, and for each of them print
    // out the dagPose info
    //
    MSelectionList slist;
    MGlobal::getActiveSelectionList( slist );
    MItSelectionList itr( slist );

    for (; !itr.isDone(); itr.next() )
    {
        MObject depNode;
        itr.getDependNode(depNode);
        if (depNode.apiType() == MFn::kJoint) {
            if (findDagPose(depNode)) {
                count++;
            }
        }
    }

    fclose(file);
    if (0 == count) {
        displayError("No poses were found on the selected joints.");
        return MS::kFailure;
    }
    
    return MS::kSuccess;
}

MStatus dagPoseInfo::redoIt()
{
    clearResult();
    setResult( (int) 1);
    return MS::kSuccess;
}

MStatus initializePlugin( MObject obj )
{
    MStatus   status;
    MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");

    status = plugin.registerCommand( "dagPoseInfo", dagPoseInfo::creator );
    if (!status) {
        status.perror("registerCommand");
        return status;
    }

    return status;
}

MStatus uninitializePlugin( MObject obj )
{
    MStatus   status;
    MFnPlugin plugin( obj );

    status = plugin.deregisterCommand( "dagPoseInfo" );
    if (!status) {
        status.perror("deregisterCommand");
    }
    return status;
}