1/* 2 * Copyright (C) 2010 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.replica.replicaisland; 18 19import java.nio.Buffer; 20import java.nio.ByteBuffer; 21import java.nio.ByteOrder; 22import java.nio.CharBuffer; 23import java.nio.FloatBuffer; 24import java.nio.IntBuffer; 25 26import javax.microedition.khronos.opengles.GL10; 27import javax.microedition.khronos.opengles.GL11; 28 29import android.util.Log; 30 31/** 32 * A 2D rectangular mesh. Can be drawn textured or untextured. 33 * This version is modified from the original Grid.java (found in 34 * the SpriteText package in the APIDemos Android sample) to support hardware 35 * vertex buffers and to insert edges between grid squares for tiling. 36 */ 37class Grid { 38 private static final int FLOAT_SIZE = 4; 39 private static final int FIXED_SIZE = 4; 40 private static final int CHAR_SIZE = 2; 41 42 private FloatBuffer mFloatVertexBuffer; 43 private FloatBuffer mFloatTexCoordBuffer; 44 private IntBuffer mFixedVertexBuffer; 45 private IntBuffer mFixedTexCoordBuffer; 46 private CharBuffer mIndexBuffer; 47 48 private Buffer mVertexBuffer; 49 private Buffer mTexCoordBuffer; 50 private int mCoordinateSize; 51 private int mCoordinateType; 52 53 private int mVertsAcross; 54 private int mVertsDown; 55 private int mIndexCount; 56 private boolean mUseHardwareBuffers; 57 private int mVertBufferIndex; 58 private int mIndexBufferIndex; 59 private int mTextureCoordBufferIndex; 60 61 public Grid(int quadsAcross, int quadsDown, boolean useFixedPoint) { 62 final int vertsAcross = quadsAcross * 2; 63 final int vertsDown = quadsDown * 2; 64 if (vertsAcross < 0 || vertsAcross >= 65536) { 65 throw new IllegalArgumentException("quadsAcross"); 66 } 67 if (vertsDown < 0 || vertsDown >= 65536) { 68 throw new IllegalArgumentException("quadsDown"); 69 } 70 if (vertsAcross * vertsDown >= 65536) { 71 throw new IllegalArgumentException("quadsAcross * quadsDown >= 32768"); 72 } 73 74 mUseHardwareBuffers = false; 75 76 mVertsAcross = vertsAcross; 77 mVertsDown = vertsDown; 78 int size = vertsAcross * vertsDown; 79 80 81 if (useFixedPoint) { 82 mFixedVertexBuffer = ByteBuffer.allocateDirect(FIXED_SIZE * size * 3) 83 .order(ByteOrder.nativeOrder()).asIntBuffer(); 84 mFixedTexCoordBuffer = ByteBuffer.allocateDirect(FIXED_SIZE * size * 2) 85 .order(ByteOrder.nativeOrder()).asIntBuffer(); 86 87 mVertexBuffer = mFixedVertexBuffer; 88 mTexCoordBuffer = mFixedTexCoordBuffer; 89 mCoordinateSize = FIXED_SIZE; 90 mCoordinateType = GL10.GL_FIXED; 91 92 } else { 93 mFloatVertexBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 3) 94 .order(ByteOrder.nativeOrder()).asFloatBuffer(); 95 mFloatTexCoordBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 2) 96 .order(ByteOrder.nativeOrder()).asFloatBuffer(); 97 98 mVertexBuffer = mFloatVertexBuffer; 99 mTexCoordBuffer = mFloatTexCoordBuffer; 100 mCoordinateSize = FLOAT_SIZE; 101 mCoordinateType = GL10.GL_FLOAT; 102 } 103 104 105 106 107 int quadCount = quadsAcross * quadsDown; 108 int indexCount = quadCount * 6; 109 mIndexCount = indexCount; 110 mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount) 111 .order(ByteOrder.nativeOrder()).asCharBuffer(); 112 113 /* 114 * Initialize triangle list mesh. 115 * 116 * [0]------[1] [2]------[3] ... 117 * | / | | / | 118 * | / | | / | 119 * | / | | / | 120 * [w]-----[w+1] [w+2]----[w+3]... 121 * | | 122 * 123 */ 124 125 { 126 int i = 0; 127 for (int y = 0; y < quadsDown; y++) { 128 final int indexY = y * 2; 129 for (int x = 0; x < quadsAcross; x++) { 130 final int indexX = x * 2; 131 char a = (char) (indexY * mVertsAcross + indexX); 132 char b = (char) (indexY * mVertsAcross + indexX + 1); 133 char c = (char) ((indexY + 1) * mVertsAcross + indexX); 134 char d = (char) ((indexY + 1) * mVertsAcross + indexX + 1); 135 136 mIndexBuffer.put(i++, a); 137 mIndexBuffer.put(i++, b); 138 mIndexBuffer.put(i++, c); 139 140 mIndexBuffer.put(i++, b); 141 mIndexBuffer.put(i++, c); 142 mIndexBuffer.put(i++, d); 143 } 144 } 145 } 146 147 mVertBufferIndex = 0; 148 } 149 150 public void set(int quadX, int quadY, float[][] positions, float[][] uvs) { 151 if (quadX < 0 || quadX * 2 >= mVertsAcross) { 152 throw new IllegalArgumentException("quadX"); 153 } 154 if (quadY < 0 || quadY * 2 >= mVertsDown) { 155 throw new IllegalArgumentException("quadY"); 156 } 157 if (positions.length < 4) { 158 throw new IllegalArgumentException("positions"); 159 } 160 if (uvs.length < 4) { 161 throw new IllegalArgumentException("quadY"); 162 } 163 164 int i = quadX * 2; 165 int j = quadY * 2; 166 167 setVertex(i, j, positions[0][0], positions[0][1], positions[0][2], uvs[0][0], uvs[0][1]); 168 setVertex(i + 1, j, positions[1][0], positions[1][1], positions[1][2], uvs[1][0], uvs[1][1]); 169 setVertex(i, j + 1, positions[2][0], positions[2][1], positions[2][2], uvs[2][0], uvs[2][1]); 170 setVertex(i + 1, j + 1, positions[3][0], positions[3][1], positions[3][2], uvs[3][0], uvs[3][1]); 171 } 172 173 174 private void setVertex(int i, int j, float x, float y, float z, float u, float v) { 175 if (i < 0 || i >= mVertsAcross) { 176 throw new IllegalArgumentException("i"); 177 } 178 if (j < 0 || j >= mVertsDown) { 179 throw new IllegalArgumentException("j"); 180 } 181 182 final int index = mVertsAcross * j + i; 183 184 final int posIndex = index * 3; 185 final int texIndex = index * 2; 186 187 188 if (mCoordinateType == GL10.GL_FLOAT) { 189 mFloatVertexBuffer.put(posIndex, x); 190 mFloatVertexBuffer.put(posIndex + 1, y); 191 mFloatVertexBuffer.put(posIndex + 2, z); 192 193 mFloatTexCoordBuffer.put(texIndex, u); 194 mFloatTexCoordBuffer.put(texIndex + 1, v); 195 } else { 196 mFixedVertexBuffer.put(posIndex, (int)(x * (1 << 16))); 197 mFixedVertexBuffer.put(posIndex + 1, (int)(y * (1 << 16))); 198 mFixedVertexBuffer.put(posIndex + 2, (int)(z * (1 << 16))); 199 200 mFixedTexCoordBuffer.put(texIndex, (int)(u * (1 << 16))); 201 mFixedTexCoordBuffer.put(texIndex + 1, (int)(v * (1 << 16))); 202 } 203 } 204 205 public static void beginDrawing(GL10 gl, boolean useTexture) { 206 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 207 208 if (useTexture) { 209 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 210 gl.glEnable(GL10.GL_TEXTURE_2D); 211 } else { 212 gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 213 gl.glDisable(GL10.GL_TEXTURE_2D); 214 } 215 } 216 217 public void beginDrawingStrips(GL10 gl, boolean useTexture) { 218 beginDrawing(gl, useTexture); 219 if (!mUseHardwareBuffers) { 220 gl.glVertexPointer(3, mCoordinateType, 0, mVertexBuffer); 221 222 if (useTexture) { 223 gl.glTexCoordPointer(2, mCoordinateType, 0, mTexCoordBuffer); 224 } 225 226 } else { 227 GL11 gl11 = (GL11)gl; 228 // draw using hardware buffers 229 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex); 230 gl11.glVertexPointer(3, mCoordinateType, 0, 0); 231 232 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex); 233 gl11.glTexCoordPointer(2, mCoordinateType, 0, 0); 234 235 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex); 236 } 237 } 238 239 // Assumes beginDrawingStrips() has been called before this. 240 public void drawStrip(GL10 gl, boolean useTexture, int startIndex, int indexCount) { 241 int count = indexCount; 242 if (startIndex + indexCount >= mIndexCount) { 243 count = mIndexCount - startIndex; 244 } 245 if (!mUseHardwareBuffers) { 246 gl.glDrawElements(GL10.GL_TRIANGLES, count, 247 GL10.GL_UNSIGNED_SHORT, mIndexBuffer.position(startIndex)); 248 } else { 249 GL11 gl11 = (GL11)gl; 250 gl11.glDrawElements(GL11.GL_TRIANGLES, count, 251 GL11.GL_UNSIGNED_SHORT, startIndex * CHAR_SIZE); 252 253 } 254 } 255 256 public void draw(GL10 gl, boolean useTexture) { 257 if (!mUseHardwareBuffers) { 258 gl.glVertexPointer(3, mCoordinateType, 0, mVertexBuffer); 259 260 if (useTexture) { 261 gl.glTexCoordPointer(2, mCoordinateType, 0, mTexCoordBuffer); 262 } 263 264 gl.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, 265 GL10.GL_UNSIGNED_SHORT, mIndexBuffer); 266 } else { 267 GL11 gl11 = (GL11)gl; 268 // draw using hardware buffers 269 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex); 270 gl11.glVertexPointer(3, mCoordinateType, 0, 0); 271 272 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex); 273 gl11.glTexCoordPointer(2, mCoordinateType, 0, 0); 274 275 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex); 276 gl11.glDrawElements(GL11.GL_TRIANGLES, mIndexCount, 277 GL11.GL_UNSIGNED_SHORT, 0); 278 279 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0); 280 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0); 281 282 283 } 284 } 285 286 public static void endDrawing(GL10 gl) { 287 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 288 } 289 290 public boolean usingHardwareBuffers() { 291 return mUseHardwareBuffers; 292 } 293 294 /** 295 * When the OpenGL ES device is lost, GL handles become invalidated. 296 * In that case, we just want to "forget" the old handles (without 297 * explicitly deleting them) and make new ones. 298 */ 299 public void invalidateHardwareBuffers() { 300 mVertBufferIndex = 0; 301 mIndexBufferIndex = 0; 302 mTextureCoordBufferIndex = 0; 303 mUseHardwareBuffers = false; 304 } 305 306 /** 307 * Deletes the hardware buffers allocated by this object (if any). 308 */ 309 public void releaseHardwareBuffers(GL10 gl) { 310 if (mUseHardwareBuffers) { 311 if (gl instanceof GL11) { 312 GL11 gl11 = (GL11)gl; 313 int[] buffer = new int[1]; 314 buffer[0] = mVertBufferIndex; 315 gl11.glDeleteBuffers(1, buffer, 0); 316 317 buffer[0] = mTextureCoordBufferIndex; 318 gl11.glDeleteBuffers(1, buffer, 0); 319 320 buffer[0] = mIndexBufferIndex; 321 gl11.glDeleteBuffers(1, buffer, 0); 322 } 323 324 invalidateHardwareBuffers(); 325 } 326 } 327 328 /** 329 * Allocates hardware buffers on the graphics card and fills them with 330 * data if a buffer has not already been previously allocated. Note that 331 * this function uses the GL_OES_vertex_buffer_object extension, which is 332 * not guaranteed to be supported on every device. 333 * @param gl A pointer to the OpenGL ES context. 334 */ 335 public void generateHardwareBuffers(GL10 gl) { 336 if (!mUseHardwareBuffers) { 337 DebugLog.i("Grid", "Using Hardware Buffers"); 338 if (gl instanceof GL11) { 339 GL11 gl11 = (GL11)gl; 340 int[] buffer = new int[1]; 341 342 // Allocate and fill the vertex buffer. 343 gl11.glGenBuffers(1, buffer, 0); 344 mVertBufferIndex = buffer[0]; 345 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex); 346 final int vertexSize = mVertexBuffer.capacity() * mCoordinateSize; 347 // too fast task switching leaves buffers in the middle pos which 348 // crashes app 349 mVertexBuffer.position(0); 350 gl11.glBufferData(GL11.GL_ARRAY_BUFFER, vertexSize, 351 mVertexBuffer, GL11.GL_STATIC_DRAW); 352 353 // Allocate and fill the texture coordinate buffer. 354 gl11.glGenBuffers(1, buffer, 0); 355 mTextureCoordBufferIndex = buffer[0]; 356 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 357 mTextureCoordBufferIndex); 358 final int texCoordSize = 359 mTexCoordBuffer.capacity() * mCoordinateSize; 360 mTexCoordBuffer.position(0); 361 gl11.glBufferData(GL11.GL_ARRAY_BUFFER, texCoordSize, 362 mTexCoordBuffer, GL11.GL_STATIC_DRAW); 363 364 // Unbind the array buffer. 365 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0); 366 367 // Allocate and fill the index buffer. 368 gl11.glGenBuffers(1, buffer, 0); 369 mIndexBufferIndex = buffer[0]; 370 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 371 mIndexBufferIndex); 372 // A char is 2 bytes. 373 final int indexSize = mIndexBuffer.capacity() * 2; 374 375 mIndexBuffer.position(0); 376 gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, indexSize, mIndexBuffer, 377 GL11.GL_STATIC_DRAW); 378 379 // Unbind the element array buffer. 380 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0); 381 382 mUseHardwareBuffers = true; 383 384 assert mVertBufferIndex != 0; 385 assert mTextureCoordBufferIndex != 0; 386 assert mIndexBufferIndex != 0; 387 assert gl11.glGetError() == 0; 388 389 390 } 391 } 392 } 393 394} 395