File Translator Examples
The following examples demonstrate the usage of file translators.
Implementing the Proxy Polygon Exporter
The polyExporter
class inherits from MPxFileTranslator
and defines a number of virtual methods such as writer()
.
class polyExporter:public MPxFileTranslator
{
public:
polyExporter();
virtual ~polyExporter();
virtual MStatus writer (const MFileObject& file,
const MString& optionsString, MPxFileTranslator::FileAccessMode mode);
virtual bool haveWriteMethod () const;
virtual bool haveReadMethod () const;
virtual bool canBeOpened () const;
virtual MString defaultExtension () const = 0;
protected:
virtual bool isVisible(MFnDagNode& fnDag, MStatus& status);
virtual MStatus exportAll(ostream& os);
virtual MStatus exportSelection(ostream& os);
virtual void writeHeader(ostream& os);
virtual void writeFooter(ostream& os);
virtual MStatus processPolyMesh(const MDagPath dagPath, ostream& os);
virtual polyWriter* createPolyWriter(const MDagPath dagPath, MStatus& status) = 0;
};
Initializing the Plug-in
You need to register the new File Translator with MFnPlugin
when initializing the plug-in. There are six arguments associated with the registerFileTranslator
method. The latter three arguments are optional.
In this example, the argument Rawtext
is the file translator name. The option1=1
argument contains the default value of the options strings for the option box for the translator. The last argument is of boolean type that determines the ability for a translator to execute MEL scripts within the translator. A true
value of this argument allows the MEL commands be executed through the MGlobal::executeCommand
method.
MStatus initializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj, "Autodesk", "4.5", "Any");
status = plugin.registerFileTranslator("RawText",
"", polyRawExporter::creator, "", "option1=1", true);
if (!status) {
status.perror("registerFileTranslator");
return status;
}
return status;
}
Removing the translator is done in the uninitializePlugin()
through a call to the deregisterFileTranslator()
method of MFnPlugin
.
MStatus uninitializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin( obj );
status = plugin.deregisterFileTranslator("RawText");
if (!status) {
status.perror("deregisterFileTranslator");
return status;
}
return status;
}
Reader Method
You need to implement a reader()
method if you wish to load a file type that is supported by your file translator.
The haveReadMethod()
method checks if the translator provides a read method. In the LepTranslator
class, the method returns true because the reader()
method exists.
bool LepTranslator::haveReadMethod () const
{
return true;
}
The reader()
method reads each line of the file and returns a MS::kFailure
if it cannot be opened by the translator. If a file type cannot be recognized by the translator, the method creates a new object via MEL to support the data in that file.
MStatus LepTranslator::reader ( const MFileObject& file,
const MString& options, MPxFileTranslator::FileAccessMode mode)
{
#if defined (OSMac_)
char nameBuffer[MAXPATHLEN];
strcpy (nameBuffer, file.fullName().asChar());
const MString fname(nameBuffer);
#else
const MString fname = file.fullName();
#endif
MStatus rval(MS::kSuccess);
const int maxLineSize = 1024;
char buf[maxLineSize];
ifstream inputfile(fname.asChar(), ios::in);
if (!inputfile) {
// open failed
cerr << fname << ": could not be opened for reading\n";
return MS::kFailure;
}
if (!inputfile.getline (buf, maxLineSize)) {
cerr << "file " << fname << " contained no lines ... aborting\n";
return MS::kFailure;
}
if (0 != strncmp(buf, magic.asChar(), magic.length())) {
cerr << "first line of file " << fname;
cerr << " did not contain " << magic.asChar() << " ... aborting\n";
return MS::kFailure;
}
while (inputfile.getline (buf, maxLineSize)) {
//processing each line of the file
MString cmdString;
cmdString.set(buf);
if (!MGlobal::executeCommand(cmdString))
rval = MS::kFailure;
}
inputfile.close();
return rval;
}
Lines of files are processed in order to add new objects to the model.
Writer Method
You need to include a writer()
method if you want to save a file type that is supported by your translator.
The haveWriteMethod()
method checks if the translator has a write method. In the polyExporter
class, the method returns true because the writer()
method is implemented.
bool polyExporter::haveWriteMethod() const
{
return true;
}
The writer()
method provides a message through the script editor and returns a status to indicate the results.
In this example, only ‘export all’ and ‘export selection’ options are allowed when trying to save data. Other options will result in the display of a failure message through the script editor and returns a MS:kFailure
, which indicates that the file type cannot be understood by the translator. For your plug-in, you will have to set your own identifier string. If the method is successful, the data will be saved as a new file in a file type that is supported by the translator.
MStatus polyExporter::writer(const MFileObject& file,
const MString& /*options*/, MPxFileTranslator::FileAccessMode mode)
{
#if defined (OSMac_)
char nameBuffer[MAXPATHLEN];
strcpy (nameBuffer, file.fullName().asChar());
const MString fileName(nameBuffer);
#else
const MString fileName = file.fullName();
#endif
ofstream newFile(fileName.asChar(), ios::out);
if (!newFile) {
MGlobal::displayError(fileName + ": could not be opened for reading");
return MS::kFailure;
}
newFile.setf(ios::unitbuf);
writeHeader(newFile);
if (MPxFileTranslator::kExportAccessMode == mode) {
if (MStatus::kFailure == exportAll(newFile)) {
return MStatus::kFailure;
}
}
else if (MPxFileTranslator::kExportActiveAccessMode == mode) {
if (MStatus::kFailure == exportSelection(newFile)) {
return MStatus::kFailure;
}
}
else {
return MStatus::kFailure;
}
writeFooter(newFile);
newFile.flush();
newFile.close();
MGlobal::displayInfo("Export to " + fileName + " successful!");
return MS::kSuccess;
}
IdentifyFile Method
This method is typically used to check if the file extension of the file in question is the correct file type for the translator.
When a file is encountered, Maya calls the identifyFile()
method and queries each translator until it finds an appropriate match. The method is given an MFileObject
indicating the file being checked and a pointer name
to the initial file contents. In this example below, any file types being passed to this method other than .anim
will result in MS::kNotMyFileType
being returned, which indicates that the translator cannot understand the file type. Otherwise, the file is understood by the translator and is able to operate in Maya through the translator plug-in.
MPxFileTranslator::MFileKind
animExportUtil::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);
}
File Extensions
The defaultExtension()
method defines the default file extension of a translator and returns a string.
MString polyRawExporter::defaultExtension () const
{
return MString("raw");
}
In this example, Maya calls the method and saves the file with a .raw
file extension. Note that the period should not be included in the extension name.
FileAccess Mode
The fileAccessMode()
is an enum method that returns the type of file access mode that Maya is currently in. There are six types of file access modes in Maya.
In this example, the mode is kImportAccessMode
, which is when Maya imports data into the scene.
if (mode == kImportAccessMode) {
status = importAnim(animFile, pasteFlags);
}