- •Contents
- •Acknowledgments
- •Preface
- •What Makes Android Special?
- •Who Should Read This Book?
- •Online Resources
- •Fast-Forward >>
- •Introducing Android
- •Quick Start
- •Installing the Tools
- •Creating Your First Program
- •Running on the Emulator
- •Running on a Real Phone
- •Key Concepts
- •The Big Picture
- •Building Blocks
- •Using Resources
- •Safe and Secure
- •Android Basics
- •Designing the User Interface
- •Introducing the Sudoku Example
- •Designing by Declaration
- •Creating the Opening Screen
- •Using Alternate Resources
- •Implementing an About Box
- •Applying a Theme
- •Adding a Menu
- •Adding Settings
- •Starting a New Game
- •Debugging
- •Exiting the Game
- •Exploring 2D Graphics
- •Learning the Basics
- •Adding Graphics to Sudoku
- •Handling Input
- •The Rest of the Story
- •Making More Improvements
- •Multimedia
- •Playing Audio
- •Playing Video
- •Adding Sounds to Sudoku
- •Storing Local Data
- •Adding Options to Sudoku
- •Continuing an Old Game
- •Remembering the Current Position
- •Accessing the Internal File System
- •Accessing SD Cards
- •Beyond the Basics
- •The Connected World
- •Browsing by Intent
- •Web with a View
- •From JavaScript to Java and Back
- •Using Web Services
- •Locating and Sensing
- •Location, Location, Location
- •Set Sensors to Maximum
- •Putting SQL to Work
- •Introducing SQLite
- •Hello, Database
- •Data Binding
- •Using a ContentProvider
- •Implementing a ContentProvider
- •3D Graphics in OpenGL
- •Understanding 3D Graphics
- •Introducing OpenGL
- •Building an OpenGL Program
- •Rendering the Scene
- •Building a Model
- •Lights, Camera, ...
- •Action!
- •Applying Texture
- •Peekaboo
- •Measuring Smoothness
- •Fast-Forward >>
- •The Next Generation
- •Multi-Touch
- •Building the Touch Example
- •Understanding Touch Events
- •Setting Up for Image Transformation
- •Implementing the Drag Gesture
- •Implementing the Pinch Zoom Gesture
- •Hello, Widget
- •Live Wallpaper
- •Write Once, Test Everywhere
- •Gentlemen, Start Your Emulators
- •Building for Multiple Versions
- •Evolving with Android APIs
- •Bug on Parade
- •All Screens Great and Small
- •Installing on the SD Card
- •Publishing to the Android Market
- •Preparing
- •Signing
- •Publishing
- •Updating
- •Closing Thoughts
- •Appendixes
- •Bibliography
- •Index
RENDERING THE SCENE 202
We override the onPause( ) and onResume( ) methods so they can call the methods of the same name in the view.
We won’t need the layout resource (res/layout/main.xml), so you can delete it. Now let’s define our custom view class:
Download OpenGL/src/org/example/opengl/GLView.java
package org.example.opengl;
import android.content.Context; import android.opengl.GLSurfaceView;
class GLView extends GLSurfaceView { private final GLRenderer renderer;
GLView(Context context) { super(context);
// Uncomment this to turn on error-checking and logging //setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
renderer = new GLRenderer(context); setRenderer(renderer);
}
}
GLSurfaceView is a new class introduced in Android 1.5 that greatly simplifies using OpenGL in Android. It provides the glue to connect OpenGL ES to the view system and activity life cycle. It takes care of picking the appropriate frame buffer pixel format, and it manages a separate rendering thread to enable smooth animation. All GLView needs to do is extend GLSurfaceView and define a renderer for the view.
In the next section, we’ll fill the screen with a solid color.
10.4Rendering the Scene
As we saw in Section 4.2, Drawing the Board, on page 83, the Android 2D library calls the onDraw( ) method of your view whenever it needs to redraw a section of the screen. OpenGL is a bit different.
In OpenGL ES on Android, drawing is separated into a rendering class that is responsible for initializing and drawing the entire screen. Let’s define that now.
RENDERING THE SCENE 203
Here’s the outline for the GLRenderer class:
Download OpenGL/src/org/example/opengl/GLRenderer.java
package org.example.opengl;
import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10;
import android.content.Context; import android.opengl.GLSurfaceView; import android.opengl.GLU;
import android.util.Log;
class GLRenderer implements GLSurfaceView.Renderer { private static final String TAG = "GLRenderer"; private final Context context;
GLRenderer(Context context) { this.context = context;
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) { // ...
}
public void onSurfaceChanged(GL10 gl, int width, int height) { // ...
}
public void onDrawFrame(GL10 gl) { // ...
}
}
GLRenderer implements the GLSurfaceView.Renderer interface, which has three methods. Let’s start with the onSurfaceCreated( ) method, which is called when the OpenGL Surface (kind of like a Canvas in regular 2D) is created or re-created:
Download OpenGL/src/org/example/opengl/GLRenderer.java
Line 1 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
2// Set up any OpenGL options we need
3gl.glEnable(GL10.GL_DEPTH_TEST);
4gl.glDepthFunc(GL10.GL_LEQUAL);
5gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
6
7 // Optional: disable dither to boost performance
8 // gl.glDisable(GL10.GL_DITHER);
9}
RENDERING THE SCENE 204
On line 3, we set a couple of OpenGL options. OpenGL has dozens of options that can be enabled or disabled with glEnable( ) and glDisable( ). The most commonly used ones include the following:
Option |
Description |
GL_BLEND |
Blend the incoming color values with the values |
|
already in the color buffer. |
GL_CULL_FACE |
Ignore polygons based on their winding (clockwise |
|
or counterclockwise) in window coordinates. This is |
|
a cheap way to eliminate back faces. |
GL_DEPTH_TEST |
Do depth comparisons, and update the depth |
|
buffer. Pixels farther away than those already |
|
drawn will be ignored. |
GL_LIGHTi |
Include light number i when figuring out an object’s |
|
brightness and color. |
GL_LIGHTING |
Turn on lighting and material calculations. |
GL_LINE_SMOOTH |
Draw antialiased lines (lines without jaggies). |
GL_MULTISAMPLE |
Perform multisampling for antialiasing and other |
|
effects. |
GL_POINT_SMOOTH |
Draw antialiased points. |
GL_TEXTURE_2D |
Use textures to draw surfaces. |
All options are off by default except for GL_DITHER and GL_MULTISAMPLE. Note that everything you enable has some cost in performance.
Next let’s fill out the onSurfaceChanged( ) method. This method is called once after the Surface is created and then again whenever the size of the Surface changes:
Download OpenGL/src/org/example/opengl/GLRenderer.java
Line 1 public void onSurfaceChanged(GL10 gl, int width, int height) {
2// Define the view frustum
3gl.glViewport(0, 0, width, height);
4gl.glMatrixMode(GL10.GL_PROJECTION);
5gl.glLoadIdentity();
6float ratio = (float) width / height;
7 GLU.gluPerspective(gl, 45.0f, ratio, 1, 100f);
8}
Here we configure our view frustum and set a few OpenGL options. Note the call to the GLU.gluPerspective( ) helper function on line 7. The last two arguments are the distance from the eye to the near and far clipping planes (see Figure 10.1, on page 199).
RENDERING THE SCENE 205
Figure 10.2: That was a lot of trouble to get a black screen.
It’s time to draw something. The onDrawFrame( ) method is called over and over in the rendering thread created by the GLSurfaceView class.
Download OpenGL/src/org/example/opengl/GLRenderer.java
public void onDrawFrame(GL10 gl) {
//Clear the screen to black gl.glClear(GL10.GL_COLOR_BUFFER_BIT
| GL10.GL_DEPTH_BUFFER_BIT);
//Position model so we can see it gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0, 0, -3.0f);
//Other drawing commands go here...
}
To start with, we set the screen to black. We clear both the color and depth buffers. Always remember to clear both, or you’ll get some very