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.Arrays; 20 import java.util.Comparator; 21 import java.util.HashMap; 22 23 import javax.microedition.khronos.opengles.GL10; 24 import javax.microedition.khronos.opengles.GL11; 25 26 import android.content.Context; 27 28 import com.cooliris.app.App; 29 import com.cooliris.app.Res; 30 31 public final class GridDrawManager { 32 public static final int PASS_THUMBNAIL_CONTENT = 0; 33 public static final int PASS_FOCUS_CONTENT = 1; 34 public static final int PASS_FRAME = 2; 35 public static final int PASS_PLACEHOLDER = 3; 36 public static final int PASS_FRAME_PLACEHOLDER = 4; 37 public static final int PASS_TEXT_LABEL = 5; 38 public static final int PASS_SELECTION_LABEL = 6; 39 public static final int PASS_VIDEO_LABEL = 7; 40 public static final int PASS_LOCATION_LABEL = 8; 41 public static final int PASS_MEDIASET_SOURCE_LABEL = 9; 42 43 private static final MediaItemTexture.Config sThumbnailConfig = new MediaItemTexture.Config(); 44 private final DisplayItem[] mDisplayItems; 45 private final DisplaySlot[] mDisplaySlots; 46 private final DisplayList mDisplayList; 47 private final GridCamera mCamera; 48 private final GridDrawables mDrawables; 49 private IndexRange mBufferedVisibleRange; 50 private IndexRange mVisibleRange; 51 private int mSelectedSlot; 52 private int mCurrentFocusSlot; 53 private DisplayItem[] mItemsDrawn; 54 private int mDrawnCounter; 55 private float mTargetFocusMixRatio = 0.0f; 56 private float mFocusMixRatio = 0.0f; 57 private final FloatAnim mSelectedMixRatio = new FloatAnim(0f); 58 private float mCurrentFocusItemWidth; 59 private float mCurrentFocusItemHeight; 60 private boolean mCurrentFocusIsPressed; 61 private final Texture mNoItemsTexture; 62 private int mCurrentScaleSlot; 63 private float mSpreadValue; 64 private ScaleGestureDetector mScaleGestureDetector; 65 private boolean mHoldPosition; 66 67 private static final Comparator<DisplayItem> sDisplayItemComparator = new Comparator<DisplayItem>() { 68 public int compare(DisplayItem a, DisplayItem b) { 69 if (a == null || b == null) { 70 return 0; 71 } 72 float delta = (a.mAnimatedPosition.z - b.mAnimatedPosition.z); 73 if (delta > 0) { 74 return 1; 75 } else if (delta < 0) { 76 return -1; 77 } else { 78 return 0; 79 } 80 } 81 }; 82 83 public GridDrawManager(Context context, GridCamera camera, GridDrawables drawables, DisplayList displayList, 84 DisplayItem[] displayItems, DisplaySlot[] displaySlots) { 85 sThumbnailConfig.thumbnailWidth = 128; 86 sThumbnailConfig.thumbnailHeight = 96; 87 mDisplayItems = displayItems; 88 mDisplaySlots = displaySlots; 89 mDisplayList = displayList; 90 mDrawables = drawables; 91 mCamera = camera; 92 mItemsDrawn = new DisplayItem[GridLayer.MAX_ITEMS_DRAWABLE]; 93 94 StringTexture.Config stc = new StringTexture.Config(); 95 stc.bold = true; 96 stc.fontSize = 16 * App.PIXEL_DENSITY; 97 stc.sizeMode = StringTexture.Config.SIZE_EXACT; 98 stc.overflowMode = StringTexture.Config.OVERFLOW_FADE; 99 mNoItemsTexture = new StringTexture(context.getResources().getString(Res.string.no_items), stc); 100 101 } 102 103 public void prepareDraw(IndexRange bufferedVisibleRange, IndexRange visibleRange, int selectedSlot, int currentFocusSlot, 104 int currentScaleSlot, boolean currentFocusIsPressed, float spreadValue, ScaleGestureDetector scaleGestureDetector, 105 boolean holdPosition) { 106 mBufferedVisibleRange = bufferedVisibleRange; 107 mVisibleRange = visibleRange; 108 mSelectedSlot = selectedSlot; 109 mCurrentFocusSlot = currentFocusSlot; 110 mCurrentFocusIsPressed = currentFocusIsPressed; 111 mCurrentScaleSlot = currentScaleSlot; 112 mScaleGestureDetector = scaleGestureDetector; 113 mSpreadValue = spreadValue; 114 mHoldPosition = holdPosition; 115 } 116 117 public boolean update(float timeElapsed) { 118 mFocusMixRatio = FloatUtils.animate(mFocusMixRatio, mTargetFocusMixRatio, timeElapsed); 119 mTargetFocusMixRatio = 0.0f; 120 if (mFocusMixRatio != mTargetFocusMixRatio || mSelectedMixRatio.isAnimating()) { 121 return true; 122 } 123 return false; 124 } 125 126 public void drawThumbnails(RenderView view, GL11 gl, int state) { 127 final GridDrawables drawables = mDrawables; 128 final DisplayList displayList = mDisplayList; 129 final DisplayItem[] displayItems = mDisplayItems; 130 final int firstBufferedVisibleSlot = mBufferedVisibleRange.begin; 131 final int lastBufferedVisibleSlot = mBufferedVisibleRange.end; 132 final int firstVisibleSlot = mVisibleRange.begin; 133 final int lastVisibleSlot = mVisibleRange.end; 134 final int selectedSlotIndex = mSelectedSlot; 135 final int currentFocusSlot = mCurrentFocusSlot; 136 final int currentScaleSlot = mCurrentScaleSlot; 137 final DisplayItem[] itemsDrawn = mItemsDrawn; 138 itemsDrawn[0] = null; // No items drawn yet. 139 int drawnCounter = 0; 140 final GridQuad grid = GridDrawables.sGrid; 141 grid.bindArrays(gl); 142 int numTexturesQueued = 0; 143 Context context = view.getContext(); 144 for (int itrSlotIndex = firstBufferedVisibleSlot; itrSlotIndex <= lastBufferedVisibleSlot; ++itrSlotIndex) { 145 int index = itrSlotIndex; 146 boolean priority = !(index < firstVisibleSlot || index > lastVisibleSlot); 147 int startSlotIndex = 0; 148 final int maxDisplayedItemsPerSlot = (index == mCurrentScaleSlot) ? GridLayer.MAX_DISPLAYED_ITEMS_PER_FOCUSED_SLOT 149 : GridLayer.MAX_DISPLAYED_ITEMS_PER_SLOT; 150 if (index != mCurrentScaleSlot) { 151 for (int j = maxDisplayedItemsPerSlot - 1; j >= 0; --j) { 152 DisplayItem displayItem = displayItems[(index - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT + j]; 153 if (displayItem == null) { 154 continue; 155 } else { 156 Texture texture = displayItem.getThumbnailImage(context, sThumbnailConfig); 157 if (texture != null && texture.isLoaded() == false) { 158 startSlotIndex = j; 159 break; 160 } 161 } 162 } 163 } 164 // Prime the textures in the reverse order. 165 for (int j = 0; j < maxDisplayedItemsPerSlot; ++j) { 166 int stackIndex = (index == mCurrentScaleSlot) ? maxDisplayedItemsPerSlot - j - 1 : j; 167 DisplayItem displayItem = displayItems[(index - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT 168 + stackIndex]; 169 if (displayItem == null) { 170 continue; 171 } else { 172 displayItem.mCurrentSlotIndex = index; 173 if (selectedSlotIndex != Shared.INVALID && (index <= selectedSlotIndex - 2 || index >= selectedSlotIndex + 2)) { 174 displayItem.clearScreennailImage(); 175 } 176 Texture texture = displayItem.getThumbnailImage(context, sThumbnailConfig); 177 if (index == mCurrentScaleSlot && texture != null && !texture.isLoaded()) { 178 view.prime(texture, true); 179 view.bind(texture); 180 } else if (texture != null && !texture.isLoaded() && numTexturesQueued <= 6) { 181 boolean isCached = texture.isCached(); 182 view.prime(texture, priority); 183 view.bind(texture); 184 if (priority && isCached && texture.mState != Texture.STATE_ERROR) 185 ++numTexturesQueued; 186 } 187 } 188 } 189 if (itrSlotIndex == selectedSlotIndex) { 190 continue; 191 } 192 view.prime(drawables.mTexturePlaceholder, true); 193 Texture placeholder = (state == GridLayer.STATE_GRID_VIEW) ? drawables.mTexturePlaceholder : null; 194 final boolean pushDown = (state == GridLayer.STATE_GRID_VIEW || state == GridLayer.STATE_FULL_SCREEN) ? false : true; 195 for (int j = 0; j < GridLayer.MAX_ITEMS_PER_SLOT; ++j) { 196 DisplayItem displayItem = displayItems[(index - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT + j]; 197 if (displayItem == null) 198 continue; 199 Texture texture = displayItem.getThumbnailImage(context, sThumbnailConfig); 200 if (texture == null || !texture.isLoaded()) { 201 if (currentScaleSlot != index) { 202 if (j == 0) { 203 final MediaSet parentSet = displayItem.mItemRef.mParentMediaSet; 204 if (parentSet != null && parentSet.getNumItems() <= 1) { 205 displayList.setAlive(displayItem, false); 206 } 207 } else { 208 displayList.setAlive(displayItem, false); 209 } 210 } 211 } 212 final float dx1 = mScaleGestureDetector.getTopFingerDeltaX(); 213 final float dy1 = mScaleGestureDetector.getTopFingerDeltaY(); 214 final float dx2 = mScaleGestureDetector.getBottomFingerDeltaX(); 215 final float dy2 = mScaleGestureDetector.getBottomFingerDeltaY(); 216 final float span = mScaleGestureDetector.getCurrentSpan(); 217 if (state == GridLayer.STATE_FULL_SCREEN) { 218 displayList.setOffset(displayItem, false, true, span, dx1, dy1, dx2, dy2); 219 } else { 220 if (!mHoldPosition) { 221 if (state != GridLayer.STATE_GRID_VIEW) { 222 if (currentScaleSlot == index) { 223 displayList.setOffset(displayItem, true, false, span, dx1, dy1, dx2, dy2); 224 } else if (currentScaleSlot != Shared.INVALID) { 225 displayList.setOffset(displayItem, true, true, span, dx1, dy1, dx2, dy2); 226 } else { 227 displayList.setOffset(displayItem, false, false, span, dx1, dy1, dx2, dy2); 228 } 229 } else { 230 float minVal = -1.0f; 231 float maxVal = GridCamera.EYE_Z * 0.5f; 232 float zVal = minVal + mSpreadValue; 233 zVal = FloatUtils.clamp(zVal, minVal, maxVal); 234 if (Float.isInfinite(zVal) || Float.isNaN(zVal)) { 235 mCamera.moveZTo(0); 236 } else { 237 mCamera.moveZTo(-zVal); 238 } 239 } 240 } 241 } 242 } 243 for (int j = startSlotIndex; j < GridLayer.MAX_ITEMS_PER_SLOT; ++j) { 244 DisplayItem displayItem = displayItems[(index - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT + j]; 245 if (displayItem == null) { 246 break; 247 } else { 248 if (currentFocusSlot == index) { 249 displayList.setHasFocus(displayItem, true, pushDown); 250 mTargetFocusMixRatio = 1.0f; 251 } else { 252 displayList.setHasFocus(displayItem, false, pushDown); 253 } 254 if (j >= maxDisplayedItemsPerSlot) 255 continue; 256 Texture texture = displayItem.getThumbnailImage(view.getContext(), sThumbnailConfig); 257 if (texture != null) { 258 if (index == mCurrentScaleSlot) 259 displayItem.mAlive = true; 260 if ((!displayItem.isAnimating() || !texture.isLoaded()) 261 && displayItem.getStackIndex() > GridLayer.MAX_ITEMS_PER_SLOT) { 262 displayList.setAlive(displayItem, true); 263 continue; 264 } 265 if (index < firstVisibleSlot || index > lastVisibleSlot) { 266 if (view.bind(texture)) { 267 displayList.setAlive(displayItem, true); 268 } 269 continue; 270 } 271 drawDisplayItem(view, gl, displayItem, texture, PASS_THUMBNAIL_CONTENT, placeholder, 272 displayItem.mAnimatedPlaceholderFade); 273 } else { 274 // Move on to the next stack. 275 break; 276 } 277 if (drawnCounter >= GridLayer.MAX_ITEMS_DRAWABLE - 1 || drawnCounter < 0) { 278 break; 279 } 280 // Insert in order of z. 281 itemsDrawn[drawnCounter++] = displayItem; 282 itemsDrawn[drawnCounter] = null; 283 } 284 } 285 } 286 mDrawnCounter = drawnCounter; 287 grid.unbindArrays(gl); 288 } 289 290 public float getFocusQuadWidth() { 291 return mCurrentFocusItemWidth; 292 } 293 294 public float getFocusQuadHeight() { 295 return mCurrentFocusItemHeight; 296 } 297 298 public void drawFocusItems(RenderView view, GL11 gl, float zoomValue, boolean slideshowMode, float timeElapsedSinceView) { 299 int selectedSlotIndex = mSelectedSlot; 300 GridDrawables drawables = mDrawables; 301 GridCamera camera = mCamera; 302 DisplayItem[] displayItems = mDisplayItems; 303 int firstBufferedVisibleSlot = mBufferedVisibleRange.begin; 304 int lastBufferedVisibleSlot = mBufferedVisibleRange.end; 305 boolean isCameraZAnimating = mCamera.isZAnimating(); 306 for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { 307 if (selectedSlotIndex != Shared.INVALID && (i >= selectedSlotIndex - 2 && i <= selectedSlotIndex + 2)) { 308 continue; 309 } 310 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 311 if (displayItem != null) { 312 displayItem.clearScreennailImage(); 313 } 314 } 315 if (selectedSlotIndex != Shared.INVALID) { 316 float camX = camera.mLookAtX * camera.mScale; 317 int centerIndexInDrawnArray = (selectedSlotIndex - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT; 318 if (centerIndexInDrawnArray < 0 || centerIndexInDrawnArray >= displayItems.length) { 319 return; 320 } 321 DisplayItem centerDisplayItem = displayItems[centerIndexInDrawnArray]; 322 if (centerDisplayItem == null || centerDisplayItem.mItemRef.mId == Shared.INVALID) { 323 return; 324 } 325 boolean focusItemTextureLoaded = false; 326 Texture centerTexture = centerDisplayItem.getScreennailImage(view.getContext()); 327 if (centerTexture != null && centerTexture.isLoaded()) { 328 focusItemTextureLoaded = true; 329 } 330 float centerTranslateX = centerDisplayItem.mAnimatedPosition.x; 331 final boolean skipPrevious = centerTranslateX < camX; 332 view.setAlpha(1.0f); 333 gl.glEnable(GL11.GL_BLEND); 334 gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); 335 float backupImageTheta = 0.0f; 336 for (int i = -1; i <= 1; ++i) { 337 if (slideshowMode && timeElapsedSinceView > 1.0f && i != 0) 338 continue; 339 float viewAspect = camera.mAspectRatio; 340 int selectedSlotToUse = selectedSlotIndex + i; 341 if (selectedSlotToUse >= 0 && selectedSlotToUse <= lastBufferedVisibleSlot) { 342 int indexInDrawnArray = (selectedSlotToUse - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT; 343 if (indexInDrawnArray < 0 || indexInDrawnArray >= displayItems.length) { 344 return; 345 } 346 DisplayItem displayItem = displayItems[indexInDrawnArray]; 347 MediaItem item = displayItem.mItemRef; 348 final Texture thumbnailTexture = displayItem.getThumbnailImage(view.getContext(), sThumbnailConfig); 349 Texture texture = displayItem.getScreennailImage(view.getContext()); 350 if (isCameraZAnimating && (texture == null || !texture.isLoaded())) { 351 texture = thumbnailTexture; 352 mSelectedMixRatio.setValue(0f); 353 mSelectedMixRatio.animateValue(1f, 0.75f, view.getFrameTime()); 354 } 355 Texture hiRes = (zoomValue != 1.0f && i == 0 && item.getMediaType() != MediaItem.MEDIA_TYPE_VIDEO) ? displayItem 356 .getHiResImage(view.getContext()) 357 : null; 358 if (App.PIXEL_DENSITY > 1.0f) { 359 hiRes = texture; 360 } 361 if (i != 0) { 362 displayItem.clearHiResImage(); 363 } 364 if (hiRes != null) { 365 if (!hiRes.isLoaded()) { 366 view.bind(hiRes); 367 view.prime(hiRes, true); 368 } else { 369 texture = hiRes; 370 } 371 } 372 final Texture fsTexture = texture; 373 if (texture == null || !texture.isLoaded()) { 374 if (Math.abs(centerTranslateX - camX) < 0.1f) { 375 if (focusItemTextureLoaded && i != 0) { 376 view.bind(texture); 377 } 378 if (i == 0) { 379 view.bind(texture); 380 view.prime(texture, true); 381 } 382 } 383 texture = thumbnailTexture; 384 if (i == 0) { 385 mSelectedMixRatio.setValue(0f); 386 mSelectedMixRatio.animateValue(1f, 0.75f, view.getFrameTime()); 387 } 388 } 389 if (mCamera.isAnimating() || slideshowMode) { 390 if (!slideshowMode && skipPrevious && i == -1) { 391 continue; 392 } 393 if (!skipPrevious && i == 1) { 394 continue; 395 } 396 } 397 int theta = (int) displayItem.getImageTheta(); 398 // If it is in slideshow mode, we draw the previous item in 399 // the next item's position. 400 if (slideshowMode && timeElapsedSinceView < 1.0f && timeElapsedSinceView != 0) { 401 if (i == -1) { 402 int nextSlotToUse = selectedSlotToUse + 1; 403 if (nextSlotToUse >= 0 && nextSlotToUse <= lastBufferedVisibleSlot) { 404 int nextIndexInDrawnArray = (nextSlotToUse - firstBufferedVisibleSlot) 405 * GridLayer.MAX_ITEMS_PER_SLOT; 406 if (nextIndexInDrawnArray >= 0 && nextIndexInDrawnArray < displayItems.length) { 407 float currentImageTheta = displayItem.mAnimatedImageTheta; 408 displayItem = displayItems[nextIndexInDrawnArray]; 409 backupImageTheta = displayItem.mAnimatedImageTheta; 410 displayItem.mAnimatedImageTheta = currentImageTheta; 411 view.setAlpha(1.0f - timeElapsedSinceView); 412 } 413 } 414 } else if (i == 0) { 415 displayItem.mAnimatedImageTheta = backupImageTheta; 416 view.setAlpha(timeElapsedSinceView); 417 } 418 } 419 if (texture != null) { 420 int vboIndex = i + 1; 421 float alpha = view.getAlpha(); 422 float selectedMixRatio = mSelectedMixRatio.getValue(view.getFrameTime()); 423 if (selectedMixRatio != 1f) { 424 texture = thumbnailTexture; 425 view.setAlpha(alpha * (1.0f - selectedMixRatio)); 426 } 427 GridQuad quad = GridDrawables.sFullscreenGrid[vboIndex]; 428 float u = texture.getNormalizedWidth(); 429 float v = texture.getNormalizedHeight(); 430 float imageWidth = texture.getWidth(); 431 float imageHeight = texture.getHeight(); 432 boolean portrait = ((theta / 90) % 2 == 1); 433 if (portrait) { 434 viewAspect = 1.0f / viewAspect; 435 } 436 quad.resizeQuad(viewAspect, u, v, imageWidth, imageHeight); 437 quad.bindArrays(gl); 438 drawDisplayItem(view, gl, displayItem, texture, PASS_FOCUS_CONTENT, null, 0.0f); 439 quad.unbindArrays(gl); 440 if (selectedMixRatio != 0.0f && selectedMixRatio != 1.0f) { 441 texture = fsTexture; 442 if (texture != null) { 443 float drawAlpha = selectedMixRatio; 444 view.setAlpha(alpha * drawAlpha); 445 u = texture.getNormalizedWidth(); 446 v = texture.getNormalizedHeight(); 447 imageWidth = texture.getWidth(); 448 imageHeight = texture.getHeight(); 449 quad.resizeQuad(viewAspect, u, v, imageWidth, imageHeight); 450 quad.bindArrays(gl); 451 drawDisplayItem(view, gl, displayItem, fsTexture, PASS_FOCUS_CONTENT, null, 1.0f); 452 quad.unbindArrays(gl); 453 } 454 } 455 if (i == 0 || slideshowMode) { 456 mCurrentFocusItemWidth = quad.getWidth(); 457 mCurrentFocusItemHeight = quad.getHeight(); 458 if (portrait) { 459 // Swap these values. 460 float itemWidth = mCurrentFocusItemWidth; 461 mCurrentFocusItemWidth = mCurrentFocusItemHeight; 462 mCurrentFocusItemHeight = itemWidth; 463 } 464 } 465 view.setAlpha(alpha); 466 if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) { 467 // The play graphic overlay. 468 GridDrawables.sVideoGrid.bindArrays(gl); 469 drawDisplayItem(view, gl, displayItem, drawables.mTextureVideo, PASS_VIDEO_LABEL, null, 0); 470 GridDrawables.sVideoGrid.unbindArrays(gl); 471 } 472 } 473 } 474 } 475 } 476 } 477 478 public void drawBlendedComponents(RenderView view, GL11 gl, float alpha, int state, int hudMode, float stackMixRatio, 479 float gridMixRatio, MediaBucketList selectedBucketList, MediaBucketList markedBucketList, boolean isFeedLoading) { 480 int firstBufferedVisibleSlot = mBufferedVisibleRange.begin; 481 int lastBufferedVisibleSlot = mBufferedVisibleRange.end; 482 int firstVisibleSlot = mVisibleRange.begin; 483 int lastVisibleSlot = mVisibleRange.end; 484 DisplayItem[] displayItems = mDisplayItems; 485 GridDrawables drawables = mDrawables; 486 487 // We draw the frames around the drawn items. 488 boolean currentFocusIsPressed = mCurrentFocusIsPressed; 489 if (state != GridLayer.STATE_FULL_SCREEN) { 490 GridDrawables.sFrame.bindArrays(gl); 491 Texture texturePlaceHolder = (state == GridLayer.STATE_GRID_VIEW) ? drawables.mTextureGridFrame 492 : drawables.mTextureFrame; 493 for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { 494 if (i < firstVisibleSlot || i > lastVisibleSlot) { 495 continue; 496 } 497 boolean slotIsAlive = false; 498 final int maxDisplayedItemsPerSlot = (i == mCurrentScaleSlot) ? GridLayer.MAX_DISPLAYED_ITEMS_PER_FOCUSED_SLOT 499 : GridLayer.MAX_DISPLAYED_ITEMS_PER_SLOT; 500 if (state != GridLayer.STATE_MEDIA_SETS && state != GridLayer.STATE_TIMELINE) { 501 for (int j = 0; j < maxDisplayedItemsPerSlot; ++j) { 502 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT + j]; 503 if (displayItem != null) { 504 slotIsAlive |= displayItem.mAlive; 505 } 506 } 507 if (!slotIsAlive) { 508 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 509 if (displayItem != null) { 510 drawDisplayItem(view, gl, displayItem, texturePlaceHolder, PASS_FRAME_PLACEHOLDER, null, 0); 511 } 512 } 513 } 514 } 515 Texture texturePressed = drawables.mTextureFramePressed; 516 Texture textureFocus = drawables.mTextureFrameFocus; 517 Texture textureGrid = drawables.mTextureGridFrame; 518 Texture texture = drawables.mTextureFrame; 519 520 int drawnCounter = mDrawnCounter; 521 DisplayItem[] itemsDrawn = mItemsDrawn; 522 if (texture != null) { 523 if (drawnCounter > 0) { 524 Arrays.sort(itemsDrawn, 0, drawnCounter, sDisplayItemComparator); 525 float timeElapsedSinceGridView = gridMixRatio; 526 float timeElapsedSinceStackView = stackMixRatio; 527 for (int i = drawnCounter - 1; i >= 0; --i) { 528 DisplayItem itemDrawn = itemsDrawn[i]; 529 if (itemDrawn == null) { 530 continue; 531 } 532 boolean displayItemPresentInSelectedItems = selectedBucketList.find(itemDrawn.mItemRef); 533 boolean displayItemPresentInMarkedItems = markedBucketList.find(itemDrawn.mItemRef); 534 Texture previousTexture = (displayItemPresentInSelectedItems) ? texturePressed : texture; 535 Texture textureToUse = (itemDrawn.getHasFocus()) ? (currentFocusIsPressed ? texturePressed : textureFocus) 536 : ((displayItemPresentInSelectedItems) ? texturePressed 537 : (displayItemPresentInMarkedItems) ? texture : textureGrid); 538 float ratio = timeElapsedSinceGridView; 539 if (itemDrawn.mAlive) { 540 if (state != GridLayer.STATE_GRID_VIEW) { 541 previousTexture = (displayItemPresentInSelectedItems) ? texturePressed : texture; 542 textureToUse = (itemDrawn.getHasFocus()) ? (currentFocusIsPressed ? texturePressed : textureFocus) 543 : previousTexture; 544 if (timeElapsedSinceStackView == 1.0f) { 545 ratio = mFocusMixRatio; 546 } else { 547 ratio = timeElapsedSinceStackView; 548 previousTexture = textureGrid; 549 } 550 } 551 drawDisplayItem(view, gl, itemDrawn, textureToUse, PASS_FRAME, previousTexture, ratio); 552 } 553 } 554 } 555 } 556 GridDrawables.sFrame.unbindArrays(gl); 557 if (mSpreadValue <= 1.0f) 558 gl.glDepthFunc(GL10.GL_ALWAYS); 559 if (state == GridLayer.STATE_MEDIA_SETS || state == GridLayer.STATE_TIMELINE) { 560 DisplaySlot[] displaySlots = mDisplaySlots; 561 GridDrawables.sTextGrid.bindArrays(gl); 562 final float textOffsetY = 0.82f; 563 gl.glTranslatef(0.0f, -textOffsetY, 0.0f); 564 HashMap<String, StringTexture> stringTextureTable = GridDrawables.sStringTextureTable; 565 ReverseGeocoder reverseGeocoder = App.get(view.getContext()).getReverseGeocoder(); 566 567 boolean itemsPresent = false; 568 569 for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { 570 itemsPresent = true; 571 if (mSpreadValue > 1.0f) 572 continue; 573 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 574 if (displayItem != null) { 575 DisplaySlot displaySlot = displaySlots[i - firstBufferedVisibleSlot]; 576 Texture textureString = displaySlot.getTitleImage(stringTextureTable); 577 view.loadTexture(textureString); 578 if (textureString != null) { 579 if (i < firstVisibleSlot || i > lastVisibleSlot) { 580 continue; 581 } 582 drawDisplayItem(view, gl, displayItem, textureString, PASS_TEXT_LABEL, null, 0); 583 } 584 } 585 } 586 587 if (!itemsPresent && !isFeedLoading) { 588 // Draw the no items texture. 589 int wWidth = view.getWidth(); 590 int wHeight = view.getHeight(); 591 592 // Size this to be 40 pxls less than screen width 593 mNoItemsTexture.mWidth = wWidth - 40; 594 595 int x = (int) Math.floor((wWidth / 2) - (mNoItemsTexture.getWidth() / 2)); 596 int y = (int) Math.floor((wHeight / 2) - (mNoItemsTexture.getHeight() / 2)); 597 view.draw2D(mNoItemsTexture, x, y); 598 } 599 600 float yLocOffset = 0.2f; 601 gl.glTranslatef(0.0f, -yLocOffset, 0.0f); 602 for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { 603 if (mSpreadValue > 1.0f) 604 continue; 605 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 606 if (displayItem != null) { 607 DisplaySlot displaySlot = displaySlots[i - firstBufferedVisibleSlot]; 608 StringTexture textureString = displaySlot.getLocationImage(reverseGeocoder, stringTextureTable); 609 if (textureString != null) { 610 view.loadTexture(textureString); 611 drawDisplayItem(view, gl, displayItem, textureString, PASS_TEXT_LABEL, null, 0); 612 } 613 } 614 } 615 if (state == GridLayer.STATE_TIMELINE) { 616 GridDrawables.sLocationGrid.bindArrays(gl); 617 Texture locationTexture = drawables.mTextureLocation; 618 final float yLocationLabelOffset = 0.19f; 619 for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { 620 if (mCurrentScaleSlot != Shared.INVALID) 621 continue; 622 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 623 if (displayItem != null) { 624 if (displayItem.mAlive == true) { 625 DisplaySlot displaySlot = displaySlots[i - firstBufferedVisibleSlot]; 626 if (displaySlot.hasValidLocation()) { 627 StringTexture textureString = displaySlot.getLocationImage(reverseGeocoder, stringTextureTable); 628 float textWidth = (textureString != null) ? textureString.computeTextWidth() : 0; 629 textWidth *= (mCamera.mOneByScale * 0.5f); 630 if (textWidth == 0.0f) { 631 textWidth -= 0.18f; 632 } 633 textWidth += 0.1f; 634 gl.glTranslatef(textWidth, -yLocationLabelOffset, 0.0f); 635 drawDisplayItem(view, gl, displayItem, locationTexture, PASS_LOCATION_LABEL, null, 0); 636 gl.glTranslatef(-textWidth, yLocationLabelOffset, 0.0f); 637 } 638 } 639 } 640 } 641 642 GridDrawables.sLocationGrid.unbindArrays(gl); 643 } else if (state == GridLayer.STATE_MEDIA_SETS && stackMixRatio > 0.0f) { 644 GridDrawables.sSourceIconGrid.bindArrays(gl); 645 Texture transparentTexture = drawables.mTextureTransparent; 646 for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { 647 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 648 if (mCurrentScaleSlot != Shared.INVALID) 649 continue; 650 if (displayItem != null) { 651 if (displayItem.mAlive == true) { 652 DisplaySlot displaySlot = displaySlots[i - firstBufferedVisibleSlot]; 653 Texture locationTexture = view.getResource(drawables 654 .getIconForSet(displaySlot.getMediaSet(), false), false); 655 656 // Draw the icon at 0.85 alpha over the top item 657 // in the stack. 658 gl.glTranslatef(0.24f, 0.5f, 0); 659 drawDisplayItem(view, gl, displayItem, locationTexture, PASS_MEDIASET_SOURCE_LABEL, 660 transparentTexture, 0.85f); 661 gl.glTranslatef(-0.24f, -0.5f, 0); 662 } 663 } 664 } 665 GridDrawables.sSourceIconGrid.unbindArrays(gl); 666 } 667 gl.glTranslatef(0.0f, yLocOffset, 0.0f); 668 gl.glTranslatef(0.0f, textOffsetY, 0.0f); 669 GridDrawables.sTextGrid.unbindArrays(gl); 670 } 671 if (hudMode == HudLayer.MODE_SELECT && state != GridLayer.STATE_FULL_SCREEN) { 672 Texture textureSelectedOn = drawables.mTextureCheckmarkOn; 673 Texture textureSelectedOff = drawables.mTextureCheckmarkOff; 674 view.prime(textureSelectedOn, true); 675 view.prime(textureSelectedOff, true); 676 GridDrawables.sSelectedGrid.bindArrays(gl); 677 for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { 678 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 679 if (displayItem != null) { 680 Texture textureToUse = selectedBucketList.find(displayItem.mItemRef) ? textureSelectedOn 681 : textureSelectedOff; 682 drawDisplayItem(view, gl, displayItem, textureToUse, PASS_SELECTION_LABEL, null, 0); 683 } 684 } 685 GridDrawables.sSelectedGrid.unbindArrays(gl); 686 } 687 GridDrawables.sVideoGrid.bindArrays(gl); 688 Texture videoTexture = drawables.mTextureVideo; 689 for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { 690 DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 691 if (displayItem != null && displayItem.mAlive) { 692 if (displayItem.mItemRef.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) { 693 drawDisplayItem(view, gl, displayItem, videoTexture, PASS_VIDEO_LABEL, null, 0); 694 } 695 } 696 } 697 GridDrawables.sVideoGrid.unbindArrays(gl); 698 gl.glDepthFunc(GL10.GL_LEQUAL); 699 } 700 } 701 702 private void drawDisplayItem(RenderView view, GL11 gl, DisplayItem displayItem, Texture texture, int pass, 703 Texture previousTexture, float mixRatio) { 704 GridCamera camera = mCamera; 705 Vector3f animatedPosition = displayItem.mAnimatedPosition; 706 float translateXf = animatedPosition.x * camera.mOneByScale; 707 float translateYf = animatedPosition.y * camera.mOneByScale; 708 float translateZf = -animatedPosition.z; 709 int stackId = displayItem.getStackIndex(); 710 final int maxDisplayedItemsPerSlot = (displayItem.mCurrentSlotIndex == mCurrentScaleSlot && mCurrentScaleSlot != Shared.INVALID) ? GridLayer.MAX_DISPLAYED_ITEMS_PER_FOCUSED_SLOT 711 : GridLayer.MAX_DISPLAYED_ITEMS_PER_SLOT; 712 if (pass == PASS_PLACEHOLDER || pass == PASS_FRAME_PLACEHOLDER) { 713 translateZf = -0.04f; 714 } else { 715 if (pass == PASS_FRAME) 716 translateZf += 0.02f; 717 if ((pass == PASS_TEXT_LABEL || pass == PASS_LOCATION_LABEL || pass == PASS_SELECTION_LABEL) && !displayItem.isAlive()) { 718 translateZf = 0.0f; 719 } 720 if (pass == PASS_TEXT_LABEL && translateZf > 0) { 721 translateZf = 0.0f; 722 } 723 } 724 boolean usingMixedTextures = false; 725 boolean bind = false; 726 if ((pass != PASS_THUMBNAIL_CONTENT) 727 || (stackId < maxDisplayedItemsPerSlot && texture.isLoaded() && (previousTexture == null || previousTexture 728 .isLoaded()))) { 729 if (mixRatio == 1.0f || previousTexture == null || texture == previousTexture) { 730 bind = view.bind(texture); 731 } else if (mixRatio != 0.0f) { 732 if (!texture.isLoaded() || !previousTexture.isLoaded()) { 733 // Submit the previous texture to the load queue 734 view.bind(previousTexture); 735 bind = view.bind(texture); 736 } else { 737 usingMixedTextures = true; 738 bind = view.bindMixed(previousTexture, texture, mixRatio); 739 } 740 } else { 741 bind = view.bind(previousTexture); 742 } 743 } else if (stackId >= maxDisplayedItemsPerSlot && pass == PASS_THUMBNAIL_CONTENT) { 744 mDisplayList.setAlive(displayItem, true); 745 } 746 if (!texture.isLoaded() || !bind) { 747 if (pass == PASS_THUMBNAIL_CONTENT) { 748 if (previousTexture != null && previousTexture.isLoaded() && translateZf == 0.0f) { 749 translateZf = -0.08f; 750 bind |= view.bind(previousTexture); 751 } 752 if (!bind) { 753 return; 754 } 755 } else { 756 return; 757 } 758 } else { 759 if (pass == PASS_THUMBNAIL_CONTENT || pass == PASS_FOCUS_CONTENT) { 760 if (!displayItem.mAlive) { 761 mDisplayList.setAlive(displayItem, true); 762 } 763 } 764 } 765 gl.glTranslatef(-translateXf, -translateYf, -translateZf); 766 float theta = (pass == PASS_FOCUS_CONTENT) ? displayItem.mAnimatedImageTheta + displayItem.mAnimatedTheta 767 : displayItem.mAnimatedTheta; 768 if (theta != 0.0f) { 769 gl.glRotatef(theta, 0.0f, 0.0f, 1.0f); 770 } 771 float orientation = 0.0f; 772 if (pass == PASS_THUMBNAIL_CONTENT && displayItem.mAnimatedImageTheta != 0.0f) { 773 orientation = displayItem.mAnimatedImageTheta; 774 } 775 if (pass == PASS_FRAME || pass == PASS_FRAME_PLACEHOLDER) { 776 GridQuadFrame.draw(gl); 777 } else { 778 GridQuad.draw(gl, orientation); 779 } 780 if (theta != 0.0f) { 781 gl.glRotatef(-theta, 0.0f, 0.0f, 1.0f); 782 } 783 gl.glTranslatef(translateXf, translateYf, translateZf); 784 if (usingMixedTextures) { 785 view.unbindMixed(); 786 } 787 } 788 } 789