animFileExport.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.
// ==========================================================================
//+

//
//      File Name: animFileExport.cpp
//
//      Description:
//              Utility classes to write .anim files.
//
#include <maya/MGlobal.h>

#include <maya/MIOStream.h>
#include <maya/MFStream.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "animFileExport.h"
#include <maya/MString.h>
#include <maya/MFnAnimCurve.h>

//-------------------------------------------------------------------------
//      Class animUnitNames
//-------------------------------------------------------------------------

//      String names for units.
//
const char *kMmString =                 "mm";
const char *kCmString =                 "cm";
const char *kMString =                  "m";
const char *kKmString =                 "km";
const char *kInString =                 "in";
const char *kFtString =                 "ft";
const char *kYdString =                 "yd";
const char *kMiString =                 "mi";

const char *kMmLString =                "millimeter";
const char *kCmLString =                "centimeter";
const char *kMLString =                 "meter";
const char *kKmLString =                "kilometer";
const char *kInLString =                "inch";
const char *kFtLString =                "foot";
const char *kYdLString =                "yard";
const char *kMiLString =                "mile";

const char *kRadString =                "rad";
const char *kDegString =                "deg";
const char *kMinString =                "min";
const char *kSecString =                "sec";

const char *kRadLString =               "radian";
const char *kDegLString =               "degree";
const char *kMinLString =               "minute";
const char *kSecLString =               "second";

const char *kHourTString =              "hour";
const char *kMinTString =               "min";
const char *kSecTString =               "sec";
const char *kMillisecTString =  "millisec";

const char *kGameTString =              "game";
const char *kFileTString =              "film";
const char *kPalTString =               "pal";
const char *kNtscTString =              "ntsc";
const char *kShowTString =              "show";
const char *kPalFTString =              "palf";
const char *kNtscFTString =             "ntscf";

const char *kUnitlessString = "unitless";
const char *kUnknownTimeString =        "Unknown Time Unit";
const char *kUnknownAngularString =     "Unknown Angular Unit";
const char *kUnknownLinearString =      "Unknown Linear Unit";

animUnitNames::animUnitNames()
//
//      Description:
//              Class constructor.
//
{
}

animUnitNames::~animUnitNames()
//
//      Description:
//              Class destructor.
//
{
}

/* static */
void animUnitNames::setToLongName(const MAngle::Unit& unit, MString& name)
//
//      Description:
//              Sets the string with the long text name of the angle unit.
//
{
        switch(unit) {
                case MAngle::kDegrees:
                        name.set(kDegLString);
                        break;
                case MAngle::kRadians:
                        name.set(kRadLString);
                        break;
                case MAngle::kAngMinutes:
                        name.set(kMinLString);
                        break;
                case MAngle::kAngSeconds:
                        name.set(kSecLString);
                        break;
                default:
                        name.set(kUnknownAngularString);
                        break;
        }
}

/* static */
void animUnitNames::setToShortName(const MAngle::Unit& unit, MString& name)
//
//      Description:
//              Sets the string with the short text name of the angle unit.
//
{
        switch(unit) {
                case MAngle::kDegrees:
                        name.set(kDegString);
                        break;
                case MAngle::kRadians:
                        name.set(kRadString);
                        break;
                case MAngle::kAngMinutes:
                        name.set(kMinString);
                        break;
                case MAngle::kAngSeconds:
                        name.set(kSecString);
                        break;
                default:
                        name.set(kUnknownAngularString);
                        break;
        }
}

/* static */
void animUnitNames::setToLongName(const MDistance::Unit& unit, MString& name)
//
//      Description:
//              Sets the string with the long text name of the distance unit.
//
{
        switch(unit) {
                case MDistance::kInches:
                        name.set(kInLString);
                        break;
                case MDistance::kFeet:
                        name.set(kFtLString);
                        break;
                case MDistance::kYards:
                        name.set(kYdLString);
                        break;
                case MDistance::kMiles:
                        name.set(kMiLString);
                        break;
                case MDistance::kMillimeters:
                        name.set(kMmLString);
                        break;
                case MDistance::kCentimeters:
                        name.set(kCmLString);
                        break;
                case MDistance::kKilometers:
                        name.set(kKmLString);
                        break;
                case MDistance::kMeters:
                        name.set(kMLString);
                        break;
                default:
                        name.set(kUnknownLinearString);
                        break;
        }
}

/* static */
void animUnitNames::setToShortName(const MDistance::Unit& unit, MString& name)
//
//      Description:
//              Sets the string with the short text name of the distance unit.
//
{
        switch(unit) {
                case MDistance::kInches:
                        name.set(kInString);
                        break;
                case MDistance::kFeet:
                        name.set(kFtString);
                        break;
                case MDistance::kYards:
                        name.set(kYdString);
                        break;
                case MDistance::kMiles:
                        name.set(kMiString);
                        break;
                case MDistance::kMillimeters:
                        name.set(kMmString);
                        break;
                case MDistance::kCentimeters:
                        name.set(kCmString);
                        break;
                case MDistance::kKilometers:
                        name.set(kKmString);
                        break;
                case MDistance::kMeters:
                        name.set(kMString);
                        break;
                default:
                        name.set(kUnknownLinearString);
                        break;
        }
}

/* static */
void animUnitNames::setToLongName(const MTime::Unit &unit, MString &name)
//
//      Description:
//              Sets the string with the long text name of the time unit.
//
{
        switch(unit) {
                case MTime::kHours:
                        name.set(kHourTString);
                        break;
                case MTime::kMinutes:
                        name.set(kMinTString);
                        break;
                case MTime::kSeconds:
                        name.set(kSecTString);
                        break;
                case MTime::kMilliseconds:
                        name.set(kMillisecTString);
                        break;
                case MTime::kGames:
                        name.set(kGameTString);
                        break;
                case MTime::kFilm:
                        name.set(kFileTString);
                        break;
                case MTime::kPALFrame:
                        name.set(kPalTString);
                        break;
                case MTime::kNTSCFrame:
                        name.set(kNtscTString);
                        break;
                case MTime::kShowScan:
                        name.set(kShowTString);
                        break;
                case MTime::kPALField:
                        name.set(kPalFTString);
                        break;
                case MTime::kNTSCField:
                        name.set(kNtscFTString);
                        break;
                default:
                        name.set(kUnknownTimeString);
                        break;
        }
}

/* static */
void animUnitNames::setToShortName(const MTime::Unit &unit, MString &name)
//
//      Description:
//              Sets the string with the short text name of the time unit.
//
{
        setToLongName(unit, name);
}

//-------------------------------------------------------------------------
//      Class animBase
//-------------------------------------------------------------------------

// Tangent type words
//
const char *kWordTangentGlobal = "global";
const char *kWordTangentFixed = "fixed";
const char *kWordTangentLinear = "linear";
const char *kWordTangentFlat = "flat";
const char *kWordTangentSmooth = "spline";
const char *kWordTangentStep = "step";  // Maintains current value until next key
const char *kWordTangentStepNext = "stepnext";  // Immediately steps to next key's value
const char *kWordTangentSlow = "slow";
const char *kWordTangentFast = "fast";
const char *kWordTangentClamped = "clamped";
const char *kWordTangentPlateau = "plateau";

// Infinity type words
//
const char *kWordConstant = "constant";
const char *kWordLinear = "linear";
const char *kWordCycle = "cycle";
const char *kWordCycleRelative = "cycleRelative";
const char *kWordOscillate = "oscillate";

//      Param Curve types
//
const char *kWordTypeUnknown = "unknown";
const char *kWordTypeLinear = "linear";
const char *kWordTypeAngular = "angular";
const char *kWordTypeTime = "time";
const char *kWordTypeUnitless = "unitless";

//      Keywords
//
const char *kAnim = "anim";
const char *kAnimData = "animData";
const char *kMovData = "movData";
const char *kMayaVersion = "mayaVersion";
const char *kAnimVersion = "animVersion";

const char *kTimeUnit = "timeUnit";
const char *kLinearUnit = "linearUnit";
const char *kAngularUnit = "angularUnit";
const char *kStartTime = "startTime";
const char *kEndTime = "endTime";
const char *kStartUnitless = "startUnitless";
const char *kEndUnitless = "endUnitless";

// animVersions:
//
const char *kAnimVersionString = "1.1";

const char *kTwoSpace = "  ";

//      animData keywords
//
const char *kInputString = "input";
const char *kOutputString = "output";
const char *kWeightedString = "weighted";
const char *kPreInfinityString = "preInfinity";
const char *kPostInfinityString = "postInfinity";
const char *kInputUnitString = "inputUnit";
const char *kOutputUnitString = "outputUnit";
const char *kTanAngleUnitString = "tangentAngleUnit";
const char *kKeysString = "keys";

//      special characters
//
const char kSemiColonChar       = ';';
const char kSpaceChar           = ' ';
const char kBraceLeftChar       = '{';
const char kBraceRightChar      = '}';

animBase::animBase ()
//
//      Description:
//              The constructor.
//
{
        resetUnits();
}
        
animBase::~animBase()
//
//      Description:
//              The destructor.
//
{
}

void animBase::resetUnits()
//
//      Description:
//              Reset the units used by this class to the ui units.
//
{
        timeUnit = MTime::uiUnit();
        linearUnit = MDistance::uiUnit();
        angularUnit = MAngle::uiUnit();
}

const char *
animBase::tangentTypeAsWord(MFnAnimCurve::TangentType type)
//
//      Description:
//              Returns a string with a test based desription of the passed
//              MFnAnimCurve::TangentType. 
//
{
        switch (type) {
                case MFnAnimCurve::kTangentGlobal:
                        return (kWordTangentGlobal);
                case MFnAnimCurve::kTangentFixed:
                        return (kWordTangentFixed);
                case MFnAnimCurve::kTangentLinear:
                        return (kWordTangentLinear);
                case MFnAnimCurve::kTangentFlat:
                        return (kWordTangentFlat);
                case MFnAnimCurve::kTangentSmooth:
                        return (kWordTangentSmooth);
                case MFnAnimCurve::kTangentStep:
                        return (kWordTangentStep);
                case MFnAnimCurve::kTangentSlow:
                        return (kWordTangentSlow);
                case MFnAnimCurve::kTangentFast:
                        return (kWordTangentFast);
                case MFnAnimCurve::kTangentClamped:
                        return (kWordTangentClamped);
                case MFnAnimCurve::kTangentPlateau:
                        return (kWordTangentPlateau);
                case MFnAnimCurve::kTangentStepNext:
                        return (kWordTangentStepNext);
                default:
                        break;
        }
        return (kWordTangentGlobal);
}

const char *
animBase::infinityTypeAsWord(MFnAnimCurve::InfinityType type)
//      
//      Description:
//              Returns a string containing the name of the passed 
//              MFnAnimCurve::InfinityType type.
//
{
        switch (type) {
                case MFnAnimCurve::kConstant:
                        return (kWordConstant);
                case MFnAnimCurve::kLinear:
                        return (kWordLinear);
                case MFnAnimCurve::kCycle:
                        return (kWordCycle);
                case MFnAnimCurve::kCycleRelative:
                        return (kWordCycleRelative);
                case MFnAnimCurve::kOscillate:
                        return (kWordOscillate);
                default:
                        break;
        }
        return (kWordConstant);
}

const char *
animBase::outputTypeAsWord (MFnAnimCurve::AnimCurveType type)
//
//      Description:
//              Returns a string identifying the output type of the
//              passed MFnAnimCurve::AnimCurveType.
//
{
        switch (type) {
                case MFnAnimCurve::kAnimCurveTL:
                case MFnAnimCurve::kAnimCurveUL:
                        return (kWordTypeLinear);
                case MFnAnimCurve::kAnimCurveTA:
                case MFnAnimCurve::kAnimCurveUA:
                        return (kWordTypeAngular);
                case MFnAnimCurve::kAnimCurveTT:
                case MFnAnimCurve::kAnimCurveUT:
                        return (kWordTypeTime);
                case MFnAnimCurve::kAnimCurveTU:
                case MFnAnimCurve::kAnimCurveUU:
                        return (kWordTypeUnitless);
                case MFnAnimCurve::kAnimCurveUnknown:
                        return (kWordTypeUnitless);
        }
        return (kWordTypeUnknown);
}

const char *
animBase::boolInputTypeAsWord(bool isUnitless) 
//
//      Description:
//              Returns a string based on a bool. 
//
{
        if (isUnitless) {
                return (kWordTypeUnitless);
        } else {
                return (kWordTypeTime);
        }
}

//-------------------------------------------------------------------------
//      Class animWriter
//-------------------------------------------------------------------------

animWriter::animWriter()
//
//      Description:
//              Class constructor.
//
{
}

animWriter::~animWriter()
//
//      Description:
//              Class destructor.
//
{
}

bool animWriter::writeHeader(ofstream& clip,
                                                        double startTime, double endTime,
                                                        double startUnitless, double endUnitless
)
//
//      Description:
//              Writes the header for the file. The header contains the clipboard
//              specific data. 
//
{
        if (!clip) {
                return false;
        }

        clip << kAnimVersion << kSpaceChar << kAnimVersionString << kSemiColonChar << endl;
        clip << kMayaVersion << kSpaceChar << MGlobal::mayaVersion() << kSemiColonChar << endl;

        if (startTime != endTime) {
                MString unit;
                animUnitNames::setToShortName(timeUnit, unit);
                clip << kTimeUnit << kSpaceChar << unit << kSemiColonChar << endl;
                animUnitNames::setToShortName(linearUnit, unit);
                clip << kLinearUnit << kSpaceChar << unit << kSemiColonChar << endl;
                animUnitNames::setToShortName(angularUnit, unit);
                clip << kAngularUnit << kSpaceChar << unit << kSemiColonChar << endl;
                clip << kStartTime << kSpaceChar << startTime << kSemiColonChar << endl;
                clip << kEndTime << kSpaceChar << endTime << kSemiColonChar << endl;
        }

        if (startUnitless != endUnitless) {
                clip << kStartUnitless << kSpaceChar << startUnitless << 
                                kSemiColonChar << endl;
                clip << kEndUnitless << kSpaceChar << endUnitless << 
                                kSemiColonChar << endl;
        }

        return true;
}

bool animWriter::writeAnimCurve(ofstream &clip, 
                                                                const MObject *animCurveObj,
                                                                bool verboseUnits /* false */)
//
//      Description:
//              Write out the anim curve from the clipboard item into the
//              ofstream. The actual anim curve data is written out.
//
//              This method returns true if the write was successful.
//
{
        if (NULL == animCurveObj || animCurveObj->isNull() || !clip) {
                return true;
        }

        MStatus status = MS::kSuccess;
        MFnAnimCurve animCurve(*animCurveObj, &status);
        if (MS::kSuccess != status) {
                cerr << "Error: Could not read the anim curve for export." << endl;
                return false;
        }

        clip << kAnimData << kSpaceChar << kBraceLeftChar << endl;

        clip << kTwoSpace << kInputString << kSpaceChar <<
                        boolInputTypeAsWord(animCurve.isUnitlessInput()) << 
                        kSemiColonChar << endl;

        clip << kTwoSpace << kOutputString << kSpaceChar <<
                        outputTypeAsWord(animCurve.animCurveType()) << kSemiColonChar << endl;

        clip << kTwoSpace << kWeightedString << kSpaceChar <<
                        (animCurve.isWeighted() ? 1 : 0) << kSemiColonChar << endl;

        //      These units default to the units in the header of the file.
        //      
        if (verboseUnits) {
                clip << kTwoSpace << kInputUnitString << kSpaceChar;
                if (animCurve.isTimeInput()) {
                        MString unitName;
                        animUnitNames::setToShortName(timeUnit, unitName);
                        clip << unitName;
                } else {
                        //      The anim curve has unitless input.
                        //
                        clip << kUnitlessString;
                }
                clip << kSemiColonChar << endl;

                clip << kTwoSpace << kOutputUnitString << kSpaceChar;
        }

        double conversion = 1.0;
        MString unitName;
        switch (animCurve.animCurveType()) {
                case MFnAnimCurve::kAnimCurveTA:
                case MFnAnimCurve::kAnimCurveUA:
                        animUnitNames::setToShortName(angularUnit, unitName);
                        if (verboseUnits) clip << unitName;
                        {
                                MAngle angle(1.0);
                                conversion = angle.as(angularUnit);
                        }
                        break;
                case MFnAnimCurve::kAnimCurveTL:
                case MFnAnimCurve::kAnimCurveUL:
                        animUnitNames::setToShortName(linearUnit, unitName);
                        if (verboseUnits) clip << unitName;
                        {
                                MDistance distance(1.0);
                                conversion = distance.as(linearUnit);
                        }
                        break;
                case MFnAnimCurve::kAnimCurveTT:
                case MFnAnimCurve::kAnimCurveUT:
                        animUnitNames::setToShortName(timeUnit, unitName);
                        if (verboseUnits) clip << unitName;
                        break;
                default:
                        if (verboseUnits) clip << kUnitlessString;
                        break;
        }
        if (verboseUnits) clip << kSemiColonChar << endl;

        if (verboseUnits) {
                MString angleUnitName;
                animUnitNames::setToShortName(angularUnit, angleUnitName);
                clip << kTwoSpace << kTanAngleUnitString << 
                                kSpaceChar << angleUnitName << kSemiColonChar << endl;
        }

        clip << kTwoSpace << kPreInfinityString << kSpaceChar <<
                        infinityTypeAsWord(animCurve.preInfinityType()) << 
                        kSemiColonChar << endl;

        clip << kTwoSpace << kPostInfinityString << kSpaceChar <<
                        infinityTypeAsWord(animCurve.postInfinityType()) << 
                        kSemiColonChar << endl;

        clip << kTwoSpace << kKeysString << kSpaceChar << kBraceLeftChar << endl;

        // And then write out each keyframe
        //
        unsigned numKeys = animCurve.numKeyframes();
        for (unsigned i = 0; i < numKeys; i++) {
                clip << kTwoSpace << kTwoSpace;
                if (animCurve.isUnitlessInput()) {
                        clip << animCurve.unitlessInput(i);
                }
                else {
                        clip << animCurve.time(i).value();
                }

                clip << kSpaceChar << (conversion*animCurve.value(i));

                clip << kSpaceChar << tangentTypeAsWord(animCurve.inTangentType(i));
                clip << kSpaceChar << tangentTypeAsWord(animCurve.outTangentType(i));

                clip << kSpaceChar << (animCurve.tangentsLocked(i) ? 1 : 0);
                clip << kSpaceChar << (animCurve.weightsLocked(i) ? 1 : 0);
                clip << kSpaceChar << (animCurve.isBreakdown(i) ? 1 : 0);

                if (animCurve.inTangentType(i) == MFnAnimCurve::kTangentFixed) {
                        MAngle angle;
                        double weight;
                        animCurve.getTangent(i, angle, weight, true);

                        clip << kSpaceChar << angle.as(angularUnit);
                        clip << kSpaceChar << weight;
                }
                if (animCurve.outTangentType(i) == MFnAnimCurve::kTangentFixed) {
                        MAngle angle;
                        double weight;
                        animCurve.getTangent(i, angle, weight, false);

                        clip << kSpaceChar << angle.as(angularUnit);
                        clip << kSpaceChar << weight;
                }

                clip << kSemiColonChar << endl;
        }
        clip << kTwoSpace << kBraceRightChar << endl;

        clip << kBraceRightChar << endl;

        return true;
}

Autodesk® Maya® 2009 © 1997-2008 Autodesk, Inc. All rights reserved. Generated with doxygen 1.5.6