summaryrefslogtreecommitdiffstats
path: root/docs/html/training/graphics/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'docs/html/training/graphics/opengl')
-rw-r--r--docs/html/training/graphics/opengl/draw.jd195
-rw-r--r--docs/html/training/graphics/opengl/environment.jd223
-rw-r--r--docs/html/training/graphics/opengl/index.jd75
-rw-r--r--docs/html/training/graphics/opengl/motion.jd92
-rw-r--r--docs/html/training/graphics/opengl/projection.jd152
-rw-r--r--docs/html/training/graphics/opengl/shapes.jd153
-rw-r--r--docs/html/training/graphics/opengl/touch.jd145
7 files changed, 1035 insertions, 0 deletions
diff --git a/docs/html/training/graphics/opengl/draw.jd b/docs/html/training/graphics/opengl/draw.jd
new file mode 100644
index 0000000..156ff70
--- /dev/null
+++ b/docs/html/training/graphics/opengl/draw.jd
@@ -0,0 +1,195 @@
+page.title=Drawing Shapes
+parent.title=Displaying Graphics with OpenGL ES
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Defining Shapes
+previous.link=environment.html
+next.title=Applying Projection and Camera Views
+next.link=projection.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#initialize">Initialize Shapes</a></li>
+ <li><a href="#draw">Draw a Shape</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
+</ul>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/OpenGLES.zip"
+class="button">Download the sample</a>
+ <p class="filename">OpenGLES.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>After you define shapes to be drawn with OpenGL, you probably want to draw them. Drawing shapes
+with the OpenGL ES 2.0 takes a bit more code than you might imagine, because the API provides a
+great deal of control over the graphics rendering pipeline.</p>
+
+<p>This lesson explains how to draw the shapes you defined in the previous lesson using the OpenGL
+ES 2.0 API.</p>
+
+
+<h2 id="initialize">Initialize Shapes</h2>
+
+<p>Before you do any drawing, you must initialize and load the shapes you plan to draw. Unless the
+structure (the original coordinates) of the shapes you use in your program change during the course
+of execution, you should initialize them in the {@link
+android.opengl.GLSurfaceView.Renderer#onSurfaceCreated onSurfaceCreated()} method of your renderer
+for memory and processing efficiency.</p>
+
+<pre>
+public void onSurfaceCreated(GL10 unused, EGLConfig config) {
+ ...
+
+ // initialize a triangle
+ mTriangle = new Triangle();
+ // initialize a square
+ mSquare = new Square();
+}
+</pre>
+
+
+<h2 id="draw">Draw a Shape</h2>
+
+<p>Drawing a defined shape using OpenGL ES 2.0 requires a significant amount of code, because you
+must provide a lot of details to the graphics rendering pipeline. Specifically, you must define the
+following:</p>
+
+<ul>
+ <li><em>Vertex Shader</em> - OpenGL ES graphics code for rendering the vertices of a shape.</li>
+ <li><em>Fragment Shader</em> - OpenGL ES code for rendering the face of a shape with colors or
+textures.</li>
+ <li><em>Program</em> - An OpenGL ES object that contains the shaders you want to use for drawing
+one or more shapes.</li>
+</ul>
+
+<p>You need at least one vertex shader to draw a shape and one fragment shader to color that shape.
+These shaders must be complied and then added to an OpenGL ES program, which is then used to draw
+the shape. Here is an example of how to define basic shaders you can use to draw a shape:</p>
+
+<pre>
+private final String vertexShaderCode =
+ "attribute vec4 vPosition;" +
+ "void main() {" +
+ " gl_Position = vPosition;" +
+ "}";
+
+private final String fragmentShaderCode =
+ "precision mediump float;" +
+ "uniform vec4 vColor;" +
+ "void main() {" +
+ " gl_FragColor = vColor;" +
+ "}";
+</pre>
+
+<p>Shaders contain OpenGL Shading Language (GLSL) code that must be compiled prior to using it in
+the OpenGL ES environment. To compile this code, create a utility method in your renderer class:</p>
+
+<pre>
+public static int loadShader(int type, String shaderCode){
+
+ // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
+ // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
+ int shader = GLES20.glCreateShader(type);
+
+ // add the source code to the shader and compile it
+ GLES20.glShaderSource(shader, shaderCode);
+ GLES20.glCompileShader(shader);
+
+ return shader;
+}
+</pre>
+
+<p>In order to draw your shape, you must compile the shader code, add them to a OpenGL ES program
+object and then link the program. Do this in your drawn object’s constructor, so it is only done
+once.</p>
+
+<p class="note"><strong>Note:</strong> Compiling OpenGL ES shaders and linking programs is expensive
+in terms of CPU cycles and processing time, so you should avoid doing this more than once. If you do
+not know the content of your shaders at runtime, you should build your code such that they only
+get created once and then cached for later use.</p>
+
+<pre>
+public Triangle() {
+ ...
+
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
+ int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
+
+ mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
+ GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
+ GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
+ GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables
+}
+</pre>
+
+<p>At this point, you are ready to add the actual calls that draw your shape. Drawing shapes with
+OpenGL ES requires that you specify several parameters to tell the rendering pipeline what you want
+to draw and how to draw it. Since drawing options can vary by shape, it's a good idea to have your
+shape classes contain their own drawing logic.</p>
+
+<p>Create a {@code draw()} method for drawing the shape. This code sets the position and
+color values to the shape’s vertex shader and fragment shader, and then executes the drawing
+function.</p>
+
+<pre>
+public void draw() {
+ // Add program to OpenGL ES environment
+ GLES20.glUseProgram(mProgram);
+
+ // get handle to vertex shader's vPosition member
+ mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
+
+ // Enable a handle to the triangle vertices
+ GLES20.glEnableVertexAttribArray(mPositionHandle);
+
+ // Prepare the triangle coordinate data
+ GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
+ GLES20.GL_FLOAT, false,
+ vertexStride, vertexBuffer);
+
+ // get handle to fragment shader's vColor member
+ mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
+
+ // Set color for drawing the triangle
+ GLES20.glUniform4fv(mColorHandle, 1, color, 0);
+
+ // Draw the triangle
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
+
+ // Disable vertex array
+ GLES20.glDisableVertexAttribArray(mPositionHandle);
+}
+</pre>
+
+<p>Once you have all this code in place, drawing this object just requires a call to the
+{@code draw()} method from within your renderer’s {@link
+android.opengl.GLSurfaceView.Renderer#onDrawFrame onDrawFrame()} method. When you run the
+application, it should look something like this:</p>
+
+<img src="{@docRoot}images/opengl/ogl-triangle.png">
+<p class="img-caption">
+<strong>Figure 1.</strong> Triangle drawn without a projection or camera view.</p>
+
+<p>There are a few problems with this code example. First of all, it is not going to impress your
+friends. Secondly, the triangle is a bit squashed and changes shape when you change the screen
+orientation of the device. The reason the shape is skewed is due to the fact that the object’s
+vertices have not been corrected for the proportions of the screen area where the {@link
+android.opengl.GLSurfaceView} is displayed. You can fix that problem using a projection and camera
+view in the next lesson.</p>
+
+<p>Lastly, the triangle is stationary, which is a bit boring. In the <a href="motion.html">Adding
+Motion</a> lesson, you make this shape rotate and make more interesting use of the OpenGL ES
+graphics pipeline.</p> \ No newline at end of file
diff --git a/docs/html/training/graphics/opengl/environment.jd b/docs/html/training/graphics/opengl/environment.jd
new file mode 100644
index 0000000..e1e2c8a
--- /dev/null
+++ b/docs/html/training/graphics/opengl/environment.jd
@@ -0,0 +1,223 @@
+page.title=Building an OpenGL ES Environment
+parent.title=Displaying Graphics with OpenGL ES
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Displaying Graphics with OpenGL ES
+previous.link=index.html
+next.title=Defining Shapes
+next.link=shapes.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#manifest">Declare OpenGL ES Use in the Manifest</a></li>
+ <li><a href="#activity">Create an Activity for OpenGL ES Graphics</a></li>
+ <li><a href="#glsurfaceview">Build a GLSurfaceView Object</a></li>
+ <li><a href="#renderer">Build a Renderer Class</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/OpenGLES.zip"
+class="button">Download the sample</a>
+ <p class="filename">OpenGLES.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p>In order to draw graphics with OpenGL ES in your Android application, you must create a
+view container for them. One of the more straight-forward ways to do this is to implement both a
+{@link android.opengl.GLSurfaceView} and a {@link android.opengl.GLSurfaceView.Renderer}. A {@link
+android.opengl.GLSurfaceView} is a view container for graphics drawn with OpenGL and {@link
+android.opengl.GLSurfaceView.Renderer} controls what is drawn within that view. For more information
+about these classes, see the <a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL ES</a>
+developer guide.</p>
+
+<p>{@link android.opengl.GLSurfaceView} is just one way to incorporate OpenGL ES graphics into your
+application. For a full-screen or near-full screen graphics view, it is a reasonable choice.
+Developers who want to incorporate OpenGL ES graphics in a small portion of their layouts should
+take a look at {@link android.view.TextureView}. For real, do-it-yourself developers, it is also
+possible to build up an OpenGL ES view using {@link android.view.SurfaceView}, but this requires
+writing quite a bit of additional code.</p>
+
+<p>This lesson explains how to complete a minimal implementation of {@link
+android.opengl.GLSurfaceView} and {@link android.opengl.GLSurfaceView.Renderer} in a simple
+application activity.</p>
+
+
+<h2 id="manifest">Declare OpenGL ES Use in the Manifest</h2>
+
+<p>In order for your application to use the OpenGL ES 2.0 API, you must add the following
+declaration to your manifest:</p>
+
+<pre>
+&lt;uses-feature android:glEsVersion="0x00020000" android:required="true" /&gt;
+</pre>
+
+<p>If your application uses texture compression, you must also declare which compression formats
+you support so that devices that do not support theses formats do not try to run your
+application:</p>
+
+<pre>
+&lt;supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" /&gt;
+&lt;supports-gl-texture android:name="GL_OES_compressed_paletted_texture" /&gt;
+</pre>
+
+<p>For more information about texture compression formats, see the
+<a href="{@docRoot}guide/topics/graphics/opengl.html#textures">OpenGL</a> developer guide.</p>
+
+
+<h2 id="activity">Create an Activity for OpenGL ES Graphics</h2>
+
+<p>Android applications that use OpenGL ES have activities just like any other application that has
+a user interface. The main difference from other applications is what you put in the layout for your
+activity. While in many applications you might use {@link android.widget.TextView}, {@link
+android.widget.Button} and {@link android.widget.ListView}, in an app that uses OpenGL ES, you can
+also add a {@link android.opengl.GLSurfaceView}.</p>
+
+<p>The following code example shows a minimal implementation of an activity that uses a
+{@link android.opengl.GLSurfaceView} as its primary view:</p>
+
+<pre>
+public class OpenGLES20 extends Activity {
+
+ private GLSurfaceView mGLView;
+
+ &#64;Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Create a GLSurfaceView instance and set it
+ // as the ContentView for this Activity.
+ mGLView = new MyGLSurfaceView(this);
+ setContentView(mGLView);
+ }
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> OpenGL ES 2.0 requires Android 2.2 (API Level 8) or higher,
+so make sure your Android project targets that API or higher.</p>
+
+
+<h2 id="glsurfaceview">Build a GLSurfaceView Object</h2>
+
+<p>A {@link android.opengl.GLSurfaceView} is a specialized view where you can draw OpenGL ES
+graphics.
+It does not do much by itself. The actual drawing of objects is controlled in the {@link
+android.opengl.GLSurfaceView.Renderer} that you set on this view. In fact, the code for this object
+is so thin, you may be tempted to skip extending it and just create an unmodified {@link
+android.opengl.GLSurfaceView} instance, but don’t do that. You need to extend this class in
+order to capture touch events, which is covered in the <a href="#touch.html">Responding to Touch
+Events</a> lesson.</p>
+
+<p>The essential code for a {@link android.opengl.GLSurfaceView} is minimal, so for a quick
+implementation, it is common to
+just create an inner class in the activity that uses it:</p>
+
+<pre>
+class MyGLSurfaceView extends GLSurfaceView {
+
+ public MyGLSurfaceView(Context context){
+ super(context);
+
+ // Set the Renderer for drawing on the GLSurfaceView
+ setRenderer(new MyRenderer());
+ }
+}
+</pre>
+
+<p>When using OpenGL ES 2.0, you must add another call to your {@link android.opengl.GLSurfaceView}
+constructor, specifying that you want to use the 2.0 API:</p>
+
+<pre>
+// Create an OpenGL ES 2.0 context
+setEGLContextClientVersion(2);
+</pre>
+
+<p class="note"><strong>Note:</strong> If you are using the OpenGL ES 2.0 API, make sure you declare
+this in your application manifest. For more information, see <a href="#manifest">Declare OpenGL ES
+Use
+in the Manifest</a>.</p>
+
+<p>One other optional addition to your {@link android.opengl.GLSurfaceView} implementation is to set
+the render mode to only draw the view when there is a change to your drawing data using the
+{@link android.opengl.GLSurfaceView#RENDERMODE_WHEN_DIRTY GLSurfaceView.RENDERMODE_WHEN_DIRTY}
+setting:</p>
+
+<pre>
+// Render the view only when there is a change in the drawing data
+setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+</pre>
+
+<p>This setting prevents the {@link android.opengl.GLSurfaceView} frame from being redrawn until you
+call {@link android.opengl.GLSurfaceView#requestRender requestRender()}, which is more
+efficient for this sample app.</p>
+
+
+<h2 id="renderer">Build a Renderer Class</h2>
+
+<p>The implementation of the {@link android.opengl.GLSurfaceView.Renderer} class, or renderer,
+within an application that uses OpenGL ES is where things start to get interesting. This class
+controls
+what gets drawn on the {@link android.opengl.GLSurfaceView} with which it is associated. There are
+three methods in a renderer that are called by the Android system in order to figure out what and
+how to draw on a {@link android.opengl.GLSurfaceView}:</p>
+
+<ul>
+ <li>{@link android.opengl.GLSurfaceView.Renderer#onSurfaceCreated onSurfaceCreated()} -
+Called once to set up the view's OpenGL ES environment.</li>
+ <li>{@link android.opengl.GLSurfaceView.Renderer#onDrawFrame onDrawFrame()} - Called for each
+redraw of the view.</li>
+ <li>{@link android.opengl.GLSurfaceView.Renderer#onSurfaceChanged onSurfaceChanged()} - Called if
+the geometry of the view changes, for example when the device's screen orientation changes.
+ </li>
+</ul>
+
+<p>Here is a very basic implementation of an OpenGL ES renderer, that does nothing more than draw a
+gray background in the {@link android.opengl.GLSurfaceView}:</p>
+
+<pre>
+public class MyGL20Renderer implements GLSurfaceView.Renderer {
+
+ public void onSurfaceCreated(GL10 unused, EGLConfig config) {
+ // Set the background frame color
+ GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+ }
+
+ public void onDrawFrame(GL10 unused) {
+ // Redraw background color
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ }
+
+ public void onSurfaceChanged(GL10 unused, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+ }
+}
+</pre>
+
+<p>That’s all there is to it! The code examples above create a simple Android application that
+displays a gray screen using OpenGL. While this code does not do anything very interesting, by
+creating these classes, you have laid the foundation you need to start drawing graphic elements with
+OpenGL.</p>
+
+<p class="note"><strong>Note:</strong> You may wonder why these methods have a {@link
+javax.microedition.khronos.opengles.GL10} parameter, when you are using the OpengGL ES 2.0 APIs.
+These method signatures are simply reused for the 2.0 APIs to keep the Android framework code
+simpler.</p>
+
+<p>If you are familiar with the OpenGL ES APIs, you should now be able to set up a OpenGL ES
+environment in your app and start drawing graphics. However, if you need a bit more help getting
+started with OpenGL, head on to the next lessons for a few more hints.</p>
diff --git a/docs/html/training/graphics/opengl/index.jd b/docs/html/training/graphics/opengl/index.jd
new file mode 100644
index 0000000..23a734a
--- /dev/null
+++ b/docs/html/training/graphics/opengl/index.jd
@@ -0,0 +1,75 @@
+page.title=Displaying Graphics with OpenGL ES
+trainingnavtop=true
+next.title=Building an OpenGL ES Environment
+next.link=environment.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 2.2 (API Level 8) or higher</li>
+ <li>Experience building an <a href="{@docRoot}training/basics/firstapp/index.html">Android
+app</a></li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/OpenGLES.zip"
+class="button">Download the sample</a>
+ <p class="filename">OpenGLES.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>The Android framework provides plenty of standard tools for creating attractive, functional
+graphical user interfaces. However, if you want more control of what your application draws on
+screen, or are venturing into three dimensional graphics, you need to use a different tool. The
+OpenGL ES APIs provided by the Android framework offers a set of tools for displaying high-end,
+animated graphics that are limited only by your imagination and can also benefit from the
+acceleration of graphics processing units (GPUs) provided on many Android devices.</p>
+
+<p>This class walks you through the basics of developing applications that use OpenGL, including
+setup, drawing objects, moving drawn elements and responding to touch input.</p>
+
+<p>The example code in this class uses the OpenGL ES 2.0 APIs, which is the recommended API version
+to use with current Android devices. For more information about versions of OpenGL ES, see the <a
+href="{@docRoot}guide/topics/graphics/opengl.html#choosing-version">OpenGL</a>
+developer guide.</p>
+
+<p class="note"><strong>Note:</strong> Be careful not to mix OpenGL ES 1.x API calls with OpenGL
+ES 2.0 methods! The two APIs are not interchangeable and trying to use them together only results in
+frustration and sadness.</p>
+
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt><b><a href="environment.html">Building an OpenGL ES Environment</a></b></dt>
+ <dd>Learn how to set up an Android application to be able to draw OpenGL graphics.</dd>
+
+ <dt><b><a href="shapes.html">Defining Shapes</a></b></dt>
+ <dd>Learn how to define shapes and why you need to know about faces and winding.</dd>
+
+ <dt><b><a href="draw.html">Drawing Shapes</a></b></dt>
+ <dd>Learn how to draw OpenGL shapes in your application.</dd>
+
+ <dt><b><a href="projection.html">Applying Projection and Camera Views</a></b></dt>
+ <dd>Learn how to use projection and camera views to get a new perspective on your drawn
+objects.</dd>
+
+ <dt><b><a href="motion.html">Adding Motion</a></b></dt>
+ <dd>Learn how to do basic movement and animation of drawn objects with OpenGL.</dd>
+
+ <dt><b><a href="touch.html">Responding to Touch Events</a></b></dt>
+ <dd>Learn how to do basic interaction with OpenGL graphics.</dd>
+</dl>
diff --git a/docs/html/training/graphics/opengl/motion.jd b/docs/html/training/graphics/opengl/motion.jd
new file mode 100644
index 0000000..6888235
--- /dev/null
+++ b/docs/html/training/graphics/opengl/motion.jd
@@ -0,0 +1,92 @@
+page.title=Adding Motion
+parent.title=Displaying Graphics with OpenGL ES
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Applying Projection and Camera Views
+previous.link=projection.html
+next.title=Responding to Touch Events
+next.link=touch.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#rotate-gl1">Rotate a Shape</a></li>
+ <li><a href="#cont-render">Enable Continuous Rendering</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
+</ul>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/OpenGLES.zip"
+class="button">Download the sample</a>
+ <p class="filename">OpenGLES.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Drawing objects on screen is a pretty basic feature of OpenGL, but you can do this with other
+Android graphics framwork classes, including {@link android.graphics.Canvas} and
+{@link android.graphics.drawable.Drawable} objects. OpenGL ES provides additional capabilities for
+moving and transforming drawn objects in three dimensions or in other unique ways to create
+compelling user experiences.</p>
+
+<p>In this lesson, you take another step forward into using OpenGL ES by learning how to add motion
+to a shape with rotation.</p>
+
+
+<h2 id="rotate">Rotate a Shape</h2>
+
+<p>Rotating a drawing object with OpenGL ES 2.0 is relatively simple. You create another
+transformation matrix (a rotation matrix) and then combine it with your projection and
+camera view tranformation matrices:</p>
+
+<pre>
+private float[] mRotationMatrix = new float[16];
+public void onDrawFrame(GL10 gl) {
+ ...
+ // Create a rotation transformation for the triangle
+ long time = SystemClock.uptimeMillis() % 4000L;
+ float angle = 0.090f * ((int) time);
+ Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
+
+ // Combine the rotation matrix with the projection and camera view
+ Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
+
+ // Draw triangle
+ mTriangle.draw(mMVPMatrix);
+}
+</pre>
+
+<p>If your triangle does not rotate after making these changes, make sure you have commented out the
+{@link android.opengl.GLSurfaceView#RENDERMODE_WHEN_DIRTY GLSurfaceView.RENDERMODE_WHEN_DIRTY}
+setting, as described in the next section.</p>
+
+
+<h2 id="cont-render">Enable Continuous Rendering</h2>
+
+<p>If you have diligently followed along with the example code in this class to this point, make
+sure you comment out the line that sets the render mode only draw when dirty, otherwise OpenGL
+rotates the shape only one increment and then waits for a call to {@link
+android.opengl.GLSurfaceView#requestRender requestRender()} from the {@link
+android.opengl.GLSurfaceView} container:</p>
+
+<pre>
+public MyGLSurfaceView(Context context) {
+ ...
+ // Render the view only when there is a change in the drawing data
+ //setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); // comment out for auto-rotation
+}
+</pre>
+
+<p>Unless you have objects changing without any user interaction, it’s usually a good idea have this
+flag turned on. Be ready to uncomment this code, because the next lesson makes this call applicable
+once again.</p>
diff --git a/docs/html/training/graphics/opengl/projection.jd b/docs/html/training/graphics/opengl/projection.jd
new file mode 100644
index 0000000..2a91093
--- /dev/null
+++ b/docs/html/training/graphics/opengl/projection.jd
@@ -0,0 +1,152 @@
+page.title=Applying Projection and Camera Views
+parent.title=Displaying Graphics with OpenGL ES
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Drawing Shapes
+previous.link=draw.html
+next.title=Applying Projection and Camera Views
+next.link=projection.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#projection">Define a Projection</a></li>
+ <li><a href="#camera-view">Define a Camera View</a></li>
+ <li><a href="#transform">Apply Projection and Camera Transformations</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
+</ul>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/OpenGLES.zip"
+class="button">Download the sample</a>
+ <p class="filename">OpenGLES.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>In the OpenGL ES environment, projection and camera views allow you to display drawn objects in a
+way that more closely resembles how you see physical objects with your eyes. This simulation of
+physical viewing is done with mathematical transformations of drawn object coordinates:</p>
+
+<ul>
+ <li><em>Projection</em> - This transformation adjusts the coordinates of drawn objects based on
+the width and height of the {@link android.opengl.GLSurfaceView} where they are displayed. Without
+this calculation, objects drawn by OpenGL ES are skewed by the unequal proportions of the view
+window. A projection transformation typically only has to be calculated when the proportions of the
+OpenGL view are established or changed in the {@link
+android.opengl.GLSurfaceView.Renderer#onSurfaceChanged
+onSurfaceChanged()} method of your renderer. For more information about OpenGL ES projections and
+coordinate mapping, see <a
+href="{@docRoot}guide/topics/graphics/opengl.html#coordinate-mapping">Mapping Coordinates for Drawn
+Objects</a>.</li>
+ <li><em>Camera View</em> - This transformation adjusts the coordinates of drawn objects based on a
+virtual camera position. It’s important to note that OpenGL ES does not define an actual camera
+object, but instead provides utility methods that simulate a camera by transforming the display of
+drawn objects. A camera view transformation might be calculated only once when you establish your
+{@link android.opengl.GLSurfaceView}, or might change dynamically based on user actions or your
+application’s function.</li>
+</ul>
+
+<p>This lesson describes how to create a projection and camera view and apply it to shapes drawn in
+your {@link android.opengl.GLSurfaceView}.</p>
+
+
+<h2 id="projection">Define a Projection</h2>
+
+<p>The data for a projection transformation is calculated in the {@link
+android.opengl.GLSurfaceView.Renderer#onSurfaceChanged onSurfaceChanged()}
+method of your {@link android.opengl.GLSurfaceView.Renderer} class. The following example code
+takes the height and width of the {@link android.opengl.GLSurfaceView} and uses it to populate a
+projection transformation {@link android.opengl.Matrix} using the {@link
+android.opengl.Matrix#frustumM Matrix.frustumM()} method:</p>
+
+<pre>
+&#64;Override
+public void onSurfaceChanged(GL10 unused, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+
+ float ratio = (float) width / height;
+
+ // this projection matrix is applied to object coordinates
+ // in the onDrawFrame() method
+ Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
+}
+</pre>
+
+<p>This code populates a projection matrix, {@code mProjMatrix} which you can then combine with a
+camera view transformation in the {@link android.opengl.GLSurfaceView.Renderer#onDrawFrame
+onDrawFrame()} method, which is shown in the next section.</p>
+
+<p class="note"><strong>Note:</strong> Just applying a projection transformation to your
+drawing objects typically results in a very empty display. In general, you must also apply a camera
+view transformation in order for anything to show up on screen.</p>
+
+
+<h2 id="camera-view">Define a Camera View</h2>
+
+<p>Complete the process of transforming your drawn objects by adding a camera view transformation as
+part of the drawing process. In the following example code, the camera view transformation is
+calculated using the {@link android.opengl.Matrix#setLookAtM Matrix.setLookAtM()} method and then
+combined with the previously calculated projection matrix. The combined transformation matrices
+are then passed to the drawn shape.</p>
+
+<pre>
+&#64;Override
+public void onDrawFrame(GL10 unused) {
+ ...
+
+ // Set the camera position (View matrix)
+ Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+
+ // Calculate the projection and view transformation
+ Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
+
+ // Draw shape
+ mTriangle.draw(mMVPMatrix);
+}
+</pre>
+
+
+<h2 id="#transform">Apply Projection and Camera Transformations</h2>
+
+<p>In order to use the combined projection and camera view transformation matrix shown in the
+previews sections, modify the {@code draw()} method of your graphic objects to accept the combined
+transformation matrix and apply it to the shape:</p>
+
+<pre>
+public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix
+ ...
+
+ // get handle to shape's transformation matrix
+ mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
+
+ // Apply the projection and view transformation
+ GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
+
+ // Draw the triangle
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
+ ...
+}
+</pre>
+
+<p>Once you have correctly calulated and applied the projection and camera view transformations,
+your graphic objects are drawn in correct proportions and should look like this:</p>
+
+
+<img src="{@docRoot}images/opengl/ogl-triangle-projected.png">
+<p class="img-caption">
+<strong>Figure 1.</strong> Triangle drawn with a projection and camera view applied.</p>
+
+
+<p>Now that you have an application that displays your shapes in correct proportions, it's time to
+add motion to your shapes.</p>
diff --git a/docs/html/training/graphics/opengl/shapes.jd b/docs/html/training/graphics/opengl/shapes.jd
new file mode 100644
index 0000000..98381cc
--- /dev/null
+++ b/docs/html/training/graphics/opengl/shapes.jd
@@ -0,0 +1,153 @@
+page.title=Defining Shapes
+parent.title=Displaying Graphics with OpenGL ES
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Building an OpenGL ES Environment
+previous.link=environment.html
+next.title=Drawing Shapes
+next.link=draw.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#triangle">Define a Triangle</a></li>
+ <li><a href="#square">Define a Square</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
+</ul>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/OpenGLES.zip"
+class="button">Download the sample</a>
+ <p class="filename">OpenGLES.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Being able to define shapes to be drawn in the context of an OpenGL ES view is the first step in
+creating your high-end graphics masterpiece. Drawing with OpenGL ES can be a little tricky without
+knowing a few basic things about how OpenGL ES expects you to define graphic objects.</p>
+
+<p>This lesson explains the OpenGL ES coordinate system relative to an Android device screen, the
+basics of defining a shape, shape faces, as well as defining a triangle and a square.</p>
+
+
+<h2 id="triangle">Define a Triangle</h2>
+
+<p>OpenGL ES allows you to define drawn objects using coordinates in three-dimensional space. So,
+before you can draw a triangle, you must define its coordinates. In OpenGL, the typical way to do
+this is to define a vertex array of floating point numbers for the coordinates. For maximum
+efficiency, you write these coordinates into a {@link java.nio.ByteBuffer}, that is passed into the
+OpenGL ES graphics pipeline for processing.</p>
+
+<pre>
+class Triangle {
+
+ private FloatBuffer vertexBuffer;
+
+ // number of coordinates per vertex in this array
+ static final int COORDS_PER_VERTEX = 3;
+ static float triangleCoords[] = { // in counterclockwise order:
+ 0.0f, 0.622008459f, 0.0f, // top
+ -0.5f, -0.311004243f, 0.0f, // bottom left
+ 0.5f, -0.311004243f, 0.0f // bottom right
+ };
+
+ // Set color with red, green, blue and alpha (opacity) values
+ float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
+
+ public Triangle() {
+ // initialize vertex byte buffer for shape coordinates
+ ByteBuffer bb = ByteBuffer.allocateDirect(
+ // (number of coordinate values * 4 bytes per float)
+ triangleCoords.length * 4);
+ // use the device hardware's native byte order
+ bb.order(ByteOrder.nativeOrder());
+
+ // create a floating point buffer from the ByteBuffer
+ vertexBuffer = bb.asFloatBuffer();
+ // add the coordinates to the FloatBuffer
+ vertexBuffer.put(triangleCoords);
+ // set the buffer to read the first coordinate
+ vertexBuffer.position(0);
+ }
+}
+</pre>
+
+<p>By default, OpenGL ES assumes a coordinate system where [0,0,0] (X,Y,Z) specifies the center of
+the {@link android.opengl.GLSurfaceView} frame, [1,1,0] is the top right corner of the frame and
+[-1,-1,0] is bottom left corner of the frame. For an illustration of this coordinate system, see the
+<a href="{@docRoot}guide/topics/graphics/opengl.html#coordinate-mapping">OpenGL ES</a> developer
+guide.</p>
+
+<p>Note that the coordinates of this shape are defined in a counterclockwise order. The drawing
+order is important because it defines which side is the front face of the shape, which you typically
+want to have drawn, and the back face, which you can choose to not draw using the OpenGL ES cull
+face feature. For more information about faces and culling, see the <a
+href="{@docRoot}guide/topics/graphics/opengl.html#faces-winding">OpenGL ES</a> developer guide.</p>
+
+
+<h2 id="square">Define a Square</h2>
+
+<p>Defining triangles is pretty easy in OpenGL, but what if you want to get a just a little more
+complex? Say, a square? There are a number of ways to do this, but a typical path to drawing such a
+shape in OpenGL ES is to use two triangles drawn together:</p>
+
+<img src="{@docRoot}images/opengl/ccw-square.png">
+<p class="img-caption">
+ <strong>Figure 1.</strong> Drawing a square using two triangles.</p>
+
+<p>Again, you should define the vertices in a counterclockwise order for both triangles that
+represent this shape, and put the values in a {@link java.nio.ByteBuffer}. In order to avoid
+defining the two coordinates shared by each triangle twice, use a drawing list to tell the
+OpenGL ES graphics pipeline how to draw these vertices. Here’s the code for this shape:</p>
+
+<pre>
+class Square {
+
+ private FloatBuffer vertexBuffer;
+ private ShortBuffer drawListBuffer;
+
+ // number of coordinates per vertex in this array
+ static final int COORDS_PER_VERTEX = 3;
+ static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left
+ -0.5f, -0.5f, 0.0f, // bottom left
+ 0.5f, -0.5f, 0.0f, // bottom right
+ 0.5f, 0.5f, 0.0f }; // top right
+
+ private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
+
+ public Square() {
+ // initialize vertex byte buffer for shape coordinates
+ ByteBuffer bb = ByteBuffer.allocateDirect(
+ // (# of coordinate values * 4 bytes per float)
+ squareCoords.length * 4);
+ bb.order(ByteOrder.nativeOrder());
+ vertexBuffer = bb.asFloatBuffer();
+ vertexBuffer.put(squareCoords);
+ vertexBuffer.position(0);
+
+ // initialize byte buffer for the draw list
+ ByteBuffer dlb = ByteBuffer.allocateDirect(
+ // (# of coordinate values * 2 bytes per short)
+ drawOrder.length * 2);
+ dlb.order(ByteOrder.nativeOrder());
+ drawListBuffer = dlb.asShortBuffer();
+ drawListBuffer.put(drawOrder);
+ drawListBuffer.position(0);
+ }
+}
+</pre>
+
+<p>This example gives you a peek at what it takes to create more complex shapes with OpenGL. In
+general, you use collections of triangles to draw objects. In the next lesson, you learn how to draw
+these shapes on screen.</p>
diff --git a/docs/html/training/graphics/opengl/touch.jd b/docs/html/training/graphics/opengl/touch.jd
new file mode 100644
index 0000000..c058a59
--- /dev/null
+++ b/docs/html/training/graphics/opengl/touch.jd
@@ -0,0 +1,145 @@
+page.title= Responding to Touch Events
+parent.title=Displaying Graphics with OpenGL ES
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Adding Motion
+previous.link=motion.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#listener">Setup a Touch Listener</a></li>
+ <li><a href="#angle">Expose the Rotation Angle</a></li>
+ <li><a href="#rotate">Apply Rotation</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
+</ul>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/OpenGLES.zip"
+class="button">Download the sample</a>
+ <p class="filename">OpenGLES.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Making objects move according to a preset program like the rotating triangle is useful for
+getting some attention, but what if you want to have users interact with your OpenGL ES graphics?
+The key to making your OpenGL ES application touch interactive is expanding your implementation of
+{@link android.opengl.GLSurfaceView} to override the {@link
+android.opengl.GLSurfaceView#onTouchEvent onTouchEvent()} to listen for touch events.</p>
+
+<p>This lesson shows you how to listen for touch events to let users rotate an OpenGL ES object.</p>
+
+
+<h2 id="listener">Setup a Touch Listener</h2>
+
+<p>In order to make your OpenGL ES application respond to touch events, you must implement the
+{@link android.opengl.GLSurfaceView#onTouchEvent onTouchEvent()} method in your
+{@link android.opengl.GLSurfaceView} class. The example implementation below shows how to listen for
+{@link android.view.MotionEvent#ACTION_MOVE MotionEvent.ACTION_MOVE} events and translate them to
+an angle of rotation for a shape.</p>
+
+<pre>
+&#64;Override
+public boolean onTouchEvent(MotionEvent e) {
+ // MotionEvent reports input details from the touch screen
+ // and other input controls. In this case, you are only
+ // interested in events where the touch position changed.
+
+ float x = e.getX();
+ float y = e.getY();
+
+ switch (e.getAction()) {
+ case MotionEvent.ACTION_MOVE:
+
+ float dx = x - mPreviousX;
+ float dy = y - mPreviousY;
+
+ // reverse direction of rotation above the mid-line
+ if (y &gt; getHeight() / 2) {
+ dx = dx * -1 ;
+ }
+
+ // reverse direction of rotation to left of the mid-line
+ if (x &lt; getWidth() / 2) {
+ dy = dy * -1 ;
+ }
+
+ mRenderer.mAngle += (dx + dy) * TOUCH_SCALE_FACTOR; // = 180.0f / 320
+ requestRender();
+ }
+
+ mPreviousX = x;
+ mPreviousY = y;
+ return true;
+}
+</pre>
+
+<p>Notice that after calculating the rotation angle, this method calls {@link
+android.opengl.GLSurfaceView#requestRender requestRender()} to tell the
+renderer that it is time to render the frame. This approach is the most efficient in this example
+because the frame does not need to be redrawn unless there is a change in the rotation. However, it
+does not have any impact on efficiency unless you also request that the renderer only redraw when
+the data changes using the {@link android.opengl.GLSurfaceView#setRenderMode setRenderMode()}
+method, so make sure this line is uncommented in the renderer:</p>
+
+<pre>
+public MyGLSurfaceView(Context context) {
+ ...
+ // Render the view only when there is a change in the drawing data
+ <strong>setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);</strong>
+}
+</pre>
+
+<h2 id="angle">Expose the Rotation Angle</h2>
+
+<p>The example code above requires that you expose the rotation angle through your renderer by
+adding a public member. Since the renderer code is running on a separate thread from the main user
+interface thread of your application, you must declare this public variable as {@code volatile}.
+Here is the code to do that:</p>
+
+<pre>
+public class MyGLRenderer implements GLSurfaceView.Renderer {
+ ...
+ public volatile float mAngle;
+</pre>
+
+
+<h2 id="rotate">Apply Rotation</h2>
+
+<p>To apply the rotation generated by touch input, comment out the code that generates an angle and
+add {@code mAngle}, which contains the touch input generated angle:</p>
+
+<pre>
+public void onDrawFrame(GL10 gl) {
+ ...
+ // Create a rotation for the triangle
+ // long time = SystemClock.uptimeMillis() % 4000L;
+ // float angle = 0.090f * ((int) time);
+ <strong>Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);</strong>
+
+ // Combine the rotation matrix with the projection and camera view
+ Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
+
+ // Draw triangle
+ mTriangle.draw(mMVPMatrix);
+}
+</pre>
+
+<p>When you have completed the steps described above, run the program and drag your finger over the
+screen to rotate the triangle:</p>
+
+<img src="{@docRoot}images/opengl/ogl-triangle-touch.png">
+<p class="img-caption">
+<strong>Figure 1.</strong> Triangle being rotated with touch input (circle shows touch
+location).</p>