• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 java.io.IOException;
20 import java.io.InputStream;
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import java.nio.CharBuffer;
24 import java.nio.FloatBuffer;
25 
26 import javax.microedition.khronos.egl.EGLConfig;
27 import javax.microedition.khronos.opengles.GL;
28 import javax.microedition.khronos.opengles.GL10;
29 import javax.microedition.khronos.opengles.GL11;
30 import javax.microedition.khronos.opengles.GL11Ext;
31 
32 import android.content.Context;
33 import android.graphics.Bitmap;
34 import android.graphics.BitmapFactory;
35 import android.opengl.GLSurfaceView;
36 import android.opengl.GLU;
37 import android.opengl.GLUtils;
38 import android.os.SystemClock;
39 
40 import com.example.android.apis.R;
41 
42 public class MatrixPaletteRenderer implements GLSurfaceView.Renderer{
43     private Context mContext;
44     private Grid mGrid;
45     private int mTextureID;
46 
47     /** A grid is a topologically rectangular array of vertices.
48      *
49      * This grid class is customized for the vertex data required for this
50      * example.
51      *
52      * The vertex and index data are held in VBO objects because on most
53      * GPUs VBO objects are the fastest way of rendering static vertex
54      * and index data.
55      *
56      */
57 
58     private static class Grid {
59         // Size of vertex data elements in bytes:
60         final static int FLOAT_SIZE = 4;
61         final static int CHAR_SIZE = 2;
62 
63         // Vertex structure:
64         // float x, y, z;
65         // float u, v;
66         // float weight0, weight1;
67         // byte palette0, palette1, pad0, pad1;
68 
69         final static int VERTEX_SIZE = 8 * FLOAT_SIZE;
70         final static int VERTEX_TEXTURE_BUFFER_INDEX_OFFSET = 3;
71         final static int VERTEX_WEIGHT_BUFFER_INDEX_OFFSET = 5;
72         final static int VERTEX_PALETTE_INDEX_OFFSET = 7 * FLOAT_SIZE;
73 
74         private int mVertexBufferObjectId;
75         private int mElementBufferObjectId;
76 
77         // These buffers are used to hold the vertex and index data while
78         // constructing the grid. Once createBufferObjects() is called
79         // the buffers are nulled out to save memory.
80 
81         private ByteBuffer mVertexByteBuffer;
82         private FloatBuffer mVertexBuffer;
83         private CharBuffer mIndexBuffer;
84 
85         private int mW;
86         private int mH;
87         private int mIndexCount;
88 
Grid(int w, int h)89         public Grid(int w, int h) {
90             if (w < 0 || w >= 65536) {
91                 throw new IllegalArgumentException("w");
92             }
93             if (h < 0 || h >= 65536) {
94                 throw new IllegalArgumentException("h");
95             }
96             if (w * h >= 65536) {
97                 throw new IllegalArgumentException("w * h >= 65536");
98             }
99 
100             mW = w;
101             mH = h;
102             int size = w * h;
103 
104             mVertexByteBuffer = ByteBuffer.allocateDirect(VERTEX_SIZE * size)
105                 .order(ByteOrder.nativeOrder());
106             mVertexBuffer = mVertexByteBuffer.asFloatBuffer();
107 
108             int quadW = mW - 1;
109             int quadH = mH - 1;
110             int quadCount = quadW * quadH;
111             int indexCount = quadCount * 6;
112             mIndexCount = indexCount;
113             mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount)
114                 .order(ByteOrder.nativeOrder()).asCharBuffer();
115 
116             /*
117              * Initialize triangle list mesh.
118              *
119              *     [0]-----[  1] ...
120              *      |    /   |
121              *      |   /    |
122              *      |  /     |
123              *     [w]-----[w+1] ...
124              *      |       |
125              *
126              */
127 
128             {
129                 int i = 0;
130                 for (int y = 0; y < quadH; y++) {
131                     for (int x = 0; x < quadW; x++) {
132                         char a = (char) (y * mW + x);
133                         char b = (char) (y * mW + x + 1);
134                         char c = (char) ((y + 1) * mW + x);
135                         char d = (char) ((y + 1) * mW + x + 1);
136 
137                         mIndexBuffer.put(i++, a);
138                         mIndexBuffer.put(i++, c);
139                         mIndexBuffer.put(i++, b);
140 
141                         mIndexBuffer.put(i++, b);
142                         mIndexBuffer.put(i++, c);
143                         mIndexBuffer.put(i++, d);
144                     }
145                 }
146             }
147 
148         }
149 
set(int i, int j, float x, float y, float z, float u, float v, float w0, float w1, int p0, int p1)150         public void set(int i, int j, float x, float y, float z,
151                 float u, float v,
152                 float w0, float w1,
153                 int p0, int p1) {
154             if (i < 0 || i >= mW) {
155                 throw new IllegalArgumentException("i");
156             }
157             if (j < 0 || j >= mH) {
158                 throw new IllegalArgumentException("j");
159             }
160 
161             if (w0 + w1 != 1.0f) {
162                 throw new IllegalArgumentException("Weights must add up to 1.0f");
163             }
164 
165             int index = mW * j + i;
166 
167             mVertexBuffer.position(index * VERTEX_SIZE / FLOAT_SIZE);
168             mVertexBuffer.put(x);
169             mVertexBuffer.put(y);
170             mVertexBuffer.put(z);
171             mVertexBuffer.put(u);
172             mVertexBuffer.put(v);
173             mVertexBuffer.put(w0);
174             mVertexBuffer.put(w1);
175 
176             mVertexByteBuffer.position(index * VERTEX_SIZE + VERTEX_PALETTE_INDEX_OFFSET);
177             mVertexByteBuffer.put((byte) p0);
178             mVertexByteBuffer.put((byte) p1);
179         }
180 
createBufferObjects(GL gl)181         public void createBufferObjects(GL gl) {
182             // Generate a the vertex and element buffer IDs
183             int[] vboIds = new int[2];
184             GL11 gl11 = (GL11) gl;
185             gl11.glGenBuffers(2, vboIds, 0);
186             mVertexBufferObjectId = vboIds[0];
187             mElementBufferObjectId = vboIds[1];
188 
189             // Upload the vertex data
190             gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
191             mVertexByteBuffer.position(0);
192             gl11.glBufferData(GL11.GL_ARRAY_BUFFER, mVertexByteBuffer.capacity(), mVertexByteBuffer, GL11.GL_STATIC_DRAW);
193 
194             gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
195             mIndexBuffer.position(0);
196             gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.capacity() * CHAR_SIZE, mIndexBuffer, GL11.GL_STATIC_DRAW);
197 
198             // We don't need the in-memory data any more
199             mVertexBuffer = null;
200             mVertexByteBuffer = null;
201             mIndexBuffer = null;
202         }
203 
draw(GL10 gl)204         public void draw(GL10 gl) {
205             GL11 gl11 = (GL11) gl;
206             GL11Ext gl11Ext = (GL11Ext) gl;
207 
208             gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
209 
210             gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
211             gl11.glVertexPointer(3, GL10.GL_FLOAT, VERTEX_SIZE, 0);
212             gl11.glTexCoordPointer(2, GL10.GL_FLOAT, VERTEX_SIZE, VERTEX_TEXTURE_BUFFER_INDEX_OFFSET * FLOAT_SIZE);
213 
214             gl.glEnableClientState(GL11Ext.GL_MATRIX_INDEX_ARRAY_OES);
215             gl.glEnableClientState(GL11Ext.GL_WEIGHT_ARRAY_OES);
216 
217             gl11Ext.glWeightPointerOES(2, GL10.GL_FLOAT, VERTEX_SIZE, VERTEX_WEIGHT_BUFFER_INDEX_OFFSET  * FLOAT_SIZE);
218             gl11Ext.glMatrixIndexPointerOES(2, GL10.GL_UNSIGNED_BYTE, VERTEX_SIZE, VERTEX_PALETTE_INDEX_OFFSET );
219 
220             gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
221             gl11.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, 0);
222             gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
223             gl.glDisableClientState(GL11Ext.GL_MATRIX_INDEX_ARRAY_OES);
224             gl.glDisableClientState(GL11Ext.GL_WEIGHT_ARRAY_OES);
225             gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
226             gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
227         }
228     }
229 
MatrixPaletteRenderer(Context context)230     public MatrixPaletteRenderer(Context context) {
231         mContext = context;
232     }
233 
onSurfaceCreated(GL10 gl, EGLConfig config)234     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
235         /*
236          * By default, OpenGL enables features that improve quality
237          * but reduce performance. One might want to tweak that
238          * especially on software renderer.
239          */
240         gl.glDisable(GL10.GL_DITHER);
241 
242         /*
243          * Some one-time OpenGL initialization can be made here
244          * probably based on features of this particular context
245          */
246         gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
247                 GL10.GL_FASTEST);
248 
249         gl.glClearColor(.5f, .5f, .5f, 1);
250         gl.glShadeModel(GL10.GL_SMOOTH);
251         gl.glEnable(GL10.GL_DEPTH_TEST);
252         gl.glEnable(GL10.GL_TEXTURE_2D);
253 
254         /*
255          * Create our texture. This has to be done each time the
256          * surface is created.
257          */
258 
259         int[] textures = new int[1];
260         gl.glGenTextures(1, textures, 0);
261 
262         mTextureID = textures[0];
263         gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
264 
265         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
266                 GL10.GL_NEAREST);
267         gl.glTexParameterf(GL10.GL_TEXTURE_2D,
268                 GL10.GL_TEXTURE_MAG_FILTER,
269                 GL10.GL_LINEAR);
270 
271         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
272                 GL10.GL_CLAMP_TO_EDGE);
273         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
274                 GL10.GL_CLAMP_TO_EDGE);
275 
276         gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
277                 GL10.GL_REPLACE);
278 
279         InputStream is = mContext.getResources()
280                 .openRawResource(R.raw.robot);
281         Bitmap bitmap;
282         try {
283             bitmap = BitmapFactory.decodeStream(is);
284         } finally {
285             try {
286                 is.close();
287             } catch(IOException e) {
288                 // Ignore.
289             }
290         }
291 
292         GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
293         bitmap.recycle();
294 
295         mGrid = generateWeightedGrid(gl);
296     }
297 
onDrawFrame(GL10 gl)298     public void onDrawFrame(GL10 gl) {
299         /*
300          * By default, OpenGL enables features that improve quality
301          * but reduce performance. One might want to tweak that
302          * especially on software renderer.
303          */
304         gl.glDisable(GL10.GL_DITHER);
305 
306         gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
307                 GL10.GL_MODULATE);
308 
309         /*
310          * Usually, the first thing one might want to do is to clear
311          * the screen. The most efficient way of doing this is to use
312          * glClear().
313          */
314 
315         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
316 
317         gl.glEnable(GL10.GL_DEPTH_TEST);
318 
319         gl.glEnable(GL10.GL_CULL_FACE);
320 
321         /*
322          * Now we're ready to draw some 3D objects
323          */
324 
325         gl.glMatrixMode(GL10.GL_MODELVIEW);
326         gl.glLoadIdentity();
327 
328         GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
329 
330         gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
331         gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
332 
333         gl.glActiveTexture(GL10.GL_TEXTURE0);
334         gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
335         gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
336                 GL10.GL_REPEAT);
337         gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
338                 GL10.GL_REPEAT);
339 
340         long time = SystemClock.uptimeMillis() % 4000L;
341 
342         // Rock back and forth
343         double animationUnit = ((double) time) / 4000;
344         float unitAngle = (float) Math.cos(animationUnit * 2 * Math.PI);
345         float angle = unitAngle * 135f;
346 
347         gl.glEnable(GL11Ext.GL_MATRIX_PALETTE_OES);
348         gl.glMatrixMode(GL11Ext.GL_MATRIX_PALETTE_OES);
349 
350         GL11Ext gl11Ext = (GL11Ext) gl;
351 
352         // matrix 0: no transformation
353         gl11Ext.glCurrentPaletteMatrixOES(0);
354         gl11Ext.glLoadPaletteFromModelViewMatrixOES();
355 
356 
357         // matrix 1: rotate by "angle"
358         gl.glRotatef(angle, 0, 0, 1.0f);
359 
360         gl11Ext.glCurrentPaletteMatrixOES(1);
361         gl11Ext.glLoadPaletteFromModelViewMatrixOES();
362 
363         mGrid.draw(gl);
364 
365         gl.glDisable(GL11Ext.GL_MATRIX_PALETTE_OES);
366     }
367 
onSurfaceChanged(GL10 gl, int w, int h)368     public void onSurfaceChanged(GL10 gl, int w, int h) {
369         gl.glViewport(0, 0, w, h);
370 
371         /*
372         * Set our projection matrix. This doesn't have to be done
373         * each time we draw, but usually a new projection needs to
374         * be set when the viewport is resized.
375         */
376 
377         float ratio = (float) w / h;
378         gl.glMatrixMode(GL10.GL_PROJECTION);
379         gl.glLoadIdentity();
380         gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
381     }
382 
generateWeightedGrid(GL gl)383     private Grid generateWeightedGrid(GL gl) {
384         final int uSteps = 20;
385         final int vSteps = 20;
386 
387         float radius = 0.25f;
388         float height = 2.0f;
389         Grid grid = new Grid(uSteps + 1, vSteps + 1);
390 
391         for (int j = 0; j <= vSteps; j++) {
392             for (int i = 0; i <= uSteps; i++) {
393                 double angle = Math.PI * 2 * i / uSteps;
394                 float x = radius * (float) Math.cos(angle);
395                 float y = height * ((float) j / vSteps - 0.5f);
396                 float z = radius * (float) Math.sin(angle);
397                 float u = -4.0f * (float) i / uSteps;
398                 float v = -4.0f * (float) j / vSteps;
399                 float w0 = (float) j / vSteps;
400                 float w1 = 1.0f - w0;
401                 grid.set(i, j, x, y, z, u, v, w0, w1, 0, 1);
402             }
403         }
404 
405         grid.createBufferObjects(gl);
406         return grid;
407     }
408 }
409