iPhone and Widescreen 2D with OpenGL

For a project that I’ve been working on, I’ve been using OpenGL ES on the iPhone to do 2D in widescreen. Since I struggled a bit to get it setup, I’ll go ahead and share how I got things going.

First up, you need a project to work in — I’m using the OpenGL ES Application template in XCode for this. Also, I’m using the 3.0 SDK. This should apply just the same to earlier SDK versions, but there may be minor differences.

ortho1

Out of the box, this project will use an orthogonal view. But it isn’t in widescreen mode, and the 0,0 is in the center of the screen. This might be fine for some uses, but if you are porting code that expects 0,0 to be someplace else, this just isn’t going to work. For this example, we are going to setup the scene so that 0,0 is the bottom left and 480,320 is the top right.

First off, lets change the method -(id)initWithCoder:(NSCoder*)coder. Underneath the line:

    animationInterval = 1.0 / 60.0;

put in the following code:

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
    glOrthof(-480.0f / 2.0f, 480.0f / 2.0f, -320.0f / 2.0f, 320.0f / 2.0f, -1.0f, 1.0f);
 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(-480.0f / 2.0f, -320.0f / 2.0f, 0.0f);

What we are doing here is setting up our two matrices — the projection matrix and the model/view matrix. We rotate the matrix -90 degrees so that we will be in widescreen mode with the home button on the right. If you want to flip it the other way, just rotate +90 degrees instead. Once we’ve done that, we can setup our orthogonal projection with the bottom left being 0,0 and the top right being 480,320.

For the model/view matrix, all we need to do is just translate the matrix so that the bottom left is 0,0 and the top right is 480,320.

Down below in the -(void)drawView method, you need to remove this block of code:

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);

Since we are setting up the projection matrix in our initialization code, we do not need to reset it every time we draw a frame. Also you will need to replace this block of code:

    const GLfloat squareVertices[] = {
        -0.5f, -0.5f,
         0.5f, -0.5f,
        -0.5f,  0.5f,
         0.5f,  0.5f,
    };

with this:

    const GLfloat squareVertices[] = {
        -120.0f, -120.0ff,
         120.0f, -120.0ff,
        -120.0f,  120.0f,
         120.0f,  120.0f,
    };

The old coordinates were based on 0,0 being in the center of the screen and that the width/height of the screen was 2.0 and 3.0. We also need to change where it is drawn. We can do that by adding the following code right before the glMatrixMode(GL_MODELVIEW) call:

    glPushMatrix();
    glTranslatef(480.0f / 2.0f, 320.0f / 2.0f, 0.0f);

and this after the glDrawArrays() call:

    glPopMatrix();

It should look like this now:

ortho2

A couple of quick notes — you probably noticed that the glTranslatef() in drawView cancels out the one in initWithCoder:. This is really only for demo purposes. In my projects, I do rotation and translation myself so that I can take advantage of calling glDrawArrays() for a batch of objects instead of sending them to GL one at a time. But that’s beyond the scope of this article. The other thing is that if you run this project right now, you’ll also notice that it’s still not in widescreen and it’s no longer rotating the cube. The first is really easy to fix. Open the plist file for your project — mine is called OrthoGL-Info.plist and it’s located in Resources. You need to add the following flag:

ortho3

You can add a new entry by clicking on the + button that shows up when you click on any line. It doesn’t matter where in the file the flag is — you can put it anywhere.

That fixes the first problem, but the second problem still remains. We lost rotation when we added the glPush/PopMatrix() calls. This one is fairly easy to fix as well. Simply add a new instance variable to the EAGLView.h file. Call it rotation with a GLfloat type:

ortho4
and then replace the glRotate() in drawView with this:

    rotation += 3.0f;
    glRotatef(rotation, 0.0f, 0.0f, 1.0f);

All done!

ortho5

I hope at this point you have enough to get started with 2D projection in widescreen on the iPhone. Please let me know in the comments below any questions you may have, and I’ll try to answer them. Maybe if there is enough interest, I can do a follow up article as well.

Advertisements

About this entry