/*

      ..:: Plugin Visuel Basique Pour Winamp en OpenGL ::..
        Code Réalisé Par BeLZeL (fini le 30 juillet 2002)
                  Sous Microsoft Visual C++ 5.0
    
    Site : http://headlines.fr.st
    Mail : belzel@free.fr

    Le Plugin dessine un Cube arc-en-ciel qui tourne en arrière-plan. Devant, deux
    lignes représentent les ondes du canal gauche et droit de la musique. Le Plugin
    affiche aussi le nombre d'images par seconde dans le titre de la fenêtre. J'espère
    que ce petit code d'exemple (qui peut être assez dur à comprendre pour les
    débutants) pourra vous permettre de faire le meilleur plugin visuel du monde
    pour Winamp ;)

    Pour le Plugin, je suis parti du plugin visuel de base, fourni par Winamp :
     - http://ftp.winamp.com/winamp/nsdn/vis_minisdk.zip

    Je l'ai fusionné avec un programme OpenGL fait pour Win32. Informations et
    tutoriaux en français sur l'excellent site d'Antoche :
     - http://antoche.alrj.org/prog/opengl/OpenGLII/OpenGLII.htm
     - http://antoche.alrj.org/prog/opengl/OpenGLII/OpenGLIIbis.htm

    Project / Settings
     - Links : OpenGL32.lib GLu32.lib GLaux.lib kernel32.lib user32.lib gdi32.lib 
     - Output Filename : c:/répertoire/de/winamp/plugins/vis_test.dll

    Fichiers :
     - svis.c : fichiers source modifié
     - vis.h  : header non modifié (mais modifiable :), fourni par Winamp.

    Notes : Le projet doit être compilable sous Dev-C++ mais j'ai eu trop de problèmes
    de compilations bizarres. Parfois, il fallait redémarrer le logiciel pour
    qu'il compile la DLL.

*/

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

    #include <windows.h>          // on est bien sous Windows, je vous le confirme           
    #include <gl/glut.h>           // on travaille aussi avec OpenGL
    #include <stdio.h>            // nécessaire juste pour "sprintf"
    #include <math.h>             // pour les cos et autres sin
    #include <time.h>             // pour le calcul du nombre d'images par seconde
    #include "vis.h"              // notre petit header préféré

//------------------------------------------------------------------------------
// Fonctions & Procédures
//------------------------------------------------------------------------------

    // WINAMP
    winampVisModule *getModule(int which);               // quel module ?
    void    ConfigMod(struct winampVisModule *this_mod); // quelle config ?
    int     InitMod(struct winampVisModule *this_mod);   // classe et fenêtre
    int     RenderMod(struct winampVisModule *this_mod); // le rendu
    void    QuitMod(struct winampVisModule *this_mod);   // la fin
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

    // OpenGL
    void    SetupPixelFormat(HDC hDC);                // Format Des Pixels
    void    Reshape(int width, int height);           // Redimensionnement    
    void    InitGL();                                 // Initialisation d'OpenGL

    // Autres    
    bool    AnimateNextFrame(int desiredFrameRate);
    void    BuildFont(LPSTR nom, int hauteur);
    void    CreateRenderTexture(UINT textureArray[], int size, int channels, int type, int textureID);
    void    DrawMB(struct winampVisModule *this_mod);
    void    DrawNMB(struct winampVisModule *this_mod);
    void    glPrint(const char *fmt, ...);
    void    RenderMotionBlur(int textureID);

//------------------------------------------------------------------------------
// Variables & Constantes
//------------------------------------------------------------------------------

    // couleur arc-en-ciel
    #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)));
    float   arc_en_ciel = 0.0f;

    // pour les FPS
    double  frame=0;

    // pour la rotation du cube
    #define PI  3.1415926535897932384626433832795f // PI pour les angles
    double  a = 0;    

    // pour l'écriture    
    #define FONT_HEIGHT	24
    UINT    base;                // Base Display List For The Font Set
    float   cnt1;                // 1st Counter Used To Move Text & For Coloring
    float   cnt2;                // 2nd Counter Used To Move Text & For Coloring

    // pour la fenêtre
    HWND    hMainWnd;                  // Handle (numéro) de la fenêtre
    char    szAppName[] = "BeLZeLVis"; // Nom de notre classe
    int     ORIGINX=50;                // origine en X
    int     ORIGINY=50;                // origine en Y
    int     WIDTH=800;                 // largeur de la fenêtre
    int     HEIGHT=600;                // hauteur de la fenêtre
    HDC     DC;                        // Device Context
    HGLRC   RC;                        // Rendering Context

    // pour le motion blur
    UINT    g_Texture[2];
    int     g_Viewport = 0;
    int     g_BlurRate = 50;
    int     n=0;

    // constantes et variables WINAMP
    #define WM_WA_IPC            WM_USER
    #define IPC_GETOUTPUTTIME    105  // position et durée d'une musique
    #define IPC_GETLISTPOS       125  // position dans la playlist
    #define IPC_GETPLAYLISTTITLE 212  // titre de la musique
    int     Winamp_Pos;               // position
    int     Winamp_Max;               // durée
    int     Winamp_Num;               // numéro
    char    Winamp_Titre[255];        // titre
    char    *Winamp_Titre2;           // titre tampon (tmp)
    int     load=0;

    // pour Winamp (Nom du Plugin et Nom du Module)
    winampVisHeader hdr = { VIS_HDRVER, "Le Cube A BeLZeL", getModule };
    winampVisModule mod1 = { "Cube",
                             NULL,    // hwndParent
                             NULL,    // hDllInstance
                             2,       // sRate
                             2,       // nCh
                             25,      // latencyMS
                             25,      // delayMS
                             2,       // spectrumNch
                             2,       // waveformNch
                             { 0, },  // spectrumData
                             { 0, },  // waveformData
                             ConfigMod,
                             InitMod,
                             RenderMod,
                             QuitMod };

//------------------------------------------------------------------------------
// DLL
//------------------------------------------------------------------------------

    #ifdef __cplusplus
        extern "C" {
    #endif
    __declspec( dllexport ) winampVisHeader *winampVisGetHeader() { return &hdr; }
    #ifdef __cplusplus
        }
    #endif

//------------------------------------------------------------------------------
// Peut-on afficher la frame suivante ? Et on calcule/affiche le nombre de FPS
//------------------------------------------------------------------------------

bool AnimateNextFrame(int desiredFrameRate)
{
    static  float   lastTime = 0.0f;               // dernier temps récupéré
    char    title[255];        // titre de la fenêtre
    float   float_fps=0;       // nombre de FPS
    float   currentTime = GetTickCount() * 0.001f; // temps actuel en ms
    float   elapsedTime = currentTime - lastTime;  // temps écoulé

    // on vérifie si on peut animer la prochaine frame (1 seconde / FPS)
    if( elapsedTime > (1.0f / desiredFrameRate) )
    {
        float_fps = (float)frame/(float)(currentTime-lastTime);  // calcul des FPS
        frame = 0;
        lastTime = currentTime;
        sprintf(title,"Le Cube A BeLZeL - %4.2f FPS", float_fps);
        SetWindowText(hMainWnd, title);
        return true;
    }
    return false;               // on anime pas encore
}

//------------------------------------------------------------------------------
// Création de la Police de Caractères
//------------------------------------------------------------------------------

void BuildFont(LPSTR nom, int hauteur)                                // Build Our Bitmap Font
{
    HFONT    font;                                       // Windows Font ID
    HFONT    oldfont;                                    // Used For Good House Keeping

    base = glGenLists(96);                               // Storage For 96 Characters

    font = CreateFont( hauteur,                          // Height Of Font
                       0,                                // Width Of Font
                       0,                                // Angle Of Escapement
                       0,                                // Orientation Angle
                       FW_BOLD,                          // Font Weight
                       FALSE,                            // Italic
                       FALSE,                            // Underline
                       FALSE,                            // Strikeout
                       ANSI_CHARSET,                     // Character Set Identifier
                       OUT_TT_PRECIS,                    // Output Precision
                       CLIP_DEFAULT_PRECIS,              // Clipping Precision
                       ANTIALIASED_QUALITY,              // Output Quality
                       FF_DONTCARE|DEFAULT_PITCH,        // Family And Pitch
                       nom );                            // Font Name

    oldfont = (HFONT)SelectObject(DC, font);             // Selects The Font We Want
    wglUseFontBitmaps(DC, 32, 96, base);                 // Builds 96 Characters Starting At Character 32
    SelectObject(DC, oldfont);                           // Selects The Font We Want
    DeleteObject(font);                                  // Delete The Font
}

//------------------------------------------------------------------------------
// ConfigMod : que ce passe-t-il quand on appuie sur le bouton "config" de Winamp
//------------------------------------------------------------------------------

void ConfigMod(struct winampVisModule *this_mod)
{
    MessageBox(this_mod->hwndParent,"Un tit Cube qui tourne en OpenGL.\n"
                "Exemple Basique d'un Plugin visuel pour Winamp.\n\n"
                "   Par BeLZeL © 29/07/2k2",
                "Le Cube A BeLZeL (30/07/2k2)",MB_OK);
}

//------------------------------------------------------------------------------
// Crée une texture vide
//------------------------------------------------------------------------------
    
void CreateRenderTexture(UINT textureArray[], int size, int channels, int type, int textureID)
{
    unsigned int *pTexture = NULL;  // crée un pointeur

    // Alloue de la mémoire et initialise la mémoire
    pTexture = new unsigned int [size * size * channels];
    memset(pTexture, 0, size * size * channels * sizeof(unsigned int));    

    // Enregistre la texture dans OpenGL
    glGenTextures(1, &textureArray[textureID]);            
    glBindTexture(GL_TEXTURE_2D, textureArray[textureID]);
    glTexImage2D(GL_TEXTURE_2D, 0, channels, size, size, 0, type, GL_UNSIGNED_INT, pTexture);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

    // Since we stored the texture space with OpenGL, we can delete the image data
    delete [] pTexture;    
}

//------------------------------------------------------------------------------
// DrawMB : Dessine ce qui est nécessaire, avec Motion Blur
//------------------------------------------------------------------------------

void DrawMB(struct winampVisModule *this_mod)
{  
    int x, y;
    float bass=0, aigu=0;

    glDisable(GL_TEXTURE_2D);
    glEnable(GL_COLOR);

    // CALCUL DES BASSES
    for (y=0;y<this_mod->nCh;y++)                  // il n'y a que 2 canaux ("y" va de 0 à 1)
        for (x=0;x<20;x++)                        // il y a 576 données par canaux        
            bass += this_mod->spectrumData[y][x];
    bass /= (float)(1000*y);         // moyenne
    if (bass < 0.05) bass = 0.05;    

    // CALCUL DES AIGUES
    for (y=0;y<this_mod->nCh;y++)                  // il n'y a que 2 canaux ("y" va de 0 à 1)
        for (x=100;x<150;x++)                     // il y a 576 données par canaux        
            aigu += this_mod->spectrumData[y][x];
    aigu /= (float)(5*y);        // moyenne

    a+=aigu + 2;                                       // ajout

    glTranslated(-5*cos(a/(float)(45*PI)),-4*sin(a/(float)(45*PI)),10);
    glRotated(a, 1, 2, 3);

    // LE CUBE
    glBegin(GL_LINE_STRIP);
    //glBegin(GL_LINES);
    //glBegin(GL_QUADS);
      // derrière
      glColor3f(0,0,0); glVertex3f(-bass,bass,-bass);
      glColor3f(1,0,0); glVertex3f(bass,bass,-bass);
      glColor3f(1,1,0); glVertex3f(bass,-bass,-bass);
      glColor3f(0,1,0); glVertex3f(-bass,-bass,-bass);
      // devant
      glColor3f(0,0,1); glVertex3f(-bass,bass,bass);
      glColor3f(1,0,1); glVertex3f(bass,bass,bass);
      glColor3f(1,1,1); glVertex3f(bass,-bass,bass);
      glColor3f(0,1,1); glVertex3f(-bass,-bass,bass);
      // gauche
      glColor3f(0,0,0); glVertex3f(-bass,bass,-bass);
      glColor3f(0,1,0); glVertex3f(-bass,-bass,-bass);
      glColor3f(0,1,1); glVertex3f(-bass,-bass,bass);
      glColor3f(0,0,1); glVertex3f(-bass,bass,bass);
      // droite
      glColor3f(1,0,0); glVertex3f(bass,bass,-bass);
      glColor3f(1,1,0); glVertex3f(bass,-bass,-bass);
      glColor3f(1,1,1); glVertex3f(bass,-bass,bass);
      glColor3f(1,0,1); glVertex3f(bass,bass,bass);
      // haut
      glColor3f(0,0,0); glVertex3f(-bass,bass,-bass);
      glColor3f(1,0,0); glVertex3f(bass,bass,-bass);
      glColor3f(1,0,1); glVertex3f(bass,bass,bass);
      glColor3f(0,0,1); glVertex3f(-bass,bass,bass);
      // bas
      glColor3f(0,1,0); glVertex3f(-bass,-bass,-bass);
      glColor3f(1,1,0); glVertex3f(bass,-bass,-bass);
      glColor3f(1,1,1); glVertex3f(bass,-bass,bass);
      glColor3f(0,1,1); glVertex3f(-bass,-bass,bass);
    glEnd();

    // PASSAGE EN ORTHO 2D
    glMatrixMode(GL_PROJECTION);            // On se met en PROJECTION 2D
    glLoadIdentity();                       // On initialise la matrice    
    glOrtho(0,WIDTH,0,HEIGHT,0,0.1);        // Fait un écran Ortho, 0-0 en bas à gauche
    glMatrixMode(GL_MODELVIEW);             // On se met en MODELVIEW 3D
    glLoadIdentity();                       // On initialise

    COLOR_ARC_EN_CIEL;
    // LES LIGNES (composées de points)    
    glBegin(GL_POINTS);    
    for (x=0;x<576;x++)                 // il y a 576 données par canaux
        for (y=0;y<this_mod->nCh;y++)           // il n'y a que 2 canaux ("y" va de 0 à 1)
            glVertex3f(x*WIDTH/(float)576,(HEIGHT*0.001*(this_mod->waveformData[y][x]^128) + (0.5*y*HEIGHT) + HEIGHT*0.1),0);
    glEnd();

    // LES BARRES
    glBegin(GL_LINES);    
    for (y=0; y<this_mod->nCh;y++)
    {
        for (x=0;x<100;x++)
        {
            if (y == 0) bass = this_mod->spectrumData[y][x];
            else        bass = -(this_mod->spectrumData[y][x]);
            glColor3d(0,0,0);  glVertex3f(x*WIDTH/(float)100, 0+(HEIGHT*y),   0);
            glColor4f(x/(float)100, fabs(bass)/(float)100, this_mod->nCh*0.5, 0.6);
            glVertex3f(x*WIDTH/(float)100, 0.5*bass+(HEIGHT*y),0);            
        }
    }
    glEnd();

    // LE CERCLE
    glBegin(GL_POINTS);    
    for (y=0;y<this_mod->nCh;y+=2)           // il n'y a que 2 canaux ("y" va de 0 à 1)
        for (x=0;x<576;x++)                 // il y a 576 données par canaux        
        {
            glColor3f(1.0f*float(cos(cnt2)),1.0f*float(sin(cnt1)),1.0f-0.5f*float(cos(cnt1+cnt2)));
            glVertex3f(0.5*((this_mod->waveformData[y][x]^128)+20)*sin(x*360/(float)576)+WIDTH*0.5,
                       0.5*((this_mod->waveformData[y][x]^128)+20)*cos(x*360/(float)576)+HEIGHT*0.5,
                       0);
        }
    glEnd();

    glDisable(GL_COLOR);
    glEnable(GL_TEXTURE_2D);
    glColor3d(1,1,1);
}

//------------------------------------------------------------------------------
// DrawNMB : Dessine ce qui est nécessaire, sans Motion Blur
//------------------------------------------------------------------------------

void DrawNMB(struct winampVisModule *this_mod)
{  
    glEnable(GL_COLOR);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);

    // TITRE DE LA CHANSON
    glColor4f(1.0f*float(cos(cnt1)),1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2)), 0.8);
    glRasterPos2f(20,20);
    glPrint("%s", Winamp_Titre);
    cnt1+=0.051f;                                        // Increase The First Counter
    cnt2+=0.005f;                                        // Increase The First Counter
   
    // BARRE DE PROGRESSION
    glColor4f(0.2,0.6,0.9,0.5);

    glBegin(GL_QUADS);
        glVertex2d( 0, 0 );
        glVertex2d( 0.001*Winamp_Pos*WIDTH/(float)Winamp_Max, 0 );
        glVertex2d( 0.001*Winamp_Pos*WIDTH/(float)Winamp_Max, 15 );
        glVertex2d( 0, 15 );
    glEnd();

    glDisable(GL_COLOR);
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glColor3d(1,1,1);
}

//------------------------------------------------------------------------------
// GetModule : quel module est choisi depuis Winamp
//------------------------------------------------------------------------------

winampVisModule *getModule(int which)
{
    switch (which)
    {
        case 0: return &mod1;
        default:return NULL;
    }
}

//------------------------------------------------------------------------------
// InitMod : Classes enregistrées, création de la fenêtre, etc ...
//------------------------------------------------------------------------------

int InitMod(struct winampVisModule *this_mod)
{
    // Notre Classe    
    WNDCLASS wc;
    memset(&wc,0,sizeof(wc));
    wc.lpfnWndProc = WndProc;                // our window procedure
    wc.hInstance = this_mod->hDllInstance;   // hInstance of DLL
    wc.lpszClassName = szAppName;            // our window class name    
    if (!RegisterClass(&wc)) 
     {
        MessageBox(this_mod->hwndParent,"Erreur lors de l'enregistrement de la classe de la fenêtre","Attention !",MB_OK);
        return 1;
     }

    // Notre fenêtre
    hMainWnd = CreateWindowEx( WS_EX_TOOLWINDOW|WS_EX_APPWINDOW, // these exstyles put a nice small frame, 
                                                                 // but also a button in the taskbar
                               szAppName,                        // our window class name
                               this_mod->description,            // use description for a window title
                               WS_VISIBLE|WS_SYSMENU,            // make the window visible with a close button
                               ORIGINX,ORIGINY,                  // screen position (read from config)
                               WIDTH,HEIGHT,                     // width & height of window (need to adjust client area later)
                               this_mod->hwndParent,             // parent window (winamp main window)
                               NULL,                             // no menu
                               this_mod->hDllInstance,           // hInstance of DLL
                               0);                               // no window creation data
    if (!hMainWnd) 
     {
        MessageBox(this_mod->hwndParent,"Erreur lors de la création de la fenêtre","Attention !",MB_OK);
        return 1;
     }

    return 0;
}

//------------------------------------------------------------------------------
// Affichage d'un texte à l'écran
//------------------------------------------------------------------------------

void glPrint(const char *fmt, ...)
{
    char    text[256];                                 // Holds Our String
    va_list ap;                                        // Pointer To List Of Arguments

    if (fmt == NULL) return;                           // If There's No Text Do Nothing                                                       

    va_start(ap, fmt);                                 // Parses The String For Variables
        vsprintf(text, fmt, ap);                       // And Converts Symbols To Actual Numbers
    va_end(ap);                                        // Results Are Stored In Text

    glPushAttrib(GL_LIST_BIT);                         // Pushes The Display List Bits
    glListBase(base - 32);                             // Sets The Base Character to 32
    glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws The Display List Text
    glPopAttrib();                                     // Pops The Display List Bits
}

//------------------------------------------------------------------------------
// Initialisation d'OpenGL
//------------------------------------------------------------------------------

void    InitGL()
 {    
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);           // Arrière Plan Noir
    glClearDepth(1.0f);         // Configuration de la profondeur du buffer

    Reshape(WIDTH, HEIGHT);
    
    glDepthFunc(GL_LEQUAL);    
    glEnable(GL_DEPTH_TEST);    // Test sur la profondeur (évite des bugs)

    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDisable(GL_BLEND);

    glEnable(GL_TEXTURE_2D);    // Enable Texture Mapping    
    
    glShadeModel(GL_SMOOTH);    // Smooth Shading Activé, il doit lisser les formes (?)
    glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);

    glPointSize(2);             // taille des points en pixels
    glLineWidth(6);

    CreateRenderTexture(g_Texture, 512, 3, GL_RGB, 0);
    BuildFont("Courier New", FONT_HEIGHT);
    glEnable(GL_COLOR);

    while ((pow(2,n) <= WIDTH) && (pow(2,n) <= HEIGHT)) n++;
    g_Viewport = pow(2,n-1);
 }

//------------------------------------------------------------------------------
// QuitMod : heu ... lorsqu'on quitte
//------------------------------------------------------------------------------

void QuitMod(struct winampVisModule *this_mod)
{
    glDeleteLists(base, 96);
    DeleteObject(DC);
    DestroyWindow(hMainWnd); // delete our window
    UnregisterClass(szAppName,this_mod->hDllInstance); // unregister window class
}

//------------------------------------------------------------------------------
// RenderMod : Notre rendu de la fenêtre
//------------------------------------------------------------------------------

int RenderMod(struct winampVisModule *this_mod)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // Clear The Screen And The Depth Buffer
    Reshape(WIDTH, HEIGHT);

    arc_en_ciel++;         // Pour la couleur arc-en-ciel
    frame++;

    gluLookAt(0,0,-10,0,0,0,0,1,0);

    Winamp_Pos = SendMessage(this_mod->hwndParent,WM_WA_IPC,0,IPC_GETOUTPUTTIME);
    // load = 0 -> lancement du plugin / chargement demandé -> passage à 2
    // load = 1 -> nouvelle musique / chargement demandé -> passage à 3
    // load = 2 -> attente d'une nouvelle musique / pas de chargement
    // load = 3 -> passage à 2
    if (load == 3) load = 2;
    if ((Winamp_Pos < 1000) && (load != 3)) load = 1;    
    if (load <= 1)
    {
        load+=2;
        Winamp_Max = SendMessage(this_mod->hwndParent,WM_WA_IPC,1,IPC_GETOUTPUTTIME);
        Winamp_Num = SendMessage(this_mod->hwndParent,WM_WA_IPC,0,IPC_GETLISTPOS);    
        Winamp_Titre2 = (char *)SendMessage(this_mod->hwndParent,WM_WA_IPC,Winamp_Num,IPC_GETPLAYLISTTITLE);
        strcpy(Winamp_Titre, Winamp_Titre2);        
    }
        
    if( AnimateNextFrame(g_BlurRate) )
    {        
        glViewport(0, 0, g_Viewport, g_Viewport);
        RenderMotionBlur(0);
        DrawMB(this_mod);
        
        glBindTexture(GL_TEXTURE_2D,g_Texture[0]);
        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, g_Viewport, g_Viewport, 0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glViewport(0, 0, WIDTH, HEIGHT);
    }

    RenderMotionBlur(0);
    DrawNMB(this_mod);

        

    SwapBuffers(DC); 
    return 0;
}

//------------------------------------------------------------------------------
// Rendu du Motion Blur
//------------------------------------------------------------------------------

void RenderMotionBlur(int textureID)
{
    int add=-10;

    glPushMatrix();        

    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);

    glBindTexture(GL_TEXTURE_2D, g_Texture[textureID]);            
    glColor4f(1, 1, 1, 0.95f);

    // OrthoMode
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho( 0, WIDTH, HEIGHT, 0, 0, 1 );
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 1.0f); glVertex2f(-add, -add);
        glTexCoord2f(0.0f, 0.0f); glVertex2f(-add, HEIGHT+add);
        glTexCoord2f(1.0f, 0.0f); glVertex2f(WIDTH+add, HEIGHT+add);
        glTexCoord2f(1.0f, 1.0f); glVertex2f(WIDTH+add, -add);
    glEnd();
        
    // PerspectiveMode
    glMatrixMode( GL_PROJECTION );
    glPopMatrix();
    glMatrixMode( GL_MODELVIEW );

    glEnable(GL_DEPTH_TEST);    
    glDisable(GL_BLEND);        

    glPopMatrix();
}

//------------------------------------------------------------------------------
// Redimensionnement de la fenêtre
//------------------------------------------------------------------------------

void Reshape(int width, int height) 
{  
    if (height==0) height=1;

    glViewport(0,0,width,height); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity();  
    gluPerspective(45,(float)width/(float)height,0.5f,500);
    glMatrixMode(GL_MODELVIEW);        // Select The Modelview Matrix
    glLoadIdentity();                // Reset The Modelview Matrix

} 

//------------------------------------------------------------------------------
// Format Des Pixels
//------------------------------------------------------------------------------

void SetupPixelFormat(HDC hDC) 
{   
    PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // taille du descripteur de format 
                                  1,                    // version 
                                  PFD_SUPPORT_OPENGL |
                                  PFD_DRAW_TO_WINDOW |
                                  PFD_DOUBLEBUFFER,     // Propriétés 
                                  PFD_TYPE_RGBA,        // Mode de couleurs 
                                  16,                   // Bits de couleur 
                                  0, 0, 0, 0, 0, 0,     // Paramètres des couleurs 
                                  0,0,                  // Paramètres alpha 
                                  0,0, 0, 0, 0,         // Paramètres du buffer d'accumulation 
                                  32,                   // Bits de profondeur 
                                  0,                    // Bits du buffer stencil  
                                  0,                    // Nombre de buffers auxiliaires 
                                  0,                    // ignoré (obsolète) 
                                  0,                    // réservé 
                                  0,                    // ignoré (obsolète) 
                                  0,                    // Couleur de transparence 
                                  0 };                  // Ignoré (obsolète)     
  
    int pixelFormat = ChoosePixelFormat(hDC, &pfd);  

    // Vérifie si un PixelFormat existe et s'il peut l'appliquer
    if ((!pixelFormat) || (!SetPixelFormat(hDC, pixelFormat, &pfd)))
    {
        MessageBox ( WindowFromDC(hDC), "Mode graphique non supporté.", "Problème - 1", MB_ICONERROR | MB_OK );
        exit(1);
 
    }  
}   

//------------------------------------------------------------------------------
// WndProc : Interception des messages virtuels
//------------------------------------------------------------------------------

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_CREATE:
            DC=GetDC(hwnd);
            SetupPixelFormat(DC);
            RC = wglCreateContext(DC);
            if (!RC) SendMessage(hwnd,WM_CLOSE,0,0);
            wglMakeCurrent(DC, RC);
            InitGL();            
            return 0;

        case WM_DESTROY:
            wglMakeCurrent(NULL, NULL); 
            if (RC) wglDeleteContext(RC); 
            ReleaseDC(hwnd,DC);
            PostQuitMessage(0);
            return 0;

        case WM_KEYDOWN:
		    switch(wParam)
            {
			case VK_ESCAPE:
				PostQuitMessage(0);
                return 0;
/*
            case VK_SPACE:
                g_Viewport=pow(2,n);
                n++;
                return 0;*/
		    }
            return 0;
    }
    return DefWindowProc(hwnd,message,wParam,lParam);
}

//------------------------------------------------------------------------------
// Fin Du Programme (ouf !)
//------------------------------------------------------------------------------