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 17a4eae1abb4f2547dfbda84301ee764ce35464881John Reckpackage com.android.gallery3d.glrenderer; 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 29a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.ui.GLRoot; 30a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport com.android.gallery3d.ui.GLRoot.OnGLIdleListener; 31a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 32a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport java.util.ArrayDeque; 33a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Linimport java.util.ArrayList; 34a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 35a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin// This class is similar to BitmapTexture, except the bitmap is 36a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin// split into tiles. By doing so, we may increase the time required to 37a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin// upload the whole bitmap but we reduce the time of uploading each tile 38a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin// so it make the animation more smooth and prevents jank. 39adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Linpublic class TiledTexture implements Texture { 4004d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin private static final int CONTENT_SIZE = 254; 4104d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin private static final int BORDER_SIZE = 1; 42a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static final int TILE_SIZE = CONTENT_SIZE + 2 * BORDER_SIZE; 43a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static final int INIT_CAPACITY = 8; 44a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 45d71a718afe02282153d86b78f6a44c4783203d54Owen Lin // We are targeting at 60fps, so we have 16ms for each frame. 46d71a718afe02282153d86b78f6a44c4783203d54Owen Lin // In this 16ms, we use about 4~8 ms to upload tiles. 47d71a718afe02282153d86b78f6a44c4783203d54Owen Lin private static final long UPLOAD_TILE_LIMIT = 4; // ms 48d71a718afe02282153d86b78f6a44c4783203d54Owen Lin 49a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Tile sFreeTileHead = null; 50a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static final Object sFreeTileLock = new Object(); 51a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 52a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Bitmap sUploadBitmap; 53a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Canvas sCanvas; 5404d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin private static Paint sBitmapPaint; 55a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Paint sPaint; 56a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 57a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private int mUploadIndex = 0; 58a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 5918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong private final Tile[] mTiles; // Can be modified in different threads. 6018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // Should be protected by "synchronized." 61a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final int mWidth; 62a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final int mHeight; 63a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final RectF mSrcRect = new RectF(); 64a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final RectF mDestRect = new RectF(); 65a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 66a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public static class Uploader implements OnGLIdleListener { 67a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final ArrayDeque<TiledTexture> mTextures = 68a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin new ArrayDeque<TiledTexture>(INIT_CAPACITY); 69a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 70a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private final GLRoot mGlRoot; 71a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private boolean mIsQueued = false; 72a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 73a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public Uploader(GLRoot glRoot) { 74a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mGlRoot = glRoot; 75a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 76a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 77a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public synchronized void clear() { 78a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTextures.clear(); 79a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 80a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 81a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public synchronized void addTexture(TiledTexture t) { 82a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (t.isReady()) return; 83a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTextures.addLast(t); 84a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 85a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (mIsQueued) return; 86a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mIsQueued = true; 87a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mGlRoot.addOnGLIdleListener(this); 88a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 89a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 90a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin @Override 91a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) { 92a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin ArrayDeque<TiledTexture> deque = mTextures; 93a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin synchronized (this) { 94d71a718afe02282153d86b78f6a44c4783203d54Owen Lin long now = SystemClock.uptimeMillis(); 95d71a718afe02282153d86b78f6a44c4783203d54Owen Lin long dueTime = now + UPLOAD_TILE_LIMIT; 9618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong while (now < dueTime && !deque.isEmpty()) { 97a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin TiledTexture t = deque.peekFirst(); 98a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (t.uploadNextTile(canvas)) { 99a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin deque.removeFirst(); 100a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mGlRoot.requestRender(); 101a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 102d71a718afe02282153d86b78f6a44c4783203d54Owen Lin now = SystemClock.uptimeMillis(); 103a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 104a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mIsQueued = !mTextures.isEmpty(); 105a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 106a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // return true to keep this listener in the queue 107a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return mIsQueued; 108a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 109a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 110a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 111a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 112a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static class Tile extends UploadedTexture { 113a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public int offsetX; 114a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public int offsetY; 115a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public Bitmap bitmap; 116a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public Tile nextFreeTile; 117a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public int contentWidth; 118a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public int contentHeight; 119a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 120a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin @Override 121a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void setSize(int width, int height) { 122a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin contentWidth = width; 123a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin contentHeight = height; 124a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mWidth = width + 2 * BORDER_SIZE; 125a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mHeight = height + 2 * BORDER_SIZE; 126a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTextureWidth = TILE_SIZE; 127a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTextureHeight = TILE_SIZE; 128a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 129a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 130a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin @Override 131a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin protected Bitmap onGetBitmap() { 132da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware // make a local copy of the reference to the bitmap, 133da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware // since it might be null'd in a different thread. b/8694871 134da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware Bitmap localBitmapRef = bitmap; 135a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin bitmap = null; 136a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 137da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware if (localBitmapRef != null) { 138da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware int x = BORDER_SIZE - offsetX; 139da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware int y = BORDER_SIZE - offsetY; 140da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware int r = localBitmapRef.getWidth() + x; 141da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware int b = localBitmapRef.getHeight() + y; 142da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware sCanvas.drawBitmap(localBitmapRef, x, y, sBitmapPaint); 143da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware localBitmapRef = null; 144da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware 145da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware // draw borders if need 146da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware if (x > 0) sCanvas.drawLine(x - 1, 0, x - 1, TILE_SIZE, sPaint); 147da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware if (y > 0) sCanvas.drawLine(0, y - 1, TILE_SIZE, y - 1, sPaint); 148da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware if (r < CONTENT_SIZE) sCanvas.drawLine(r, 0, r, TILE_SIZE, sPaint); 149da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware if (b < CONTENT_SIZE) sCanvas.drawLine(0, b, TILE_SIZE, b, sPaint); 150da713ad257719520234fc071c3d11deea8125ed6Mangesh Ghiware } 151a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 152a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return sUploadBitmap; 153a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 154a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 155a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin @Override 156a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin protected void onFreeBitmap(Bitmap bitmap) { 157a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // do nothing 158a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 159a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 160a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 161a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static void freeTile(Tile tile) { 162a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.invalidateContent(); 163a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.bitmap = null; 164a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin synchronized (sFreeTileLock) { 165a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.nextFreeTile = sFreeTileHead; 166a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sFreeTileHead = tile; 167a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 168a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 169a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 170a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static Tile obtainTile() { 171a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin synchronized (sFreeTileLock) { 172a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin Tile result = sFreeTileHead; 173a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (result == null) return new Tile(); 174a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sFreeTileHead = result.nextFreeTile; 175a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin result.nextFreeTile = null; 176a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return result; 177a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 178a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 179a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 180a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private boolean uploadNextTile(GLCanvas canvas) { 181a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin if (mUploadIndex == mTiles.length) return true; 182adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 18318b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 18418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong Tile next = mTiles[mUploadIndex++]; 185d54825d1cad2ab586b6d32853acc09dc6df5945fBobby Georgescu 18618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // Make sure tile has not already been recycled by the time 18718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // this is called (race condition in onGLIdle) 18818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong if (next.bitmap != null) { 18918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong boolean hasBeenLoad = next.isLoaded(); 19018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong next.updateContent(canvas); 191d54825d1cad2ab586b6d32853acc09dc6df5945fBobby Georgescu 19218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // It will take some time for a texture to be drawn for the first 19318b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // time. When scrolling, we need to draw several tiles on the screen 19418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // at the same time. It may cause a UI jank even these textures has 19518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // been uploaded. 19618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong if (!hasBeenLoad) next.draw(canvas, 0, 0); 19718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 198d54825d1cad2ab586b6d32853acc09dc6df5945fBobby Georgescu } 199a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return mUploadIndex == mTiles.length; 200a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 201a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 202a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public TiledTexture(Bitmap bitmap) { 203a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mWidth = bitmap.getWidth(); 204a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mHeight = bitmap.getHeight(); 205a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin ArrayList<Tile> list = new ArrayList<Tile>(); 206a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 207a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin for (int x = 0, w = mWidth; x < w; x += CONTENT_SIZE) { 208a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin for (int y = 0, h = mHeight; y < h; y += CONTENT_SIZE) { 209a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin Tile tile = obtainTile(); 210a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.offsetX = x; 211a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.offsetY = y; 212a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.bitmap = bitmap; 213a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin tile.setSize( 214a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin Math.min(CONTENT_SIZE, mWidth - x), 215a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin Math.min(CONTENT_SIZE, mHeight - y)); 216a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin list.add(tile); 217a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 218a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 219a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin mTiles = list.toArray(new Tile[list.size()]); 220a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 221a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 222a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public boolean isReady() { 223a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin return mUploadIndex == mTiles.length; 224a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 225a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 22618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong // Can be called in UI thread. 227a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void recycle() { 22818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 22918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong for (int i = 0, n = mTiles.length; i < n; ++i) { 23018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong freeTile(mTiles[i]); 23118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 232a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 233a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 234a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 235a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public static void freeResources() { 236a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sUploadBitmap = null; 237a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sCanvas = null; 23804d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sBitmapPaint = null; 239a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sPaint = null; 240a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 241a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 242a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public static void prepareResources() { 243a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sUploadBitmap = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE, Config.ARGB_8888); 244a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sCanvas = new Canvas(sUploadBitmap); 24504d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sBitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); 24604d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sBitmapPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); 24704d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sPaint = new Paint(); 24804d324e313b8ee36ce878f5e8c92949b32de33c0Owen Lin sPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); 249a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin sPaint.setColor(Color.TRANSPARENT); 250a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 251a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 252a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // We want to draw the "source" on the "target". 253a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // This method is to find the "output" rectangle which is 254a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // the corresponding area of the "src". 255a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // (x,y) target 256a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // (x0,y0) source +---------------+ 257a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // +----------+ | | 258a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // | src | | output | 259a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // | +--+ | linear map | +----+ | 260a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // | +--+ | ----------> | | | | 261a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // | | by (scaleX, scaleY) | +----+ | 262a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // +----------+ | | 263a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Texture +---------------+ 264a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Canvas 265a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin private static void mapRect(RectF output, 266a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF src, float x0, float y0, float x, float y, float scaleX, 267a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleY) { 268a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin output.set(x + (src.left - x0) * scaleX, 269a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin y + (src.top - y0) * scaleY, 270a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin x + (src.right - x0) * scaleX, 271a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin y + (src.bottom - y0) * scaleY); 272a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 273a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 274a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Draws a mixed color of this texture and a specified color onto the 275a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // a rectangle. The used color is: from * (1 - ratio) + to * ratio. 276a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void drawMixed(GLCanvas canvas, int color, float ratio, 277a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin int x, int y, int width, int height) { 278a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF src = mSrcRect; 279a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF dest = mDestRect; 28018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong float scaleX = (float) width / mWidth; 281a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleY = (float) height / mHeight; 28218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 28318b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong for (int i = 0, n = mTiles.length; i < n; ++i) { 28418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong Tile t = mTiles[i]; 28518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.set(0, 0, t.contentWidth, t.contentHeight); 28618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(t.offsetX, t.offsetY); 28718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong mapRect(dest, src, 0, 0, x, y, scaleX, scaleY); 28818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); 28918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong canvas.drawMixed(t, color, ratio, mSrcRect, mDestRect); 29018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 291a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 292a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 293a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 294a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Draws the texture on to the specified rectangle. 295adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 296a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void draw(GLCanvas canvas, int x, int y, int width, int height) { 297a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF src = mSrcRect; 298a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF dest = mDestRect; 29918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong float scaleX = (float) width / mWidth; 300a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleY = (float) height / mHeight; 30118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 30218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong for (int i = 0, n = mTiles.length; i < n; ++i) { 30318b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong Tile t = mTiles[i]; 30418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.set(0, 0, t.contentWidth, t.contentHeight); 30518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(t.offsetX, t.offsetY); 30618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong mapRect(dest, src, 0, 0, x, y, scaleX, scaleY); 30718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); 30818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong canvas.drawTexture(t, mSrcRect, mDestRect); 30918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 310a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 311a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 312a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 313a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin // Draws a sub region of this texture on to the specified rectangle. 314a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin public void draw(GLCanvas canvas, RectF source, RectF target) { 315a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF src = mSrcRect; 316a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin RectF dest = mDestRect; 317a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float x0 = source.left; 318a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float y0 = source.top; 319a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float x = target.left; 320a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float y = target.top; 321a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleX = target.width() / source.width(); 322a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin float scaleY = target.height() / source.height(); 323a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin 32418b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong synchronized (mTiles) { 32518b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong for (int i = 0, n = mTiles.length; i < n; ++i) { 32618b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong Tile t = mTiles[i]; 32718b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.set(0, 0, t.contentWidth, t.contentHeight); 32818b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(t.offsetX, t.offsetY); 32918b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong if (!src.intersect(source)) continue; 33018b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong mapRect(dest, src, x0, y0, x, y, scaleX, scaleY); 33118b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); 33218b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong canvas.drawTexture(t, src, dest); 33318b388839ed9858a3b35cec9a636e5cde58a528aAngus Kong } 334a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 335a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin } 336adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 337adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 338adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin public int getWidth() { 339adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin return mWidth; 340adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin } 341adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 342adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 343adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin public int getHeight() { 344adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin return mHeight; 345adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin } 346adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 347adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 348adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin public void draw(GLCanvas canvas, int x, int y) { 349adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin draw(canvas, x, y, mWidth, mHeight); 350adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin } 351adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin 352adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin @Override 353adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin public boolean isOpaque() { 354adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin return false; 355adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin } 356a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin} 357