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 17 package com.replica.replicaisland; 18 19 import java.nio.Buffer; 20 import java.nio.ByteBuffer; 21 import java.nio.ByteOrder; 22 import java.nio.CharBuffer; 23 import java.nio.FloatBuffer; 24 import java.nio.IntBuffer; 25 26 import javax.microedition.khronos.opengles.GL10; 27 import javax.microedition.khronos.opengles.GL11; 28 29 import 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 */ 37 class 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 Grid(int quadsAcross, int quadsDown, boolean useFixedPoint)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 set(int quadX, int quadY, float[][] positions, float[][] uvs)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 setVertex(int i, int j, float x, float y, float z, float u, float v)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 beginDrawing(GL10 gl, boolean useTexture)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 beginDrawingStrips(GL10 gl, boolean useTexture)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. drawStrip(GL10 gl, boolean useTexture, int startIndex, int indexCount)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 draw(GL10 gl, boolean useTexture)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 endDrawing(GL10 gl)286 public static void endDrawing(GL10 gl) { 287 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 288 } 289 usingHardwareBuffers()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 */ invalidateHardwareBuffers()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 */ releaseHardwareBuffers(GL10 gl)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 */ generateHardwareBuffers(GL10 gl)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