animExportUtil/animFileExport.cpp

animExportUtil/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) {
name.set(kDegLString);
break;
name.set(kRadLString);
break;
name.set(kMinLString);
break;
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) {
name.set(kDegString);
break;
name.set(kRadString);
break;
name.set(kMinString);
break;
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) {
name.set(kInLString);
break;
name.set(kFtLString);
break;
name.set(kYdLString);
break;
name.set(kMiLString);
break;
name.set(kMmLString);
break;
name.set(kCmLString);
break;
name.set(kKmLString);
break;
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) {
name.set(kInString);
break;
name.set(kFtString);
break;
name.set(kYdString);
break;
name.set(kMiString);
break;
name.set(kMmString);
break;
name.set(kCmString);
break;
name.set(kKmString);
break;
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) {
name.set(kHourTString);
break;
name.set(kMinTString);
break;
name.set(kSecTString);
break;
name.set(kMillisecTString);
break;
name.set(kGameTString);
break;
name.set(kFileTString);
break;
name.set(kPalTString);
break;
name.set(kNtscTString);
break;
name.set(kShowTString);
break;
name.set(kPalFTString);
break;
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";
const char *kWordTangentAuto = "auto";
// 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) {
return (kWordTangentGlobal);
return (kWordTangentFixed);
return (kWordTangentLinear);
return (kWordTangentFlat);
return (kWordTangentSmooth);
return (kWordTangentStep);
return (kWordTangentSlow);
return (kWordTangentFast);
return (kWordTangentClamped);
return (kWordTangentPlateau);
return (kWordTangentStepNext);
return (kWordTangentAuto);
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) {
return (kWordConstant);
return (kWordLinear);
return (kWordCycle);
return (kWordCycleRelative);
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) {
return (kWordTypeLinear);
return (kWordTypeAngular);
return (kWordTypeTime);
return (kWordTypeUnitless);
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;
}
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()) {
animUnitNames::setToShortName(angularUnit, unitName);
if (verboseUnits) clip << unitName;
{
MAngle angle(1.0);
conversion = angle.as(angularUnit);
}
break;
animUnitNames::setToShortName(linearUnit, unitName);
if (verboseUnits) clip << unitName;
{
MDistance distance(1.0);
conversion = distance.as(linearUnit);
}
break;
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;
}