#include <maya/MFStream.h>
#include <stdlib.h>
#include <string.h>
#include <maya/MGlobal.h>
#include <maya/MString.h>
#include <maya/MFnPlugin.h>
#include <maya/MPxFileTranslator.h>
#include <maya/MDagPath.h>
#include <maya/MPlug.h>
#include <maya/MPlugArray.h>
#include <maya/MObjectArray.h>
#include <maya/MItDag.h>
#include <maya/MItDependencyNodes.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnSet.h>
#include <maya/MSelectionList.h>
#include <maya/MItSelectionList.h>
#include <maya/MFnAnimCurve.h>
#include <maya/MAnimUtil.h>
#include "animExportUtil.h"
#include "animFileExport.h"
#if defined (OSMac_)
using namespace std;
extern "C" int strcasecmp (const char *, const char *);
#endif
#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
TanimExportUtil::TanimExportUtil()
{
}
TanimExportUtil::~TanimExportUtil()
{
}
MStatus
TanimExportUtil::writer (
const MFileObject &file,
const MString &,
FileAccessMode mode
)
{
ofstream animFile (file.fullName().asChar());
MSelectionList list;
if (mode == kExportActiveAccessMode) {
MGlobal::getActiveSelectionList (list);
}
else {
MItDag dagIt (MItDag::kBreadthFirst);
for (dagIt.next(); !dagIt.isDone(); dagIt.next()) {
MDagPath path;
if (dagIt.getPath (path) != MS::kSuccess) {
continue;
}
list.add (path);
dagIt.prune ();
}
MItDependencyNodes nodeIt;
for (; !nodeIt.isDone(); nodeIt.next()) {
MObject node = nodeIt.item();
if (node.isNull()) {
continue;
}
if (node.hasFn (MFn::kDagNode)) {
continue;
}
if (node.hasFn (MFn::kCharacter)) {
MFnDependencyNode fnNode (node);
MObject aMessage = fnNode.attribute (MString ("message"));
MPlug messagePlug (node, aMessage);
MPlugArray srcPlugArray;
messagePlug.connectedTo (srcPlugArray, false, true);
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;
}
if (!MAnimUtil::isAnimated (node)) {
continue;
}
list.add (node);
}
}
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 (i = 0; i < numPlugs; i++) {
MPlug plug = animatedPlugs[i];
MObjectArray animation;
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());
}
}
}
}
animWriter writer;
writer.writeHeader (animFile, startTime, endTime, startUnitless, endUnitless);
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)
{
MItDag dagIt (MItDag::kDepthFirst);
dagIt.reset (path, MItDag::kDepthFirst);
for (; !dagIt.isDone(); dagIt.next()) {
MDagPath thisPath;
if (dagIt.getPath (thisPath) != MS::kSuccess) {
continue;
}
MPlugArray animatedPlugs;
MObject node = thisPath.node();
MFnDependencyNode fnNode (node);
MAnimUtil::findAnimatedPlugs (thisPath, animatedPlugs);
unsigned int numPlugs = animatedPlugs.length();
if (numPlugs == 0) {
animFile << "anim " << fnNode.name().asChar() << " " << dagIt.depth() << " " << thisPath.childCount() << " 0;\n";
}
else {
writeAnimatedPlugs (animFile, animatedPlugs, fnNode.name(), dagIt.depth(), thisPath.childCount());
}
}
}
void
TanimExportUtil::write (ofstream &animFile, const MObject &node)
{
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++];
MFnSet fnSet (thisNode);
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++;
}
MPlugArray animatedPlugs;
MAnimUtil::findAnimatedPlugs (thisNode, animatedPlugs);
unsigned int numPlugs = animatedPlugs.length();
if (numPlugs == 0) {
animFile << "anim " << fnSet.name().asChar() << " " << thisDepth << " " << childCount << " 0;\n";
}
else {
writeAnimatedPlugs (animFile, animatedPlugs, fnSet.name(), thisDepth, childCount);
}
}
return;
}
MPlugArray animatedPlugs;
MFnDependencyNode fnNode (node);
MAnimUtil::findAnimatedPlugs (node, animatedPlugs);
unsigned int numPlugs = animatedPlugs.length();
if (numPlugs != 0) {
writeAnimatedPlugs (animFile, animatedPlugs, fnNode.name(), 0, 0);
}
}
void
TanimExportUtil::writeAnimatedPlugs (
ofstream &animFile,
const MPlugArray &animatedPlugs,
const MString &nodeName,
unsigned int depth,
unsigned int childCount
)
{
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;
}
animFile << "anim ";
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();
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 * ,
short
) const
{
const char *name = file.name().asChar();
int nameLength = (int)strlen(name);
if ((nameLength > 5) && !strcasecmp(name+nameLength-5, ".anim")) {
return (kIsMyFileType);
}
return (kNotMyFileType);
}
void *
TanimExportUtil::creator ()
{
return (new TanimExportUtil);
}
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);
}