#define STRICT

// Includes standard Windows
#include <windows.h>
#include <windowsx.h>
#include <time.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <stdio.h>
#include <math.h>
#include <io.h>

// Includes D3D
#define  D3D_OVERLOADS
#include <ddraw.h>
#include <d3d.h>
#include <d3dx.h>

// Includes utilitaires D3D
#include "d3dmath.h"
#include "d3dutil.h"
#include "D3DEnum.h"

// Ids Resources
#include "resource.h"

// Constantes
#include "const.h"

// Types
#include "types.h"

// Variables globales projet
#include "vars.h"

// Prototypes fonctions autres modules
#include "proto.h"

// Macros
#include "macros.h"

void vSaveBin(void)
{
    char cBuffer[13];
    static TCHAR sFileName[512];
    FILE* hFile;

#ifndef _AMIGA_
    static TCHAR sInitialDir[512] = "";
    TCHAR sCurrentName[512] = "*.sk3d";

	// Récupérer le directory courant
	GetCurrentDirectory(sizeof(sInitialDir), sInitialDir);

    // Préparer une structure OPENFILENAME
	OPENFILENAME sOFName = { sizeof(OPENFILENAME), NULL, NULL,
                         "Fichiers Scènes sKulpt (*.sk3d)\0*.sk3d\0\0",
                         NULL, 0, 1, sCurrentName, 512, sFileName, 512,
                         sInitialDir, "Ouvrir un fichier scène sKulpt", 0, 0, 1,
                         ".sk3d", 0, NULL, NULL };

    // Choisir un fichier
    if(!GetOpenFileName(&sOFName))
        return;

    // Stocker le nom du directory pour le prochain appel
    strcpy(sInitialDir, sCurrentName);
    strstr(sInitialDir, sFileName)[0] = '\0';
#else
    strcpy(sFileName, "#?.sk3d");
    if (!FSelect("Ouvrir...", sFileName))
        return;
#endif

    hFile = fopen(sFileName,
#ifndef _AMIGA_
                     "wb");
#else
                     "w");
#endif

    if (!hFile)
    {
        vTrace("Pb ouverture fichier %s", sFileName);
        return;
    }

    vTrace("*** Fichier scène ouvert : %s", sFileName);
        
    // Garbage collecter
    vCollect();

    // Ecrire la structure d'entête et les données sKulpt 3D mode binaire
    strcpy(cBuffer,
#ifndef _AMIGA_
                    "FORMINTLSK3D"
#else
                    "FORMM68KSK3D"
#endif
           );

    fwrite(cBuffer, 1, 12, hFile);

    vTrace("Ecriture de %d vertices", iVertFirstAvailable);
    fwrite("VERT", 1, 4, hFile);
    fwrite(&iVertFirstAvailable, 1, sizeof(iVertFirstAvailable), hFile);
    fwrite(Vertices, 1, iVertFirstAvailable * sizeof(gSommet), hFile);

    vTrace("Ecriture de %d lampes", iLampFirstAvailable);
    fwrite("LAMP", 1, 4, hFile);
    fwrite(&iLampFirstAvailable, 1, sizeof(iLampFirstAvailable), hFile);
    fwrite(Lampes, 1, iLampFirstAvailable * sizeof(gLamp), hFile);

    vTrace("Ecriture de %d triangles", iTriaFirstAvailable);
    fwrite("FACE", 1, 4, hFile);
    fwrite(&iTriaFirstAvailable, 1, sizeof(iTriaFirstAvailable), hFile);
    fwrite(Triangles, 1, iTriaFirstAvailable * sizeof(gTri), hFile);

    vTrace("Ecriture de %d arêtes", iEdgeFirstAvailable);
    fwrite("EDGE", 1, 4, hFile);
    fwrite(&iEdgeFirstAvailable, 1, sizeof(iEdgeFirstAvailable), hFile);
    fwrite(Edges, 1, iEdgeFirstAvailable * sizeof(gEdge), hFile);

    vTrace("Ecriture de %d matériaux", iMtrlFirstAvailable);
    fwrite("MTRL", 1, 4, hFile);
    fwrite(&iMtrlFirstAvailable, 1, sizeof(iMtrlFirstAvailable), hFile);
    fwrite(Materials, 1, iMtrlFirstAvailable * sizeof(gMtrl), hFile);

    vTrace("Ecriture de l'environnement");
    fwrite("OBSV", 1, 4, hFile);
    fwrite(&Observer, 1, sizeof(Observer), hFile);
    fwrite(&Target, 1, sizeof(Target), hFile);
    fwrite(&cAmbient, 1, sizeof(cAmbient), hFile);
    fwrite(&cBack, 1, sizeof(cBack), hFile);

    // Fermer le fichier
    fclose(hFile);
    vTrace("Fichier scène créé");
}

void vLoadBin(void)
{
    int iNumVertex = 0, iNumFace = 0, iNumLamps = 0, iNumEdges = 0, iNumMtrl = 0, iX;
    char cBuffer[13];
    DWORD dwNBytesRead;
    static TCHAR sFileName[512];

#ifndef _AMIGA_
    HANDLE hFile;
    static TCHAR sInitialDir[512] = "";
    TCHAR sCurrentName[512] = "*.sk3d";
    OFSTRUCT ReOpenBuff;
    // Récupérer le directory courant
    GetCurrentDirectory(sizeof(sInitialDir), sInitialDir);

    // Préparer une structure OPENFILENAME
    OPENFILENAME sOFName = { sizeof(OPENFILENAME), NULL, NULL,
                         "Fichiers Scènes sk3d (*.sk3d)\0*.sk3d\0\0",
                         NULL, 0, 1, sCurrentName, 512, sFileName, 512,
                         sInitialDir, "Ouvrir un fichier scène sk3d", OFN_FILEMUSTEXIST, 0, 1,
                         ".sk3d", 0, NULL, NULL };

    // Choisir un fichier
    if(!GetOpenFileName(&sOFName))
        return;

    // Stocker le nom du directory pour le prochain appel
    strcpy(sInitialDir, sCurrentName);
    strstr(sInitialDir, sFileName)[0] = '\0';

    // Ouvrir le fichier en lecture
    if ((HANDLE) HFILE_ERROR == (hFile = (HANDLE) OpenFile(sFileName, &ReOpenBuff, OF_READ)))
        return;
#else
    FILE* hFile;

    strcpy(sFileName, "#?.sk3d");

    if (!FSelect("Ouvrir...", sFileName))
        return;

    hFile = fopen(sFileName, "r");
    if (!hFile)
    {
        vTrace("Pb ouverture fichier %s", sFileName);
        return;
    }
#endif // _AMIGA_

    vTrace("*** Fichier scène ouvert :");
    vTrace(sFileName);
        
    // Effacer tous les objets présents en mémoire
    vDeleteObjects();

    // Vérifier la structure d'entête SKulpt 3D mode binaire
#ifndef _AMIGA_
    ReadFile(hFile, cBuffer, 12, &dwNBytesRead, NULL);
#else
    dwNBytesRead = fread(cBuffer, 1, 12, hFile);
#endif

    if (strncmp((char *) cBuffer,
#ifndef _AMIGA_
         "FORMINTLSK3D"
#else
         "FORMM68KSK3D"
#endif
         , 12))
    {
        vTrace("*** E0024 : En-tête fichier scène incorrect");
        goto _Fin;
    }

    // Parcourir le fichier en décodant les chunks au fur et à mesure
    cBuffer[4] = 0;
#ifndef _AMIGA_
    while ((ReadFile(hFile, cBuffer, 4, &dwNBytesRead, NULL)) && (dwNBytesRead == 4))
#else
    while (4 == (dwNBytesRead = fread(cBuffer, 1, 4, hFile)))
#endif
    {
        vTrace("Chunk : %4s", cBuffer);

        if (!strncmp((char *) cBuffer, "VERT", 4))  // Sommets
        {
            // Charger le nombre de vertex
#ifndef _AMIGA_
            ReadFile(hFile, &iNumVertex, 4, &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(&iNumVertex, 1, 4, hFile);
#endif
            vTrace("Nombre de sommets : %ld", iNumVertex);

            // Lire directement le chunk vertices
#ifndef _AMIGA_
            ReadFile(hFile, Vertices, iNumVertex * sizeof(gSommet), &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(Vertices, 1, iNumVertex * sizeof(gSommet), hFile);
#endif
            continue;
        }

        if (!strncmp((char *) cBuffer, "LAMP", 4))  // Lampes
        {
            // Charger le nombre de lampes
#ifndef _AMIGA_
            ReadFile(hFile, &iNumLamps, 4, &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(&iNumLamps, 1, 4, hFile);
#endif
            vTrace("Nombre de lampes : %ld", iNumLamps);

            // Lire les lampes
#ifndef _AMIGA_
            ReadFile(hFile, Lampes, iNumLamps * sizeof(gLamp), &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(Lampes, 1, iNumLamps * sizeof(gLamp), hFile);
#endif
            continue;
        }

        if (!strncmp((char *) cBuffer, "FACE", 4)) // Triangles
        {
            // Charger le nombre de faces
#ifndef _AMIGA_
            ReadFile(hFile, &iNumFace, 4, &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(&iNumFace, 1, 4, hFile);
#endif
            vTrace("Nombre de faces : %ld", iNumFace);

            // Lire les faces
#ifndef _AMIGA_
            ReadFile(hFile, Triangles, iNumFace * sizeof(gTri), &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(Triangles, 1, iNumFace * sizeof(gTri), hFile);
#endif
            continue;
        }

        if (!strncmp((char *) cBuffer, "EDGE", 4)) // Arêtes
        {
            // Charger le nombre d'arêtes
#ifndef _AMIGA_
            ReadFile(hFile, &iNumEdges, 4, &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(&iNumEdges, 1, 4, hFile);
#endif
            vTrace("Nombre d'arêtes : %ld", iNumEdges);

            // Lire les arêtes
#ifndef _AMIGA_
            ReadFile(hFile, Edges, iNumEdges * sizeof(gEdge), &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(Edges, 1, iNumEdges * sizeof(gEdge), hFile);
#endif
            continue;
        }

        if (!strncmp((char *) cBuffer, "MTRL", 4)) // Matériaux
        {
            // Charger le nombre de matériaux
#ifndef _AMIGA_
            ReadFile(hFile, &iNumMtrl, 4, &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(&iNumMtrl, 1, 4, hFile);
#endif
            vTrace("Nombre de matériaux : %ld", iNumMtrl);

            // Lire les arêtes
#ifndef _AMIGA_
            ReadFile(hFile, Materials, iNumMtrl * sizeof(gMtrl), &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(Materials, 1, iNumMtrl * sizeof(gMtrl), hFile);
#endif
            continue;
        }

        if (!strncmp((char *) cBuffer, "OBSV", 4)) // Environnement
        {
            // Charger la structure observer
#ifndef _AMIGA_
            ReadFile(hFile, &Observer, sizeof(Observer), &dwNBytesRead, NULL);
            ReadFile(hFile, &Target, sizeof(Observer), &dwNBytesRead, NULL);
            ReadFile(hFile, &cAmbient, sizeof(cAmbient), &dwNBytesRead, NULL);
            ReadFile(hFile, &cBack, sizeof(cBack), &dwNBytesRead, NULL);
#else
            dwNBytesRead = fread(&Observer, 1, sizeof(Observer), hFile);
            dwNBytesRead = fread(&Target, 1, sizeof(Target), hFile);
            dwNBytesRead = fread(&cAmbient, 1, sizeof(cAmbient), hFile);
            dwNBytesRead = fread(&cBack, 1, sizeof(cBack), hFile);
#endif
            D3DUtil_SetViewMatrix(matView,
              Observer, // From
              Target,   // To
              D3DVECTOR(0.f, 0.f, 0.f));
            continue;
        }

        // Chunk non traité.
#ifndef _AMIGA_
        ReadFile(hFile, &iX, 4, &dwNBytesRead, NULL);
#else
        dwNBytesRead = fread(&iX, 1, 4, hFile);
#endif

        vTrace("Skip %d octets", iX);
#ifndef _AMIGA_
        SetFilePointer(hFile, iX, NULL, FILE_CURRENT);
#else
        fseek(hFile, iX, SEEK_CUR);
#endif
    }

_Fin:

    // Fermer le fichier
#ifndef _AMIGA_
    CloseHandle(hFile);
#else
    fclose(hFile);
#endif

    iVertLastUsed = (iVertFirstAvailable = iNumVertex) - 1;
    iEdgeLastUsed = (iEdgeFirstAvailable = iNumEdges) - 1;
    iLampLastUsed = (iLampFirstAvailable = iNumLamps) - 1;
    iTriaLastUsed = (iTriaFirstAvailable = iNumFace) - 1;
    iMtrlLastUsed = (iMtrlFirstAvailable = iNumMtrl) - 1;

#ifndef _AMIGA_
    // Forcer le recalcul des sommets de chaque triangle (car on a changé les points)
    for (int iTriangle = 0 ; iTriangle <= iTriaLastUsed ; iTriangle++)
        bUpdateD3DTri(iTriangle);
#endif
}
