////////////////////////////////////////////////////////////////////////////////
//        +----    |      |    +---+     +-----                               //
//       /         |      |    |    )    |                                    //
//      |          |      |    |---<     +---         By BeLZeL               //
//      \          \     /     |    \    |              Copyright © 2002-2004 //
//       +----      +---+      +----+    +-----   v 2.5   Featuring OpenGL    //
////////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------
// Includes                          
//------------------------------------------------------------------------------

    #include <windows.h>                            // Header pour les Applications Windows
    #include <stdio.h>                              // Header d'Entrée/Sortie Standard
    #include <GL/glut.h>                            // Header OpenGL Utility Toolkit (GLUT)
    #include <string.h>                             // Header pour strcpy et strcat
    #include <mmsystem.h>                           // Header pour le son wav
    #include <math.h>                               // Header utilisé pour les puissances

//------------------------------------------------------------------------------
// Constantes
//------------------------------------------------------------------------------

    #define EXIT        {fclose(fichier);return -1;}    // Permet de quitter plus rapidement
    #define CTOI(C)     (*(int*)&C)                     // Récupère en int un nombre pointé par un char*
    #define pi          3.1415926535897932384626433832795f // PI pour les angles
    #define scal        4                               // Echelle
    #define Blend_ON    {glEnable(GL_BLEND);glDisable(GL_DEPTH_TEST);}
    #define Blend_OFF   {glDisable(GL_BLEND);glEnable(GL_DEPTH_TEST);}
    #define TOTAL_BOUTON    20
    #define COLOR_ARC_EN_CIEL   glColor3f(1.0f*(float)(cos(arc_en_ciel/20.0f)),1.0f*(float)(sin(arc_en_ciel/25.0f)),1.0f-0.5f*(float)(cos(arc_en_ciel/17.0f)))
    
    #ifndef bool
        typedef int bool;
        #define false (1==2)
        #define true (1==1)
    #endif

//------------------------------------------------------------------------------
// Variables
//------------------------------------------------------------------------------

    GLUquadricObj*  g_quadratic;                    // Storage For Our Quadratic Objects (NEW)
    float   float_fps;

    // utilisées temporairement pour la lumière
    GLfloat LightAmbient[]= { 3.0f, 3.0f, 3.0f, 0.5f };
    GLfloat LightDiffuse[]= { 4.0f, 4.0f, 4.0f, 1.0f };
    GLfloat LightPosition[]={ 0.0f, 0.0f, 0.0f, 0.0f };
    bool    light=true;                // Lighting ON/OFF

    // utilisées pour le choix de l'affichage
    bool    g_gamemode=true;                        // GameMode ON/OFF                              | GestionSpecial(MAIN), main(MAIN), ask_gamemode(GAME)
    bool    g_blend = false;                        // Blending ON/OFF                              | GestionSpecial(MAIN)

    // utilisées pour lire et convertir les MAP
    int     nb1, nb2;                               // Pour les boucles                             | Create_Map(MAP)
    bool    map = false;                            // Lecture de la Map OUI/NON                    | Create_Map(MAP)
    int     mat[100][100];                          // Matrice de la map convertie                  | Create_Map(MAP)
    char    *map_name="maplab.map";                 // Nom de la map                                | Create_Map(MAP)

    // utilisées pour les FPS et le titre
    struct TEMPS
    {
        int tps;                // temps depuis le début
        int non_ecoule;         // temps non ecoulé pendant la pause
        float ecart;            // ecart de temps entre deux frames
        long int frame;         // nombre de frames depuis le début
        int frame_fps;          // nombre réinitialisé pour les FPS
        int base;               // temps réinitialisé pour les FPS
        int pause;              // pause du temps
        float fps;              // nombre de FPS
    };
    // Gestion du temps
    struct TEMPS temps;
    
    char    nbfps[30]="";                           // FPS                                          | Draw(MAIN), fps(FPS)
    float   cg_console_size=0;                      // Taille affichée de la console                | GestionSpecial(MAIN), draw_console(HUD)

    // utilisées pour la gestion du target dans GluLookAt
    double  mouse_up=0;                             // Souris haut-bas                              | GestionSpecial(MAIN), ClavierBouge(MAIN), Draw(MAIN), Reshape(RESHAPE)
    double  mouse_rl=0;                             // Souris droite-gauche                         | GestionSpecial(MAIN), ClavierBouge(MAIN), Draw(MAIN), Reshape(RESHAPE)
    POINT   mpos;                                   // Position de la souris, mpos.x et mpos.y      | Draw(MAIN)
    float   targetx=0, targety=0, targetz=0;        // Les 3 targets de la caméra                   | Draw(MAIN)

    // utilisées pour les menus
    int     sensitivity=2;                          // Vitesse de la souris                         | selectSensitivity(MENUS)
    int     cg_fov=90;                              // Champ de vision en degré                     | Draw(MAIN), selectFov(MENUS)
    int     cg_crosshair=2;                         // Dessin qui permet de viser                   | selectCrossHair(MENUS), draw_crosshair(HUD)
    int     cg_console=0;                           // Console ON/OFF                               | GestionClavier(MAIN), draw_console(HUD)
    int     cg_player=1;                            // Caméra Spectateur ou Joueur                  | ClavierBouge(MAIN), selectCam(MENUS)
    bool    zoom=false;                             // Zoom ON/OFF
    float   cg_zoom=0;                              // Importance du zoom
    bool    menu=false;                             // Menu ON/OFF ... si ON -> menu principal, si OFF affiche les polygones
    bool    map_menu=false;                         // Menu Principal
    bool    graph_menu=false;                       // Menu Graphics
    bool    main_menu=false;                        // Menu Map
    bool    ciel=true;                              // Ciel ON/OFF
    int     champ_depth=200;                        // Profondeur de Champ
    float   arc_en_ciel = 0.0f;                     // Utilisée pour une couleur arc-en-ciel dans le menu
    int     scroll;                                 // Permet de scroller dans le menu Graphics
    int     maxtokens;                              // Garde le nombre total d'extensions OpenGL gérées
    bool    m3D=true;                               // Permet d'utiliser ou non l'optimisation du moteur 3D
    typedef struct                                  // Création d'une structure pour les boutons
     {
        int     x1;                                 // bas gauche X
        int     y1;                                 // bas gauche Y
        int     x2;                                 // haut droit X
        int     y2;                                 // haut droit Y
        bool    stat;                               // etat, curseur dessus ou pas
        bool    clic;                               // clic ou pas
        char    texte[10];                          // texte pour une commande
        bool    select;                             // bouton sélectionné
     } Buttons;          
    Buttons bouton[TOTAL_BOUTON];

    // utilisées pour les déplacements
    double  move_rl=1;                              // Droite-Gauche                                | GestionSpeciale(MAIN), ClavierBouge(MAIN), Draw(MAIN), map_create_mat(MAPMAT)
    double  run=1;                                  // Avant-Arrière                                | GestionSpeciale(MAIN), ClavierBouge(MAIN), Draw(MAIN), map_create_mat(MAPMAT)
    double  jump=1;                                 // Monter-Descendre                             | GestionSpeciale(MAIN), ClavierBouge(MAIN), Draw(MAIN), map_create_mat(MAPMAT)
    double  move_hb;                                // Monter-Descendre légèrement lorsqu'on avance | ClavierBouge(MAIN)
    bool    g_keys[256];                            // Touches Appuyées                             | GestionClavier(MAIN), ClavierBouge(MAIN), KeyN_Up(MAIN)

    // taille de l'écran divisé par 2
    int     width;                                  // Largeur de la fenêtre divisée par 2          | SourisBouge(MAIN), ClavierBouge(MAIN), Draw(MAIN), Reshape(RESHAPE)
    int     height;                                 // Hauteur de la fenêtre divisée par 2          | GestionClavier(MAIN), SourisBouge(MAIN), ClavierBouge(MAIN), Draw(MAIN), Reshape(RESHAPE)

    // Textures BMP et TGA
    GLuint  Name[50];                               // Nombre de textures à charger ( PLUS UN ! )   | Draw(MAIN), LoadBMP(LOADBMP), petitcube(PCUBE), groscube(GCUBE), draw_console(HUD), map_draw(MAPDRAW)
    float   roll=0;                                 // Fait bouger les textures
    float   roll1=0, roll2=0;                       // Pour la fumée
    bool    fire=false;                             // Pour le ShotGun et la fumée
    int     base;                                   // Liste pour afficher un caractère
    

//------------------------------------------------------------------------------
// Includes des fichiers associés au projet
//------------------------------------------------------------------------------

    #include "font.h"                               // affiche une police non vectorielle à l'écran, venant d'une texture TGA
    #include "fps.h"                                // calcul des FPS et affichage dans le titre
    #include "hud.h"                                // affichage du hud
    #include "init.h"                               // initialisation de l'affichage et de la fenêtre
    #include "load.h"                               // chargement des textures BMP & TGA
    #include "map.h"                                // affichage de la map
    #include "move.h"                               // tous les déplacements clavier-souris
    #include "draw.h"                               // affichage du menu

//------------------------------------------------------------------------------
// Gestion de l'affichage
//------------------------------------------------------------------------------

void    Draw()
 {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    menu=main_menu || map_menu || graph_menu;
    if (!menu)
     {
        glutSetCursor(GLUT_CURSOR_NONE);            // Plus de curseurs

        // modification du fov
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        if ((zoom) && (cg_fov-cg_zoom>20)) cg_zoom+=100*temps.ecart;   // On zoome
        if ((!zoom) && (cg_fov-cg_zoom<cg_fov)) cg_zoom-=100*temps.ecart; // On dézoome
        gluPerspective(cg_fov-cg_zoom,width/height,0.001f,champ_depth); // On fixe le FOV

        // calcul du positionnement de la caméra
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        draw_cam();                                 // Place la caméra

        glScaled(scal,scal,scal);                   // Echelle
        roll=roll+temps.ecart*0.1;                           // Fait bouger les textures
        Create_Map();                               // Affichage de la map
        if (ciel) Draw_Ciel();                      // Affiche le ciel et le soleil

        SourisBouge();                              // Mouvements de la souris
        if (!g_blend)                               // S'il le blend est activé, on affiche aucun texte car ils utilisent déjà le blend
         {
            // On fait un écran Ortho 2D pour le HUD
            glMatrixMode(GL_PROJECTION);            // On se met en PROJECTION 2D
            glLoadIdentity();                       // On initialise la matrice
            glOrtho(0,640,0,480,0.1,0.2);           // Fait un écran Ortho, 0-0 en haut à droite, comme pour les coordonnées de la souris

            // On passe tout de même en 3D pour le texte
            glMatrixMode(GL_MODELVIEW);             // On se met en MODELVIEW 3D
            glLoadIdentity();                       // On initialise
            draw_hud();                             // on affiche le texte, le hud
         }
     }

    if (main_menu)
     {
        glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);
        GetCursorPos(&mpos);                        // On récupère la position actuelle du curseur
        mpos.y=480-mpos.y;
    
        // On fait un écran Ortho 2D pour le HUD
        glMatrixMode(GL_PROJECTION);                // On se met en PROJECTION 2D
        glLoadIdentity();                           // On initialise la matrice
        glOrtho(0,640,0,480,0.1,0.2);               // Fait un écran Ortho
        draw_main_menu();
     }

    if (map_menu)
     {
        glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);
        GetCursorPos(&mpos);                        // On récupère la position actuelle du curseur
        mpos.y=480-mpos.y;                          // Les coordonnées de la souris commencent en haut à gauche alors que l'affichage commence en bas à gauche
    
        // On fait un écran Ortho 2D pour le HUD
        glMatrixMode(GL_PROJECTION);                // On se met en PROJECTION 2D
        glLoadIdentity();                           // On initialise la matrice
        glOrtho(0,640,0,480,0.1,0.2);               // Fait un écran Ortho
        draw_map_menu();
     }

    if (graph_menu)
     {
        glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);
        GetCursorPos(&mpos);                        // On récupère la position actuelle du curseur
        mpos.y=480-mpos.y;                          // Les coordonnées de la souris commencent en haut à gauche alors que l'affichage commence en bas à gauche
    
        // On fait un écran Ortho 2D pour le HUD
        glMatrixMode(GL_PROJECTION);                // On se met en PROJECTION 2D
        glLoadIdentity();                           // On initialise la matrice
        glOrtho(0,640,0,480,0.1,0.2);               // Fait un écran Ortho
        draw_graph_menu();
     }

    // Mise à jour du temps
    temps.frame++;
    temps.frame_fps++;
    temps.ecart = (double)(( glutGet ( GLUT_ELAPSED_TIME ) - temps.tps - 0.0001) / 1000);
    temps.tps = glutGet ( GLUT_ELAPSED_TIME );

    arc_en_ciel+= 100*temps.ecart;                  // Pour la couleur arc-en-ciel
    fps ( );                                        // Calcul des FPS
    glutSwapBuffers();                              // Vide le buffer
    glutPostRedisplay();                            // Redessine la scène
 }

//------------------------------------------------------------------------------
// Fonction principale, lancée une seule fois
//------------------------------------------------------------------------------

int    main( int argc, char *argv[ ], char *envp[ ] )
 {
    // Initialise l'affichage
    glutInit(&argc,argv);                           // Initialise GLUT
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); // Précise le mode de rendu
    Enable_GameMode();                              // GameMode - ON/OFF
    glutReshapeFunc(Reshape);                       // Fonction pour l'affichage
    glutDisplayFunc(Draw);                          // Fonction pour création ou redimensionnement de fenêtre
    InitGL();                                       // initialisation de l'affichage et des fonctions OpenGL

    // Chargement des textures
    LoadTGA("textures/crosshairj.tga", 1);          // Crosshair
    LoadTGA("textures/sky.tga", 2);                 // Ciel
    LoadTGA("textures/mur2.tga", 3);                // Grilles transparentes
    LoadTGA("textures/explode.tga", 4);             // Fumée du ShotGun
    LoadTGA("textures/shotgun.tga", 5);             // ShotGun
    LoadTGA("textures/soleil.tga", 6);              // Soleil
    LoadTGA("textures/font.tga", 9);                // Police de caractèress
    LoadTGA("textures/cube-tex-2.tga", 11);           // Logo pour la console
    LoadBMP("textures/mur.bmp", 12);                // Mur sur 3 faces
    LoadBMP("textures/sol.bmp", 13);                // Sol
    LoadBMP("textures/mapbelzel.bmp", 14);          // Map
    LoadBMP("textures/maplab.bmp", 15);             // Map
    LoadBMP("textures/mapjail.bmp", 16);            // Map
    LoadBMP("textures/mapmrboom.bmp", 17);          // Map

    LoadBMP("textures/1.bmp", 21);                  // Map
    LoadBMP("textures/2.bmp", 22);                  // Map
    LoadBMP("textures/3.bmp", 23);                  // Map
    LoadBMP("textures/4.bmp", 24);                  // Map
    LoadBMP("textures/5.bmp", 25);                  // Map
    LoadBMP("textures/6.bmp", 26);                  // Map

    // Initialise les fonctions diverses
    glutKeyboardFunc(GestionClavier);               // Détecte les touches normales appuyées
    glutSpecialFunc(GestionSpecial);                // Détecte les touches spéciales appuyées
    glutMouseFunc(SourisTir);                       // Permet le tir à la souris
    glutKeyboardUpFunc(KeyN_up);                    // Détecte une touche relachée et la désactive si nécessaire
    glutIdleFunc(ClavierBouge);                     // Lance cette fonction non GLUT à chaque fois, elle sert aux déplacements
    BuildFont();                                    // Création de la police
    PlaySound("sons/fight.wav",NULL,SND_ASYNC);     // Fight
    glutMainLoop();                                 // Boucle infinie
    
    return 0;
 }

//------------------------------------------------------------------------------
// Fin Du Fichier
//------------------------------------------------------------------------------