Using GLSurfaceView (Easy OpenGL ES) Android

Several new classes were introduced with Android 1.5 (API Level 3) that you can use to simplify application OpenGL ES implementation. The GLSurfaceView and GL Surface View.Renderer classes effectively require less code to write so that you can focus on the actual GL drawing process instead of the implementation details and upkeep necessary to handle OpenGL ES calls. Essentially, the GLSurfaceView class handles the EGL initialization, threading, and calls in to a user-defined Renderer class. The Renderer class handles the drawing and GL initialization.

To use the GLSurfaceView class, you must either extend it or instantiate it directly. Either way, you then need to provide an implementation of a GLSurface View .Renderer class. The Renderer class must contain appropriate callbacks for drawing and GL initialization. Additionally, the Activity must pass onPause() and onResume() events on to the GLSurfaceView. The EGL initialization is handled by the GLSurfaceView object, and threading is used to offload the processing away from the main thread.

The following code demonstrates an entire Activity that duplicates the colorful triangle we drew earlier in this chapter:

public class AndroidOpenGL extends Activity {
CustomSurfaceView mAndroidSurface = null;
protected void onPause() {
super.onPause();
mAndroidSurface.onPause();
}
protected void onResume() {
super.onResume();
mAndroidSurface.onResume();
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAndroidSurface = new CustomSurfaceView(this);
setContentView(mAndroidSurface);
}
private class CustomSurfaceView extends GLSurfaceView {
final CustomRenderer mRenderer = new CustomRenderer();
public CustomSurfaceView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
setRenderer(mRenderer);
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_P:
queueEvent(new Runnable() {
public void run() {
mRenderer.togglePause();
}
});
return true;
}
return super.onKeyDown(keyCode, event);
}
}
private class CustomRenderer implements
GLSurfaceView.Renderer {
TriangleSmallGLUT mTriangle = new TriangleSmallGLUT(3);
boolean fAnimPaused = false;
public void onDrawFrame(GL10 gl) {
if (!fAnimPaused) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT |
GL10.GL_DEPTH_BUFFER_BIT);
gl.glRotatef(1f, 0, 0, 1f);
if (mTriangle != null) {
mTriangle.drawColorful(gl);
}
}
}
public void togglePause() {
if (fAnimPaused == true) {
fAnimPaused = false;
} else {
fAnimPaused = true;
}
}
public void onSurfaceChanged(GL10 gl, int width,
int height) {
gl.glViewport(0, 0, width, height);
// configure projection to screen
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
float aspect = (float) width / height;
GLU.gluPerspective(gl, 45.0f, aspect, 1.0f, 30.0f);
}
public void onSurfaceCreated(GL10 gl,
EGLConfig config) {
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// configure model space
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 0, 10f, 0, 0, 0, 0, 1, 0f);
gl.glColor4f(1f, 0f, 0f, 1f);
}
}}

As you can see, this code demonstrates creating a new GLSurfaceView and a new GLSurfaceView.Renderer. The end result, with proper implementation of the triangle drawing class (included with the book code and discussed earlier in this chapter), is a spinning triangle that the user can pause with the press of the P key. The GLSurfaceView implementation contains its own renderer, which is less generic than assigning it externally, but with the key handling we implemented. The two classes must work closely together.

The GLSurfaceView implements key handling by overriding the onKeyDown() method of the regular View class. The action is passed on to the Renderer through a helper method called queueEvent().The queueEvent() method passes the Runnable object on to the Renderer thread held by the GLSurfaceView.

Next, the Renderer implementation provides the drawing in the onDrawFrame() method. This is either called continuously or on demand, depending on the render mode set via a call to the GLSurfaceView.setRenderMode() method. The implementation of onSurfaceChanged() is now where we set up the screen projection—an appropriate place because this method is called on orientation or size changes of the surface. Then, in onSurfaceCreated(), the basic GL configuration is performed, including setting client states and static data, such as the model view.

All EGL configuration is now performed internally to GLSurfaceView, so the application need not worry about it. If, however, the application needs to perform custom configuration of the EGL, the EGLConfig object is passed to the onSurfaceCreated() method and is used to perform such custom configuration. If you choose to use this method to bring up a GL surface on Android, the implementation of the rendering code doesn’t need to change at all.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Android Topics