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