164 INTRODUCING OPENGL ES CHAPTER 7 implementations currently support it. The stencil operations GL_INCR_WRAP and GL_DECR_WRAP have been omitted. OpenGL ES blending functionality conforms to OpenGL 1.1, rather than version 1.3 like the rest of the API. This eliminates functions such as glBlendFuncSeparate, glBlendEquation, and glBlendColor that were introduced in OpenGL 1.2. Frame buffer operations The most significant changes relate to the frame buffer operations. There is only a sin- gle drawing buffer, and accumulation buffering is not supported. The entire imaging subset has been removed. 2D rendering through glDrawPixels or glBitmap is not supported, as it can be emulated with a texture-mapped pair of triangles. The depth and stencil buffers cannot be read back, as glReadBuffer and glCopyPixels have been omitted. glReadPixels is supported, although with a very limited number of pixel formats. Miscellaneous Evaluators, feedback, selection, and display lists have been omitted since they have a high implementation burden and can be reasonably easily emulated in the application. With the exception of display lists these features are not wi dely used even in desktop OpenGL. OpenGL ES 1.0 supports only queries for static state whose values are defined when an OpenGL context is created, and will not change during execution. This means that an application must track its own state as it cannot be queried back from GL. An optional extension glQueryMatrixxOES was created to enable reading back the current matrix values. The convenience routines for saving and restoring the state via the attribute stacks are not supported. 7.4.3 NEW FEATURES IN OPENGL ES 1.1 OpenGL ES 1.1 was first int roduced at SIGGRAPH 2004. This version is clearly more hardware-oriented than its predecessor, with features targeted at gaming applications and for higher-level APIs such as M3G. Nevertheless, software implementations of OpenGLES 1.1 remain feasible. Vertex buffer objects Vertex buffer objects that allow encapsulating and storing vertex data on the server side are supported. However, to simplify efficient implementations, reading back the buffered vertex and index data is not allowed. SECTION 7.4 API OVERVIEW 165 Point sprites OpenGL ES 1.1 introduces point sprites for 2D billboards and particle effects. A point size array allows specifying an array of point sizes for efficient rendering of point sprites with differing sizes. The point sizes can also be attenuated as a function of distance from the camera. User clip planes and matrix palette User clip planes are supported, although the implementation is required to support only one. OpenGL ES 1.1 provides also an optional matrix palette extension for accelerating char- acter animation and vertex skinning. Texturing enhancements While the first version only requires one texturing unit, OpenGL ES 1.1 requires at least two texturing units. Automatic mipmap generation is supported. Also texture combiners are introduced (including bump mapping), only the crossbar functionality of combiners is not included. Draw texture An optional extension glDrawTex{sifx}[v]OES was created to support fast 2D ren- dering. The image data is given in a texture object, so that the data can be cached on the server. The glDrawPixels of OpenGL does not allow such caching. Dynamic state queries OpenGL ES 1.1 introduced dynamic state queries. The ability to query back the GL state makes the use of middleware libraries easier, as state does not have to be tracked externally. 7.4.4 EXTENSION MECHANISM The extensibility of OpenGL has always been one of its key strengths. It enables individual hardware vendors to add new features reflecting advances in hardware desig n. If these features prove successful in the marketplace, they are introduced as core features in future versions of the GL specification. OpenGL ES continues this tradition and the extension mechanism is an integral part of its design. There are several different kinds of extensions. The core extensions are mandatory com- ponents of the OpenGL ES specification that are not part of the desktop GL. The optional 166 INTRODUCING OPENGL ES CHAPTER 7 extensions are not strictly required. They are often the features that the working group expects to become a part of the core specification in the future, but does not yet feel comfortable mandating. Both the core and the optional extensions have the suffix OES added to their function names. The Vendor-specific extensions are introduced by individual hardware vendors to provide access to their hardware-specific features. These functions get their postfixes from the names of the companies providing them. Multi-vendor extensions (with postfix EXT)are used when multiple companies want to expose the same feature. Extensions often provide a faster and more efficient way of accomplishing a given task. Since the optional or the vendor-specific extensions are not particularly portable, we recommend that you first write a portable version of an algorithm using the core func- tionality, and then switch to using an extension if it is available on a given platform. 7.4.5 OPENGL ES EXTENSION PACK The OpenGL ES extension pack was introduced in August 2005. It is a collection of exten- sions found in some existing and upcoming devices. Features introduced in the extension pack include several improvements to the texturing system, e.g., texture crossbar, cube mapping, and the mirrored repeat mode. New blending modes as well as stencil buffering modes are introduced. The minimum requirements for the size of the matrix palettes are made more rigorous. Finally, the concept of frame buffer objects (FBOs) is introduced into OpenGL ES. 7.4.6 UTILITY APIS OpenGL ES does not contain any APIs for creating the windows and surfaces used as render targets. The portable way of doing this is using EGL, a companion API that acts as a glue between OpenGL ES and the operating system. EGL is similar to the WGL on Windows and GLX on X Windows, but designed to be portable across a number of embedded platforms. EGL is covered in more depth in Chapter 11. GLU and GLUT are other utility libr aries used on the desktop. Khronos has not speci- fied embedded variants for these. Instead, the libraries have been ported directly as an open source effort. 3 The GLU library sits on top of OpenGL ES and contains function- ality for creating various meshes, computing mipmaps, defining NURBS objects, and various helper functions for manipulating matrices. GLUT, on the other hand, is a cross- platform library for handling system-level input and output. This includes mouse event 3 glutes.sourceforge.net/ SECTION 7.4 API OVERVIEW 167 handling, keyboard input, timer events, and support for more exotic de vices. The library also provides some UI components such as pop-up menus. 7.4.7 CONVENTIONS OpenGL ES follows a number of conventions established by OpenGL. Some of the most important ones are briefly reviewed here. Prefixes and suffixes All GL functions are prefixed with the symbol gl (glViewport). Data types use the GL prefix (GLbyte) whereas macros and enumerants use the prefix GL_ (GL_LIGHT0). Functions specific to OpenGL ES use the suffix OES. Function names contain suffixes for indicating the types of their arguments. For example, glClearDepthf and glClearDepthx are two variants of the same function where the first takes its input parameters as floating-point and the latter as fixed-point numbers. The following data types are supported by OpenGL ES: b 8-bit integer GLbyte s 16-bit integer GLshort i 32-bit integer GLint, GLsizei, GLintptr, GLsizeiptr x 32-bit fixed point GLfixed, GLclampx f 32-bit floating point GLfloat, GLclampf ub 8-bit unsigned integer GLubyte, GLboolean us 16-bit unsigned integer GLushort ui 32-bit unsigned integer GLuint, GLenum, GLbitfield In the following text, if several argument types are possible, the type is denoted by T.For example, void glColor4{fx ub}(T red, T g reen, T blue, T alpha) is a shorthand for three function definitions void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) void glColor4x(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha). A suffix v is added to variants that take in a pointer to a parameter array as an argument, for example void glLight{fx}v(GLenum light, GLenum pname, const T * params) 168 INTRODUCING OPENGL ES CHAPTER 7 passes parameters in params while void glGetPointerv(GLenum pname, void ** params) returns parameters in params. State machine model OpenGL ES operates as a state machine. The state consists of various features being either turned on or off, and most capabilities are turned off by default. On the server, or the graphics engine side, the following calls are used to set the state: void glEnable(GLenum cap) void glDisable(GLenum cap) For example, to turn lighting on, one needs to enable both lighting itself and at least one light: glEnable( GL_LIGHTING ); glEnable( GL_LIGHT0 ); Starting from OpenGL ES 1.1, the function glIsEnabled can be used for querying whether a given server-side capability is enabled. The client-side, i.e., application or CPU-side, functions to enable and disable the use of various vertex arrays are: void glEnableClientState(GLenum array) void glDisableClientState(GLenum array) Error handling Instead of individual functions providing error codes as their return values, OpenGL ES uses a global error flag that is set whenever an error occurs in any of the API functions. Most GL functions validate their input parameters before modifying the internal GL state. If an invalid parameter is encountered, the global error flag is set, and the function returns without modifying the state. GLenum glGetError(void) returns the current error code and resets it to GL_NO_ERROR. The error codes are listed in Table 7.1. OpenGL allows dist ributed implementations to have a separate error flag for each replicated graphics unit, and in such a case you should call glGetError repeatedly until it returns GL_NO_ERROR. However, OpenGL ES implementations typically have only one graphics unit. It is a good programming practice, at least in debug builds, to call glGetError every now and then to check that no GL errors have occurred. Some debugging libraries even SECTION 7.4 API OVERVIEW 169 Table 7.1: GL error codes. Error Meaning Command ignored? GL_NO_ERROR No errors No GL_INVALID_ENUM Enum argument is out of range Yes GL_INVALID_VALUE Numeric value is out of range Yes GL_INVALID_OPERATION Operation illegal in current state Yes GL_STACK_OVERFLOW Command would cause a stack overflow Yes GL_STACK_UNDERFLOW Command would cause a stack underflow Yes GL_OUT_OF_MEMORY Not enough memory to execute command Unknown wrap every GL call with a glGetError and then raise an assertion immediately when an error occurs. Packaging The main header file is called GLES/gl.h, and it always has to be included. Additionally, most applications need to include EGL/egl.h.Thegl.h header also includes follow- ing version definitions: #define GL_VERSION_ES_CL_1_x 1 or #define GL_VERSION_ES_CM_1_x 1 depending on which profile is supported. x denotes the supported minor API version number. Pitfall: Even though the official OpenGL ES 1.0 specification states exactly how the version number definitions should be presented in the header file, many current GL header files define instead erroneously GL_OES_VERSION_1_x. For maximal porta- bility one should use a construct such as this in the source code: #if (defined(GL_OES_VERSION_1_0) || defined(GL_VERSION_ES_CM_1_0) When OpenGL ES and EGL were originally specified it was recommended that both APIs should be exposed from the same DLL. As new companion APIs that can be used with EGL emerged, such as OpenVG and OpenGL ES 2.0, this arrangement became burdensome as using EGL with OpenVG would require linking also to the OpenGL ES library which might not even be present on the device. For this reason a new linkage was specified where the EGL API is exposed from a separate link library and the client APIs from their separate libraries. Note that the actual linkage may vary as it is actually controlled typically by the operating system vendor or the device 170 INTRODUCING OPENGL ES CHAPTER 7 Table 7.2: Library naming scheme. Library content Name of the link library OpenGL ES 1.x with EGL (Common Profile) libGLES_CM.{lib,dll,a,so} OpenGL ES 1.x with EGL (Lite Profile) libGLES_CL.{lib,dll,a,so} OpenGL ES 1.x without EGL (Common Profile) libGLESv1_CM.{lib,dll,a,so} OpenGL ES 1.x without EGL (Lite Profile) libGLESv1_CL.{lib,dll,a,so} EGL libEGL.{lib,dll,a,so} vendor. For documentation on how the linkage is done for your particular device, see the SDK documentation for the platform. A recommended library naming scheme is presented in Table 7.2. 7.5 HELLO, OPENGL ES! Here is a simple OpenGL ES example that renders one smoothly shaded triangle on the display. Before any OpenGL ES calls can be executed, some resources need to be created with the EGL API. See Chapter 11 for more information on EGL. First we include some necessary headers, and define the vertex data: #include <GLES/gl.h> /* vertex data (3 vertices for single triangle) */ static const GLbyte vertices[3 * 3] = { —1,1,0, 1, — 1, 0, 1, 1, 0 }; static const GLubyte colors[3 * 4] = { 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255 }; Let us set the basic state. Here we assume a clean OpenGL ES context with the default state settings. If the initial state were totally unknown, much more initialization code would be required. glDisable( GL_DEPTH_TEST ); glShadeModel( GL_SMOOTH ); glClearColor( 0.f, 0.f, 0.1f, 1.f ); SECTION 7.5 HELLO, OPENGL ES! 171 Next, we set the array pointers for vertex and color arrays, and enable the corresponding arrays: glVertexPointer( 3, GL_BYTE, 0, vertices ); glColorPointer( 4, GL_UNSIGNED_BYTE, 0, colors ); glEnableClientState( GL_VERTEX_ARRAY ); glEnableClientState( GL_COLOR_ARRAY ); Then we set the view parameters: glViewport( 0, 0, width, height ); glMatrixMode( GL_PROJECTION ); glFrustumf( — 1.f, 1.f, — 1.f, 1.f, 3.f, 1000.f ); glMatrixMode( GL_MODELVIEW ); Next we have the main function that gets called in each render cycle. Here the code typi- cally clears the buffers and renders the frame. At first, we clear the color buffer, then set the camera, and finally draw the triangle. void render_frame( void ) { glClear( GL_COLOR_BUFFER_BIT ); glLoadIdentity(); glTranslatef( 0, 0, — 5.f ); glDrawArrays( GL_TRIANGLES, 0, 3 ); } A buffer swap is required at the end of the frame. How to do that will be introduced later in Chapter 11. This page intentionally left blank 8 CHAPTER OPENGL ES TRANSFORMATION AND LIGHTING This chapter covers the geometry pipeline of OpenGL ES. This includes primitive and vertex specification, matrix processing, and the interaction between light sources and materials. 8.1 DRAWING PRIMITIVES In this section we describe the geometric primitives supported by OpenGL ES. While there is also some support for raster primitives, we defer that discussion until we have introduced texture mapping. The geometric primitives are made of vertices, and each vertex can have properties such as position, color, surface normal, texture coordinate, and point size. We briefly describe the original OpenGL model for specifying vertex data, and then the newer way of specifying vertex arrays, which was adopted by OpenGL ES. We continue by explaining how the primitives are actually drawn using the vertex data. Finally we describe an alternative to vertex arrays that was introduced in OpenGL ES 1.1: vertex buffer objects (see Section 8.1.4). 173 . pipeline of OpenGL ES. This includes primitive and vertex specification, matrix processing, and the interaction between light sources and materials. 8.1 DRAWING PRIMITIVES In this section we describe. with EGL (Lite Profile) libGLES_CL.{lib,dll,a,so} OpenGL ES 1.x without EGL (Common Profile) libGLESv1_CM.{lib,dll,a,so} OpenGL ES 1.x without EGL (Lite Profile) libGLESv1_CL.{lib,dll,a,so} EGL libEGL.{lib,dll,a,so} vendor extensibility of OpenGL has always been one of its key strengths. It enables individual hardware vendors to add new features reflecting advances in hardware desig n. If these features prove successful in