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.cooliris.media; 18 19 import java.nio.ByteBuffer; 20 import java.nio.ByteOrder; 21 import java.nio.CharBuffer; 22 import java.nio.FloatBuffer; 23 24 import javax.microedition.khronos.opengles.GL10; 25 import javax.microedition.khronos.opengles.GL11; 26 27 /** 28 * A 2D rectangular mesh. Can be drawn textured or untextured. This version is 29 * modified from the original Grid.java (found in the SpriteText package in the 30 * APIDemos Android sample) to support hardware vertex buffers. 31 */ 32 final class GridQuadMesh { 33 private FloatBuffer mVertexBuffer; 34 private FloatBuffer mTexCoordBuffer; 35 private CharBuffer mIndexBuffer; 36 37 private int mW; 38 private int mH; 39 private int mIndexCount; 40 private int mVertBufferIndex; 41 private int mIndexBufferIndex; 42 private int mTextureCoordBufferIndex; 43 GridQuadMesh(int vertsAcross, int vertsDown)44 public GridQuadMesh(int vertsAcross, int vertsDown) { 45 if (vertsAcross < 0 || vertsAcross >= 65536) { 46 throw new IllegalArgumentException("vertsAcross"); 47 } 48 if (vertsDown < 0 || vertsDown >= 65536) { 49 throw new IllegalArgumentException("vertsDown"); 50 } 51 if (vertsAcross * vertsDown >= 65536) { 52 throw new IllegalArgumentException("vertsAcross * vertsDown >= 65536"); 53 } 54 55 mW = vertsAcross; 56 mH = vertsDown; 57 int size = vertsAcross * vertsDown; 58 final int FLOAT_SIZE = 4; 59 final int CHAR_SIZE = 2; 60 mVertexBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 3).order(ByteOrder.nativeOrder()).asFloatBuffer(); 61 mTexCoordBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 2).order(ByteOrder.nativeOrder()).asFloatBuffer(); 62 63 int quadW = mW - 1; 64 int quadH = mH - 1; 65 int quadCount = quadW * quadH; 66 int indexCount = quadCount * 6; 67 mIndexCount = indexCount; 68 mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount).order(ByteOrder.nativeOrder()).asCharBuffer(); 69 70 /* 71 * Initialize triangle list mesh. 72 * 73 * [0]-----[ 1] ... | / | | / | | / | [w]-----[w+1] ... | | 74 */ 75 76 { 77 int i = 0; 78 for (int y = 0; y < quadH; y++) { 79 for (int x = 0; x < quadW; x++) { 80 char a = (char) (y * mW + x); 81 char b = (char) (y * mW + x + 1); 82 char c = (char) ((y + 1) * mW + x); 83 char d = (char) ((y + 1) * mW + x + 1); 84 85 mIndexBuffer.put(i++, a); 86 mIndexBuffer.put(i++, b); 87 mIndexBuffer.put(i++, c); 88 89 mIndexBuffer.put(i++, b); 90 mIndexBuffer.put(i++, c); 91 mIndexBuffer.put(i++, d); 92 } 93 } 94 } 95 96 mVertBufferIndex = 0; 97 } 98 set(int i, int j, float x, float y, float z, float u, float v)99 void set(int i, int j, float x, float y, float z, float u, float v) { 100 if (i < 0 || i >= mW) { 101 throw new IllegalArgumentException("i"); 102 } 103 if (j < 0 || j >= mH) { 104 throw new IllegalArgumentException("j"); 105 } 106 107 int index = mW * j + i; 108 109 int posIndex = index * 3; 110 mVertexBuffer.put(posIndex, x); 111 mVertexBuffer.put(posIndex + 1, y); 112 mVertexBuffer.put(posIndex + 2, z); 113 114 int texIndex = index * 2; 115 mTexCoordBuffer.put(texIndex, u); 116 mTexCoordBuffer.put(texIndex + 1, v); 117 } 118 draw(GL10 gl, boolean useTexture)119 public void draw(GL10 gl, boolean useTexture) { 120 if (mVertBufferIndex == 0) { 121 gl.glVertexPointer(3, GL11.GL_FLOAT, 0, mVertexBuffer); 122 123 if (useTexture) { 124 gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, mTexCoordBuffer); 125 } 126 127 gl.glDrawElements(GL11.GL_TRIANGLES, mIndexCount, GL11.GL_UNSIGNED_SHORT, mIndexBuffer); 128 } else { 129 GL11 gl11 = (GL11) gl; 130 // draw using hardware buffers 131 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex); 132 gl11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0); 133 134 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex); 135 gl11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0); 136 137 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex); 138 gl11.glDrawElements(GL11.GL_TRIANGLES, mIndexCount, GL11.GL_UNSIGNED_SHORT, 0); 139 140 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0); 141 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0); 142 143 } 144 } 145 usingHardwareBuffers()146 public boolean usingHardwareBuffers() { 147 return mVertBufferIndex != 0; 148 } 149 150 /** 151 * When the OpenGL ES device is lost, GL handles become invalidated. In that 152 * case, we just want to "forget" the old handles (without explicitly 153 * deleting them) and make new ones. 154 */ forgetHardwareBuffers()155 public void forgetHardwareBuffers() { 156 mVertBufferIndex = 0; 157 mIndexBufferIndex = 0; 158 mTextureCoordBufferIndex = 0; 159 } 160 161 /** 162 * Deletes the hardware buffers allocated by this object (if any). 163 */ freeHardwareBuffers(GL10 gl)164 public void freeHardwareBuffers(GL10 gl) { 165 if (mVertBufferIndex != 0) { 166 if (gl instanceof GL11) { 167 GL11 gl11 = (GL11) gl; 168 int[] buffer = new int[1]; 169 buffer[0] = mVertBufferIndex; 170 gl11.glDeleteBuffers(1, buffer, 0); 171 172 buffer[0] = mTextureCoordBufferIndex; 173 gl11.glDeleteBuffers(1, buffer, 0); 174 175 buffer[0] = mIndexBufferIndex; 176 gl11.glDeleteBuffers(1, buffer, 0); 177 } 178 179 forgetHardwareBuffers(); 180 } 181 } 182 183 /** 184 * Allocates hardware buffers on the graphics card and fills them with data 185 * if a buffer has not already been previously allocated. Note that this 186 * function uses the GL_OES_vertex_buffer_object extension, which is not 187 * guaranteed to be supported on every device. 188 * 189 * @param gl 190 * A pointer to the OpenGL ES context. 191 */ generateHardwareBuffers(GL10 gl)192 public void generateHardwareBuffers(GL10 gl) { 193 if (mVertBufferIndex == 0) { 194 if (gl instanceof GL11) { 195 GL11 gl11 = (GL11) gl; 196 int[] buffer = new int[1]; 197 198 // Allocate and fill the vertex buffer. 199 gl11.glGenBuffers(1, buffer, 0); 200 mVertBufferIndex = buffer[0]; 201 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex); 202 final int vertexSize = mVertexBuffer.capacity() * 4; 203 mVertexBuffer.position(0); 204 gl11.glBufferData(GL11.GL_ARRAY_BUFFER, vertexSize, mVertexBuffer, GL11.GL_STATIC_DRAW); 205 206 // Allocate and fill the texture coordinate buffer. 207 gl11.glGenBuffers(1, buffer, 0); 208 mTextureCoordBufferIndex = buffer[0]; 209 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex); 210 final int texCoordSize = mTexCoordBuffer.capacity() * 4; 211 mTexCoordBuffer.position(0); 212 gl11.glBufferData(GL11.GL_ARRAY_BUFFER, texCoordSize, mTexCoordBuffer, GL11.GL_STATIC_DRAW); 213 214 // Unbind the array buffer. 215 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0); 216 217 // Allocate and fill the index buffer. 218 gl11.glGenBuffers(1, buffer, 0); 219 mIndexBufferIndex = buffer[0]; 220 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex); 221 // A char is 2 bytes. 222 final int indexSize = mIndexBuffer.capacity() * 2; 223 mIndexBuffer.position(0); 224 gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, indexSize, mIndexBuffer, GL11.GL_STATIC_DRAW); 225 226 // Unbind the element array buffer. 227 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0); 228 } 229 } 230 } 231 232 } 233