/* * Copyright (C) 2009 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.cooliris.media; import javax.microedition.khronos.opengles.GL11; import javax.microedition.khronos.opengles.GL11Ext; import android.graphics.Bitmap; import android.graphics.Canvas; import android.opengl.GLUtils; public abstract class CanvasTexture { private int mWidth; private int mHeight; private int mTextureId; private int mTextureWidth; private int mTextureHeight; private float mNormalizedWidth; private float mNormalizedHeight; private final Canvas mCanvas = new Canvas(); private final Bitmap.Config mBitmapConfig; private Bitmap mBitmap = null; private boolean mNeedsDraw = false; private boolean mNeedsResize = false; private GL11 mCachedGL = null; public CanvasTexture(Bitmap.Config bitmapConfig) { mBitmapConfig = bitmapConfig; } public final void setNeedsDraw() { mNeedsDraw = true; } public final int getWidth() { return mWidth; } public final int getHeight() { return mHeight; } public final float getNormalizedWidth() { return mNormalizedWidth; } public final float getNormalizedHeight() { return mNormalizedHeight; } public final void setSize(int width, int height) { mWidth = width; mHeight = height; mNeedsResize = true; mTextureWidth = -1; mTextureHeight = -1; onSizeChanged(); } public void resetTexture() { // Happens when restoring the scene. Need to manage this more // automatically. mTextureId = 0; mNeedsResize = true; } // This code seems largely a dup of CanvasLayer. public boolean bind(GL11 gl) { if (mCachedGL != gl) { mCachedGL = gl; resetTexture(); } int width = (int) mWidth; int height = (int) mHeight; int textureId = mTextureId; int textureWidth = mTextureWidth; int textureHeight = mTextureHeight; Canvas canvas = mCanvas; Bitmap bitmap = mBitmap; if (mNeedsResize || mTextureId == 0) { // Clear the resize flag and mark as needing draw. mNeedsDraw = true; // Compute the power-of-2 padded size for the texture. int newTextureWidth = Shared.nextPowerOf2(width); int newTextureHeight = Shared.nextPowerOf2(height); // Reallocate the bitmap only if the padded size has changed. // TODO: reuse same texture if it is already large enough, just // change clip rect. if (textureWidth != newTextureWidth || textureHeight != newTextureHeight || mTextureId == 0) { // Allocate a texture if needed. if (textureId == 0) { int[] textureIdOut = new int[1]; gl.glGenTextures(1, textureIdOut, 0); textureId = textureIdOut[0]; mNeedsResize = false; mTextureId = textureId; // Set texture parameters. gl.glBindTexture(GL11.GL_TEXTURE_2D, textureId); gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); } // Set the new texture width and height. textureWidth = newTextureWidth; textureHeight = newTextureHeight; mTextureWidth = newTextureWidth; mTextureHeight = newTextureHeight; mNormalizedWidth = (float) width / textureWidth; mNormalizedHeight = (float) height / textureHeight; // Recycle the existing bitmap and create a new one. if (bitmap != null) bitmap.recycle(); if (textureWidth > 0 && textureHeight > 0) { bitmap = Bitmap.createBitmap(textureWidth, textureHeight, mBitmapConfig); canvas.setBitmap(bitmap); mBitmap = bitmap; } } } // Bind the texture to the context. if (textureId == 0) { return false; } gl.glBindTexture(GL11.GL_TEXTURE_2D, textureId); // Redraw the contents of the texture if needed. if (mNeedsDraw) { mNeedsDraw = false; renderCanvas(canvas, bitmap, width, height); int[] cropRect = { 0, height, width, -height }; gl.glTexParameteriv(GL11.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, 0); GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0); } return true; } public void draw(RenderView view, GL11 gl, int x, int y) { if (bind(gl)) { view.draw2D(x, y, 0, mWidth, mHeight); } } public void drawWithEffect(RenderView view, GL11 gl, float x, float y, float anchorX, float anchorY, float alpha, float scale) { if (bind(gl)) { float width = mWidth; float height = mHeight; // Apply scale transform if not identity. if (scale != 1) { // CR: 1.0f float originX = x + anchorX * width; float originY = y + anchorY * height; width *= scale; height *= scale; x = originX - anchorX * width; y = originY - anchorY * height; } // Set alpha if needed. if (alpha != 1f) { // CR: 1.0f view.setAlpha(alpha); } view.draw2D(x, y, 0, width, height); if (alpha != 1f) { view.resetColor(); } } } protected abstract void onSizeChanged(); protected abstract void renderCanvas(Canvas canvas, Bitmap backing, int width, int height); } // CR: superfluous newline above.