Home | History | Annotate | Download | only in replicaisland
      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 
     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