macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Developing in OpenGL Using Makefiles

by Michael J. Norton
04/01/2005

When I was in college, I was furnished with a terminal to access the mainframe and used vi and makefiles to develop software. And I liked it! The days of coding on mainframes and PDP-11s may be long gone, but the methodology of software development is still pretty much the same.

Well, some things do change. I have long since moved over to using EMACS, which is about as much change as this software engineer can take. Sure, I've heard of that cool development tool called Xcode, but hey, when we were young we didn't have Xcode, we had raw makefiles. They were interesting then, and I think you'll find that they still have legs.

I recently decided to start dabbling again in C code and expand my horizons in OpenGL. My system environment is primarily UNIX. In one day, I hop back and forth quite a bit between the Solaris OS and Mac OS X, using X Windows. Looking around for example code to reverse engineer and analyze for both platforms is next to impossible. For example, the self-supported OpenGL tutorial site, NeonHelium, contains examples for multiple platforms and operating systems. The coding examples for the Macintosh are primarily for Cocoa or the old Mac OS. The majority of the other source code is for UNIX and Microsoft Windows.

If you're a Cocoa programmer, then the source you'll find on the internet will suit you. However, if you just want to use the platform-independent source code that runs on a multitude of UNIX platforms, you'll have to do it old school--with makefiles. Ironically, those Mac OS X examples that go out of their way to demonstrate Cocoa compile and run just as easily in their UNIX state of code. An open systems development approach eliminates the Cocoa application dependencies from the fray.

The source code I accumulated was primarily from two books: OpenGL Programming Guide (known as "the red book" in OpenGL programming circles, and available in PDF format) and Edward Angel's excellent textbook using OpenGL examples, Interactive Computer Graphics.

I downloaded and built the example binaries on my Sun Ultra 10. Once my elation was over after watching the first couple of demos run on my Ultra 10, I decided to see if I could get these same examples to run on my PowerBook. After all, Mac OS X has Darwin, a *NIX kernel, right?

The Makefile

The UNIX make utility was the key to my example code build success. When the make utility is executed, the program looks for a file named makefile or Makefile, by default.

The contents of the makefile contain information called dependencies and targets. Pretty much any code compiled uses a makefile. You will need Apple's Xcode package installed to play with these examples. For posterity or edification, here is my makefile to build a simple OpenGL application.

LIBPATH += 
-L"/System/Library/Frameworks/OpenGL.framework/Libraries"

FRAMEWORK = -framework GLUT
FRAMEWORK += -framework OpenGL 

COMPILERFLAGS = -Wall 
CC = g++ 
CFLAGS = $(COMPILERFLAGS) 
LIBRARIES = -lGL -lGLU -lm -lobjc -lstdc++ 

OBJECTS = GlutExample.o 
All: GlutExample 

GlutExample: GlutExample.o $(OBJECTS) 
    $(CC) $(FRAMEWORK) $(CFLAGS) -o $@ $(LIBPATH) $(OBJECTS)

$(LIBRARIES) 
       ./GlutExample

This is an example of a basic makefile. A makefile consists of an assignment of variable definitions and dependencies. For example:

COMPILERFLAGS = -Wall
CC = g++
CFLAGS = $(COMPILERFLAGS)
LIBRARIES = -lGL -lGLU -lm -lobjc -lstdc++

The variable COMPILERFLAGS is assigned the compiler flags variable the value -Wall. This tells the compiler to give all warnings during the compile process. COMPILERFLAGS is passed to the variable CFLAGS in the following manner:

CFLAGS = $(COMPILERFLAGS)

Notice how the COMPILERFLAGS value is accessed when it is assigned to the CFLAGS variable. The referencing of variables uses the $(var) syntax, as is used with the CFLAGS assignment of $(COMPILERFLAGS).

The true power of the makefile is in its handling of dependency and build rules. Here is how I am going to build the source code example GlutExample.c.

GlutExample: GlutExample.o $(OBJECTS)
<tab>$(CC) $(FRAMEWORK) $(CFLAGS) -o $@ $(LIBDIR) \
$(OBJECTS) $(LIBRARIES)

The first line says the target, the binary we are building, GlutExample, depends on the object file GlutExample.o. The second line has the commands we'll need to build the target program, GlutExample. The compiler invokes the commands which we set, such as the CFLAGS variable option. The make utility is very picky about spaces and tabs. In the above example, replace the <tab> label with a real tab in your editor.

GlutExample.c

The OpenGL example is based around a C function, tetrahedron, found in Edward Angel's book Interactive Computer Graphics. I filled in the rest of the code to demonstrate how to call it from OpenGL. This is our working example that demonstrates how to build OpenGL code in C using makefiles.

#include <stdlib.h> 
#include <GLUT/glut.h> /* Header File For The GLut Library*/ 

#define kWindowWidth      640 
#define kWindowHeight     480 

typedef GLfloat point[3]; 

point v[4] ={{0.0, 0.0, 1.0}, 
             {0.0, 0.942809, -0.333333}, 
             {-0.816497, -0.471405, -0.333333}, 
             {0.816497, -0.471405, -0.333333}};

void triangle( point a, point b, point c) 
{ 
  glBegin(GL_LINE_LOOP);
  glVertex3fv(a); 
  glVertex3fv(b); 
  glVertex3fv(c); 
  glEnd(); 
} 

void tetrahedron(void) 
{ 
  triangle(v[0], v[1], v[2]); 
  triangle(v[3], v[2], v[1]); 
  triangle(v[0], v[2], v[3]); 
} 

void display(void)
{ 
  glClear(GL_COLOR_BUFFER_BIT); 
  glColor3f(1.0,1.0,1.0); 
  glLoadIdentity(); 

  tetrahedron(); 
  glutSwapBuffers();
} 

int main(int argc, char** argv) 
{ 
  glutInit(&argc, argv); 
  glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); 
  glutInitWindowSize (kWindowWidth, kWindowHeight); 
  glutInitWindowPosition (100, 100); 
  glutCreateWindow ("simple opengl example");

  glutDisplayFunc(display);

  glutMainLoop();

  return 0;
}

In most source files you will download from the internet, you'll see the following headers in the source code.

/* Header File For The OpenGL32 Library */
#include <OpenGL/gl.h>
/* Header File For The GLu32 Library */
#include <OpenGL/glu.h>

For Mac OS X builds, replace those header files with the following:

#include <GLUT/glut.h> /* Header File For The GLut Library*/

Using Apple's X11, in the Applications/Utilities folder, open an xterm window (you can use the Terminal app if you prefer), and copy the example code and makefile to the same destination directory. To use these examples, you will need the Xcode tools installed, even though we are using makefiles. The Xcode install provides the frameworks and libraries required to build the code.

When the source code and makefile are copied into GlutExample.c and makefile, respectively, you can invoke the make utility. The example below shows the source directory before the make invocation.

~/Game_Dev/Glut_Test mnorton$ ls
lutExample.c   makefile

Invoke the make utility. The make utility looks in the local directory for the makefile. If the build is successful, the OpenGL application will launch automatically when the build completes.

~/Game_Dev/Glut_Test mnorton$ make
g++ -Wall    -c -o GlutExample.o GlutExample.c
g++ -framework GLUT -framework OpenGL -Wall -o GlutExample -
L"/Library/Frameworks/GLUT.framework"  -
L"/System/Library/Frameworks/OpenGL.framework/Libraries"
GlutExample.o
-lGL -lGLU -lm -lobjc -lstdc++  
./GlutExample

Here are the files the make utility created: the object file, GlutExample.o, and the executable binary file, GlutExample.

~/Game_Dev/Glut_Test mnorton$ ls 
GlutExample     GlutExample.c   GlutExample.o   makefile
~/Game_Dev/Glut_Test mnorton$

If your make executed successfully, the last line of the makefile, ./GlutExample, launches the binary. You should see a wireframe tetrahedron in an OpenGL window. Be sure the makefile portion is working properly before venturing on into the EMACS territory of this demonstration.

Figure 1. Tetrahedron from GlutExample.cFigure 1. Tetrahedron from GlutExample.c

EMACS

For source code editing, I use EMACS almost exclusively. In *NIX circles, religious debates always surface over which old school editor is better, vi or EMACS. I find text entry to be easier using EMACS. It behaves like a normal text editor.

EMACS provides more bells and whistles than any one developer could possibly master in a lifetime. But one cool feature you can master at this moment is how to use EMACS to edit source code and invoke the make utility from inside of EMACS. The EMACS environment is included as a part of the basic BSD install when your computer arrived at your doorstep. An Aqua flavor of EMACS exists, but I recommend the xemacs utility available from the fink package installer. For this demonstration, I will use the basic EMACS that shipped with your system. Let's load the OpenGL example code into our EMACS editing environment. From a UNIX prompt, this should be in the directory to which you copied the GlutExample.c file and the makefile. Simply type:

emacs GlutExample.c

Entering EMACS is the easy part. Using EMACS requires knowledge of a finger twister: two basic key sequences, Ctrl-X key sequences and meta (Esc) key sequences. To save your source file, you need to type the key sequence Ctrl-X Ctrl-S. To quit the EMACS utility, you use the key sequence, Ctrl-X Ctrl-C. Note that the Ctrl key is held down during the stroke of the X key and the C or S key. For a meta key, the Esc key is pressed and then released before the next keystroke. A meta-key command in EMACS docs is denoted as "M-keystroke." For the meta command M-x, press Esc, release it, and then press the X key. This is an M-x command keystroke. Whenever you see the meta key in EMACS, just think Esc key.

That's the basic tour. You can now open source code in EMACS and quit EMACS.

Running make from EMACS

EMACS can be used as a development environment for many scripting and computer languages. EMACS even knows how to compile and run makefiles for C code. To compile C code, use the meta command M-x compile (Esc x). You will be prompted for a compile command, make -k. Accept the command-line option and hit the Enter key.

No, there is nothing wrong with your eyesight. You read that correctly--EMACS will load your makefile and build the application.

Figure 2. M-x compile Figure 2. M-x compile

EMACS will display two buffers. The top is your source code; the bottom buffer is your makefile build status and displays the compile errors. Using the EMACS environment, you can put your cursor over the error in the bottom buffer, type Ctrl-C Ctrl-C, and the top buffer will display the line of code where the compile error occurred. Pretty slick for old school, huh?

Class Adjourned

You've covered a lot of ground here. For starters, you know how to compile platform-independent OpenGL code on the Macintosh. You've created a simple makefile to use for building the OpenGL code. And you know how build applications in EMACS. Putting it all together, you have a great starting point if you want to learn OpenGL application development on the Macintosh.

Mastering the makefile will help you load the platform-independent examples you find on the internet. The UNIX flavor of OpenGL examples do run with little or no modification. You may want to visit the nehe.gamdev.net and opengl.org for some great tutorials and examples.

Mac OS X Panther for Unix Geeks

Related Reading

Mac OS X Panther for Unix Geeks
Apple Developer Connection Recommended Title
By Brian Jepson, Ernest E. Rothman

Michael J. Norton is a software engineer at Cisco Systems.


Return to MacDevCenter.com.