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
17package com.example.android.apis.graphics;
18
19import static android.opengl.GLES10.*;
20
21import java.io.IOException;
22import java.io.InputStream;
23import java.nio.ByteBuffer;
24import java.nio.ByteOrder;
25import java.nio.FloatBuffer;
26import java.nio.ShortBuffer;
27
28import javax.microedition.khronos.egl.EGLConfig;
29import javax.microedition.khronos.opengles.GL10;
30
31import android.content.Context;
32import android.graphics.Bitmap;
33import android.graphics.BitmapFactory;
34import android.opengl.GLSurfaceView;
35import android.opengl.GLU;
36import android.opengl.GLUtils;
37import android.os.SystemClock;
38
39import 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 */
51public class StaticTriangleRenderer implements GLSurfaceView.Renderer{
52
53    public interface TextureLoader {
54        /**
55         * Load a texture into the currently bound OpenGL texture.
56         */
57        void load(GL10 gl);
58    }
59
60    public StaticTriangleRenderer(Context context) {
61        init(context, new RobotTextureLoader());
62    }
63
64    public StaticTriangleRenderer(Context context, TextureLoader loader) {
65        init(context, loader);
66    }
67
68    private void init(Context context, TextureLoader loader) {
69        mContext = context;
70        mTriangle = new Triangle();
71        mTextureLoader = loader;
72    }
73
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
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
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 {
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 {
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
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