• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TextureLibrary()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
reset()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      */
allocateTexture(int resourceID)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. */
loadTexture(Context context, GL10 gl, int resourceID)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. */
loadAll(Context context, GL10 gl)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 */
deleteAll(GL10 gl)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 */
invalidateAll()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. */
loadBitmap(Context context, GL10 gl, Texture texture)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 
isTextureLoaded(int resourceID)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      */
getTextureByResource(int resourceID)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 
getHashIndex(int id)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      */
findFirstKey(int startIndex, int key)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 */
addTexture(int id, int name, int width, int height)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 
removeAll()274     public void removeAll() {
275         for (int x = 0; x < mTextureHash.length; x++) {
276             mTextureHash[x].reset();
277         }
278     }
279 
280 }
281