Saturday, September 10, 2011

Tutorial: simple OpenGL program in XCode using C++

I managed to get an OpenGL program working in XCode (IDE that comes with a Mac) with C++ as a base.  Given that my long-term memory tends to fill up with such useful tidbits as "My phone number when I was 6" or "the complete lyrics to the DoodleBear TV jingle" rather than any recollection of how I got this working, I thought I'd record the instructions here.  These are aimed at someone with a basic knowledge of C++, but who hasn't used XCode, GLUT, or OpenGL before (i.e. me, as of half an hour ago).

What this covers:
  • How to find XCode on a Mac (I'm using OS 10.6.8)
  • How to create a new C++ project
  • How to include the GLUT framework
  • How to build and run a simple OpenGL application
My resources:
UCSD CSE 167 Fall 2010 Project 1 base code, by Juergen Schulze
Aaron Schwartz's blog entry on setting up Project 1 on Mac
Tutorial on setting up GLUT/OpenGL in C on XCode, by OneSadCookie

So, let's get started.


How to find XCode on a Mac

XCode is an IDE (Integrated Development Environment) that's included (but not necessarily pre-installed) on every mac.  It's mostly used for ObjectiveC, but can be used for C++ too.

My Mac didn't have XCode preinstalled out of the box, but there's a copy included on one of the DVDs that came with my Mac.  The DVD doesn't say "XCode" on it... it says something more like "OS".  Alternatively, you can register as a developer with Apple, and download a free copy.

Once XCode is installed, you can either use spotlight and search for XCode, or look on the Mac hard drive in the folder "Developer".

How to begin a new C++ project in XCode


Go to File > New Project > Command Line Tool

In the drop down menu under "type", choose "C++ stdc ++".

Choose a name for your project.

You'll see three files automatically generated for you, one of which is "main.cpp".

If you click on "main.cpp" you'll see that it's a simple "Hello World" program.  Just to make sure everything's OK with your xcode installation, click the Build and Run button.  It should give you a cheerful message like "Succeeded" at the lower right of the screen.  To see the output of your program, go to the left-hand window (labeled "Groups and Files"), and look under "Products", where there should be an item called "Lab 1 temp".  Double-click on that to open a terminal output window, where you should already see "Hello World!" printed.

Congratulations - you've built a C++ program in XCode.

How to include the GLUT framework

OpenGL is a graphics library that you can use to write 2D and 3D graphics displays and interfaces.  Most of the code is cross-platform (will run on Windows, Mac, and Linux), but the different platforms do have different ways of creating new windows and monitoring user input.  GLUT is a wrapper that hides the differences between platforms so you can write code that (with very minor modifications) will run on all three platforms.

Right-click (or control-click) on your project name under "Groups and Files".  It should be the first icon.  Choose "Add > Existing Frameworks".

Select "GLUT.framework" and "OpenGL.framework", and click "Add."
They should appear as little yellow suitcase icons in your project.

Now you're ready to start writing an OpenGL program!

How to build and run a simple OpenGL program

Now that you've set up XCode to use GLUT and OpenGL, create a simple program to test that everything's working.  As an example, I'll use code from UCSD CSE 167 Fall 2010 Project 1, by Juergen Schulze.  The code for Windows and OS is identical (thanks to GLUT), except for the line that includes GLUT:

---Begin code---

/* Use the following line on a Windows machine:
 #include <GL/glut.h>
 */
/* This line is for Max OSX  */
#include <GLUT/glut.h>


/*! GLUT display callback function */
void display(void);
/*! GLUT window reshape callback function */
void reshape(int, int);

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
   
    /* set the window size to 512 x 512 */
    glutInitWindowSize(512, 512);
   
    /* set the display mode to Red, Green, Blue and Alpha
     allocate a depth buffer
     enable double buffering
     */
    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
   
    /* create the window (and call it Lab 1) */
    glutCreateWindow("Lab 1");
   
    /* set the glut display callback function
     this is the function GLUT will call every time
     the window needs to be drawn
     */
    glutDisplayFunc(display);
   
    /* set the glut reshape callback function
     this is the function GLUT will call whenever
     the window is resized, including when it is
     first created
     */
    glutReshapeFunc(reshape);
   
    /* set the default background color to black */
    glClearColor(0,0,0,1);
   
    /* enter the main event loop so that GLUT can process
     all of the window event messages
     */
    glutMainLoop();
   
    return 0;
}

/*! glut display callback function.  Every time the window needs to be drawn,
 glut will call this function.  This includes when the window size
 changes, or when another window covering part of this window is
 moved so this window is uncovered.
 */
void display()
{
    /* clear the color buffer (resets everything to black) */
    glClear(GL_COLOR_BUFFER_BIT);
   
    /* set the current drawing color to red */
    glColor3f(1, 0, 0);
   
    /* start drawing triangles, each triangle takes 3 vertices */
    glBegin(GL_TRIANGLES);
   
    /* give the 3 triangle vertex coordinates 1 at a time */
    glVertex2f(10, 10);
    glVertex2f(250, 400);
    glVertex2f(400, 10);
   
    /* tell OpenGL we're done drawing triangles */
    glEnd();
   
    /* swap the back and front buffers so we can see what we just drew */
    glutSwapBuffers();
}

/*! glut reshape callback function.  GLUT calls this function whenever
 the window is resized, including the first time it is created.
 You can use variables to keep track the current window size.
 */
void reshape(int width, int height)
{
    /* tell OpenGL we want to display in a recangle that is the
     same size as the window
     */
    glViewport(0,0,width,height);
   
    /* switch to the projection matrix */
    glMatrixMode(GL_PROJECTION);
   
    /* clear the projection matrix */
    glLoadIdentity();
   
    /* set the camera view, orthographic projection in 2D */
    gluOrtho2D(0,width,0,height);
   
    /* switch back to the model view matrix */
    glMatrixMode(GL_MODELVIEW);
}

--- end code ---

Replace the contents of main.cpp with the code above. Then click "build and run".  A window should pop up with a beautiful red triangle on a black background.

Ta-da!