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



#define MAX_VERTICES	8192
#define MAX_TRIANGLES	16384



#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::eTypeImport;
}



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


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());

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

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

    int nOptionFlags = dlgOptions.GetOptionFlags ();

	//
	//
	//
	ClearErrList3ds ();
   
	file3ds *file = OpenFile3ds ((LPCTSTR) sPath, "rw");
	if (PrintError ())
		return -1;

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

	if (nOptionFlags & eMaterials)
	{
		namelist3ds *matlist = NULL;
		material3ds *mat = NULL;
		int i;
      
		GetMaterialNameList3ds (db, &matlist);
		if (PrintError ())
			return -1;
      
		for (i = 0; i < (int) matlist->count; i++)
		{
			msVec4 vec4;

			GetMaterialByName3ds (db, matlist->list[i].name, &mat);
			if (PrintError ())
				return -1;

			int nMaterial = msModel_AddMaterial (pModel);
			msMaterial *pMaterial = msModel_GetMaterialAt (pModel, nMaterial);
			msMaterial_SetName (pMaterial, mat->name);

			vec4[0] = mat->ambient.r;
			vec4[1] = mat->ambient.g;
			vec4[2] = mat->ambient.b;
			vec4[3] = 1.0f;
			msMaterial_SetAmbient (pMaterial, vec4);

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

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

			msMaterial_SetTransparency (pMaterial, 1.0f);//1.0f - mat->transparency);
			msMaterial_SetShininess (pMaterial, mat->shininess);
			msMaterial_SetDiffuseTexture (pMaterial, mat->texture.map.name);

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

		ReleaseNameList3ds (&matlist);
		if (PrintError ())
			return -1;
	} // eMaterials

	if (nOptionFlags & eMeshes)
	{
		namelist3ds *meshlist = NULL;
		mesh3ds *mesh = NULL;
		int i;

		// count vertices and faces
		int nTotalVertices = 0;
		int nTotalFaces = 0;
		for (i = 0; i < msModel_GetMeshCount (pModel); i++)
		{
			msMesh *pMesh = msModel_GetMeshAt (pModel, i);
			nTotalVertices += msMesh_GetVertexCount (pMesh);
			nTotalFaces += msMesh_GetTriangleCount (pMesh);
		}

		/* Generate a list of names to test the Name searching */
		GetMeshNameList3ds (db, &meshlist);
		if (PrintError ())
			return -1;
      
		for (i = 0; i < (int) meshlist->count; i++)
		{
			GetMeshByName3ds (db, meshlist->list[i].name, &mesh);
			if (PrintError ())
				return -1;

			//
			// check total faces and vertices
			//
			nTotalFaces += mesh->nfaces;
			nTotalVertices += mesh->nvertices;
			if (nTotalFaces > MAX_TRIANGLES ||
				nTotalVertices > MAX_VERTICES)
			{
				CString s;
				s.Format ("Too many faces (%d) or vertices (%d).", nTotalFaces, nTotalVertices);
				::AfxMessageBox (s);
				RelMeshObj3ds (&mesh);
				if (PrintError ())
					return -1;
				continue;
			}

			//
			// add mesh
			//
			int nMesh = msModel_AddMesh (pModel);
			msMesh *pMesh = msModel_GetMeshAt (pModel, nMesh);
			msMesh_SetName (pMesh, mesh->name);
			if (mesh->nmats == 1)
			{
				int nMaterialIndex = msModel_FindMaterialByName (pModel, mesh->matarray->name);
				msMesh_SetMaterialIndex (pMesh, nMaterialIndex);
			}

			int j;
			for (j = 0; j < mesh->nvertices; j++)
			{
				msVec3 vec3;
				int nVertex = msMesh_AddVertex (pMesh);
				msVertex *pVertex = msMesh_GetVertexAt (pMesh, nVertex);

				vec3[0] = mesh->vertexarray[j].x;
				vec3[1] = mesh->vertexarray[j].y;
				vec3[2] = mesh->vertexarray[j].z;
				msVertex_SetVertex (pVertex, vec3);

				if (mesh->ntextverts == mesh->nvertices)
				{
					msVec2 uv;
					uv[0] = mesh->textarray[j].u;
					uv[1] = 1.0f - mesh->textarray[j].v;
					msVertex_SetTexCoords (pVertex, uv);
				}
			}

			for (j = 0; j < mesh->nfaces; j++)
			{
				int nTriangle = msMesh_AddTriangle (pMesh);
				msTriangle *pTriangle = msMesh_GetTriangleAt (pMesh, nTriangle);

				word nIndices[3];
				nIndices[0] = mesh->facearray[j].v1;
				nIndices[1] = mesh->facearray[j].v2;
				nIndices[2] = mesh->facearray[j].v3;
				msTriangle_SetVertexIndices (pTriangle, nIndices);

				if (mesh->smootharray)
				{
					int s = mesh->smootharray[j];
					int nSmoothingGroup = 0;
					while (s > 0)
					{
						s >>= 1;
						++nSmoothingGroup;
					}
					if (nSmoothingGroup == 0)
						++nSmoothingGroup;

					msTriangle_SetSmoothingGroup (pTriangle, nSmoothingGroup);
				}
			}

			RelMeshObj3ds (&mesh);
			if (PrintError ())
				return -1;
		}

		ReleaseNameList3ds(&meshlist);
		if (PrintError ())
			return -1;
	} // eMeshes

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

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

    return 0;
}

