1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.apis.graphics;
18 
19 import static android.opengl.GLES10.*;
20 
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25 import java.nio.FloatBuffer;
26 import java.nio.ShortBuffer;
27 
28 import javax.microedition.khronos.egl.EGLConfig;
29 import javax.microedition.khronos.opengles.GL10;
30 
31 import android.content.Context;
32 import android.graphics.Bitmap;
33 import android.graphics.BitmapFactory;
34 import android.opengl.GLSurfaceView;
35 import android.opengl.GLU;
36 import android.opengl.GLUtils;
37 import android.os.SystemClock;
38 
39 import com.example.android.apis.R;
40 
41 /**
42  * A GLSurfaceView.Renderer that uses the Android-specific
43  * android.opengl.GLESXXX static OpenGL ES APIs. The static APIs
44  * expose more of the OpenGL ES features than the
45  * javax.microedition.khronos.opengles APIs, and also
46  * provide a programming model that is closer to the C OpenGL ES APIs, which
47  * may make it easier to reuse code and documentation written for the
48  * C OpenGL ES APIs.
49  *
50  */
51 public class StaticTriangleRenderer implements GLSurfaceView.Renderer{
52 
53     public interface TextureLoader {
54         /**
55          * Load a texture into the currently bound OpenGL texture.
56          */
load(GL10 gl)57         void load(GL10 gl);
58     }
59 
StaticTriangleRenderer(Context context)60     public StaticTriangleRenderer(Context context) {
61         init(context, new RobotTextureLoader());
62     }
63 
StaticTriangleRenderer(Context context, TextureLoader loader)64     public StaticTriangleRenderer(Context context, TextureLoader loader) {
65         init(context, loader);
66     }
67 
init(Context context, TextureLoader loader)68     private void init(Context context, TextureLoader loader) {
69         mContext = context;
70         mTriangle = new Triangle();
71         mTextureLoader = loader;
72     }
73 
onSurfaceCreated(GL10 gl, EGLConfig config)74     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
75         /*
76          * By default, OpenGL enables features that improve quality
77          * but reduce performance. One might want to tweak that
78          * especially on software renderer.
79          */
80         glDisable(GL_DITHER);
81 
82         /*
83          * Some one-time OpenGL initialization can be made here
84          * probably based on features of this particular context
85          */
86         glHint(GL_PERSPECTIVE_CORRECTION_HINT,
87                 GL_FASTEST);
88 
89         glClearColor(.5f, .5f, .5f, 1);
90         glShadeModel(GL_SMOOTH);
91         glEnable(GL_DEPTH_TEST);
92         glEnable(GL_TEXTURE_2D);
93 
94         /*
95          * Create our texture. This has to be done each time the
96          * surface is created.
97          */
98 
99         int[] textures = new int[1];
100         glGenTextures(1, textures, 0);
101 
102         mTextureID = textures[0];
103         glBindTexture(GL_TEXTURE_2D, mTextureID);
104 
105         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
106                 GL_NEAREST);
107         glTexParameterf(GL_TEXTURE_2D,
108                 GL_TEXTURE_MAG_FILTER,
109                 GL_LINEAR);
110 
111         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
112                 GL_CLAMP_TO_EDGE);
113         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
114                 GL_CLAMP_TO_EDGE);
115 
116         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
117                 GL_REPLACE);
118         mTextureLoader.load(gl);
119     }
120 
onDrawFrame(GL10 gl)121     public void onDrawFrame(GL10 gl) {
122         /*
123          * By default, OpenGL enables features that improve quality
124          * but reduce performance. One might want to tweak that
125          * especially on software renderer.
126          */
127         glDisable(GL_DITHER);
128 
129         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
130                 GL_MODULATE);
131 
132         /*
133          * Usually, the first thing one might want to do is to clear
134          * the screen. The most efficient way of doing this is to use
135          * glClear().
136          */
137 
138         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
139 
140         /*
141          * Now we're ready to draw some 3D objects
142          */
143 
144         glMatrixMode(GL_MODELVIEW);
145         glLoadIdentity();
146 
147         GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
148 
149         glEnableClientState(GL_VERTEX_ARRAY);
150         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
151 
152         glActiveTexture(GL_TEXTURE0);
153         glBindTexture(GL_TEXTURE_2D, mTextureID);
154         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
155                 GL_REPEAT);
156         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
157                 GL_REPEAT);
158 
159         long time = SystemClock.uptimeMillis() % 4000L;
160         float angle = 0.090f * ((int) time);
161 
162         glRotatef(angle, 0, 0, 1.0f);
163 
164         mTriangle.draw(gl);
165     }
166 
onSurfaceChanged(GL10 gl, int w, int h)167     public void onSurfaceChanged(GL10 gl, int w, int h) {
168         glViewport(0, 0, w, h);
169 
170         /*
171         * Set our projection matrix. This doesn't have to be done
172         * each time we draw, but usually a new projection needs to
173         * be set when the viewport is resized.
174         */
175 
176         float ratio = (float) w / h;
177         glMatrixMode(GL_PROJECTION);
178         glLoadIdentity();
179         glFrustumf(-ratio, ratio, -1, 1, 3, 7);
180     }
181 
182     private Context mContext;
183     private Triangle mTriangle;
184     private int mTextureID;
185     private TextureLoader mTextureLoader;
186 
187     private class RobotTextureLoader implements TextureLoader {
load(GL10 gl)188         public void load(GL10 gl) {
189             InputStream is = mContext.getResources().openRawResource(
190                     R.raw.robot);
191             Bitmap bitmap;
192             try {
193                 bitmap = BitmapFactory.decodeStream(is);
194             } finally {
195                 try {
196                     is.close();
197                 } catch (IOException e) {
198                     // Ignore.
199                 }
200             }
201 
202             GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
203             bitmap.recycle();
204         }
205     }
206 
207     static class Triangle {
Triangle()208         public Triangle() {
209 
210             // Buffers to be passed to gl*Pointer() functions
211             // must be direct, i.e., they must be placed on the
212             // native heap where the garbage collector cannot
213             // move them.
214             //
215             // Buffers with multi-byte datatypes (e.g., short, int, float)
216             // must have their byte order set to native order
217 
218             ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
219             vbb.order(ByteOrder.nativeOrder());
220             mFVertexBuffer = vbb.asFloatBuffer();
221 
222             ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4);
223             tbb.order(ByteOrder.nativeOrder());
224             mTexBuffer = tbb.asFloatBuffer();
225 
226             ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
227             ibb.order(ByteOrder.nativeOrder());
228             mIndexBuffer = ibb.asShortBuffer();
229 
230             // A unit-sided equilateral triangle centered on the origin.
231             float[] coords = {
232                     // X, Y, Z
233                     -0.5f, -0.25f, 0,
234                      0.5f, -0.25f, 0,
235                      0.0f,  0.559016994f, 0
236             };
237 
238             for (int i = 0; i < VERTS; i++) {
239                 for(int j = 0; j < 3; j++) {
240                     mFVertexBuffer.put(coords[i*3+j] * 2.0f);
241                 }
242             }
243 
244             for (int i = 0; i < VERTS; i++) {
245                 for(int j = 0; j < 2; j++) {
246                     mTexBuffer.put(coords[i*3+j] * 2.0f + 0.5f);
247                 }
248             }
249 
250             for(int i = 0; i < VERTS; i++) {
251                 mIndexBuffer.put((short) i);
252             }
253 
254             mFVertexBuffer.position(0);
255             mTexBuffer.position(0);
256             mIndexBuffer.position(0);
257         }
258 
draw(GL10 gl)259         public void draw(GL10 gl) {
260             glFrontFace(GL_CCW);
261             glVertexPointer(3, GL_FLOAT, 0, mFVertexBuffer);
262             glEnable(GL_TEXTURE_2D);
263             glTexCoordPointer(2, GL_FLOAT, 0, mTexBuffer);
264             glDrawElements(GL_TRIANGLE_STRIP, VERTS,
265                     GL_UNSIGNED_SHORT, mIndexBuffer);
266         }
267 
268         private final static int VERTS = 3;
269 
270         private FloatBuffer mFVertexBuffer;
271         private FloatBuffer mTexBuffer;
272         private ShortBuffer mIndexBuffer;
273     }
274 }
275