Tải bản đầy đủ (.pdf) (10 trang)

3D Graphics with OpenGL ES and M3G- P26 potx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (137.82 KB, 10 trang )

234 MISCELLANEOUS OPENGL ES FEATURES CHAPTER 10
10.4 EXTENSIONS
OpenGL ES inherits the extension mechanism of the desktop OpenGL. Any vendor can
create their own extensions to the basic behavior. Additionally, the OpenGL ES specifica-
tion defines a few optional extensions that are likely to be implemented by several vendors,
as it would not be very useful if the vendors implemented them in slightly different ways.
We first explain the mechanism for querying which extensions are present and obtaining
pointers to the extension functions. We continue by describing three extensions: query
matrix, matrix palette, and draw texture.
10.4.1 QUERYING EXTENSIONS
The list of supported extensions can be queried by calling glGetString with the argu-
ment GL_EXTENSIONS. This call returns a space-separated string containing the list of
all supported extensions. The application can thenparse this string and use an OS-specific
mechanism for obtaining access to the extension functions. If the platform supports EGL,
then the function eglGetProcAddress can be used for receiving the address of an
extension function:
/* define a function pointer of the right type, set to NULL */
void (*_glDrawTexx)(GLfixed, GLfixed, GLfixed, GLfixed, GLfixed) = NULL;
if( strstr( glGetString( GL_EXTENSIONS ), "GL_OES_draw_texture" ) )
{
_glDrawTexx = (void (*)( GLfixed, GLfixed, GLfixed, GLfixed, GLfixed ))
eglGetProcAddress( "glDrawTexxOES" );
}
In the example the return value from eglGetProcAddress is cast to a function pointer
that matches the extension function prototype. If your implementation has the glext.h
header file that contains a ready-made prototype for the extension, you can use it instead.
Note that eglGetProcAddress does not work for the core OpenGL ES func-
tions. When extensions are folded into the core in newer versions, the extensions for
the same functionality are also left in place so that they can still be queried with
eglGetProcAddress.
10.4.2 QUERY MATRIX


The OES_query_matrix extension introduces the function glQueryMatrixxOES
that can be used for reading back the top of the current matrix stack. This somewhat
surprising function was introduced in OpenGL ES 1.0 as there was no support for any
dynamic state queries, yet the working group felt that mat rix read-back would be useful
at least for debugging purposes. The function returns the matrix components’ mantissas
and exponents separately, thus providing a representation that is independent of the
actual internal implementation of the matrix stack.
SECTION 10.4 EXTENSIONS 235
GLbitfield glQueryMatrixxOES(GLfixed mantissa[16], GLint expone nt[16])
queries the matrix at the top of the current matrix stack. The mantissa array will contain
the signed 16.16 mantissas of the 4×4 matrix, and the exponent array the exponents. Each
entry is then mantissa ∗ 2
exponent
. The function returns status, which is a bitfield, which is
zero if all the components are valid. If status & (1<<i) != 0, then component
i is invalid (e.g., NaN or +−infinity). The following example queries the elements of the
current matrix and converts them to floats. The mantissa is first converted to a float, then,
depending on the sign of the exponent, it is either multiplied or divided by a suitable
poweroftwo.
int i,j;
GLfixed mantissa[16];
GLint exponent[16];
GLfloat matrix[16];
GLbitfield status;
status = glQueryMatrixxOES( mantissa, exponent );
if( 0 == status )
{
for(i=0;i<16;i++)
{
float t = (float)mantissa[i] / 65536.0f;

matrix[i]=t*pow( 2, exponent[i] );
}
}
Note that this extension has been deprecated in OpenGL ES 1.1. A new extension,
OES_matrix_get is provided instead. This allows querying the internal floating-point
matrices as integer bit patterns.
10.4.3 MATRIX PALETTE
Vertex skinning is brought into OpenGL ES by the optional OES_matrix_palette
extension. This is a somewhat simplified version of the ARB_matrix_palette exten-
sion from the desktop world. Matrix palettes were first introduced to OpenGL ES in
version 1.1.
Here is a short example code that first checks whether the optional extension is supported,
then queries the extension function pointers, sets up the required OpenGL ES state to use
the matrix palette, and finally sets up a few matrices in the matrix palette:
/* Check if extension is supported, bail out if not */
if( !strstr( glGetString(GL_EXTENSIONS), "GL_OES_matrix_palette" ) )
{
return NULL;
}
236 MISCELLANEOUS OPENGL ES FEATURES CHAPTER 10
/* Get the extension function pointers and store to global store */
_glCurrentPaletteMatrix =
(void (*)(GLuint))
eglGetProcAddress( "glCurrentPaletteMatrixOES" );
_glLoadPaletteFromModelViewMatrix =
(void (*)(void))
eglGetProcAddress( "glLoadPaletteFromModelViewMatrixOES" );
_glMatrixIndexPointer =
(void (*)( GLint, GLenum, GLsizei, const GLvoid * ))
eglGetProcAddress( "glMatrixIndexPointerOES" );

_glWeightPointer =
(void (*)( GLint, GLenum, GLsizei, const GLvoid * ))
eglGetProcAddress( "glWeightPointerOES" );
_glWeightPointer( 3, GL_FLOAT, 0, mtxweights );
_glMatrixIndexPointer( 3, GL_UNSIGNED_BYTE, 0, mtxindices );
glEnableClientState( GL_MATRIX_INDEX_ARRAY_OES );
glEnableClientState( GL_WEIGHT_ARRAY_OES );
glEnable( GL_MATRIX_PALETTE_OES );
/* set up basic modelview matrix */
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0, 0, -4.f );
glScalef( 0.2f, 0.2f, 0.2f);
/* set up matrices in palette indices 0 and 1 */
glMatrixMode( GL_MATRIX_PALETTE_OES );
_glCurrentPaletteMatrix( 0 );
_glLoadPaletteFromModelViewMatrix();
glTranslatef( 0.7f, 0, 0 );
_glCurrentPaletteMatrix( 0 );
_glLoadPaletteFromModelViewMatrix();
glTranslatef( -0.2f, 0, 0 );
void glCurrentPaletteMatrixOES(GLuint matrixpaletteindex)
defines which matrix is affected by future matrix manipulation calls.
void glLoadPaletteFromModelViewMatrixOES(void)
copies the top of the modelview matrix stack to the current matrix palette.
void glMatrixIndexPointerOES(GLint size, GLenum type, GLsizei stride, const
GLvoid * pointer)
defines an array of matrix indices. The parameter size determines the number of indices
per vertex, type is the data type of the indices (only GL_UNSIGNED_BYTE accepted),
SECTION 10.4 EXTENSIONS 237

stride is the stride in bytes between consecutive matrix indices, and pointer points to
the matrix index of the first vertex in the array. This vertex array is enabled by calling
glEnableClientState with the argument GL_MATRIX_INDEX_ARRAY_OES.
void glWeightPointerOES(GLint size, GLenum type, GLsizei stride, const
GLvoid * pointer)
defines an array of matrix weights. The parameter size defines the number of weights per
vertex, type is the data type used for the weights (GL_FIXED and GL_FLOAT are sup-
ported), str ide is the stride in bytes between consecutive weights, and pointer points to the
first weight of the first vertex. This vertex array is enabled by calling glEnableClient
State with the argument GL_WEIGHT_ARRAY_OES.
There are several state queries that become possible if the matrix palette extension is
supported. They are
GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES the buffer object name
bound to the matrix index array.
GL_MATRIX_INDEX_ARRAY_SIZE_OES the number of matrix indices per vertex.
GL_MATRIX_INDEX_ARRAY_STRIDE_OES the by te offset between elements.
GL_MATRIX_INDEX_ARRAY_TYPE_OES the type of matrix indices.
GL_MAX_PALETTE_MATRICES_OES the number of supported matrix palettes
(≥ 9).
GL_MAX_VERTEX_UNITS_OES the number of supported matrices per vertex (≥ 3).
GL_WEIGHT_ARRAY_BUFFER_BINDING_OES the buffer object name bound to
weight array.
GL_WEIGHT_ARRAY_SIZE_OES the number of weights per vertex.
GL_WEIGHT_ARRAY_STRIDE_OES byte offset between weights.
GL_WEIGHT_ARRAY_TYPE_OES type of weights.
void glGetPointerv(GLenum pname, void ** params)
supports two additional tokens:
GL_MATRIX_INDEX_ARRAY_POINTER_OES
GL_WEIGHT_ARRAY_POINTER_OES
GLboolean glIsEnabled(GLenum cap)

supports these additional capabilities:
GL_MATRIX_PALETTE_OES
GL_MATRIX_INDEX_ARRAY_OES
GL_WEIGHT_ARRAY_OES
238 MISCELLANEOUS OPENGL ES FEATURES CHAPTER 10
Pitfall: Implementations only need to support 9 bones for a single vertex array. How-
ever, many models use more bones than 9, for example, a human character typi-
cally requires at least 15, even over 40 bones. If the model uses more bones than the
OpenGL ES implementation can handle, you have to split the model into smaller par-
titions and render the mesh with several glDrawElements calls.
10.4.4 DRAW TEXTURE
The OES_draw_texture extension introduced in OpenGL ES 1.1 provides a mech-
anism for rendering a two-dimensional texture-mapped pixel rectangle to a rectangular
portion of the screen.
void glDrawTex{sifx}OES(T x, T y, T z, T width, T height )
renders a texture-mapped pixel block to the screen. Here x and y define the window coor-
dinates of the lower-left corner of the rectangle, and z is a value between 0 and 1 where
0 maps to the near plane and 1 maps to the far plane of the current depth range. The
parameters width and height give the size of the screen rectangle in pixels.
void glDrawTex{sifx}vOES(const T * coords)
provides variants that take the five input coordinates as an array.
10.4.5 USING EXTENSIONS
When using an extension, you should first implement a generic version, and switch to the
faster-executing extension only if it is available. The following example shows how this
is done. Here point sprites are the preferred method, draw texture comes next, and the
ultimate fall-back is to render two texture-mapped tr iangles. For the complete drawing
code, see the full example on the accompanying web site.
{
/* initial values for decision variables */
int oes11 = 0;

int drawtexture = 0;
int pot = 0;
int pointsize = 0;
/* check GL version */
ver = glGetString( GL_VERSION );
major = ver[strlen(ver)-3];
minor = ver[strlen(ver)-1];
if(minor > ’0’) oes11 = 1;
/* Check drawtexture extension */
if( strstr( glGetString(GL_EXTENSIONS), "GL_OES_draw_texture" ) )
SECTION 10.4 EXTENSIONS 239
{
drawtexture = 1;
_glDrawTexx = (void (*)( GLfixed, GLfixed, GLfixed, GLfixed,
GLfixed ))
eglGetProcAddress( "glDrawTexxOES" );
}
Next, we check whether the dimensions of the source are powers of two and whether the
source region size is inside the supported point size range.
/* check if dimensions are power-of-two */
if(( getnextpow2( image_width ) == image_width ) &&
( getnextpow2( image_height ) == image_height ))
{
pot=1;
}
/* is the size supported? Supported point sprite
range is the same as aliased point size range */
{
GLfloat pointsizerange[2];
glGetFloatv( GL_ALIASED_POINT_SIZE_RANGE, pointsizerange );

if(( image_width >= pointsizerange[0] ) &&
( image_height <= pointsizerange[1] ))
{
pointsize = 1;
}
}
Now the decision variables are ready for a final decision on which method is going to be
used for rendering. The basic fall-back is to draw the region using two triangles.
/* if everything else fails, use two triangles */
method = BLIT_DRAW_METHOD_TRIANGLES;
/* if width == height AND power of two AND we have OpenGL ES 1.1 AND
the point size is inside the supported range we use point sprites */
if( ( BLIT_WIDTH == BLIT_HEIGHT ) && oes11 && pot && pointsize )
{
method = BLIT_DRAW_METHOD_POINTSPRITE;
}
else if(drawtexture)
{
/* if draw_texture extension is supported, use it */
method = BLIT_DRAW_METHOD_DRAWTEXTURE;
}
Each of these methods has different setup and drawing codes. Refer to the blit example
on the companion web site for a fully working example that also does the setup of the
240 MISCELLANEOUS OPENGL ES FEATURES CHAPTER 10
methods and actual rendering. The example also shows the correct handling of point
clipping for point sprites.
If you end up using a pair of texture-mapped triangles, the easiest approach is to set the
modelview matrix, projection matrix, and v iewport so that a single step in the x or y
direction in vertex data is equal to a step of a single pixel on the display.
11

CHAPTER
EGL
When the desktop OpenGL API was first specified, the windowing system and operating
system dependent parts were left out of the core specification. Different windowing sys-
tems have their own ways to handle displays, windows, graphics devices, and contexts, and
different operating systems developed their own companion APIs for initializing graphics
resources. For X11 there is GLX, Mac has AGL, and Windows uses WGL.
Even though all of these APIs differ from each other, it is possible to create a “template
API” that mostly abstracts out platform differences, but allows platform-dependent data
types to be used where absolutely necessary. EGL unifies the OpenGL ES–related resource
management across platforms, and defines standard function names and tokens for
the implementations and applications to use. This increases source-level portability for
OpenGL ES applications across the many operating systems in the mobile domain,
e.g., Symbian, BREW, Linux, and Palm OS.
Some parameter types in EGL are really placeholders for OS-specific types. For example
EGLDisplay eglGetDisplay(NativeDisplayType display_id)
takes in an OS-dependent display type, initializes EGL to use that display, and returns an
OS-independent type EGLDisplay. NativeDisplayType is usually typedef ’d, as the
name implies, to a handle to the native display type.
With this approach application developers ideally need only to change a few lines in their
EGL initialization code when porting from one platform to another. Typically, an appli-
cation developer only needs to take care of initializing the platform-dependent window,
241
242 EGL CHAPTER 11
and to provide it as a parameter to eglCreateWindowSurface. All other EGL calls
are portable across the different platforms.
One thing to note is that EGL is an optional API—platforms are free to choose how
they bind their windowing with OpenGL ES. Luckily most platforms that have adop-
ted OpenGL ES have also chosen to suppor t EGL. This is good news for application
portability.

This chapter begins w ith an example and an overview of the EGL functionality, then pro-
ceeds to describe EGL configuration, the different surface types supported by EGL, and
the OpenGL ES/EGL context. We cover EGL extensions and describe how the surfaces
can be used to mix OpenGL ES and other graphics library calls. We also cover additions
introduced by EGL 1.1: optional support for rendering directly into texture maps, and
better support for power events and power optimization.
11.1 API OVERVIEW
Here is a walk-through of a simplified EGL initialization code without er ror checking.
#include <GLES/egl.h>
const EGLint attrib_list[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 16,
EGL_NONE
};
EGLDisplay display;
EGLConfig config;
EGLContext context;
EGLSurface surface;
void initEgl( void )
{
int numofconfigs;
display = eglGetDisplay( EGL_DEFAULT_DISPLAY );
eglInitialize( display, NULL, NULL );
eglChooseConfig( display, attrib_list, &config, 1,
&numofconfigs );
context = eglCreateContext( display, config,

EGL_NO_CONTEXT, NULL );
/* replace WINDOW() with the OS dependent window type */
surface = eglCreateWindowSurface( display, config,
WINDOW(), NULL );
SECTION 11.1 API OVERVIEW 243
eglMakeCurrent( display, surface, surface, context );
}
void renderOneFrame( void )
{
/* some GL rendering calls */
eglSwapBuffers( display, surface );
}
void terminateEgl( void )
{
eglMakeCurrent( display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT );
eglDestroySurface( display, surface );
eglDestroyContext( display, context );
eglTerminate( display );
}
First, we need to acquire a display. Some devices may support multiple displays, but in this
example we simply use the default display, which we can do in a source-level portable way
using the token EGL_DEFAULT_DISPLAY. Other than the default display, the display
handling is platform-dependent, and you need to consult platform documentation to find
out how displays are controlled. On some systems the display control may partially take
place even outside EGL.
EGLDisplay eglGetDisplay void can be used to get the currently active display
that is associated with the current context.
After the display handle has been acquired, EGL is initialized with
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint * major, EGLint * minor)

which returns EGL_TRUE on success, and if major and minor are not NULL they are filled
with the EGL version number. If initialization fails, the function returns EGL_FALSE and
sets up an error flag, w hich can be retrieved with
EGLint eglGetError(void)
Possible errors returned by eglGetError are listed in Table 11.1.
After EGL has been initialized, you need to select a buffer configuration. Either
eglChooseConfig or eglGetConfigs may be used to choose the configuration
that best matches the given attributes. In the example code we simply retrieve a configu-
ration that has at least 8 bits for each of the red, green, and blue color channels, at least 16
bits for the depth buffer, and that supports window surfaces (different surface types are
covered later).
After a configuration is chosen, a surface and a context can be created. Contexts are con-
tainers that carry the whole internal state of OpenGL ES. You can use several contexts for
each surface or use the same context for different surfaces. Surfaces represent containers
where the actual rendered pixels will end up. In this example, we create a window surface,
so the pixels will end up inside a window on the device display.

×