How to create a tile effect in OpenGL

Back to OpenGL Tutorial Index

Well due to a request, here is a tiling example for you all.

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

To tile in OpenGL, it is not that easy to merge or combine textures to create a simple 2D tiling game.
It is easier for us to draw a bunch of quads that take up the space of the world in which we want
to tile and assign different textures to those quads according to what is in our map file.

Here is the example map file that I am using for this tutorial:

int cMap[10][10] = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};

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

Now if you don't like storing this in your program, you can just as easily store all of this in a file and load
it in when you need it.

So now that we have our 'map', we want to load in our two textures for our two states, 1 or 0, which will be
either grass or dirt in the case of the textures I have created.

1 will be dirt, and 0 will be grass.

So as this is building on from the texturing tutorial, we need to create another variable to hold our
other texture.
GLuint texture2; //the array for our second texture

Now that we have our textures, we need to load them in, do this just like you did in the texturing tutorial:

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

glutMainLoop ();

Free our texture
FreeTexture(texture);
FreeTexture(texture2);

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

And now for the drawTiles() function. This function will be called in the display function and takes no parameters.

void drawTiles (void) { //our function to draw the tiles
First thing we want to do is start looping through the height of the map, the value of 10 here is specific
to this application. If you have a bigger or smaller map, change this value as you need.
for (int i = 0; i < 10; i++) //loop through the height of the map
{
Then we will want to loop through the width of the map, just as I said above, the value 10 is specific
to this tutorial.
for (int j = 0; j < 10; j++) //loop through the width of the map
{
Now here is where the main part of our tiling takes place, we need to check if the map value at the
current [i][j] position is either a 0 or a 1. If it is a 0, then we bind the grass texture to the quad
that we are about to draw.
if (cMap[i][j] == 0) //if the map at this position contains a 0
{
glBindTexture( GL_TEXTURE_2D, texture ); //bind our grass texture to our shape
}
Else we automatically assign it to dirt. If you have more than two states, you will need to make several if statements,
and if you do not want a default, then you will remove the else and replace it with an if.
else //otherwise
{
glBindTexture( GL_TEXTURE_2D, texture2 ); //bind our dirt texture to our shape
}

The rest of the code draws a quad at the current i, j position we are at.
Drawing a quad should be simple for you at this stage. So I will not explain it.
glPushMatrix(); //push the matrix so that our translations only affect this tile
glTranslatef(j, -i, 0); //translate the tile to where it should belong

glBegin (GL_QUADS); //begin drawing our quads
glTexCoord2d(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0); //with our vertices we have to assign a texcoord

glTexCoord2d(1.0, 0.0);
glVertex3f(1.0, 0.0, 0.0); //so that our texture has some points to draw to

glTexCoord2d(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);

glTexCoord2d(0.0, 1.0);
glVertex3f(0.0, 1.0, 0.0);
glEnd();
glPopMatrix(); //pop the matrix
} //end first loop
} //end second loop
}

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

And there we have it, you can now create a 2D tiled map for use with a game. Simple wasn't it? :-)
If you have any questions, email me at swiftless@gmail.com

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

GLuint texture; //the array for our texture
GLuint texture2; //the array for our second texture

int cMap[10][10] = { //our map
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};

//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 drawTiles (void) { //our function to draw the tiles
for (int i = 0; i < 10; i++) //loop through the height of the map
{
for (int j = 0; j < 10; j++) //loop through the width of the map
{
if (cMap[i][j] == 0) //if the map at this position contains a 0
{
glBindTexture( GL_TEXTURE_2D, texture ); //bind our grass texture to our shape
}
else //otherwise
{
glBindTexture( GL_TEXTURE_2D, texture2 ); //bind our dirt texture to our shape
}

glPushMatrix(); //push the matrix so that our translations only affect this tile
glTranslatef(j, -i, 0); //translate the tile to where it should belong

glBegin (GL_QUADS); //begin drawing our quads
glTexCoord2d(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0); //with our vertices we have to assign a texcoord

glTexCoord2d(1.0, 0.0);
glVertex3f(1.0, 0.0, 0.0); //so that our texture has some points to draw to

glTexCoord2d(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);

glTexCoord2d(0.0, 1.0);
glVertex3f(0.0, 1.0, 0.0);
glEnd();
glPopMatrix(); //pop the matrix
} //end first loop
} //end second loop
}

void display (void) {
glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glEnable( GL_TEXTURE_2D );
glTranslatef(-5, 4, -20); //translate back a bit to view the map correctly
drawTiles(); //draw our tiles
glutSwapBuffers();
}
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);
texture2 = LoadTexture("texture2.raw", 256, 256);

glutMainLoop ();

//Free our texture
FreeTexture(texture);
FreeTexture(texture2);

return 0;
}

Download C++ Source Code for this Tutorial

Download Texture(.RAW file)

Download the second Texture (.RAW file)

     

 

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