3
votes

I am playing with OpenGL, trying to write a proof of concept for drawing a 2x2 quad textured with a 2x2 GL_RGB GL_FLOAT bitmap.

From my understanding; to accomplish this, I must

  1. enable 2d textures by calling glEnable(GL_TEXTURE_2D).
  2. fill the texture with pixel data by calling glTexture2D.
  3. set the glOrtho to match the window coordinate system (0, width, 0, height, -1, 1).

  4. call glGenTextures to get an identifier to uniquely identify my texture.

  5. select my texture by calling glBindTexture.
  6. set texture parameters by calling glTexParameteri.
  7. use glBegin(glEnd)/glDrawArrays with specified texture coordinates and verteces.

My attempt with glBegin looks like

#include <gl/glut.h>
#include <stdio.h>

const char *appTitle = "OpenGL Texture Experiment";

static GLfloat identity4f[] = {
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1
};

static GLfloat pixels[] = {
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    1, 1, 1
};

GLuint texid[] = {-1};

static inline void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0, 0, 0, 0);  

    glColor3f(0, 1, 0);

    glBindTexture(GL_TEXTURE_2D, texid[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBegin(GL_TRIANGLES);

    glTexCoord2f(0, 0);
    glVertex2f(0, 0);

    glTexCoord2f(0, 1);
    glVertex2f(0, 2);

    glTexCoord2f(1, 0);
    glVertex2f(2, 2);

    glTexCoord2f(1, 0);
    glVertex2f(2, 2);

    glTexCoord2f(1, 1);    
    glVertex2f(2, 0);

    glTexCoord2f(0, 0);
    glVertex2f(0, 0);

    glEnd();

    glutSwapBuffers();        
}

static inline void init()
{
    glEnable(GL_TEXTURE_2D);

    glGenTextures(1, texid);

    /* anonymous scope: set texture */
    {
        GLenum target = GL_TEXTURE_2D;
        GLint level = 0;
        GLint internalformat = GL_RGB;
        GLsizei width = 2;
        GLsizei height = 2;
        GLint border = 0;
        GLenum format = GL_RGB;
        GLenum type = GL_FLOAT;
        const GLvoid *data = pixels;

        glTexImage2D (
            target,
            level,
            internalformat,
            width,
            height,
            border,
            format,
            type,
            data
        );
    }
    printf("got texture #%d.\n", texid[0]);

    typedef struct {
        double x_left;
        double x_right;
        double y_bottom;
        double y_top;
        double z_near;
        double z_far;
    } glOrtho_arguments;


    const struct {
        GLint width;
        GLint height;
    } glutInfo = {
        glutGet(GLUT_WINDOW_WIDTH),
        glutGet(GLUT_WINDOW_HEIGHT)
    };

    glOrtho_arguments args;
    args.x_left = 0;
    args.x_right = glutInfo.width;
    args.y_bottom = glutInfo.height;
    args.y_top = 0;
    args.z_near = -1;
    args.z_far = 1;

    glClearColor(0, 0, 0, 0);
    glMatrixMode(GL_PROJECTION);
    glMultMatrixf(identity4f);        
    glOrtho (
        args.x_left, 
        args.x_right, 
        args.y_bottom, 
        args.y_top, 
        args.z_near, 
        args.z_far
    );
}

int main(int argc, char **argv)
{    
    glMatrixMode(GL_MODELVIEW);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(appTitle);
    init();    
    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

My attempt with glDrawArrays looks like:

#include <gl/glut.h>
#include <stdio.h>

const char *appTitle = "OpenGL Texture Experiment";

static GLfloat identity4f[] = {
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1
};

static GLfloat pixels[] = {
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    1, 1, 1
};

static GLfloat vertices[] = {
    0, 0, 0,
    0, 2, 0,
    2, 2, 0,
    2, 2, 0,
    2, 0, 0,
    0, 0, 0
};

static GLfloat colors[] = {
    0, 1, 0,
    0, 1, 0,
    0, 1, 0,
    0, 1, 0,
    0, 1, 0,
    0, 1, 0
};

static GLfloat coords[] = {
    0, 0, 0,
    0, 1, 0,
    1, 0, 0,
    1, 1, 0
};

GLuint texid[] = {-1};

static inline void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0, 0, 0, 0);  

    glColor3f(0, 1, 0);

    glBindTexture(GL_TEXTURE_2D, texid[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexCoordPointer(3, GL_FLOAT, 0, coords);
    glVertexPointer(3, GL_FLOAT, 0, vertices);
    glColorPointer(3, GL_FLOAT, 0, colors);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    glutSwapBuffers();        
}

static inline void init()
{
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glGenTextures(1, texid);

    /* set texture */
    {
        GLenum target = GL_TEXTURE_2D;
        GLint level = 0;
        GLint internalformat = GL_RGB;
        GLsizei width = 2;
        GLsizei height = 2;
        GLint border = 0;
        GLenum format = GL_RGB;
        GLenum type = GL_FLOAT;
        const GLvoid *data = pixels;

        glTexImage2D (
            target,
            level,
            internalformat,
            width,
            height,
            border,
            format,
            type,
            data
        );
    }
    printf("got texture #%d.\n", texid[0]);

    typedef struct {
        double x_left;
        double x_right;
        double y_bottom;
        double y_top;
        double z_near;
        double z_far;
    } glOrtho_arguments;

    const struct {
        GLint width;
        GLint height;
    } glutInfo = {
        glutGet(GLUT_WINDOW_WIDTH),
        glutGet(GLUT_WINDOW_HEIGHT)
    };

    glOrtho_arguments args;
    args.x_left = 0;
    args.x_right = glutInfo.width;
    args.y_bottom = glutInfo.height;
    args.y_top = 0;
    args.z_near = -1;
    args.z_far = 1;

    glClearColor(0, 0, 0, 0);
    glMatrixMode(GL_PROJECTION);
    glMultMatrixf(identity4f);        
    glOrtho (
        args.x_left, 
        args.x_right, 
        args.y_bottom, 
        args.y_top, 
        args.z_near, 
        args.z_far
    );
}

int main(int argc, char **argv)
{    
    glMatrixMode(GL_MODELVIEW);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(appTitle);
    init();    
    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

Here's an attempt to modify the working answer to use vertex arrays, it looks funny.

#include <GL/glut.h>
#include <stdio.h>

static GLfloat pixels[] =
{
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    1, 1, 1
};

GLuint texid[] = { -1 };

static inline void init()
{
    glEnable( GL_TEXTURE_2D );
    glGenTextures( 1, texid );
    glBindTexture( GL_TEXTURE_2D, texid[ 0 ] );
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

static inline void display()
{
    glClearColor( 0, 0, 0, 0 );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho(0, 5, 5, 0, -1, 1 );

    glColor3f( 1, 1, 1 );

    glBindTexture( GL_TEXTURE_2D, texid[ 0 ] );

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    GLfloat c[] = {
        0, 0, 0,
        1, 0, 0,
        1, 1, 0,
        0, 1, 0
    };

    glVertexPointer(3, GL_FLOAT, 0, c);
    glColorPointer(3, GL_FLOAT, 0, pixels);
    glTexCoordPointer(3, GL_FLOAT, 0, c);
    glDrawArrays(GL_QUADS, 0, 4);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glutSwapBuffers();
}

int main( int argc, char **argv )
{
    glMatrixMode( GL_MODELVIEW );
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
    glutInitWindowSize( 300, 300 );
    glutCreateWindow( "OpenGL Texture Experiment" );
    init();
    glutDisplayFunc( display );
    glutMainLoop();
    return 0;
}

The result only shows a green untextured 2x2 square; I want it to be a 2x2 square with

top 2 pixels being red, green, and bottom two being blue and white.

What am I doing wrong?

EDIT:

Here's a proof of concept for texturing triangles; I thought it would warp in some weird way but instead it behaves it works like this:

enter image description here

#include <gl/glut.h>

const char *appTitle = "OpenGL Basic Template";

static GLuint texid[] = {-1};

static GLfloat pixels[] = {
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    1, 1, 1
};

static inline void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor((float)0x55/0xff, (float)0x55/0xff, 1, 1);  

/**
    glBindTexture(GL_TEXTURE_2D, texid[0]);
    glBegin(GL_QUADS);
    glColor3f(1, 1, 1);
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(0, 1);
    glVertex2f(0, 1);
    glTexCoord2f(1, 1);
    glVertex2f(1, 1);
    glTexCoord2f(1, 0);
    glVertex2f(1, 0);
    glEnd();

*/

    glBindTexture(GL_TEXTURE_2D, texid[0]);
    glBegin(GL_TRIANGLES);
    glColor3f(1, 1, 1);
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(0, 1);
    glVertex2f(0, 1);
    glTexCoord2f(1, 1);
    glVertex2f(1, 1);
    glEnd();

    glPushMatrix();
    glTranslatef(-1, -1, 0);
    glBegin(GL_TRIANGLES);
    glColor3f(1, 1, 1);
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(1, 1);
    glVertex2f(1, 1);
    glTexCoord2f(1, 0);
    glVertex2f(1, 0);
    glEnd();
    glPopMatrix();



    glColor3f(0, 0, 0);
    glLineWidth(1.0);
    glBegin(GL_LINES);
    glVertex2f(0, 0);
    glVertex2f(0, 1);
    glVertex2f(0, 1);
    glVertex2f(1, 1);
    glVertex2f(1, 1);
    glVertex2f(0, 0);
    glEnd();

    glPushMatrix();
    glTranslatef(-1, -1, 0);
    glBegin(GL_LINES);
    glVertex2f(0, 0);
    glVertex2f(1, 1);
    glVertex2f(1, 1);
    glVertex2f(1, 0);
    glVertex2f(1, 0);
    glVertex2f(0, 0);
    glEnd();
    glPopMatrix();

    glutSwapBuffers();
}

static inline void init()
{
    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, texid);
    glBindTexture(GL_TEXTURE_2D, texid[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);    

    // | there is no overhead for using this
    // | but it makes it much more explicit what the values
    // | mean!
    typedef struct {
        double x_left;
        double x_right;
        double y_bottom;
        double y_top;
        double z_near;
        double z_far;
    } glOrtho_arguments;

    glOrtho_arguments args;
    args.x_left = -1;
    args.x_right = 1;
    args.y_bottom = -1;
    args.y_top = 1;
    args.z_near = -1;
    args.z_far = 1;

    glClearColor(0, 0, 0, 0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();        
    glOrtho (
        args.x_left, 
        args.x_right, 
        args.y_bottom, 
        args.y_top, 
        args.z_near, 
        args.z_far
    );
}

int main(int argc, char **argv)
{    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(appTitle);
    init();    
    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

EDIT2:

ok I got it working; here's version using quads:

#include <gl/glut.h>
#include <stdio.h>

const char *appTitle = "OpenGL Texture Experiment";

static GLfloat identity4f[] = {
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1
};

static GLfloat pixels[] = {
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    1, 1, 1
};

static GLfloat vertices[] = {
    0, 0, 
    0, 2, 
    2, 2, 
    2, 0, 
};

static GLfloat coords[] = {
    0, 0,
    1, 0,
    1, 1,
    0, 1
};

GLuint texid[] = {-1};

static inline void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor((float)81/255, (float)81/255, 1, 1);  

    glColor3f(1, 1, 1);

    glBindTexture(GL_TEXTURE_2D, texid[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexCoordPointer(2, GL_FLOAT, 0, coords);
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glDrawArrays(GL_QUADS, 0, 4);

    glutSwapBuffers();        
}

static inline void init()
{
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glGenTextures(1, texid);

    glBindTexture(GL_TEXTURE_2D, texid[0]);
    /* set texture */
    {
        GLenum target = GL_TEXTURE_2D;
        GLint level = 0;
        GLint internalformat = GL_RGB;
        GLsizei width = 2;
        GLsizei height = 2;
        GLint border = 0;
        GLenum format = GL_RGB;
        GLenum type = GL_FLOAT;
        const GLvoid *data = pixels;

        glTexImage2D (
            target,
            level,
            internalformat,
            width,
            height,
            border,
            format,
            type,
            data
        );
    }
    printf("got texture #%d.\n", texid[0]);

    typedef struct {
        double x_left;
        double x_right;
        double y_bottom;
        double y_top;
        double z_near;
        double z_far;
    } glOrtho_arguments;

    const struct {
        GLint width;
        GLint height;
    } glutInfo = {
        glutGet(GLUT_WINDOW_WIDTH),
        glutGet(GLUT_WINDOW_HEIGHT)
    };

    glOrtho_arguments args;
    args.x_left = 0;
    args.x_right = glutInfo.width;
    args.y_bottom = glutInfo.height;
    args.y_top = 0;
    args.z_near = -1;
    args.z_far = 1;

    glClearColor(0, 0, 0, 0);
    glMatrixMode(GL_PROJECTION);
    glMultMatrixf(identity4f);        
    glOrtho (
        args.x_left, 
        args.x_right, 
        args.y_bottom, 
        args.y_top, 
        args.z_near, 
        args.z_far
    );
}

int main(int argc, char **argv)
{    
    glMatrixMode(GL_MODELVIEW);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(appTitle);
    init();    
    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

And here is a version that uses triangles

#include <gl/glut.h>
#include <stdio.h>

const char *appTitle = "OpenGL Texture Experiment";

static GLfloat identity4f[] = {
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1
};

static GLfloat pixels[] = {
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    1, 1, 1
};

static GLfloat vertices[] = {
    0, 0, 
    0, 2, 
    2, 2, 
    2, 2, 
    2, 0, 
    0, 0
};

static GLfloat coords[] = {
    0, 0,
    1, 0,
    1, 1,
    1, 1,
    0, 1,
    0, 0
};

GLuint texid[] = {-1};

static inline void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor((float)81/255, (float)81/255, 1, 1);  

    glColor3f(1, 1, 1);

    glBindTexture(GL_TEXTURE_2D, texid[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexCoordPointer(2, GL_FLOAT, 0, coords);
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    glutSwapBuffers();        
}

static inline void init()
{
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glGenTextures(1, texid);

    glBindTexture(GL_TEXTURE_2D, texid[0]);
    /* set texture */
    {
        GLenum target = GL_TEXTURE_2D;
        GLint level = 0;
        GLint internalformat = GL_RGB;
        GLsizei width = 2;
        GLsizei height = 2;
        GLint border = 0;
        GLenum format = GL_RGB;
        GLenum type = GL_FLOAT;
        const GLvoid *data = pixels;

        glTexImage2D (
            target,
            level,
            internalformat,
            width,
            height,
            border,
            format,
            type,
            data
        );
    }
    printf("got texture #%d.\n", texid[0]);

    typedef struct {
        double x_left;
        double x_right;
        double y_bottom;
        double y_top;
        double z_near;
        double z_far;
    } glOrtho_arguments;

    const struct {
        GLint width;
        GLint height;
    } glutInfo = {
        glutGet(GLUT_WINDOW_WIDTH),
        glutGet(GLUT_WINDOW_HEIGHT)
    };

    glOrtho_arguments args;
    args.x_left = 0;
    args.x_right = glutInfo.width;
    args.y_bottom = glutInfo.height;
    args.y_top = 0;
    args.z_near = -1;
    args.z_far = 1;

    glClearColor(0, 0, 0, 0);
    glMatrixMode(GL_PROJECTION);
    glMultMatrixf(identity4f);        
    glOrtho (
        args.x_left, 
        args.x_right, 
        args.y_bottom, 
        args.y_top, 
        args.z_near, 
        args.z_far
    );
}

int main(int argc, char **argv)
{    
    glMatrixMode(GL_MODELVIEW);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(appTitle);
    init();    
    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

enter image description here

1

1 Answers

1
votes

Switch GL_TEXTURE_ENV to GL_DECAL or use glColor3f(1, 1, 1) before rendering if you're going to stick with the default GL_MODULATE texenv.

You also need to glBindTexture() before you call glTexImage2D() so OpenGL knows which texture object to populate.

All together:

#include <GL/glut.h>
#include <stdio.h>

static GLfloat pixels[] =
{
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    1, 1, 1
};

GLuint texid[] = { -1 };

static inline void init()
{
    glEnable( GL_TEXTURE_2D );
    glGenTextures( 1, texid );
    glBindTexture( GL_TEXTURE_2D, texid[ 0 ] );
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
}

static inline void display()
{
    glClearColor( 0, 0, 0, 0 );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho( -2, 2, -2, 2, -1, 1 );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glColor3f( 1, 1, 1 );

    glBindTexture( GL_TEXTURE_2D, texid[ 0 ] );
    glBegin( GL_QUADS );
    glTexCoord2f( 0, 0 );
    glVertex2f( 0, 0 );
    glTexCoord2f( 1, 0 );
    glVertex2f( 1, 0 );
    glTexCoord2f( 1, 1 );
    glVertex2f( 1, 1 );
    glTexCoord2f( 0, 1 );
    glVertex2f( 0, 1 );
    glEnd();

    glutSwapBuffers();
}

int main( int argc, char **argv )
{
    glMatrixMode( GL_MODELVIEW );
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
    glutInitWindowSize( 300, 300 );
    glutCreateWindow( "OpenGL Texture Experiment" );
    init();
    glutDisplayFunc( display );
    glutMainLoop();
    return 0;
}