// Copyright 2008 Google Inc. // // 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.google.android.stardroid.renderer.util; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.opengl.GLUtils; import android.util.Log; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import javax.microedition.khronos.opengles.GL10; /** * Manages all textures used by the application. Useful to make sure that we don't accidentally * use deleted textures and don't leak textures, and that we don't create multiple instances of the * same texture. * * TODO(jpowell): We only ever need one instance of this class, but it would be cleaner if it was * a normal class instead of a global singleton, so I should change it when I get a chance. * * @author James Powell * */ public final class TextureManager { private final Resources mRes; private Map<Integer, TextureData> mResourceIdToTextureMap = new HashMap<Integer, TextureData>(); private ArrayList<TextureReferenceImpl> mAllTextures = new ArrayList<TextureReferenceImpl>(); public TextureManager(Resources res) { mRes = res; } public TextureReference createTexture(GL10 gl) { return createTextureInternal(gl); } public TextureReference getTextureFromResource(GL10 gl, int resourceID) { // If the texture already exists, return it. TextureData texData = mResourceIdToTextureMap.get(resourceID); if (texData != null) { // Increment the reference count texData.refCount++; return texData.ref; } TextureReferenceImpl tex = createTextureFromResource(gl, resourceID); // Add it to the map. TextureData data = new TextureData(); data.ref = tex; data.refCount = 1; mResourceIdToTextureMap.put(resourceID, data); return tex; } public void reset() { mResourceIdToTextureMap.clear(); for (TextureReferenceImpl ref : mAllTextures) { ref.invalidate(); } mAllTextures.clear(); } private static class TextureReferenceImpl implements TextureReference { public TextureReferenceImpl(int id) { mTextureID = id; } public void bind(GL10 gl) { checkValid(); gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID); } public void delete(GL10 gl) { checkValid(); gl.glDeleteTextures(1, new int[] {mTextureID}, 0); invalidate(); } public int getID() { return mTextureID; } public void invalidate() { mValid = false; } private void checkValid() { if (!mValid) { Log.e("TextureManager", "Setting invalidated texture ID: " + mTextureID); StringWriter writer = new StringWriter(); new Throwable().printStackTrace(new PrintWriter(writer)); Log.e("TextureManager", writer.toString()); } } private int mTextureID; private boolean mValid = true; } private static class TextureData { public TextureReferenceImpl ref = null; public int refCount = 0; } private TextureReferenceImpl createTextureFromResource(GL10 gl, int resourceID) { // The texture hasn't been loaded yet, so load it. TextureReferenceImpl tex = createTextureInternal(gl); Options opts = new Options(); opts.inScaled = false; Bitmap bmp = BitmapFactory.decodeResource(mRes, resourceID, opts); tex.bind(gl); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 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); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0); bmp.recycle(); return tex; } private TextureReferenceImpl createTextureInternal(GL10 gl) { // The texture hasn't been loaded yet, so load it. int[] texID = new int[1]; gl.glGenTextures(1, texID, 0); TextureReferenceImpl tex = new TextureReferenceImpl(texID[0]); mAllTextures.add(tex); return tex; } }