package com.cooliris.media; import java.util.HashMap; import javax.microedition.khronos.opengles.GL11; import android.util.Log; import com.cooliris.media.RenderView.Lists; public class BackgroundLayer extends Layer { private static final String TAG = "AdaptiveBackground"; private final GridLayer mGridLayer; private CrossFadingTexture mBackground; private static final int MAX_ADAPTIVES_TO_KEEP_IN_MEMORY = 16; private final HashMap<Texture, AdaptiveBackgroundTexture> mCacheAdaptiveTexture = new HashMap<Texture, AdaptiveBackgroundTexture>(); private int mCount; private int mBackgroundBlitWidth; private int mBackgroundOverlap; private Texture mFallbackBackground = null; private static final float Z_FAR_PLANE = 0.9999f; private static final float PARALLAX = 0.5f; private static final int ADAPTIVE_BACKGROUND_WIDTH = 256; private static final int ADAPTIVE_BACKGROUND_HEIGHT = 128; public BackgroundLayer(GridLayer layer) { mGridLayer = layer; } @Override public void generate(RenderView view, Lists lists) { lists.blendedList.add(this); lists.updateList.add(this); lists.opaqueList.add(this); } @Override public boolean update(RenderView view, float frameInterval) { if (mFallbackBackground == null || !mFallbackBackground.isLoaded()) return false; if (mBackground == null) { mBackground = new CrossFadingTexture(mFallbackBackground); } final boolean retVal = mBackground.update(frameInterval); int cameraPosition = (int) mGridLayer.getScrollPosition(); final int backgroundSpacing = mBackgroundBlitWidth - mBackgroundOverlap; cameraPosition = (int) ((cameraPosition / backgroundSpacing) * backgroundSpacing); final DisplayItem displayItem = mGridLayer.getRepresentativeDisplayItem(); if (displayItem != null) { mBackground.setTexture(getAdaptive(view, displayItem)); } return retVal; } private Texture getAdaptive(RenderView view, DisplayItem item) { if (item == null) { return mFallbackBackground; } Texture itemThumbnail = item.getThumbnailImage(view.getContext(), null); if (item == null || itemThumbnail == null || !itemThumbnail.isLoaded()) { return mFallbackBackground; } HashMap<Texture, AdaptiveBackgroundTexture> adaptives = mCacheAdaptiveTexture; AdaptiveBackgroundTexture retVal = adaptives.get(itemThumbnail); if (retVal == null) { retVal = new AdaptiveBackgroundTexture(itemThumbnail, ADAPTIVE_BACKGROUND_WIDTH, ADAPTIVE_BACKGROUND_HEIGHT); if (mCount == MAX_ADAPTIVES_TO_KEEP_IN_MEMORY) { mCount = 0; adaptives.clear(); Log.i(TAG, "Clearing unused adaptive backgrounds."); } ++mCount; adaptives.put(itemThumbnail, retVal); } return retVal; } @Override public void renderOpaque(RenderView view, GL11 gl) { gl.glClear(GL11.GL_COLOR_BUFFER_BIT); if (mFallbackBackground == null) { mFallbackBackground = view.getResource(R.drawable.default_background, false); view.loadTexture(mFallbackBackground); } } @Override public void renderBlended(RenderView view, GL11 gl) { if (mBackground == null || mFallbackBackground == null) return; gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE); CrossFadingTexture anchorTexture = mBackground; boolean bind = anchorTexture.bind(view, gl); if (!bind) { view.bind(mFallbackBackground); } else { Texture texture = anchorTexture.getTexture(); if (texture != null && texture.isLoaded()) { mFallbackBackground = texture; } } // We stitch this crossfading texture, and to cover all cases of overlap // we need to perform 3 draws. int cameraPosition = (int) (mGridLayer.getScrollPosition() * PARALLAX); int backgroundSpacing = mBackgroundBlitWidth - mBackgroundOverlap; int anchorEdge = -cameraPosition % (backgroundSpacing); int rightEdge = anchorEdge + backgroundSpacing; view.draw2D(rightEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight); view.draw2D(anchorEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight); int leftEdge = anchorEdge - backgroundSpacing; view.draw2D(leftEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight); if (bind) { anchorTexture.unbind(view, gl); } gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } @Override protected void onSizeChanged() { mBackgroundBlitWidth = (int) (mWidth * 1.5f); mBackgroundOverlap = (int) (mBackgroundBlitWidth * 0.25f); } public void clear() { clearCache(); mBackground = null; mFallbackBackground = null; } public void clearCache() { mCacheAdaptiveTexture.clear(); } }