blob: 57403ea75dce26356e0e64b7e309b0cd88a4fdcb [file] [log] [blame]
Dirk Dougherty22558d02009-12-10 16:25:06 -08001page.title=Introducing GLSurfaceView
2@jd:body
3
4
5<p>The {@link android android.opengl.GLSurfaceView} class makes it
6easier for you to use OpenGL ES rendering in your applications by:</p>
7
8<ul>
9<li>Providing the glue code to connect OpenGL ES to the {@link
10android.view.View} system.</li>
11<li>Providing the glue code to make OpenGL ES work with the {@link
12android.app.Activity} life-cycle.</li>
13<li>Making it easy to choose an appropriate frame buffer pixel format.</li>
14<li>Creating and managing a separate rendering thread, to enable smooth
15animation.</li>
16<li>Providing easy-to-use debugging tools for tracing OpenGL ES API calls and
17checking for errors.</li>
18</ul>
19
20<p>GLSurfaceView is a good base for building an application that uses OpenGL ES
21for part or all of its rendering. A 2D or 3D action game would be a good
22candidate, as would a 2D or 3D data visualization application such as <a
23href="http://www.youtube.com/watch?v=4PRfVKzuUJ4&amp;fmt=18" title="Google Maps
24StreetView">Google Maps StreetView</a>.</p>
25
26<h3>A simple GLSurfaceView application</h3>
27
28<p>Here's the source code to the simplest possible OpenGL ES application:</p>
29
30<pre>package com.example.android.apis.graphics;
31
32import javax.microedition.khronos.egl.EGLConfig;
33import javax.microedition.khronos.opengles.GL10;
34
35import android.app.Activity;
36import android.opengl.GLSurfaceView;
37import android.os.Bundle;
38
39public class ClearActivity extends Activity {
40 &#64;Override
41 protected void onCreate(Bundle savedInstanceState) {
42 super.onCreate(savedInstanceState);
43 mGLView = new GLSurfaceView(this);
44 mGLView.setRenderer(new ClearRenderer());
45 setContentView(mGLView);
46 }
47
48 &#64;Override
49 protected void onPause() {
50 super.onPause();
51 mGLView.onPause();
52 }
53
54 &#64;Override
55 protected void onResume() {
56 super.onResume();
57 mGLView.onResume();
58 }
59
60 private GLSurfaceView mGLView;
61}
62
63class ClearRenderer implements GLSurfaceView.Renderer {
64 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
65 // Do nothing special.
66 }
67
68 public void onSurfaceChanged(GL10 gl, int w, int h) {
69 gl.glViewport(0, 0, w, h);
70 }
71
72 public void onDrawFrame(GL10 gl) {
73 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
74 }
75}</pre>
76
77<p>This program doesn't do much: it clears the screen to black on every frame.
78But it is a complete OpenGL application that correctly implements the
79Android activity life-cycle. It pauses rendering when the activity is
80paused, and resumes it when the activity is resumed. You could use this
81application as the basis for non-interactive demonstration programs.
82Just add more OpenGL calls to the <code>ClearRenderer.onDrawFrame()</code> method.
83Notice that you don't even need to subclass the <code>GLSurfaceView</code> view.</p>
84
85<p>The {@link android.opengl.GLSurfaceView.Renderer} interface has three methods:</p>
86
87<ul>
88<li>The
89<code>onSurfaceCreated()</code> method is called at the start of rendering, and
90whenever the OpenGL ES drawing context has to be recreated. (The
91drawing context is typically lost and recreated when the activity is
92paused and resumed.) <code>OnSurfaceCreated()</code> is a good place to create
93long-lived OpenGL resources such as textures.</li>
94<li>The <code>onSurfaceChanged()</code>
95method is called when the surface changes size. It's a good place to
96set your OpenGL viewport. You may also want to set your camera here, if
97it's a fixed camera that doesn't move around the scene.</li>
98<li>The <code>onDrawFrame()</code> method is called every frame, and is
99responsible for drawing the scene. You would typically start by calling
100<code>glClear</code> to clear the framebuffer, followed by other OpenGL ES calls
101to draw the current scene.</li>
102</ul>
103
104<h3>How about user input?</h3>
105
106<p>If you want an interactive application (such as a game), you will typically
107subclass <code>GLSurfaceView</code>, because that's an easy way of obtaining
108input events. Here's a slightly longer example showing how to do that:</p>
109
110<pre>package com.google.android.ClearTest;
111
112import javax.microedition.khronos.egl.EGLConfig;
113import javax.microedition.khronos.opengles.GL10;
114
115import android.app.Activity;
116import android.content.Context;
117import android.opengl.GLSurfaceView;
118import android.os.Bundle;
119import android.view.MotionEvent;
120
121public class ClearActivity extends Activity {
122 &#64;Override
123 protected void onCreate(Bundle savedInstanceState) {
124 super.onCreate(savedInstanceState);
125 mGLView = new ClearGLSurfaceView(this);
126 setContentView(mGLView);
127 }
128
129 &#64;Override
130 protected void onPause() {
131 super.onPause();
132 mGLView.onPause();
133 }
134
135 &#64;Override
136 protected void onResume() {
137 super.onResume();
138 mGLView.onResume();
139 }
140
141 private GLSurfaceView mGLView;
142}
143
144class ClearGLSurfaceView extends GLSurfaceView {
145 public ClearGLSurfaceView(Context context) {
146 super(context);
147 mRenderer = new ClearRenderer();
148 setRenderer(mRenderer);
149 }
150
151 public boolean onTouchEvent(final MotionEvent event) {
152 queueEvent(new Runnable(){
153 public void run() {
154 mRenderer.setColor(event.getX() / getWidth(),
155 event.getY() / getHeight(), 1.0f);
156 }});
157 return true;
158 }
159
160 ClearRenderer mRenderer;
161}
162
163class ClearRenderer implements GLSurfaceView.Renderer {
164 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
165 // Do nothing special.
166 }
167
168 public void onSurfaceChanged(GL10 gl, int w, int h) {
169 gl.glViewport(0, 0, w, h);
170 }
171
172 public void onDrawFrame(GL10 gl) {
173 gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
174 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
175 }
176
177 public void setColor(float r, float g, float b) {
178 mRed = r;
179 mGreen = g;
180 mBlue = b;
181 }
182
183 private float mRed;
184 private float mGreen;
185 private float mBlue;
186}</pre>
187
188<p>This application clears the screen for every frame. When you tap on the
189screen, it sets the clear color based on the (x,y) coordinates of your touch
190event. Note the use of <code>queueEvent()</code> in
191<code>ClearGLSurfaceView.onTouchEvent()</code>. The <code>queueEvent()</code>
192method is used to safely communicate between the UI thread and the rendering
193thread. If you prefer, you can use some other Java cross-thread communication
194technique, such as synchronized methods on the <code>Renderer</code> class
195itself. However, queueing events is often the simplest way of dealing with
196cross-thread communication.</p>
197
198<h3>Other GLSurfaceView samples</h3>
199
200<p>Tired
201of just clearing the screen? You can find more interesting samples in
202the API Demos sample included in the Android SDK. All the OpenGL ES samples have been
203converted to use the <code>GLSurfaceView</code> view:</p>
204
205<ul>
206<li>GLSurfaceView - a spinning triangle</li>
207<li>Kube - a cube puzzle demo</li>
208<li>Translucent GLSurfaceView - shows how to display 3D graphics on a translucent background</li>
209<li>Textured Triangle - shows how to draw a textured 3D triangle</li>
210<li>Sprite Text - shows how to draw text into a texture and then composite it into a 3D scene</li>
211<li>Touch Rotate - shows how to rotate a 3D object in response to user input.</li>
212</ul>
213
214<h3>Choosing a surface</h3>
215
216<p><code>GLSurfaceView</code>
217helps you choose the type of surface to render to. Different Android
218devices support different types of surfaces, with no common subset.
219This makes it tricky problem to choose the best available surface on
220each device. </p>
221
222<p>By default, <code>GLSurfaceView</code> tries to find a surface that's as
223close as possible to a 16-bit RGB frame buffer with a 16-bit depth
224buffer. Depending upon your application's needs you may want to change
225this behavior. For example, the Translucent GLSurfaceView sample needs
226an Alpha channel in order to render translucent data. <code>GLSurfaceView</code>
227provides an overloaded <code>setEGLSurfaceChooser()</code> method to give
228you control over which surface type is chosen:</p>
229
230<dl>
231<dt><code>setEGLConfigChooser(boolean needDepth)</code></dt>
232<dd>Choose a config that's closest to R5G6B5 with or without a 16-bit framebuffer</dd>
233<dt><code>setEGLConfigChooser(int redSize, int greenSize,int blueSize,
234int alphaSize,int depthSize, int stencilSize)</code></dt>
235<dd>Choose the config with the fewest number of bits per pixel that has at least
236as many bits-per-channel as specified in the constructor.</dd>
237<dt><code>setEGLConfigChooser(EGLConfigChooser configChooser)</code></dt>
238<dd>Allow total control over choosing a configuration. You pass in your own
239implementation of <code>EGLConfigChooser</code>, which gets to inspect the
240device's capabilities and choose a configuration.</dd>
241</dl>
242
243<h3>Continuous rendering versus render-when-dirty</h3>
244
245<p>Most 3D applications, such as games or simulations, are continuously
246animated. But some 3D applications are more reactive: they wait passively until
247the user does something, and then react to it. For those types of applications,
248the default <code>GLSurfaceView</code> behavior of continuously redrawing the
249screen is a waste of time. If you are developing a reactive application, you can
250call <code>GLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY)</code>, which
251turns off the continuous animation. Then you call
252<code>GLSurfaceView.requestRender()</code> whenever you want to re-render.</p>
253
254<h3>Help With debugging</h3>
255
256<p><code>GLSurfaceView</code> has a handy built-in feature for debugging OpenGL ES
257applications: the <code>GLSurfaceView.setDebugFlags()</code> method can be used
258to enable logging and/or error checking your OpenGL ES calls. Call this method
259in your <code>GLSurfaceView</code>'s constructor, before calling
260<code>setRenderer()</code>:</p>
261
262<pre>public ClearGLSurfaceView(Context context) {
263 super(context);
264 // Turn on error-checking and logging
265 setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
266 mRenderer = new ClearRenderer();
267 setRenderer(mRenderer);
268}</pre>