Nebexport
From DreamsteepWiki
#ifndef M_NEBULA_MESHEXPORT_CMD_H
#define M_NEBULA_MESHEXPORT_CMD_H
#include <maya/MPxCommand.h>
#include <maya/MDagPath.h>
//forward declarations
class wfObject;
class MNebulaMeshExportCmd : public MPxCommand {
public:
virtual MStatus doIt(const MArgList& args);
static void* creator() { return new MNebulaMeshExportCmd; }
private:
/**
* Opens the mesh file specified in the command arguments.
* @return Success status
*/
MStatus openMeshFile();
/**
* Exports the vertices in the specified mesh.
* @return Success status
*/
MStatus exportVertices();
/**
* Exports UV coordinates for texturing.
* Up to four UV sets will be exported.
* @return Success status
*/
MStatus exportUVs();
/**
* Exports the vertex normals.
* @return Success status
*/
MStatus exportNormals();
/**
* Exports the faces in the mesh.
* @return Success status
*/
MStatus exportPolygons();
/**
* Exports vertex colors, if any exist for the object.
* @return Success status
*/
MStatus exportVertexColors();
/**
* Runs cleanup functions in WFTools on the mesh object.
* @return Success status
*/
MStatus cleanupMesh();
/**
* Writes the mesh file to the specified file name.
* @return Success status.
*/
MStatus writeMeshFile();
/**
* Closes the file.
* @return Success status
*/
MStatus closeMeshFile();
static const int MAX_UVSETS;
MString m_filename;
MDagPath m_shapePath;
FILE* m_file;
wfObject *m_mesh;
bool m_hasColors;
};
#endif
#include "MNebulaMeshExportCmd.h"
#include <maya/MString.h>
#include <maya/MArgList.h>
#include <maya/MFnPlugin.h>
#include <maya/MObject.h>
#include <maya/MSelectionList.h>
#include <maya/MDagPath.h>
#include <maya/MFnMesh.h>
#include <maya/MGlobal.h>
#include <maya/MItGeometry.h>
#include <maya/MFloatArray.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MColorArray.h>
#include <maya/MItMeshPolygon.h>
#include <direct.h>
#include <sys/types.h>
#include <sys/STAT.H>
//wftools
#include <tools/wftoolbox.h>
#include <tools/wftools.h>
#define CHECKSTAT(status_, msg_) \
if (!status_) { \
MString errstr("ERROR:"); \
errstr += msg_; \
errstr += " (LINE "; \
errstr += __LINE__; \
errstr += " FILE "; \
errstr += __FILE__; \
errstr += ")\n"; \
status_.perror(errstr); \
return status_; \
}
const int MNebulaMeshExportCmd::MAX_UVSETS = 4;
MStatus __declspec(dllexport) initializePlugin(MObject obj) {
MFnPlugin pluginFn(obj, "ORI", "0.5");
MStatus result;
result = pluginFn.registerCommand("exportNebulaMesh", MNebulaMeshExportCmd::creator);
CHECKSTAT(result, "Unable to register command");
return result;
}
MStatus __declspec(dllexport) uninitializePlugin(MObject obj) {
MFnPlugin pluginFn(obj, "ORI", "0.5");
MStatus result;
result = pluginFn.deregisterCommand("exportNebulaMesh");
CHECKSTAT(result, "Unable to deregister command");
return result;
}
MStatus MNebulaMeshExportCmd::doIt(const MArgList& args) {
MStatus result = MStatus::kSuccess;
m_hasColors = false;
unsigned int transPathIdx = args.flagIndex("p", "path");
if (transPathIdx == MArgList::kInvalidArgIndex) {
result.perror("Path argument not specified");
return result;
}
unsigned int meshFileIdx = args.flagIndex("f", "file");
if (meshFileIdx == MArgList::kInvalidArgIndex) {
result.perror("File argument not specified");
}
MString transPath;
result = args.get(transPathIdx+1, transPath);
CHECKSTAT(result, "Unable to get path argument");
result = args.get(meshFileIdx+1, m_filename);
CHECKSTAT(result, "Unable to get file argument");
//MGlobal::displayInfo("meshPath: "+transPath);
//MGlobal::displayInfo("meshFile: "+m_filename);
//I wonder if there is a better way to do this, but I can't seem to find
//a way to simply get a DagNode using a string.
MSelectionList list;
result = list.add(transPath);
CHECKSTAT(result, "Unable to add meshpath");
result = list.getDagPath(0, m_shapePath);
CHECKSTAT(result, "Unable to retrieve dagpath from selection list (perhaps the path given does not uniquely identify a node)");
result = m_shapePath.extendToShape();
CHECKSTAT(result, "extending to shape");
//get mesh functor
if (m_shapePath.apiType() != MFn::kMesh) {
result.perror("Wrong type of object given (doesn't have a mesh shape)");
result = MStatus::kFailure;
return result;
}
//MGlobal::displayInfo("Shape path: "+m_shapePath.fullPathName());
m_mesh = new wfObject();
result = exportVertices();
CHECKSTAT(result, "Exporting vertices failed");
result = exportUVs();
CHECKSTAT(result, "Exporting UVs failed");
result = exportNormals();
CHECKSTAT(result, "Exporting normals failed");
result = exportVertexColors();
CHECKSTAT(result, "Exporting vertex colors failed");
result = exportPolygons();
CHECKSTAT(result, "Exporting polygons failed");
result = cleanupMesh();
CHECKSTAT(result, "Cleaning mesh failed");
result = openMeshFile();
CHECKSTAT(result, "Opening mesh file failed");
result = writeMeshFile();
CHECKSTAT(result, "Writing mesh file failed");
result = closeMeshFile();
CHECKSTAT(result, "Closing mesh file failed");
delete m_mesh;
return result;
}
MStatus MNebulaMeshExportCmd::openMeshFile() {
MStatus result = MStatus::kSuccess;
vector<MString> paths;
MString tmp = m_filename;
printf("file: %s\n", m_filename.asChar());
//break up path into directories
while (1) {
int end = tmp.rindex('\\');
if (end == -1) {
end = tmp.rindex('/');
}
if (end <= 0) {
break;
}
tmp = tmp.substring(0, end-1);
int begin = tmp.rindex('\\');
if (begin == -1) {
begin = tmp.rindex('/');
}
MString pathElem = tmp.substring(begin+1, tmp.length()-1);
paths.push_back(pathElem);
}
MString currentDir = "";
for (vector<MString>::reverse_iterator ri = paths.rbegin(); ri != paths.rend(); ++ri ) {
currentDir += ri->asChar();
struct stat dirStat;
int status = stat(currentDir.asChar(), &dirStat);
bool isDrive = (currentDir.length()==2 && currentDir.asChar()[1] == ':')? true : false;
//if directory not found
if (!isDrive && status == -1) {
status = mkdir(currentDir.asChar());
if (status) {
result.perror("Unable to create output directory: "+currentDir+" - "+strerror(status));
result = MStatus::kSuccess;
return result;
}
}
currentDir += "/";
}
m_file = fopen(m_filename.asChar(), "wt");
if (!m_file) {
result.perror("Unable to open file: "+m_filename+" - "+strerror(errno));
result = MStatus::kFailure;
}
else {
MString msg("Writing mesh to file: ");
msg += m_filename;
msg += "\n";
MGlobal::displayInfo(msg);
}
return result;
}
MStatus MNebulaMeshExportCmd::exportVertices() {
MStatus result = MStatus::kSuccess;
MItGeometry geoIt(m_shapePath, &result);
CHECKSTAT(result, "Unable to create MItGeometry");
for (; !geoIt.isDone(); geoIt.next())
{
//changed from kWorld;
MPoint pnt = geoIt.position(MSpace::kObject, &result);
CHECKSTAT(result, "SaveVertexAttributes: MItGeometry::position failed");
wfCoord currentVertex((float)pnt.x, (float)pnt.y, (float)pnt.z);
m_mesh->v_array.push_back(currentVertex);
}
return result;
}
MStatus MNebulaMeshExportCmd::exportUVs() {
MStatus result = MStatus::kSuccess;
MFnMesh fnMesh(m_shapePath, &result);
CHECKSTAT(result, "Unable to create mesh functor");
MStringArray uvSets;
result = fnMesh.getUVSetNames(uvSets);
CHECKSTAT(result, "Getting UV Set names");
MFloatArray uArray, vArray;
for (unsigned int i = 0; i < uvSets.length() && i < MAX_UVSETS; i++)
{
result = fnMesh.getUVs(uArray, vArray, &uvSets[i]);
CHECKSTAT(result, "SaveVertexAttributes: MFnMesh::getUVs failed");
for (unsigned int j = 0; j < uArray.length(); j++) {
vector2 curUV(uArray[j],vArray[j]);
switch(i) {
case 0:
m_mesh->vt_array.push_back(curUV);
break;
case 1:
m_mesh->vt1_array.push_back(curUV);
break;
case 2:
m_mesh->vt2_array.push_back(curUV);
break;
case 3:
m_mesh->vt3_array.push_back(curUV);
break;
}
}
}
return result;
}
MStatus MNebulaMeshExportCmd::exportNormals() {
MStatus result = MStatus::kSuccess;
MFnMesh fnMesh(m_shapePath, &result);
CHECKSTAT(result, "Unable to create mesh functor");
MFloatVectorArray normals;
//changed from kWorld
result = fnMesh.getNormals(normals, MSpace::kObject);
CHECKSTAT(result, "getNormals failed");
//max of four layers of textures
for (unsigned int i = 0; i < normals.length(); i++) {
vector3 v(normals[i].x, normals[i].y, normals[i].z);
m_mesh->vn_array.push_back(v);
}
return result;
}
MStatus MNebulaMeshExportCmd::exportVertexColors() {
MStatus result = MStatus::kSuccess;
MFnMesh fnMesh(m_shapePath, &result);
CHECKSTAT(result, "Unable to create mesh functor");
MColorArray colorArray;
result = fnMesh.getVertexColors(colorArray);
CHECKSTAT(result, "Unable to get vertex colors");
for (unsigned int i = 0; i < colorArray.length(); ++i) {
m_hasColors = true;
vector4 *curColors;
//a value of -1 means that the this vertex has no coloring data
if (colorArray[i].r == -1) {
curColors = new vector4(0.0, 0.0, 0.0, 1.0);
}
else {
curColors = new vector4(colorArray[i].r, colorArray[i].g, colorArray[i].b, colorArray[i].a);
}
m_mesh->c_array.push_back(*curColors);
delete curColors;
}
return result;
}
MStatus MNebulaMeshExportCmd::exportPolygons() {
MStatus result = MStatus::kSuccess;
MItMeshPolygon polyIt(m_shapePath, MObject::kNullObj, &result);
CHECKSTAT(result, "Creating MItMeshPolygon failed");
// Count all the vertices in the meshes before us
//
/*int vertsAlreadyWritten = 0;
int normsAlreadyWritten = 0;
int UVsAlreadyWritten = 0;
for (unsigned int idx = 0; idx < meshIdx; idx++) // meshIdx is the current mesh index
{
vertsAlreadyWritten += m_vertsWritten[idx];
normsAlreadyWritten += m_normsWritten[idx];
UVsAlreadyWritten += m_UVsWritten[idx];
}*/
MFnMesh fnMesh(m_shapePath, &result);
CHECKSTAT(result, "Unable to create mesh functor");
MStringArray uvSets;
result = fnMesh.getUVSetNames(uvSets);
for (; !polyIt.isDone(); polyIt.next())
{
unsigned int numVerts = polyIt.polygonVertexCount(&result);
CHECKSTAT(result, "polygonVertexCount failed");
/*if (numVerts != 3)
{
result.perror("Number of vertices > 3");
continue;
}*/
wfFace curFace;
for (unsigned int i = 0; i < numVerts; i++)
{
//reset UV values
int uvIndices[MAX_UVSETS];
for (int j = 0; j < MAX_UVSETS; j++) {
uvIndices[j] = -1;
}
//fill list of UV indices
for (unsigned int k = 0; k < uvSets.length() && k < MAX_UVSETS; ++k) {
result = polyIt.getUVIndex(i, uvIndices[k], &uvSets[k]);
if (!result) {
//we may not have information for this uvset/vertex
uvIndices[k] = -1;
result.perror("Mesh does not have UV information for face, uvset="+uvSets[k]+"\n");
}
//CHECKSTAT(result, "Filling UV index");
}
int vertexIdx = polyIt.vertexIndex(i, &result);
CHECKSTAT(result, "Getting vertex index");
int normalIdx = polyIt.normalIndex(i, &result);
CHECKSTAT(result, "Getting normal index");
wfPoint curPoint(vertexIdx, normalIdx, (m_hasColors?vertexIdx:-1), uvIndices[0], uvIndices[1], uvIndices[2], uvIndices[3]);
curFace.points.push_back(curPoint);
}
m_mesh->f_array.push_back(curFace);
}
return result;
}
MStatus MNebulaMeshExportCmd::cleanupMesh() {
MStatus result = MStatus::kSuccess;
wfToolbox toolbox;
wfObject *tmp = new wfObject();
try {
toolbox.clean(*m_mesh, *tmp, 0.0000001f, 0.0000001f, 0.0000001f, 0.0000001f);
delete m_mesh;
m_mesh = tmp;
tmp = new wfObject();
toolbox.triangulate(*m_mesh, *tmp);
delete m_mesh;
m_mesh = tmp;
tmp = new wfObject();
toolbox.flatten(*m_mesh, *tmp);
delete m_mesh;
m_mesh = tmp;
}
catch (...) {
result = MStatus::kFailure;
CHECKSTAT(result, "Unknown exception caught");
}
return result;
}
MStatus MNebulaMeshExportCmd::writeMeshFile() {
m_mesh->save(m_file);
return MStatus::kSuccess;
}
MStatus MNebulaMeshExportCmd::closeMeshFile() {
MStatus result = MStatus::kSuccess;
int status = fclose(m_file);
if (status) {
return MStatus::kFailure;
CHECKSTAT(result, "Unable to close file");
}
return MStatus::kSuccess;
}
# Microsoft Developer Studio Project File - Name="MeshExporter" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Application" 0x0101 CFG=MeshExporter - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "MeshExporter.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "MeshExporter.mak" CFG="MeshExporter - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "MeshExporter - Win32 Release" (based on "Win32 (x86) Application") !MESSAGE "MeshExporter - Win32 Debug" (based on "Win32 (x86) Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "MeshExporter - Win32 Release" # PROP BASE Use_MFC 2 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "C:\Program Files\AliasWavefront\Maya4.5\\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /D "NT_PLUGIN" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 # ADD LINK32 Foundation.lib OpenMaya.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release\nebulaMeshExporterCmd.mll" /libpath:"C:\Program Files\AliasWavefront\Maya4.5\\lib" /export:initializePlugin /export:uninitializePlugin !ELSEIF "$(CFG)" == "MeshExporter - Win32 Debug" # PROP BASE Use_MFC 2 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "C:\Program Files\AliasWavefront\Maya4.5\\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /D "NT_PLUGIN" /FR /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # ADD LINK32 Foundation.lib OpenMaya.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug\nebulaMeshExporterCmd.mll" /pdbtype:sept /libpath:"C:\Program Files\AliasWavefront\Maya4.5\\lib" /export:initializePlugin /export:uninitializePlugin !ENDIF # Begin Target # Name "MeshExporter - Win32 Release" # Name "MeshExporter - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\MNebulaMeshExportCmd.cpp # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\MNebulaMeshExportCmd.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project

