OpenGL ES: A Subset of OpenGL
OpenGL ES 1.0 is defined as a subset of OpenGL 1.3. Because of the limits of embedded systems (small footprints, lower power consumption, and so on), many standard OpenGL features were not included in OpenGL ES. For instance, redundant primitives such as GL_QUADS
and later are gone, along with the entire glBegin/glEnd
immediate-mode paradigm. All geometry must be submitted via vertex arrays. Using immediate mode for geometry batches burns CPU cycles, which are at a premium on the devices for which OpenGL ES is intended.
Also gone from OpenGL ES are display lists, color index mode (good riddance), user-defined clipping planes, stippling, the imaging subset, feedback-and-selection, evaluators, edge flags, polygon modes, and saving-and-restoring attributes with the glPushAttrib
family of functions. Although vertex arrays are now the standard way to submit geometry, interleaved arrays and glArrayElement
have also been eliminated, and the entire GLU helper library is gone.
However, OpenGL ES does support fixed-point math via the data type GLfixed
, and many standard OpenGL functions now have fixed-point variants, each appended with the letter x
to indicate the arguments are fixed point. Functions that normally accept double-precision arguments (another feature dropped from OpenGL ES) are further updated to accept either floating-point or fixed-point values. For example, the glFrustum
function, which accepted double precision (type GLdouble
) parameters in OpenGL, is available in OpenGL ES as glFrustumx() and glFrustumf()
, which accept GLfixed
parameters and GLfloat
parameters, respectively.
Porting to the Gizmondo
The best introduction to OpenGL ES is porting existing OpenGL programs to the Gizmondo. I selected from my book The OpenGL SuperBible
(Pearson Education, 1999) a vertex-array example that rendered a 3D textured model on screen. The .TGA loader for textures compiled without any problems, and the main body of code that created and rendered the indexed array required only a few minor changes.
I also decided to load compressed textures via the .dds file format; I recommend this because texture memory is at a premium. According to my SDK notes, once the frame buffer is allocated on the Gizmondo, a mere 830 KB remain for textures. My source Targa file was 192 KB, but dropped to 33 KB when compressed and saved as a .dds file using an NVidia-provided Photoshop plug-in. It is also recommended (but not required) that you forgo mipmapping when possible to conserve even more texture space. I used code provided by NVidia for loading .dds files on Windows and found that it compiled and worked without any change on Windows CE.
The first problem with my existing code was that I used gluPerspective
to set up my 3D projection. The GLU library (ee.1asphost.com/vmelkon/glu.html) is not included, and I was forced to use glFrustum
. I find glFrustum
a pain to use, and anyone spoiled by gluPerspective
has to either learn to use glFrustum
, or write and use their own equivalent function. Of course, glFrustum
really isn't available; you must use either glFrustumf
or glFrustumx
.
The last hurdle to moving my sample was calculating and displaying the frame rate. Measuring the frame rate is necessary if you want to objectively measure any performance impacts to code changes and optimizations. On Windows, I created a C++ class that worked like a stopwatch. It uses the Win32 QueryPerformanceCounter
functions because there is no such hardware timing available on a handheld device. I was pleasantly surprised to learn that this function was supported by Windows CE, although not with the same accuracy and resolution as was available on the desktop. Because I was going to average 100 frames to determine the running frame rate, a little slop was going to be lost as noise, and I would still have a reasonably accurate measure of performance.
The real headache was in my text rendering code. Most desktop OpenGL implementations have some extensions that let you make use of OpenGL native fonts (these extensions are also missing from OpenGL ES). Game developers avoid these as they are often not very fast and don't look that great. The standard game technique for text is to load a texture with your character set and render billboarded quads on the screen, using texture coordinates to access individual characters. This is fast and allows for a good deal of creative freedom (slimy-looking or rust-themed letters, for instance).
My code that implemented this technique used immediate mode. I'd call glBegin
at the beginning of text rendering, send down any number of GL_QUADS
in an orthographic projection, and then finish with glEnd
. However, GL_QUADS
or the glBegin/glEnd
mechanism for submitting geometry are supported by OpenGL ES. Reengineering my text class to use small triangle strips and send down one letter at a time via vertex arrays was the only real nuisance to using OpenGL ES. Of course, this is the sort of thing you only have to do once and is easy to reuse from project to project.