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