Featured Posts

8. Bump Mapping in GLSL8. Bump Mapping in GLSL Introduction Bump mapping is essential in todays computer games, and computer graphics in general. Would you like to know the best thing about it? It is extremely simple to implement. Bump mapping works...

Read more

Swiftless GLSL Shader DeveloperSwiftless GLSL Shader Developer Swiftless GLSL Shader Developer   Version 0.1a Currently Swiftless GLSL Shader Developer is in it's first public release, and is currently in alpha status, meaning it is not complete and may contain...

Read more

Wordpress Optimization Wordpress Website Optimizations Introduction Wordpress itself is a fairly wonderful tool. Since switching to it, I find it is a lot quicker to make changes to my website and it is also quicker to get...

Read more

36. OpenGL Framebuffers36. OpenGL Framebuffers Introduction Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing...

Read more

1. Terrain Class1. Terrain Class Terrain is one of those things that so far, hasn't been perfectly recreated in computer graphics. But it is almost there! Looking over a beautiful landscape can be one of the most amazing feelings in the...

Read more

  • Prev
  • Next

35. OpenGL Tiling Engine

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , ,

12

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 of a map file that I am using for this tutorial, which is integrated into the code:

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},
};

Now if you don’t like storing this in your program, you can just as easily store all of this in a file and loadit 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 beeither grass or dirt in the case of the textures I have created.

I am setting 1 to 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, as we already setup the first texture in the first tutorial.
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);

So now that we have our map, and our textures, we need to now draw it all. I am creating a method called drawTiles(). This method 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

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.

  

#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 )
    glBindTexture( GL_TEXTURE_2D, texture );
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE
 ); //set texture environment parameters

    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 Texture(.RAW file)

Download the second Texture (.RAW file)

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.7/10 (3 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
35. OpenGL Tiling Engine, 8.7 out of 10 based on 3 ratings

Related posts:

  1. 32. OpenGL Particle Engine
  2. 20. OpenGL MipMap Generation
  3. 33. OpenGL Animating Textures
  4. 16. OpenGL Texturing
  5. 17. OpenGL Texture Coordinate Generation

Comments (12)

After looking for a solution for this poor performance I found out that if you check the currently bound textures and if it is already bound then just skipping the binding it actually gives a huge speed boost.

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Yes, I mean don’t draw them.

In the loop, before you draw, you can do the check as to whether or not you need to draw.

Cheers,
Swiftless

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

when you mean cull them do you mean not draw them because doesn’t the whole thing just go through a loop

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hey Jjack,

GL_CULL culls back-facing polygons, so it won’t take care of removing objects out side of the field of view.

If you have a set field of view, then you could do a hack and work out the distance between tiles and the centre of the screen, and cull them if they are too far away. However the correct way is to do a bounding box collision check against the view frustrum.

Vertex Buffer Objects can be set once and then drawn whenever you want them, the advantage being that they are stored on the graphics card and not system memory, so they are so much faster than regular rendering. You can alternatively set the VBO to be update-able if you need to make changes to it at any stage.

Cheers,
Swiftless

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Will the simple glEnable(GL_CULL); work or will you have to do some fancy algorithms and with vertex buffer objects do you have to update them each frame or can you just set them once and then they will not get overwritten?

Thanks

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Thanks for the tutorial I have been looking all over the internet for one and this seems the most recent. Well I would like to ask why the FPS is so low I am getting about <10 frames per second when scrolling.

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hi jjack,

The number of frames per second if you use this straight out, is going to be fairly poor for a large number of tiles. I am not doing any culling to test if a tile is visible or not, which means every tile is going to be drawn, even if it isn’t in the window.

Another reason it would be so slow, is this is using OpenGL’s Immediate Mode, to speed it up even more so, you could store the tiles in Vertex Buffer Objects.

Cheers,
Swiftless

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

i played the original SimCity in the 90′s and until now i still play the latest version of SimCity*`:

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

I have just fixed it up, it appears that


tags are causing the tutorials to disappear in some instances.

Let me know if you find any more.

Cheers,
Swiftless

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hey,
can you re-upload this tutorial, please?

Thank’s a lot!

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hi Meee,

If all the tiles are white, then this sounds like it simply isn’t loading your textures.

Make sure your textures are in the correct directory and that they are loading correctly.

Cheers,
Swiftless

VN:F [1.9.3_1094]
Rating: 5.0/5 (1 vote cast)
VN:F [1.9.3_1094]
Rating: +1 (from 1 vote)

Why am I just getting a white block?

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Write a comment

Improve the web with Nofollow Reciprocity.