//------------------------------------------------------------------------------
// README
//------------------------------------------------------------------------------
// Programme créer sur les bases de la leçon n°3 de NeHe (nehe.gamedev.net)
// pour la création de la fenêtre sans GLUT. D'où les commentaires en anglais.
//
// Il s'agit ici de s'amuser avec la hierarchie. Késako ? En fait, ce bras
// s'articule autour de différents axes. Il faut donc effectuer les rotations
// autour du bon axe. Les rotations sont bornées selon un certain angle.
//
// Les touches :
//  F1 : plein écran
//  F2-F3 : rotation de la 2è partie
//  F4-F5 : rotation de la 3è partie
//  F6-F7 : rotation de la main
//  Les flèches : ouverture et allongement de la main
//------------------------------------------------------------------------------


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

    #ifdef __WIN32__
        #include <windows.h>        // Header pour les Applications Windows
    #endif
    #include <gl\gl.h>              // Header OpenGL32
    #include <gl\glu.h>             // Header GLu32
    
    // définition d'un booléen
    #ifndef __cplusplus
        typedef int bool;
        #define false (1==2)
        #define true (1==1)
    #endif
    
//------------------------------------------------------------------------------
// Variables & Constantes
//------------------------------------------------------------------------------

    HDC         hDC=NULL;           // Private GDI Device Context
    HGLRC       hRC=NULL;           // Permanent Rendering Context
    HWND        hWnd=NULL;          // Holds Our Window Handle
    HINSTANCE   hInstance;          // Holds The Instance Of The Application

    bool    keys[256];              // Array Used For The Keyboard Routine
    bool    active=true;            // Window Active Flag Set To true By Default
    bool    fullscreen=true;        // Fullscreen Flag Set To Fullscreen Mode By Default

    // Rotation et translation des différents élements
    float Piston1Rot=0, Piston2Rot=0, Piston3Rot=0, Piston4Rot=0;
    float Piston3Trans=1, Piston4Trans=1, PinceRot=45;

    // Fonctions concernant la création de la fenêtre
    #include "hierarchie.h"

//------------------------------------------------------------------------------
// Fonction d'Initialisation
//------------------------------------------------------------------------------

int InitGL(GLvoid)                                        // All Setup For OpenGL Goes Here
{
    // -- Anti Aliasing
    glEnable (GL_LINE_SMOOTH);
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    glLineWidth (1.5);
    // -- Fin Anti Aliasing

    glShadeModel(GL_SMOOTH);                            // Enable Smooth Shading
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);                // Black Background
    glClearDepth(1.0f);                                    // Depth Buffer Setup
    glEnable(GL_DEPTH_TEST);                            // Enables Depth Testing
    glDepthFunc(GL_LEQUAL);                                // The Type Of Depth Testing To Do
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);    // Really Nice Perspective Calculations
    return true;                                        // Initialization Went OK
}

//------------------------------------------------------------------------------
// Affichage d'un cube
//------------------------------------------------------------------------------

void Cube ( float cote )
{
    // haut
    glBegin(GL_QUADS);
        glVertex3f( 0.0f, cote, 0.0f);
        glVertex3f( cote, cote, 0.0f);
        glVertex3f( cote, cote, -cote);
        glVertex3f( 0.0f, cote, -cote);
    glEnd();
    // bas
    glBegin(GL_QUADS);
        glVertex3f( 0.0f, 0.0f, 0.0f);
        glVertex3f( cote, 0.0f, 0.0f);
        glVertex3f( cote, 0.0f, -cote);
        glVertex3f( 0.0f, 0.0f, -cote);
    glEnd();
    // devant
    glBegin(GL_QUADS);
        glVertex3f(0.0f, 0.0f, 0.0f);
        glVertex3f(cote, 0.0f, 0.0f);
        glVertex3f(cote, cote, 0.0f);
        glVertex3f(0.0f, cote, 0.0f);
    glEnd();
    // derriere
    glBegin(GL_QUADS);
        glVertex3f(0.0f, 0.0f, -cote);
        glVertex3f(cote, 0.0f, -cote);
        glVertex3f(cote, cote, -cote);
        glVertex3f(0.0f, cote, -cote);
    glEnd();
    // gauche
    glBegin(GL_QUADS);
        glVertex3f( 0.0f, 0.0f, 0.0f);
        glVertex3f( 0.0f, cote, 0.0f);
        glVertex3f( 0.0f, cote, -cote);
        glVertex3f( 0.0f, 0.0f, -cote);
    glEnd();
    // droite
    glBegin(GL_QUADS);
        glVertex3f( cote, 0.0f, 0.0f);
        glVertex3f( cote, cote, 0.0f);
        glVertex3f( cote, cote, -cote);
        glVertex3f( cote, 0.0f, -cote);
    glEnd();
}

//------------------------------------------------------------------------------
// Fonction d'affichage
//------------------------------------------------------------------------------
// Translatef : translation
// Rotatef : rotation
// Scalef : mise à l'echelle (ici, rédution d'un cube sous forme rectangulaire)
// Push : sauvegarde de l'environnement (position, angles, repère, etc ...)
// Pop : restauration de l'environnement
//------------------------------------------------------------------------------

int DrawGLScene(GLvoid)                               
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef( -10.0f, -5.0f, -25.0f);                

//-------------- BRAS ( 1 )

    glColor3f( 1.0f, 0.0f, 0.0f);
    glTranslatef( 0.0f, 3.0f/2.0f,-3.0f/2.0f);    
    glRotatef ( 0, 0, 0, 1 );
    glTranslatef( 0.0f, -3.0f/2.0f,3.0f/2.0f);     
    Cube ( 3 );
    glTranslatef( 3.0f,0.0f,0.0f);                

//-------------- PISTON ( 1 )

    glPushMatrix();
    glTranslated ( 0.0f, 3.0f/4.0f, 0.0f);
    glScalef (0.5f, 0.5f, 0.5f);
    Cube ( 3 );
    glPopMatrix ( );
    glTranslatef ( 3.0f/2.0f, 0.0f, 0.0f );

//-------------- BRAS ( 2 )

    glColor3f( 0.0f, 1.0f, 0.0f);                

    glTranslatef( 0.0f, 3.0f/2.0f,-3.0f/2.0f);      
    glRotatef ( Piston1Rot, 0, 0, 1 );
    glTranslatef( 0.0f, -3.0f/2.0f,3.0f/2.0f);     
    Cube ( 3 );
    glTranslatef( 3.0f,0.0f,0.0f);            

//-------------- PISTON ( 2 )

    glPushMatrix();
    glTranslated ( 0.0f, 3.0f/4.0f, 0.0f);
    glScalef (0.5f, 0.5f, 0.5f);
    Cube ( 3 );
    glPopMatrix ( );
    glTranslatef ( 3.0f/2.0f, 0.0f, 0.0f );

//-------------- BRAS ( 3 )

    glColor3f( 0.0f, 0.0f, 1.0f);
    glTranslatef( 0.0f, 3.0f/2.0f,-3.0f/2.0f); 
    glRotatef ( Piston2Rot, 0, 0, 1 );
    glTranslatef( 0.0f, -3.0f/2.0f,3.0f/2.0f); 
    Cube ( 3 );
    glTranslatef( 3.0f,0.0f,0.0f);           
    
//-------------- PISTON ( 3 )

    glTranslated ( 0.0f, 1.5f, -1.5f);    
    glRotatef ( Piston3Rot, 1, 0, 0 );
    glTranslated ( 0.0f, -1.5f, 1.5f);    
    glPushMatrix ( );
    glTranslated ( 0.0f, 1.0f, -1.0f);
    glScalef ( Piston3Trans, 1, 1 );
    Cube ( 1 );
    glPopMatrix ( );
    glTranslatef ( Piston3Trans, 0.0f, 0.0f );    
    
//-------------- PISTON ( 4 )    

    glColor3f( 0.0f, 0.3f, 0.7f);
    glPushMatrix ( );    
    glTranslated ( 0.0f, 1.0f, -1.0f);    
    glScalef ( Piston3Trans, 1, 1 );
    Cube ( 1 );
    glPopMatrix ( );
    glTranslatef ( Piston3Trans, 1.0f, -1.0f );        
    
//-------------- PINCE ( 1 )

    glPushMatrix ( );
    glColor3f( 0.5f, 0.2f, 1.0f);
    glTranslatef ( 0.0f, 0.5f, 0.0f );    
    glRotatef ( PinceRot, 0, 0, 1);
    glTranslatef ( 0.0f, -0.5f, 0.0f );        
    glPushMatrix ( );
    glScalef ( 5.0f, 1, 1 );
    Cube (1);
    glPopMatrix ( );
    glTranslatef (5,0.5f,0);
    glRotatef ( -80, 0, 0, 1);
    glTranslatef ( 0.0f, -0.5f, 0.0f );        
    glScalef ( 5.0f, 1, 1 );    
    Cube (1);
    glPopMatrix ( );
    
//-------------- PINCE ( 2 )    

    glPushMatrix ( );
    glColor3f( 0.9f, 0.5f, 0.3f);
    glTranslatef ( 0.0f, 0.5f, 0.0f );
    glRotatef ( -PinceRot, 0, 0, 1);
    glTranslatef ( 0.0f, -0.5f, 0.0f );
    glPushMatrix ( );
    glScalef ( 5.0f, 1, 1 );
    Cube (1);
    glPopMatrix ( );
    glTranslated (5,0.5f,0);
    glRotatef ( 80, 0, 0, 1);
    glTranslatef ( 0.0f, -0.5f, 0.0f );        
    glScalef ( 5.0f, 1, 1 );    
    Cube (1);
    glPopMatrix ( );

    return true;
}



int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG     msg;                                // Windows Message Structure
    BOOL    done=false;                         // Bool Variable To Exit Loop

    if (MessageBox(NULL,"Passer en plein ecran (640x480) ?", "FullScreen ?",MB_YESNO|MB_ICONQUESTION)==IDNO) fullscreen=false;
    if (!CreateGLWindow("Hierarchie",640,480,16,fullscreen)) return 0;                                    // Quit If Window Was Not Created

    while(!done)                                // Loop That Runs While done=false
    {
        if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))// Is There A Message Waiting?
        {
            if (msg.message==WM_QUIT) done=true;
            else                                // If Not, Deal With Window Messages
            {
                TranslateMessage(&msg);         // Translate The Message
                DispatchMessage(&msg);          // Dispatch The Message
            }
        }
        else                                    // If There Are No Messages
        {
            // Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()
            if ((active && !DrawGLScene()) || keys[VK_ESCAPE]) done=true;                            // ESC or DrawGLScene Signalled A Quit
            else SwapBuffers(hDC);

            if (keys[VK_F1])                    // Is F1 Being Pressed?
            {
                keys[VK_F1]=false;              // If So Make Key false
                KillGLWindow();                 // Kill Our Current Window
                fullscreen=!fullscreen;         // Toggle Fullscreen / Windowed Mode
                if (!CreateGLWindow("Hierarchie",640,480,16,fullscreen)) return 0;
            }
            
            // NOS TOUCHES
            
            if (keys[VK_F2])
            {
                keys[VK_F2]=false;
                if (Piston1Rot<75) Piston1Rot++;
            }
            if (keys[VK_F3])
            {
                keys[VK_F3]=false;
                if (Piston1Rot>-75) Piston1Rot--;
            }
            if (keys[VK_F4])                       
            {
                keys[VK_F4]=false;                
                if (Piston2Rot<75) Piston2Rot++;
            }
            if (keys[VK_F5])              
            {
                keys[VK_F5]=false; 
                if (Piston2Rot>-75) Piston2Rot--;
            }
            if (keys[VK_F6])
            {
                keys[VK_F6]=false;
                if (Piston3Rot<75) Piston3Rot++;
            }
            if (keys[VK_F7])
            {
                keys[VK_F7]=false;
                if (Piston3Rot>-75) Piston3Rot--;
            }
            if (keys[VK_RIGHT])                
            {
                keys[VK_RIGHT]=false;
                if (Piston3Trans<8) Piston3Trans++;
                if (Piston4Trans<8) Piston4Trans++;
            }
            if (keys[VK_LEFT])
            {
                keys[VK_LEFT]=false;
                if (Piston3Trans>1) Piston3Trans--;
                if (Piston4Trans>1) Piston4Trans--;
            }
            if (keys[VK_UP])
            {
                keys[VK_UP]=false;
                if (PinceRot<90) PinceRot++;
            }
            if (keys[VK_DOWN])
            {
                keys[VK_DOWN]=false;
                if (PinceRot>45) PinceRot--;
            }
        }
    }

    // Shutdown
    KillGLWindow();                                     // Kill The Window
    return (msg.wParam);                                // Exit The Program
}

//------------------------------------------------------------------------------
//EOF
//------------------------------------------------------------------------------