1a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin/* 2a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * Copyright (C) 2012 The Android Open Source Project 3a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * 4a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * you may not use this file except in compliance with the License. 6a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * You may obtain a copy of the License at 7a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * 8a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * 10a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * Unless required by applicable law or agreed to in writing, software 11a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * See the License for the specific language governing permissions and 14a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin * limitations under the License. 15a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin */ 16a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 17a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linpackage com.android.gallery3d.ui; 18a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 19a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport android.graphics.Bitmap; 20a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport android.graphics.Bitmap.Config; 21a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport android.graphics.Canvas; 22a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport android.graphics.Color; 23a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport android.graphics.Paint; 24a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport android.graphics.PorterDuff.Mode; 25a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport android.graphics.PorterDuffXfermode; 26a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport android.graphics.RectF; 27d71a718afe02282153d86b78f6a44c4783203d54Owen Linimport android.os.SystemClock; 28a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 29a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport com.android.gallery3d.ui.GLRoot.OnGLIdleListener; 30a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 31a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport java.util.ArrayDeque; 32a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport java.util.ArrayList; 33a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 34a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin// This class is similar to BitmapTexture, except the bitmap is 35a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin// split into tiles. By doing so, we may increase the time required to 36a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin// upload the whole bitmap but we reduce the time of uploading each tile 37a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin// so it make the animation more smooth and prevents jank. 38adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Linpublic class TiledTexture implements Texture { 3904d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin private static final int CONTENT_SIZE = 254; 4004d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin private static final int BORDER_SIZE = 1; 41a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static final int TILE_SIZE = CONTENT_SIZE + 2 * BORDER_SIZE; 42a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static final int INIT_CAPACITY = 8; 43a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 44d71a718afe02282153d86b78f6a44c4783203d54Owen Lin // We are targeting at 60fps, so we have 16ms for each frame. 45d71a718afe02282153d86b78f6a44c4783203d54Owen Lin // In this 16ms, we use about 4~8 ms to upload tiles. 46d71a718afe02282153d86b78f6a44c4783203d54Owen Lin private static final long UPLOAD_TILE_LIMIT = 4; // ms 47d71a718afe02282153d86b78f6a44c4783203d54Owen Lin 48a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Tile sFreeTileHead = null; 49a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static final Object sFreeTileLock = new Object(); 50a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 51a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Bitmap sUploadBitmap; 52a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Canvas sCanvas; 5304d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin private static Paint sBitmapPaint; 54a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Paint sPaint; 55a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 56a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private int mUploadIndex = 0; 57a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 5818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong private final Tile[] mTiles; // Can be modified in different threads. 5918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // Should be protected by "synchronized." 60a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final int mWidth; 61a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final int mHeight; 62a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final RectF mSrcRect = new RectF(); 63a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final RectF mDestRect = new RectF(); 64a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 65a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public static class Uploader implements OnGLIdleListener { 66a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final ArrayDeque<TiledTexture> mTextures = 67a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin new ArrayDeque<TiledTexture>(INIT_CAPACITY); 68a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 69a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final GLRoot mGlRoot; 70a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private boolean mIsQueued = false; 71a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 72a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public Uploader(GLRoot glRoot) { 73a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mGlRoot = glRoot; 74a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 75a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 76a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public synchronized void clear() { 77a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTextures.clear(); 78a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 79a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 80a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public synchronized void addTexture(TiledTexture t) { 81a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (t.isReady()) return; 82a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTextures.addLast(t); 83a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 84a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (mIsQueued) return; 85a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mIsQueued = true; 86a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mGlRoot.addOnGLIdleListener(this); 87a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 88a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 89a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin @Override 90a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) { 91a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin ArrayDeque<TiledTexture> deque = mTextures; 92a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin synchronized (this) { 93d71a718afe02282153d86b78f6a44c4783203d54Owen Lin long now = SystemClock.uptimeMillis(); 94d71a718afe02282153d86b78f6a44c4783203d54Owen Lin long dueTime = now + UPLOAD_TILE_LIMIT; 9518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong while (now < dueTime && !deque.isEmpty()) { 96a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin TiledTexture t = deque.peekFirst(); 97a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (t.uploadNextTile(canvas)) { 98a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin deque.removeFirst(); 99a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mGlRoot.requestRender(); 100a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 101d71a718afe02282153d86b78f6a44c4783203d54Owen Lin now = SystemClock.uptimeMillis(); 102a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 103a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mIsQueued = !mTextures.isEmpty(); 104a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 105a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // return true to keep this listener in the queue 106a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return mIsQueued; 107a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 108a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 109a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 110a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 111a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static class Tile extends UploadedTexture { 112a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public int offsetX; 113a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public int offsetY; 114a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public Bitmap bitmap; 115a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public Tile nextFreeTile; 116a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public int contentWidth; 117a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public int contentHeight; 118a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 119a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin @Override 120a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void setSize(int width, int height) { 121a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin contentWidth = width; 122a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin contentHeight = height; 123a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mWidth = width + 2 * BORDER_SIZE; 124a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mHeight = height + 2 * BORDER_SIZE; 125a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTextureWidth = TILE_SIZE; 126a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTextureHeight = TILE_SIZE; 127a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 128a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 129a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin @Override 130a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin protected Bitmap onGetBitmap() { 131a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin int x = BORDER_SIZE - offsetX; 132a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin int y = BORDER_SIZE - offsetY; 13304d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin int r = bitmap.getWidth() + x; 13418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong int b = bitmap.getHeight() + y; 13504d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sCanvas.drawBitmap(bitmap, x, y, sBitmapPaint); 136a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin bitmap = null; 137a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 138a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // draw borders if need 139a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (x > 0) sCanvas.drawLine(x - 1, 0, x - 1, TILE_SIZE, sPaint); 140a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (y > 0) sCanvas.drawLine(0, y - 1, TILE_SIZE, y - 1, sPaint); 141a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (r < CONTENT_SIZE) sCanvas.drawLine(r, 0, r, TILE_SIZE, sPaint); 142a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (b < CONTENT_SIZE) sCanvas.drawLine(0, b, TILE_SIZE, b, sPaint); 143a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 144a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return sUploadBitmap; 145a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 146a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 147a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin @Override 148a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin protected void onFreeBitmap(Bitmap bitmap) { 149a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // do nothing 150a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 151a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 152a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 153a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static void freeTile(Tile tile) { 154a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.invalidateContent(); 155a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.bitmap = null; 156a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin synchronized (sFreeTileLock) { 157a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.nextFreeTile = sFreeTileHead; 158a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sFreeTileHead = tile; 159a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 160a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 161a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 162a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Tile obtainTile() { 163a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin synchronized (sFreeTileLock) { 164a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin Tile result = sFreeTileHead; 165a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (result == null) return new Tile(); 166a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sFreeTileHead = result.nextFreeTile; 167a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin result.nextFreeTile = null; 168a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return result; 169a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 170a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 171a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 172a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private boolean uploadNextTile(GLCanvas canvas) { 173a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (mUploadIndex == mTiles.length) return true; 174adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 17518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 17618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong Tile next = mTiles[mUploadIndex++]; 177d54825d1cad2ab586b6d32853acc09dc6df5945fBobby Georgescu 17818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // Make sure tile has not already been recycled by the time 17918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // this is called (race condition in onGLIdle) 18018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong if (next.bitmap != null) { 18118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong boolean hasBeenLoad = next.isLoaded(); 18218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong next.updateContent(canvas); 183d54825d1cad2ab586b6d32853acc09dc6df5945fBobby Georgescu 18418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // It will take some time for a texture to be drawn for the first 18518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // time. When scrolling, we need to draw several tiles on the screen 18618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // at the same time. It may cause a UI jank even these textures has 18718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // been uploaded. 18818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong if (!hasBeenLoad) next.draw(canvas, 0, 0); 18918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 190d54825d1cad2ab586b6d32853acc09dc6df5945fBobby Georgescu } 191a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return mUploadIndex == mTiles.length; 192a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 193a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 194a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public TiledTexture(Bitmap bitmap) { 195a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mWidth = bitmap.getWidth(); 196a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mHeight = bitmap.getHeight(); 197a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin ArrayList<Tile> list = new ArrayList<Tile>(); 198a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 199a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin for (int x = 0, w = mWidth; x < w; x += CONTENT_SIZE) { 200a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin for (int y = 0, h = mHeight; y < h; y += CONTENT_SIZE) { 201a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin Tile tile = obtainTile(); 202a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.offsetX = x; 203a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.offsetY = y; 204a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.bitmap = bitmap; 205a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.setSize( 206a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin Math.min(CONTENT_SIZE, mWidth - x), 207a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin Math.min(CONTENT_SIZE, mHeight - y)); 208a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin list.add(tile); 209a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 210a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 211a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTiles = list.toArray(new Tile[list.size()]); 212a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 213a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 214a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public boolean isReady() { 215a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return mUploadIndex == mTiles.length; 216a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 217a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 21818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // Can be called in UI thread. 219a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void recycle() { 22018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 22118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong for (int i = 0, n = mTiles.length; i < n; ++i) { 22218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong freeTile(mTiles[i]); 22318b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 224a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 225a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 226a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 227a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public static void freeResources() { 228a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sUploadBitmap = null; 229a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sCanvas = null; 23004d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sBitmapPaint = null; 231a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sPaint = null; 232a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 233a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 234a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public static void prepareResources() { 235a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sUploadBitmap = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE, Config.ARGB_8888); 236a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sCanvas = new Canvas(sUploadBitmap); 23704d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sBitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); 23804d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sBitmapPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); 23904d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sPaint = new Paint(); 24004d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); 241a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sPaint.setColor(Color.TRANSPARENT); 242a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 243a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 244a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // We want to draw the "source" on the "target". 245a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // This method is to find the "output" rectangle which is 246a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // the corresponding area of the "src". 247a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // (x,y) target 248a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // (x0,y0) source +---------------+ 249a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // +----------+ | | 250a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // | src | | output | 251a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // | +--+ | linear map | +----+ | 252a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // | +--+ | ----------> | | | | 253a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // | | by (scaleX, scaleY) | +----+ | 254a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // +----------+ | | 255a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Texture +---------------+ 256a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Canvas 257a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static void mapRect(RectF output, 258a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF src, float x0, float y0, float x, float y, float scaleX, 259a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleY) { 260a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin output.set(x + (src.left - x0) * scaleX, 261a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin y + (src.top - y0) * scaleY, 262a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin x + (src.right - x0) * scaleX, 263a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin y + (src.bottom - y0) * scaleY); 264a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 265a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 266a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Draws a mixed color of this texture and a specified color onto the 267a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // a rectangle. The used color is: from * (1 - ratio) + to * ratio. 268a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void drawMixed(GLCanvas canvas, int color, float ratio, 269a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin int x, int y, int width, int height) { 270a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF src = mSrcRect; 271a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF dest = mDestRect; 27218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong float scaleX = (float) width / mWidth; 273a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleY = (float) height / mHeight; 27418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 27518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong for (int i = 0, n = mTiles.length; i < n; ++i) { 27618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong Tile t = mTiles[i]; 27718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.set(0, 0, t.contentWidth, t.contentHeight); 27818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(t.offsetX, t.offsetY); 27918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong mapRect(dest, src, 0, 0, x, y, scaleX, scaleY); 28018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); 28118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong canvas.drawMixed(t, color, ratio, mSrcRect, mDestRect); 28218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 283a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 284a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 285a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 286a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Draws the texture on to the specified rectangle. 287adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 288a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void draw(GLCanvas canvas, int x, int y, int width, int height) { 289a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF src = mSrcRect; 290a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF dest = mDestRect; 29118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong float scaleX = (float) width / mWidth; 292a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleY = (float) height / mHeight; 29318b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 29418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong for (int i = 0, n = mTiles.length; i < n; ++i) { 29518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong Tile t = mTiles[i]; 29618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.set(0, 0, t.contentWidth, t.contentHeight); 29718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(t.offsetX, t.offsetY); 29818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong mapRect(dest, src, 0, 0, x, y, scaleX, scaleY); 29918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); 30018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong canvas.drawTexture(t, mSrcRect, mDestRect); 30118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 302a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 303a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 304a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 305a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Draws a sub region of this texture on to the specified rectangle. 306a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void draw(GLCanvas canvas, RectF source, RectF target) { 307a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF src = mSrcRect; 308a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF dest = mDestRect; 309a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float x0 = source.left; 310a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float y0 = source.top; 311a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float x = target.left; 312a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float y = target.top; 313a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleX = target.width() / source.width(); 314a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleY = target.height() / source.height(); 315a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 31618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 31718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong for (int i = 0, n = mTiles.length; i < n; ++i) { 31818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong Tile t = mTiles[i]; 31918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.set(0, 0, t.contentWidth, t.contentHeight); 32018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(t.offsetX, t.offsetY); 32118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong if (!src.intersect(source)) continue; 32218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong mapRect(dest, src, x0, y0, x, y, scaleX, scaleY); 32318b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); 32418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong canvas.drawTexture(t, src, dest); 32518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 326a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 327a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 328adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 329adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 330adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin public int getWidth() { 331adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin return mWidth; 332adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin } 333adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 334adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 335adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin public int getHeight() { 336adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin return mHeight; 337adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin } 338adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 339adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 340adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin public void draw(GLCanvas canvas, int x, int y) { 341adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin draw(canvas, x, y, mWidth, mHeight); 342adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin } 343adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 344adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 345adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin public boolean isOpaque() { 346adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin return false; 347adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin } 348a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin} 349