diff options
Diffstat (limited to 'src/com/android/gallery3d/ui')
56 files changed, 261 insertions, 4284 deletions
diff --git a/src/com/android/gallery3d/ui/AbstractSlotRenderer.java b/src/com/android/gallery3d/ui/AbstractSlotRenderer.java index 10b710d2d..729439dc3 100644 --- a/src/com/android/gallery3d/ui/AbstractSlotRenderer.java +++ b/src/com/android/gallery3d/ui/AbstractSlotRenderer.java @@ -20,6 +20,11 @@ import android.content.Context; import android.graphics.Rect; import com.android.gallery3d.R; +import com.android.gallery3d.glrenderer.FadeOutTexture; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.NinePatchTexture; +import com.android.gallery3d.glrenderer.ResourceTexture; +import com.android.gallery3d.glrenderer.Texture; public abstract class AbstractSlotRenderer implements SlotView.SlotRenderer { diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java index 7191599ad..9b84bf75c 100644 --- a/src/com/android/gallery3d/ui/ActionModeHandler.java +++ b/src/com/android/gallery3d/ui/ActionModeHandler.java @@ -408,6 +408,15 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi // Pass1: Deal with unexpanded media object list for menu operation. ArrayList<MediaObject> selected = getSelectedMediaObjects(jc); if (selected == null) { + mMainHandler.post(new Runnable() { + @Override + public void run() { + mMenuTask = null; + if (jc.isCancelled()) return; + // Disable all the operations when no item is selected + MenuExecutor.updateMenuOperation(mMenu, 0); + } + }); return null; } final int operation = computeMenuOptions(selected); @@ -466,7 +475,12 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi mMenuExecutor.pause(); } + public void destroy() { + mMenuExecutor.destroy(); + } + public void resume() { if (mSelectionManager.inSelectionMode()) updateSupportedOperation(); + mMenuExecutor.resume(); } } diff --git a/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java b/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java index 80dfc919f..d5a15b4ac 100644 --- a/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java +++ b/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java @@ -29,6 +29,10 @@ import com.android.gallery3d.data.MediaItem; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.MediaSet; import com.android.gallery3d.data.Path; +import com.android.gallery3d.glrenderer.BitmapTexture; +import com.android.gallery3d.glrenderer.Texture; +import com.android.gallery3d.glrenderer.TextureUploader; +import com.android.gallery3d.glrenderer.TiledTexture; import com.android.gallery3d.util.Future; import com.android.gallery3d.util.FutureListener; import com.android.gallery3d.util.ThreadPool; diff --git a/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java b/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java index 70d7c273a..5332ef89a 100644 --- a/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java +++ b/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java @@ -21,6 +21,13 @@ import com.android.gallery3d.app.AbstractGalleryActivity; import com.android.gallery3d.app.AlbumSetDataLoader; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.Path; +import com.android.gallery3d.glrenderer.ColorTexture; +import com.android.gallery3d.glrenderer.FadeInTexture; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.ResourceTexture; +import com.android.gallery3d.glrenderer.Texture; +import com.android.gallery3d.glrenderer.TiledTexture; +import com.android.gallery3d.glrenderer.UploadedTexture; import com.android.gallery3d.ui.AlbumSetSlidingWindow.AlbumSetEntry; public class AlbumSetSlotRenderer extends AbstractSlotRenderer { diff --git a/src/com/android/gallery3d/ui/AlbumSlidingWindow.java b/src/com/android/gallery3d/ui/AlbumSlidingWindow.java index 678c43251..8cd2cf500 100644 --- a/src/com/android/gallery3d/ui/AlbumSlidingWindow.java +++ b/src/com/android/gallery3d/ui/AlbumSlidingWindow.java @@ -27,6 +27,8 @@ import com.android.gallery3d.data.MediaItem; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.Path; import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; +import com.android.gallery3d.glrenderer.Texture; +import com.android.gallery3d.glrenderer.TiledTexture; import com.android.gallery3d.util.Future; import com.android.gallery3d.util.FutureListener; import com.android.gallery3d.util.JobLimiter; diff --git a/src/com/android/gallery3d/ui/AlbumSlotRenderer.java b/src/com/android/gallery3d/ui/AlbumSlotRenderer.java index ce5b7ac24..dc6c89b0e 100644 --- a/src/com/android/gallery3d/ui/AlbumSlotRenderer.java +++ b/src/com/android/gallery3d/ui/AlbumSlotRenderer.java @@ -20,6 +20,11 @@ import com.android.gallery3d.app.AbstractGalleryActivity; import com.android.gallery3d.app.AlbumDataLoader; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.Path; +import com.android.gallery3d.glrenderer.ColorTexture; +import com.android.gallery3d.glrenderer.FadeInTexture; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.Texture; +import com.android.gallery3d.glrenderer.TiledTexture; public class AlbumSlotRenderer extends AbstractSlotRenderer { @SuppressWarnings("unused") diff --git a/src/com/android/gallery3d/ui/BasicTexture.java b/src/com/android/gallery3d/ui/BasicTexture.java deleted file mode 100644 index 99cf0571c..000000000 --- a/src/com/android/gallery3d/ui/BasicTexture.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import com.android.gallery3d.common.Utils; - -import java.util.WeakHashMap; - -// BasicTexture is a Texture corresponds to a real GL texture. -// The state of a BasicTexture indicates whether its data is loaded to GL memory. -// If a BasicTexture is loaded into GL memory, it has a GL texture id. -abstract class BasicTexture implements Texture { - - @SuppressWarnings("unused") - private static final String TAG = "BasicTexture"; - protected static final int UNSPECIFIED = -1; - - protected static final int STATE_UNLOADED = 0; - protected static final int STATE_LOADED = 1; - protected static final int STATE_ERROR = -1; - - // Log a warning if a texture is larger along a dimension - private static final int MAX_TEXTURE_SIZE = 4096; - - protected int mId; - protected int mState; - - protected int mWidth = UNSPECIFIED; - protected int mHeight = UNSPECIFIED; - - protected int mTextureWidth; - protected int mTextureHeight; - - private boolean mHasBorder; - - protected GLCanvas mCanvasRef = null; - private static WeakHashMap<BasicTexture, Object> sAllTextures - = new WeakHashMap<BasicTexture, Object>(); - private static ThreadLocal sInFinalizer = new ThreadLocal(); - - protected BasicTexture(GLCanvas canvas, int id, int state) { - setAssociatedCanvas(canvas); - mId = id; - mState = state; - synchronized (sAllTextures) { - sAllTextures.put(this, null); - } - } - - protected BasicTexture() { - this(null, 0, STATE_UNLOADED); - } - - protected void setAssociatedCanvas(GLCanvas canvas) { - mCanvasRef = canvas; - } - - /** - * Sets the content size of this texture. In OpenGL, the actual texture - * size must be of power of 2, the size of the content may be smaller. - */ - protected void setSize(int width, int height) { - mWidth = width; - mHeight = height; - mTextureWidth = Utils.nextPowerOf2(width); - mTextureHeight = Utils.nextPowerOf2(height); - if (mTextureWidth > MAX_TEXTURE_SIZE || mTextureHeight > MAX_TEXTURE_SIZE) { - Log.w(TAG, String.format("texture is too large: %d x %d", - mTextureWidth, mTextureHeight), new Exception()); - } - } - - public int getId() { - return mId; - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } - - // Returns the width rounded to the next power of 2. - public int getTextureWidth() { - return mTextureWidth; - } - - // Returns the height rounded to the next power of 2. - public int getTextureHeight() { - return mTextureHeight; - } - - // Returns true if the texture has one pixel transparent border around the - // actual content. This is used to avoid jigged edges. - // - // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap - // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially - // covered by the texture will use the color of the edge texel. If we add - // the transparent border, the color of the edge texel will be mixed with - // appropriate amount of transparent. - // - // Currently our background is black, so we can draw the thumbnails without - // enabling blending. - public boolean hasBorder() { - return mHasBorder; - } - - protected void setBorder(boolean hasBorder) { - mHasBorder = hasBorder; - } - - @Override - public void draw(GLCanvas canvas, int x, int y) { - canvas.drawTexture(this, x, y, getWidth(), getHeight()); - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int w, int h) { - canvas.drawTexture(this, x, y, w, h); - } - - // onBind is called before GLCanvas binds this texture. - // It should make sure the data is uploaded to GL memory. - abstract protected boolean onBind(GLCanvas canvas); - - // Returns the GL texture target for this texture (e.g. GL_TEXTURE_2D). - abstract protected int getTarget(); - - public boolean isLoaded() { - return mState == STATE_LOADED; - } - - // recycle() is called when the texture will never be used again, - // so it can free all resources. - public void recycle() { - freeResource(); - } - - // yield() is called when the texture will not be used temporarily, - // so it can free some resources. - // The default implementation unloads the texture from GL memory, so - // the subclass should make sure it can reload the texture to GL memory - // later, or it will have to override this method. - public void yield() { - freeResource(); - } - - private void freeResource() { - GLCanvas canvas = mCanvasRef; - if (canvas != null && isLoaded()) { - canvas.unloadTexture(this); - } - mState = STATE_UNLOADED; - setAssociatedCanvas(null); - } - - @Override - protected void finalize() { - sInFinalizer.set(BasicTexture.class); - recycle(); - sInFinalizer.set(null); - } - - // This is for deciding if we can call Bitmap's recycle(). - // We cannot call Bitmap's recycle() in finalizer because at that point - // the finalizer of Bitmap may already be called so recycle() will crash. - public static boolean inFinalizer() { - return sInFinalizer.get() != null; - } - - public static void yieldAllTextures() { - synchronized (sAllTextures) { - for (BasicTexture t : sAllTextures.keySet()) { - t.yield(); - } - } - } - - public static void invalidateAllTextures() { - synchronized (sAllTextures) { - for (BasicTexture t : sAllTextures.keySet()) { - t.mState = STATE_UNLOADED; - t.setAssociatedCanvas(null); - } - } - } -} diff --git a/src/com/android/gallery3d/ui/BitmapScreenNail.java b/src/com/android/gallery3d/ui/BitmapScreenNail.java index 741eefbe3..a3d403946 100644 --- a/src/com/android/gallery3d/ui/BitmapScreenNail.java +++ b/src/com/android/gallery3d/ui/BitmapScreenNail.java @@ -19,6 +19,9 @@ package com.android.gallery3d.ui; import android.graphics.Bitmap; import android.graphics.RectF; +import com.android.gallery3d.glrenderer.BitmapTexture; +import com.android.gallery3d.glrenderer.GLCanvas; + public class BitmapScreenNail implements ScreenNail { private final BitmapTexture mBitmapTexture; diff --git a/src/com/android/gallery3d/ui/BitmapTexture.java b/src/com/android/gallery3d/ui/BitmapTexture.java deleted file mode 100644 index 607544907..000000000 --- a/src/com/android/gallery3d/ui/BitmapTexture.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.Bitmap; - -import com.android.gallery3d.common.Utils; - -// BitmapTexture is a texture whose content is specified by a fixed Bitmap. -// -// The texture does not own the Bitmap. The user should make sure the Bitmap -// is valid during the texture's lifetime. When the texture is recycled, it -// does not free the Bitmap. -public class BitmapTexture extends UploadedTexture { - protected Bitmap mContentBitmap; - - public BitmapTexture(Bitmap bitmap) { - this(bitmap, false); - } - - public BitmapTexture(Bitmap bitmap, boolean hasBorder) { - super(hasBorder); - Utils.assertTrue(bitmap != null && !bitmap.isRecycled()); - mContentBitmap = bitmap; - } - - @Override - protected void onFreeBitmap(Bitmap bitmap) { - // Do nothing. - } - - @Override - protected Bitmap onGetBitmap() { - return mContentBitmap; - } - - public Bitmap getBitmap() { - return mContentBitmap; - } -} diff --git a/src/com/android/gallery3d/ui/BitmapTileProvider.java b/src/com/android/gallery3d/ui/BitmapTileProvider.java index d4c9b1d30..c3466e7fe 100644 --- a/src/com/android/gallery3d/ui/BitmapTileProvider.java +++ b/src/com/android/gallery3d/ui/BitmapTileProvider.java @@ -25,7 +25,7 @@ import com.android.gallery3d.data.BitmapPool; import java.util.ArrayList; -public class BitmapTileProvider implements TileImageView.Model { +public class BitmapTileProvider implements TileImageView.TileSource { private final ScreenNail mScreenNail; private final Bitmap[] mMipmaps; private final Config mConfig; @@ -72,22 +72,21 @@ public class BitmapTileProvider implements TileImageView.Model { @Override public Bitmap getTile(int level, int x, int y, int tileSize, - int borderSize, BitmapPool pool) { + BitmapPool pool) { x >>= level; y >>= level; - int size = tileSize + 2 * borderSize; Bitmap result = pool == null ? null : pool.getBitmap(); if (result == null) { - result = Bitmap.createBitmap(size, size, mConfig); + result = Bitmap.createBitmap(tileSize, tileSize, mConfig); } else { result.eraseColor(0); } Bitmap mipmap = mMipmaps[level]; Canvas canvas = new Canvas(result); - int offsetX = -x + borderSize; - int offsetY = -y + borderSize; + int offsetX = -x; + int offsetY = -y; canvas.drawBitmap(mipmap, offsetX, offsetY, null); return result; } diff --git a/src/com/android/gallery3d/ui/CanvasTexture.java b/src/com/android/gallery3d/ui/CanvasTexture.java deleted file mode 100644 index a2e9e48ad..000000000 --- a/src/com/android/gallery3d/ui/CanvasTexture.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; - -// CanvasTexture is a texture whose content is the drawing on a Canvas. -// The subclasses should override onDraw() to draw on the bitmap. -// By default CanvasTexture is not opaque. -abstract class CanvasTexture extends UploadedTexture { - protected Canvas mCanvas; - private final Config mConfig; - - public CanvasTexture(int width, int height) { - mConfig = Config.ARGB_8888; - setSize(width, height); - setOpaque(false); - } - - @Override - protected Bitmap onGetBitmap() { - Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, mConfig); - mCanvas = new Canvas(bitmap); - onDraw(mCanvas, bitmap); - return bitmap; - } - - @Override - protected void onFreeBitmap(Bitmap bitmap) { - if (!inFinalizer()) { - bitmap.recycle(); - } - } - - abstract protected void onDraw(Canvas canvas, Bitmap backing); -} diff --git a/src/com/android/gallery3d/ui/ColorTexture.java b/src/com/android/gallery3d/ui/ColorTexture.java deleted file mode 100644 index 733c05653..000000000 --- a/src/com/android/gallery3d/ui/ColorTexture.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import com.android.gallery3d.common.Utils; - -// ColorTexture is a texture which fills the rectangle with the specified color. -public class ColorTexture implements Texture { - - private final int mColor; - private int mWidth; - private int mHeight; - - public ColorTexture(int color) { - mColor = color; - mWidth = 1; - mHeight = 1; - } - - @Override - public void draw(GLCanvas canvas, int x, int y) { - draw(canvas, x, y, mWidth, mHeight); - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int w, int h) { - canvas.fillRect(x, y, w, h, mColor); - } - - @Override - public boolean isOpaque() { - return Utils.isOpaque(mColor); - } - - public void setSize(int width, int height) { - mWidth = width; - mHeight = height; - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } -} diff --git a/src/com/android/gallery3d/ui/CropView.java b/src/com/android/gallery3d/ui/CropView.java deleted file mode 100644 index 1890c7630..000000000 --- a/src/com/android/gallery3d/ui/CropView.java +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PointF; -import android.graphics.RectF; -import android.media.FaceDetector; -import android.os.Handler; -import android.os.Message; -import android.util.FloatMath; -import android.view.MotionEvent; -import android.view.animation.DecelerateInterpolator; -import android.widget.Toast; - -import com.android.gallery3d.R; -import com.android.gallery3d.anim.Animation; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.common.Utils; - -import java.util.ArrayList; - -import javax.microedition.khronos.opengles.GL11; - -/** - * The activity can crop specific region of interest from an image. - */ -public class CropView extends GLView { - @SuppressWarnings("unused") - private static final String TAG = "CropView"; - - private static final int FACE_PIXEL_COUNT = 120000; // around 400x300 - - private static final int COLOR_OUTLINE = 0xFF008AFF; - private static final int COLOR_FACE_OUTLINE = 0xFF000000; - - private static final float OUTLINE_WIDTH = 3f; - - private static final int SIZE_UNKNOWN = -1; - private static final int TOUCH_TOLERANCE = 30; - - private static final float MIN_SELECTION_LENGTH = 16f; - public static final float UNSPECIFIED = -1f; - - private static final int MAX_FACE_COUNT = 3; - private static final float FACE_EYE_RATIO = 2f; - - private static final int ANIMATION_DURATION = 1250; - - private static final int MOVE_LEFT = 1; - private static final int MOVE_TOP = 2; - private static final int MOVE_RIGHT = 4; - private static final int MOVE_BOTTOM = 8; - private static final int MOVE_BLOCK = 16; - - private static final float MAX_SELECTION_RATIO = 0.8f; - private static final float MIN_SELECTION_RATIO = 0.4f; - private static final float SELECTION_RATIO = 0.60f; - private static final int ANIMATION_TRIGGER = 64; - - private static final int MSG_UPDATE_FACES = 1; - - private float mAspectRatio = UNSPECIFIED; - private float mSpotlightRatioX = 0; - private float mSpotlightRatioY = 0; - - private Handler mMainHandler; - - private FaceHighlightView mFaceDetectionView; - private HighlightRectangle mHighlightRectangle; - private TileImageView mImageView; - private AnimationController mAnimation = new AnimationController(); - - private int mImageWidth = SIZE_UNKNOWN; - private int mImageHeight = SIZE_UNKNOWN; - - private AbstractGalleryActivity mActivity; - - private GLPaint mPaint = new GLPaint(); - private GLPaint mFacePaint = new GLPaint(); - - private int mImageRotation; - - public CropView(AbstractGalleryActivity activity) { - mActivity = activity; - mImageView = new TileImageView(activity); - mFaceDetectionView = new FaceHighlightView(); - mHighlightRectangle = new HighlightRectangle(); - - addComponent(mImageView); - addComponent(mFaceDetectionView); - addComponent(mHighlightRectangle); - - mHighlightRectangle.setVisibility(GLView.INVISIBLE); - - mPaint.setColor(COLOR_OUTLINE); - mPaint.setLineWidth(OUTLINE_WIDTH); - - mFacePaint.setColor(COLOR_FACE_OUTLINE); - mFacePaint.setLineWidth(OUTLINE_WIDTH); - - mMainHandler = new SynchronizedHandler(activity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - Utils.assertTrue(message.what == MSG_UPDATE_FACES); - ((DetectFaceTask) message.obj).updateFaces(); - } - }; - } - - public void setAspectRatio(float ratio) { - mAspectRatio = ratio; - } - - public void setSpotlightRatio(float ratioX, float ratioY) { - mSpotlightRatioX = ratioX; - mSpotlightRatioY = ratioY; - } - - @Override - public void onLayout(boolean changed, int l, int t, int r, int b) { - int width = r - l; - int height = b - t; - - mFaceDetectionView.layout(0, 0, width, height); - mHighlightRectangle.layout(0, 0, width, height); - mImageView.layout(0, 0, width, height); - if (mImageHeight != SIZE_UNKNOWN) { - mAnimation.initialize(); - if (mHighlightRectangle.getVisibility() == GLView.VISIBLE) { - mAnimation.parkNow( - mHighlightRectangle.mHighlightRect); - } - } - } - - private boolean setImageViewPosition(int centerX, int centerY, float scale) { - int inverseX = mImageWidth - centerX; - int inverseY = mImageHeight - centerY; - TileImageView t = mImageView; - int rotation = mImageRotation; - switch (rotation) { - case 0: return t.setPosition(centerX, centerY, scale, 0); - case 90: return t.setPosition(centerY, inverseX, scale, 90); - case 180: return t.setPosition(inverseX, inverseY, scale, 180); - case 270: return t.setPosition(inverseY, centerX, scale, 270); - default: throw new IllegalArgumentException(String.valueOf(rotation)); - } - } - - @Override - public void render(GLCanvas canvas) { - AnimationController a = mAnimation; - if (a.calculate(AnimationTime.get())) invalidate(); - setImageViewPosition(a.getCenterX(), a.getCenterY(), a.getScale()); - super.render(canvas); - } - - @Override - public void renderBackground(GLCanvas canvas) { - canvas.clearBuffer(); - } - - public RectF getCropRectangle() { - if (mHighlightRectangle.getVisibility() == GLView.INVISIBLE) return null; - RectF rect = mHighlightRectangle.mHighlightRect; - RectF result = new RectF(rect.left * mImageWidth, rect.top * mImageHeight, - rect.right * mImageWidth, rect.bottom * mImageHeight); - return result; - } - - public int getImageWidth() { - return mImageWidth; - } - - public int getImageHeight() { - return mImageHeight; - } - - private class FaceHighlightView extends GLView { - private static final int INDEX_NONE = -1; - private ArrayList<RectF> mFaces = new ArrayList<RectF>(); - private RectF mRect = new RectF(); - private int mPressedFaceIndex = INDEX_NONE; - - public void addFace(RectF faceRect) { - mFaces.add(faceRect); - invalidate(); - } - - private void renderFace(GLCanvas canvas, RectF face, boolean pressed) { - GL11 gl = canvas.getGLInstance(); - if (pressed) { - gl.glEnable(GL11.GL_STENCIL_TEST); - gl.glClear(GL11.GL_STENCIL_BUFFER_BIT); - gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE); - gl.glStencilFunc(GL11.GL_ALWAYS, 1, 1); - } - - RectF r = mAnimation.mapRect(face, mRect); - canvas.fillRect(r.left, r.top, r.width(), r.height(), Color.TRANSPARENT); - canvas.drawRect(r.left, r.top, r.width(), r.height(), mFacePaint); - - if (pressed) { - gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); - } - } - - @Override - protected void renderBackground(GLCanvas canvas) { - ArrayList<RectF> faces = mFaces; - for (int i = 0, n = faces.size(); i < n; ++i) { - renderFace(canvas, faces.get(i), i == mPressedFaceIndex); - } - - GL11 gl = canvas.getGLInstance(); - if (mPressedFaceIndex != INDEX_NONE) { - gl.glStencilFunc(GL11.GL_NOTEQUAL, 1, 1); - canvas.fillRect(0, 0, getWidth(), getHeight(), 0x66000000); - gl.glDisable(GL11.GL_STENCIL_TEST); - } - } - - private void setPressedFace(int index) { - if (mPressedFaceIndex == index) return; - mPressedFaceIndex = index; - invalidate(); - } - - private int getFaceIndexByPosition(float x, float y) { - ArrayList<RectF> faces = mFaces; - for (int i = 0, n = faces.size(); i < n; ++i) { - RectF r = mAnimation.mapRect(faces.get(i), mRect); - if (r.contains(x, y)) return i; - } - return INDEX_NONE; - } - - @Override - protected boolean onTouch(MotionEvent event) { - float x = event.getX(); - float y = event.getY(); - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_MOVE: { - setPressedFace(getFaceIndexByPosition(x, y)); - break; - } - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - int index = mPressedFaceIndex; - setPressedFace(INDEX_NONE); - if (index != INDEX_NONE) { - mHighlightRectangle.setRectangle(mFaces.get(index)); - mHighlightRectangle.setVisibility(GLView.VISIBLE); - setVisibility(GLView.INVISIBLE); - } - } - } - return true; - } - } - - private class AnimationController extends Animation { - private int mCurrentX; - private int mCurrentY; - private float mCurrentScale; - private int mStartX; - private int mStartY; - private float mStartScale; - private int mTargetX; - private int mTargetY; - private float mTargetScale; - - public AnimationController() { - setDuration(ANIMATION_DURATION); - setInterpolator(new DecelerateInterpolator(4)); - } - - public void initialize() { - mCurrentX = mImageWidth / 2; - mCurrentY = mImageHeight / 2; - mCurrentScale = Math.min(2, Math.min( - (float) getWidth() / mImageWidth, - (float) getHeight() / mImageHeight)); - } - - public void startParkingAnimation(RectF highlight) { - RectF r = mAnimation.mapRect(highlight, new RectF()); - int width = getWidth(); - int height = getHeight(); - - float wr = r.width() / width; - float hr = r.height() / height; - final int d = ANIMATION_TRIGGER; - if (wr >= MIN_SELECTION_RATIO && wr < MAX_SELECTION_RATIO - && hr >= MIN_SELECTION_RATIO && hr < MAX_SELECTION_RATIO - && r.left >= d && r.right < width - d - && r.top >= d && r.bottom < height - d) return; - - mStartX = mCurrentX; - mStartY = mCurrentY; - mStartScale = mCurrentScale; - calculateTarget(highlight); - start(); - } - - public void parkNow(RectF highlight) { - calculateTarget(highlight); - forceStop(); - mStartX = mCurrentX = mTargetX; - mStartY = mCurrentY = mTargetY; - mStartScale = mCurrentScale = mTargetScale; - } - - public void inverseMapPoint(PointF point) { - float s = mCurrentScale; - point.x = Utils.clamp(((point.x - getWidth() * 0.5f) / s - + mCurrentX) / mImageWidth, 0, 1); - point.y = Utils.clamp(((point.y - getHeight() * 0.5f) / s - + mCurrentY) / mImageHeight, 0, 1); - } - - public RectF mapRect(RectF input, RectF output) { - float offsetX = getWidth() * 0.5f; - float offsetY = getHeight() * 0.5f; - int x = mCurrentX; - int y = mCurrentY; - float s = mCurrentScale; - output.set( - offsetX + (input.left * mImageWidth - x) * s, - offsetY + (input.top * mImageHeight - y) * s, - offsetX + (input.right * mImageWidth - x) * s, - offsetY + (input.bottom * mImageHeight - y) * s); - return output; - } - - @Override - protected void onCalculate(float progress) { - mCurrentX = Math.round(mStartX + (mTargetX - mStartX) * progress); - mCurrentY = Math.round(mStartY + (mTargetY - mStartY) * progress); - mCurrentScale = mStartScale + (mTargetScale - mStartScale) * progress; - - if (mCurrentX == mTargetX && mCurrentY == mTargetY - && mCurrentScale == mTargetScale) forceStop(); - } - - public int getCenterX() { - return mCurrentX; - } - - public int getCenterY() { - return mCurrentY; - } - - public float getScale() { - return mCurrentScale; - } - - private void calculateTarget(RectF highlight) { - float width = getWidth(); - float height = getHeight(); - - if (mImageWidth != SIZE_UNKNOWN) { - float minScale = Math.min(width / mImageWidth, height / mImageHeight); - float scale = Utils.clamp(SELECTION_RATIO * Math.min( - width / (highlight.width() * mImageWidth), - height / (highlight.height() * mImageHeight)), minScale, 2f); - int centerX = Math.round( - mImageWidth * (highlight.left + highlight.right) * 0.5f); - int centerY = Math.round( - mImageHeight * (highlight.top + highlight.bottom) * 0.5f); - - if (Math.round(mImageWidth * scale) > width) { - int limitX = Math.round(width * 0.5f / scale); - centerX = Math.round( - (highlight.left + highlight.right) * mImageWidth / 2); - centerX = Utils.clamp(centerX, limitX, mImageWidth - limitX); - } else { - centerX = mImageWidth / 2; - } - if (Math.round(mImageHeight * scale) > height) { - int limitY = Math.round(height * 0.5f / scale); - centerY = Math.round( - (highlight.top + highlight.bottom) * mImageHeight / 2); - centerY = Utils.clamp(centerY, limitY, mImageHeight - limitY); - } else { - centerY = mImageHeight / 2; - } - mTargetX = centerX; - mTargetY = centerY; - mTargetScale = scale; - } - } - - } - - private class HighlightRectangle extends GLView { - private RectF mHighlightRect = new RectF(0.25f, 0.25f, 0.75f, 0.75f); - private RectF mTempRect = new RectF(); - private PointF mTempPoint = new PointF(); - - private ResourceTexture mArrow; - - private int mMovingEdges = 0; - private float mReferenceX; - private float mReferenceY; - - public HighlightRectangle() { - mArrow = new ResourceTexture(mActivity.getAndroidContext(), - R.drawable.camera_crop_holo); - } - - public void setInitRectangle() { - float targetRatio = mAspectRatio == UNSPECIFIED - ? 1f - : mAspectRatio * mImageHeight / mImageWidth; - float w = SELECTION_RATIO / 2f; - float h = SELECTION_RATIO / 2f; - if (targetRatio > 1) { - h = w / targetRatio; - } else { - w = h * targetRatio; - } - mHighlightRect.set(0.5f - w, 0.5f - h, 0.5f + w, 0.5f + h); - } - - public void setRectangle(RectF faceRect) { - mHighlightRect.set(faceRect); - mAnimation.startParkingAnimation(faceRect); - invalidate(); - } - - private void moveEdges(MotionEvent event) { - float scale = mAnimation.getScale(); - float dx = (event.getX() - mReferenceX) / scale / mImageWidth; - float dy = (event.getY() - mReferenceY) / scale / mImageHeight; - mReferenceX = event.getX(); - mReferenceY = event.getY(); - RectF r = mHighlightRect; - - if ((mMovingEdges & MOVE_BLOCK) != 0) { - dx = Utils.clamp(dx, -r.left, 1 - r.right); - dy = Utils.clamp(dy, -r.top , 1 - r.bottom); - r.top += dy; - r.bottom += dy; - r.left += dx; - r.right += dx; - } else { - PointF point = mTempPoint; - point.set(mReferenceX, mReferenceY); - mAnimation.inverseMapPoint(point); - float left = r.left + MIN_SELECTION_LENGTH / mImageWidth; - float right = r.right - MIN_SELECTION_LENGTH / mImageWidth; - float top = r.top + MIN_SELECTION_LENGTH / mImageHeight; - float bottom = r.bottom - MIN_SELECTION_LENGTH / mImageHeight; - if ((mMovingEdges & MOVE_RIGHT) != 0) { - r.right = Utils.clamp(point.x, left, 1f); - } - if ((mMovingEdges & MOVE_LEFT) != 0) { - r.left = Utils.clamp(point.x, 0, right); - } - if ((mMovingEdges & MOVE_TOP) != 0) { - r.top = Utils.clamp(point.y, 0, bottom); - } - if ((mMovingEdges & MOVE_BOTTOM) != 0) { - r.bottom = Utils.clamp(point.y, top, 1f); - } - if (mAspectRatio != UNSPECIFIED) { - float targetRatio = mAspectRatio * mImageHeight / mImageWidth; - if (r.width() / r.height() > targetRatio) { - float height = r.width() / targetRatio; - if ((mMovingEdges & MOVE_BOTTOM) != 0) { - r.bottom = Utils.clamp(r.top + height, top, 1f); - } else { - r.top = Utils.clamp(r.bottom - height, 0, bottom); - } - } else { - float width = r.height() * targetRatio; - if ((mMovingEdges & MOVE_LEFT) != 0) { - r.left = Utils.clamp(r.right - width, 0, right); - } else { - r.right = Utils.clamp(r.left + width, left, 1f); - } - } - if (r.width() / r.height() > targetRatio) { - float width = r.height() * targetRatio; - if ((mMovingEdges & MOVE_LEFT) != 0) { - r.left = Utils.clamp(r.right - width, 0, right); - } else { - r.right = Utils.clamp(r.left + width, left, 1f); - } - } else { - float height = r.width() / targetRatio; - if ((mMovingEdges & MOVE_BOTTOM) != 0) { - r.bottom = Utils.clamp(r.top + height, top, 1f); - } else { - r.top = Utils.clamp(r.bottom - height, 0, bottom); - } - } - } - } - invalidate(); - } - - private void setMovingEdges(MotionEvent event) { - RectF r = mAnimation.mapRect(mHighlightRect, mTempRect); - float x = event.getX(); - float y = event.getY(); - - if (x > r.left + TOUCH_TOLERANCE && x < r.right - TOUCH_TOLERANCE - && y > r.top + TOUCH_TOLERANCE && y < r.bottom - TOUCH_TOLERANCE) { - mMovingEdges = MOVE_BLOCK; - return; - } - - boolean inVerticalRange = (r.top - TOUCH_TOLERANCE) <= y - && y <= (r.bottom + TOUCH_TOLERANCE); - boolean inHorizontalRange = (r.left - TOUCH_TOLERANCE) <= x - && x <= (r.right + TOUCH_TOLERANCE); - - if (inVerticalRange) { - boolean left = Math.abs(x - r.left) <= TOUCH_TOLERANCE; - boolean right = Math.abs(x - r.right) <= TOUCH_TOLERANCE; - if (left && right) { - left = Math.abs(x - r.left) < Math.abs(x - r.right); - right = !left; - } - if (left) mMovingEdges |= MOVE_LEFT; - if (right) mMovingEdges |= MOVE_RIGHT; - if (mAspectRatio != UNSPECIFIED && inHorizontalRange) { - mMovingEdges |= (y > - (r.top + r.bottom) / 2) ? MOVE_BOTTOM : MOVE_TOP; - } - } - if (inHorizontalRange) { - boolean top = Math.abs(y - r.top) <= TOUCH_TOLERANCE; - boolean bottom = Math.abs(y - r.bottom) <= TOUCH_TOLERANCE; - if (top && bottom) { - top = Math.abs(y - r.top) < Math.abs(y - r.bottom); - bottom = !top; - } - if (top) mMovingEdges |= MOVE_TOP; - if (bottom) mMovingEdges |= MOVE_BOTTOM; - if (mAspectRatio != UNSPECIFIED && inVerticalRange) { - mMovingEdges |= (x > - (r.left + r.right) / 2) ? MOVE_RIGHT : MOVE_LEFT; - } - } - } - - @Override - protected boolean onTouch(MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: { - mReferenceX = event.getX(); - mReferenceY = event.getY(); - setMovingEdges(event); - invalidate(); - return true; - } - case MotionEvent.ACTION_MOVE: - moveEdges(event); - break; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - mMovingEdges = 0; - mAnimation.startParkingAnimation(mHighlightRect); - invalidate(); - return true; - } - } - return true; - } - - @Override - protected void renderBackground(GLCanvas canvas) { - RectF r = mAnimation.mapRect(mHighlightRect, mTempRect); - drawHighlightRectangle(canvas, r); - - float centerY = (r.top + r.bottom) / 2; - float centerX = (r.left + r.right) / 2; - boolean notMoving = mMovingEdges == 0; - if ((mMovingEdges & MOVE_RIGHT) != 0 || notMoving) { - mArrow.draw(canvas, - Math.round(r.right - mArrow.getWidth() / 2), - Math.round(centerY - mArrow.getHeight() / 2)); - } - if ((mMovingEdges & MOVE_LEFT) != 0 || notMoving) { - mArrow.draw(canvas, - Math.round(r.left - mArrow.getWidth() / 2), - Math.round(centerY - mArrow.getHeight() / 2)); - } - if ((mMovingEdges & MOVE_TOP) != 0 || notMoving) { - mArrow.draw(canvas, - Math.round(centerX - mArrow.getWidth() / 2), - Math.round(r.top - mArrow.getHeight() / 2)); - } - if ((mMovingEdges & MOVE_BOTTOM) != 0 || notMoving) { - mArrow.draw(canvas, - Math.round(centerX - mArrow.getWidth() / 2), - Math.round(r.bottom - mArrow.getHeight() / 2)); - } - } - - private void drawHighlightRectangle(GLCanvas canvas, RectF r) { - GL11 gl = canvas.getGLInstance(); - gl.glLineWidth(3.0f); - gl.glEnable(GL11.GL_LINE_SMOOTH); - - gl.glEnable(GL11.GL_STENCIL_TEST); - gl.glClear(GL11.GL_STENCIL_BUFFER_BIT); - gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE); - gl.glStencilFunc(GL11.GL_ALWAYS, 1, 1); - - if (mSpotlightRatioX == 0 || mSpotlightRatioY == 0) { - canvas.fillRect(r.left, r.top, r.width(), r.height(), Color.TRANSPARENT); - canvas.drawRect(r.left, r.top, r.width(), r.height(), mPaint); - } else { - float sx = r.width() * mSpotlightRatioX; - float sy = r.height() * mSpotlightRatioY; - float cx = r.centerX(); - float cy = r.centerY(); - - canvas.fillRect(cx - sx / 2, cy - sy / 2, sx, sy, Color.TRANSPARENT); - canvas.drawRect(cx - sx / 2, cy - sy / 2, sx, sy, mPaint); - canvas.drawRect(r.left, r.top, r.width(), r.height(), mPaint); - - gl.glStencilFunc(GL11.GL_NOTEQUAL, 1, 1); - gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE); - - canvas.drawRect(cx - sy / 2, cy - sx / 2, sy, sx, mPaint); - canvas.fillRect(cx - sy / 2, cy - sx / 2, sy, sx, Color.TRANSPARENT); - canvas.fillRect(r.left, r.top, r.width(), r.height(), 0x80000000); - } - - gl.glStencilFunc(GL11.GL_NOTEQUAL, 1, 1); - gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); - - canvas.fillRect(0, 0, getWidth(), getHeight(), 0xA0000000); - - gl.glDisable(GL11.GL_STENCIL_TEST); - } - } - - private class DetectFaceTask extends Thread { - private final FaceDetector.Face[] mFaces = new FaceDetector.Face[MAX_FACE_COUNT]; - private final Bitmap mFaceBitmap; - private int mFaceCount; - - public DetectFaceTask(Bitmap bitmap) { - mFaceBitmap = bitmap; - setName("face-detect"); - } - - @Override - public void run() { - Bitmap bitmap = mFaceBitmap; - FaceDetector detector = new FaceDetector( - bitmap.getWidth(), bitmap.getHeight(), MAX_FACE_COUNT); - mFaceCount = detector.findFaces(bitmap, mFaces); - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_UPDATE_FACES, this)); - } - - private RectF getFaceRect(FaceDetector.Face face) { - PointF point = new PointF(); - face.getMidPoint(point); - - int width = mFaceBitmap.getWidth(); - int height = mFaceBitmap.getHeight(); - float rx = face.eyesDistance() * FACE_EYE_RATIO; - float ry = rx; - float aspect = mAspectRatio; - if (aspect != UNSPECIFIED) { - if (aspect > 1) { - rx = ry * aspect; - } else { - ry = rx / aspect; - } - } - - RectF r = new RectF( - point.x - rx, point.y - ry, point.x + rx, point.y + ry); - r.intersect(0, 0, width, height); - - if (aspect != UNSPECIFIED) { - if (r.width() / r.height() > aspect) { - float w = r.height() * aspect; - r.left = (r.left + r.right - w) * 0.5f; - r.right = r.left + w; - } else { - float h = r.width() / aspect; - r.top = (r.top + r.bottom - h) * 0.5f; - r.bottom = r.top + h; - } - } - - r.left /= width; - r.right /= width; - r.top /= height; - r.bottom /= height; - return r; - } - - public void updateFaces() { - if (mFaceCount > 1) { - for (int i = 0, n = mFaceCount; i < n; ++i) { - mFaceDetectionView.addFace(getFaceRect(mFaces[i])); - } - mFaceDetectionView.setVisibility(GLView.VISIBLE); - Toast.makeText(mActivity.getAndroidContext(), - R.string.multiface_crop_help, Toast.LENGTH_SHORT).show(); - } else if (mFaceCount == 1) { - mFaceDetectionView.setVisibility(GLView.INVISIBLE); - mHighlightRectangle.setRectangle(getFaceRect(mFaces[0])); - mHighlightRectangle.setVisibility(GLView.VISIBLE); - } else /*mFaceCount == 0*/ { - mHighlightRectangle.setInitRectangle(); - mHighlightRectangle.setVisibility(GLView.VISIBLE); - } - } - } - - public void setDataModel(TileImageView.Model dataModel, int rotation) { - if (((rotation / 90) & 0x01) != 0) { - mImageWidth = dataModel.getImageHeight(); - mImageHeight = dataModel.getImageWidth(); - } else { - mImageWidth = dataModel.getImageWidth(); - mImageHeight = dataModel.getImageHeight(); - } - - mImageRotation = rotation; - - mImageView.setModel(dataModel); - mAnimation.initialize(); - } - - public void detectFaces(Bitmap bitmap) { - int rotation = mImageRotation; - int width = bitmap.getWidth(); - int height = bitmap.getHeight(); - float scale = FloatMath.sqrt((float) FACE_PIXEL_COUNT / (width * height)); - - // faceBitmap is a correctly rotated bitmap, as viewed by a user. - Bitmap faceBitmap; - if (((rotation / 90) & 1) == 0) { - int w = (Math.round(width * scale) & ~1); // must be even - int h = Math.round(height * scale); - faceBitmap = Bitmap.createBitmap(w, h, Config.RGB_565); - Canvas canvas = new Canvas(faceBitmap); - canvas.rotate(rotation, w / 2, h / 2); - canvas.scale((float) w / width, (float) h / height); - canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG)); - } else { - int w = (Math.round(height * scale) & ~1); // must be even - int h = Math.round(width * scale); - faceBitmap = Bitmap.createBitmap(w, h, Config.RGB_565); - Canvas canvas = new Canvas(faceBitmap); - canvas.translate(w / 2, h / 2); - canvas.rotate(rotation); - canvas.translate(-h / 2, -w / 2); - canvas.scale((float) w / height, (float) h / width); - canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG)); - } - new DetectFaceTask(faceBitmap).start(); - } - - public void initializeHighlightRectangle() { - mHighlightRectangle.setInitRectangle(); - mHighlightRectangle.setVisibility(GLView.VISIBLE); - } - - public void resume() { - mImageView.prepareTextures(); - } - - public void pause() { - mImageView.freeTextures(); - } -} - diff --git a/src/com/android/gallery3d/ui/DetailsHelper.java b/src/com/android/gallery3d/ui/DetailsHelper.java index 301601156..47296f655 100644 --- a/src/com/android/gallery3d/ui/DetailsHelper.java +++ b/src/com/android/gallery3d/ui/DetailsHelper.java @@ -16,6 +16,8 @@ package com.android.gallery3d.ui; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.view.View.MeasureSpec; import com.android.gallery3d.R; @@ -44,6 +46,10 @@ public class DetailsHelper { public void hide(); } + public interface ResolutionResolvingListener { + public void onResolutionAvailable(int width, int height); + } + public DetailsHelper(AbstractGalleryActivity activity, GLView rootPane, DetailsSource source) { mContainer = new DialogDetailsView(activity, source); } @@ -75,6 +81,12 @@ public class DetailsHelper { return sAddressResolver.resolveAddress(latlng, listener); } + public static void resolveResolution(String path, ResolutionResolvingListener listener) { + Bitmap bitmap = BitmapFactory.decodeFile(path); + if (bitmap == null) return; + listener.onResolutionAvailable(bitmap.getWidth(), bitmap.getHeight()); + } + public static void pause() { if (sAddressResolver != null) sAddressResolver.cancel(); } diff --git a/src/com/android/gallery3d/ui/DialogDetailsView.java b/src/com/android/gallery3d/ui/DialogDetailsView.java index 8d96b821a..058c03654 100644 --- a/src/com/android/gallery3d/ui/DialogDetailsView.java +++ b/src/com/android/gallery3d/ui/DialogDetailsView.java @@ -37,6 +37,7 @@ import com.android.gallery3d.ui.DetailsAddressResolver.AddressResolvingListener; import com.android.gallery3d.ui.DetailsHelper.CloseListener; import com.android.gallery3d.ui.DetailsHelper.DetailsSource; import com.android.gallery3d.ui.DetailsHelper.DetailsViewContainer; +import com.android.gallery3d.ui.DetailsHelper.ResolutionResolvingListener; import java.util.ArrayList; import java.util.Map.Entry; @@ -111,9 +112,13 @@ public class DialogDetailsView implements DetailsViewContainer { }); } - private class DetailsAdapter extends BaseAdapter implements AddressResolvingListener { + + private class DetailsAdapter extends BaseAdapter + implements AddressResolvingListener, ResolutionResolvingListener { private final ArrayList<String> mItems; private int mLocationIndex; + private int mWidthIndex = -1; + private int mHeightIndex = -1; public DetailsAdapter(MediaDetails details) { Context context = mActivity.getAndroidContext(); @@ -123,6 +128,8 @@ public class DialogDetailsView implements DetailsViewContainer { } private void setDetails(Context context, MediaDetails details) { + boolean resolutionIsValid = true; + String path = null; for (Entry<Integer, Object> detail : details) { String value; switch (detail.getKey()) { @@ -170,6 +177,26 @@ public class DialogDetailsView implements DetailsViewContainer { } break; } + case MediaDetails.INDEX_WIDTH: + mWidthIndex = mItems.size(); + value = detail.getValue().toString(); + if (value.equalsIgnoreCase("0")) { + value = context.getString(R.string.unknown); + resolutionIsValid = false; + } + break; + case MediaDetails.INDEX_HEIGHT: { + mHeightIndex = mItems.size(); + value = detail.getValue().toString(); + if (value.equalsIgnoreCase("0")) { + value = context.getString(R.string.unknown); + resolutionIsValid = false; + } + break; + } + case MediaDetails.INDEX_PATH: + // Get the path and then fall through to the default case + path = detail.getValue().toString(); default: { Object valueObj = detail.getValue(); // This shouldn't happen, log its key to help us diagnose the problem. @@ -189,6 +216,9 @@ public class DialogDetailsView implements DetailsViewContainer { context, key), value); } mItems.add(value); + if (!resolutionIsValid) { + DetailsHelper.resolveResolution(path, this); + } } } @@ -235,6 +265,20 @@ public class DialogDetailsView implements DetailsViewContainer { mItems.set(mLocationIndex, address); notifyDataSetChanged(); } + + @Override + public void onResolutionAvailable(int width, int height) { + if (width == 0 || height == 0) return; + // Update the resolution with the new width and height + Context context = mActivity.getAndroidContext(); + String widthString = String.format("%s: %d", DetailsHelper.getDetailsName( + context, MediaDetails.INDEX_WIDTH), width); + String heightString = String.format("%s: %d", DetailsHelper.getDetailsName( + context, MediaDetails.INDEX_HEIGHT), height); + mItems.set(mWidthIndex, String.valueOf(widthString)); + mItems.set(mHeightIndex, String.valueOf(heightString)); + notifyDataSetChanged(); + } } @Override diff --git a/src/com/android/gallery3d/ui/EdgeEffect.java b/src/com/android/gallery3d/ui/EdgeEffect.java index ed369737b..87ff0c5d3 100644 --- a/src/com/android/gallery3d/ui/EdgeEffect.java +++ b/src/com/android/gallery3d/ui/EdgeEffect.java @@ -23,6 +23,8 @@ import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import com.android.gallery3d.R; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.ResourceTexture; // This is copied from android.widget.EdgeEffect with some small modifications: // (1) Copy the images (overscroll_{edge|glow}.png) to local resources. diff --git a/src/com/android/gallery3d/ui/EdgeView.java b/src/com/android/gallery3d/ui/EdgeView.java index 4aff0494d..051de18fa 100644 --- a/src/com/android/gallery3d/ui/EdgeView.java +++ b/src/com/android/gallery3d/ui/EdgeView.java @@ -19,6 +19,8 @@ package com.android.gallery3d.ui; import android.content.Context; import android.opengl.Matrix; +import com.android.gallery3d.glrenderer.GLCanvas; + // EdgeView draws EdgeEffect (blue glow) at four sides of the view. public class EdgeView extends GLView { @SuppressWarnings("unused") diff --git a/src/com/android/gallery3d/ui/ExtTexture.java b/src/com/android/gallery3d/ui/ExtTexture.java deleted file mode 100644 index eac504fe5..000000000 --- a/src/com/android/gallery3d/ui/ExtTexture.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import javax.microedition.khronos.opengles.GL11; -import javax.microedition.khronos.opengles.GL11Ext; - -// ExtTexture is a texture whose content comes from a external texture. -// Before drawing, setSize() should be called. -public class ExtTexture extends BasicTexture { - - private static int[] sTextureId = new int[1]; - private static float[] sCropRect = new float[4]; - private int mTarget; - - public ExtTexture(int target) { - GLId.glGenTextures(1, sTextureId, 0); - mId = sTextureId[0]; - mTarget = target; - } - - private void uploadToCanvas(GLCanvas canvas) { - GL11 gl = canvas.getGLInstance(); - - int width = getWidth(); - int height = getHeight(); - // Define a vertically flipped crop rectangle for OES_draw_texture. - // The four values in sCropRect are: left, bottom, width, and - // height. Negative value of width or height means flip. - sCropRect[0] = 0; - sCropRect[1] = height; - sCropRect[2] = width; - sCropRect[3] = -height; - - // Set texture parameters. - gl.glBindTexture(mTarget, mId); - gl.glTexParameterfv(mTarget, - GL11Ext.GL_TEXTURE_CROP_RECT_OES, sCropRect, 0); - gl.glTexParameteri(mTarget, - GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); - gl.glTexParameteri(mTarget, - GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); - gl.glTexParameterf(mTarget, - GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); - gl.glTexParameterf(mTarget, - GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - - setAssociatedCanvas(canvas); - mState = STATE_LOADED; - } - - @Override - protected boolean onBind(GLCanvas canvas) { - if (!isLoaded()) { - uploadToCanvas(canvas); - } - - return true; - } - - @Override - public int getTarget() { - return mTarget; - } - - @Override - public boolean isOpaque() { - return true; - } - - @Override - public void yield() { - // we cannot free the texture because we have no backup. - } -} diff --git a/src/com/android/gallery3d/ui/FadeInTexture.java b/src/com/android/gallery3d/ui/FadeInTexture.java deleted file mode 100644 index c6a9811f6..000000000 --- a/src/com/android/gallery3d/ui/FadeInTexture.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -// FadeInTexture is a texture which begins with a color, then gradually animates -// into a given texture. -public class FadeInTexture extends FadeTexture implements Texture { - @SuppressWarnings("unused") - private static final String TAG = "FadeInTexture"; - - private final int mColor; - private final TiledTexture mTexture; - - public FadeInTexture(int color, TiledTexture texture) { - super(texture.getWidth(), texture.getHeight(), texture.isOpaque()); - mColor = color; - mTexture = texture; - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int w, int h) { - if (isAnimating()) { - mTexture.drawMixed(canvas, mColor, getRatio(), x, y, w, h); - } else { - mTexture.draw(canvas, x, y, w, h); - } - } -} diff --git a/src/com/android/gallery3d/ui/FadeOutTexture.java b/src/com/android/gallery3d/ui/FadeOutTexture.java deleted file mode 100644 index 7050e535e..000000000 --- a/src/com/android/gallery3d/ui/FadeOutTexture.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -// FadeOutTexture is a texture which begins with a given texture, then gradually animates -// into fading out totally. -public class FadeOutTexture extends FadeTexture { - @SuppressWarnings("unused") - private static final String TAG = "FadeOutTexture"; - - private final BasicTexture mTexture; - - public FadeOutTexture(BasicTexture texture) { - super(texture.getWidth(), texture.getHeight(), texture.isOpaque()); - mTexture = texture; - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int w, int h) { - if (isAnimating()) { - canvas.save(GLCanvas.SAVE_FLAG_ALPHA); - canvas.setAlpha(getRatio()); - mTexture.draw(canvas, x, y, w, h); - canvas.restore(); - } - } -} diff --git a/src/com/android/gallery3d/ui/FadeTexture.java b/src/com/android/gallery3d/ui/FadeTexture.java deleted file mode 100644 index 5236d3639..000000000 --- a/src/com/android/gallery3d/ui/FadeTexture.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import com.android.gallery3d.common.Utils; - -// FadeTexture is a texture which fades the given texture along the time. -public abstract class FadeTexture implements Texture { - @SuppressWarnings("unused") - private static final String TAG = "FadeTexture"; - - // The duration of the fading animation in milliseconds - public static final int DURATION = 180; - - private final long mStartTime; - private final int mWidth; - private final int mHeight; - private final boolean mIsOpaque; - private boolean mIsAnimating; - - public FadeTexture(int width, int height, boolean opaque) { - mWidth = width; - mHeight = height; - mIsOpaque = opaque; - mStartTime = now(); - mIsAnimating = true; - } - - @Override - public void draw(GLCanvas canvas, int x, int y) { - draw(canvas, x, y, mWidth, mHeight); - } - - @Override - public boolean isOpaque() { - return mIsOpaque; - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } - - public boolean isAnimating() { - if (mIsAnimating) { - if (now() - mStartTime >= DURATION) { - mIsAnimating = false; - } - } - return mIsAnimating; - } - - protected float getRatio() { - float r = (float)(now() - mStartTime) / DURATION; - return Utils.clamp(1.0f - r, 0.0f, 1.0f); - } - - private long now() { - return AnimationTime.get(); - } -} diff --git a/src/com/android/gallery3d/ui/GLCanvas.java b/src/com/android/gallery3d/ui/GLCanvas.java deleted file mode 100644 index 6f8baef7e..000000000 --- a/src/com/android/gallery3d/ui/GLCanvas.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.RectF; - -import javax.microedition.khronos.opengles.GL11; - -// -// GLCanvas gives a convenient interface to draw using OpenGL. -// -// When a rectangle is specified in this interface, it means the region -// [x, x+width) * [y, y+height) -// -public interface GLCanvas { - // Tells GLCanvas the size of the underlying GL surface. This should be - // called before first drawing and when the size of GL surface is changed. - // This is called by GLRoot and should not be called by the clients - // who only want to draw on the GLCanvas. Both width and height must be - // nonnegative. - public void setSize(int width, int height); - - // Clear the drawing buffers. This should only be used by GLRoot. - public void clearBuffer(); - public void clearBuffer(float[] argb); - - // Sets and gets the current alpha, alpha must be in [0, 1]. - public void setAlpha(float alpha); - public float getAlpha(); - - // (current alpha) = (current alpha) * alpha - public void multiplyAlpha(float alpha); - - // Change the current transform matrix. - public void translate(float x, float y, float z); - public void translate(float x, float y); - public void scale(float sx, float sy, float sz); - public void rotate(float angle, float x, float y, float z); - public void multiplyMatrix(float[] mMatrix, int offset); - - // Pushes the configuration state (matrix, and alpha) onto - // a private stack. - public void save(); - - // Same as save(), but only save those specified in saveFlags. - public void save(int saveFlags); - - public static final int SAVE_FLAG_ALL = 0xFFFFFFFF; - public static final int SAVE_FLAG_ALPHA = 0x01; - public static final int SAVE_FLAG_MATRIX = 0x02; - - // Pops from the top of the stack as current configuration state (matrix, - // alpha, and clip). This call balances a previous call to save(), and is - // used to remove all modifications to the configuration state since the - // last save call. - public void restore(); - - // Draws a line using the specified paint from (x1, y1) to (x2, y2). - // (Both end points are included). - public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint); - - // Draws a rectangle using the specified paint from (x1, y1) to (x2, y2). - // (Both end points are included). - public void drawRect(float x1, float y1, float x2, float y2, GLPaint paint); - - // Fills the specified rectangle with the specified color. - public void fillRect(float x, float y, float width, float height, int color); - - // Draws a texture to the specified rectangle. - public void drawTexture( - BasicTexture texture, int x, int y, int width, int height); - public void drawMesh(BasicTexture tex, int x, int y, int xyBuffer, - int uvBuffer, int indexBuffer, int indexCount); - - // Draws the source rectangle part of the texture to the target rectangle. - public void drawTexture(BasicTexture texture, RectF source, RectF target); - - // Draw a texture with a specified texture transform. - public void drawTexture(BasicTexture texture, float[] mTextureTransform, - int x, int y, int w, int h); - - // Draw two textures to the specified rectangle. The actual texture used is - // from * (1 - ratio) + to * ratio - // The two textures must have the same size. - public void drawMixed(BasicTexture from, int toColor, - float ratio, int x, int y, int w, int h); - - // Draw a region of a texture and a specified color to the specified - // rectangle. The actual color used is from * (1 - ratio) + to * ratio. - // The region of the texture is defined by parameter "src". The target - // rectangle is specified by parameter "target". - public void drawMixed(BasicTexture from, int toColor, - float ratio, RectF src, RectF target); - - // Gets the underlying GL instance. This is used only when direct access to - // GL is needed. - public GL11 getGLInstance(); - - // Unloads the specified texture from the canvas. The resource allocated - // to draw the texture will be released. The specified texture will return - // to the unloaded state. This function should be called only from - // BasicTexture or its descendant - public boolean unloadTexture(BasicTexture texture); - - // Delete the specified buffer object, similar to unloadTexture. - public void deleteBuffer(int bufferId); - - // Delete the textures and buffers in GL side. This function should only be - // called in the GL thread. - public void deleteRecycledResources(); - - // Dump statistics information and clear the counters. For debug only. - public void dumpStatisticsAndClear(); - - public void beginRenderTarget(RawTexture texture); - - public void endRenderTarget(); -} diff --git a/src/com/android/gallery3d/ui/GLCanvasImpl.java b/src/com/android/gallery3d/ui/GLCanvasImpl.java deleted file mode 100644 index 45903b3cd..000000000 --- a/src/com/android/gallery3d/ui/GLCanvasImpl.java +++ /dev/null @@ -1,920 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.RectF; -import android.opengl.GLU; -import android.opengl.Matrix; - -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.util.IntArray; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import java.util.ArrayList; - -import javax.microedition.khronos.opengles.GL10; -import javax.microedition.khronos.opengles.GL11; -import javax.microedition.khronos.opengles.GL11Ext; -import javax.microedition.khronos.opengles.GL11ExtensionPack; - -public class GLCanvasImpl implements GLCanvas { - @SuppressWarnings("unused") - private static final String TAG = "GLCanvasImp"; - - private static final float OPAQUE_ALPHA = 0.95f; - - private static final int OFFSET_FILL_RECT = 0; - private static final int OFFSET_DRAW_LINE = 4; - private static final int OFFSET_DRAW_RECT = 6; - private static final float[] BOX_COORDINATES = { - 0, 0, 1, 0, 0, 1, 1, 1, // used for filling a rectangle - 0, 0, 1, 1, // used for drawing a line - 0, 0, 0, 1, 1, 1, 1, 0}; // used for drawing the outline of a rectangle - - private final GL11 mGL; - - private final float mMatrixValues[] = new float[16]; - private final float mTextureMatrixValues[] = new float[16]; - - // The results of mapPoints are stored in this buffer, and the order is - // x1, y1, x2, y2. - private final float mMapPointsBuffer[] = new float[4]; - - private final float mTextureColor[] = new float[4]; - - private int mBoxCoords; - - private final GLState mGLState; - private final ArrayList<RawTexture> mTargetStack = new ArrayList<RawTexture>(); - - private float mAlpha; - private final ArrayList<ConfigState> mRestoreStack = new ArrayList<ConfigState>(); - private ConfigState mRecycledRestoreAction; - - private final RectF mDrawTextureSourceRect = new RectF(); - private final RectF mDrawTextureTargetRect = new RectF(); - private final float[] mTempMatrix = new float[32]; - private final IntArray mUnboundTextures = new IntArray(); - private final IntArray mDeleteBuffers = new IntArray(); - private int mScreenWidth; - private int mScreenHeight; - private boolean mBlendEnabled = true; - private int mFrameBuffer[] = new int[1]; - - private RawTexture mTargetTexture; - - // Drawing statistics - int mCountDrawLine; - int mCountFillRect; - int mCountDrawMesh; - int mCountTextureRect; - int mCountTextureOES; - - GLCanvasImpl(GL11 gl) { - mGL = gl; - mGLState = new GLState(gl); - initialize(); - } - - @Override - public void setSize(int width, int height) { - Utils.assertTrue(width >= 0 && height >= 0); - - if (mTargetTexture == null) { - mScreenWidth = width; - mScreenHeight = height; - } - mAlpha = 1.0f; - - GL11 gl = mGL; - gl.glViewport(0, 0, width, height); - gl.glMatrixMode(GL11.GL_PROJECTION); - gl.glLoadIdentity(); - GLU.gluOrtho2D(gl, 0, width, 0, height); - - gl.glMatrixMode(GL11.GL_MODELVIEW); - gl.glLoadIdentity(); - - float matrix[] = mMatrixValues; - Matrix.setIdentityM(matrix, 0); - // to match the graphic coordinate system in android, we flip it vertically. - if (mTargetTexture == null) { - Matrix.translateM(matrix, 0, 0, height, 0); - Matrix.scaleM(matrix, 0, 1, -1, 1); - } - } - - @Override - public void setAlpha(float alpha) { - Utils.assertTrue(alpha >= 0 && alpha <= 1); - mAlpha = alpha; - } - - @Override - public float getAlpha() { - return mAlpha; - } - - @Override - public void multiplyAlpha(float alpha) { - Utils.assertTrue(alpha >= 0 && alpha <= 1); - mAlpha *= alpha; - } - - private static ByteBuffer allocateDirectNativeOrderBuffer(int size) { - return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()); - } - - private void initialize() { - GL11 gl = mGL; - - // First create an nio buffer, then create a VBO from it. - int size = BOX_COORDINATES.length * Float.SIZE / Byte.SIZE; - FloatBuffer xyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); - xyBuffer.put(BOX_COORDINATES, 0, BOX_COORDINATES.length).position(0); - - int[] name = new int[1]; - GLId.glGenBuffers(1, name, 0); - mBoxCoords = name[0]; - - gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBoxCoords); - gl.glBufferData(GL11.GL_ARRAY_BUFFER, - xyBuffer.capacity() * (Float.SIZE / Byte.SIZE), - xyBuffer, GL11.GL_STATIC_DRAW); - - gl.glVertexPointer(2, GL11.GL_FLOAT, 0, 0); - gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0); - - // Enable the texture coordinate array for Texture 1 - gl.glClientActiveTexture(GL11.GL_TEXTURE1); - gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0); - gl.glClientActiveTexture(GL11.GL_TEXTURE0); - gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); - - // mMatrixValues and mAlpha will be initialized in setSize() - } - - @Override - public void drawRect(float x, float y, float width, float height, GLPaint paint) { - GL11 gl = mGL; - - mGLState.setColorMode(paint.getColor(), mAlpha); - mGLState.setLineWidth(paint.getLineWidth()); - - saveTransform(); - translate(x, y); - scale(width, height, 1); - - gl.glLoadMatrixf(mMatrixValues, 0); - gl.glDrawArrays(GL11.GL_LINE_LOOP, OFFSET_DRAW_RECT, 4); - - restoreTransform(); - mCountDrawLine++; - } - - @Override - public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) { - GL11 gl = mGL; - - mGLState.setColorMode(paint.getColor(), mAlpha); - mGLState.setLineWidth(paint.getLineWidth()); - - saveTransform(); - translate(x1, y1); - scale(x2 - x1, y2 - y1, 1); - - gl.glLoadMatrixf(mMatrixValues, 0); - gl.glDrawArrays(GL11.GL_LINE_STRIP, OFFSET_DRAW_LINE, 2); - - restoreTransform(); - mCountDrawLine++; - } - - @Override - public void fillRect(float x, float y, float width, float height, int color) { - mGLState.setColorMode(color, mAlpha); - GL11 gl = mGL; - - saveTransform(); - translate(x, y); - scale(width, height, 1); - - gl.glLoadMatrixf(mMatrixValues, 0); - gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, 4); - - restoreTransform(); - mCountFillRect++; - } - - @Override - public void translate(float x, float y, float z) { - Matrix.translateM(mMatrixValues, 0, x, y, z); - } - - // This is a faster version of translate(x, y, z) because - // (1) we knows z = 0, (2) we inline the Matrix.translateM call, - // (3) we unroll the loop - @Override - public void translate(float x, float y) { - float[] m = mMatrixValues; - m[12] += m[0] * x + m[4] * y; - m[13] += m[1] * x + m[5] * y; - m[14] += m[2] * x + m[6] * y; - m[15] += m[3] * x + m[7] * y; - } - - @Override - public void scale(float sx, float sy, float sz) { - Matrix.scaleM(mMatrixValues, 0, sx, sy, sz); - } - - @Override - public void rotate(float angle, float x, float y, float z) { - if (angle == 0) return; - float[] temp = mTempMatrix; - Matrix.setRotateM(temp, 0, angle, x, y, z); - Matrix.multiplyMM(temp, 16, mMatrixValues, 0, temp, 0); - System.arraycopy(temp, 16, mMatrixValues, 0, 16); - } - - @Override - public void multiplyMatrix(float matrix[], int offset) { - float[] temp = mTempMatrix; - Matrix.multiplyMM(temp, 0, mMatrixValues, 0, matrix, offset); - System.arraycopy(temp, 0, mMatrixValues, 0, 16); - } - - private void textureRect(float x, float y, float width, float height) { - GL11 gl = mGL; - - saveTransform(); - translate(x, y); - scale(width, height, 1); - - gl.glLoadMatrixf(mMatrixValues, 0); - gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, 4); - - restoreTransform(); - mCountTextureRect++; - } - - @Override - public void drawMesh(BasicTexture tex, int x, int y, int xyBuffer, - int uvBuffer, int indexBuffer, int indexCount) { - float alpha = mAlpha; - if (!bindTexture(tex)) return; - - mGLState.setBlendEnabled(mBlendEnabled - && (!tex.isOpaque() || alpha < OPAQUE_ALPHA)); - mGLState.setTextureAlpha(alpha); - - // Reset the texture matrix. We will set our own texture coordinates - // below. - setTextureCoords(0, 0, 1, 1); - - saveTransform(); - translate(x, y); - - mGL.glLoadMatrixf(mMatrixValues, 0); - - mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, xyBuffer); - mGL.glVertexPointer(2, GL11.GL_FLOAT, 0, 0); - - mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, uvBuffer); - mGL.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0); - - mGL.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, indexBuffer); - mGL.glDrawElements(GL11.GL_TRIANGLE_STRIP, - indexCount, GL11.GL_UNSIGNED_BYTE, 0); - - mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBoxCoords); - mGL.glVertexPointer(2, GL11.GL_FLOAT, 0, 0); - mGL.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0); - - restoreTransform(); - mCountDrawMesh++; - } - - // Transforms two points by the given matrix m. The result - // {x1', y1', x2', y2'} are stored in mMapPointsBuffer and also returned. - private float[] mapPoints(float m[], int x1, int y1, int x2, int y2) { - float[] r = mMapPointsBuffer; - - // Multiply m and (x1 y1 0 1) to produce (x3 y3 z3 w3). z3 is unused. - float x3 = m[0] * x1 + m[4] * y1 + m[12]; - float y3 = m[1] * x1 + m[5] * y1 + m[13]; - float w3 = m[3] * x1 + m[7] * y1 + m[15]; - r[0] = x3 / w3; - r[1] = y3 / w3; - - // Same for x2 y2. - float x4 = m[0] * x2 + m[4] * y2 + m[12]; - float y4 = m[1] * x2 + m[5] * y2 + m[13]; - float w4 = m[3] * x2 + m[7] * y2 + m[15]; - r[2] = x4 / w4; - r[3] = y4 / w4; - - return r; - } - - private void drawBoundTexture( - BasicTexture texture, int x, int y, int width, int height) { - // Test whether it has been rotated or flipped, if so, glDrawTexiOES - // won't work - if (isMatrixRotatedOrFlipped(mMatrixValues)) { - if (texture.hasBorder()) { - setTextureCoords( - 1.0f / texture.getTextureWidth(), - 1.0f / texture.getTextureHeight(), - (texture.getWidth() - 1.0f) / texture.getTextureWidth(), - (texture.getHeight() - 1.0f) / texture.getTextureHeight()); - } else { - setTextureCoords(0, 0, - (float) texture.getWidth() / texture.getTextureWidth(), - (float) texture.getHeight() / texture.getTextureHeight()); - } - textureRect(x, y, width, height); - } else { - // draw the rect from bottom-left to top-right - float points[] = mapPoints( - mMatrixValues, x, y + height, x + width, y); - x = (int) (points[0] + 0.5f); - y = (int) (points[1] + 0.5f); - width = (int) (points[2] + 0.5f) - x; - height = (int) (points[3] + 0.5f) - y; - if (width > 0 && height > 0) { - ((GL11Ext) mGL).glDrawTexiOES(x, y, 0, width, height); - mCountTextureOES++; - } - } - } - - @Override - public void drawTexture( - BasicTexture texture, int x, int y, int width, int height) { - drawTexture(texture, x, y, width, height, mAlpha); - } - - private void drawTexture(BasicTexture texture, - int x, int y, int width, int height, float alpha) { - if (width <= 0 || height <= 0) return; - - mGLState.setBlendEnabled(mBlendEnabled - && (!texture.isOpaque() || alpha < OPAQUE_ALPHA)); - if (!bindTexture(texture)) return; - mGLState.setTextureAlpha(alpha); - drawBoundTexture(texture, x, y, width, height); - } - - @Override - public void drawTexture(BasicTexture texture, RectF source, RectF target) { - if (target.width() <= 0 || target.height() <= 0) return; - - // Copy the input to avoid changing it. - mDrawTextureSourceRect.set(source); - mDrawTextureTargetRect.set(target); - source = mDrawTextureSourceRect; - target = mDrawTextureTargetRect; - - mGLState.setBlendEnabled(mBlendEnabled - && (!texture.isOpaque() || mAlpha < OPAQUE_ALPHA)); - if (!bindTexture(texture)) return; - convertCoordinate(source, target, texture); - setTextureCoords(source); - mGLState.setTextureAlpha(mAlpha); - textureRect(target.left, target.top, target.width(), target.height()); - } - - @Override - public void drawTexture(BasicTexture texture, float[] mTextureTransform, - int x, int y, int w, int h) { - mGLState.setBlendEnabled(mBlendEnabled - && (!texture.isOpaque() || mAlpha < OPAQUE_ALPHA)); - if (!bindTexture(texture)) return; - setTextureCoords(mTextureTransform); - mGLState.setTextureAlpha(mAlpha); - textureRect(x, y, w, h); - } - - // This function changes the source coordinate to the texture coordinates. - // It also clips the source and target coordinates if it is beyond the - // bound of the texture. - private static void convertCoordinate(RectF source, RectF target, - BasicTexture texture) { - - int width = texture.getWidth(); - int height = texture.getHeight(); - int texWidth = texture.getTextureWidth(); - int texHeight = texture.getTextureHeight(); - // Convert to texture coordinates - source.left /= texWidth; - source.right /= texWidth; - source.top /= texHeight; - source.bottom /= texHeight; - - // Clip if the rendering range is beyond the bound of the texture. - float xBound = (float) width / texWidth; - if (source.right > xBound) { - target.right = target.left + target.width() * - (xBound - source.left) / source.width(); - source.right = xBound; - } - float yBound = (float) height / texHeight; - if (source.bottom > yBound) { - target.bottom = target.top + target.height() * - (yBound - source.top) / source.height(); - source.bottom = yBound; - } - } - - @Override - public void drawMixed(BasicTexture from, - int toColor, float ratio, int x, int y, int w, int h) { - drawMixed(from, toColor, ratio, x, y, w, h, mAlpha); - } - - private boolean bindTexture(BasicTexture texture) { - if (!texture.onBind(this)) return false; - int target = texture.getTarget(); - mGLState.setTextureTarget(target); - mGL.glBindTexture(target, texture.getId()); - return true; - } - - private void setTextureColor(float r, float g, float b, float alpha) { - float[] color = mTextureColor; - color[0] = r; - color[1] = g; - color[2] = b; - color[3] = alpha; - } - - private void setMixedColor(int toColor, float ratio, float alpha) { - // - // The formula we want: - // alpha * ((1 - ratio) * from + ratio * to) - // - // The formula that GL supports is in the form of: - // combo * from + (1 - combo) * to * scale - // - // So, we have combo = alpha * (1 - ratio) - // and scale = alpha * ratio / (1 - combo) - // - float combo = alpha * (1 - ratio); - float scale = alpha * ratio / (1 - combo); - - // Specify the interpolation factor via the alpha component of - // GL_TEXTURE_ENV_COLORs. - // RGB component are get from toColor and will used as SRC1 - float colorScale = scale * (toColor >>> 24) / (0xff * 0xff); - setTextureColor(((toColor >>> 16) & 0xff) * colorScale, - ((toColor >>> 8) & 0xff) * colorScale, - (toColor & 0xff) * colorScale, combo); - GL11 gl = mGL; - gl.glTexEnvfv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, mTextureColor, 0); - - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_RGB, GL11.GL_INTERPOLATE); - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_ALPHA, GL11.GL_INTERPOLATE); - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC1_RGB, GL11.GL_CONSTANT); - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND1_RGB, GL11.GL_SRC_COLOR); - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC1_ALPHA, GL11.GL_CONSTANT); - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND1_ALPHA, GL11.GL_SRC_ALPHA); - - // Wire up the interpolation factor for RGB. - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC2_RGB, GL11.GL_CONSTANT); - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND2_RGB, GL11.GL_SRC_ALPHA); - - // Wire up the interpolation factor for alpha. - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC2_ALPHA, GL11.GL_CONSTANT); - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND2_ALPHA, GL11.GL_SRC_ALPHA); - - } - - @Override - public void drawMixed(BasicTexture from, int toColor, float ratio, - RectF source, RectF target) { - if (target.width() <= 0 || target.height() <= 0) return; - - if (ratio <= 0.01f) { - drawTexture(from, source, target); - return; - } else if (ratio >= 1) { - fillRect(target.left, target.top, target.width(), target.height(), toColor); - return; - } - - float alpha = mAlpha; - - // Copy the input to avoid changing it. - mDrawTextureSourceRect.set(source); - mDrawTextureTargetRect.set(target); - source = mDrawTextureSourceRect; - target = mDrawTextureTargetRect; - - mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque() - || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA)); - - if (!bindTexture(from)) return; - - // Interpolate the RGB and alpha values between both textures. - mGLState.setTexEnvMode(GL11.GL_COMBINE); - setMixedColor(toColor, ratio, alpha); - convertCoordinate(source, target, from); - setTextureCoords(source); - textureRect(target.left, target.top, target.width(), target.height()); - mGLState.setTexEnvMode(GL11.GL_REPLACE); - } - - private void drawMixed(BasicTexture from, int toColor, - float ratio, int x, int y, int width, int height, float alpha) { - // change from 0 to 0.01f to prevent getting divided by zero below - if (ratio <= 0.01f) { - drawTexture(from, x, y, width, height, alpha); - return; - } else if (ratio >= 1) { - fillRect(x, y, width, height, toColor); - return; - } - - mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque() - || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA)); - - final GL11 gl = mGL; - if (!bindTexture(from)) return; - - // Interpolate the RGB and alpha values between both textures. - mGLState.setTexEnvMode(GL11.GL_COMBINE); - setMixedColor(toColor, ratio, alpha); - - drawBoundTexture(from, x, y, width, height); - mGLState.setTexEnvMode(GL11.GL_REPLACE); - } - - // TODO: the code only work for 2D should get fixed for 3D or removed - private static final int MSKEW_X = 4; - private static final int MSKEW_Y = 1; - private static final int MSCALE_X = 0; - private static final int MSCALE_Y = 5; - - private static boolean isMatrixRotatedOrFlipped(float matrix[]) { - final float eps = 1e-5f; - return Math.abs(matrix[MSKEW_X]) > eps - || Math.abs(matrix[MSKEW_Y]) > eps - || matrix[MSCALE_X] < -eps - || matrix[MSCALE_Y] > eps; - } - - private static class GLState { - - private final GL11 mGL; - - private int mTexEnvMode = GL11.GL_REPLACE; - private float mTextureAlpha = 1.0f; - private int mTextureTarget = GL11.GL_TEXTURE_2D; - private boolean mBlendEnabled = true; - private float mLineWidth = 1.0f; - private boolean mLineSmooth = false; - - public GLState(GL11 gl) { - mGL = gl; - - // Disable unused state - gl.glDisable(GL11.GL_LIGHTING); - - // Enable used features - gl.glEnable(GL11.GL_DITHER); - - gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); - gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); - gl.glEnable(GL11.GL_TEXTURE_2D); - - gl.glTexEnvf(GL11.GL_TEXTURE_ENV, - GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE); - - // Set the background color - gl.glClearColor(0f, 0f, 0f, 0f); - gl.glClearStencil(0); - - gl.glEnable(GL11.GL_BLEND); - gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); - - // We use 565 or 8888 format, so set the alignment to 2 bytes/pixel. - gl.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 2); - } - - public void setTexEnvMode(int mode) { - if (mTexEnvMode == mode) return; - mTexEnvMode = mode; - mGL.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, mode); - } - - public void setLineWidth(float width) { - if (mLineWidth == width) return; - mLineWidth = width; - mGL.glLineWidth(width); - } - - public void setTextureAlpha(float alpha) { - if (mTextureAlpha == alpha) return; - mTextureAlpha = alpha; - if (alpha >= OPAQUE_ALPHA) { - // The alpha is need for those texture without alpha channel - mGL.glColor4f(1, 1, 1, 1); - setTexEnvMode(GL11.GL_REPLACE); - } else { - mGL.glColor4f(alpha, alpha, alpha, alpha); - setTexEnvMode(GL11.GL_MODULATE); - } - } - - public void setColorMode(int color, float alpha) { - setBlendEnabled(!Utils.isOpaque(color) || alpha < OPAQUE_ALPHA); - - // Set mTextureAlpha to an invalid value, so that it will reset - // again in setTextureAlpha(float) later. - mTextureAlpha = -1.0f; - - setTextureTarget(0); - - float prealpha = (color >>> 24) * alpha * 65535f / 255f / 255f; - mGL.glColor4x( - Math.round(((color >> 16) & 0xFF) * prealpha), - Math.round(((color >> 8) & 0xFF) * prealpha), - Math.round((color & 0xFF) * prealpha), - Math.round(255 * prealpha)); - } - - // target is a value like GL_TEXTURE_2D. If target = 0, texturing is disabled. - public void setTextureTarget(int target) { - if (mTextureTarget == target) return; - if (mTextureTarget != 0) { - mGL.glDisable(mTextureTarget); - } - mTextureTarget = target; - if (mTextureTarget != 0) { - mGL.glEnable(mTextureTarget); - } - } - - public void setBlendEnabled(boolean enabled) { - if (mBlendEnabled == enabled) return; - mBlendEnabled = enabled; - if (enabled) { - mGL.glEnable(GL11.GL_BLEND); - } else { - mGL.glDisable(GL11.GL_BLEND); - } - } - } - - @Override - public GL11 getGLInstance() { - return mGL; - } - - @Override - public void clearBuffer(float[] argb) { - if(argb != null && argb.length == 4) { - mGL.glClearColor(argb[1], argb[2], argb[3], argb[0]); - } else { - mGL.glClearColor(0, 0, 0, 1); - } - mGL.glClear(GL10.GL_COLOR_BUFFER_BIT); - } - - @Override - public void clearBuffer() { - clearBuffer(null); - } - - private void setTextureCoords(RectF source) { - setTextureCoords(source.left, source.top, source.right, source.bottom); - } - - private void setTextureCoords(float left, float top, - float right, float bottom) { - mGL.glMatrixMode(GL11.GL_TEXTURE); - mTextureMatrixValues[0] = right - left; - mTextureMatrixValues[5] = bottom - top; - mTextureMatrixValues[10] = 1; - mTextureMatrixValues[12] = left; - mTextureMatrixValues[13] = top; - mTextureMatrixValues[15] = 1; - mGL.glLoadMatrixf(mTextureMatrixValues, 0); - mGL.glMatrixMode(GL11.GL_MODELVIEW); - } - - private void setTextureCoords(float[] mTextureTransform) { - mGL.glMatrixMode(GL11.GL_TEXTURE); - mGL.glLoadMatrixf(mTextureTransform, 0); - mGL.glMatrixMode(GL11.GL_MODELVIEW); - } - - // unloadTexture and deleteBuffer can be called from the finalizer thread, - // so we synchronized on the mUnboundTextures object. - @Override - public boolean unloadTexture(BasicTexture t) { - synchronized (mUnboundTextures) { - if (!t.isLoaded()) return false; - mUnboundTextures.add(t.mId); - return true; - } - } - - @Override - public void deleteBuffer(int bufferId) { - synchronized (mUnboundTextures) { - mDeleteBuffers.add(bufferId); - } - } - - @Override - public void deleteRecycledResources() { - synchronized (mUnboundTextures) { - IntArray ids = mUnboundTextures; - if (ids.size() > 0) { - GLId.glDeleteTextures(mGL, ids.size(), ids.getInternalArray(), 0); - ids.clear(); - } - - ids = mDeleteBuffers; - if (ids.size() > 0) { - GLId.glDeleteBuffers(mGL, ids.size(), ids.getInternalArray(), 0); - ids.clear(); - } - } - } - - @Override - public void save() { - save(SAVE_FLAG_ALL); - } - - @Override - public void save(int saveFlags) { - ConfigState config = obtainRestoreConfig(); - - if ((saveFlags & SAVE_FLAG_ALPHA) != 0) { - config.mAlpha = mAlpha; - } else { - config.mAlpha = -1; - } - - - if ((saveFlags & SAVE_FLAG_MATRIX) != 0) { - System.arraycopy(mMatrixValues, 0, config.mMatrix, 0, 16); - } else { - config.mMatrix[0] = Float.NEGATIVE_INFINITY; - } - - mRestoreStack.add(config); - } - - @Override - public void restore() { - if (mRestoreStack.isEmpty()) throw new IllegalStateException(); - ConfigState config = mRestoreStack.remove(mRestoreStack.size() - 1); - config.restore(this); - freeRestoreConfig(config); - } - - private void freeRestoreConfig(ConfigState action) { - action.mNextFree = mRecycledRestoreAction; - mRecycledRestoreAction = action; - } - - private ConfigState obtainRestoreConfig() { - if (mRecycledRestoreAction != null) { - ConfigState result = mRecycledRestoreAction; - mRecycledRestoreAction = result.mNextFree; - return result; - } - return new ConfigState(); - } - - private static class ConfigState { - float mAlpha; - float mMatrix[] = new float[16]; - ConfigState mNextFree; - - public void restore(GLCanvasImpl canvas) { - if (mAlpha >= 0) canvas.setAlpha(mAlpha); - if (mMatrix[0] != Float.NEGATIVE_INFINITY) { - System.arraycopy(mMatrix, 0, canvas.mMatrixValues, 0, 16); - } - } - } - - @Override - public void dumpStatisticsAndClear() { - String line = String.format( - "MESH:%d, TEX_OES:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d", - mCountDrawMesh, mCountTextureRect, mCountTextureOES, - mCountFillRect, mCountDrawLine); - mCountDrawMesh = 0; - mCountTextureRect = 0; - mCountTextureOES = 0; - mCountFillRect = 0; - mCountDrawLine = 0; - Log.d(TAG, line); - } - - private void saveTransform() { - System.arraycopy(mMatrixValues, 0, mTempMatrix, 0, 16); - } - - private void restoreTransform() { - System.arraycopy(mTempMatrix, 0, mMatrixValues, 0, 16); - } - - private void setRenderTarget(RawTexture texture) { - GL11ExtensionPack gl11ep = (GL11ExtensionPack) mGL; - - if (mTargetTexture == null && texture != null) { - GLId.glGenBuffers(1, mFrameBuffer, 0); - gl11ep.glBindFramebufferOES( - GL11ExtensionPack.GL_FRAMEBUFFER_OES, mFrameBuffer[0]); - } - if (mTargetTexture != null && texture == null) { - gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0); - gl11ep.glDeleteFramebuffersOES(1, mFrameBuffer, 0); - } - - mTargetTexture = texture; - if (texture == null) { - setSize(mScreenWidth, mScreenHeight); - } else { - setSize(texture.getWidth(), texture.getHeight()); - - if (!texture.isLoaded()) texture.prepare(this); - - gl11ep.glFramebufferTexture2DOES( - GL11ExtensionPack.GL_FRAMEBUFFER_OES, - GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, - GL11.GL_TEXTURE_2D, texture.getId(), 0); - - checkFramebufferStatus(gl11ep); - } - } - - @Override - public void endRenderTarget() { - RawTexture texture = mTargetStack.remove(mTargetStack.size() - 1); - setRenderTarget(texture); - restore(); // restore matrix and alpha - } - - @Override - public void beginRenderTarget(RawTexture texture) { - save(); // save matrix and alpha - mTargetStack.add(mTargetTexture); - setRenderTarget(texture); - } - - private static void checkFramebufferStatus(GL11ExtensionPack gl11ep) { - int status = gl11ep.glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES); - if (status != GL11ExtensionPack.GL_FRAMEBUFFER_COMPLETE_OES) { - String msg = ""; - switch (status) { - case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES: - msg = "FRAMEBUFFER_FORMATS"; - break; - case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES: - msg = "FRAMEBUFFER_ATTACHMENT"; - break; - case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES: - msg = "FRAMEBUFFER_MISSING_ATTACHMENT"; - break; - case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES: - msg = "FRAMEBUFFER_DRAW_BUFFER"; - break; - case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES: - msg = "FRAMEBUFFER_READ_BUFFER"; - break; - case GL11ExtensionPack.GL_FRAMEBUFFER_UNSUPPORTED_OES: - msg = "FRAMEBUFFER_UNSUPPORTED"; - break; - case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES: - msg = "FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; - break; - } - throw new RuntimeException(msg + ":" + Integer.toHexString(status)); - } - } -} diff --git a/src/com/android/gallery3d/ui/GLId.java b/src/com/android/gallery3d/ui/GLId.java deleted file mode 100644 index 689cf192e..000000000 --- a/src/com/android/gallery3d/ui/GLId.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import javax.microedition.khronos.opengles.GL11; -import javax.microedition.khronos.opengles.GL11ExtensionPack; - -// This mimics corresponding GL functions. -public class GLId { - static int sNextId = 1; - - public synchronized static void glGenTextures(int n, int[] textures, int offset) { - while (n-- > 0) { - textures[offset + n] = sNextId++; - } - } - - public synchronized static void glGenBuffers(int n, int[] buffers, int offset) { - while (n-- > 0) { - buffers[offset + n] = sNextId++; - } - } - - public synchronized static void glDeleteTextures(GL11 gl, int n, int[] textures, int offset) { - gl.glDeleteTextures(n, textures, offset); - } - - public synchronized static void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset) { - gl.glDeleteBuffers(n, buffers, offset); - } - - public synchronized static void glDeleteFramebuffers( - GL11ExtensionPack gl11ep, int n, int[] buffers, int offset) { - gl11ep.glDeleteFramebuffersOES(n, buffers, offset); - } -} diff --git a/src/com/android/gallery3d/ui/GLPaint.java b/src/com/android/gallery3d/ui/GLPaint.java deleted file mode 100644 index eb75cc51e..000000000 --- a/src/com/android/gallery3d/ui/GLPaint.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import com.android.gallery3d.common.Utils; - - -public class GLPaint { - private float mLineWidth = 1f; - private int mColor = 0; - - public void setColor(int color) { - mColor = color; - } - - public int getColor() { - return mColor; - } - - public void setLineWidth(float width) { - Utils.assertTrue(width >= 0); - mLineWidth = width; - } - - public float getLineWidth() { - return mLineWidth; - } -} diff --git a/src/com/android/gallery3d/ui/GLRoot.java b/src/com/android/gallery3d/ui/GLRoot.java index e406b6703..33a82eaf7 100644 --- a/src/com/android/gallery3d/ui/GLRoot.java +++ b/src/com/android/gallery3d/ui/GLRoot.java @@ -20,6 +20,7 @@ import android.content.Context; import android.graphics.Matrix; import com.android.gallery3d.anim.CanvasAnimation; +import com.android.gallery3d.glrenderer.GLCanvas; public interface GLRoot { diff --git a/src/com/android/gallery3d/ui/GLRootView.java b/src/com/android/gallery3d/ui/GLRootView.java index b7c48bf2e..755e10733 100644 --- a/src/com/android/gallery3d/ui/GLRootView.java +++ b/src/com/android/gallery3d/ui/GLRootView.java @@ -33,6 +33,9 @@ import com.android.gallery3d.R; import com.android.gallery3d.anim.CanvasAnimation; import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.Utils; +import com.android.gallery3d.glrenderer.BasicTexture; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.UploadedTexture; import com.android.gallery3d.util.GalleryUtils; import com.android.gallery3d.util.MotionEventHelper; import com.android.gallery3d.util.Profile; @@ -117,6 +120,7 @@ public class GLRootView extends GLSurfaceView super(context, attrs); mFlags |= FLAG_INITIALIZED; setBackgroundDrawable(null); + setEGLContextClientVersion(GLCanvas.getEGLContextClientVersion()); setEGLConfigChooser(mEglConfigChooser); setRenderer(this); if (ApiHelper.USE_888_PIXEL_FORMAT) { @@ -283,7 +287,8 @@ public class GLRootView extends GLSurfaceView mRenderLock.lock(); try { mGL = gl; - mCanvas = new GLCanvasImpl(gl); + mCanvas = GLCanvas.getInstance(); + mCanvas.initialize(gl); BasicTexture.invalidateAllTextures(); } finally { mRenderLock.unlock(); diff --git a/src/com/android/gallery3d/ui/GLView.java b/src/com/android/gallery3d/ui/GLView.java index 664012c5a..83de19fe4 100644 --- a/src/com/android/gallery3d/ui/GLView.java +++ b/src/com/android/gallery3d/ui/GLView.java @@ -23,6 +23,7 @@ import android.view.MotionEvent; import com.android.gallery3d.anim.CanvasAnimation; import com.android.gallery3d.anim.StateTransitionAnimation; import com.android.gallery3d.common.Utils; +import com.android.gallery3d.glrenderer.GLCanvas; import java.util.ArrayList; diff --git a/src/com/android/gallery3d/ui/GalleryEGLConfigChooser.java b/src/com/android/gallery3d/ui/GalleryEGLConfigChooser.java index deeb3b76d..4cf3edb34 100644 --- a/src/com/android/gallery3d/ui/GalleryEGLConfigChooser.java +++ b/src/com/android/gallery3d/ui/GalleryEGLConfigChooser.java @@ -18,6 +18,7 @@ package com.android.gallery3d.ui; import android.opengl.GLSurfaceView.EGLConfigChooser; import com.android.gallery3d.common.ApiHelper; +import com.android.gallery3d.glrenderer.GLCanvas; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; @@ -49,12 +50,35 @@ class GalleryEGLConfigChooser implements EGLConfigChooser { EGL10.EGL_NONE }; + private final int mConfig2Spec565[] = new int[] { + EGL10.EGL_RED_SIZE, 5, + EGL10.EGL_GREEN_SIZE, 6, + EGL10.EGL_BLUE_SIZE, 5, + EGL10.EGL_ALPHA_SIZE, 0, + EGL10.EGL_RENDERABLE_TYPE, 4, /* EGL_OPENGL_ES2_BIT */ + EGL10.EGL_NONE + }; + + private final int mConfig2Spec888[] = new int[] { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 0, + EGL10.EGL_RENDERABLE_TYPE, 4, /* EGL_OPENGL_ES2_BIT */ + EGL10.EGL_NONE + }; + @Override public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { int[] numConfig = new int[1]; - int mConfigSpec[] = ApiHelper.USE_888_PIXEL_FORMAT - ? mConfigSpec888 : mConfigSpec565; - if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, numConfig)) { + + int configSpec[]; + if (GLCanvas.getEGLContextClientVersion() == 2) { + configSpec = ApiHelper.USE_888_PIXEL_FORMAT ? mConfig2Spec888 : mConfig2Spec565; + } else { + configSpec = ApiHelper.USE_888_PIXEL_FORMAT ? mConfigSpec888 : mConfigSpec565; + } + if (!egl.eglChooseConfig(display, configSpec, null, 0, numConfig)) { throw new RuntimeException("eglChooseConfig failed"); } @@ -64,7 +88,7 @@ class GalleryEGLConfigChooser implements EGLConfigChooser { EGLConfig[] configs = new EGLConfig[numConfig[0]]; if (!egl.eglChooseConfig(display, - mConfigSpec, configs, configs.length, numConfig)) { + configSpec, configs, configs.length, numConfig)) { throw new RuntimeException(); } diff --git a/src/com/android/gallery3d/ui/GestureRecognizer.java b/src/com/android/gallery3d/ui/GestureRecognizer.java index e4e0c49f5..1e5250b9b 100644 --- a/src/com/android/gallery3d/ui/GestureRecognizer.java +++ b/src/com/android/gallery3d/ui/GestureRecognizer.java @@ -32,7 +32,7 @@ public class GestureRecognizer { boolean onSingleTapUp(float x, float y); boolean onDoubleTap(float x, float y); boolean onScroll(float dx, float dy, float totalX, float totalY); - boolean onFling(float velocityX, float velocityY); + boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY); boolean onScaleBegin(float focusX, float focusY); boolean onScale(float focusX, float focusY, float scale); void onScaleEnd(); @@ -94,7 +94,7 @@ public class GestureRecognizer { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - return mListener.onFling(velocityX, velocityY); + return mListener.onFling(e1, e2, velocityX, velocityY); } } diff --git a/src/com/android/gallery3d/ui/Log.java b/src/com/android/gallery3d/ui/Log.java index 32adc98eb..5570763bb 100644 --- a/src/com/android/gallery3d/ui/Log.java +++ b/src/com/android/gallery3d/ui/Log.java @@ -16,6 +16,7 @@ package com.android.gallery3d.ui; +// TODO: Delete this public class Log { public static int v(String tag, String msg) { return android.util.Log.v(tag, msg); diff --git a/src/com/android/gallery3d/ui/ManageCacheDrawer.java b/src/com/android/gallery3d/ui/ManageCacheDrawer.java index e989af27d..d210bd1f1 100644 --- a/src/com/android/gallery3d/ui/ManageCacheDrawer.java +++ b/src/com/android/gallery3d/ui/ManageCacheDrawer.java @@ -23,6 +23,9 @@ import com.android.gallery3d.app.AbstractGalleryActivity; import com.android.gallery3d.data.DataSourceType; import com.android.gallery3d.data.MediaSet; import com.android.gallery3d.data.Path; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.ResourceTexture; +import com.android.gallery3d.glrenderer.StringTexture; import com.android.gallery3d.ui.AlbumSetSlidingWindow.AlbumSetEntry; public class ManageCacheDrawer extends AlbumSetSlotRenderer { diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java index f432333ce..46e400483 100644 --- a/src/com/android/gallery3d/ui/MenuExecutor.java +++ b/src/com/android/gallery3d/ui/MenuExecutor.java @@ -31,7 +31,6 @@ import android.view.MenuItem; import com.android.gallery3d.R; import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.app.CropImage; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.DataManager; import com.android.gallery3d.data.MediaItem; @@ -62,6 +61,7 @@ public class MenuExecutor { private Future<?> mTask; // wait the operation to finish when we want to stop it. private boolean mWaitOnStop; + private boolean mPaused; private final AbstractGalleryActivity mActivity; private final SelectionManager mSelectionManager; @@ -113,7 +113,7 @@ public class MenuExecutor { break; } case MSG_TASK_UPDATE: { - if (mDialog != null) mDialog.setProgress(message.arg1); + if (mDialog != null && !mPaused) mDialog.setProgress(message.arg1); if (message.obj != null) { ProgressListener listener = (ProgressListener) message.obj; listener.onProgressUpdate(message.arg1); @@ -133,13 +133,23 @@ public class MenuExecutor { if (mTask != null) { if (!mWaitOnStop) mTask.cancel(); mTask.waitDone(); - mDialog.dismiss(); + if (mDialog != null && mDialog.isShowing()) mDialog.dismiss(); mDialog = null; mTask = null; } } + public void resume() { + mPaused = false; + if (mDialog != null) mDialog.show(); + } + public void pause() { + mPaused = true; + if (mDialog != null && mDialog.isShowing()) mDialog.hide(); + } + + public void destroy() { stopTaskAndDismissDialog(); } @@ -161,6 +171,7 @@ public class MenuExecutor { boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0; boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0; boolean supportTrim = (supported & MediaObject.SUPPORT_TRIM) != 0; + boolean supportMute = (supported & MediaObject.SUPPORT_MUTE) != 0; boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0; boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0; boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0; @@ -174,6 +185,7 @@ public class MenuExecutor { setMenuItemVisible(menu, R.id.action_rotate_cw, supportRotate); setMenuItemVisible(menu, R.id.action_crop, supportCrop); setMenuItemVisible(menu, R.id.action_trim, supportTrim); + setMenuItemVisible(menu, R.id.action_mute, supportMute); // Hide panorama until call to updateMenuForPanorama corrects it setMenuItemVisible(menu, R.id.action_share_panorama, false); setMenuItemVisible(menu, R.id.action_share, supportShare); @@ -332,7 +344,7 @@ public class MenuExecutor { mDialog.show(); } MediaOperation operation = new MediaOperation(action, ids, listener); - mTask = mActivity.getThreadPool().submit(operation, null); + mTask = mActivity.getBatchServiceThreadPoolIfAvailable().submit(operation, null); mWaitOnStop = waitOnStop; } diff --git a/src/com/android/gallery3d/ui/MultiLineTexture.java b/src/com/android/gallery3d/ui/MultiLineTexture.java deleted file mode 100644 index b0c3c2bbf..000000000 --- a/src/com/android/gallery3d/ui/MultiLineTexture.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.text.Layout; -import android.text.StaticLayout; -import android.text.TextPaint; - -// MultiLineTexture is a texture shows the content of a specified String. -// -// To create a MultiLineTexture, use the newInstance() method and specify -// the String, the font size, and the color. -class MultiLineTexture extends CanvasTexture { - private final Layout mLayout; - - private MultiLineTexture(Layout layout) { - super(layout.getWidth(), layout.getHeight()); - mLayout = layout; - } - - public static MultiLineTexture newInstance( - String text, int maxWidth, float textSize, int color, - Layout.Alignment alignment) { - TextPaint paint = StringTexture.getDefaultPaint(textSize, color); - Layout layout = new StaticLayout(text, 0, text.length(), paint, - maxWidth, alignment, 1, 0, true, null, 0); - - return new MultiLineTexture(layout); - } - - @Override - protected void onDraw(Canvas canvas, Bitmap backing) { - mLayout.draw(canvas); - } -} diff --git a/src/com/android/gallery3d/ui/NinePatchChunk.java b/src/com/android/gallery3d/ui/NinePatchChunk.java deleted file mode 100644 index 61bf22c33..000000000 --- a/src/com/android/gallery3d/ui/NinePatchChunk.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.Rect; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -// See "frameworks/base/include/utils/ResourceTypes.h" for the format of -// NinePatch chunk. -class NinePatchChunk { - - public static final int NO_COLOR = 0x00000001; - public static final int TRANSPARENT_COLOR = 0x00000000; - - public Rect mPaddings = new Rect(); - - public int mDivX[]; - public int mDivY[]; - public int mColor[]; - - private static void readIntArray(int[] data, ByteBuffer buffer) { - for (int i = 0, n = data.length; i < n; ++i) { - data[i] = buffer.getInt(); - } - } - - private static void checkDivCount(int length) { - if (length == 0 || (length & 0x01) != 0) { - throw new RuntimeException("invalid nine-patch: " + length); - } - } - - public static NinePatchChunk deserialize(byte[] data) { - ByteBuffer byteBuffer = - ByteBuffer.wrap(data).order(ByteOrder.nativeOrder()); - - byte wasSerialized = byteBuffer.get(); - if (wasSerialized == 0) return null; - - NinePatchChunk chunk = new NinePatchChunk(); - chunk.mDivX = new int[byteBuffer.get()]; - chunk.mDivY = new int[byteBuffer.get()]; - chunk.mColor = new int[byteBuffer.get()]; - - checkDivCount(chunk.mDivX.length); - checkDivCount(chunk.mDivY.length); - - // skip 8 bytes - byteBuffer.getInt(); - byteBuffer.getInt(); - - chunk.mPaddings.left = byteBuffer.getInt(); - chunk.mPaddings.right = byteBuffer.getInt(); - chunk.mPaddings.top = byteBuffer.getInt(); - chunk.mPaddings.bottom = byteBuffer.getInt(); - - // skip 4 bytes - byteBuffer.getInt(); - - readIntArray(chunk.mDivX, byteBuffer); - readIntArray(chunk.mDivY, byteBuffer); - readIntArray(chunk.mColor, byteBuffer); - - return chunk; - } -}
\ No newline at end of file diff --git a/src/com/android/gallery3d/ui/NinePatchTexture.java b/src/com/android/gallery3d/ui/NinePatchTexture.java deleted file mode 100644 index fa0e9cdc3..000000000 --- a/src/com/android/gallery3d/ui/NinePatchTexture.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Rect; - -import com.android.gallery3d.common.Utils; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -import javax.microedition.khronos.opengles.GL11; - -// NinePatchTexture is a texture backed by a NinePatch resource. -// -// getPaddings() returns paddings specified in the NinePatch. -// getNinePatchChunk() returns the layout data specified in the NinePatch. -// -public class NinePatchTexture extends ResourceTexture { - @SuppressWarnings("unused") - private static final String TAG = "NinePatchTexture"; - private NinePatchChunk mChunk; - private SmallCache<NinePatchInstance> mInstanceCache - = new SmallCache<NinePatchInstance>(); - - public NinePatchTexture(Context context, int resId) { - super(context, resId); - } - - @Override - protected Bitmap onGetBitmap() { - if (mBitmap != null) return mBitmap; - - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - Bitmap bitmap = BitmapFactory.decodeResource( - mContext.getResources(), mResId, options); - mBitmap = bitmap; - setSize(bitmap.getWidth(), bitmap.getHeight()); - byte[] chunkData = bitmap.getNinePatchChunk(); - mChunk = chunkData == null - ? null - : NinePatchChunk.deserialize(bitmap.getNinePatchChunk()); - if (mChunk == null) { - throw new RuntimeException("invalid nine-patch image: " + mResId); - } - return bitmap; - } - - public Rect getPaddings() { - // get the paddings from nine patch - if (mChunk == null) onGetBitmap(); - return mChunk.mPaddings; - } - - public NinePatchChunk getNinePatchChunk() { - if (mChunk == null) onGetBitmap(); - return mChunk; - } - - // This is a simple cache for a small number of things. Linear search - // is used because the cache is small. It also tries to remove less used - // item when the cache is full by moving the often-used items to the front. - private static class SmallCache<V> { - private static final int CACHE_SIZE = 16; - private static final int CACHE_SIZE_START_MOVE = CACHE_SIZE / 2; - private int[] mKey = new int[CACHE_SIZE]; - private V[] mValue = (V[]) new Object[CACHE_SIZE]; - private int mCount; // number of items in this cache - - // Puts a value into the cache. If the cache is full, also returns - // a less used item, otherwise returns null. - public V put(int key, V value) { - if (mCount == CACHE_SIZE) { - V old = mValue[CACHE_SIZE - 1]; // remove the last item - mKey[CACHE_SIZE - 1] = key; - mValue[CACHE_SIZE - 1] = value; - return old; - } else { - mKey[mCount] = key; - mValue[mCount] = value; - mCount++; - return null; - } - } - - public V get(int key) { - for (int i = 0; i < mCount; i++) { - if (mKey[i] == key) { - // Move the accessed item one position to the front, so it - // will less likely to be removed when cache is full. Only - // do this if the cache is starting to get full. - if (mCount > CACHE_SIZE_START_MOVE && i > 0) { - int tmpKey = mKey[i]; - mKey[i] = mKey[i - 1]; - mKey[i - 1] = tmpKey; - - V tmpValue = mValue[i]; - mValue[i] = mValue[i - 1]; - mValue[i - 1] = tmpValue; - } - return mValue[i]; - } - } - return null; - } - - public void clear() { - for (int i = 0; i < mCount; i++) { - mValue[i] = null; // make sure it's can be garbage-collected. - } - mCount = 0; - } - - public int size() { - return mCount; - } - - public V valueAt(int i) { - return mValue[i]; - } - } - - private NinePatchInstance findInstance(GLCanvas canvas, int w, int h) { - int key = w; - key = (key << 16) | h; - NinePatchInstance instance = mInstanceCache.get(key); - - if (instance == null) { - instance = new NinePatchInstance(this, w, h); - NinePatchInstance removed = mInstanceCache.put(key, instance); - if (removed != null) { - removed.recycle(canvas); - } - } - - return instance; - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int w, int h) { - if (!isLoaded()) { - mInstanceCache.clear(); - } - - if (w != 0 && h != 0) { - findInstance(canvas, w, h).draw(canvas, this, x, y); - } - } - - @Override - public void recycle() { - super.recycle(); - GLCanvas canvas = mCanvasRef; - if (canvas == null) return; - int n = mInstanceCache.size(); - for (int i = 0; i < n; i++) { - NinePatchInstance instance = mInstanceCache.valueAt(i); - instance.recycle(canvas); - } - mInstanceCache.clear(); - } -} - -// This keeps data for a specialization of NinePatchTexture with the size -// (width, height). We pre-compute the coordinates for efficiency. -class NinePatchInstance { - - @SuppressWarnings("unused") - private static final String TAG = "NinePatchInstance"; - - // We need 16 vertices for a normal nine-patch image (the 4x4 vertices) - private static final int VERTEX_BUFFER_SIZE = 16 * 2; - - // We need 22 indices for a normal nine-patch image, plus 2 for each - // transparent region. Current there are at most 1 transparent region. - private static final int INDEX_BUFFER_SIZE = 22 + 2; - - private FloatBuffer mXyBuffer; - private FloatBuffer mUvBuffer; - private ByteBuffer mIndexBuffer; - - // Names for buffer names: xy, uv, index. - private int[] mBufferNames; - - private int mIdxCount; - - public NinePatchInstance(NinePatchTexture tex, int width, int height) { - NinePatchChunk chunk = tex.getNinePatchChunk(); - - if (width <= 0 || height <= 0) { - throw new RuntimeException("invalid dimension"); - } - - // The code should be easily extended to handle the general cases by - // allocating more space for buffers. But let's just handle the only - // use case. - if (chunk.mDivX.length != 2 || chunk.mDivY.length != 2) { - throw new RuntimeException("unsupported nine patch"); - } - - float divX[] = new float[4]; - float divY[] = new float[4]; - float divU[] = new float[4]; - float divV[] = new float[4]; - - int nx = stretch(divX, divU, chunk.mDivX, tex.getWidth(), width); - int ny = stretch(divY, divV, chunk.mDivY, tex.getHeight(), height); - - prepareVertexData(divX, divY, divU, divV, nx, ny, chunk.mColor); - } - - /** - * Stretches the texture according to the nine-patch rules. It will - * linearly distribute the strechy parts defined in the nine-patch chunk to - * the target area. - * - * <pre> - * source - * /--------------^---------------\ - * u0 u1 u2 u3 u4 u5 - * div ---> |fffff|ssssssss|fff|ssssss|ffff| ---> u - * | div0 div1 div2 div3 | - * | | / / / / - * | | / / / / - * | | / / / / - * |fffff|ssss|fff|sss|ffff| ---> x - * x0 x1 x2 x3 x4 x5 - * \----------v------------/ - * target - * - * f: fixed segment - * s: stretchy segment - * </pre> - * - * @param div the stretch parts defined in nine-patch chunk - * @param source the length of the texture - * @param target the length on the drawing plan - * @param u output, the positions of these dividers in the texture - * coordinate - * @param x output, the corresponding position of these dividers on the - * drawing plan - * @return the number of these dividers. - */ - private static int stretch( - float x[], float u[], int div[], int source, int target) { - int textureSize = Utils.nextPowerOf2(source); - float textureBound = (float) source / textureSize; - - float stretch = 0; - for (int i = 0, n = div.length; i < n; i += 2) { - stretch += div[i + 1] - div[i]; - } - - float remaining = target - source + stretch; - - float lastX = 0; - float lastU = 0; - - x[0] = 0; - u[0] = 0; - for (int i = 0, n = div.length; i < n; i += 2) { - // Make the stretchy segment a little smaller to prevent sampling - // on neighboring fixed segments. - // fixed segment - x[i + 1] = lastX + (div[i] - lastU) + 0.5f; - u[i + 1] = Math.min((div[i] + 0.5f) / textureSize, textureBound); - - // stretchy segment - float partU = div[i + 1] - div[i]; - float partX = remaining * partU / stretch; - remaining -= partX; - stretch -= partU; - - lastX = x[i + 1] + partX; - lastU = div[i + 1]; - x[i + 2] = lastX - 0.5f; - u[i + 2] = Math.min((lastU - 0.5f)/ textureSize, textureBound); - } - // the last fixed segment - x[div.length + 1] = target; - u[div.length + 1] = textureBound; - - // remove segments with length 0. - int last = 0; - for (int i = 1, n = div.length + 2; i < n; ++i) { - if ((x[i] - x[last]) < 1f) continue; - x[++last] = x[i]; - u[last] = u[i]; - } - return last + 1; - } - - private void prepareVertexData(float x[], float y[], float u[], float v[], - int nx, int ny, int[] color) { - /* - * Given a 3x3 nine-patch image, the vertex order is defined as the - * following graph: - * - * (0) (1) (2) (3) - * | /| /| /| - * | / | / | / | - * (4) (5) (6) (7) - * | \ | \ | \ | - * | \| \| \| - * (8) (9) (A) (B) - * | /| /| /| - * | / | / | / | - * (C) (D) (E) (F) - * - * And we draw the triangle strip in the following index order: - * - * index: 04152637B6A5948C9DAEBF - */ - int pntCount = 0; - float xy[] = new float[VERTEX_BUFFER_SIZE]; - float uv[] = new float[VERTEX_BUFFER_SIZE]; - for (int j = 0; j < ny; ++j) { - for (int i = 0; i < nx; ++i) { - int xIndex = (pntCount++) << 1; - int yIndex = xIndex + 1; - xy[xIndex] = x[i]; - xy[yIndex] = y[j]; - uv[xIndex] = u[i]; - uv[yIndex] = v[j]; - } - } - - int idxCount = 1; - boolean isForward = false; - byte index[] = new byte[INDEX_BUFFER_SIZE]; - for (int row = 0; row < ny - 1; row++) { - --idxCount; - isForward = !isForward; - - int start, end, inc; - if (isForward) { - start = 0; - end = nx; - inc = 1; - } else { - start = nx - 1; - end = -1; - inc = -1; - } - - for (int col = start; col != end; col += inc) { - int k = row * nx + col; - if (col != start) { - int colorIdx = row * (nx - 1) + col; - if (isForward) colorIdx--; - if (color[colorIdx] == NinePatchChunk.TRANSPARENT_COLOR) { - index[idxCount] = index[idxCount - 1]; - ++idxCount; - index[idxCount++] = (byte) k; - } - } - - index[idxCount++] = (byte) k; - index[idxCount++] = (byte) (k + nx); - } - } - - mIdxCount = idxCount; - - int size = (pntCount * 2) * (Float.SIZE / Byte.SIZE); - mXyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); - mUvBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); - mIndexBuffer = allocateDirectNativeOrderBuffer(mIdxCount); - - mXyBuffer.put(xy, 0, pntCount * 2).position(0); - mUvBuffer.put(uv, 0, pntCount * 2).position(0); - mIndexBuffer.put(index, 0, idxCount).position(0); - } - - private static ByteBuffer allocateDirectNativeOrderBuffer(int size) { - return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()); - } - - private void prepareBuffers(GLCanvas canvas) { - mBufferNames = new int[3]; - GL11 gl = canvas.getGLInstance(); - GLId.glGenBuffers(3, mBufferNames, 0); - - gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBufferNames[0]); - gl.glBufferData(GL11.GL_ARRAY_BUFFER, - mXyBuffer.capacity() * (Float.SIZE / Byte.SIZE), - mXyBuffer, GL11.GL_STATIC_DRAW); - - gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBufferNames[1]); - gl.glBufferData(GL11.GL_ARRAY_BUFFER, - mUvBuffer.capacity() * (Float.SIZE / Byte.SIZE), - mUvBuffer, GL11.GL_STATIC_DRAW); - - gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mBufferNames[2]); - gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, - mIndexBuffer.capacity(), - mIndexBuffer, GL11.GL_STATIC_DRAW); - - // These buffers are never used again. - mXyBuffer = null; - mUvBuffer = null; - mIndexBuffer = null; - } - - public void draw(GLCanvas canvas, NinePatchTexture tex, int x, int y) { - if (mBufferNames == null) { - prepareBuffers(canvas); - } - canvas.drawMesh(tex, x, y, mBufferNames[0], mBufferNames[1], - mBufferNames[2], mIdxCount); - } - - public void recycle(GLCanvas canvas) { - if (mBufferNames != null) { - canvas.deleteBuffer(mBufferNames[0]); - canvas.deleteBuffer(mBufferNames[1]); - canvas.deleteBuffer(mBufferNames[2]); - mBufferNames = null; - } - } -} diff --git a/src/com/android/gallery3d/ui/PhotoFallbackEffect.java b/src/com/android/gallery3d/ui/PhotoFallbackEffect.java index 3ca09ab96..4603285a4 100644 --- a/src/com/android/gallery3d/ui/PhotoFallbackEffect.java +++ b/src/com/android/gallery3d/ui/PhotoFallbackEffect.java @@ -23,6 +23,8 @@ import android.view.animation.Interpolator; import com.android.gallery3d.anim.Animation; import com.android.gallery3d.data.Path; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.RawTexture; import com.android.gallery3d.ui.AlbumSlotRenderer.SlotFilter; import java.util.ArrayList; diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java index 6dcae4ca4..40e01ab07 100644 --- a/src/com/android/gallery3d/ui/PhotoView.java +++ b/src/com/android/gallery3d/ui/PhotoView.java @@ -35,6 +35,11 @@ import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.MediaItem; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.Path; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.RawTexture; +import com.android.gallery3d.glrenderer.ResourceTexture; +import com.android.gallery3d.glrenderer.StringTexture; +import com.android.gallery3d.glrenderer.Texture; import com.android.gallery3d.util.GalleryUtils; import com.android.gallery3d.util.RangeArray; @@ -52,7 +57,7 @@ public class PhotoView extends GLView { public int height; } - public interface Model extends TileImageView.Model { + public interface Model extends TileImageView.TileSource { public int getCurrentIndex(); public void moveTo(int index); @@ -174,8 +179,9 @@ public class PhotoView extends GLView { public static final int SCREEN_NAIL_MAX = 3; // These are constants for the delete gesture. - private static final int SWIPE_ESCAPE_VELOCITY = 2500; // dp/sec - private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec + private static final int SWIPE_ESCAPE_VELOCITY = 500; // dp/sec + private static final int MAX_DISMISS_VELOCITY = 2500; // dp/sec + private static final int SWIPE_ESCAPE_DISTANCE = 150; // dp // The picture entries, the valid index is from -SCREEN_NAIL_MAX to // SCREEN_NAIL_MAX. @@ -1070,19 +1076,19 @@ public class PhotoView extends GLView { } @Override - public boolean onFling(float velocityX, float velocityY) { + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (mIgnoreSwipingGesture) return true; if (mModeChanged) return true; if (swipeImages(velocityX, velocityY)) { mIgnoreUpEvent = true; } else { - flingImages(velocityX, velocityY); + flingImages(velocityX, velocityY, Math.abs(e2.getY() - e1.getY())); } mHadFling = true; return true; } - private boolean flingImages(float velocityX, float velocityY) { + private boolean flingImages(float velocityX, float velocityY, float dY) { int vx = (int) (velocityX + 0.5f); int vy = (int) (velocityY + 0.5f); if (!mFilmMode) { @@ -1099,11 +1105,13 @@ public class PhotoView extends GLView { } int maxVelocity = GalleryUtils.dpToPixel(MAX_DISMISS_VELOCITY); int escapeVelocity = GalleryUtils.dpToPixel(SWIPE_ESCAPE_VELOCITY); + int escapeDistance = GalleryUtils.dpToPixel(SWIPE_ESCAPE_DISTANCE); int centerY = mPositionController.getPosition(mTouchBoxIndex) .centerY(); boolean fastEnough = (Math.abs(vy) > escapeVelocity) && (Math.abs(vy) > Math.abs(vx)) - && ((vy > 0) == (centerY > getHeight() / 2)); + && ((vy > 0) == (centerY > getHeight() / 2)) + && dY >= escapeDistance; if (fastEnough) { vy = Math.min(vy, maxVelocity); int duration = mPositionController.flingFilmY(mTouchBoxIndex, vy); @@ -1237,7 +1245,10 @@ public class PhotoView extends GLView { if (mFilmMode) { int xi = (int) (x + 0.5f); int yi = (int) (y + 0.5f); - mTouchBoxIndex = mPositionController.hitTest(xi, yi); + // We only care about being within the x bounds, necessary for + // handling very wide images which are otherwise very hard to fling + mTouchBoxIndex = mPositionController.hitTest(xi, getHeight() / 2); + if (mTouchBoxIndex < mPrevBound || mTouchBoxIndex > mNextBound) { mTouchBoxIndex = Integer.MAX_VALUE; } else { diff --git a/src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java b/src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java index 36e7f4b82..f52aa5ff2 100644 --- a/src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java +++ b/src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java @@ -3,6 +3,8 @@ package com.android.gallery3d.ui; import android.os.ConditionVariable; import com.android.gallery3d.app.AbstractGalleryActivity; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.RawTexture; import com.android.gallery3d.ui.GLRoot.OnGLIdleListener; public class PreparePageFadeoutTexture implements OnGLIdleListener { diff --git a/src/com/android/gallery3d/ui/ProgressSpinner.java b/src/com/android/gallery3d/ui/ProgressSpinner.java index 4f9381c76..1b31af278 100644 --- a/src/com/android/gallery3d/ui/ProgressSpinner.java +++ b/src/com/android/gallery3d/ui/ProgressSpinner.java @@ -19,6 +19,8 @@ package com.android.gallery3d.ui; import android.content.Context; import com.android.gallery3d.R; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.ResourceTexture; public class ProgressSpinner { private static float ROTATE_SPEED_OUTER = 1080f / 3500f; diff --git a/src/com/android/gallery3d/ui/RawTexture.java b/src/com/android/gallery3d/ui/RawTexture.java deleted file mode 100644 index 4c0d9d365..000000000 --- a/src/com/android/gallery3d/ui/RawTexture.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import javax.microedition.khronos.opengles.GL11; -import javax.microedition.khronos.opengles.GL11Ext; - -public class RawTexture extends BasicTexture { - private static final String TAG = "RawTexture"; - - private final static int[] sTextureId = new int[1]; - private final static float[] sCropRect = new float[4]; - - private final boolean mOpaque; - - public RawTexture(int width, int height, boolean opaque) { - mOpaque = opaque; - setSize(width, height); - } - - @Override - public boolean isOpaque() { - return mOpaque; - } - - protected void prepare(GLCanvas canvas) { - GL11 gl = canvas.getGLInstance(); - - // Define a vertically flipped crop rectangle for - // OES_draw_texture. - // The four values in sCropRect are: left, bottom, width, and - // height. Negative value of width or height means flip. - sCropRect[0] = 0; - sCropRect[1] = mHeight; - sCropRect[2] = mWidth; - sCropRect[3] = -mHeight; - - // Upload the bitmap to a new texture. - GLId.glGenTextures(1, sTextureId, 0); - gl.glBindTexture(GL11.GL_TEXTURE_2D, sTextureId[0]); - gl.glTexParameterfv(GL11.GL_TEXTURE_2D, - GL11Ext.GL_TEXTURE_CROP_RECT_OES, sCropRect, 0); - gl.glTexParameteri(GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); - gl.glTexParameteri(GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); - gl.glTexParameterf(GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); - gl.glTexParameterf(GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - - gl.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, - getTextureWidth(), getTextureHeight(), - 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, null); - - mId = sTextureId[0]; - mState = STATE_LOADED; - setAssociatedCanvas(canvas); - } - - @Override - protected boolean onBind(GLCanvas canvas) { - if (isLoaded()) return true; - Log.w(TAG, "lost the content due to context change"); - return false; - } - - @Override - public void yield() { - // we cannot free the texture because we have no backup. - } - - @Override - protected int getTarget() { - return GL11.GL_TEXTURE_2D; - } -} diff --git a/src/com/android/gallery3d/ui/ResourceTexture.java b/src/com/android/gallery3d/ui/ResourceTexture.java deleted file mode 100644 index 1fa9d7014..000000000 --- a/src/com/android/gallery3d/ui/ResourceTexture.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - -import com.android.gallery3d.common.Utils; - -// ResourceTexture is a texture whose Bitmap is decoded from a resource. -// By default ResourceTexture is not opaque. -public class ResourceTexture extends UploadedTexture { - - protected final Context mContext; - protected final int mResId; - - public ResourceTexture(Context context, int resId) { - mContext = Utils.checkNotNull(context); - mResId = resId; - setOpaque(false); - } - - @Override - protected Bitmap onGetBitmap() { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - return BitmapFactory.decodeResource( - mContext.getResources(), mResId, options); - } - - @Override - protected void onFreeBitmap(Bitmap bitmap) { - if (!inFinalizer()) { - bitmap.recycle(); - } - } -} diff --git a/src/com/android/gallery3d/ui/ScreenNail.java b/src/com/android/gallery3d/ui/ScreenNail.java index 0a16ab850..965bf0b54 100644 --- a/src/com/android/gallery3d/ui/ScreenNail.java +++ b/src/com/android/gallery3d/ui/ScreenNail.java @@ -17,6 +17,8 @@ package com.android.gallery3d.ui; import android.graphics.RectF; +import com.android.gallery3d.glrenderer.GLCanvas; + public interface ScreenNail { public int getWidth(); public int getHeight(); diff --git a/src/com/android/gallery3d/ui/ScrollBarView.java b/src/com/android/gallery3d/ui/ScrollBarView.java index 82d4800cc..34fbcef7a 100644 --- a/src/com/android/gallery3d/ui/ScrollBarView.java +++ b/src/com/android/gallery3d/ui/ScrollBarView.java @@ -20,6 +20,9 @@ import android.content.Context; import android.graphics.Rect; import android.util.TypedValue; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.NinePatchTexture; + public class ScrollBarView extends GLView { @SuppressWarnings("unused") private static final String TAG = "ScrollBarView"; diff --git a/src/com/android/gallery3d/ui/SlideshowView.java b/src/com/android/gallery3d/ui/SlideshowView.java index bb36c47e9..b215c6661 100644 --- a/src/com/android/gallery3d/ui/SlideshowView.java +++ b/src/com/android/gallery3d/ui/SlideshowView.java @@ -21,11 +21,12 @@ import android.graphics.PointF; import com.android.gallery3d.anim.CanvasAnimation; import com.android.gallery3d.anim.FloatAnimation; +import com.android.gallery3d.glrenderer.BitmapTexture; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.GLCanvas.Blending; import java.util.Random; -import javax.microedition.khronos.opengles.GL11; - public class SlideshowView extends GLView { @SuppressWarnings("unused") private static final String TAG = "SlideshowView"; @@ -93,8 +94,8 @@ public class SlideshowView extends GLView { protected void render(GLCanvas canvas) { long animTime = AnimationTime.get(); boolean requestRender = mTransitionAnimation.calculate(animTime); - GL11 gl = canvas.getGLInstance(); - gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); + canvas.save(GLCanvas.SAVE_FLAG_BLEND); + canvas.setBlending(Blending.Additive); float alpha = mPrevTexture == null ? 1f : mTransitionAnimation.get(); if (mPrevTexture != null && alpha != 1f) { @@ -118,7 +119,7 @@ public class SlideshowView extends GLView { canvas.restore(); } if (requestRender) invalidate(); - gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + canvas.restore(); } private class SlideshowAnimation extends CanvasAnimation { diff --git a/src/com/android/gallery3d/ui/SlotView.java b/src/com/android/gallery3d/ui/SlotView.java index 15a583e5c..bd0ffdc15 100644 --- a/src/com/android/gallery3d/ui/SlotView.java +++ b/src/com/android/gallery3d/ui/SlotView.java @@ -25,6 +25,7 @@ import android.view.animation.DecelerateInterpolator; import com.android.gallery3d.anim.Animation; import com.android.gallery3d.app.AbstractGalleryActivity; import com.android.gallery3d.common.Utils; +import com.android.gallery3d.glrenderer.GLCanvas; public class SlotView extends GLView { @SuppressWarnings("unused") diff --git a/src/com/android/gallery3d/ui/StringTexture.java b/src/com/android/gallery3d/ui/StringTexture.java deleted file mode 100644 index 97995c8a5..000000000 --- a/src/com/android/gallery3d/ui/StringTexture.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint.FontMetricsInt; -import android.graphics.Typeface; -import android.text.TextPaint; -import android.text.TextUtils; -import android.util.FloatMath; - -// StringTexture is a texture shows the content of a specified String. -// -// To create a StringTexture, use the newInstance() method and specify -// the String, the font size, and the color. -class StringTexture extends CanvasTexture { - private final String mText; - private final TextPaint mPaint; - private final FontMetricsInt mMetrics; - - private StringTexture(String text, TextPaint paint, - FontMetricsInt metrics, int width, int height) { - super(width, height); - mText = text; - mPaint = paint; - mMetrics = metrics; - } - - public static TextPaint getDefaultPaint(float textSize, int color) { - TextPaint paint = new TextPaint(); - paint.setTextSize(textSize); - paint.setAntiAlias(true); - paint.setColor(color); - paint.setShadowLayer(2f, 0f, 0f, Color.BLACK); - return paint; - } - - public static StringTexture newInstance( - String text, float textSize, int color) { - return newInstance(text, getDefaultPaint(textSize, color)); - } - - public static StringTexture newInstance( - String text, float textSize, int color, - float lengthLimit, boolean isBold) { - TextPaint paint = getDefaultPaint(textSize, color); - if (isBold) { - paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); - } - if (lengthLimit > 0) { - text = TextUtils.ellipsize( - text, paint, lengthLimit, TextUtils.TruncateAt.END).toString(); - } - return newInstance(text, paint); - } - - private static StringTexture newInstance(String text, TextPaint paint) { - FontMetricsInt metrics = paint.getFontMetricsInt(); - int width = (int) FloatMath.ceil(paint.measureText(text)); - int height = metrics.bottom - metrics.top; - // The texture size needs to be at least 1x1. - if (width <= 0) width = 1; - if (height <= 0) height = 1; - return new StringTexture(text, paint, metrics, width, height); - } - - @Override - protected void onDraw(Canvas canvas, Bitmap backing) { - canvas.translate(0, -mMetrics.ascent); - canvas.drawText(mText, 0, 0, mPaint); - } -} diff --git a/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java b/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java index ceed71abe..ef8959c9d 100644 --- a/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java +++ b/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java @@ -21,6 +21,8 @@ import android.graphics.RectF; import android.graphics.SurfaceTexture; import com.android.gallery3d.common.ApiHelper; +import com.android.gallery3d.glrenderer.ExtTexture; +import com.android.gallery3d.glrenderer.GLCanvas; @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) public abstract class SurfaceTextureScreenNail implements ScreenNail, diff --git a/src/com/android/gallery3d/ui/Texture.java b/src/com/android/gallery3d/ui/Texture.java deleted file mode 100644 index 2c426f994..000000000 --- a/src/com/android/gallery3d/ui/Texture.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -// Texture is a rectangular image which can be drawn on GLCanvas. -// The isOpaque() function gives a hint about whether the texture is opaque, -// so the drawing can be done faster. -// -// This is the current texture hierarchy: -// -// Texture -// -- ColorTexture -// -- FadeInTexture -// -- BasicTexture -// -- UploadedTexture -// -- BitmapTexture -// -- Tile -// -- ResourceTexture -// -- NinePatchTexture -// -- CanvasTexture -// -- StringTexture -// -public interface Texture { - public int getWidth(); - public int getHeight(); - public void draw(GLCanvas canvas, int x, int y); - public void draw(GLCanvas canvas, int x, int y, int w, int h); - public boolean isOpaque(); -} diff --git a/src/com/android/gallery3d/ui/TextureUploader.java b/src/com/android/gallery3d/ui/TextureUploader.java deleted file mode 100644 index 9a8c47fc6..000000000 --- a/src/com/android/gallery3d/ui/TextureUploader.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import com.android.gallery3d.ui.GLRoot.OnGLIdleListener; - -import java.util.ArrayDeque; - -public class TextureUploader implements OnGLIdleListener { - private static final int INIT_CAPACITY = 64; - private static final int QUOTA_PER_FRAME = 1; - - private final ArrayDeque<UploadedTexture> mFgTextures = - new ArrayDeque<UploadedTexture>(INIT_CAPACITY); - private final ArrayDeque<UploadedTexture> mBgTextures = - new ArrayDeque<UploadedTexture>(INIT_CAPACITY); - private final GLRoot mGLRoot; - private volatile boolean mIsQueued = false; - - public TextureUploader(GLRoot root) { - mGLRoot = root; - } - - public synchronized void clear() { - while (!mFgTextures.isEmpty()) { - mFgTextures.pop().setIsUploading(false); - } - while (!mBgTextures.isEmpty()) { - mBgTextures.pop().setIsUploading(false); - } - } - - // caller should hold synchronized on "this" - private void queueSelfIfNeed() { - if (mIsQueued) return; - mIsQueued = true; - mGLRoot.addOnGLIdleListener(this); - } - - public synchronized void addBgTexture(UploadedTexture t) { - if (t.isContentValid()) return; - mBgTextures.addLast(t); - t.setIsUploading(true); - queueSelfIfNeed(); - } - - public synchronized void addFgTexture(UploadedTexture t) { - if (t.isContentValid()) return; - mFgTextures.addLast(t); - t.setIsUploading(true); - queueSelfIfNeed(); - } - - private int upload(GLCanvas canvas, ArrayDeque<UploadedTexture> deque, - int uploadQuota, boolean isBackground) { - while (uploadQuota > 0) { - UploadedTexture t; - synchronized (this) { - if (deque.isEmpty()) break; - t = deque.removeFirst(); - t.setIsUploading(false); - if (t.isContentValid()) continue; - - // this has to be protected by the synchronized block - // to prevent the inner bitmap get recycled - t.updateContent(canvas); - } - - // It will took some more time for a texture to be drawn for - // the first time. - // Thus, when scrolling, if a new column appears on screen, - // it may cause a UI jank even these textures are uploaded. - if (isBackground) t.draw(canvas, 0, 0); - --uploadQuota; - } - return uploadQuota; - } - - @Override - public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) { - int uploadQuota = QUOTA_PER_FRAME; - uploadQuota = upload(canvas, mFgTextures, uploadQuota, false); - if (uploadQuota < QUOTA_PER_FRAME) mGLRoot.requestRender(); - upload(canvas, mBgTextures, uploadQuota, true); - synchronized (this) { - mIsQueued = !mFgTextures.isEmpty() || !mBgTextures.isEmpty(); - return mIsQueued; - } - } -} diff --git a/src/com/android/gallery3d/ui/TileImageView.java b/src/com/android/gallery3d/ui/TileImageView.java index 8f26981fe..f1c31e49d 100644 --- a/src/com/android/gallery3d/ui/TileImageView.java +++ b/src/com/android/gallery3d/ui/TileImageView.java @@ -16,20 +16,24 @@ package com.android.gallery3d.ui; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; +import android.support.v4.util.LongSparseArray; +import android.util.DisplayMetrics; import android.util.FloatMath; +import android.view.WindowManager; import com.android.gallery3d.app.GalleryContext; import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.LongSparseArray; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.BitmapPool; import com.android.gallery3d.data.DecodeUtils; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.UploadedTexture; import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.GalleryUtils; import com.android.gallery3d.util.ThreadPool; import com.android.gallery3d.util.ThreadPool.CancelListener; import com.android.gallery3d.util.ThreadPool.JobContext; @@ -41,14 +45,11 @@ public class TileImageView extends GLView { @SuppressWarnings("unused") private static final String TAG = "TileImageView"; - - // TILE_SIZE must be 2^N - 2. We put one pixel border in each side of the - // texture to avoid seams between tiles. - private static int TILE_SIZE; - private static final int TILE_BORDER = 1; - private static int BITMAP_SIZE; private static final int UPLOAD_LIMIT = 1; + // TILE_SIZE must be 2^N + private static int sTileSize; + private static BitmapPool sTilePool; /* @@ -76,7 +77,7 @@ public class TileImageView extends GLView { private static final int STATE_RECYCLING = 0x20; private static final int STATE_RECYCLED = 0x40; - private Model mModel; + private TileSource mModel; private ScreenNail mScreenNail; protected int mLevelCount; // cache the value of mScaledBitmaps.length @@ -125,7 +126,7 @@ public class TileImageView extends GLView { private final ThreadPool mThreadPool; private boolean mBackgroundTileUploaded; - public static interface Model { + public static interface TileSource { public int getLevelCount(); public ScreenNail getScreenNail(); public int getImageWidth(); @@ -133,8 +134,7 @@ public class TileImageView extends GLView { // The tile returned by this method can be specified this way: Assuming // the image size is (width, height), first take the intersection of (0, - // 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). Then - // extend this intersection region by borderSize pixels on each side. If + // 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). If // in extending the region, we found some part of the region are outside // the image, those pixels are filled with black. // @@ -144,27 +144,34 @@ public class TileImageView extends GLView { // // The method would be called in another thread. public Bitmap getTile(int level, int x, int y, int tileSize, - int borderSize, BitmapPool pool); + BitmapPool pool); + } + + public static boolean isHighResolution(Context context) { + DisplayMetrics metrics = new DisplayMetrics(); + WindowManager wm = (WindowManager) + context.getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getMetrics(metrics); + return metrics.heightPixels > 2048 || metrics.widthPixels > 2048; } public TileImageView(GalleryContext context) { mThreadPool = context.getThreadPool(); mTileDecoder = mThreadPool.submit(new TileDecoder()); - if (TILE_SIZE == 0) { - if (GalleryUtils.isHighResolution(context.getAndroidContext())) { - TILE_SIZE = 510 ; + if (sTileSize == 0) { + if (isHighResolution(context.getAndroidContext())) { + sTileSize = 512 ; } else { - TILE_SIZE = 254; + sTileSize = 256; } - BITMAP_SIZE = TILE_SIZE + TILE_BORDER * 2; sTilePool = ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER - ? new BitmapPool(BITMAP_SIZE, BITMAP_SIZE, 128) + ? new BitmapPool(sTileSize, sTileSize, 128) : null; } } - public void setModel(Model model) { + public void setModel(TileSource model) { mModel = model; if (model != null) notifyModelInvalidated(); } @@ -266,7 +273,7 @@ public class TileImageView extends GLView { } for (int i = fromLevel; i < endLevel; ++i) { - int size = TILE_SIZE << i; + int size = sTileSize << i; Rect r = range[i - fromLevel]; for (int y = r.top, bottom = r.bottom; y < bottom; y += size) { for (int x = r.left, right = r.right; x < right; x += size) { @@ -320,7 +327,7 @@ public class TileImageView extends GLView { int bottom = (int) FloatMath.ceil(top + height / scale); // align the rectangle to tile boundary - int size = TILE_SIZE << level; + int size = sTileSize << level; left = Math.max(0, size * (left / size)); top = Math.max(0, size * (top / size)); right = Math.min(mImageWidth, right); @@ -431,7 +438,7 @@ public class TileImageView extends GLView { mScreenNail.noDraw(); } - int size = (TILE_SIZE << level); + int size = (sTileSize << level); float length = size * mScale; Rect r = mTileRange; @@ -594,7 +601,7 @@ public class TileImageView extends GLView { RectF source = mSourceRect; RectF target = mTargetRect; target.set(x, y, x + length, y + length); - source.set(0, 0, TILE_SIZE, TILE_SIZE); + source.set(0, 0, sTileSize, sTileSize); Tile tile = getTile(tx, ty, level); if (tile != null) { @@ -614,7 +621,7 @@ public class TileImageView extends GLView { if (drawTile(tile, canvas, source, target)) return; } if (mScreenNail != null) { - int size = TILE_SIZE << level; + int size = sTileSize << level; float scaleX = (float) mScreenNail.getWidth() / mImageWidth; float scaleY = (float) mScreenNail.getHeight() / mImageHeight; source.set(tx * scaleX, ty * scaleY, (tx + size) * scaleX, @@ -627,8 +634,6 @@ public class TileImageView extends GLView { Tile tile, GLCanvas canvas, RectF source, RectF target) { while (true) { if (tile.isContentValid()) { - // offset source rectangle for the texture border. - source.offset(TILE_BORDER, TILE_BORDER); canvas.drawTexture(tile, source, target); return true; } @@ -640,15 +645,15 @@ public class TileImageView extends GLView { source.left /= 2f; source.right /= 2f; } else { - source.left = (TILE_SIZE + source.left) / 2f; - source.right = (TILE_SIZE + source.right) / 2f; + source.left = (sTileSize + source.left) / 2f; + source.right = (sTileSize + source.right) / 2f; } if (tile.mY == parent.mY) { source.top /= 2f; source.bottom /= 2f; } else { - source.top = (TILE_SIZE + source.top) / 2f; - source.bottom = (TILE_SIZE + source.bottom) / 2f; + source.top = (sTileSize + source.top) / 2f; + source.bottom = (sTileSize + source.bottom) / 2f; } tile = parent; } @@ -678,7 +683,7 @@ public class TileImageView extends GLView { // by (1 << mTilelevel) from a region in the original image. try { mDecodedTile = DecodeUtils.ensureGLCompatibleBitmap(mModel.getTile( - mTileLevel, mX, mY, TILE_SIZE, TILE_BORDER, sTilePool)); + mTileLevel, mX, mY, sTileSize, sTilePool)); } catch (Throwable t) { Log.w(TAG, "fail to decode tile", t); } @@ -691,9 +696,9 @@ public class TileImageView extends GLView { // We need to override the width and height, so that we won't // draw beyond the boundaries. - int rightEdge = ((mImageWidth - mX) >> mTileLevel) + TILE_BORDER; - int bottomEdge = ((mImageHeight - mY) >> mTileLevel) + TILE_BORDER; - setSize(Math.min(BITMAP_SIZE, rightEdge), Math.min(BITMAP_SIZE, bottomEdge)); + int rightEdge = ((mImageWidth - mX) >> mTileLevel); + int bottomEdge = ((mImageHeight - mY) >> mTileLevel); + setSize(Math.min(sTileSize, rightEdge), Math.min(sTileSize, bottomEdge)); Bitmap bitmap = mDecodedTile; mDecodedTile = null; @@ -707,12 +712,12 @@ public class TileImageView extends GLView { // boundary). @Override public int getTextureWidth() { - return TILE_SIZE + TILE_BORDER * 2; + return sTileSize; } @Override public int getTextureHeight() { - return TILE_SIZE + TILE_BORDER * 2; + return sTileSize; } public void update(int x, int y, int level) { @@ -724,7 +729,7 @@ public class TileImageView extends GLView { public Tile getParentTile() { if (mTileLevel + 1 == mLevelCount) return null; - int size = TILE_SIZE << (mTileLevel + 1); + int size = sTileSize << (mTileLevel + 1); int x = size * (mX / size); int y = size * (mY / size); return getTile(x, y, mTileLevel + 1); @@ -733,7 +738,7 @@ public class TileImageView extends GLView { @Override public String toString() { return String.format("tile(%s, %s, %s / %s)", - mX / TILE_SIZE, mY / TILE_SIZE, mLevel, mLevelCount); + mX / sTileSize, mY / sTileSize, mLevel, mLevelCount); } } diff --git a/src/com/android/gallery3d/ui/TileImageViewAdapter.java b/src/com/android/gallery3d/ui/TileImageViewAdapter.java index 45e2ce218..0d20b0757 100644 --- a/src/com/android/gallery3d/ui/TileImageViewAdapter.java +++ b/src/com/android/gallery3d/ui/TileImageViewAdapter.java @@ -28,7 +28,7 @@ import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.BitmapPool; -public class TileImageViewAdapter implements TileImageView.Model { +public class TileImageViewAdapter implements TileImageView.TileSource { private static final String TAG = "TileImageViewAdapter"; protected ScreenNail mScreenNail; protected boolean mOwnScreenNail; @@ -84,16 +84,14 @@ public class TileImageViewAdapter implements TileImageView.Model { // (44, 44, 256, 256) from the original photo and down sample it to 106. @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) @Override - public Bitmap getTile(int level, int x, int y, int tileSize, - int borderSize, BitmapPool pool) { + public Bitmap getTile(int level, int x, int y, int tileSize, BitmapPool pool) { if (!ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER) { - return getTileWithoutReusingBitmap(level, x, y, tileSize, borderSize); + return getTileWithoutReusingBitmap(level, x, y, tileSize); } - int b = borderSize << level; int t = tileSize << level; - Rect wantRegion = new Rect(x - b, y - b, x + t + b, y + t + b); + Rect wantRegion = new Rect(x, y, x + t, y + t); boolean needClear; BitmapRegionDecoder regionDecoder = null; @@ -112,8 +110,7 @@ public class TileImageViewAdapter implements TileImageView.Model { if (bitmap != null) { if (needClear) bitmap.eraseColor(0); } else { - int s = tileSize + 2 * borderSize; - bitmap = Bitmap.createBitmap(s, s, Config.ARGB_8888); + bitmap = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); } BitmapFactory.Options options = new BitmapFactory.Options(); @@ -141,10 +138,9 @@ public class TileImageViewAdapter implements TileImageView.Model { } private Bitmap getTileWithoutReusingBitmap( - int level, int x, int y, int tileSize, int borderSize) { - int b = borderSize << level; + int level, int x, int y, int tileSize) { int t = tileSize << level; - Rect wantRegion = new Rect(x - b, y - b, x + t + b, y + t + b); + Rect wantRegion = new Rect(x, y, x + t, y + t); BitmapRegionDecoder regionDecoder; Rect overlapRegion; @@ -173,8 +169,7 @@ public class TileImageViewAdapter implements TileImageView.Model { if (wantRegion.equals(overlapRegion)) return bitmap; - int s = tileSize + 2 * borderSize; - Bitmap result = Bitmap.createBitmap(s, s, Config.ARGB_8888); + Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); Canvas canvas = new Canvas(result); canvas.drawBitmap(bitmap, (overlapRegion.left - wantRegion.left) >> level, diff --git a/src/com/android/gallery3d/ui/TiledScreenNail.java b/src/com/android/gallery3d/ui/TiledScreenNail.java index 74665f584..ab24f5b6c 100644 --- a/src/com/android/gallery3d/ui/TiledScreenNail.java +++ b/src/com/android/gallery3d/ui/TiledScreenNail.java @@ -22,6 +22,8 @@ import android.graphics.RectF; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.BitmapPool; import com.android.gallery3d.data.MediaItem; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.TiledTexture; // This is a ScreenNail wraps a Bitmap. There are some extra functions: // diff --git a/src/com/android/gallery3d/ui/TiledTexture.java b/src/com/android/gallery3d/ui/TiledTexture.java deleted file mode 100644 index 02bde9f4f..000000000 --- a/src/com/android/gallery3d/ui/TiledTexture.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PorterDuff.Mode; -import android.graphics.PorterDuffXfermode; -import android.graphics.RectF; -import android.os.SystemClock; - -import com.android.gallery3d.ui.GLRoot.OnGLIdleListener; - -import java.util.ArrayDeque; -import java.util.ArrayList; - -// This class is similar to BitmapTexture, except the bitmap is -// split into tiles. By doing so, we may increase the time required to -// upload the whole bitmap but we reduce the time of uploading each tile -// so it make the animation more smooth and prevents jank. -public class TiledTexture implements Texture { - private static final int CONTENT_SIZE = 254; - private static final int BORDER_SIZE = 1; - private static final int TILE_SIZE = CONTENT_SIZE + 2 * BORDER_SIZE; - private static final int INIT_CAPACITY = 8; - - // We are targeting at 60fps, so we have 16ms for each frame. - // In this 16ms, we use about 4~8 ms to upload tiles. - private static final long UPLOAD_TILE_LIMIT = 4; // ms - - private static Tile sFreeTileHead = null; - private static final Object sFreeTileLock = new Object(); - - private static Bitmap sUploadBitmap; - private static Canvas sCanvas; - private static Paint sBitmapPaint; - private static Paint sPaint; - - private int mUploadIndex = 0; - - private final Tile[] mTiles; // Can be modified in different threads. - // Should be protected by "synchronized." - private final int mWidth; - private final int mHeight; - private final RectF mSrcRect = new RectF(); - private final RectF mDestRect = new RectF(); - - public static class Uploader implements OnGLIdleListener { - private final ArrayDeque<TiledTexture> mTextures = - new ArrayDeque<TiledTexture>(INIT_CAPACITY); - - private final GLRoot mGlRoot; - private boolean mIsQueued = false; - - public Uploader(GLRoot glRoot) { - mGlRoot = glRoot; - } - - public synchronized void clear() { - mTextures.clear(); - } - - public synchronized void addTexture(TiledTexture t) { - if (t.isReady()) return; - mTextures.addLast(t); - - if (mIsQueued) return; - mIsQueued = true; - mGlRoot.addOnGLIdleListener(this); - } - - @Override - public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) { - ArrayDeque<TiledTexture> deque = mTextures; - synchronized (this) { - long now = SystemClock.uptimeMillis(); - long dueTime = now + UPLOAD_TILE_LIMIT; - while (now < dueTime && !deque.isEmpty()) { - TiledTexture t = deque.peekFirst(); - if (t.uploadNextTile(canvas)) { - deque.removeFirst(); - mGlRoot.requestRender(); - } - now = SystemClock.uptimeMillis(); - } - mIsQueued = !mTextures.isEmpty(); - - // return true to keep this listener in the queue - return mIsQueued; - } - } - } - - private static class Tile extends UploadedTexture { - public int offsetX; - public int offsetY; - public Bitmap bitmap; - public Tile nextFreeTile; - public int contentWidth; - public int contentHeight; - - @Override - public void setSize(int width, int height) { - contentWidth = width; - contentHeight = height; - mWidth = width + 2 * BORDER_SIZE; - mHeight = height + 2 * BORDER_SIZE; - mTextureWidth = TILE_SIZE; - mTextureHeight = TILE_SIZE; - } - - @Override - protected Bitmap onGetBitmap() { - int x = BORDER_SIZE - offsetX; - int y = BORDER_SIZE - offsetY; - int r = bitmap.getWidth() + x; - int b = bitmap.getHeight() + y; - sCanvas.drawBitmap(bitmap, x, y, sBitmapPaint); - bitmap = null; - - // draw borders if need - if (x > 0) sCanvas.drawLine(x - 1, 0, x - 1, TILE_SIZE, sPaint); - if (y > 0) sCanvas.drawLine(0, y - 1, TILE_SIZE, y - 1, sPaint); - if (r < CONTENT_SIZE) sCanvas.drawLine(r, 0, r, TILE_SIZE, sPaint); - if (b < CONTENT_SIZE) sCanvas.drawLine(0, b, TILE_SIZE, b, sPaint); - - return sUploadBitmap; - } - - @Override - protected void onFreeBitmap(Bitmap bitmap) { - // do nothing - } - } - - private static void freeTile(Tile tile) { - tile.invalidateContent(); - tile.bitmap = null; - synchronized (sFreeTileLock) { - tile.nextFreeTile = sFreeTileHead; - sFreeTileHead = tile; - } - } - - private static Tile obtainTile() { - synchronized (sFreeTileLock) { - Tile result = sFreeTileHead; - if (result == null) return new Tile(); - sFreeTileHead = result.nextFreeTile; - result.nextFreeTile = null; - return result; - } - } - - private boolean uploadNextTile(GLCanvas canvas) { - if (mUploadIndex == mTiles.length) return true; - - synchronized (mTiles) { - Tile next = mTiles[mUploadIndex++]; - - // Make sure tile has not already been recycled by the time - // this is called (race condition in onGLIdle) - if (next.bitmap != null) { - boolean hasBeenLoad = next.isLoaded(); - next.updateContent(canvas); - - // It will take some time for a texture to be drawn for the first - // time. When scrolling, we need to draw several tiles on the screen - // at the same time. It may cause a UI jank even these textures has - // been uploaded. - if (!hasBeenLoad) next.draw(canvas, 0, 0); - } - } - return mUploadIndex == mTiles.length; - } - - public TiledTexture(Bitmap bitmap) { - mWidth = bitmap.getWidth(); - mHeight = bitmap.getHeight(); - ArrayList<Tile> list = new ArrayList<Tile>(); - - for (int x = 0, w = mWidth; x < w; x += CONTENT_SIZE) { - for (int y = 0, h = mHeight; y < h; y += CONTENT_SIZE) { - Tile tile = obtainTile(); - tile.offsetX = x; - tile.offsetY = y; - tile.bitmap = bitmap; - tile.setSize( - Math.min(CONTENT_SIZE, mWidth - x), - Math.min(CONTENT_SIZE, mHeight - y)); - list.add(tile); - } - } - mTiles = list.toArray(new Tile[list.size()]); - } - - public boolean isReady() { - return mUploadIndex == mTiles.length; - } - - // Can be called in UI thread. - public void recycle() { - synchronized (mTiles) { - for (int i = 0, n = mTiles.length; i < n; ++i) { - freeTile(mTiles[i]); - } - } - } - - public static void freeResources() { - sUploadBitmap = null; - sCanvas = null; - sBitmapPaint = null; - sPaint = null; - } - - public static void prepareResources() { - sUploadBitmap = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE, Config.ARGB_8888); - sCanvas = new Canvas(sUploadBitmap); - sBitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); - sBitmapPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); - sPaint = new Paint(); - sPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); - sPaint.setColor(Color.TRANSPARENT); - } - - // We want to draw the "source" on the "target". - // This method is to find the "output" rectangle which is - // the corresponding area of the "src". - // (x,y) target - // (x0,y0) source +---------------+ - // +----------+ | | - // | src | | output | - // | +--+ | linear map | +----+ | - // | +--+ | ----------> | | | | - // | | by (scaleX, scaleY) | +----+ | - // +----------+ | | - // Texture +---------------+ - // Canvas - private static void mapRect(RectF output, - RectF src, float x0, float y0, float x, float y, float scaleX, - float scaleY) { - output.set(x + (src.left - x0) * scaleX, - y + (src.top - y0) * scaleY, - x + (src.right - x0) * scaleX, - y + (src.bottom - y0) * scaleY); - } - - // Draws a mixed color of this texture and a specified color onto the - // a rectangle. The used color is: from * (1 - ratio) + to * ratio. - public void drawMixed(GLCanvas canvas, int color, float ratio, - int x, int y, int width, int height) { - RectF src = mSrcRect; - RectF dest = mDestRect; - float scaleX = (float) width / mWidth; - float scaleY = (float) height / mHeight; - synchronized (mTiles) { - for (int i = 0, n = mTiles.length; i < n; ++i) { - Tile t = mTiles[i]; - src.set(0, 0, t.contentWidth, t.contentHeight); - src.offset(t.offsetX, t.offsetY); - mapRect(dest, src, 0, 0, x, y, scaleX, scaleY); - src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); - canvas.drawMixed(t, color, ratio, mSrcRect, mDestRect); - } - } - } - - // Draws the texture on to the specified rectangle. - @Override - public void draw(GLCanvas canvas, int x, int y, int width, int height) { - RectF src = mSrcRect; - RectF dest = mDestRect; - float scaleX = (float) width / mWidth; - float scaleY = (float) height / mHeight; - synchronized (mTiles) { - for (int i = 0, n = mTiles.length; i < n; ++i) { - Tile t = mTiles[i]; - src.set(0, 0, t.contentWidth, t.contentHeight); - src.offset(t.offsetX, t.offsetY); - mapRect(dest, src, 0, 0, x, y, scaleX, scaleY); - src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); - canvas.drawTexture(t, mSrcRect, mDestRect); - } - } - } - - // Draws a sub region of this texture on to the specified rectangle. - public void draw(GLCanvas canvas, RectF source, RectF target) { - RectF src = mSrcRect; - RectF dest = mDestRect; - float x0 = source.left; - float y0 = source.top; - float x = target.left; - float y = target.top; - float scaleX = target.width() / source.width(); - float scaleY = target.height() / source.height(); - - synchronized (mTiles) { - for (int i = 0, n = mTiles.length; i < n; ++i) { - Tile t = mTiles[i]; - src.set(0, 0, t.contentWidth, t.contentHeight); - src.offset(t.offsetX, t.offsetY); - if (!src.intersect(source)) continue; - mapRect(dest, src, x0, y0, x, y, scaleX, scaleY); - src.offset(BORDER_SIZE - t.offsetX, BORDER_SIZE - t.offsetY); - canvas.drawTexture(t, src, dest); - } - } - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } - - @Override - public void draw(GLCanvas canvas, int x, int y) { - draw(canvas, x, y, mWidth, mHeight); - } - - @Override - public boolean isOpaque() { - return false; - } -} diff --git a/src/com/android/gallery3d/ui/UndoBarView.java b/src/com/android/gallery3d/ui/UndoBarView.java index 8c9836deb..42f12ae72 100644 --- a/src/com/android/gallery3d/ui/UndoBarView.java +++ b/src/com/android/gallery3d/ui/UndoBarView.java @@ -21,6 +21,10 @@ import android.view.MotionEvent; import com.android.gallery3d.R; import com.android.gallery3d.common.Utils; +import com.android.gallery3d.glrenderer.GLCanvas; +import com.android.gallery3d.glrenderer.NinePatchTexture; +import com.android.gallery3d.glrenderer.ResourceTexture; +import com.android.gallery3d.glrenderer.StringTexture; import com.android.gallery3d.util.GalleryUtils; public class UndoBarView extends GLView { diff --git a/src/com/android/gallery3d/ui/UploadedTexture.java b/src/com/android/gallery3d/ui/UploadedTexture.java deleted file mode 100644 index bb86d05ef..000000000 --- a/src/com/android/gallery3d/ui/UploadedTexture.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.opengl.GLUtils; - -import com.android.gallery3d.common.Utils; - -import java.util.HashMap; - -import javax.microedition.khronos.opengles.GL11; -import javax.microedition.khronos.opengles.GL11Ext; - -// UploadedTextures use a Bitmap for the content of the texture. -// -// Subclasses should implement onGetBitmap() to provide the Bitmap and -// implement onFreeBitmap(mBitmap) which will be called when the Bitmap -// is not needed anymore. -// -// isContentValid() is meaningful only when the isLoaded() returns true. -// It means whether the content needs to be updated. -// -// The user of this class should call recycle() when the texture is not -// needed anymore. -// -// By default an UploadedTexture is opaque (so it can be drawn faster without -// blending). The user or subclass can override it using setOpaque(). -abstract class UploadedTexture extends BasicTexture { - - // To prevent keeping allocation the borders, we store those used borders here. - // Since the length will be power of two, it won't use too much memory. - private static HashMap<BorderKey, Bitmap> sBorderLines = - new HashMap<BorderKey, Bitmap>(); - private static BorderKey sBorderKey = new BorderKey(); - - @SuppressWarnings("unused") - private static final String TAG = "Texture"; - private boolean mContentValid = true; - - // indicate this textures is being uploaded in background - private boolean mIsUploading = false; - private boolean mOpaque = true; - private boolean mThrottled = false; - private static int sUploadedCount; - private static final int UPLOAD_LIMIT = 100; - - protected Bitmap mBitmap; - private int mBorder; - - protected UploadedTexture() { - this(false); - } - - protected UploadedTexture(boolean hasBorder) { - super(null, 0, STATE_UNLOADED); - if (hasBorder) { - setBorder(true); - mBorder = 1; - } - } - - protected void setIsUploading(boolean uploading) { - mIsUploading = uploading; - } - - public boolean isUploading() { - return mIsUploading; - } - - private static class BorderKey implements Cloneable { - public boolean vertical; - public Config config; - public int length; - - @Override - public int hashCode() { - int x = config.hashCode() ^ length; - return vertical ? x : -x; - } - - @Override - public boolean equals(Object object) { - if (!(object instanceof BorderKey)) return false; - BorderKey o = (BorderKey) object; - return vertical == o.vertical - && config == o.config && length == o.length; - } - - @Override - public BorderKey clone() { - try { - return (BorderKey) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(e); - } - } - } - - protected void setThrottled(boolean throttled) { - mThrottled = throttled; - } - - private static Bitmap getBorderLine( - boolean vertical, Config config, int length) { - BorderKey key = sBorderKey; - key.vertical = vertical; - key.config = config; - key.length = length; - Bitmap bitmap = sBorderLines.get(key); - if (bitmap == null) { - bitmap = vertical - ? Bitmap.createBitmap(1, length, config) - : Bitmap.createBitmap(length, 1, config); - sBorderLines.put(key.clone(), bitmap); - } - return bitmap; - } - - private Bitmap getBitmap() { - if (mBitmap == null) { - mBitmap = onGetBitmap(); - int w = mBitmap.getWidth() + mBorder * 2; - int h = mBitmap.getHeight() + mBorder * 2; - if (mWidth == UNSPECIFIED) { - setSize(w, h); - } - } - return mBitmap; - } - - private void freeBitmap() { - Utils.assertTrue(mBitmap != null); - onFreeBitmap(mBitmap); - mBitmap = null; - } - - @Override - public int getWidth() { - if (mWidth == UNSPECIFIED) getBitmap(); - return mWidth; - } - - @Override - public int getHeight() { - if (mWidth == UNSPECIFIED) getBitmap(); - return mHeight; - } - - protected abstract Bitmap onGetBitmap(); - - protected abstract void onFreeBitmap(Bitmap bitmap); - - protected void invalidateContent() { - if (mBitmap != null) freeBitmap(); - mContentValid = false; - mWidth = UNSPECIFIED; - mHeight = UNSPECIFIED; - } - - /** - * Whether the content on GPU is valid. - */ - public boolean isContentValid() { - return isLoaded() && mContentValid; - } - - /** - * Updates the content on GPU's memory. - * @param canvas - */ - public void updateContent(GLCanvas canvas) { - if (!isLoaded()) { - if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) { - return; - } - uploadToCanvas(canvas); - } else if (!mContentValid) { - Bitmap bitmap = getBitmap(); - int format = GLUtils.getInternalFormat(bitmap); - int type = GLUtils.getType(bitmap); - canvas.getGLInstance().glBindTexture(GL11.GL_TEXTURE_2D, mId); - GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, mBorder, mBorder, - bitmap, format, type); - freeBitmap(); - mContentValid = true; - } - } - - public static void resetUploadLimit() { - sUploadedCount = 0; - } - - public static boolean uploadLimitReached() { - return sUploadedCount > UPLOAD_LIMIT; - } - - static int[] sTextureId = new int[1]; - static float[] sCropRect = new float[4]; - - private void uploadToCanvas(GLCanvas canvas) { - GL11 gl = canvas.getGLInstance(); - - Bitmap bitmap = getBitmap(); - if (bitmap != null) { - try { - int bWidth = bitmap.getWidth(); - int bHeight = bitmap.getHeight(); - int width = bWidth + mBorder * 2; - int height = bHeight + mBorder * 2; - int texWidth = getTextureWidth(); - int texHeight = getTextureHeight(); - - Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight); - - // Define a vertically flipped crop rectangle for - // OES_draw_texture. - // The four values in sCropRect are: left, bottom, width, and - // height. Negative value of width or height means flip. - sCropRect[0] = mBorder; - sCropRect[1] = mBorder + bHeight; - sCropRect[2] = bWidth; - sCropRect[3] = -bHeight; - - // Upload the bitmap to a new texture. - GLId.glGenTextures(1, sTextureId, 0); - gl.glBindTexture(GL11.GL_TEXTURE_2D, sTextureId[0]); - gl.glTexParameterfv(GL11.GL_TEXTURE_2D, - GL11Ext.GL_TEXTURE_CROP_RECT_OES, sCropRect, 0); - gl.glTexParameteri(GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); - gl.glTexParameteri(GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); - gl.glTexParameterf(GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); - gl.glTexParameterf(GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - - if (bWidth == texWidth && bHeight == texHeight) { - GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0); - } else { - int format = GLUtils.getInternalFormat(bitmap); - int type = GLUtils.getType(bitmap); - Config config = bitmap.getConfig(); - - gl.glTexImage2D(GL11.GL_TEXTURE_2D, 0, format, - texWidth, texHeight, 0, format, type, null); - GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, - mBorder, mBorder, bitmap, format, type); - - if (mBorder > 0) { - // Left border - Bitmap line = getBorderLine(true, config, texHeight); - GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, - 0, 0, line, format, type); - - // Top border - line = getBorderLine(false, config, texWidth); - GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, - 0, 0, line, format, type); - } - - // Right border - if (mBorder + bWidth < texWidth) { - Bitmap line = getBorderLine(true, config, texHeight); - GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, - mBorder + bWidth, 0, line, format, type); - } - - // Bottom border - if (mBorder + bHeight < texHeight) { - Bitmap line = getBorderLine(false, config, texWidth); - GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, - 0, mBorder + bHeight, line, format, type); - } - } - } finally { - freeBitmap(); - } - // Update texture state. - setAssociatedCanvas(canvas); - mId = sTextureId[0]; - mState = STATE_LOADED; - mContentValid = true; - } else { - mState = STATE_ERROR; - throw new RuntimeException("Texture load fail, no bitmap"); - } - } - - @Override - protected boolean onBind(GLCanvas canvas) { - updateContent(canvas); - return isContentValid(); - } - - @Override - protected int getTarget() { - return GL11.GL_TEXTURE_2D; - } - - public void setOpaque(boolean isOpaque) { - mOpaque = isOpaque; - } - - @Override - public boolean isOpaque() { - return mOpaque; - } - - @Override - public void recycle() { - super.recycle(); - if (mBitmap != null) freeBitmap(); - } -} |