Code Snippets: OpenGL in 2D

July 12, 2009
Tutorials

This code tutorial will demonstrate how to set up a 2D orthographic projection. It also covers the basics of loading image files and painting to the screen using OpenGL. It’s mostly code samples and not actually very instructive. Just set up a base template for any new 2D AllegroGL project!

I really like using OpenGL, but many of my games are in 2D. Fortunately, this is not a problem.

Part 1 : 3D to 2D

Here is the code that sets up your 2D environment. It’s pretty simple. We just go to the projection matrix and change it by using the glOrtho command. Then we switch back to Modelview (which is where we draw everything.)

set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 320,240, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

You see, the projection matrix tells us how we see the game’s environment. In this case, we use glOrtho to create a 2D projection onto the screen. You’ll quickly notice that 0,0 is in the top-left corner and 320,240 is in the bottom-right. That’s right, y-values run positive as you go down the screen. Trust me, in the long run, this makes life easier.

Hey! Did you notice? glOrtho tells you what you’re looking at. It effectively defines where the camera is pointing. This means if you want to move the camera around, you can just move the Ortho to follow the main character’s x,y coordinates.

glOrtho(player.x-160, playerx+160, player.y-120, player.y+120, 0, 1);

Your screen coordinates (also your mouse coordinates) are NOT tied to your in-game coordinates. You’ll notice that the window size is 640 x 480 and yet the Ortho is 320 x 240. That means that each pixel in the game will be twice as large. If you change the Ortho size, you’ll zoom in/out of your game world!

Since we don’t need the z coordinate, let’s just turn it off.

glDisable(GL_DEPTH_TEST)

Part 2: Loading Graphics

Sadly, OpenGL can be a pain for loading textures. Allegro also needs some help. Here’s how you get the results that you want.

  • Get the ALPNG library. Working with PNGs is fantastic. They are easy to use, compatible with many paint programs, efficient, and just all-around pretty sweet.
  • Load the PNG file into an Allegro bitmap.
  • Turn that bitmap into an OpenGL texture.
  • Turn off filtering so that it looks pixelated and not all smudgy and lame.
GLuint LoadPNG(char* Filename)  /*Make sure your texture is in powers of 2!  2x4, 32x16, 128x128, etc. */
{
    BITMAP* temp;
    temp = load_png(Filename, 0);

    GLuint theImage = allegro_gl_make_texture_ex(AGL_TEXTURE_HAS_ALPHA, temp, GL_RGBA);
    glBindTexture(GL_TEXTURE_2D, theImage);					// Bind Our Texture
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    destroy_bitmap(temp);

    return theImage;
}

A few things to note:

  • Always make sure your texture has a width and height that are a power of 2. This really speeds up the graphics processing. If you have to leave blank unused space in your image, so be it. You’d rather waste that space than waste the run-time.
  • After loading your image, bind it and work with it. I use the GL_NEAREST filter, because it gives that
    nice sharp look. There are other options; I trust you know how to use Google.
  • I usually destroy the bitmap data once I’m done with it. You rarely need it.
  • Texture data are referenced by a GLuint. You’ll be using that variable to paint with your texture.

Part 3: Painting Graphics

There are a lot of tutorials out there that deal with drawing in OpenGL. Here’s the code. I’ll explain parts of it, but I won’t elaborate. Trust me, anything I say will pale in comparison to NeHe.

void PaintImage(GLuint texID, float x , float y, float sizex, float sizey, int r, int g, int b, int a)
{
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texID);
    glPushMatrix();
    glTranslatef(x, y, 0);
    glColor4ub(r,g,b,a);
    glBegin(GL_QUADS);
        glTexCoord2f(0, 0); //top left for both texture and rectangle.
        glVertex2f(0, 0);
        glTexCoord2f(1, 0);  //top right
        glVertex2f(sizex, 0);
        glTexCoord2f(1, 1);  //bottom right
        glVertex2f(sizex,sizey);
        glTexCoord2f(0, 1);  //bottom left
        glVertex2f(0,sizey);
    glEnd();
    glPopMatrix();
}

glVertex2f will place a point in your game-space. You’ll notice I call it 4 times, once for each point on the rectangle. In this case, the code does the following:

  • Turn on textures and then bind the given texture. This is what our rectangle will look like.
  • Move to the object’s game-space position.
  • Draw a rectangle of a given size.

So what’s glTexCoord all about? Every texture, regardless of actual size, ranges from 0 to 1 on the x and y axis. So 0,0 is the top-left corner and 1,1 is the bottom-right corner.

In this example, I pull the whole texture and stretch it onto my rectangle.

So if my texture was only 16×16, but my rectangle was 32×16, it would stretch out along the x-axis to fit the rectangle. That would look pretty weird. If you want to maintain a 1:1 relationship between your texture and rectangle, make sure you know the dimensions of your texture.

So what if you just want to use a piece of your texture? What if your texture is really a character map for your font? I’ll show you how to do that easily another day.

Some things to note:

  • GL_TRIANGLES are technically faster, but you probably won’t notice the difference.
  • Draw your rectangle points in order! I start from the top-left and work my way around.
  • Call glColor4ub BEFORE you do glBegin. It offers a minor speed benefit.
  • glColor4ub denotes the r,g,b,a in that order. Play around with it in the download below to learn!

Really, that’s all I have to say. This page isn’t really a tutorial. It just presents some code samples you can use. When I create a new project, I almost always start with this source code as a base. Take it and use it as you wish.

Base source code (+win32 binary)

, , , , , ,


Add a comment?


Leave Your Mark



      
Powered by Wordpress. All content written by Michael Vendittelli.