Home | History | Annotate | Download | only in media
      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 
     17 package com.cooliris.media;
     18 
     19 import java.util.HashMap;
     20 import javax.microedition.khronos.opengles.GL11;
     21 import android.util.Log;
     22 
     23 import com.cooliris.app.Res;
     24 import com.cooliris.media.RenderView.Lists;
     25 
     26 public 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