#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "msPlugInImpl.h"
#include "msLib.h"
#include "DlgOptions.h"
#include "3dsftk.h"



#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



/////////////////////////////////////////////////////////////////////////////
// CMsPlugInApp

BEGIN_MESSAGE_MAP(CMsPlugInApp, CWinApp)
	//{{AFX_MSG_MAP(CMsPlugInApp)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
//

CMsPlugInApp::CMsPlugInApp()
{
}

/////////////////////////////////////////////////////////////////////////////
//

CMsPlugInApp theApp;



cMsPlugIn*
CreatePlugIn ()
{
  return new cPlugIn ();
}



cPlugIn::cPlugIn ()
{
    strcpy (szTitle, "Autodesk 3DS...");
}



cPlugIn::~cPlugIn ()
{
}



int
cPlugIn::GetType ()
{
    return cMsPlugIn::eTypeExport;
}



const char*
cPlugIn::GetTitle ()
{
    return szTitle;
}



static void
MakeShortName (const char *szName, char *szOut, int nMaxLength)
{
	strncpy (szOut, szName, nMaxLength);

	if ((int) strlen (szOut) <= nMaxLength)
		return;

	szOut[nMaxLength] = '\0';
}



static void
MakeShortFileName (const char *szName, char *szOut)
{
	strcpy (szOut, szName);

	char *ptr = strrchr (szName, '\\');
	if (!ptr)
		ptr = strrchr (szName, '/');
	if (ptr)
		strcpy (szOut, ptr + 1);

	if ((int) strlen (szOut) <= 12)
		return;

	ptr = strrchr (szOut, '.');
	if (ptr)
	{
		memcpy (szOut + 8, ptr, 4);
		szOut[12] = '\0';
	}
	else
	{
		szOut[12] = '\0';
	}
}



int 
cPlugIn::PrintError ()
{
	if (ftkerr3ds)
	{
		const ErrRec3ds *pErr = ReturnErrorList3ds ();
		CString sErr;
		sErr.Format ("ERROR (%d): %s", pErr->id, pErr->desc);
		::AfxMessageBox (sErr);
	}
	return (int) ftkerr3ds;
}

int
cPlugIn::Execute (msModel *pModel)
{
    if (!pModel)
        return -1;

    //
    // switch the module state for MFC Dlls
    //
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

	if (msModel_GetMeshCount (pModel) == 0 &&
		msModel_GetMaterialCount (pModel) == 0)
	{
		::AfxMessageBox ("The model ist empty!  Nothing exported!");
		return -1;
	}

    //
    // options dialog
    //
    cDlgOptions dlgOptions (NULL);
    if (dlgOptions.DoModal () != IDOK)
        return 0;

    CString sPath = dlgOptions.GetPathName ();
    if (sPath.IsEmpty ())
        return 0;

    int nOptionFlags = dlgOptions.GetOptionFlags ();

	//
	//
	//
	/* Clear error list, not necessary but safe */
	ClearErrList3ds();
   
	file3ds *file = OpenFile3ds ((LPCTSTR) sPath, "w");
	if (PrintError ())
		return -1;

	database3ds *db = NULL;
	InitDatabase3ds (&db);
	if (PrintError ())
		return -1;
    
	CreateNewDatabase3ds (db, MeshFile);
	if (PrintError ())
		return -1;

	/*--- MESH SETTINGS */
	meshset3ds *mset = NULL;
	InitMeshSet3ds (&mset);
	if (PrintError ())
		return -1;
   
	mset->ambientlight.r = mset->ambientlight.g = mset->ambientlight.b = 0.3F;
	PutMeshSet3ds (db, mset);  
	if (PrintError ())
		return -1;

	ReleaseMeshSet3ds (&mset);
	if (PrintError ())
		return -1;

	if (nOptionFlags & eMaterials)
	{
		for (int i = 0; i < msModel_GetMaterialCount (pModel); i++)
		{
			msMaterial *pMaterial = msModel_GetMaterialAt (pModel, i);
			msVec4 vec4;
			
			material3ds *mat = NULL;
			InitMaterial3ds (&mat);
			if (PrintError ())
				return -1;

			char szName[128], szOut[128];
			msMaterial_GetName (pMaterial, szName, 128);
			MakeShortName (szName, szOut, 16);
			strcpy (mat->name, szOut);
			
			msMaterial_GetAmbient (pMaterial, vec4);
			mat->ambient.r = vec4[0];
			mat->ambient.g = vec4[1];
			mat->ambient.b = vec4[2];

			msMaterial_GetDiffuse (pMaterial, vec4);
			mat->diffuse.r = vec4[0];
			mat->diffuse.g = vec4[1];
			mat->diffuse.b = vec4[2];

			msMaterial_GetSpecular (pMaterial, vec4);
			mat->specular.r = vec4[0];
			mat->specular.g = vec4[1];
			mat->specular.b = vec4[2];

			mat->shininess = msMaterial_GetShininess (pMaterial) / 128.0f;
			mat->shinstrength = mat->shininess / 5.0F;
			mat->wiresize = 1.0F;
			mat->shading = Phong;
			mat->soften = True3ds;

			msMaterial_GetDiffuseTexture (pMaterial, szName, 128);
			MakeShortFileName (szName, szOut);
			strcpy (mat->texture.map.name, szOut);
			mat->texture.map.percent = 1.0F;
			mat->texture.map.tiling = Tile;
			mat->texture.map.ignorealpha = False3ds;
			mat->texture.map.filter = Pyramidal;
			mat->texture.map.blur = 0.0F;
			mat->texture.map.mirror = False3ds;
			mat->texture.map.negative = False3ds;
			mat->texture.map.uscale = 1.0F;
			mat->texture.map.vscale = 1.0F;
			mat->texture.map.uoffset = 0.0F;
			mat->texture.map.voffset = 0.0F;
			mat->texture.map.rotation = 0.0F;
			mat->texture.map.source = RGB;

			PutMaterial3ds (db, mat);
			if (PrintError ())
				return -1;

			ReleaseMaterial3ds (&mat);
			if (PrintError ())
				return -1;
		}
	} // eMaterials

	if (nOptionFlags & eMeshes)
	{
		for (int i = 0; i < msModel_GetMeshCount (pModel); i++)
		{
			msMesh *pMesh = msModel_GetMeshAt (pModel, i);
			int nVertices = msMesh_GetVertexCount (pMesh);
			int nFaces = msMesh_GetTriangleCount (pMesh);

			if (nVertices == 0 || nFaces == 0)
				continue;

			mesh3ds *mobj = NULL;
			InitMeshObj3ds (&mobj, nVertices, nFaces,
				InitVertexArray3ds | InitTextArray3ds | InitFaceArray3ds | InitSmoothArray3ds);

			char szName[128], szOut[128];
			msMesh_GetName (pMesh, szName, 128);
			MakeShortName (szName, szOut, 10);
			strcpy (mobj->name, szOut);

			int j;
			for (j = 0; j < nVertices; j++)
			{
				msVertex *pVertex = msMesh_GetVertexAt (pMesh, j);
				msVec3 vec;
				msVertex_GetVertex (pVertex, vec);
				
				mobj->vertexarray[j].x = vec[0];
				mobj->vertexarray[j].y = vec[1];
				mobj->vertexarray[j].z = vec[2];

				msVec2 uv;
				msVertex_GetTexCoords (pVertex, uv);
				mobj->textarray[j].u = uv[0];
				mobj->textarray[j].v = 1.0f - uv[1];
			}

			for (j = 0; j < nFaces; j++)
			{
				msTriangle *pTriangle = msMesh_GetTriangleAt (pMesh, j);
				word nIndices[3];
				msTriangle_GetVertexIndices (pTriangle, nIndices);

				mobj->facearray[j].v1 = nIndices[0];
				mobj->facearray[j].v2 = nIndices[1];
				mobj->facearray[j].v3 = nIndices[2];
				mobj->facearray[j].flag = FaceABVisable3ds | FaceBCVisable3ds | FaceCAVisable3ds;

				int nSmoothingGroup = msTriangle_GetSmoothingGroup (pTriangle);
				if (nSmoothingGroup > 0)
					mobj->smootharray[j] = 1 << (nSmoothingGroup - 1);
				else
					mobj->smootharray[j] = 1;
			}

			if (nOptionFlags & eMaterials)
			{
				int nMaterialIndex = msMesh_GetMaterialIndex (pMesh);
				if (nMaterialIndex != -1)
				{
					mobj->nmats = 1;
					InitMeshObjField3ds (mobj, InitMatArray3ds);
					if (PrintError ())
						return -1;

					InitMatArrayIndex3ds (mobj, 0, nFaces);
					if (PrintError ())
						return -1;

					char szName[128], szOut[128];
					msMaterial *pMaterial = msModel_GetMaterialAt (pModel, nMaterialIndex);
					msMaterial_GetName (pMaterial, szName, 128);
					MakeShortName (szName, szOut, 16);
					strcpy(mobj->matarray[0].name, szOut);

					for (int k = 0; k < nFaces; k++)
					{
						mobj->matarray[0].faceindex[k] = k;
					}
					mobj->matarray[0].nfaces = nFaces;
				}
			}

			// indentity matrix
			mobj->locmatrix[0] = 1.0F;
			mobj->locmatrix[1] = 0.0F;
			mobj->locmatrix[2] = 0.0F;
			mobj->locmatrix[3] = 0.0F;
			mobj->locmatrix[4] = 1.0F;
			mobj->locmatrix[5] = 0.0F;
			mobj->locmatrix[6] = 0.0F;
			mobj->locmatrix[7] = 0.0F;
			mobj->locmatrix[8] = 1.0F;
			mobj->locmatrix[9] = 0.0F;
			mobj->locmatrix[10] = 0.0F;
			mobj->locmatrix[11] = 0.0F;

			PutMesh3ds (db, mobj);
			if (PrintError ())
				return -1;

			RelMeshObj3ds (&mobj);
			if (PrintError ())
				return -1;
		}
	} // eMeshes

	WriteDatabase3ds (file, db);
	if (PrintError ())
		return -1;

	ReleaseDatabase3ds (&db);
	if (PrintError ())
		return -1;

	CloseAllFiles3ds ();
	if (PrintError ())
		return -1;

	//
	// Never forget to destroy the model, after an export!!
	//
	msModel_Destroy (pModel);

    return 0;
}

