| /* |
| * 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 java.util.HashMap; |
| import javax.microedition.khronos.opengles.GL11; |
| import android.util.Log; |
| |
| import com.cooliris.app.Res; |
| 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) { |
| Texture fallback = mFallbackBackground; |
| if (fallback == null || !fallback.isLoaded()) |
| return false; |
| CrossFadingTexture background = mBackground; |
| if (background == null) { |
| background = new CrossFadingTexture(fallback); |
| mBackground = background; |
| } |
| final boolean retVal = background.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) { |
| background.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(Res.drawable.default_background, false); |
| view.loadTexture(mFallbackBackground); |
| } |
| } |
| |
| @Override |
| public void renderBlended(RenderView view, GL11 gl) { |
| CrossFadingTexture anchorTexture = mBackground; |
| 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); |
| 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(); |
| } |
| } |