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 }