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