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

    #ifdef __WIN32__
    #include <windows.h>                        // Header pour les Applications Windows
    #endif
    #include <GL/glut.h>
    #include <stdio.h>

//------------------------------------------------------------------------------
// Constantes & Variable
//------------------------------------------------------------------------------
    
    #define EXIT        {fclose(fichier); return -1;}
    #define CTOI(C)     (*(int*)&C)
        
    GLuint  TexNum[1];
 
//------------------------------------------------------------------------------
// Charge une image BMP 24 bits
//------------------------------------------------------------------------------

int LoadBMP(char *filename, int nb)
 {
    GLubyte     *image;
    GLubyte     Header[0x36];
    GLuint      DataPos, imageSize;
    GLsizei     Width,Height;
    int         i;
    
    // Lit le fichier et son header
    FILE * fichier = fopen(filename,"rb");
    if (!fichier) return -1;
    if (fread(Header,1,0x36,fichier)!=0x36) EXIT;
    if (Header[0]!='B' || Header[1]!='M')   EXIT;
    if (CTOI(Header[0x1E])!=0)              EXIT;
    if (CTOI(Header[0x1C])!=24)             EXIT;
    
    // Récupère les infos de l'image
    Width   = CTOI(Header[0x12]);
    Height  = CTOI(Header[0x16]);
    ( CTOI(Header[0x0A]) == 0 ) ? ( DataPos=0x36 ) : ( DataPos = CTOI(Header[0x0A]) );
    ( CTOI(Header[0x22]) == 0 ) ? ( imageSize=Width*Height*3 ) : ( DataPos = CTOI(Header[0x22]) );        

    // Charge l'image
    image = (GLubyte *) malloc ( imageSize );
    if (fread(image,1,imageSize,fichier)!=imageSize) 
     {
        free (image);
        EXIT;
     }

    // Inverse R et B
    for ( i = 0; i < imageSize; i += 3 )
     {
        int t = image[i];
        image[i] = image[i+2];
        image[i+2] = t;
     }

    // Traitements de la texture par OpenGL
    glPixelStorei(GL_UNPACK_ALIGNMENT,1);        // Construit la texture sous forme de données
    glGenTextures(nb, &TexNum[nb]);              // Génère une ID pour la texture OpenGL                                             
    
    glBindTexture(GL_TEXTURE_2D, TexNum[nb]);    // Pointe la texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

    // Génère la texture OpenGL en mémoire
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Width, Height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

    fclose (fichier);
    free (image);
    return TexNum[nb];
 }

//------------------------------------------------------------------------------
// Redimensionnement
//------------------------------------------------------------------------------

void    ReshapeGL ( int Width, int Height )
 {
    glViewport ( 0, 0, Width, Height );
    glMatrixMode ( GL_PROJECTION );
    glLoadIdentity ( );
    gluPerspective ( 45, (float)Width/(float)Height, 1, 100 );
    glMatrixMode ( GL_MODELVIEW );
    glLoadIdentity ( );
 }

//------------------------------------------------------------------------------
// Initialisation
//------------------------------------------------------------------------------

void    InitGL ( )
 {
    glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );        // Black Background
    glClearDepth(1.0f);                             // Configuration de la profondeur du buffer
    glEnable ( GL_TEXTURE_2D );
 }

//------------------------------------------------------------------------------
// Dessin
//------------------------------------------------------------------------------

void    DrawGL ( )
 {
    static int angle=0;

    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Efface les buffers
    glLoadIdentity ( );        
    
    gluLookAt ( 0, 0, -15, 0, 0, 0, 0, 1, 0 );
    glRotated ( angle++, 1, 2, 3);

    glBindTexture ( GL_TEXTURE_2D, TexNum[0] );
    glBegin ( GL_QUADS );
        glTexCoord2d ( 0, 0 ); glVertex2f (  5, -5);
        glTexCoord2d ( 0, 1 ); glVertex2f (  5,  5);
        glTexCoord2d ( 1, 1 ); glVertex2f ( -5,  5);
        glTexCoord2d ( 1, 0 ); glVertex2f ( -5, -5);
    glEnd ( );
  
    glutSwapBuffers ( );                           // Dessine la frame à l'écran
    glutPostRedisplay ( );                         // Redémarre DrawGL
 }

//------------------------------------------------------------------------------
// Fonction principale
//------------------------------------------------------------------------------

int main( int argc, char *argv[ ], char *envp[ ] )
 {
    // Création de la fenêtre
    glutInit ( &argc, argv );
    glutInitDisplayMode ( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
    glutInitWindowSize ( 320, 240 );
    glutInitWindowPosition ( 50, 50 );
    glutCreateWindow ( "Load BMP" );
    InitGL ( );

    // Fichiers externes
    LoadBMP ( "tex.bmp", 0 );

    glutReshapeFunc ( ReshapeGL );
    glutDisplayFunc ( DrawGL );
    
    glutMainLoop ( );
    return 0;
 }

//------------------------------------------------------------------------------
// THE END
//------------------------------------------------------------------------------