#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "msPlugInImpl.h"
#include "msLib.h"
#include "DlgOptions.h"
#include "DlgMessage.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, "MilkShape 3D ASCII...");
}



cPlugIn::~cPlugIn ()
{
}



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



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


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

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

    //
    // ask for deletion
    //
    if (msModel_GetBoneCount (pModel) > 0)
    {
        int RC = ::AfxMessageBox (IDS_WARNING_MODEL_DELETE, MB_YESNOCANCEL);
        if (RC != IDYES)
            return 0;
    }

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

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

    int nOptionFlags = dlgOptions.GetOptionFlags ();

    CString s;
    FILE *file = fopen ((LPCTSTR) sPath, "rt");
    if (!file)
    {
        s.Format(IDS_ERROR_OPENING_FILE_P, sPath);
        ::AfxMessageBox (s);
        return -1;
    }

    cDlgMessage dlgMessage (NULL);
    dlgMessage.Create (IDD_MESSAGE, NULL);
    dlgMessage.SetTitle ("Importing...");

    //
    // destroy the bones
    //
    if (pModel->pBones)
    {
        free (pModel->pBones);
        pModel->pBones = 0;
        pModel->nNumBones = 0;
        pModel->nNumAllocedBones = 0;
    }
    int i, j;

    // detach the vertices from the bones
    for (i = 0; i < msModel_GetMeshCount (pModel); i++)
    {
        msMesh *pMesh = msModel_GetMeshAt (pModel, i);
        for (j = 0; j < msMesh_GetVertexCount (pMesh); j++)
        {
            msVertex *pVertex = msMesh_GetVertexAt (pMesh, j);
            msVertex_SetBoneIndex (pVertex, -1);
        }
    }

    bool bError = false;
    char szLine[256];
    char szName[MS_MAX_NAME];
    int nFlags, nIndex;

    while (fgets (szLine, 256, file) != NULL  && !bError)
    {
        if (!strncmp (szLine, "//", 2))
            continue;

        int nFrame;
        if (sscanf (szLine, "Frames: %d", &nFrame) == 1)
        {
            msModel_SetTotalFrames (pModel, nFrame);
        }
        if (sscanf (szLine, "Frame: %d", &nFrame) == 1)
        {
            msModel_SetFrame (pModel, nFrame);
        }

        int nNumMeshes = 0;
        if (sscanf (szLine, "Meshes: %d", &nNumMeshes) == 1 && nOptionFlags & eMeshes)
        {
            dlgMessage.SetMessage ("Importing Meshes...");
            dlgMessage.SetRange (nNumMeshes);
            dlgMessage.SetPosition (0);
            for (i = 0; i < nNumMeshes && !bError; i++)
            {
                int nMesh = msModel_AddMesh (pModel);
                msMesh *pMesh = msModel_GetMeshAt (pModel, i);
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }

                // mesh: name, flags, material index
                if (sscanf (szLine, "\"%[^\"]\" %d %d",szName, &nFlags, &nIndex) != 3)
                {
                    bError = true;
                    break;
                }

                msMesh_SetName (pMesh, szName);
                msMesh_SetFlags (pMesh, nFlags);
                if (nOptionFlags & eMaterials)
                    msMesh_SetMaterialIndex (pMesh, nIndex);
                else
                    msMesh_SetMaterialIndex (pMesh, -1);

                //
                // vertices
                //
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }

                int nNumVertices = 0;
                if (sscanf (szLine, "%d", &nNumVertices) != 1)
                {
                    bError = true;
                    break;
                }

                for (j = 0; j < nNumVertices; j++)
                {
                    if (!fgets (szLine, 256, file))
                    {
                        bError = true;
                        break;
                    }

                    msVec3 Vertex;
                    msVec2 uv;
                    if (sscanf (szLine, "%d %f %f %f %f %f %d",
                        &nFlags,
                        &Vertex[0], &Vertex[1], &Vertex[2],
                        &uv[0], &uv[1],
                        &nIndex
                        ) != 7)
                    {
                        bError = true;
                        break;
                    }

                    int nVertex = msMesh_AddVertex (pMesh);
                    msVertex *pVertex = msMesh_GetVertexAt (pMesh, nVertex);
                    msVertex_SetFlags (pVertex, nFlags);
                    msVertex_SetVertex (pVertex, Vertex);
                    msVertex_SetTexCoords (pVertex, uv);
                    if (nOptionFlags & eBones)
                        msVertex_SetBoneIndex (pVertex, nIndex);
                    else
                        msVertex_SetBoneIndex (pVertex, -1);

                }

                //
                // normals
                //
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }

                int nNumNormals = 0;
                if (sscanf (szLine, "%d", &nNumNormals) != 1)
                {
                    bError = true;
                    break;
                }

                for (j = 0; j < nNumNormals; j++)
                {
                    if (!fgets (szLine, 256, file))
                    {
                        bError = true;
                        break;
                    }

                    msVec3 Normal;
                    if (sscanf (szLine, "%f %f %f", &Normal[0], &Normal[1], &Normal[2]) != 3)
                    {
                        bError = true;
                        break;
                    }

                    int nNormal = msMesh_AddVertexNormal (pMesh);
                    msMesh_SetVertexNormalAt (pMesh, nNormal, Normal);
                }
                //
                // triangles
                //
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }

                int nNumTriangles = 0;
                if (sscanf (szLine, "%d", &nNumTriangles) != 1)
                {
                    bError = true;
                    break;
                }

                for (j = 0; j < nNumTriangles; j++)
                {
                    if (!fgets (szLine, 256, file))
                    {
                        bError = true;
                        break;
                    }

                    word nIndices[3];
                    word nNormalIndices[3];
                    if (sscanf (szLine, "%d %d %d %d %d %d %d %d",
                        &nFlags,
                        &nIndices[0], &nIndices[1], &nIndices[2],
                        &nNormalIndices[0], &nNormalIndices[1], &nNormalIndices[2],
                        &nIndex
                        ) != 8)
                    {
                        bError = true;
                        break;
                    }

                    int nTriangle = msMesh_AddTriangle (pMesh);
                    msTriangle *pTriangle = msMesh_GetTriangleAt (pMesh, nTriangle);
                    msTriangle_SetFlags (pTriangle, nFlags);
                    msTriangle_SetVertexIndices (pTriangle, nIndices);
                    msTriangle_SetNormalIndices (pTriangle, nNormalIndices);
                    msTriangle_SetSmoothingGroup (pTriangle, nIndex);
                }
                dlgMessage.SetPosition (i + 1);
            }
        }

        //
        // materials
        //
        int nNumMaterials = 0;
        if (sscanf (szLine, "Materials: %d", &nNumMaterials) == 1 && nOptionFlags & eMaterials)
        {
            int i;
            char szName[MS_MAX_NAME];

            dlgMessage.SetMessage ("Importing Materials...");
            dlgMessage.SetRange (nNumMaterials);
            dlgMessage.SetPosition (0);
            for (i = 0; i < nNumMaterials && !bError; i++)
            {
                int nMaterial = msModel_AddMaterial (pModel);
                msMaterial *pMaterial = msModel_GetMaterialAt (pModel, i);

                // name
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                if (sscanf (szLine, "\"%[^\"]\"", szName) != 1)
                {
                    bError = true;
                    break;
                }
                msMaterial_SetName (pMaterial, szName);

                // ambient
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                msVec4 Ambient;
                if (sscanf (szLine, "%f %f %f %f", &Ambient[0], &Ambient[1], &Ambient[2], &Ambient[3]) != 4)
                {
                    bError = true;
                    break;
                }
                msMaterial_SetAmbient (pMaterial, Ambient);

                // diffuse
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                msVec4 Diffuse;
                if (sscanf (szLine, "%f %f %f %f", &Diffuse[0], &Diffuse[1], &Diffuse[2], &Diffuse[3]) != 4)
                {
                    bError = true;
                    break;
                }
                msMaterial_SetDiffuse (pMaterial, Diffuse);

                // specular
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                msVec4 Specular;
                if (sscanf (szLine, "%f %f %f %f", &Specular[0], &Specular[1], &Specular[2], &Specular[3]) != 4)
                {
                    bError = true;
                    break;
                }
                msMaterial_SetSpecular (pMaterial, Specular);

                // emissive
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                msVec4 Emissive;
                if (sscanf (szLine, "%f %f %f %f", &Emissive[0], &Emissive[1], &Emissive[2], &Emissive[3]) != 4)
                {
                    bError = true;
                    break;
                }
                msMaterial_SetEmissive (pMaterial, Emissive);

                // shininess
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                float fShininess;
                if (sscanf (szLine, "%f", &fShininess) != 1)
                {
                    bError = true;
                    break;
                }
                msMaterial_SetShininess (pMaterial, fShininess);

                // transparency
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                float fTransparency;
                if (sscanf (szLine, "%f", &fTransparency) != 1)
                {
                    bError = true;
                    break;
                }
                if (nOptionFlags & eNoTransparency)
                    msMaterial_SetTransparency (pMaterial, 1.0f);
                else
                    msMaterial_SetTransparency (pMaterial, fTransparency);

                // diffuse texture
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                if (sscanf (szLine, "\"%[^\"]\"", szName) != 1)
                {
                  msMaterial_SetDiffuseTexture (pMaterial, "");
                }
                else
                {
                  msMaterial_SetDiffuseTexture (pMaterial, szName);
                }

                // alpha texture
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                strcpy (szName, "");
                sscanf (szLine, "\"%[^\"]\"", szName);

                msMaterial_SetAlphaTexture (pMaterial, szName);
                dlgMessage.SetPosition (i + 1);
            }
        }

        //
        // bones
        //
        int nNumBones = 0;
        if (sscanf (szLine, "Bones: %d", &nNumBones) == 1 && nOptionFlags & eBones)
        {
            int i;
            char szName[MS_MAX_NAME];

            dlgMessage.SetMessage ("Importing Bones...");
            dlgMessage.SetRange (nNumBones);
            dlgMessage.SetPosition (0);
            for (i = 0; i < nNumBones && !bError; i++)
            {
                int nBone = msModel_AddBone (pModel);
                msBone *pBone = msModel_GetBoneAt (pModel, i);

                // name
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                if (sscanf (szLine, "\"%[^\"]\"", szName) != 1)
                {
                    bError = true;
                    break;
                }
                msBone_SetName (pBone, szName);

                // alpha texture
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                strcpy (szName, "");
                sscanf (szLine, "\"%[^\"]\"", szName);

                msBone_SetParentName (pBone, szName);

                // flags, position, rotation
                msVec3 Position, Rotation;
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                if (sscanf (szLine, "%d %f %f %f %f %f %f",
                    &nFlags,
                    &Position[0], &Position[1], &Position[2],
                    &Rotation[0], &Rotation[1], &Rotation[2]) != 7)
                {
                    bError = true;
                    break;
                }
                msBone_SetFlags (pBone, nFlags);
                msBone_SetPosition (pBone, Position);
                msBone_SetRotation (pBone, Rotation);

                float fTime;

                // position key count
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                int nNumPositionKeys = 0;
                if (sscanf (szLine, "%d", &nNumPositionKeys) != 1)
                {
                    bError = true;
                    break;
                }

                for (j = 0; j < nNumPositionKeys; j++)
                {
                    if (!fgets (szLine, 256, file))
                    {
                        bError = true;
                        break;
                    }
                    if (sscanf (szLine, "%f %f %f %f", &fTime, &Position[0], &Position[1], &Position[2]) != 4)
                    {
                        bError = true;
                        break;
                    }

                    if (nOptionFlags & eKeyFrames)
                        msBone_AddPositionKey (pBone, fTime, Position);
                }

                // rotation key count
                if (!fgets (szLine, 256, file))
                {
                    bError = true;
                    break;
                }
                int nNumRotationKeys = 0;
                if (sscanf (szLine, "%d", &nNumRotationKeys) != 1)
                {
                    bError = true;
                    break;
                }

                for (j = 0; j < nNumRotationKeys; j++)
                {
                    if (!fgets (szLine, 256, file))
                    {
                        bError = true;
                        break;
                    }
                    if (sscanf (szLine, "%f %f %f %f", &fTime, &Rotation[0], &Rotation[1], &Rotation[2]) != 4)
                    {
                        bError = true;
                        break;
                    }

                    if (nOptionFlags & eKeyFrames)
                        msBone_AddRotationKey (pBone, fTime, Rotation);
                }
                dlgMessage.SetPosition (i + 1);
            }
        }
    }

    fclose (file);

    return 0;
}

