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.ArrayList; 20 21public 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}