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
17package com.android.test;
18/*
19 * Copyright (C) 2008 The Android Open Source Project
20 *
21 * Licensed under the Apache License, Version 2.0 (the "License");
22 * you may not use this file except in compliance with the License.
23 * You may obtain a copy of the License at
24 *
25 *      http://www.apache.org/licenses/LICENSE-2.0
26 *
27 * Unless required by applicable law or agreed to in writing, software
28 * distributed under the License is distributed on an "AS IS" BASIS,
29 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30 * See the License for the specific language governing permissions and
31 * limitations under the License.
32 */
33
34import java.nio.ByteBuffer;
35import java.nio.ByteOrder;
36import java.nio.CharBuffer;
37import java.nio.FloatBuffer;
38
39import android.content.Context;
40import android.opengl.GLSurfaceView;
41import android.util.AttributeSet;
42import android.util.Log;
43import android.view.KeyEvent;
44import android.view.MotionEvent;
45
46import javax.microedition.khronos.egl.EGL10;
47import javax.microedition.khronos.egl.EGLConfig;
48import javax.microedition.khronos.opengles.GL;
49import javax.microedition.khronos.opengles.GL10;
50import javax.microedition.khronos.opengles.GL11;
51/**
52 * An implementation of SurfaceView that uses the dedicated surface for
53 * displaying an OpenGL animation.  This allows the animation to run in a
54 * separate thread, without requiring that it be driven by the update mechanism
55 * of the view hierarchy.
56 *
57 * The application-specific rendering code is delegated to a GLView.Renderer
58 * instance.
59 */
60class TestView extends GLSurfaceView {
61    TestView(Context context) {
62        super(context);
63        init();
64    }
65
66    public TestView(Context context, AttributeSet attrs) {
67        super(context, attrs);
68        init();
69    }
70
71    private void init() {
72        setRenderer(new Renderer());
73        setRenderMode(RENDERMODE_WHEN_DIRTY);
74    }
75
76        /** A grid is a topologically rectangular array of vertices.
77    *
78    * The vertex and index data are held in VBO objects because on most
79    * GPUs VBO objects are the fastest way of rendering static vertex
80    * and index data.
81    *
82    */
83
84   private static class Grid {
85       // Size of vertex data elements in bytes:
86       final static int FLOAT_SIZE = 4;
87       final static int CHAR_SIZE = 2;
88
89       // Vertex structure:
90       // float x, y, z;
91
92       final static int VERTEX_SIZE = 3 * FLOAT_SIZE;
93
94       private int mVertexBufferObjectId;
95       private int mElementBufferObjectId;
96
97       // These buffers are used to hold the vertex and index data while
98       // constructing the grid. Once createBufferObjects() is called
99       // the buffers are nulled out to save memory.
100
101       private ByteBuffer mVertexByteBuffer;
102       private FloatBuffer mVertexBuffer;
103       private CharBuffer mIndexBuffer;
104
105       private int mW;
106       private int mH;
107       private int mIndexCount;
108
109       public Grid(int w, int h) {
110           if (w < 0 || w >= 65536) {
111               throw new IllegalArgumentException("w");
112           }
113           if (h < 0 || h >= 65536) {
114               throw new IllegalArgumentException("h");
115           }
116           if (w * h >= 65536) {
117               throw new IllegalArgumentException("w * h >= 65536");
118           }
119
120           mW = w;
121           mH = h;
122           int size = w * h;
123
124           mVertexByteBuffer = ByteBuffer.allocateDirect(VERTEX_SIZE * size)
125               .order(ByteOrder.nativeOrder());
126           mVertexBuffer = mVertexByteBuffer.asFloatBuffer();
127
128           int quadW = mW - 1;
129           int quadH = mH - 1;
130           int quadCount = quadW * quadH;
131           int indexCount = quadCount * 6;
132           mIndexCount = indexCount;
133           mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount)
134               .order(ByteOrder.nativeOrder()).asCharBuffer();
135
136           /*
137            * Initialize triangle list mesh.
138            *
139            *     [0]-----[  1] ...
140            *      |    /   |
141            *      |   /    |
142            *      |  /     |
143            *     [w]-----[w+1] ...
144            *      |       |
145            *
146            */
147
148           {
149               int i = 0;
150               for (int y = 0; y < quadH; y++) {
151                   for (int x = 0; x < quadW; x++) {
152                       char a = (char) (y * mW + x);
153                       char b = (char) (y * mW + x + 1);
154                       char c = (char) ((y + 1) * mW + x);
155                       char d = (char) ((y + 1) * mW + x + 1);
156
157                       mIndexBuffer.put(i++, a);
158                       mIndexBuffer.put(i++, c);
159                       mIndexBuffer.put(i++, b);
160
161                       mIndexBuffer.put(i++, b);
162                       mIndexBuffer.put(i++, c);
163                       mIndexBuffer.put(i++, d);
164                   }
165               }
166           }
167
168       }
169
170       public void set(int i, int j, float x, float y, float z) {
171           if (i < 0 || i >= mW) {
172               throw new IllegalArgumentException("i");
173           }
174           if (j < 0 || j >= mH) {
175               throw new IllegalArgumentException("j");
176           }
177
178           int index = mW * j + i;
179
180           mVertexBuffer.position(index * VERTEX_SIZE / FLOAT_SIZE);
181           mVertexBuffer.put(x);
182           mVertexBuffer.put(y);
183           mVertexBuffer.put(z);
184       }
185
186       public void createBufferObjects(GL gl) {
187           // Generate a the vertex and element buffer IDs
188           int[] vboIds = new int[2];
189           GL11 gl11 = (GL11) gl;
190           gl11.glGenBuffers(2, vboIds, 0);
191           mVertexBufferObjectId = vboIds[0];
192           mElementBufferObjectId = vboIds[1];
193
194           // Upload the vertex data
195           gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
196           mVertexByteBuffer.position(0);
197           gl11.glBufferData(GL11.GL_ARRAY_BUFFER, mVertexByteBuffer.capacity(), mVertexByteBuffer, GL11.GL_STATIC_DRAW);
198
199           gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
200           mIndexBuffer.position(0);
201           gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.capacity() * CHAR_SIZE, mIndexBuffer, GL11.GL_STATIC_DRAW);
202
203           // We don't need the in-memory data any more
204           mVertexBuffer = null;
205           mVertexByteBuffer = null;
206           mIndexBuffer = null;
207       }
208
209       public void draw(GL10 gl) {
210           GL11 gl11 = (GL11) gl;
211
212           gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
213
214           gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
215           gl11.glVertexPointer(3, GL10.GL_FLOAT, VERTEX_SIZE, 0);
216
217           gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
218           gl11.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, 0);
219           gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
220           gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
221           gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
222       }
223   }
224
225
226    private class Renderer implements GLSurfaceView.Renderer {
227        private static final String TAG = "Renderer";
228        private Grid mGrid;
229
230        public void onDrawFrame(GL10 gl) {
231			gl.glClearColor(0,0,1,1);
232			gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
233            mGrid.draw(gl);
234        }
235
236        public void onSurfaceChanged(GL10 gl, int width, int height) {
237            gl.glViewport(0, 0, width, height);
238			gl.glMatrixMode(GL11.GL_PROJECTION);
239			gl.glLoadIdentity();
240			gl.glOrthof(0, width, height, 0, -1, 1);
241			gl.glMatrixMode(GL11.GL_MODELVIEW);
242            createGrid(gl, width, height);
243        }
244
245        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
246        }
247
248        private void createGrid(GL10 gl, float w, float h) {
249        mGrid = new Grid(2, 2);
250			for (int j = 0; j < 2; j++) {
251				for (int i = 0; i < 2; i++) {
252					float x = w * i;
253					float y = h * j;
254					float z = 0.0f;
255					mGrid.set(i,j, x, y, z);
256				}
257			}
258			mGrid.createBufferObjects(gl);
259		}
260    }
261}
262
263