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.ArrayList;
     20 
     21 public final class GridCameraManager {
     22     private final GridCamera mCamera;
     23     private static final Pool<Vector3f> sPool;
     24     static {
     25         final Vector3f[] vectorPool = new Vector3f[128];
     26         int length = vectorPool.length;
     27         for (int i = 0; i < length; ++i) {
     28             vectorPool[i] = new Vector3f();
     29         }
     30         sPool = new Pool<Vector3f>(vectorPool);
     31     }
     32 
     33     public GridCameraManager(final GridCamera camera) {
     34         mCamera = camera;
     35     }
     36 
     37     public void centerCameraForSlot(LayoutInterface layout, int slotIndex, float baseConvergence, Vector3f deltaAnchorPositionIn,
     38             int selectedSlotIndex, float zoomValue, float imageTheta, int state) {
     39         final GridCamera camera = mCamera;
     40         final Pool<Vector3f> pool = sPool;
     41         synchronized (camera) {
     42             final boolean zoomin = (selectedSlotIndex != Shared.INVALID);
     43             final int theta = (int) imageTheta;
     44             final int portrait = (theta / 90) % 2;
     45             if (slotIndex == selectedSlotIndex) {
     46                 camera.mConvergenceSpeed = baseConvergence * (zoomin ? 2.0f : 2.0f);
     47                 camera.mFriction = 0.0f;
     48             }
     49             final float oneByZoom = 1.0f / zoomValue;
     50             if (slotIndex >= 0) {
     51                 final Vector3f position = pool.create();
     52                 final Vector3f deltaAnchorPosition = pool.create();
     53                 try {
     54                     deltaAnchorPosition.set(deltaAnchorPositionIn);
     55                     GridCameraManager.getSlotPositionForSlotIndex(slotIndex, camera, layout, deltaAnchorPosition, position);
     56                     position.x = (zoomValue == 1.0f) ? ((position.x) * camera.mOneByScale) : camera.mLookAtX;
     57                     position.y = (zoomValue == 1.0f) ? 0 : camera.mLookAtY;
     58                     if (state == GridLayer.STATE_MEDIA_SETS || state == GridLayer.STATE_TIMELINE) {
     59                         position.y = -0.1f;
     60                     }
     61                     float width = camera.mItemWidth;
     62                     float height = camera.mItemHeight;
     63                     if (portrait != 0) {
     64                         float temp = width;
     65                         width = height;
     66                         height = temp;
     67                     }
     68                     camera.moveTo(position.x, position.y, zoomin ? camera.getDistanceToFitRect(width * oneByZoom, height
     69                             * oneByZoom) : 0);
     70                 } finally {
     71                     pool.delete(position);
     72                     pool.delete(deltaAnchorPosition);
     73                 }
     74             } else {
     75                 camera.moveYTo(0);
     76                 camera.moveZTo(0);
     77             }
     78         }
     79     }
     80 
     81     // CR: line too long. Documentation--what are the semantics of the return
     82     // value?
     83     /**
     84      */
     85     public boolean constrainCameraForSlot(LayoutInterface layout, int slotIndex, Vector3f deltaAnchorPositionIn,
     86             float currentFocusItemWidth, float currentFocusItemHeight) {
     87         final GridCamera camera = mCamera;
     88         final Pool<Vector3f> pool = sPool;
     89         boolean retVal = false;
     90         synchronized (camera) {
     91             final Vector3f position = pool.create();
     92             final Vector3f deltaAnchorPosition = pool.create();
     93             final Vector3f topLeft = pool.create();
     94             final Vector3f bottomRight = pool.create();
     95             final Vector3f imgTopLeft = pool.create();
     96             final Vector3f imgBottomRight = pool.create();
     97 
     98             try {
     99                 if (slotIndex >= 0) {
    100                     deltaAnchorPosition.set(deltaAnchorPositionIn);
    101                     GridCameraManager.getSlotPositionForSlotIndex(slotIndex, camera, layout, deltaAnchorPosition, position);
    102                     position.x *= camera.mOneByScale;
    103                     position.y = 0.0f;
    104                     float width = (currentFocusItemWidth / 2);
    105                     float height = (currentFocusItemHeight / 2);
    106                     imgTopLeft.set(position.x - width, position.y - height, 0);
    107                     imgBottomRight.set(position.x + width, position.y + height, 0);
    108                     camera.convertToCameraSpace(0, 0, 0, topLeft);
    109                     camera.convertToCameraSpace(camera.mWidth, camera.mHeight, 0, bottomRight);
    110                     float leftExtent = topLeft.x - imgTopLeft.x;
    111                     float rightExtent = bottomRight.x - imgBottomRight.x;
    112                     camera.mConvergenceSpeed = 2.0f;
    113                     camera.mFriction = 0.0f;
    114                     if (leftExtent < 0) {
    115                         retVal = true;
    116                         camera.moveBy(-leftExtent, 0, 0);
    117                     }
    118                     if (rightExtent > 0) {
    119                         retVal = true;
    120                         camera.moveBy(-rightExtent, 0, 0);
    121                     }
    122                     float topExtent = topLeft.y - imgTopLeft.y;
    123                     float bottomExtent = bottomRight.y - imgBottomRight.y;
    124                     if (topExtent < 0) {
    125                         camera.moveBy(0, -topExtent, 0);
    126                     }
    127                     if (bottomExtent > 0) {
    128                         camera.moveBy(0, -bottomExtent, 0);
    129                     }
    130                 }
    131             } finally {
    132                 pool.delete(position);
    133                 pool.delete(deltaAnchorPosition);
    134                 pool.delete(topLeft);
    135                 pool.delete(bottomRight);
    136                 pool.delete(imgTopLeft);
    137                 pool.delete(imgBottomRight);
    138             }
    139         }
    140         return retVal;
    141     }
    142 
    143     public void computeVisibleRange(MediaFeed feed, LayoutInterface layout, Vector3f deltaAnchorPositionIn,
    144             IndexRange outVisibleRange, IndexRange outBufferedVisibleRange, IndexRange outCompleteRange, int state) {
    145         GridCamera camera = mCamera;
    146         Pool<Vector3f> pool = sPool;
    147         float offset = (camera.mLookAtX * camera.mScale);
    148         int itemWidth = camera.mItemWidth;
    149         float maxIncrement = camera.mWidth * 0.5f + itemWidth;
    150         float left = -maxIncrement + offset;
    151         float right = left + 2.0f * maxIncrement;
    152         if (state == GridLayer.STATE_MEDIA_SETS || state == GridLayer.STATE_TIMELINE) {
    153             right += (itemWidth * 0.5f);
    154         }
    155         float top = -maxIncrement;
    156         float bottom = camera.mHeight + maxIncrement;
    157         // the hint to compute the visible display items
    158         int numSlots = 0;
    159         if (feed != null) {
    160             numSlots = feed.getNumSlots();
    161         }
    162         synchronized (outCompleteRange) {
    163             outCompleteRange.set(0, numSlots - 1);
    164         }
    165 
    166         Vector3f position = pool.create();
    167         Vector3f deltaAnchorPosition = pool.create();
    168         try {
    169             int firstVisibleSlotIndex = 0;
    170             int lastVisibleSlotIndex = numSlots - 1;
    171             int leftEdge = firstVisibleSlotIndex;
    172             int rightEdge = lastVisibleSlotIndex;
    173             int index = (leftEdge + rightEdge) / 2;
    174             lastVisibleSlotIndex = firstVisibleSlotIndex;
    175             deltaAnchorPosition.set(deltaAnchorPositionIn);
    176             while (index != leftEdge) {
    177                 GridCameraManager.getSlotPositionForSlotIndex(index, camera, layout, deltaAnchorPosition, position);
    178                 if (FloatUtils.boundsContainsPoint(left, right, top, bottom, position.x, position.y)) {
    179                     // this index is visible
    180                     firstVisibleSlotIndex = index;
    181                     lastVisibleSlotIndex = index;
    182                     break;
    183                 } else {
    184                     if (position.x > left) {
    185                         rightEdge = index;
    186                     } else {
    187                         leftEdge = index;
    188                     }
    189                     index = (leftEdge + rightEdge) / 2;
    190                 }
    191             }
    192             // CR: comments would make me a happy panda.
    193             while (firstVisibleSlotIndex >= 0 && firstVisibleSlotIndex < numSlots) {
    194                 GridCameraManager.getSlotPositionForSlotIndex(firstVisibleSlotIndex, camera, layout, deltaAnchorPosition, position);
    195                 // CR: !fubar instead of fubar == false.
    196                 if (FloatUtils.boundsContainsPoint(left, right, top, bottom, position.x, position.y) == false) {
    197                     ++firstVisibleSlotIndex;
    198                     break;
    199                 } else {
    200                     --firstVisibleSlotIndex;
    201                 }
    202             }
    203             while (lastVisibleSlotIndex >= 0 && lastVisibleSlotIndex < numSlots) {
    204                 GridCameraManager.getSlotPositionForSlotIndex(lastVisibleSlotIndex, camera, layout, deltaAnchorPosition, position);
    205                 if (FloatUtils.boundsContainsPoint(left, right, top, bottom, position.x, position.y) == false) {
    206                     --lastVisibleSlotIndex;
    207                     break;
    208                 } else {
    209                     ++lastVisibleSlotIndex;
    210                 }
    211             }
    212             if (firstVisibleSlotIndex < 0)
    213                 firstVisibleSlotIndex = 0;
    214             if (lastVisibleSlotIndex >= numSlots)
    215                 lastVisibleSlotIndex = numSlots - 1;
    216             synchronized (outVisibleRange) {
    217                 outVisibleRange.set(firstVisibleSlotIndex, lastVisibleSlotIndex);
    218             }
    219             if (feed != null) {
    220                 feed.setVisibleRange(firstVisibleSlotIndex, lastVisibleSlotIndex);
    221             }
    222             final int buffer = 24;
    223             firstVisibleSlotIndex = ((firstVisibleSlotIndex - buffer) / buffer) * buffer;
    224             lastVisibleSlotIndex += buffer;
    225             lastVisibleSlotIndex = (lastVisibleSlotIndex / buffer) * buffer;
    226             if (firstVisibleSlotIndex < 0) {
    227                 firstVisibleSlotIndex = 0;
    228             }
    229             if (lastVisibleSlotIndex >= numSlots) {
    230                 lastVisibleSlotIndex = numSlots - 1;
    231             }
    232             synchronized (outBufferedVisibleRange) {
    233                 outBufferedVisibleRange.set(firstVisibleSlotIndex, lastVisibleSlotIndex);
    234             }
    235         } finally {
    236             pool.delete(position);
    237             pool.delete(deltaAnchorPosition);
    238         }
    239     }
    240 
    241     public static final void getSlotPositionForSlotIndex(int slotIndex, GridCamera camera, LayoutInterface layout,
    242             Vector3f deltaAnchorPosition, Vector3f outVal) {
    243         layout.getPositionForSlotIndex(slotIndex, camera.mItemWidth, camera.mItemHeight, outVal);
    244         outVal.subtract(deltaAnchorPosition);
    245     }
    246 
    247     public static final float getFillScreenZoomValue(GridCamera camera, Pool<Vector3f> pool, float currentFocusItemWidth,
    248             float currentFocusItemHeight) {
    249         final Vector3f topLeft = pool.create();
    250         final Vector3f bottomRight = pool.create();
    251         float potentialZoomValue = 1.0f;
    252         try {
    253             camera.convertToCameraSpace(0, 0, 0, topLeft);
    254             camera.convertToCameraSpace(camera.mWidth, camera.mHeight, 0, bottomRight);
    255             float xExtent = Math.abs(topLeft.x - bottomRight.x) / currentFocusItemWidth;
    256             float yExtent = Math.abs(topLeft.y - bottomRight.y) / currentFocusItemHeight;
    257             potentialZoomValue = Math.max(xExtent, yExtent);
    258         } finally {
    259             pool.delete(topLeft);
    260             pool.delete(bottomRight);
    261         }
    262         return potentialZoomValue;
    263     }
    264 }