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 final class GridQuadFrame { 28 private FloatBuffer mVertexBuffer; 29 private FloatBuffer mTexCoordBuffer; 30 private FloatBuffer mSecTexCoordBuffer; 31 private CharBuffer mIndexBuffer; 32 33 private int mW; 34 private int mH; 35 36 // This has 8 quads, 16 vertices, 22 triangles (for tristrip). 37 // We have more triangles because we have to make degenerate triangles to 38 // use tri-strips 39 public static final int INDEX_COUNT = 25; 40 private int mVertBufferIndex; 41 private int mIndexBufferIndex; 42 private int mTextureCoordBufferIndex; 43 private int mSecTextureCoordBufferIndex; 44 45 public static GridQuadFrame createFrame(float width, float height, int itemWidth, int itemHeight) { 46 GridQuadFrame frame = new GridQuadFrame(); 47 final float textureSize = 64.0f; 48 final float numPixelsYOriginShift = 7; 49 final float inset = 6; 50 final float ratio = 1.0f / (float) itemHeight; 51 final float frameXThickness = 0.5f * textureSize * ratio; 52 final float frameYThickness = 0.5f * textureSize * ratio; 53 final float frameX = width * 0.5f + frameXThickness * 0.5f - inset * ratio; 54 float frameY = height * 0.5f + frameYThickness * 0.5f + (inset - 1) * ratio; 55 final float originX = 0.0f; 56 final float originY = numPixelsYOriginShift * ratio; 57 58 frame.set(0, 0, -frameX + originX, -frameY + originY, 0, 1.0f, 1.0f); 59 frame.set(1, 0, -frameX + originX + frameXThickness, -frameY + originY, 0, 0.5f, 1.0f); 60 frame.set(2, 0, frameX - frameXThickness + originX, -frameY + originY, 0, 0.5f, 1.0f); 61 frame.set(3, 0, frameX + originX, -frameY + originY, 0, 0.0f, 1.0f); 62 63 frameY -= frameYThickness; 64 65 frame.set(0, 1, -frameX + originX, -frameY + originY, 0, 1.0f, 0.5f); 66 frame.set(1, 1, -frameX + frameXThickness + originX, -frameY + originY, 0, 0.5f, 0.5f); 67 frame.set(2, 1, frameX - frameXThickness + originX, -frameY + originY, 0, 0.5f, 0.5f); 68 frame.set(3, 1, frameX + originX, -frameY + originY, 0, 0.0f, 0.5f); 69 70 frameY = height * 0.5f - frameYThickness; 71 72 frame.set(0, 2, -frameX + originX, frameY + originY, 0, 1.0f, 0.5f); 73 frame.set(1, 2, -frameX + frameXThickness + originX, frameY + originY, 0, 0.5f, 0.5f); 74 frame.set(2, 2, frameX - frameXThickness + originX, frameY + originY, 0, 0.5f, 0.5f); 75 frame.set(3, 2, frameX + originX, frameY + originY, 0, 0.0f, 0.5f); 76 77 frameY += frameYThickness; 78 79 frame.set(0, 3, -frameX + originX, frameY + originY, 0, 1.0f, 0.0f); 80 frame.set(1, 3, -frameX + frameXThickness + originX, frameY + originY, 0, 0.5f, 0.0f); 81 frame.set(2, 3, frameX - frameXThickness + originX, frameY + originY, 0, 0.5f, 0.0f); 82 frame.set(3, 3, frameX + originX, frameY + originY, 0, 0.0f, 0.0f); 83 84 return frame; 85 } 86 87 public GridQuadFrame() { 88 int vertsAcross = 4; 89 int vertsDown = 4; 90 mW = vertsAcross; 91 mH = vertsDown; 92 int size = vertsAcross * vertsDown; 93 final int FLOAT_SIZE = 4; 94 final int CHAR_SIZE = 2; 95 mVertexBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 3).order(ByteOrder.nativeOrder()).asFloatBuffer(); 96 mTexCoordBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 2).order(ByteOrder.nativeOrder()).asFloatBuffer(); 97 mSecTexCoordBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 2).order(ByteOrder.nativeOrder()).asFloatBuffer(); 98 99 int indexCount = INDEX_COUNT; // using tristrips 100 mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount).order(ByteOrder.nativeOrder()).asCharBuffer(); 101 102 /* 103 * Initialize triangle list mesh. 104 * 105 * [0]---[1]---------[2]---[3] ... | / | / | / | 106 * [4]---[5]---------[6]---[7] | / | | /| | / | | / | | / | | / | 107 * [8]---[9]---------[10]---[11] | / | \ | \ | 108 * [12]--[13]--------[14]---[15] 109 */ 110 CharBuffer buffer = mIndexBuffer; 111 buffer.put(0, (char) 0); 112 buffer.put(1, (char) 4); 113 buffer.put(2, (char) 1); 114 buffer.put(3, (char) 5); 115 buffer.put(4, (char) 2); 116 buffer.put(5, (char) 6); 117 buffer.put(6, (char) 3); 118 buffer.put(7, (char) 7); 119 buffer.put(8, (char) 11); 120 buffer.put(9, (char) 6); 121 buffer.put(10, (char) 10); 122 buffer.put(11, (char) 14); 123 buffer.put(12, (char) 11); 124 buffer.put(13, (char) 15); 125 buffer.put(14, (char) 15); 126 buffer.put(15, (char) 14); 127 buffer.put(16, (char) 14); 128 buffer.put(17, (char) 10); 129 buffer.put(18, (char) 13); 130 buffer.put(19, (char) 9); 131 buffer.put(20, (char) 12); 132 buffer.put(21, (char) 8); 133 buffer.put(22, (char) 4); 134 buffer.put(23, (char) 9); 135 buffer.put(24, (char) 5); 136 mVertBufferIndex = 0; 137 } 138 139 void set(int i, int j, float x, float y, float z, float u, float v) { 140 if (i < 0 || i >= mW) { 141 throw new IllegalArgumentException("i"); 142 } 143 if (j < 0 || j >= mH) { 144 throw new IllegalArgumentException("j"); 145 } 146 147 int index = mW * j + i; 148 149 int posIndex = index * 3; 150 mVertexBuffer.put(posIndex, x); 151 mVertexBuffer.put(posIndex + 1, y); 152 mVertexBuffer.put(posIndex + 2, z); 153 154 int texIndex = index * 2; 155 mTexCoordBuffer.put(texIndex, u); 156 mTexCoordBuffer.put(texIndex + 1, v); 157 158 int secTexIndex = index * 2; 159 mSecTexCoordBuffer.put(secTexIndex, u); 160 mSecTexCoordBuffer.put(secTexIndex + 1, v); 161 } 162 163 public void bindArrays(GL10 gl) { 164 GL11 gl11 = (GL11) gl; 165 // draw using hardware buffers 166 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex); 167 gl11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0); 168 169 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex); 170 gl11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0); 171 gl11.glClientActiveTexture(GL11.GL_TEXTURE1); 172 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mSecTextureCoordBufferIndex); 173 gl11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0); 174 gl11.glClientActiveTexture(GL11.GL_TEXTURE0); 175 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex); 176 } 177 178 public static final void draw(GL11 gl11) { 179 // Don't call this method unless bindArrays was called. 180 gl11.glDrawElements(GL11.GL_TRIANGLE_STRIP, INDEX_COUNT, GL11.GL_UNSIGNED_SHORT, 0); 181 } 182 183 public void unbindArrays(GL10 gl) { 184 GL11 gl11 = (GL11) gl; 185 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0); 186 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0); 187 } 188 189 public boolean usingHardwareBuffers() { 190 return mVertBufferIndex != 0; 191 } 192 193 /** 194 * When the OpenGL ES device is lost, GL handles become invalidated. In that 195 * case, we just want to "forget" the old handles (without explicitly 196 * deleting them) and make new ones. 197 */ 198 public void forgetHardwareBuffers() { 199 mVertBufferIndex = 0; 200 mIndexBufferIndex = 0; 201 mTextureCoordBufferIndex = 0; 202 mSecTextureCoordBufferIndex = 0; 203 } 204 205 /** 206 * Deletes the hardware buffers allocated by this object (if any). 207 */ 208 public void freeHardwareBuffers(GL10 gl) { 209 if (mVertBufferIndex != 0) { 210 if (gl instanceof GL11) { 211 GL11 gl11 = (GL11) gl; 212 int[] buffer = new int[1]; 213 buffer[0] = mVertBufferIndex; 214 gl11.glDeleteBuffers(1, buffer, 0); 215 216 buffer[0] = mTextureCoordBufferIndex; 217 gl11.glDeleteBuffers(1, buffer, 0); 218 219 buffer[0] = mSecTextureCoordBufferIndex; 220 gl11.glDeleteBuffers(1, buffer, 0); 221 222 buffer[0] = mIndexBufferIndex; 223 gl11.glDeleteBuffers(1, buffer, 0); 224 } 225 forgetHardwareBuffers(); 226 } 227 } 228 229 /** 230 * Allocates hardware buffers on the graphics card and fills them with data 231 * if a buffer has not already been previously allocated. Note that this 232 * function uses the GL_OES_vertex_buffer_object extension, which is not 233 * guaranteed to be supported on every device. 234 * 235 * @param gl 236 * A pointer to the OpenGL ES context. 237 */ 238 public void generateHardwareBuffers(GL10 gl) { 239 if (mVertBufferIndex == 0) { 240 if (gl instanceof GL11) { 241 GL11 gl11 = (GL11) gl; 242 int[] buffer = new int[1]; 243 244 // Allocate and fill the vertex buffer. 245 gl11.glGenBuffers(1, buffer, 0); 246 mVertBufferIndex = buffer[0]; 247 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex); 248 mVertexBuffer.position(0); 249 final int vertexSize = mVertexBuffer.capacity() * 4; 250 gl11.glBufferData(GL11.GL_ARRAY_BUFFER, vertexSize, mVertexBuffer, GL11.GL_STATIC_DRAW); 251 252 // Allocate and fill the texture coordinate buffer. 253 gl11.glGenBuffers(1, buffer, 0); 254 mTextureCoordBufferIndex = buffer[0]; 255 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex); 256 final int texCoordSize = mTexCoordBuffer.capacity() * 4; 257 mTexCoordBuffer.position(0); 258 gl11.glBufferData(GL11.GL_ARRAY_BUFFER, texCoordSize, mTexCoordBuffer, GL11.GL_STATIC_DRAW); 259 260 // Allocate and fill the secondary texture coordinate buffer. 261 gl11.glGenBuffers(1, buffer, 0); 262 mSecTextureCoordBufferIndex = buffer[0]; 263 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mSecTextureCoordBufferIndex); 264 final int secTexCoordSize = mSecTexCoordBuffer.capacity() * 4; 265 mSecTexCoordBuffer.position(0); 266 gl11.glBufferData(GL11.GL_ARRAY_BUFFER, secTexCoordSize, mSecTexCoordBuffer, GL11.GL_STATIC_DRAW); 267 268 // Unbind the array buffer. 269 gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0); 270 271 // Allocate and fill the index buffer. 272 gl11.glGenBuffers(1, buffer, 0); 273 mIndexBufferIndex = buffer[0]; 274 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex); 275 // A char is 2 bytes. 276 final int indexSize = mIndexBuffer.capacity() * 2; 277 mIndexBuffer.position(0); 278 gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, indexSize, mIndexBuffer, GL11.GL_STATIC_DRAW); 279 280 // Unbind the element array buffer. 281 gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0); 282 } 283 } 284 } 285 } 286