CS315 Lab 7: OpenGL ES


Highlights of this lab:

This lab is an introduction to OpenGL ES programming on the iPod Touch and iPhone. The assignment is based on the vertex array solution to last week's Thunderbird lab.

Assignment:

Online OpenGL ES 1.1 Manual


Seminar Notes

"OpenGL® ES is a royalty-free, cross-platform API for full-function 2D and 3D graphics on embedded systems - including consoles, phones, appliances and vehicles. It consists of well-defined subsets of desktop OpenGL, creating a flexible and powerful low-level interface between software and graphics acceleration. OpenGL ES includes profiles for floating-point and fixed-point systems and the EGL™ specification for portably binding to native windowing systems. OpenGL ES 1.X is for fixed function hardware and offers acceleration, image quality and performance. OpenGL ES 2.X enables full programmable 3D graphics. OpenGL SC is tuned for the safety critical market.

"For fixed function hardware: OpenGL ES 1.1 is defined relative to the OpenGL 1.5 specification and emphasizes hardware acceleration of the API, but is fully backwards compatible with 1.0. It provides enhanced functionality, improved image quality and optimizations to increase performance while reducing memory bandwidth usage to save power. The OpenGL ES 1.1 Extension Pack is a collection of optional extensions added to OpenGL ES 1.1 that reduced variability and bring significant improvements in image quality and performance."

Khronos.org OpenGL ES Overview

A. Starting an OpenGL ES Project

You need XCode, the iPhone SDK and a Mac to write applications for the iPhone and Touch. If you have a Mac, you can download the iPhone SDK and XCode from http://developer.apple.com/iphone/. You need to register with Apple as a developer if you want XCode and access to their programmind documentation. You also need a bit of time - the download is large. The install is easy, but you should read through their instructions to be safe.

The iPhone SDK for XCode provides several templates for building iPhone applications and libraries. We will build our OpenGL ES project with one of these.

I would like to accommodate you if you want to try your program on a real iPhone or iPod device. However, I have never provisioned devices other than my own, so it may turn out to be more work than is possible within the lab.

B. Tour of the Major Components

Objective-C and C++

As you explore the code you will notice that there are .h files and .m files. These are the extensions for the Objective-C language.

Although OpenGL ES is an established standard for embedded 3D that is available on many platforms, the way to access it is different on every platform. The popular Apple iPhone line of products presents a special problem for programmers new to Apple development. The default programming language for Apple UI products is Objective-C. Objective-C is a C based OOP language that is very different from C++. Its class definition and member calling syntax is very alien to those familiar with Java, C# or C++. Fortunately, if you are programming OpenGL ES, you can mostly ignore Objective-C because OpenGL ES is a C based library that is very similar to OpenGL and Objective-C is extremely compatible with C and C++.

To write and include C++ code in your iPhone programs you can signal to the compiler that you want to use the Objective-C++ flavour of the language. To do this simply change all .m files to .mm files.

The new constructs in Objective-C deal primarily with object oriented programming. The following is a quick primer so that you know what you are reading in the code today.

If you want to learn more about Objective-C programming, you can pick up excellent tutorial style resources like Cocoa Programming for Mac OS X, you can read Apples Objective-C Primer, read the Objective-C Language Book, or learn as you go with tutorials from the iPhone Development Guide.

Source files

main.m - in the Other Sources folder.
Its sole purpose is to house main() which starts memory management and hands execution over to the UI toolkit.
 
*AppDelegate.h/m - in the Classes folder
In Cocoa, the UI toolkit used on the iPhone and Mac, some classes specialize their behaviour by handing jobs over to other classes called delegates. Delegates are supposed to implement functions that match certain prototypes. They are often used to handle UI events.

The *AppDelegate class is designed in intercept application start, and stop events and send signals to our OpenGL ES class. In this application the delegates set appropriate framerates for different application states.
 
EAGLView.h.m - in the Classes folder.
This is where OpenGL ES allocation and deallocation happens. You will need to modify this code if you want any special purpose buffers like a depth buffer. It is also the best place for resize code.
 
*ViewController.h/m - in the Classes folder.
This is where you will do most of your OpenGL magic. This controller responds to draw and interaction events. It has functions that correspond to draw, and init. It also provides an animation timer. It initializes its view member to an instance of the EAGLView class and is able to call its public functions.

Selected EAGLView Class Members

framebufferWidth and framebufferHeight
Provide information about the dimensions of the OpenGL rendering area in pixels. Their values are set by the private createFramebuffer function.
 
context
Pointer to the Open GL ES Rendering Context for this class.
 
colorRenderbuffer, defaultFramebuffer
GLuint pointers to rendering memory. These would normally be aquired as part of the Hardware Context, but the iPhone uses dynamically allocated Frame Buffer Objects as render targets. You will need to allocate a depth buffer as one is not provided in the demo.
 
setFramebuffer
Performs tasks necessary to prepare the framebuffer object for drawing. This function should be called before the controller tries to draw anything with the drawFrame function. The demo places glViewport() here so we will place ChangeSize here.
 
presentFramebuffer
Performs the equivalent of a buffer swap in a double buffered system. It "presents" the drawing results in the color buffer to the world.
 
dealloc
This is EAGLView's destructor.

Selected *ViewController Members

 
context
Pointer to the Open GL ES Rendering Context for this class.
 
program
OpenGL pointer for a shader program.
 
animating
State variable that keeps track of whether animation is happening. Represents whether the displayLink animation timer is running.
 
displayLink
A timer object that is set by the startAnimation function to call drawFrame after a time specified by animationInterval.
 
animationInterval
This value controls the maximum frame rate for your OpenGL ES app. The interval is specified in refresh cycles. The default interval is 1 refresh. This results in 60FPS on a 60Hz monitor.
 
awakeFromNib
This is the closest thing the display controller has to a constructor. The OpenGL view is allocated, we aquire a pointer to it and bind it as the current Rendering Context. The end of this function is a good place to place your own OpenGL ES init code. Note that the animation rate is set in this function.
 
drawFrame
This is where we do our OpenGL ES drawing. The demo version of this function performs init and resize tasks that are better placed elsewhere. The lab exercise will guide you through where to place this code.
 
startAnimation, stopAnimation, setAnimationTimer, setAnimationInterval
Used to control the animation and framerate of your application. The timer is started and stopped by the delegate functions in *AppDelegate depending on whether the application is active.
 
dealloc
This is the view controller's destructor.

C. OpenGL ES 1.1

Once you know where to put your OpenGL ES calls you need to know the calls to use. Fortunately, they are mostly the same as the OpenGL ones you already know. There are some differences, though. Here are a few you will run into:

I encourage you to learn about these by trial and error. As you work on this week's lab refer to the OpenGL ES man pages for equivalents to functions that give you compile errors, and to find constants that seem to have gone missing.

Unfortunately, Apple does not document OpenGL ES or its management class, EAGL, very well. If you want to learn more about OpenGL ES programming on the iPhone, you can refer to the excellent iPhone Development blog.


Lab Exercise

In this exercise you will port the Vertex Arrays portion of Thunderbird to the iPhone.

Goals:

Instructions:

  1. (Optional) It is possible to deploy your application to your iOS device. To do this:
  2. Start with a new OpenGL ES iPhone Application.
  3. By default iPhone apps are written in Objective-C which is C based. To be able to mix C++ into your application you need to signal the compiler that you want to use Objective-C++. The way to do this is to use the .mm extension on your Objective-C files. Change all .m files to .mm files.

  4. Copy the following files from your Thunderbird solution to your iPhone project and add them: You can copy the files directly from your Thunderbird solution by using Add Existing Files and selecting Copy items into destination group's folder (if needed) after you have selected the files and clicked Add. There should be no need to place things in folders, but you may do so if you wish. The textures, in particular, will be copied to the built app's Resource folder automatically when you build.

  5. OpenGL ES requires different headers than OpenGL did.
    Add the following includes to body.cpp, glass.cpp and thunderbird.cpp:
    #include <OpenGLES/ES1/gl.h>
    #include <OpenGLES/ES1/glext.h>
    Remove any references to the old OpenGL or GLUT headers.

  6. Resource files for iOS apps have complex paths that change from device to device. You will need special functions to learn this path for each file you want to load. The Objective-C function for this is a member of the application's main bundle called pathForResource:. Details for loading an image with Objective-C are here. This function is not available from C++, but you can add this file to your project to get the path: ResourceLoader.h. To use it:
  7. Clean up functions in Thunderbird.cpp to remove code that is incompatible with OpenGL ES. You should remove the following functions:
  8. Create a thunderbird.h header file that exports the functions needed to initialize and run your program
    extern void SetupRC();
    extern void RenderScene();
    extern void ChangeSize(int w, int h);
  9. In your *ViewController.mm file:

  10. In EAGLView.mm:
  11. BONUS: Add touch interaction to rotate the plane.

Deliverables

Bring your completed work to lab next week. We will be doing lab evaluations, marking wrap up and Q&A.

References