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.io.IOException;
     20 import java.io.InputStream;
     21 
     22 import javax.microedition.khronos.opengles.GL10;
     23 import javax.microedition.khronos.opengles.GL11;
     24 import javax.microedition.khronos.opengles.GL11Ext;
     25 
     26 import android.content.Context;
     27 import android.graphics.Bitmap;
     28 import android.graphics.BitmapFactory;
     29 import android.opengl.GLU;
     30 import android.opengl.GLUtils;
     31 
     32 /**
     33  * The Texture Library manages all textures in the game.  Textures are pooled and handed out to
     34  * requesting parties via allocateTexture().  However, the texture data itself is not immediately
     35  * loaded at that time; it may have already been loaded or it may be loaded in the future via
     36  * a call to loadTexture() or loadAllTextures().  This allows Texture objects to be dispersed to
     37  * various game systems and while the texture data itself is streamed in or loaded as necessary.
     38  */
     39 public class TextureLibrary extends BaseObject {
     40     // Textures are stored in a simple hash.  This class implements its own array-based hash rather
     41     // than using HashMap for performance.
     42     Texture[] mTextureHash;
     43     int[] mTextureNameWorkspace;
     44     int[] mCropWorkspace;
     45     static final int DEFAULT_SIZE = 512;
     46     static BitmapFactory.Options sBitmapOptions  = new BitmapFactory.Options();
     47 
     48     public TextureLibrary() {
     49         super();
     50         mTextureHash = new Texture[DEFAULT_SIZE];
     51         for (int x = 0; x < mTextureHash.length; x++) {
     52             mTextureHash[x] = new Texture();
     53         }
     54 
     55         mTextureNameWorkspace = new int[1];
     56         mCropWorkspace = new int[4];
     57 
     58         sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
     59     }
     60 
     61     @Override
     62     public void reset() {
     63         removeAll();
     64     }
     65 
     66     /**
     67      * Creates a Texture object that is mapped to the passed resource id.  If a texture has already
     68      * been allocated for this id, the previously allocated Texture object is returned.
     69      * @param resourceID
     70      * @return
     71      */
     72     public Texture allocateTexture(int resourceID) {
     73         Texture texture = getTextureByResource(resourceID);
     74         if (texture == null) {
     75             texture = addTexture(resourceID, -1, 0, 0);
     76         }
     77 
     78         return texture;
     79     }
     80 
     81     /** Loads a single texture into memory.  Does nothing if the texture is already loaded. */
     82     public Texture loadTexture(Context context, GL10 gl, int resourceID) {
     83         Texture texture = allocateTexture(resourceID);
     84         texture = loadBitmap(context, gl, texture);
     85         return texture;
     86     }
     87 
     88     /** Loads all unloaded textures into OpenGL memory.  Already-loaded textures are ignored. */
     89     public void loadAll(Context context, GL10 gl) {
     90         for (int x = 0; x < mTextureHash.length; x++) {
     91             if (mTextureHash[x].resource != -1 && mTextureHash[x].loaded == false) {
     92                 loadBitmap(context, gl, mTextureHash[x]);
     93             }
     94         }
     95     }
     96 
     97     /** Flushes all textures from OpenGL memory */
     98     public void deleteAll(GL10 gl) {
     99         for (int x = 0; x < mTextureHash.length; x++) {
    100             if (mTextureHash[x].resource != -1 && mTextureHash[x].loaded) {
    101             	assert mTextureHash[x].name != -1;
    102                 mTextureNameWorkspace[0] = mTextureHash[x].name;
    103                 mTextureHash[x].name = -1;
    104                 mTextureHash[x].loaded = false;
    105                 gl.glDeleteTextures(1, mTextureNameWorkspace, 0);
    106                 int error = gl.glGetError();
    107                 if (error != GL10.GL_NO_ERROR) {
    108                     DebugLog.d("Texture Delete", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + mTextureHash[x].resource);
    109                 }
    110 
    111                 assert error == GL10.GL_NO_ERROR;
    112             }
    113         }
    114     }
    115 
    116     /** Marks all textures as unloaded */
    117     public void invalidateAll() {
    118         for (int x = 0; x < mTextureHash.length; x++) {
    119             if (mTextureHash[x].resource != -1 && mTextureHash[x].loaded) {
    120                 mTextureHash[x].name = -1;
    121                 mTextureHash[x].loaded = false;
    122             }
    123         }
    124     }
    125 
    126     /** Loads a bitmap into OpenGL and sets up the common parameters for 2D texture maps. */
    127     protected Texture loadBitmap(Context context, GL10 gl, Texture texture) {
    128         assert gl != null;
    129         assert context != null;
    130         assert texture != null;
    131         if (texture.loaded == false && texture.resource != -1) {
    132             gl.glGenTextures(1, mTextureNameWorkspace, 0);
    133 
    134             int error = gl.glGetError();
    135             if (error != GL10.GL_NO_ERROR) {
    136                 DebugLog.d("Texture Load 1", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + texture.resource);
    137             }
    138 
    139             assert error == GL10.GL_NO_ERROR;
    140 
    141             int textureName = mTextureNameWorkspace[0];
    142 
    143             gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
    144 
    145             error = gl.glGetError();
    146             if (error != GL10.GL_NO_ERROR) {
    147                 DebugLog.d("Texture Load 2", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + texture.resource);
    148             }
    149 
    150             assert error == GL10.GL_NO_ERROR;
    151 
    152             gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
    153             gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
    154 
    155             gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
    156             gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
    157 
    158             gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE); //GL10.GL_REPLACE);
    159 
    160             InputStream is = context.getResources().openRawResource(texture.resource);
    161             Bitmap bitmap;
    162             try {
    163                 bitmap = BitmapFactory.decodeStream(is);
    164             } finally {
    165                 try {
    166                     is.close();
    167                 } catch (IOException e) {
    168                 	e.printStackTrace();
    169                     // Ignore.
    170                 }
    171             }
    172 
    173             GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
    174 
    175             error = gl.glGetError();
    176             if (error != GL10.GL_NO_ERROR) {
    177                 DebugLog.d("Texture Load 3", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + texture.resource);
    178             }
    179 
    180             assert error == GL10.GL_NO_ERROR;
    181 
    182             mCropWorkspace[0] = 0;
    183             mCropWorkspace[1] = bitmap.getHeight();
    184             mCropWorkspace[2] = bitmap.getWidth();
    185             mCropWorkspace[3] = -bitmap.getHeight();
    186 
    187             ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES,
    188                             mCropWorkspace, 0);
    189 
    190             texture.name = textureName;
    191             texture.width = bitmap.getWidth();
    192             texture.height = bitmap.getHeight();
    193 
    194             bitmap.recycle();
    195 
    196             error = gl.glGetError();
    197             if (error != GL10.GL_NO_ERROR) {
    198                 DebugLog.d("Texture Load 4", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + texture.resource);
    199             }
    200 
    201             assert error == GL10.GL_NO_ERROR;
    202 
    203             texture.loaded = true;
    204 
    205         }
    206 
    207         return texture;
    208     }
    209 
    210     public boolean isTextureLoaded(int resourceID) {
    211         return getTextureByResource(resourceID) != null;
    212     }
    213 
    214     /**
    215      * Returns the texture associated with the passed Android resource ID.
    216      * @param resourceID The resource ID of a bitmap defined in R.java.
    217      * @return An associated Texture object, or null if there is no associated
    218      *  texture in the library.
    219      */
    220     public Texture getTextureByResource(int resourceID) {
    221         int index = getHashIndex(resourceID);
    222         int realIndex = findFirstKey(index, resourceID);
    223         Texture texture = null;
    224         if (realIndex != -1) {
    225             texture = mTextureHash[realIndex];
    226         }
    227         return texture;
    228     }
    229 
    230     private int getHashIndex(int id) {
    231         return id % mTextureHash.length;
    232     }
    233 
    234     /**
    235      * Locates the texture in the hash.  This hash uses a simple linear probe chaining mechanism:
    236      * if the hash slot is occupied by some other entry, the next empty array index is used.
    237      * This is O(n) for the worst case (every slot is a cache miss) but the average case is
    238      * constant time.
    239      * @param startIndex
    240      * @param key
    241      * @return
    242      */
    243     private int findFirstKey(int startIndex, int key) {
    244         int index = -1;
    245         for (int x = 0; x < mTextureHash.length; x++) {
    246             final int actualIndex = (startIndex + x) % mTextureHash.length;
    247             if (mTextureHash[actualIndex].resource == key) {
    248                 index = actualIndex;
    249                 break;
    250             } else if (mTextureHash[actualIndex].resource == -1) {
    251                 break;
    252             }
    253         }
    254         return index;
    255     }
    256 
    257     /** Inserts a texture into the hash */
    258     protected Texture addTexture(int id, int name, int width, int height) {
    259         int index = findFirstKey(getHashIndex(id), -1);
    260         Texture texture = null;
    261         assert index != -1;
    262 
    263         if (index != -1) {
    264             mTextureHash[index].resource = id;
    265             mTextureHash[index].name = name;
    266             mTextureHash[index].width = width;
    267             mTextureHash[index].height = height;
    268             texture = mTextureHash[index];
    269         }
    270 
    271         return texture;
    272     }
    273 
    274     public void removeAll() {
    275         for (int x = 0; x < mTextureHash.length; x++) {
    276             mTextureHash[x].reset();
    277         }
    278     }
    279 
    280 }
    281