blob: f3e542f07879563e0251e459b8ab4a834b173748 [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cooliris.media;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
final class GridQuadFrame {
private FloatBuffer mVertexBuffer;
private FloatBuffer mTexCoordBuffer;
private FloatBuffer mSecTexCoordBuffer;
private CharBuffer mIndexBuffer;
private int mW;
private int mH;
// This has 8 quads, 16 vertices, 22 triangles (for tristrip).
// We have more triangles because we have to make degenerate triangles to
// use tri-strips
public static final int INDEX_COUNT = 25;
private int mVertBufferIndex;
private int mIndexBufferIndex;
private int mTextureCoordBufferIndex;
private int mSecTextureCoordBufferIndex;
public static GridQuadFrame createFrame(float width, float height, int itemWidth, int itemHeight) {
GridQuadFrame frame = new GridQuadFrame();
final float textureSize = 64.0f;
final float numPixelsYOriginShift = 7;
final float inset = 6;
final float ratio = 1.0f / (float) itemHeight;
final float frameXThickness = 0.5f * textureSize * ratio;
final float frameYThickness = 0.5f * textureSize * ratio;
final float frameX = width * 0.5f + frameXThickness * 0.5f - inset * ratio;
float frameY = height * 0.5f + frameYThickness * 0.5f + (inset - 1) * ratio;
final float originX = 0.0f;
final float originY = numPixelsYOriginShift * ratio;
frame.set(0, 0, -frameX + originX, -frameY + originY, 0, 1.0f, 1.0f);
frame.set(1, 0, -frameX + originX + frameXThickness, -frameY + originY, 0, 0.5f, 1.0f);
frame.set(2, 0, frameX - frameXThickness + originX, -frameY + originY, 0, 0.5f, 1.0f);
frame.set(3, 0, frameX + originX, -frameY + originY, 0, 0.0f, 1.0f);
frameY -= frameYThickness;
frame.set(0, 1, -frameX + originX, -frameY + originY, 0, 1.0f, 0.5f);
frame.set(1, 1, -frameX + frameXThickness + originX, -frameY + originY, 0, 0.5f, 0.5f);
frame.set(2, 1, frameX - frameXThickness + originX, -frameY + originY, 0, 0.5f, 0.5f);
frame.set(3, 1, frameX + originX, -frameY + originY, 0, 0.0f, 0.5f);
frameY = height * 0.5f - frameYThickness;
frame.set(0, 2, -frameX + originX, frameY + originY, 0, 1.0f, 0.5f);
frame.set(1, 2, -frameX + frameXThickness + originX, frameY + originY, 0, 0.5f, 0.5f);
frame.set(2, 2, frameX - frameXThickness + originX, frameY + originY, 0, 0.5f, 0.5f);
frame.set(3, 2, frameX + originX, frameY + originY, 0, 0.0f, 0.5f);
frameY += frameYThickness;
frame.set(0, 3, -frameX + originX, frameY + originY, 0, 1.0f, 0.0f);
frame.set(1, 3, -frameX + frameXThickness + originX, frameY + originY, 0, 0.5f, 0.0f);
frame.set(2, 3, frameX - frameXThickness + originX, frameY + originY, 0, 0.5f, 0.0f);
frame.set(3, 3, frameX + originX, frameY + originY, 0, 0.0f, 0.0f);
return frame;
}
public GridQuadFrame() {
int vertsAcross = 4;
int vertsDown = 4;
mW = vertsAcross;
mH = vertsDown;
int size = vertsAcross * vertsDown;
final int FLOAT_SIZE = 4;
final int CHAR_SIZE = 2;
mVertexBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 3).order(ByteOrder.nativeOrder()).asFloatBuffer();
mTexCoordBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
mSecTexCoordBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
int indexCount = INDEX_COUNT; // using tristrips
mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount).order(ByteOrder.nativeOrder()).asCharBuffer();
/*
* Initialize triangle list mesh.
*
* [0]---[1]---------[2]---[3] ... | / | / | / |
* [4]---[5]---------[6]---[7] | / | | /| | / | | / | | / | | / |
* [8]---[9]---------[10]---[11] | / | \ | \ |
* [12]--[13]--------[14]---[15]
*/
CharBuffer buffer = mIndexBuffer;
buffer.put(0, (char) 0);
buffer.put(1, (char) 4);
buffer.put(2, (char) 1);
buffer.put(3, (char) 5);
buffer.put(4, (char) 2);
buffer.put(5, (char) 6);
buffer.put(6, (char) 3);
buffer.put(7, (char) 7);
buffer.put(8, (char) 11);
buffer.put(9, (char) 6);
buffer.put(10, (char) 10);
buffer.put(11, (char) 14);
buffer.put(12, (char) 11);
buffer.put(13, (char) 15);
buffer.put(14, (char) 15);
buffer.put(15, (char) 14);
buffer.put(16, (char) 14);
buffer.put(17, (char) 10);
buffer.put(18, (char) 13);
buffer.put(19, (char) 9);
buffer.put(20, (char) 12);
buffer.put(21, (char) 8);
buffer.put(22, (char) 4);
buffer.put(23, (char) 9);
buffer.put(24, (char) 5);
mVertBufferIndex = 0;
}
void set(int i, int j, float x, float y, float z, float u, float v) {
if (i < 0 || i >= mW) {
throw new IllegalArgumentException("i");
}
if (j < 0 || j >= mH) {
throw new IllegalArgumentException("j");
}
int index = mW * j + i;
int posIndex = index * 3;
mVertexBuffer.put(posIndex, x);
mVertexBuffer.put(posIndex + 1, y);
mVertexBuffer.put(posIndex + 2, z);
int texIndex = index * 2;
mTexCoordBuffer.put(texIndex, u);
mTexCoordBuffer.put(texIndex + 1, v);
int secTexIndex = index * 2;
mSecTexCoordBuffer.put(secTexIndex, u);
mSecTexCoordBuffer.put(secTexIndex + 1, v);
}
public void bindArrays(GL10 gl) {
GL11 gl11 = (GL11) gl;
// draw using hardware buffers
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex);
gl11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex);
gl11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
gl11.glClientActiveTexture(GL11.GL_TEXTURE1);
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mSecTextureCoordBufferIndex);
gl11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
gl11.glClientActiveTexture(GL11.GL_TEXTURE0);
gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex);
}
public static final void draw(GL11 gl11) {
// Don't call this method unless bindArrays was called.
gl11.glDrawElements(GL11.GL_TRIANGLE_STRIP, INDEX_COUNT, GL11.GL_UNSIGNED_SHORT, 0);
}
public void unbindArrays(GL10 gl) {
GL11 gl11 = (GL11) gl;
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
}
public boolean usingHardwareBuffers() {
return mVertBufferIndex != 0;
}
/**
* When the OpenGL ES device is lost, GL handles become invalidated. In that
* case, we just want to "forget" the old handles (without explicitly
* deleting them) and make new ones.
*/
public void forgetHardwareBuffers() {
mVertBufferIndex = 0;
mIndexBufferIndex = 0;
mTextureCoordBufferIndex = 0;
mSecTextureCoordBufferIndex = 0;
}
/**
* Deletes the hardware buffers allocated by this object (if any).
*/
public void freeHardwareBuffers(GL10 gl) {
if (mVertBufferIndex != 0) {
if (gl instanceof GL11) {
GL11 gl11 = (GL11) gl;
int[] buffer = new int[1];
buffer[0] = mVertBufferIndex;
gl11.glDeleteBuffers(1, buffer, 0);
buffer[0] = mTextureCoordBufferIndex;
gl11.glDeleteBuffers(1, buffer, 0);
buffer[0] = mSecTextureCoordBufferIndex;
gl11.glDeleteBuffers(1, buffer, 0);
buffer[0] = mIndexBufferIndex;
gl11.glDeleteBuffers(1, buffer, 0);
}
forgetHardwareBuffers();
}
}
/**
* Allocates hardware buffers on the graphics card and fills them with data
* if a buffer has not already been previously allocated. Note that this
* function uses the GL_OES_vertex_buffer_object extension, which is not
* guaranteed to be supported on every device.
*
* @param gl
* A pointer to the OpenGL ES context.
*/
public void generateHardwareBuffers(GL10 gl) {
if (mVertBufferIndex == 0) {
if (gl instanceof GL11) {
GL11 gl11 = (GL11) gl;
int[] buffer = new int[1];
// Allocate and fill the vertex buffer.
gl11.glGenBuffers(1, buffer, 0);
mVertBufferIndex = buffer[0];
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex);
mVertexBuffer.position(0);
final int vertexSize = mVertexBuffer.capacity() * 4;
gl11.glBufferData(GL11.GL_ARRAY_BUFFER, vertexSize, mVertexBuffer, GL11.GL_STATIC_DRAW);
// Allocate and fill the texture coordinate buffer.
gl11.glGenBuffers(1, buffer, 0);
mTextureCoordBufferIndex = buffer[0];
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex);
final int texCoordSize = mTexCoordBuffer.capacity() * 4;
mTexCoordBuffer.position(0);
gl11.glBufferData(GL11.GL_ARRAY_BUFFER, texCoordSize, mTexCoordBuffer, GL11.GL_STATIC_DRAW);
// Allocate and fill the secondary texture coordinate buffer.
gl11.glGenBuffers(1, buffer, 0);
mSecTextureCoordBufferIndex = buffer[0];
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mSecTextureCoordBufferIndex);
final int secTexCoordSize = mSecTexCoordBuffer.capacity() * 4;
mSecTexCoordBuffer.position(0);
gl11.glBufferData(GL11.GL_ARRAY_BUFFER, secTexCoordSize, mSecTexCoordBuffer, GL11.GL_STATIC_DRAW);
// Unbind the array buffer.
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
// Allocate and fill the index buffer.
gl11.glGenBuffers(1, buffer, 0);
mIndexBufferIndex = buffer[0];
gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex);
// A char is 2 bytes.
final int indexSize = mIndexBuffer.capacity() * 2;
mIndexBuffer.position(0);
gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, indexSize, mIndexBuffer, GL11.GL_STATIC_DRAW);
// Unbind the element array buffer.
gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
}
}
}
}