TextureLibrary.java :  » Game » replicaisland » com » replica » replicaisland » Android Open Source

Android Open Source » Game » replicaisland 
replicaisland » com » replica » replicaisland » TextureLibrary.java
/*
 * Copyright (C) 2010 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.replica.replicaisland;

import java.io.IOException;
import java.io.InputStream;

import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLU;
import android.opengl.GLUtils;

/**
 * The Texture Library manages all textures in the game.  Textures are pooled and handed out to
 * requesting parties via allocateTexture().  However, the texture data itself is not immediately
 * loaded at that time; it may have already been loaded or it may be loaded in the future via
 * a call to loadTexture() or loadAllTextures().  This allows Texture objects to be dispersed to
 * various game systems and while the texture data itself is streamed in or loaded as necessary.
 */
public class TextureLibrary extends BaseObject {
    // Textures are stored in a simple hash.  This class implements its own array-based hash rather
    // than using HashMap for performance.
    Texture[] mTextureHash;
    int[] mTextureNameWorkspace;
    int[] mCropWorkspace;
    static final int DEFAULT_SIZE = 512;
    static BitmapFactory.Options sBitmapOptions  = new BitmapFactory.Options();
    
    public TextureLibrary() {
        super();
        mTextureHash = new Texture[DEFAULT_SIZE];
        for (int x = 0; x < mTextureHash.length; x++) {
            mTextureHash[x] = new Texture();
        }

        mTextureNameWorkspace = new int[1];
        mCropWorkspace = new int[4];
                
        sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
    }
    
    @Override
    public void reset() {
        removeAll();
    }

    /** 
     * Creates a Texture object that is mapped to the passed resource id.  If a texture has already
     * been allocated for this id, the previously allocated Texture object is returned.
     * @param resourceID
     * @return
     */
    public Texture allocateTexture(int resourceID) {
        Texture texture = getTextureByResource(resourceID);
        if (texture == null) {
            texture = addTexture(resourceID, -1, 0, 0);
        }

        return texture;
    }

    /** Loads a single texture into memory.  Does nothing if the texture is already loaded. */
    public Texture loadTexture(Context context, GL10 gl, int resourceID) {
        Texture texture = allocateTexture(resourceID);
        texture = loadBitmap(context, gl, texture);
        return texture;
    }

    /** Loads all unloaded textures into OpenGL memory.  Already-loaded textures are ignored. */
    public void loadAll(Context context, GL10 gl) {
        for (int x = 0; x < mTextureHash.length; x++) {
            if (mTextureHash[x].resource != -1 && mTextureHash[x].loaded == false) {
                loadBitmap(context, gl, mTextureHash[x]);
            }
        }
    }

    /** Flushes all textures from OpenGL memory */
    public void deleteAll(GL10 gl) {
        for (int x = 0; x < mTextureHash.length; x++) {
            if (mTextureHash[x].resource != -1 && mTextureHash[x].loaded) {
              assert mTextureHash[x].name != -1;
                mTextureNameWorkspace[0] = mTextureHash[x].name;
                mTextureHash[x].name = -1;
                mTextureHash[x].loaded = false;
                gl.glDeleteTextures(1, mTextureNameWorkspace, 0);
                int error = gl.glGetError();
                if (error != GL10.GL_NO_ERROR) {
                    DebugLog.d("Texture Delete", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + mTextureHash[x].resource);
                }
                
                assert error == GL10.GL_NO_ERROR;
            }
        }
    }
    
    /** Marks all textures as unloaded */
    public void invalidateAll() {
        for (int x = 0; x < mTextureHash.length; x++) {
            if (mTextureHash[x].resource != -1 && mTextureHash[x].loaded) {
                mTextureHash[x].name = -1;
                mTextureHash[x].loaded = false;
            }
        }
    }

    /** Loads a bitmap into OpenGL and sets up the common parameters for 2D texture maps. */
    protected Texture loadBitmap(Context context, GL10 gl, Texture texture) {
        assert gl != null;
        assert context != null;
        assert texture != null;
        if (texture.loaded == false && texture.resource != -1) {
            gl.glGenTextures(1, mTextureNameWorkspace, 0);
            
            int error = gl.glGetError();
            if (error != GL10.GL_NO_ERROR) {
                DebugLog.d("Texture Load 1", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + texture.resource);
            }
            
            assert error == GL10.GL_NO_ERROR;
            
            int textureName = mTextureNameWorkspace[0];
            
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
            
            error = gl.glGetError();
            if (error != GL10.GL_NO_ERROR) {
                DebugLog.d("Texture Load 2", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + texture.resource);
            }
            
            assert error == GL10.GL_NO_ERROR;

            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

            gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE); //GL10.GL_REPLACE);

            InputStream is = context.getResources().openRawResource(texture.resource);
            Bitmap bitmap;
            try {
                bitmap = BitmapFactory.decodeStream(is);
            } finally {
                try {
                    is.close();
                } catch (IOException e) {
                  e.printStackTrace();
                    // Ignore.
                }
            }
            
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
            
            error = gl.glGetError();
            if (error != GL10.GL_NO_ERROR) {
                DebugLog.d("Texture Load 3", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + texture.resource);
            }
            
            assert error == GL10.GL_NO_ERROR;

            mCropWorkspace[0] = 0;
            mCropWorkspace[1] = bitmap.getHeight();
            mCropWorkspace[2] = bitmap.getWidth();
            mCropWorkspace[3] = -bitmap.getHeight();

            ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES,
                            mCropWorkspace, 0);

            texture.name = textureName;
            texture.width = bitmap.getWidth();
            texture.height = bitmap.getHeight();

            bitmap.recycle();
            
            error = gl.glGetError();
            if (error != GL10.GL_NO_ERROR) {
                DebugLog.d("Texture Load 4", "GLError: " + error + " (" + GLU.gluErrorString(error) + "): " + texture.resource);
            }
            
            assert error == GL10.GL_NO_ERROR;
            
            texture.loaded = true;

        }

        return texture;
    }

    public boolean isTextureLoaded(int resourceID) {
        return getTextureByResource(resourceID) != null;
    }

    /**
     * Returns the texture associated with the passed Android resource ID.
     * @param resourceID The resource ID of a bitmap defined in R.java.
     * @return An associated Texture object, or null if there is no associated
     *  texture in the library.
     */
    public Texture getTextureByResource(int resourceID) {
        int index = getHashIndex(resourceID);
        int realIndex = findFirstKey(index, resourceID);
        Texture texture = null;
        if (realIndex != -1) {
            texture = mTextureHash[realIndex];
        }        
        return texture;
    }

    private int getHashIndex(int id) {
        return id % mTextureHash.length;
    }

    /**
     * Locates the texture in the hash.  This hash uses a simple linear probe chaining mechanism:
     * if the hash slot is occupied by some other entry, the next empty array index is used.  
     * This is O(n) for the worst case (every slot is a cache miss) but the average case is
     * constant time. 
     * @param startIndex
     * @param key
     * @return
     */
    private int findFirstKey(int startIndex, int key) {
        int index = -1;
        for (int x = 0; x < mTextureHash.length; x++) {
            final int actualIndex = (startIndex + x) % mTextureHash.length;
            if (mTextureHash[actualIndex].resource == key) {
                index = actualIndex;
                break;
            } else if (mTextureHash[actualIndex].resource == -1) {
                break;
            }
        }
        return index;
    }

    /** Inserts a texture into the hash */
    protected Texture addTexture(int id, int name, int width, int height) {
        int index = findFirstKey(getHashIndex(id), -1);
        Texture texture = null;
        assert index != -1;
        
        if (index != -1) {
            mTextureHash[index].resource = id;
            mTextureHash[index].name = name;
            mTextureHash[index].width = width;
            mTextureHash[index].height = height;
            texture = mTextureHash[index];
        }

        return texture;
    }
    
    public void removeAll() {
        for (int x = 0; x < mTextureHash.length; x++) {
            mTextureHash[x].reset();
        }
    }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.