package org.andengine.opengl.texture.bitmap; import java.io.IOException; import java.io.InputStream; import org.andengine.opengl.texture.ITextureStateListener; import org.andengine.opengl.texture.PixelFormat; import org.andengine.opengl.texture.Texture; import org.andengine.opengl.texture.TextureManager; import org.andengine.opengl.texture.TextureOptions; import org.andengine.opengl.util.GLState; import org.andengine.util.StreamUtils; import org.andengine.util.adt.io.in.IInputStreamOpener; import org.andengine.util.exception.NullBitmapException; import org.andengine.util.math.MathUtils; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.opengl.GLES20; import android.opengl.GLUtils; /** * (c) Zynga 2011 * * @author Nicolas Gramlich <ngramlich@zynga.com> * @since 16:16:25 - 30.07.2011 */ public class BitmapTexture extends Texture { // =========================================================== // Constants // =========================================================== // =========================================================== // Fields // =========================================================== private final int mWidth; private final int mHeight; private final IInputStreamOpener mInputStreamOpener; private final BitmapTextureFormat mBitmapTextureFormat; // =========================================================== // Constructors // =========================================================== public BitmapTexture(final TextureManager pTextureManager, final IInputStreamOpener pInputStreamOpener) throws IOException { this(pTextureManager, pInputStreamOpener, BitmapTextureFormat.RGBA_8888, TextureOptions.DEFAULT, null); } public BitmapTexture(final TextureManager pTextureManager, final IInputStreamOpener pInputStreamOpener, final BitmapTextureFormat pBitmapTextureFormat) throws IOException { this(pTextureManager, pInputStreamOpener, pBitmapTextureFormat, TextureOptions.DEFAULT, null); } public BitmapTexture(final TextureManager pTextureManager, final IInputStreamOpener pInputStreamOpener, final TextureOptions pTextureOptions) throws IOException { this(pTextureManager, pInputStreamOpener, BitmapTextureFormat.RGBA_8888, pTextureOptions, null); } public BitmapTexture(final TextureManager pTextureManager, final IInputStreamOpener pInputStreamOpener, final BitmapTextureFormat pBitmapTextureFormat, final TextureOptions pTextureOptions) throws IOException { this(pTextureManager, pInputStreamOpener, pBitmapTextureFormat, pTextureOptions, null); } public BitmapTexture(final TextureManager pTextureManager, final IInputStreamOpener pInputStreamOpener, final BitmapTextureFormat pBitmapTextureFormat, final TextureOptions pTextureOptions, final ITextureStateListener pTextureStateListener) throws IOException { super(pTextureManager, pBitmapTextureFormat.getPixelFormat(), pTextureOptions, pTextureStateListener); this.mInputStreamOpener = pInputStreamOpener; this.mBitmapTextureFormat = pBitmapTextureFormat; final BitmapFactory.Options decodeOptions = new BitmapFactory.Options(); decodeOptions.inJustDecodeBounds = true; final InputStream in = null; try { BitmapFactory.decodeStream(pInputStreamOpener.open(), null, decodeOptions); } finally { StreamUtils.close(in); } this.mWidth = decodeOptions.outWidth; this.mHeight = decodeOptions.outHeight; } // =========================================================== // Getter & Setter // =========================================================== @Override public int getWidth() { return this.mWidth; } @Override public int getHeight() { return this.mHeight; } // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== @Override protected void writeTextureToHardware(final GLState pGLState) throws IOException { final Config bitmapConfig = this.mBitmapTextureFormat.getBitmapConfig(); final Bitmap bitmap = this.onGetBitmap(bitmapConfig); if(bitmap == null) { throw new NullBitmapException("Caused by: '" + this.toString() + "'."); } final boolean useDefaultAlignment = MathUtils.isPowerOfTwo(bitmap.getWidth()) && MathUtils.isPowerOfTwo(bitmap.getHeight()) && (this.mPixelFormat == PixelFormat.RGBA_8888); if(!useDefaultAlignment) { /* Adjust unpack alignment. */ GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); } final boolean preMultipyAlpha = this.mTextureOptions.mPreMultiplyAlpha; if(preMultipyAlpha) { GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); } else { pGLState.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0, this.mPixelFormat); } if(!useDefaultAlignment) { /* Restore default unpack alignment. */ GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, GLState.GL_UNPACK_ALIGNMENT_DEFAULT); } bitmap.recycle(); } // =========================================================== // Methods // =========================================================== protected Bitmap onGetBitmap(final Config pBitmapConfig) throws IOException { final BitmapFactory.Options decodeOptions = new BitmapFactory.Options(); decodeOptions.inPreferredConfig = pBitmapConfig; return BitmapFactory.decodeStream(this.mInputStreamOpener.open(), null, decodeOptions); } // =========================================================== // Inner and Anonymous Classes // =========================================================== }