///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	This file contains the ASCII Format exporter plug-in for Flexporter.
 *	\file		IceASCIIExporter.cpp
 *	\author		Pierre Terdiman
 *	\date		April, 4, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"

static ASCIIFormat		gASCIIExporter;		// Gloabl exporter instance
static ExportSettings	gSettings;			// Global export settings

// FLEXPORTER Identification Callbacks

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

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

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

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Flexporter callback.
 *	Returns the default exportation settings for this format. This is the right place to initialize the default settings for your format.
 *	\relates	ASCIIFormat
 *	\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			= false;
	gSettings.mExportPHYSIQUE				= 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				= false;
	gSettings.mComputeFaceNormals			= false;
	gSettings.mComputeVertexNormals			= true;
	gSettings.mExportNormalInfo				= false;
	gSettings.mWeightNormalsByArea			= false;
	// Material settings
	gSettings.mForceAmbient					= false;
	gSettings.mForceDiffuse					= false;
	gSettings.mExpMtlCtrl					= false;
	// Texture settings
	gSettings.mOpacityInAlpha				= false;
	gSettings.mTexnameOnly					= true;
	gSettings.mKeepAmbientTexture			= false;
	gSettings.mKeepDiffuseTexture			= true;
	gSettings.mKeepSpecularTexture			= false;
	gSettings.mKeepShininessTexture			= false;
	gSettings.mKeepShiningStrengthTexture	= false;
	gSettings.mKeepSelfIllumTexture			= false;
	gSettings.mKeepOpacityTexture			= true;
	gSettings.mKeepFilterTexture			= false;
	gSettings.mKeepBumpTexture				= false;
	gSettings.mKeepReflexionTexture			= false;
	gSettings.mKeepRefractionTexture		= false;
	gSettings.mKeepDisplacementTexture		= false;
	gSettings.mTexMaxSize					= 0;
	gSettings.mFlipHorizontal				= false;
	gSettings.mFlipVertical					= false;
	gSettings.mQuantizeTextures				= false;
	// Camera settings
	gSettings.mExpCameras					= true;
	gSettings.mExpFOVCtrl					= false;
	gSettings.mExpCamCtrl					= false;
	// Light settings
	gSettings.mExpLights					= true;
	gSettings.mExpLitCtrl					= false;
	gSettings.mComputeVtxColors				= false;
	gSettings.mComputeShadows				= false;
	gSettings.mColorSmoothing				= false;
	// Animation settings
	gSettings.mSingleFrame					= true;
	gSettings.mSampling						= true;
	gSettings.mSamplingRate					= 1;
	// Shape settings
	gSettings.mExpShapes					= false;
	// Helper settings
	gSettings.mExpHelpers					= false;

	return &gSettings;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Flexporter callback.
 *	Returns the enabled/disabled status for all settings. This is the right place to disable options your own format doesn't support.
 *	\relates	ASCIIFormat
 *	\fn			GetEnabled()
 *	\return		pointer to a global Enabled instance.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DLLEXPORT Enabled* GetEnabled()
{
	// Let's disable some features for the ASCII format
	static Enabled Settings;
	Settings.mCompression		= false;
	Settings.mOpacityInAlpha	= false;
	Settings.mTexnameOnly		= false;
	Settings.mTexMaxSize		= false;
	Settings.mFlipHorizontal	= false;
	Settings.mFlipVertical		= false;
	Settings.mQuantizeTextures	= false;
	return &Settings;
}

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










///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	An ASCII exporter plug-in for Flexporter..
 *	\class		ASCIIFormat
 *	\author		Pierre Terdiman
 *	\version	1.0
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

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

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	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 ASCIIFormat::Init(bool motion)
{
	mGeneral
		.StoreASCII("// File created by FLEXPORTER\n")
		.StoreASCII("// Copyright (c) 2000 Pierre Terdiman\n");

	if(!motion)
	{
		mGeneral		.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("GENERAL INFORMATION\n");
		mGeomObjects	.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("MESHES\n");
		mCameras		.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("CAMERAS\n");
		mLights			.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("LIGHTS\n");
		mShapes			.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("SHAPES\n");
		mHelpers		.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("HELPERS\n");
		mTexmaps		.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("TEXTURES\n");
		mMaterials		.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("MATERIALS\n");
		mControllers	.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("CONTROLLERS\n");
	}
	mMotion			.StoreASCII("\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n").StoreASCII("MOTIONS\n");

	mIsMotionFile	= motion;

	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 ASCIIFormat::SetSceneInfo(const MainDescriptor& maininfo)
{
	// Save time info for later
	CopyMemory(&mTimeInfo, &maininfo.mTime, sizeof(MAXTimeInfo));

	// Export time info
	mGeneral
		.StoreASCII("First frame: ")		.StoreASCII((long)(mTimeInfo.mStartTime / mTimeInfo.mDeltaTime))
		.StoreASCII("\nLast frame: ")		.StoreASCII((long)(mTimeInfo.mEndTime / mTimeInfo.mDeltaTime))
		.StoreASCII("\nFrame rate: ")		.StoreASCII(mTimeInfo.mFrameRate)
		.StoreASCII("\nTicks per frame: ")	.StoreASCII((long)mTimeInfo.mDeltaTime)
		.StoreASCII("\n");

	// Export background color
	mGeneral
		.StoreASCII("Background color: ")
		.StoreASCII(maininfo.mBackColor.r).StoreASCII(" ")
		.StoreASCII(maininfo.mBackColor.g).StoreASCII(" ")
		.StoreASCII(maininfo.mBackColor.b).StoreASCII("\n");

	// Export ambient color
	mGeneral
		.StoreASCII("Global ambient color: ")
		.StoreASCII(maininfo.mAmbColor.r).StoreASCII(" ")
		.StoreASCII(maininfo.mAmbColor.g).StoreASCII(" ")
		.StoreASCII(maininfo.mAmbColor.b).StoreASCII("\n");

	// Export scene info
	if(maininfo.mSceneInfos)	mGeneral.StoreASCII("\nScene info:   ").StoreASCII((const char*)maininfo.mSceneInfos);

	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Common method used to export basic information for a mesh, a camera, a light, etc.
 *	\param		obj			[in] current object
 *	\param		array		[out] destination export array
 *	\return		true if success.
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ASCIIFormat::ExportBasicInfo(const ObjectDescriptor* obj, CustomArray* array)
{
	// Checkings
	if(!array || !obj) return false;

	// Export name
	array	->StoreASCII((const char*)obj->mName);

	// Export database management information
	array	->StoreASCII("\nNodeID:       ").StoreASCII(obj->mObjectID)
			.StoreASCII("\nParentNodeID: ")	.StoreASCII(obj->mParentID)
			.StoreASCII("\nLinkID:       ")	.StoreASCII(obj->mLinkID)
			.StoreASCII("\nIsInGroup:    ")	.StoreASCII(obj->mIsGroupMember)
			.StoreASCII("\n");

	// Export common properties
	array	->StoreASCII("\nPosition:     ").StoreASCII(obj->mPrs.Position.x)	.StoreASCII("  ")
											.StoreASCII(obj->mPrs.Position.y)	.StoreASCII("  ")
											.StoreASCII(obj->mPrs.Position.z)

			.StoreASCII("\nRotation:     ")	.StoreASCII(obj->mPrs.Rotation.x)	.StoreASCII("  ")
											.StoreASCII(obj->mPrs.Rotation.y)	.StoreASCII("  ")
											.StoreASCII(obj->mPrs.Rotation.z)	.StoreASCII("  ")
											.StoreASCII(obj->mPrs.Rotation.w)

			.StoreASCII("\nScale:        ")	.StoreASCII(obj->mPrs.Scale.x)		.StoreASCII("  ")
											.StoreASCII(obj->mPrs.Scale.y)		.StoreASCII("  ")
											.StoreASCII(obj->mPrs.Scale.z)

			.StoreASCII("\nWireColor:    ")	.StoreASCII(obj->mWireColor)

			.StoreASCII("\nLocal PRS:    ")	.StoreASCII(obj->mLocalPRS)

			.StoreASCII("\nD3D compliant:")	.StoreASCII(obj->mD3DCompliant);

	// Export user-defined properties
	if(obj->mUserProps)	array->StoreASCII("\nUser props:   ").StoreASCII((const char*)obj->mUserProps);

	array	->StoreASCII("\n");

	// Export pivot
	array	->StoreASCII("\nPivot position:  ")	.StoreASCII(obj->mPivotPos.x)	.StoreASCII("  ")
												.StoreASCII(obj->mPivotPos.y)	.StoreASCII("  ")
												.StoreASCII(obj->mPivotPos.z)

			.StoreASCII("\nPivot rotation:   ")	.StoreASCII(obj->mPivotRot.x)	.StoreASCII("  ")
												.StoreASCII(obj->mPivotRot.y)	.StoreASCII("  ")
												.StoreASCII(obj->mPivotRot.z)	.StoreASCII("  ")
												.StoreASCII(obj->mPivotRot.w);

	array	->StoreASCII("\n\n");

	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 ASCIIFormat::EndExport(const StatsDescriptor& stats)
{
	// Complete general chunk
	if(!mIsMotionFile)
	{
		mGeneral
			.StoreASCII("Number of geom objects:      ")	.StoreASCII(stats.mNbGeomObjects)
			.StoreASCII("\nNumber of derived objects:   ")	.StoreASCII(stats.mNbDerivedObjects)
			.StoreASCII("\nNumber of cameras:           ")	.StoreASCII(stats.mNbCameras)
			.StoreASCII("\nNumber of lights:            ")	.StoreASCII(stats.mNbLights)
			.StoreASCII("\nNumber of shapes:            ")	.StoreASCII(stats.mNbShapes)
			.StoreASCII("\nNumber of helpers:           ")	.StoreASCII(stats.mNbHelpers)
			.StoreASCII("\nNumber of controllers:       ")	.StoreASCII(stats.mNbControllers)
			.StoreASCII("\nNumber of materials:         ")	.StoreASCII(stats.mNbMaterials)
			.StoreASCII("\nNumber of texmaps:           ")	.StoreASCII(stats.mNbTexmaps)
			.StoreASCII("\nNumber of unknown nodes:     ")	.StoreASCII(stats.mNbUnknowns)
			.StoreASCII("\nNumber of object-free nodes: ")	.StoreASCII(stats.mNbInvalidNodes)
			.StoreASCII("\n");
	}

	// Export to disk
	{
		// Open output file
		udword fp = CreateFile(mFilename, FILE_WRITE, FILE_CREATE_ALWAYS);
		if(fp!=-1)
		{
			// Write data to disk
			void* Data;
			Data = mGeneral				.Collapse();	if(Data)	WriteFile(fp, Data, mGeneral		.GetOffset());
			if(!mIsMotionFile)
			{
				Data = mGeomObjects		.Collapse();	if(Data)	WriteFile(fp, Data, mGeomObjects	.GetOffset());
				Data = mCameras			.Collapse();	if(Data)	WriteFile(fp, Data, mCameras		.GetOffset());
				Data = mLights			.Collapse();	if(Data)	WriteFile(fp, Data, mLights			.GetOffset());
				Data = mShapes			.Collapse();	if(Data)	WriteFile(fp, Data, mShapes			.GetOffset());
				Data = mHelpers			.Collapse();	if(Data)	WriteFile(fp, Data, mHelpers		.GetOffset());
				Data = mTexmaps			.Collapse();	if(Data)	WriteFile(fp, Data, mTexmaps		.GetOffset());
				Data = mMaterials		.Collapse();	if(Data)	WriteFile(fp, Data, mMaterials		.GetOffset());
				Data = mControllers		.Collapse();	if(Data)	WriteFile(fp, Data, mControllers	.GetOffset());
			}
			Data = mMotion				.Collapse();	if(Data)	WriteFile(fp, Data, mMotion			.GetOffset());

			// Close output file
			CloseFile(fp);
		}

		// Free everything for next call
		mGeneral		.Clean();
		mGeomObjects	.Clean();
		mCameras		.Clean();
		mLights			.Clean();
		mShapes			.Clean();
		mHelpers		.Clean();
		mTexmaps		.Clean();
		mMaterials		.Clean();
		mControllers	.Clean();
		mMotion			.Clean();
	}

	return true;
}
