How to Texture your shapes on Windows

Back to OpenGL Tutorial Index

Because it is so much simpler at the moment, I am going to show you how to use
 textures under Windows only, the only thing is the actual, The original loading
 code I was using had it's limitations so I have reworked it to make it more general.

 But back to the actual texturing, because it is under windows we have to include
 the windows header file, then we also need to add the stdio header file.

 using GLuint we create a variable for the texture, called 'texture', but you can call it
 whatever you wish.

 in the 'display' function we first set the variable 'texture' to the actual
 loaded image using:
 texture = LoadTexture( "texture.raw", 256, 256 );
 where 256, 256 is the width and the height of the file respectively.
 then we enable the 2D Texturing, this is done with:
 glEnable( GL_TEXTURE_2D );
 and bind the texture with:
 glBindTexture( GL_TEXTURE_2D, texture );

 then after drawing everything we need with the texture, we clear it to save
 system resources.

 ------------------------------------------------------------------------------
 Section 1: The loading of the texture:

GLuint LoadTexture( const char * filename, int width, int height )
{
    GLuint texture;
    unsigned char * data;
    FILE * file;


 The following code will read in our RAW file
    file = fopen( filename, "rb" );  We need to open our file
    if ( file == NULL ) return 0;  If our file is empty, set our texture to empty


    data = (unsigned char *)malloc( width * height * 3 ); assign the nessecary memory for the texture


    fread( data, width * height * 3, 1, file );  read in our file
    fclose( file ); close our file, no point leaving it open


    glGenTextures( 1, &texture ); then we need to tell OpenGL that we are generating a texture
    glBindTexture( GL_TEXTURE_2D, texture ); now we bind the texture that we are working with
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); set texture environment parameters
 The parameter GL_MODULATE will blend the texture with whatever is underneath, setting it to GL_DECAL
 will tell the texture to replace whatever is on the object.

here we are setting what textures to use and when. The MIN filter is which quality to show
when the texture is near the view, and the MAG filter is which quality to show when the texture
is far from the view.

The qualities are (in order from worst to best)
GL_NEAREST
GL_LINEAR
GL_LINEAR_MIPMAP_NEAREST
GL_LINEAR_MIPMAP_LINEAR


 The two mipmap variables only work in textures with generated mipmaps, so you will see that in action
 in a later tutorial.

And if you go and use extensions, you can use Anisotropic filtering textures which are of an
even better quality, but this will do for now.

    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );


Here we are setting the parameter to repeat the texture instead of clamping the texture
to the edge of our shape.

    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );


Generate the texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

    free( data ); free the texture
    return texture; return the texture data
}



--------------------------------------------------------------------------------
Section 2: Cleaning Up:

If we decide not to clean up after our work, you will find that the program will inevitably
slow down your computer, taking more and more memory.
void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture );  Delete our texture, simple enough.
}



-------------------------------------------------------------------------------
Section 3: Texture Coordinates

This is how texture coordinates are arranged

  0,1   -----   1,1
       |     |
       |     |
       |     |
  0,0   -----   1,0

 With 0,0 being the bottom left and 1,1 being the top right.

 Now the point of using the value 0,1 instead of 0,10, is so that it is mapping 1 texture to the
 coordinates. Changing that to 10 would then try to map 10 textures to the one quad. Which because
 I have the repeat parameter set in our texture, it would draw 10 across and 10 down, if we had
 it clamped, we would be still drawing 1. The repeat function is good for things like
 brick walls.

 To assign texture coordinates to a vertex look at the following code:
glBegin (GL_QUADS);

glTexCoord2d(0.0,0.0);
with our vertices we have to assign a texcoord so that our texture has some points to draw to
glVertex2d(-1.0,-1.0);

glTexCoord2d(1.0,0.0);
glVertex2d(+1.0,-1.0);

glTexCoord2d(1.0,1.0);
glVertex2d(+1.0,+1.0);

glTexCoord2d(0.0,1.0);
glVertex2d(-1.0,+1.0);

glEnd();

For every vertex, we are assigning a texture coordinate that corresponds with it. Keep in mind
that this does not mean that if a vertex is a -10, 20, the texture coordinates will be -10, 20.
They will infact be something along the lines of 0,1.

---------------------------------------------------------------------

So now you should have a rough idea of the basics associated with texturing.
If you have any questions, feel free to email me at swiftless@gmail.com

#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

GLuint texture; //the array for our texture

GLfloat angle = 0.0;

//function to load the RAW file

GLuint LoadTexture( const char * filename, int width, int height )
{
    GLuint texture;
    unsigned char * data;
    FILE * file;

    //The following code will read in our RAW file
    file = fopen( filename, "rb" );
    if ( file == NULL ) return 0;
    data = (unsigned char *)malloc( width * height * 3 );
    fread( data, width * height * 3, 1, file );
    fclose( file );

    glGenTextures( 1, &texture ); //generate the texture with the loaded data
    glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture to it's array
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); //set texture environment parameters

    //here we are setting what textures to use and when. The MIN filter is which quality to show
    //when the texture is near the view, and the MAG filter is which quality to show when the texture
    //is far from the view.

    //The qualities are (in order from worst to best)
    //GL_NEAREST
    //GL_LINEAR
    //GL_LINEAR_MIPMAP_NEAREST
    //GL_LINEAR_MIPMAP_LINEAR

    //And if you go and use extensions, you can use Anisotropic filtering textures which are of an
    //even better quality, but this will do for now.
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    //Here we are setting the parameter to repeat the texture instead of clamping the texture
    //to the edge of our shape.
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

    //Generate the texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    free( data ); //free the texture
    return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture );
}

void square (void) {
    glBindTexture( GL_TEXTURE_2D, texture ); //bind our texture to our shape
    glRotatef( angle, 1.0f, 1.0f, 1.0f );
    glBegin (GL_QUADS);
    glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0); //with our vertices we have to assign a texcoord
    glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0); //so that our texture has some points to draw to
    glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
    glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
    glEnd();


//This is how texture coordinates are arranged
//
//  0,1  --  1,1
//       |     |
//       |     |
//       |     |
//  0,0  --  1,0

// With 0,0 being the bottom left and 1,1 being the top right.

// Now the point of using the value 0,1 instead of 0,10, is so that it is mapping 1 texture to the
// coordinates. Changing that to 10 would then try to map 10 textures to the one quad. Which because
// I have the repeat parameter set in our texture, it would draw 10 across and 10 down, if we had
// it clamped, we would be still drawing 1. The repeat function is good for things like
// brick walls.
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glEnable( GL_TEXTURE_2D );
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    square();
    glutSwapBuffers();
    angle ++;
}
void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("A basic OpenGL Window");
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);

    //Load our texture
    texture = LoadTexture( "texture.raw", 256, 256 );

    glutMainLoop ();

    //Free our texture
    FreeTexture( texture );

    return 0;
}

Download C++ Source Code for this Tutorial

Download Visual Basic Source Code for this Tutorial

Download Texture(.RAW file)

Download Texture(.BMP file)

     

 

Copyright 2008, Donald Urquhart
Proudly supported by http://www.cdadc.com