//////////////////////Maya Exporter Plugin for Custom File format .celu///////////////////////////////
//==================================================================
//Copyright (C) 2007  Celambarasan Ramsamy
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation.
//
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//===================================================================

/* Date 10/25/07										*/



#include <maya/MIOStream.h>
#include <maya/MSimple.h>
#include <maya/MFileIO.h>
#include <maya/MFileObject.h>
#include <maya/MObject.h>
#include <maya/MStatus.h>
#include <maya/MString.h>
#include <maya/MPxFileTranslator.h>
#include <maya/MFnMesh.h>
#include <maya/MItDag.h>
#include <maya/MGlobal.h>
#include <maya/MFloatPointArray.h>
#include <maya/MPointArray.h>
#include <maya/MDagPathArray.h>
#include <maya/MDagPath.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MStringArray.h>
#include <maya/MFnPlugin.h>
#include <maya/MSelectionList.h>
#include <maya/MItSelectionList.h>
#include <maya/MFnCamera.h>
#include <maya/MFnLight.h>
#include<maya/MColor.h>
#include<maya/MFnPointLight.h>
#include<maya/MFnAmbientLight.h>
#include<maya/MFnDirectionalLight.h>
#include<maya/MFnSpotLight.h>
#include<maya/MFnAreaLight.h> 
#include<maya/MTransformationMatrix.h>
#include<maya/MMatrix.h>
#include <vector>
#include <fstream>


//	The plugin must export two functions namley initialize and uninitialize plugin

# define MLL_EXPORT __declspec(dllexport)


enum C_LIGHT_TYPE{C_POINT_LIGHT,C_SPOT_LIGHT};
enum C_DECAY_TYPE{C_NO_DECAY,C_LINEAR_DECAY,C_QUADRATIC_DECAY};




void ProcessMesh(MFnMesh& tMeshFunctionSet,MObject& tMeshMObject,std::ofstream& tOutputFileStream,unsigned int& tInstanceCountForCurrentMesh, MStatus * tErrorObject = 0)
{

	char tTempString[100];

	//	Output the name of the Mesh

	tOutputFileStream << "m," << tMeshFunctionSet.name().asChar() << ",";

	
	//	Get all the Dag Paths associated with this mesh node(and hence the number of mesh instances)

	tInstanceCountForCurrentMesh=tMeshFunctionSet.parentCount();


	//	If instance count is zero, then return failure and quit

	if(tInstanceCountForCurrentMesh==0)
	{

		*tErrorObject=MS::kFailure;

		MGlobal::displayError("Instance Count for current mesh is zero,reading scene data failed");

	}


	//	If instance count is greater than one get all the dag paths for the current mesh

	MDagPathArray tDagPathsForTheCurrentMesh;

	tMeshFunctionSet.getAllPaths(tDagPathsForTheCurrentMesh);


	//	For each DAG path(instance) get the vertex positions in world space

	for(unsigned int i=0; i < tInstanceCountForCurrentMesh; i++)
	{

		//	Write the instance count

		sprintf_s(tTempString, "instance,%d,",(i+1)); 
		tOutputFileStream << tTempString;


		MFloatPointArray tMeshVertexPointsArray;
		MFloatVectorArray tNormalArray;
		MStringArray tUVSetsNameArray;


		//	Attach the MFnMesh function set to the DAGPath objects

		MFnMesh tMeshCurrentDAGFunctionSet(tDagPathsForTheCurrentMesh[i],tErrorObject);


		//	Standard error checking

		if(*tErrorObject != MS::kSuccess)
		{
			MGlobal::displayError("Error Assigning Dag Path to MeshFunctionSet in current mesh");
			return;
		}



	//	Get the vertex positions from the mesh

	tMeshCurrentDAGFunctionSet.getPoints(tMeshVertexPointsArray,MSpace::kWorld);
	tMeshCurrentDAGFunctionSet.getNormals(tNormalArray,MSpace::kWorld);


	unsigned int tVertexCount=tMeshVertexPointsArray.length();
	unsigned int tNormalCount=tNormalArray.length();




	//	Output the number of vertices

	//cout << " Total Vertex Count " << tVertexCount << endl << endl;


	//write the number of vertices to the file

	sprintf_s(tTempString, "vertices,%d,",tVertexCount); 
	tOutputFileStream << tTempString;


	//	Itreate throught the array and print all the points

	for(unsigned int i=0;i<tVertexCount;i++)
	{
	
		//cout << tMeshVertexPointsArray[i].x << " " << tMeshVertexPointsArray[i].y << " " << tMeshVertexPointsArray[i].z << endl;

		sprintf_s(tTempString, "v,%e,%e,%e,",tMeshVertexPointsArray[i].x,tMeshVertexPointsArray[i].y,tMeshVertexPointsArray[i].z); 
		tOutputFileStream << tTempString;

	}


/*
	MVectorArray tVertexNormalArray(tVertexCount);

	//	Itreate through and get the face normals for all the vertex

	for(unsigned int i=0;i<tVertexCount;i++)
	{

		//	Retreive the per vertex normals

		tMeshCurrentDAGFunctionSet.getVertexNormal(i,tVertexNormalArray[i],MSpace::kWorld);

	}


	// write the number of face normals to the file

	sprintf_s(tTempString, "vertexnormals,%d,",tVertexCount); 
	tOutputFileStream << tTempString;
	
	
	//	Output the worldspace face normals

	for(unsigned int i=0;i < tVertexCount;i++)
	{

	//cout << tNormalArray[i].x << " " << tNormalArray[i].y << " " << tNormalArray[i].z << endl;

	sprintf_s(tTempString, "n,%e,%e,%e,",tVertexNormalArray[i].x,tVertexNormalArray[i].y,tVertexNormalArray[i].z); 
	tOutputFileStream << tTempString;

	}

*/
	// write the number of face normals to the file

	sprintf_s(tTempString, "normals,%d,",tNormalCount); 
	tOutputFileStream << tTempString;
	
	
	//	Output the worldspace face normals

	for(unsigned int i=0;i < tNormalCount;i++)
	{

	//cout << tNormalArray[i].x << " " << tNormalArray[i].y << " " << tNormalArray[i].z << endl;

	sprintf_s(tTempString, "n,%e,%e,%e,",tNormalArray[i].x,tNormalArray[i].y,tNormalArray[i].z); 
	tOutputFileStream << tTempString;

	}


	//	Get the names of the UV sets attached to this mesh object

	tMeshFunctionSet.getUVSetNames(tUVSetsNameArray);


	unsigned int tNumberOfUVSets=tUVSetsNameArray.length();


	//	A flag to indicate later whether index into the UV array needs to be added in the face data

	bool tDoesTextureCoordinateExist=true;


	//	Check for the case where the mesh has no UV sets attached to it

	if((!tNumberOfUVSets) || (!tMeshFunctionSet.numUVs(tUVSetsNameArray[0])))
	{
		//cout<< "No Texture Data Available";

		//	No UV set is attached to this object, indicate UV set count as zero

		tOutputFileStream << "uvsetcount,0,";


		//	Dont add index into the UV array for the polygon data

		tDoesTextureCoordinateExist=false;


	}
	else
	{

		//	If texture co-ordinates are available then write them to file

		sprintf_s(tTempString, "uvsetcount,%d,",tNumberOfUVSets); 
		tOutputFileStream << tTempString;

		//cout << " Number Of Texture Co-ordinate Sets : " << tNumberOfUVSets << endl;


		//	For each UV set display the texture co-ordinate for the individual vertices

		for(unsigned int i=0;i<tNumberOfUVSets;i++)
		{

			//	write the name of the UVSet to the file

			tOutputFileStream  << tUVSetsNameArray[i].asChar() << ",";


			//cout << tUVSetsNameArray[i].asChar() << endl;

			MFloatArray tUCoordinates,tVCoordinates;

			tMeshFunctionSet.getUVs(tUCoordinates,tVCoordinates,&tUVSetsNameArray[i]);


			//	Get the number of texture co-ordinate values in this given set

			unsigned int tTextureCoordinateValuesCount=tMeshFunctionSet.numUVs(tUVSetsNameArray[i]);


			//	Write the number of texture co-ordinate values in this given set to the file

			sprintf_s(tTempString, "%d,",tTextureCoordinateValuesCount); 
			tOutputFileStream << tTempString;
			
			//	Loop through and write all the UV coordinates in the current set

			for(unsigned int i=0;i<tTextureCoordinateValuesCount;i++)
			{

				sprintf_s(tTempString, "%e,%e,",tUCoordinates[i],tVCoordinates[i]); 
				tOutputFileStream << tTempString;

				//cout << tUCoordinates[i] << " " << tVCoordinates[i] << endl;
			}

			

		}
	}

	//	Get the index for each vertex

	//	Add a polygon itreator to the mesh object
	
	MItMeshPolygon tCurrentMeshPolygonItreator(tMeshMObject,tErrorObject);


	//	Standard error checking

	if(*tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error Creating Polygon Itreator for current mesh object");
		return;
	}

	unsigned int tFaceCount=0;


	//	Loop through and count the number of polygons in the mesh

	while(!tCurrentMeshPolygonItreator.isDone())
	{
		tFaceCount++;
		tCurrentMeshPolygonItreator.next();
	}


	//	Reset the face itreator to the first polygon 

	tCurrentMeshPolygonItreator.reset();


	//	Write the face count for the current mesh

	sprintf_s(tTempString, "facecount,%d,",tFaceCount); 
	tOutputFileStream << tTempString;


	//	Loop until all the polygons are done

	while(!tCurrentMeshPolygonItreator.isDone())
	{

		unsigned int tVertexCountForTheCurrentPolygon=tCurrentMeshPolygonItreator.polygonVertexCount();


		//	Write out the vertex count for the current polygon

		sprintf_s(tTempString, "f,%d,",tVertexCountForTheCurrentPolygon); 
		tOutputFileStream << tTempString;


		//	Write out vi to indicate the start of vertex index count

		tOutputFileStream << "vi,";


		//	Write out the index into the vertex array

		for(unsigned int i=0;i<tVertexCountForTheCurrentPolygon;i++)
		{

		sprintf_s(tTempString, "%d,",tCurrentMeshPolygonItreator.vertexIndex(i)); 
		tOutputFileStream << tTempString;

			//cout << tCurrentMeshPolygonItreator.vertexIndex(i) << " ";
		}


		//	Write out ni to indicate the start of vertex index count

		tOutputFileStream << "ni,";


		//	Write out the index into the normal array

		for(unsigned int i=0;i<tVertexCountForTheCurrentPolygon;i++)
		{

		sprintf_s(tTempString, "%d,",tCurrentMeshPolygonItreator.normalIndex(i)); 
		tOutputFileStream << tTempString;

			//cout << tCurrentMeshPolygonItreator.vertexIndex(i) << " ";
		}


		//	Write out the index into the UV array for each vertex of this face, only if texturing info exists for this polygonal face

		if(tDoesTextureCoordinateExist)
		{

			//	For each UV set, write out the index into the corresponding UV array for each vertex of the polygonal face

			for(unsigned int j=0;j<tNumberOfUVSets;j++)
			{
			
			//	write out the count that identifies a UV set

			sprintf_s(tTempString, "uvi,%d,",j+1); 
			tOutputFileStream << tTempString;


			int tIndexIntoUVArray;

			//	Write out the index into the UV array

			for(unsigned int i=0;i<tVertexCountForTheCurrentPolygon;i++)
			{

			//	Check for error while retreiving UV index

			if(tCurrentMeshPolygonItreator.getUVIndex(i,tIndexIntoUVArray,&tUVSetsNameArray[j]) != MS::kSuccess)
			{
			MGlobal::displayError("Error Retreiving UV index for Polygonal Face");
			return;
			}

			sprintf_s(tTempString, "%d,",tIndexIntoUVArray); 
			tOutputFileStream << tTempString;

				//cout << tCurrentMeshPolygonItreator.vertexIndex(i) << " ";
			}
			}
		}


		//	Write Out the Vertex Color for the Current Polygonal Face in RGBA format


		tOutputFileStream << "vc,";

		for(unsigned int i=0;i<tVertexCountForTheCurrentPolygon;i++)
		{

			//	Read the vertex color only if the current vertex has a vertex color set for it

			if(tCurrentMeshPolygonItreator.hasColor(i))
			{

				MColor tCurrentVertexColor;

				if(tCurrentMeshPolygonItreator.getColor(tCurrentVertexColor,i) != MS::kSuccess)
				{
				MGlobal::displayError("Error Retreiving Vertex Color for Polygonal Face");
				return;
				}

				//	Write out the retreived color

				sprintf_s(tTempString, "%f,%f,%f,%f,",tCurrentVertexColor.r,tCurrentVertexColor.g,tCurrentVertexColor.b,tCurrentVertexColor.a); 
				tOutputFileStream << tTempString;

			}
			else
			{
				//	If the vertex does not have a color associated with it then return a default black color

				tOutputFileStream << "0.0,0.0,0.0,1.0,";

			}

		}





			



		//cout << endl;

		tCurrentMeshPolygonItreator.next();
	}

	
	}

	//	This mesh has been read sucessfully

	*tErrorObject = MS::kSuccess;

}








MStatus ExportCommand( MString tFileName)
{
	
	//	Keeps track of the number of mesh objects and their instances

	std::vector<int> tMeshAndInstanceCount;

	//	Take the input argument and create a .celu Data File

	MString tDataFileName=tFileName+"_data.celu";
	MString tHeaderFileName=tFileName+"_header.celu";
	MString tCameraFileName=tFileName+"_camera.celu";
	MString tLightFileName=tFileName+"_light.celu";

	//	Create a file output stream for outputing the scene data

	std::ofstream tOutputDataFileStream (tDataFileName.asChar(),std::ios::out | std::ios::binary);


	//	Create another file output stream for outputing the scene data header file

	std::ofstream tOutputHeaderFileStream (tHeaderFileName.asChar(),std::ios::out | std::ios::binary);


	MStatus tErrorObject;

	
	//	Create an Dag Node Itreator and itreate through all the meshes in the scene

	MItDag tItreator(MItDag::kDepthFirst,MFn::kMesh,&tErrorObject);




	//	Standard error checking

	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error Creating Dag Itreator");
		tOutputDataFileStream.close();
		tOutputHeaderFileStream.close();
		return tErrorObject;
	}


	//	Loop through all the meshes that are not intermediate objects

	while(!tItreator.isDone())
	{

		//	Attach the function set to the object

		MFnMesh tMeshFunctionSet(tItreator.item(),&tErrorObject);


		//	Standard error checking

		if(tErrorObject != MS::kSuccess)
		{
			MGlobal::displayError("Error attaching Mesh function set to DAG node");
			tOutputDataFileStream.close();
			tOutputHeaderFileStream.close();
			return tErrorObject;
		}


		//	We are only interested in non history Items

		if(!tMeshFunctionSet.isIntermediateObject())
		{

			unsigned int tInstanceCountForCurrentMesh=1;


			//	Process this non history mesh Object

			ProcessMesh(tMeshFunctionSet,tItreator.item(),tOutputDataFileStream,tInstanceCountForCurrentMesh,&tErrorObject);


			//	Standard Error Checking

			if(tErrorObject != MS::kSuccess)
			{
				MGlobal::displayError("Error writing Mesh Data To File");
				tOutputDataFileStream.close();
				tOutputHeaderFileStream.close();
				return tErrorObject;
			}


			//	Update the instance count for the current mesh

			tMeshAndInstanceCount.push_back(tInstanceCountForCurrentMesh);

		}

		tItreator.next();
	}


	char tTempString[100];

	//	Write out the scene data header file

	sprintf_s(tTempString, "mesh,%d,",(int)tMeshAndInstanceCount.size()); 
	tOutputHeaderFileStream << tTempString;


	//	Write out the number of instances of each mesh

	for(unsigned int i=0;i < tMeshAndInstanceCount.size();i++)
	{
		sprintf_s(tTempString, "%d,",tMeshAndInstanceCount[i]); 
		tOutputHeaderFileStream << tTempString;
	}

	//	Close the file after writing

	tOutputDataFileStream.close();
	tOutputHeaderFileStream.close();


	//	Export the details of the perspective camera for this scene


	//	Loop through all the cameras and locate the perspective camera in the scene

	MItDag tCameraItreator(MItDag::kDepthFirst,MFn::kCamera,&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error creating camera itreator");

	}


	unsigned int tPerspectiveCameraCount=0;


	//	Count the number of perspective cameras in the scene

	while(!tCameraItreator.isDone())
	{ 

		MDagPath tCameraDagPath;
		
		tCameraItreator.getPath(tCameraDagPath);


		// Attach the function set to the camera dag path

		MFnCamera tCameraFunctionSet(tCameraDagPath);

		//	Check if this is the perspShape Camera Node

		if(tCameraFunctionSet.isOrtho())
		{

			//	Else Move on to the Next Camera

			tCameraItreator.next();

			continue;
		}

		tPerspectiveCameraCount++;

		tCameraItreator.next();

	}


	tCameraItreator.reset();


	//	Create a file output stream for outputing the current perspective camera position data

	std::ofstream tOutputCameraFileStream (tCameraFileName.asChar(),std::ios::out | std::ios::binary);


	//	Write the count of total number of perspective cameras in the scene

	sprintf_s(tTempString, "%d,",tPerspectiveCameraCount); 

	tOutputCameraFileStream << tTempString;



	while(!tCameraItreator.isDone())
	{  

	MDagPath tCameraDagPath;
	
	tCameraItreator.getPath(tCameraDagPath);


	// Attach the function set to the camera dag path

	MFnCamera tCameraFunctionSet(tCameraDagPath);


	//	Check if this is the perspShape Camera Node

	if(tCameraFunctionSet.isOrtho() || tCameraFunctionSet.name() == MString(""))
	{

		//	Else Move on to the Next Camera

		tCameraItreator.next();

		continue;
	}




	tOutputCameraFileStream << "camera,";


	//	Write Out the name of the Camera

	tOutputCameraFileStream << tCameraFunctionSet.name().asChar() << ",";


	MPoint tPoint;

	
	//	Write out the eye position

	tPoint=tCameraFunctionSet.eyePoint(MSpace::kWorld,&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading Camera eye point");

		
	}


	//	Write out the eye point to the file

	sprintf_s(tTempString, "eyepoint,%e,%e,%e,",tPoint.x,tPoint.y,tPoint.z); 

	tOutputCameraFileStream << tTempString;


	//	Write out the LookAt position

	tPoint=tCameraFunctionSet.centerOfInterestPoint(MSpace::kWorld,&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading Camera centerOfInterest Point");

	
	}


	//	Write out the lookAt point to the file

	sprintf_s(tTempString, "lookatpoint,%e,%e,%e,",tPoint.x,tPoint.y,tPoint.z); 

	tOutputCameraFileStream << tTempString;


	MVector tVector;


	//	Write out the view vector

	tVector=tCameraFunctionSet.viewDirection(MSpace::kWorld,&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading Camera view direction");
	
	}


	tVector.normalize();

	//	Write out the view vector to the file

	sprintf_s(tTempString, "viewvector,%e,%e,%e,",tVector.x,tVector.y,tVector.z); 

	tOutputCameraFileStream << tTempString;



	//	Write out the Up Axis

	tVector=tCameraFunctionSet.upDirection(MSpace::kWorld,&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading Camera up direction");

	
	}


	tVector.normalize();

	//	Write out the up vector to the file

	sprintf_s(tTempString, "upvector,%e,%e,%e,",tVector.x,tVector.y,tVector.z); 

	tOutputCameraFileStream << tTempString;


	//	Write out the right Axis

	tVector=tCameraFunctionSet.rightDirection(MSpace::kWorld,&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading Camera right direction");

	
	}


	tVector.normalize();

	//	Write out the right direction to the file

	sprintf_s(tTempString, "rightvector,%e,%e,%e,",tVector.x,tVector.y,tVector.z); 

	tOutputCameraFileStream << tTempString;


	float tAspectRatio=tCameraFunctionSet.aspectRatio(&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading pixel aspect ratio");
	}


	//	Write out the aspect ratio to the file

	sprintf_s(tTempString, "aspectratio,%e,",tAspectRatio); 

	tOutputCameraFileStream << tTempString;


	//	Write out the vertical fov

	float tVerticalFov=tCameraFunctionSet.verticalFieldOfView(&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading Camera verical fov");
	}


	//	Write out the vertical fov to the file

	sprintf_s(tTempString, "verticalfov,%e,",tVerticalFov); 

	tOutputCameraFileStream << tTempString;


	//	Write out the near plane distance

	float tNearPlaneDistance=tCameraFunctionSet.nearClippingPlane(&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading Camera verical fov");
	}


	//	Write out the near plane distance to the file

	sprintf_s(tTempString, "nearplane,%e,",tNearPlaneDistance); 

	tOutputCameraFileStream << tTempString;


	//	Write out the far plane distance

	float tFarPlaneDistance=tCameraFunctionSet.farClippingPlane(&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error reading Camera verical fov");
	}


	//	Write out the far plane distance to the file

	sprintf_s(tTempString, "farplane,%e,",tFarPlaneDistance); 

	tOutputCameraFileStream << tTempString;


	tCameraItreator.next();

	}

	//	Close the file after writing out all the details of the scene cameras

	tOutputCameraFileStream .close();


	//	Implement a rough light support for now, we can fine tune the implementation later
	//	Loop through and write out all the point and spot lights in the scene


	MItDag tLightItreator(MItDag::kDepthFirst,MFn::kLight,&tErrorObject);


	if(tErrorObject != MS::kSuccess)
	{
		MGlobal::displayError("Error creating Light itreator for the scene");

	}

	std::ofstream tOutputLightFileStream(tLightFileName.asChar(),std::ios::out | std::ios::binary);


	unsigned int tSceneLightCount=0;

	while(!tLightItreator.isDone())
	{

		MDagPath tDagPathObject;

		
		//	Get the DAG path for the current light object

		tErrorObject=tLightItreator.getPath(tDagPathObject);

		if(tErrorObject != MS::kSuccess)
		{
			MGlobal::displayError("Error retreiving DAG object");
		}

		
		if(tDagPathObject.hasFn(MFn::kSpotLight)||tDagPathObject.hasFn(MFn::kPointLight))

			tSceneLightCount++;

		tLightItreator.next();

	}

	//	Write out the total number of spot and point lights in the scene

	sprintf_s(tTempString, "%d,",tSceneLightCount); 

	tOutputLightFileStream << tTempString;

	

	tLightItreator.reset();

	while(!tLightItreator.isDone())
	{   

		MDagPath tDagPathObject;

		
		//	Get the DAG path for the current light object

		tErrorObject=tLightItreator.getPath(tDagPathObject);

		if(tErrorObject != MS::kSuccess)
		{
			MGlobal::displayError("Error retreiving DAG object");
		}


		// Attach a light function set to the dagpath object of the current light and write out their details

		MFnLight tLightFunctionSet(tDagPathObject,&tErrorObject);

		if(tErrorObject != MS::kSuccess)
		{
			MGlobal::displayError("Error attaching light function set to light transform node");
		}


		C_LIGHT_TYPE tLightType;	//	0 - PointLight	//	See the enum in the top of the file
									//	1 - SpotLight
		C_DECAY_TYPE tDecayRate;	//	See enum at the top of the page
		MVector tLightDirection=MVector(0.0,0.0,0.0);
		float tConeAngle=0.0;
		float tPenumbraAngle=0.0;
		

		//	Identify the type of light and retreive any special attribute for the light if needed

		if(tDagPathObject.hasFn(MFn::kSpotLight))
		{

			//	Retreive the values specific to the spot light


			MFnSpotLight tSpotLightFunctionSet(tDagPathObject);

			tLightType=C_SPOT_LIGHT;


			tLightDirection=tLightFunctionSet.lightDirection(0,MSpace::kWorld,&tErrorObject);

			if(tErrorObject != MS::kSuccess)
			{
				MGlobal::displayError("Error retreiving the light direction");
			}


			tConeAngle=tSpotLightFunctionSet.coneAngle();

			tPenumbraAngle=tSpotLightFunctionSet.penumbraAngle();

			tDecayRate=(C_DECAY_TYPE)tSpotLightFunctionSet.decayRate();

		}
		else if(tDagPathObject.hasFn(MFn::kPointLight))
		{

			MFnPointLight tPointLightFunctionSet(tDagPathObject);

			//	Retreive the Values Specific to the Point Light

			tLightType=C_POINT_LIGHT;

			tDecayRate=(C_DECAY_TYPE)tPointLightFunctionSet.decayRate();

		}else
		{
			//	For any other type of light other than spot light or point light skip the current light


			tLightItreator.next();

			continue;

		}


		//	Enter the keyword that marks the beginning of each light Object

		tOutputLightFileStream << "light,";



		//	Write out the type of light

		sprintf_s(tTempString, "%d,",tLightType); 

		tOutputLightFileStream << tTempString;


		//	Retreive the location of the current light

		MObject tCurrentLightTransformNode=tDagPathObject.transform();
		
		MFnDagNode tCurrentLightTransformNodeFunctionSet(tCurrentLightTransformNode);

		MTransformationMatrix	tLightTransformationMatrix(tCurrentLightTransformNodeFunctionSet.transformationMatrix(&tErrorObject));

		if(tErrorObject != MS::kSuccess)
		{
			MGlobal::displayError("Error retreivng light transformation matrix");
		}


		MVector tLightTranslationVector=tLightTransformationMatrix.translation(MSpace::kWorld);


		//	Write out the world coordinate position of the light
		
		sprintf_s(tTempString, "position,%e,%e,%e,",tLightTranslationVector.x,tLightTranslationVector.y,tLightTranslationVector.z); 

		tOutputLightFileStream << tTempString;


		//	Write out the color of the light

		MColor tLightColor=tLightFunctionSet.color(&tErrorObject);


		if(tErrorObject != MS::kSuccess)
		{
			MGlobal::displayError("Error retreiving color of the light");
		}


		//	Write out the color of the light

		sprintf_s(tTempString, "color,%e,%e,%e,",tLightColor.r,tLightColor.g,tLightColor.b); 

		tOutputLightFileStream << tTempString;


		//	Reterive the intensity of the light

		float tLightIntensity=tLightFunctionSet.intensity(&tErrorObject);

		if(tErrorObject != MS::kSuccess)
		{
			MGlobal::displayError("Error retreiving light intensity");
		}


		//	Write out the intensity of the light

		sprintf_s(tTempString, "intensity,%e,",tLightIntensity); 

		tOutputLightFileStream << tTempString;


		//	Write out the decay rate for the current light

		sprintf_s(tTempString, "decayrate,%d,",tDecayRate); 

		tOutputLightFileStream << tTempString;


		//	Write out the direction of the current light...Point Lights have a direction of (0.0,0.0,0.0)

		tLightDirection.normalize();

		sprintf_s(tTempString, "direction,%e,%e,%e,",tLightDirection.x,tLightDirection.y,tLightDirection.z); 

		tOutputLightFileStream << tTempString;


		//	Write out the cone angle for the current light

		sprintf_s(tTempString, "coneangle,%e,",tConeAngle); 

		tOutputLightFileStream << tTempString;


		//	Write out the penumbra angle for the current light

		sprintf_s(tTempString, "penumbraangle,%e,",tPenumbraAngle); 

		tOutputLightFileStream << tTempString;


		tLightItreator.next();

	}


	tOutputLightFileStream.close();


	return MS::kSuccess;
}




//	CeluMayaExporter is the maya class that contains the functionality of the file exporter...it should derive from the maya's MPxFileTranslator class

class CeluMayaExporter : public MPxFileTranslator
{
public:

	//	Default Constructor

	CeluMayaExporter():MPxFileTranslator()
	{}


	//	Destructor

	~CeluMayaExporter()
	{}


	//	Writer method that must be overloaded to implement the export function

	MStatus writer(const MFileObject &file,const MString& tOptions,FileAccessMode mode)
	{

		MStatus tErrorObject;


		//	Export selection mode not supported yet

		if(mode == kExportActiveAccessMode)
		{

		cout << "Export selection not implemented yet..exporting the entire scene" << endl;

		}

		//	Get the name for the new file to be created and create the file

		tErrorObject=ExportCommand(file.name());


		if(tErrorObject!=MS::kSuccess)
		{
			cout << "Error Exporting Scene";
		}




		return tErrorObject;
	}

	
	MStatus	reader( const MFileObject& file,const MString& optionsString,FileAccessMode mode)
	{
		MStatus tDummyObject;

		return tDummyObject;
	}
	


	//	Identifies if the writer function has been exported

	bool haveWriteMethod() const
	{
		return true;
	}


	//	Returns the default file format extension for this translator

	MString defaultExtension() const
	{
		return "celu";
	}


	//	Used by maya to create a new instance of our exporter

	static void *creator()
	{
		return new CeluMayaExporter();
	}


};




//	The initialize function is called initially when the plugin is loaded,the registration of the plugin takes place here

MLL_EXPORT MStatus initializePlugin(MObject tObject)
{

	MStatus tErrorObject;


	//	Attach a plugin funtion set to the received maya object

	MFnPlugin tPlugin(tObject,"Celu","1.0","Any",&tErrorObject);


	//	Standard error checking

	if(tErrorObject != MS::kSuccess)
	{
		printf(" Error attaching MFnPlugin function to the MObject in the plugin initialization function ");

		return tErrorObject;
	}


	tErrorObject=tPlugin.registerFileTranslator("Celu Exporter For Maya","none",CeluMayaExporter::creator);


	//	Standard error checking

	if(tErrorObject != MS::kSuccess)
	{
		printf(" Error registering the file translator plugin in the initialization method");

		return tErrorObject;
	}

	return tErrorObject;
}


//	The second function is the uninitialize function that is called when the plugin is unloaded

MLL_EXPORT MStatus uninitializePlugin(MObject tObject)
{

	MStatus tErrorObject;


	//	Attach a plugin funtion set to the received maya object

	MFnPlugin tPlugin(tObject,"Celu","1.0","Any",&tErrorObject);


	//	Standard error checking

	if(tErrorObject != MS::kSuccess)
	{
		printf(" Error attaching MFnPlugin function to the MObject in the plugin uninitialization function ");

		return tErrorObject;
	}


	//	Deregister the file translator plugin with maya

	tErrorObject=tPlugin.deregisterFileTranslator("Celu Exporter For Maya");


	//	Standard error checking

	if(tErrorObject != MS::kSuccess)
	{
		printf(" Error deregistering the file translator plugin in the uninitialization method");

		return tErrorObject;
	}

	return tErrorObject;

}

