Nebexport

From DreamsteepWiki

Jump to: navigation, search
#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








						
						
Personal tools