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                     camera.mConvergenceSpeed = 2.0f;
    111                     camera.mFriction = 0.0f;
    112                     if ((bottomRight.x - topLeft.x) > (imgBottomRight.x - imgTopLeft.x)) {
    113                         final float hCenterExtent= (bottomRight.x + topLeft.x)/2 -
    114                             (imgBottomRight.x + imgTopLeft.x)/2;
    115                         camera.moveBy(-hCenterExtent, 0, 0);
    116                     } else {
    117                         float leftExtent = topLeft.x - imgTopLeft.x;
    118                         float rightExtent = bottomRight.x - imgBottomRight.x;
    119                         if (leftExtent < 0) {
    120                             retVal = true;
    121                             camera.moveBy(-leftExtent, 0, 0);
    122                         }
    123                         if (rightExtent > 0) {
    124                             retVal = true;
    125                             camera.moveBy(-rightExtent, 0, 0);
    126                         }
    127                     }
    128                     if ((bottomRight.y - topLeft.y) > (imgBottomRight.y - imgTopLeft.y)) {
    129                         final float vCenterExtent= (bottomRight.y + topLeft.y)/2 -
    130                             (imgBottomRight.y + imgTopLeft.y)/2;
    131                         camera.moveBy(0, -vCenterExtent, 0);
    132                     } else {
    133                         float topExtent = topLeft.y - imgTopLeft.y;
    134                         float bottomExtent = bottomRight.y - imgBottomRight.y;
    135                         if (topExtent < 0) {
    136                             camera.moveBy(0, -topExtent, 0);
    137                         }
    138                         if (bottomExtent > 0) {
    139                             camera.moveBy(0, -bottomExtent, 0);
    140                         }
    141                     }
    142                 }
    143             } finally {
    144                 pool.delete(position);
    145                 pool.delete(deltaAnchorPosition);
    146                 pool.delete(topLeft);
    147                 pool.delete(bottomRight);
    148                 pool.delete(imgTopLeft);
    149                 pool.delete(imgBottomRight);
    150             }
    151         }
    152         return retVal;
    153     }
    154 
    155     public void computeVisibleRange(MediaFeed feed, LayoutInterface layout, Vector3f deltaAnchorPositionIn,
    156             IndexRange outVisibleRange, IndexRange outBufferedVisibleRange, IndexRange outCompleteRange, int state) {
    157         GridCamera camera = mCamera;
    158         Pool<Vector3f> pool = sPool;
    159         float offset = (camera.mLookAtX * camera.mScale);
    160         int itemWidth = camera.mItemWidth;
    161         float maxIncrement = camera.mWidth * 0.5f + itemWidth;
    162         float left = -maxIncrement + offset;
    163         float right = left + 2.0f * maxIncrement;
    164         if (state == GridLayer.STATE_MEDIA_SETS || state == GridLayer.STATE_TIMELINE) {
    165             right += (itemWidth * 0.5f);
    166         }
    167         float top = -maxIncrement;
    168         float bottom = camera.mHeight + maxIncrement;
    169         // the hint to compute the visible display items
    170         int numSlots = 0;
    171         if (feed != null) {
    172             numSlots = feed.getNumSlots();
    173         }
    174         synchronized (outCompleteRange) {
    175             outCompleteRange.set(0, numSlots - 1);
    176         }
    177 
    178         Vector3f position = pool.create();
    179         Vector3f deltaAnchorPosition = pool.create();
    180         try {
    181             int firstVisibleSlotIndex = 0;
    182             int lastVisibleSlotIndex = numSlots - 1;
    183             int leftEdge = firstVisibleSlotIndex;
    184             int rightEdge = lastVisibleSlotIndex;
    185             int index = (leftEdge + rightEdge) / 2;
    186             lastVisibleSlotIndex = firstVisibleSlotIndex;
    187             deltaAnchorPosition.set(deltaAnchorPositionIn);
    188             while (index != leftEdge) {
    189                 GridCameraManager.getSlotPositionForSlotIndex(index, camera, layout, deltaAnchorPosition, position);
    190                 if (FloatUtils.boundsContainsPoint(left, right, top, bottom, position.x, position.y)) {
    191                     // this index is visible
    192                     firstVisibleSlotIndex = index;
    193                     lastVisibleSlotIndex = index;
    194                     break;
    195                 } else {
    196                     if (position.x > left) {
    197                         rightEdge = index;
    198                     } else {
    199                         leftEdge = index;
    200                     }
    201                     index = (leftEdge + rightEdge) / 2;
    202                 }
    203             }
    204             // CR: comments would make me a happy panda.
    205             while (firstVisibleSlotIndex >= 0 && firstVisibleSlotIndex < numSlots) {
    206                 GridCameraManager.getSlotPositionForSlotIndex(firstVisibleSlotIndex, camera, layout, deltaAnchorPosition, position);
    207                 // CR: !fubar instead of fubar == false.
    208                 if (FloatUtils.boundsContainsPoint(left, right, top, bottom, position.x, position.y) == false) {
    209                     ++firstVisibleSlotIndex;
    210                     break;
    211                 } else {
    212                     --firstVisibleSlotIndex;
    213                 }
    214             }
    215             while (lastVisibleSlotIndex >= 0 && lastVisibleSlotIndex < numSlots) {
    216                 GridCameraManager.getSlotPositionForSlotIndex(lastVisibleSlotIndex, camera, layout, deltaAnchorPosition, position);
    217                 if (FloatUtils.boundsContainsPoint(left, right, top, bottom, position.x, position.y) == false) {
    218                     --lastVisibleSlotIndex;
    219                     break;
    220                 } else {
    221                     ++lastVisibleSlotIndex;
    222                 }
    223             }
    224             if (firstVisibleSlotIndex < 0)
    225                 firstVisibleSlotIndex = 0;
    226             if (lastVisibleSlotIndex >= numSlots)
    227                 lastVisibleSlotIndex = numSlots - 1;
    228             synchronized (outVisibleRange) {
    229                 outVisibleRange.set(firstVisibleSlotIndex, lastVisibleSlotIndex);
    230             }
    231             if (feed != null) {
    232                 feed.setVisibleRange(firstVisibleSlotIndex, lastVisibleSlotIndex);
    233             }
    234             final int buffer = 24;
    235             firstVisibleSlotIndex = ((firstVisibleSlotIndex - buffer) / buffer) * buffer;
    236             lastVisibleSlotIndex += buffer;
    237             lastVisibleSlotIndex = (lastVisibleSlotIndex / buffer) * buffer;
    238             if (firstVisibleSlotIndex < 0) {
    239                 firstVisibleSlotIndex = 0;
    240             }
    241             if (lastVisibleSlotIndex >= numSlots) {
    242                 lastVisibleSlotIndex = numSlots - 1;
    243             }
    244             synchronized (outBufferedVisibleRange) {
    245                 outBufferedVisibleRange.set(firstVisibleSlotIndex, lastVisibleSlotIndex);
    246             }
    247         } finally {
    248             pool.delete(position);
    249             pool.delete(deltaAnchorPosition);
    250         }
    251     }
    252 
    253     public static final void getSlotPositionForSlotIndex(int slotIndex, GridCamera camera, LayoutInterface layout,
    254             Vector3f deltaAnchorPosition, Vector3f outVal) {
    255         layout.getPositionForSlotIndex(slotIndex, camera.mItemWidth, camera.mItemHeight, outVal);
    256         outVal.subtract(deltaAnchorPosition);
    257     }
    258 
    259     public static final float getFillScreenZoomValue(GridCamera camera, Pool<Vector3f> pool, float currentFocusItemWidth,
    260             float currentFocusItemHeight) {
    261         final Vector3f topLeft = pool.create();
    262         final Vector3f bottomRight = pool.create();
    263         float potentialZoomValue = 1.0f;
    264         try {
    265             camera.convertToCameraSpace(0, 0, 0, topLeft);
    266             camera.convertToCameraSpace(camera.mWidth, camera.mHeight, 0, bottomRight);
    267             float xExtent = Math.abs(topLeft.x - bottomRight.x) / currentFocusItemWidth;
    268             float yExtent = Math.abs(topLeft.y - bottomRight.y) / currentFocusItemHeight;
    269             potentialZoomValue = Math.max(xExtent, yExtent);
    270         } finally {
    271             pool.delete(topLeft);
    272             pool.delete(bottomRight);
    273         }
    274         return potentialZoomValue;
    275     }
    276 }