1e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/* 2e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Copyright (C) 2013 The Android Open Source Project 3e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * 4e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * you may not use this file except in compliance with the License. 6e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * You may obtain a copy of the License at 7e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * 8e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * 10e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Unless required by applicable law or agreed to in writing, software 11e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * See the License for the specific language governing permissions and 14e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * limitations under the License. 15e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */ 16e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 17e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapackage com.android.photos.views; 18e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 19e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.annotation.SuppressLint; 20e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.annotation.TargetApi; 21e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.Context; 22e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap; 23e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Canvas; 24e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Color; 25e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Matrix; 26e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Paint; 27e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Paint.Align; 28e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.RectF; 29e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.opengl.GLSurfaceView; 30e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.opengl.GLSurfaceView.Renderer; 31e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.os.Build; 32e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.AttributeSet; 33e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.Choreographer; 34e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.Choreographer.FrameCallback; 35e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.View; 36e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.widget.FrameLayout; 37e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 38e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.glrenderer.BasicTexture; 39e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.glrenderer.GLES20Canvas; 40e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.photos.views.TiledImageRenderer.TileSource; 41e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 42e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport javax.microedition.khronos.egl.EGLConfig; 43e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport javax.microedition.khronos.opengles.GL10; 44e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 45e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/** 46e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView} 47e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * or {@link BlockingGLTextureView}. 48e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */ 49e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapublic class TiledImageView extends FrameLayout { 50e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 51e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static final boolean USE_TEXTURE_VIEW = false; 52e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static final boolean IS_SUPPORTED = 53e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 54e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static final boolean USE_CHOREOGRAPHER = 55e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 56e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 57e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private BlockingGLTextureView mTextureView; 58e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private GLSurfaceView mGLSurfaceView; 59e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private boolean mInvalPending = false; 60e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private FrameCallback mFrameCallback; 61e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 62e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka protected static class ImageRendererWrapper { 63e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // Guarded by locks 64e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public float scale; 65e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int centerX, centerY; 6669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka public int rotation; 67e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public TileSource source; 68e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Runnable isReadyCallback; 69e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 70e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // GL thread only 71e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka TiledImageRenderer image; 72e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 73e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 74e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private float[] mValues = new float[9]; 75e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 76e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // ------------------------- 77e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // Guarded by mLock 78e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // ------------------------- 79e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka protected Object mLock = new Object(); 80e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka protected ImageRendererWrapper mRenderer; 81e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 82e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public static boolean isTilingSupported() { 83e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return IS_SUPPORTED; 84e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 85e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 86e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public TiledImageView(Context context) { 87e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka this(context, null); 88e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 89e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 90e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public TiledImageView(Context context, AttributeSet attrs) { 91e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka super(context, attrs); 92e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 93e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 94e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 95e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 96e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer = new ImageRendererWrapper(); 97e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.image = new TiledImageRenderer(this); 98e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka View view; 99e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (USE_TEXTURE_VIEW) { 100e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mTextureView = new BlockingGLTextureView(context); 101e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mTextureView.setRenderer(new TileRenderer()); 102e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka view = mTextureView; 103e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } else { 104e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView = new GLSurfaceView(context); 105e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView.setEGLContextClientVersion(2); 106e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView.setRenderer(new TileRenderer()); 107e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 108e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka view = mGLSurfaceView; 109e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 110e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka addView(view, new LayoutParams( 111e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 112e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka //setTileSource(new ColoredTiles()); 113e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 114e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 115e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void destroy() { 116e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 117e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 118e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 119e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (USE_TEXTURE_VIEW) { 120e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mTextureView.destroy(); 121e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } else { 122e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView.queueEvent(mFreeTextures); 123e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 124e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 125e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 126e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private Runnable mFreeTextures = new Runnable() { 127e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 128e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 129e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void run() { 130e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.image.freeTextures(); 131e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 132e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka }; 133e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 134e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void onPause() { 135e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 136e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 137e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 138e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!USE_TEXTURE_VIEW) { 139e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView.onPause(); 140e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 141e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 142e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 143e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void onResume() { 144e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 145e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 146e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 147e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!USE_TEXTURE_VIEW) { 148e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView.onResume(); 149e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 150e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 151e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 152e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void setTileSource(TileSource source, Runnable isReadyCallback) { 153e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 154e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 155e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 156e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka synchronized (mLock) { 157e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.source = source; 158e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.isReadyCallback = isReadyCallback; 159e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.centerX = source != null ? source.getImageWidth() / 2 : 0; 160e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.centerY = source != null ? source.getImageHeight() / 2 : 0; 161e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.rotation = source != null ? source.getRotation() : 0; 162e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.scale = 0; 163e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka updateScaleIfNecessaryLocked(mRenderer); 164e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 165e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka invalidate(); 166e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 167e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 168e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 169e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka protected void onLayout(boolean changed, int left, int top, int right, 170e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int bottom) { 171e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka super.onLayout(changed, left, top, right, bottom); 172e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 173e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 174e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 175e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka synchronized (mLock) { 176e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka updateScaleIfNecessaryLocked(mRenderer); 177e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 178e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 179e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 180e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private void updateScaleIfNecessaryLocked(ImageRendererWrapper renderer) { 181e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (renderer == null || renderer.source == null 182e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka || renderer.scale > 0 || getWidth() == 0) { 183e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 184e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 185e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka renderer.scale = Math.min( 186e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka (float) getWidth() / (float) renderer.source.getImageWidth(), 187e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka (float) getHeight() / (float) renderer.source.getImageHeight()); 188e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 189e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 190e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 191e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka protected void dispatchDraw(Canvas canvas) { 192e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 193e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 194e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 195e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (USE_TEXTURE_VIEW) { 196e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mTextureView.render(); 197e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 198e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka super.dispatchDraw(canvas); 199e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 200e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 201e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @SuppressLint("NewApi") 202e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 203e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void setTranslationX(float translationX) { 204e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 205e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 206e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 207e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka super.setTranslationX(translationX); 208e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 209e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 210e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 211e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void invalidate() { 212e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 213e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 214e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 215e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (USE_TEXTURE_VIEW) { 216e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka super.invalidate(); 217e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mTextureView.invalidate(); 218e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } else { 219e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (USE_CHOREOGRAPHER) { 220e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka invalOnVsync(); 221e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } else { 222e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView.requestRender(); 223e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 224e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 225e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 226e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 227e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 228e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private void invalOnVsync() { 229e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!mInvalPending) { 230e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mInvalPending = true; 231e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (mFrameCallback == null) { 232e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mFrameCallback = new FrameCallback() { 233e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 234e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void doFrame(long frameTimeNanos) { 235e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mInvalPending = false; 236e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mGLSurfaceView.requestRender(); 237e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 238e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka }; 239e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 240e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Choreographer.getInstance().postFrameCallback(mFrameCallback); 241e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 242e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 243e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 244e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private RectF mTempRectF = new RectF(); 245e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void positionFromMatrix(Matrix matrix) { 246e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (!IS_SUPPORTED) { 247e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return; 248e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 249e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (mRenderer.source != null) { 250e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka final int rotation = mRenderer.source.getRotation(); 251e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka final boolean swap = !(rotation % 180 == 0); 252e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka final int width = swap ? mRenderer.source.getImageHeight() 253e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka : mRenderer.source.getImageWidth(); 254e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka final int height = swap ? mRenderer.source.getImageWidth() 255e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka : mRenderer.source.getImageHeight(); 256e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mTempRectF.set(0, 0, width, height); 257e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka matrix.mapRect(mTempRectF); 258e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka matrix.getValues(mValues); 259e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int cx = width / 2; 260e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int cy = height / 2; 261e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka float scale = mValues[Matrix.MSCALE_X]; 262e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int xoffset = Math.round((getWidth() - mTempRectF.width()) / 2 / scale); 263e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int yoffset = Math.round((getHeight() - mTempRectF.height()) / 2 / scale); 264e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (rotation == 90 || rotation == 180) { 265e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka cx += (mTempRectF.left / scale) - xoffset; 266e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } else { 267e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka cx -= (mTempRectF.left / scale) - xoffset; 268e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 269e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (rotation == 180 || rotation == 270) { 270e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka cy += (mTempRectF.top / scale) - yoffset; 271e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } else { 272e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka cy -= (mTempRectF.top / scale) - yoffset; 273e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 274e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.scale = scale; 275e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.centerX = swap ? cy : cx; 276e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.centerY = swap ? cx : cy; 277e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka invalidate(); 278e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 279e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 280e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 281e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private class TileRenderer implements Renderer { 282e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 283e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private GLES20Canvas mCanvas; 284e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 285e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 286e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void onSurfaceCreated(GL10 gl, EGLConfig config) { 287e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas = new GLES20Canvas(); 288e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka BasicTexture.invalidateAllTextures(); 289e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.image.setModel(mRenderer.source, mRenderer.rotation); 290e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 291e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 292e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 293e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void onSurfaceChanged(GL10 gl, int width, int height) { 294e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.setSize(width, height); 295e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.image.setViewSize(width, height); 296e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 297e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 298e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 299e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public void onDrawFrame(GL10 gl) { 300e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.clearBuffer(); 301e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Runnable readyCallback; 302e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka synchronized (mLock) { 303e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka readyCallback = mRenderer.isReadyCallback; 304e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.image.setModel(mRenderer.source, mRenderer.rotation); 305e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.image.setPosition(mRenderer.centerX, mRenderer.centerY, 306e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.scale); 307e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 308e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka boolean complete = mRenderer.image.draw(mCanvas); 309e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (complete && readyCallback != null) { 310e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka synchronized (mLock) { 311e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // Make sure we don't trample on a newly set callback/source 312e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka // if it changed while we were rendering 313e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (mRenderer.isReadyCallback == readyCallback) { 314e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mRenderer.isReadyCallback = null; 315e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 316e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 317e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (readyCallback != null) { 318e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka post(readyCallback); 319e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 320e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 321e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 322e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 323e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 324e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 325e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @SuppressWarnings("unused") 326e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static class ColoredTiles implements TileSource { 327e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private static final int[] COLORS = new int[] { 328e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Color.RED, 329e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Color.BLUE, 330e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Color.YELLOW, 331e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Color.GREEN, 332e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Color.CYAN, 333e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Color.MAGENTA, 334e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Color.WHITE, 335e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka }; 336e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 337e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private Paint mPaint = new Paint(); 338e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka private Canvas mCanvas = new Canvas(); 339e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 340e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 341e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int getTileSize() { 342e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return 256; 343e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 344e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 345e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 346e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int getImageWidth() { 347e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return 16384; 348e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 349e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 350e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 351e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int getImageHeight() { 352e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return 8192; 353e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 354e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 355e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 356e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public int getRotation() { 357e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return 0; 358e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 359e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 360e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 361e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public Bitmap getTile(int level, int x, int y, Bitmap bitmap) { 362e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka int tileSize = getTileSize(); 363e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka if (bitmap == null) { 364e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka bitmap = Bitmap.createBitmap(tileSize, tileSize, 365e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka Bitmap.Config.ARGB_8888); 366e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 367e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.setBitmap(bitmap); 368e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.drawColor(COLORS[level]); 369e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mPaint.setColor(Color.BLACK); 370e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mPaint.setTextSize(20); 371e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mPaint.setTextAlign(Align.CENTER); 372e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.drawText(x + "x" + y, 128, 128, mPaint); 373e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka tileSize <<= level; 374e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka x /= tileSize; 375e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka y /= tileSize; 376e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.drawText(x + "x" + y + " @ " + level, 128, 30, mPaint); 377e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka mCanvas.setBitmap(null); 378e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return bitmap; 379e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 380e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka 381e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka @Override 382e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka public BasicTexture getPreview() { 383e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka return null; 384e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 385e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka } 386e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka} 387