f///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	This file contains the Void Format exporter plug-in for Flexporter.
 *	\file		VoidExporter.cpp
 *	\author		Pierre Terdiman
 *	\date		May, 6, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
#include <locale.h>
#include "3pxExporter.h"
#include "MLHelpers.h"


static VoidFormat		gVoidExporter;		// Gloabl exporter instance
static ExportSettings	gSettings;			// Global export settings

// FLEXPORTER Identification Callbacks

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DLLEXPORT Enabled* GetEnabled()
{
	// Let's disable some features for the ASCII format
	static Enabled Settings;
	return &Settings;
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Flexporter callback.
 *	Gives a brief exporter description. That string is displayed inside MAX, in the Options Panel.
 *	\relates	VoidFormat
 *	\fn			ExporterDescription()
 *	\return		a description string
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DLLEXPORT const char* ExporterDescription()
{ 
	return "3PX Exporter";
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Flexporter callback.
 *	Returns the format's extension. That string is displayed inside MAX, in the Options Panel.
 *	\relates	VoidFormat
 *	\fn			FormatExtension()
 *	\return		an extension string
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DLLEXPORT const char* FormatExtension()
{
	return "txt";
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Flexporter callback.
 *	Returns the one and only exporter instance.
 *	\relates	VoidFormat
 *	\fn			GetExporter()
 *	\return		pointer to the global exporter instance.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DLLEXPORT ExportFormat* GetExporter()
{
	return &gVoidExporter;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Flexporter callback.
 *	Returns the default exportation settings for this format. This is the right place to initialize the default settings for your format.
 *	\relates	VoidFormat
 *	\fn			GetDefaultSettings()
 *	\return		pointer to the global ExportSettings instance.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DLLEXPORT ExportSettings* GetDefaultSettings()
{
  // General settings
  gSettings.mCompression					= COMPRESSION_NONE;
	gSettings.mNbBits						  = 8;
	gSettings.mExportWholeScene		= true;
	gSettings.mExportVisTrack			= false;
	gSettings.mExportHiddenNodes		= true;
	gSettings.mExportBIPED					= false;
	gSettings.mAlwaysExportMotion	= false;
	// Mesh settings
	gSettings.mExpUVW						  = true;
	gSettings.mDiscardW						= true;
	gSettings.mExpVTXColor					= true;
	gSettings.mUseSmgrp						= true;
	gSettings.mRemoveScaling				= true;
	gSettings.mConvertToD3D				= true;
	gSettings.mAbsolutePRS					= false;
	gSettings.mConvexHull					= false;
	gSettings.mBoundingSphere			= false;
	gSettings.mInertiaTensor				= false;
	gSettings.mEdgeVis						  = false;
	gSettings.mMakeManifold				= false;
	gSettings.mExpTargetNodes			= true;
	// Consolidation settings
	gSettings.mConsolidateMesh				  = true;
	gSettings.mComputeFaceNormals			= true;
	gSettings.mComputeVertexNormals		= true;
	gSettings.mExportNormalInfo				= true;
	gSettings.mWeightNormalsByArea			= false;
	// Material settings
	gSettings.mForceAmbient					  = false;
	gSettings.mForceDiffuse					  = false;
	// Texture settings
	gSettings.mOpacityInAlpha				  = true;
	gSettings.mTexnameOnly					    = false;
	gSettings.mKeepAmbientTexture			= true;
	gSettings.mKeepDiffuseTexture			= true;
	gSettings.mKeepSpecularTexture			= true;
	gSettings.mKeepShininessTexture			= true;
	gSettings.mKeepShiningStrengthTexture	= true;
	gSettings.mKeepSelfIllumTexture			= true;
	gSettings.mKeepOpacityTexture			= true;
	gSettings.mKeepFilterTexture				= true;
	gSettings.mKeepBumpTexture				= true;
	gSettings.mKeepReflexionTexture			= true;
	gSettings.mKeepRefractionTexture			= true;
	gSettings.mKeepDisplacementTexture		= true;
	gSettings.mTexMaxSize					= 256;
	gSettings.mFlipHorizontal				= false;
	gSettings.mFlipVertical					= false;
	gSettings.mQuantizeTextures				= false;
	// Camera settings
	gSettings.mExpCameras					= true;
  gSettings.mExpFOVCtrl					= true;
	
	// Light settings
	gSettings.mExpLights						= true;
	gSettings.mComputeVtxColors				= false;
	gSettings.mComputeShadows				= false;
	gSettings.mColorSmoothing				= false;
	// Animation settings
	gSettings.mSingleFrame					= false;
	gSettings.mSampling						= true;
	gSettings.mSamplingRate					= 1;

	// Shape settings
	gSettings.mExpShapes						= false;

	return &gSettings;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Flexporter callback.
 *	Returns the FLEXPORTER SDK Version.
 *	\relates	VoidFormat
 *	\fn			Version()
 *	\return		FLEXPORTER_VERSION
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DLLEXPORT int Version()
{
	return FLEXPORTER_VERSION;
}









///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	A void exporter plug-in for Flexporter..
 *	\class		VoidFormat
 *	\author		Pierre Terdiman
 *	\version	1.0
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Constructor.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VoidFormat::VoidFormat()
{
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Destructor.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VoidFormat::~VoidFormat()
{
}

bool VoidFormat::ExportBasicInfo(const ObjectDescriptor* obj)
{  
	// Export ID
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , obj->mObjectID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ID", false);  			

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NAME", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"%s\"\n" , obj->mName);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NAME", false);  			
  
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "PARENTID", true);  
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , obj->mParentID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "PARENTID", false);  

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "LINKID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , obj->mLinkID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "LINKID", false);  			

  if (obj->mIsGroupMember)
  {
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "GROUP", true);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "GROUP", false);  			
  }


  // Export Position
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "POSITION", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%20f %20f %20f\n" , 
    obj->mPrs.Position.x, obj->mPrs.Position.y, obj->mPrs.Position.z);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "POSITION", false);

  // Export Rotation
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ROTATION", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%20f %20f %20f %20f\n" , 
    obj->mPrs.Rotation.x, obj->mPrs.Rotation.y, obj->mPrs.Rotation.z, obj->mPrs.Rotation.w);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ROTATION", false);

  // Export Position
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "PIVOTPOSITION", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%20f %20f %20f\n" , 
    obj->mPivotPos.x, obj->mPivotPos.y, obj->mPivotPos.z);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "PIVOTPOSITION", false);

  // Export Rotation
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "PIVOTROTATION", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%20f %20f %20f %20f\n" , 
    obj->mPivotRot.x, obj->mPivotRot.y, obj->mPivotRot.z, obj->mPivotRot.w);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "PIVOTROTATION", false);

  // Export Color
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "WIRECOLOR", true);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "WIRECOLOR", false);
  	
	return true;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Plug-in initialization method.
 *	This method is called once before each export. When this method is called, the mSettings and mFilename members of the base format are valid.
 *	\param		motion		[in] true for pure motion files.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::Init(bool motion)
{
  if (!(m_f=fopen(mFilename, "wt")))
  {
    return (false);
  }

  setlocale( LC_ALL, "usa" );
  

  MLHelpers::InitWrite(m_f);  
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SCENE", true);

  return (true);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Scene export method.
 *	This method is called once to export the scene global information.
 *	\param		maininfo	[in] main info structure
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::SetSceneInfo(const MainDescriptor& maininfo)
{
  // Save time info for later
	CopyMemory(&mTimeInfo, &maininfo.mTime, sizeof(MAXTimeInfo));

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SCENEINFO", true);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "AMBIENT", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f %f %f\n", maininfo.mAmbColor.r, 
                                                               maininfo.mAmbColor.g, 
                                                               maininfo.mAmbColor.b);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "AMBIENT", false);


  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FRAMERATE", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n", mTimeInfo.mFrameRate);                                                      
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FRAMERATE", false);


  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SCENEINFO", false);  					
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Camera export method.
 *	This method is called once for each exported camera.
 *	\param		camera		[in] a structure filled with current camera information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportCamera(const CameraDescriptor& camera)
{
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "CAMERA", true);

  ExportBasicInfo(&camera);

  /*
  // Export common information
	mCameras.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("Camera:       ");
	ExportBasicInfo(&camera, &mCameras);

	// Export camera parameters
	if(camera.mOrthoCam)
	{
		mCameras.StoreASCII("Type: orthographic\nWidth: ").StoreASCII(camera.mFOV).StoreASCII("\n");
	}
	else
	{
		mCameras.StoreASCII("Type: perspective\nField Of View: ").StoreASCII(camera.mFOV).StoreASCII("\n");
	}

	// Horizon line display
	mCameras.StoreASCII("Horizon line display: ")	.StoreASCII(camera.mHLineDisplay).StoreASCII("\n");	// Horizon line display

	// Export environment ranges if needed
	// Environment ranges
	mCameras
		.StoreASCII("\nENVIRONMENT RANGES:\n")
		.StoreASCII("\nNear range: ")				.StoreASCII(camera.mEnvNearRange)					// Near range
		.StoreASCII("\nFar range: ")				.StoreASCII(camera.mEnvFarRange)					// Far range
	// Environment display
		.StoreASCII("\nEnv display: ")				.StoreASCII(camera.mEnvDisplay)						// Environment display
		.StoreASCII("\n");

	// Export clipping planes if needed
	mCameras
		.StoreASCII("\nCLIPPING PLANES:\n")
		.StoreASCII("\nManual clip: ")				.StoreASCII(camera.mManualClip)						// Manual clip
		.StoreASCII("\nNear clip: ")				.StoreASCII(camera.mNearClip)						// Near clip
		.StoreASCII("\nFar clip: ")					.StoreASCII(camera.mFarClip)						// Far clip
		.StoreASCII("\n");
    */
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FOV", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f\n" , camera.mFOV);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FOV", false);  					

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NEAR", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f\n" , camera.mNearClip);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NEAR", false);  					
  
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FAR", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f\n" , camera.mFarClip);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FAR", false);  					
	

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "CAMERA", false);  				
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Controller export method.
 *	This method is called once for each exported controller.
 *	\param		controller		[in] a structure filled with current controller information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportController(const ControllerDescriptor& controller)
{
  ControllerData* cdata = controller.mData;

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "CONTROLLER", true);


  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , controller.mObjectID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "OWNERID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , controller.mOwnerID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "OWNERID", false);

  int iValuesPerSample=10;

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "TYPE", true);
  if      (cdata->mType==CTRL_FLOAT)        
  {	MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"FLOAT\"\n" , controller.mOwnerID); iValuesPerSample = 1;	}
	else	if(cdata->mType==CTRL_VECTOR)		    
  {	MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"VEC\"\n" , controller.mOwnerID); iValuesPerSample = 3;	}
	else	if(cdata->mType==CTRL_QUAT)			    
  {	MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"QUAT\"\n" , controller.mOwnerID); iValuesPerSample = 4;	}
	else	if(cdata->mType==CTRL_PR)			      
  {	MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"POSROT\"\n" , controller.mOwnerID); iValuesPerSample = 7;	}
	else	if(cdata->mType==CTRL_PRS)			    
  {	MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"POSROTSCALE\"\n" , controller.mOwnerID); iValuesPerSample = 10;	}
	else	if(cdata->mType==CTRL_VERTEXCLOUD)	
  {	MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"VERTEXCLOUD\"\n" , controller.mOwnerID); iValuesPerSample = 3; }
	else										                  
  {	assert("Non supported controller"); }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "TYPE", false);

  	
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "DATA", true);

  if(cdata->mMode==CTRL_SAMPLES)
	{
		if(cdata->mType==CTRL_VERTEXCLOUD)
		{
      // A standard controller
			MorphData* mdata = (MorphData*)cdata;
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLES", true);
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n", mdata->mNbSamples);
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLES", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "VERTICES", true);
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n", mdata->mNbVertices);
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "VERTICES", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLINGRATE", true);
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n", mdata->mSamplingRate);
			MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLINGRATE", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLES", true);

			// Dump samples as a list of floats
			float* Values = (float*)mdata->mSamples;

			for(unsigned i=0 ;i<mdata->mNbSamples*mdata->mNbVertices ; i++)
      {
        MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
        for (int j=0 ; j<iValuesPerSample ; j++)
        {
          MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%20f ", Values[iValuesPerSample*i+j]);
        }
        MLHelpers::WriteRaw(0, "\n");
      }

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLES", false);      
		}
		else
		{
			// A standard controller
			SampleData* sdata = (SampleData*)cdata;
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMBERSAMPLES", true);
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n", sdata->mNbSamples);
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMBERSAMPLES", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLINGRATE", true);
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n", sdata->mSamplingRate);
			MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLINGRATE", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLES", true);

			// Dump samples as a list of floats
			float* Values = (float*)sdata->mSamples;

			for(unsigned i=0 ;i<sdata->mNbSamples;i++)
      {
        MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
        for (int j=0 ; j<iValuesPerSample ; j++)
        {
          MLHelpers::WriteRaw(0, "%20f ", Values[iValuesPerSample*i+j]);
        }
        MLHelpers::WriteRaw(0, "\n");
      }

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SAMPLES", false);
		}
	}
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "DATA", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "CONTROLLER", false);  			
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Helper export method.
 *	This method is called once for each exported helper.
 *	\param		helper		[in] a structure filled with current helper information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportHelper(const HelperDescriptor& helper)
{
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "HELPER", true);
  ExportBasicInfo(&helper);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "HELPER", false);  			
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Light export method.
 *	This method is called once for each exported light.
 *	\param		light		[in] a structure filled with current light information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportLight(const LightDescriptor& light)
{
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "LIGHT", true);
  ExportBasicInfo(&light);


  // Type of light
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "TYPE", true);
  switch (light.mLightType)
  {
  case LTYPE_OMNI:					
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"OMNI\"\n"); break;      
  case LTYPE_TSPOT:
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"TSPOT\"\n"); break;      
  case LTYPE_DIR:
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"DIRECTIONAL\"\n"); break;      
  case LTYPE_FSPOT:
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"SPOT\"\n"); break;      
  case LTYPE_TDIR:
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"TDIRECTIONAL\"\n"); break;      
  }  
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "TYPE", false);  		

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "COLOR", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f %f %f\n", light.mColor.x, light.mColor.y, light.mColor.z);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "COLOR", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SPECULAR", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f %f %f\n", light.mColor.x, light.mColor.y, light.mColor.z);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SPECULAR", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MULTIPLIER", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f\n", light.mIntensity);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MULTIPLIER", false);

  if (light.mUseAtten)
  {
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FARATTENUATION", true);
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f\n", light.mAttenEnd);
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FARATTENUATION", false);
  }

  
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "LIGHT", false);  		
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Material export method.
 *	This method is called once for each exported material.
 *	\param		material		[in] a structure filled with current material information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportMaterial(const MaterialDescriptor& material)
{
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIAL", true);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NAME", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"%s\"\n" , (const char*)material.mName);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NAME", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mObjectID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "AMBIENTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mAmbientMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "AMBIENTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "DIFFUSETEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mDiffuseMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "DIFFUSETEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SPECULARTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mSpecularMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SPECULARTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SHININESSTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mShininessMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SHININESSTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SHININGSTRENGTHTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mShiningStrengthMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SHININGSTRENGTHTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SELFILLUMINATIONTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mSelfIllumMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SELFILLUMINATIONTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "OPACITYTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mSelfIllumMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "OPACITYTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FILTERTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mFilterMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FILTERTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "BUMPTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mBumpMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "BUMPTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "REFLECTIONTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mReflexionMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "REFLECTIONTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "REFRACTIONTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mRefractionMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "REFRACTIONTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "DISPLACEMENTTEXTUREID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , material.mDisplacementMapID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "DISPLACEMENTTEXTUREID", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "DIFFUSECOLOR", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%f %f %f\n" , 
    material.mMtlDiffuseColor.r, material.mMtlDiffuseColor.g, material.mMtlDiffuseColor.b);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "DIFFUSECOLOR", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIAL", false);  		
	

  

  
/*
	// 3) Export material parameters
	mMaterials
		.Store(material.mAmbientMapID)
		.Store(material.mDiffuseMapID)
		.Store(material.mSpecularMapID)
		.Store(material.mShininessMapID)
		.Store(material.mShiningStrengthMapID)
		.Store(material.mSelfIllumMapID)
		.Store(material.mOpacityMapID)
		.Store(material.mFilterMapID)
		.Store(material.mBumpMapID)
		.Store(material.mReflexionMapID)
		.Store(material.mRefractionMapID)
		.Store(material.mDisplacementMapID)

		.Store(material.mAmbientCoeff)
		.Store(material.mDiffuseCoeff)
		.Store(material.mSpecularCoeff)
		.Store(material.mShininessCoeff)
		.Store(material.mShiningStrengthCoeff)
		.Store(material.mSelfIllumCoeff)
		.Store(material.mOpacityCoeff)
		.Store(material.mFilterCoeff)
    .Store(material.mBumpCoeff)rááÑ
		.Store(material.mReflexionCoeff)
		.Store(material.mRefractionCoeff)
		.Store(material.mDisplacementCoeff)

		.Store(material.mMtlAmbientColor.r)		.Store(material.mMtlAmbientColor.g)		.Store(material.mMtlAmbientColor.b)
		.Store(material.mMtlDiffuseColor.r)		.Store(material.mMtlDiffuseColor.g)		.Store(material.mMtlDiffuseColor.b)
		.Store(material.mMtlSpecularColor.r)	.Store(material.mMtlSpecularColor.g)	.Store(material.mMtlSpecularColor.b)
		.Store(material.mMtlFilterColor.r)		.Store(material.mMtlFilterColor.g)		.Store(material.mMtlFilterColor.b)

		.Store(material.mShading)
		.Store(material.mSoften)
		.Store(material.mFaceMap)
		.Store(material.mTwoSided)
		.Store(material.mWire)
		.Store(material.mWireUnits)
		.Store(material.mFalloffOut)
		.Store(material.mTransparencyType)

		.Store(material.mShininess)
		.Store(material.mShiningStrength)
		.Store(material.mSelfIllum)
		.Store(material.mOpacity)
		.Store(material.mOpaFalloff)
		.Store(material.mWireSize)
		.Store(material.mIOR)

		.Store(material.mBounce)
		.Store(material.mStaticFriction)
		.Store(material.mSlidingFriction);

	// 4) Export cropping values
	mMaterials
		.Store(material.mCValues.OffsetU).Store(material.mCValues.OffsetV).Store(material.mCValues.ScaleU).Store(material.mCValues.ScaleV);

	// 5) Export texture matrix
	mMaterials
		.Store(material.mTMtx.m[0][0]).Store(material.mTMtx.m[0][1]).Store(material.mTMtx.m[0][2])
		.Store(material.mTMtx.m[1][0]).Store(material.mTMtx.m[1][1]).Store(material.mTMtx.m[1][2])
		.Store(material.mTMtx.m[2][0]).Store(material.mTMtx.m[2][1]).Store(material.mTMtx.m[2][2])
		.Store(material.mTMtx.m[3][0]).Store(material.mTMtx.m[3][1]).Store(material.mTMtx.m[3][2]);
    */

  return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Mesh export method.
 *	This method is called once for each exported mesh.
 *	\param		mesh		[in] a structure filled with current mesh information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportMesh(const MeshDescriptor& mesh)
{
  unsigned i;

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MESH", true);

  ExportBasicInfo(&mesh);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MAXMESH", true);
  const MAXNativeMesh* Mesh = &mesh.mOriginalMesh;

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMFACES", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Mesh->mNbFaces);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMFACES", false);

  // Num Vertices
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMVERTICES", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Mesh->mNbVerts);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMVERTICES", false);

  // Num UV Vertices
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMUVVERTICES", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Mesh->mNbTVerts);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMUVVERTICES", false);

  // Vertex Colors
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMVERTEXCOLORS", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Mesh->mNbCVerts);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMVERTEXCOLORS", false);

  // Vertices
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "VERTICES", true);
  if(Mesh->mVerts)
  {
    MAXPoint* v = Mesh->mVerts;			    
    for(i=0 ; i<Mesh->mNbVerts ; i++)
	  {
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%20f %20f %20f\n" , v[i].x, v[i].y, v[i].z);		
	  }
  }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "VERTICES", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "UVVERTICES", true);
  if (Mesh->mTVerts)
  {
    MAXPoint* v = Mesh->mTVerts;			    
    for(i=0 ; i<Mesh->mNbTVerts ; i++)
	  {
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%20f %20f\n" , v[i].x, v[i].y);		
	  }
  }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "UVVERTICES", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "COLORVERTICES", true);
  if (Mesh->mCVerts)
  {
    MAXPoint* v = Mesh->mCVerts;			    
    for(i=0 ; i<Mesh->mNbCVerts ; i++)
	  {
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%20f %20f %20f\n" , v[i].x, v[i].y, v[i].z);		
	  }
  }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "COLORVERTICES", false);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FACES", true);
  
  MAXFace* f = Mesh->mFaces;

  // Position vertices indices
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "VERTICESINDICES", true);
  if (Mesh->mFlags&MESH_VFACE)
  {
    for(i=0;i<Mesh->mNbFaces;i++)	
    {    
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i %i %i\n", f[i].VRef[0], f[i].VRef[1], f[i].VRef[2]);		    
    }    
  }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "VERTICESINDICES", false);

  // Texture coord indices
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "TVERTICESINDICES", true);
  if((Mesh->mFlags&MESH_TFACE)&&(Mesh->mFlags&MESH_UVW))
	{
    for(i=0;i<Mesh->mNbFaces;i++)	
    {    
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i %i %i\n", f[i].TRef[0], f[i].TRef[1], f[i].TRef[2]);		    
    }  
  }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "TVERTICESINDICES", false);

  // Color vertices indices
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "CVERTICESINDICES", true);
  if((Mesh->mFlags&MESH_CFACE)&&(Mesh->mFlags&MESH_VERTEXCOLORS))
	{
    for(i=0;i<Mesh->mNbFaces;i++)	
    {    
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i %i %i\n", f[i].CRef[0], f[i].CRef[1], f[i].CRef[2]);		    
    }
  }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "CVERTICESINDICES", false);

  // Material Indices
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIALINDICES", true);
  if (Mesh->mNbFaces) MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
  for(i=0;i<Mesh->mNbFaces;i++)	
  {    
    if ((i&15)==15)
    {
      MLHelpers::WriteRaw(0, "\n");
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
    }
    MLHelpers::WriteRaw(0, "%i ", f[i].MatID);		    
  }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIALINDICES", false);

  // Smoothing groups
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SMOOTHINGGROUP", true);
  if (Mesh->mNbFaces) MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
  for(i=0;i<Mesh->mNbFaces;i++)	
  {
    
    if ((i&15)==15)
    {
      MLHelpers::WriteRaw(0, "\n");
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
    }
    MLHelpers::WriteRaw(0, "%i ", f[i].Smg);		    
  }
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SMOOTHINGGROUP", false);


  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FACES", false);


  	

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MAXMESH", false);  

  /*
  if(Mesh->mFlags&MESH_CONSOLIDATION)
	{
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "RENDER", true);  

    MBTopology& Topo = mesh.mCleanMesh->Topology;

    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMFACES", true);
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Topo.NbFaces);
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FACES", false);

    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMSUBMESHES", true);
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Topo.NbSubmeshes);
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMSUBMESHES", false);

    
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIALS", true);

    MBMaterials& Mtl = mesh.mCleanMesh->Materials;    
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMMATERIALS", true);
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Mtl.NbMtls);
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMMATERIALS", false);

    for(i=0 ; i<Mtl.NbMtls ; i++)
		{
      
      MBMatInfo* CurMtl = &Mtl.MaterialInfo[i];
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIAL", true);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIAL INDEX", true);
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , i);
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIAL INDEX", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIAL ID", true);
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , CurMtl->MatID);
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIAL ID", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIAL", false);

    }        

    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MATERIALS", false);
    

    for (i=0 ; i<Topo.NbSubmeshes;i++)
		{
			MBSubmesh* CurSM = &Topo.SubmeshProperties[i];

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SUBMESH", true);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMTRIS", true);
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Topo.FacesInSubmesh[i]);
      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMTRIS", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "CONNECTIVITY", true);
      

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "CONNECTIVITY", false);

      MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SUBMESH", false);
    }



    // Optimized geometry
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "GEOMETRY", true);


    // Vertices
    MBGeometry& Geo = mesh.mCleanMesh->Geometry;

	  
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMPOINTS", true);
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Geo.NbGeomPts);
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMPOINTS", false);

    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMVERTS", true);
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Geo.NbVerts);
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMVERTS", false);

    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMTVERTS", true);
    MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , Geo.NbTVerts);
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "NUMTVERTS", false);


	  
	  // Indexed geometry
	  unsigned MaxRef=0;
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "INDICES", true);
	  if(Geo.VertsRefs)
	  {			
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
      for(i=0 ; i<Geo.NbVerts ; i++)
		  {            
			  unsigned Ref = Geo.VertsRefs[i];
			  if(Ref>MaxRef)	MaxRef=Ref;
      
        MLHelpers::WriteRaw(0, "%5i " , Ref);
			  if((i&15)==15)	
        {
          MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\n");
          MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
        }
		  }					
	  }
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "INDICES", false);

	  // Vertices
    unsigned NbVerts = Geo.VertsRefs ? (MaxRef+1) : Geo.NbVerts;
	  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "VERTICES", true);
	  for(i=0 ; i<NbVerts ; i++)
	  {
		  float x = Geo.Verts[i*3+0];
		  float y = Geo.Verts[i*3+1];
		  float z = Geo.Verts[i*3+2];					
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%16f %16f %16f\n", x, y, z);
	  }
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "VERTICES", false);



    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "UVINDICES", true);
    MaxRef = 0;
    if (Geo.TVertsRefs)
    {
      MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
      for(int i=0;i<Geo.NbVerts;i++)
		  {
			  unsigned Ref = Geo.TVertsRefs[i];
			  if(Ref>MaxRef)	MaxRef=Ref;

			  MLHelpers::WriteRaw(0, "%5i " , Ref);
			  if((i&15)==15)	
        {
          MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\n");
          MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "");
        }
		  }
    }
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "UVINDICES", false);


    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "UVVERTICES", true);
    if (Geo.TVerts)
    {
      for(int i=0;i<Geo.NbTVerts;i+=2)
		  {
			  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%16f %16f\n", 
          Geo.TVerts[i], 
          Geo.TVerts[i+1]);
		  }
    }
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "UVVERTICES", false);             

    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "GEOMETRY", false);
     
    MLHelpers::WriteTag(MLHelpers::NestingLevel(), "RENDER", false);  
  }
  */

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MESH", false);  	
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Motion export method.
 *	This method is called once for each exported motion.
 *	\param		motion		[in] a structure filled with current motion information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportMotion(const MotionDescriptor& motion)
{
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MOTION", true);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "MOTION", false);  
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Shape export method.
 *	This method is called once for each exported shape.
 *	\param		shape		[in] a structure filled with current shape information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportShape(const ShapeDescriptor& shape)
{
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SHAPE", true);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SHAPE", false);
  return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Texture export method.
 *	This method is called once for each exported texture.
 *	\param		texture		[in] a structure filled with current texture information.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::ExportTexture(const TextureDescriptor& texture)
{
  //texture.
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "TEXTURE", true);

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FILE", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "\"%s\"\n" , (const char*)texture.mName);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "FILE", false);  

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ID", true);
  MLHelpers::WriteRaw(MLHelpers::NestingLevel(), "%i\n" , (const char*)texture.mObjectID);
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "ID", false);  

  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "TEXTURE", false);
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	End of export notification.
 *	This method is called once all nodes have been exported. This is a convenient place to free all used ram, etc.
 *	\param		stats		[in] a structure filled with some export statistics.
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool VoidFormat::EndExport(const StatsDescriptor& stats)
{
  MLHelpers::WriteTag(MLHelpers::NestingLevel(), "SCENE", false);
  MLHelpers::Shutdown();
  if (m_f) 
  {
    fclose(m_f);
    m_f=0;
  }
  
	return true;
}

