1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.cooliris.media; 18 19import java.util.HashMap; 20import javax.microedition.khronos.opengles.GL11; 21import android.util.Log; 22 23import com.cooliris.app.Res; 24import com.cooliris.media.RenderView.Lists; 25 26public class BackgroundLayer extends Layer { 27 private static final String TAG = "AdaptiveBackground"; 28 private final GridLayer mGridLayer; 29 private CrossFadingTexture mBackground; 30 private static final int MAX_ADAPTIVES_TO_KEEP_IN_MEMORY = 16; 31 32 private final HashMap<Texture, AdaptiveBackgroundTexture> mCacheAdaptiveTexture = new HashMap<Texture, AdaptiveBackgroundTexture>(); 33 private int mCount; 34 private int mBackgroundBlitWidth; 35 private int mBackgroundOverlap; 36 private Texture mFallbackBackground = null; 37 private static final float Z_FAR_PLANE = 0.9999f; 38 private static final float PARALLAX = 0.5f; 39 private static final int ADAPTIVE_BACKGROUND_WIDTH = 256; 40 private static final int ADAPTIVE_BACKGROUND_HEIGHT = 128; 41 42 public BackgroundLayer(GridLayer layer) { 43 mGridLayer = layer; 44 } 45 46 @Override 47 public void generate(RenderView view, Lists lists) { 48 lists.blendedList.add(this); 49 lists.updateList.add(this); 50 lists.opaqueList.add(this); 51 } 52 53 @Override 54 public boolean update(RenderView view, float frameInterval) { 55 Texture fallback = mFallbackBackground; 56 if (fallback == null || !fallback.isLoaded()) 57 return false; 58 CrossFadingTexture background = mBackground; 59 if (background == null) { 60 background = new CrossFadingTexture(fallback); 61 mBackground = background; 62 } 63 final boolean retVal = background.update(frameInterval); 64 int cameraPosition = (int) mGridLayer.getScrollPosition(); 65 final int backgroundSpacing = mBackgroundBlitWidth - mBackgroundOverlap; 66 cameraPosition = (int) ((cameraPosition / backgroundSpacing) * backgroundSpacing); 67 final DisplayItem displayItem = mGridLayer.getRepresentativeDisplayItem(); 68 if (displayItem != null) { 69 background.setTexture(getAdaptive(view, displayItem)); 70 } 71 return retVal; 72 } 73 74 private Texture getAdaptive(RenderView view, DisplayItem item) { 75 if (item == null) { 76 return mFallbackBackground; 77 } 78 Texture itemThumbnail = item.getThumbnailImage(view.getContext(), null); 79 if (item == null || itemThumbnail == null || !itemThumbnail.isLoaded()) { 80 return mFallbackBackground; 81 } 82 HashMap<Texture, AdaptiveBackgroundTexture> adaptives = mCacheAdaptiveTexture; 83 AdaptiveBackgroundTexture retVal = adaptives.get(itemThumbnail); 84 if (retVal == null) { 85 retVal = new AdaptiveBackgroundTexture(itemThumbnail, ADAPTIVE_BACKGROUND_WIDTH, ADAPTIVE_BACKGROUND_HEIGHT); 86 if (mCount == MAX_ADAPTIVES_TO_KEEP_IN_MEMORY) { 87 mCount = 0; 88 adaptives.clear(); 89 Log.i(TAG, "Clearing unused adaptive backgrounds."); 90 } 91 ++mCount; 92 adaptives.put(itemThumbnail, retVal); 93 } 94 return retVal; 95 } 96 97 @Override 98 public void renderOpaque(RenderView view, GL11 gl) { 99 gl.glClear(GL11.GL_COLOR_BUFFER_BIT); 100 if (mFallbackBackground == null) { 101 mFallbackBackground = view.getResource(Res.drawable.default_background, false); 102 view.loadTexture(mFallbackBackground); 103 } 104 } 105 106 @Override 107 public void renderBlended(RenderView view, GL11 gl) { 108 CrossFadingTexture anchorTexture = mBackground; 109 if (mBackground == null || mFallbackBackground == null) 110 return; 111 gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); 112 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE); 113 boolean bind = anchorTexture.bind(view, gl); 114 if (!bind) { 115 view.bind(mFallbackBackground); 116 } else { 117 Texture texture = anchorTexture.getTexture(); 118 if (texture != null && texture.isLoaded()) { 119 mFallbackBackground = texture; 120 } 121 } 122 123 // We stitch this crossfading texture, and to cover all cases of overlap 124 // we need to perform 3 draws. 125 int cameraPosition = (int) (mGridLayer.getScrollPosition() * PARALLAX); 126 int backgroundSpacing = mBackgroundBlitWidth - mBackgroundOverlap; 127 int anchorEdge = -cameraPosition % (backgroundSpacing); 128 int rightEdge = anchorEdge + backgroundSpacing; 129 130 view.draw2D(rightEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight); 131 132 view.draw2D(anchorEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight); 133 134 int leftEdge = anchorEdge - backgroundSpacing; 135 view.draw2D(leftEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight); 136 137 if (bind) { 138 anchorTexture.unbind(view, gl); 139 } 140 141 gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); 142 gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 143 } 144 145 @Override 146 protected void onSizeChanged() { 147 mBackgroundBlitWidth = (int) (mWidth * 1.5f); 148 mBackgroundOverlap = (int) (mBackgroundBlitWidth * 0.25f); 149 } 150 151 public void clear() { 152 clearCache(); 153 mBackground = null; 154 mFallbackBackground = null; 155 } 156 157 public void clearCache() { 158 mCacheAdaptiveTexture.clear(); 159 } 160} 161