Loading res/layout/photoeditor_flip_view.xml 0 → 100644 +20 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- 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. --> <com.android.gallery3d.photoeditor.actions.FlipView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fullscreen_effect_tool" style="@style/FullscreenToolView"/> src/com/android/gallery3d/photoeditor/PhotoView.java +24 −1 Original line number Diff line number Diff line Loading @@ -87,6 +87,13 @@ public class PhotoView extends GLSurfaceView { renderer.rotatePhoto(degrees); } /** * Flips displayed photo; this method must be queued for GL thread. */ public void flipPhoto(float horizontalDegrees, float verticalDegrees) { renderer.flipPhoto(horizontalDegrees, verticalDegrees); } /** * Renderer that renders the GL surface-view and only be called from the GL thread. */ Loading @@ -99,6 +106,8 @@ public class PhotoView extends GLSurfaceView { int viewWidth; int viewHeight; float rotatedDegrees; float flippedHorizontalDegrees; float flippedVerticalDegrees; void setPhoto(Photo photo, boolean clearTransform) { int width = (photo != null) ? photo.width() : 0; Loading @@ -115,18 +124,23 @@ public class PhotoView extends GLSurfaceView { } void updateSurface(boolean clearTransform, boolean sizeChanged) { boolean transformed = (rotatedDegrees != 0); boolean flipped = (flippedHorizontalDegrees != 0) || (flippedVerticalDegrees != 0); boolean transformed = (rotatedDegrees != 0) || flipped; if ((clearTransform && transformed) || (sizeChanged && !transformed)) { // Fit photo when clearing existing transforms or changing surface/photo sizes. if (photo != null) { RendererUtils.setRenderToFit(renderContext, photo.width(), photo.height(), viewWidth, viewHeight); rotatedDegrees = 0; flippedHorizontalDegrees = 0; flippedVerticalDegrees = 0; } } else { // Restore existing transformations for orientation changes or awaking from sleep. if (rotatedDegrees != 0) { rotatePhoto(rotatedDegrees); } else if (flipped) { flipPhoto(flippedHorizontalDegrees, flippedVerticalDegrees); } } } Loading @@ -139,6 +153,15 @@ public class PhotoView extends GLSurfaceView { } } void flipPhoto(float horizontalDegrees, float verticalDegrees) { if (photo != null) { RendererUtils.setRenderToFlip(renderContext, photo.width(), photo.height(), viewWidth, viewHeight, horizontalDegrees, verticalDegrees); flippedHorizontalDegrees = horizontalDegrees; flippedVerticalDegrees = verticalDegrees; } } @Override public void onDrawFrame(GL10 gl) { Runnable r = null; Loading src/com/android/gallery3d/photoeditor/RendererUtils.java +73 −6 Original line number Diff line number Diff line Loading @@ -121,13 +121,13 @@ public class RendererUtils { checkGlError("glDeleteTextures"); } public static void setRenderToFit(RenderContext context, int srcWidth, int srcHeight, int dstWidth, int dstHeight) { private static float[] getFitVertices(int srcWidth, int srcHeight, int dstWidth, int dstHeight) { float srcAspectRatio = ((float) srcWidth) / srcHeight; float dstAspectRatio = ((float) dstWidth) / dstHeight; float relativeAspectRatio = dstAspectRatio / srcAspectRatio; float vertices[] = new float[8]; float[] vertices = new float[8]; System.arraycopy(POS_VERTICES, 0, vertices, 0, vertices.length); if (relativeAspectRatio > 1.0f) { // Screen is wider than the camera, scale down X Loading @@ -141,13 +141,20 @@ public class RendererUtils { vertices[5] *= relativeAspectRatio; vertices[7] *= relativeAspectRatio; } context.posVertices = createVerticesBuffer(vertices); return vertices; } public static void setRenderToFit(RenderContext context, int srcWidth, int srcHeight, int dstWidth, int dstHeight) { context.posVertices = createVerticesBuffer( getFitVertices(srcWidth, srcHeight, dstWidth, dstHeight)); } public static void setRenderToRotate(RenderContext context, int srcWidth, int srcHeight, int dstWidth, int dstHeight, float degrees) { float cosTheta = (float) Math.cos(-degrees * DEGREE_TO_RADIAN); float sinTheta = (float) Math.sin(-degrees * DEGREE_TO_RADIAN); float radian = -degrees * DEGREE_TO_RADIAN; float cosTheta = (float) Math.cos(radian); float sinTheta = (float) Math.sin(radian); float cosWidth = cosTheta * srcWidth; float sinWidth = sinTheta * srcWidth; float cosHeight = cosTheta * srcHeight; Loading @@ -174,6 +181,66 @@ public class RendererUtils { context.posVertices = createVerticesBuffer(vertices); } public static void setRenderToFlip(RenderContext context, int srcWidth, int srcHeight, int dstWidth, int dstHeight, float horizontalDegrees, float verticalDegrees) { // Calculate the base flip coordinates. float[] base = getFitVertices(srcWidth, srcHeight, dstWidth, dstHeight); int horizontalRounds = (int) horizontalDegrees / 180; if (horizontalRounds % 2 != 0) { base[0] = -base[0]; base[4] = base[0]; base[2] = -base[2]; base[6] = base[2]; } int verticalRounds = (int) verticalDegrees / 180; if (verticalRounds % 2 != 0) { base[1] = -base[1]; base[3] = base[1]; base[5] = -base[5]; base[7] = base[5]; } float length = 5; float[] vertices = new float[8]; System.arraycopy(base, 0, vertices, 0, vertices.length); if (horizontalDegrees % 180f != 0) { float radian = (horizontalDegrees - horizontalRounds * 180) * DEGREE_TO_RADIAN; float cosTheta = (float) Math.cos(radian); float sinTheta = (float) Math.sin(radian); float scale = length / (length + sinTheta * base[0]); vertices[0] = cosTheta * base[0] * scale; vertices[1] = base[1] * scale; vertices[4] = vertices[0]; vertices[5] = base[5] * scale; scale = length / (length + sinTheta * base[2]); vertices[2] = cosTheta * base[2] * scale; vertices[3] = base[3] * scale; vertices[6] = vertices[2]; vertices[7] = base[7] * scale; } if (verticalDegrees % 180f != 0) { float radian = (verticalDegrees - verticalRounds * 180) * DEGREE_TO_RADIAN; float cosTheta = (float) Math.cos(radian); float sinTheta = (float) Math.sin(radian); float scale = length / (length + sinTheta * base[1]); vertices[0] = base[0] * scale; vertices[1] = cosTheta * base[1] * scale; vertices[2] = base[2] * scale; vertices[3] = vertices[1]; scale = length / (length + sinTheta * base[5]); vertices[4] = base[4] * scale; vertices[5] = cosTheta * base[5] * scale; vertices[6] = base[6] * scale; vertices[7] = vertices[5]; } context.posVertices = createVerticesBuffer(vertices); } public static void renderBackground() { GLES20.glClearColor(0, 0, 0, 1); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); Loading src/com/android/gallery3d/photoeditor/actions/EffectToolFactory.java +4 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,10 @@ public class EffectToolFactory { return (TouchView) createFullscreenTool(R.layout.photoeditor_touch_view); } public FlipView createFlipView() { return (FlipView) createFullscreenTool(R.layout.photoeditor_flip_view); } public RotateView createRotateView() { return (RotateView) createFullscreenTool(R.layout.photoeditor_rotate_view); } Loading src/com/android/gallery3d/photoeditor/actions/FlipAction.java +70 −28 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.gallery3d.photoeditor.actions; import android.content.Context; import android.util.AttributeSet; import com.android.gallery3d.R; import com.android.gallery3d.photoeditor.PhotoView; import com.android.gallery3d.photoeditor.filters.FlipFilter; /** Loading @@ -26,9 +28,14 @@ import com.android.gallery3d.photoeditor.filters.FlipFilter; */ public class FlipAction extends EffectAction { private boolean flipHorizontal; private boolean flipVertical; private TouchView touchView; private static final float DEFAULT_ANGLE = 0.0f; private static final float DEFAULT_FLIP_SPAN = 180.0f; private FlipFilter filter; private float horizontalFlipDegrees; private float verticalFlipDegrees; private Runnable queuedFlipChange; private FlipView flipView; public FlipAction(Context context, AttributeSet attrs) { super(context, attrs); Loading @@ -36,51 +43,86 @@ public class FlipAction extends EffectAction { @Override public void doBegin() { final FlipFilter filter = new FlipFilter(); filter = new FlipFilter(); flipView = factory.createFlipView(); flipView.setOnFlipChangeListener(new FlipView.OnFlipChangeListener() { touchView = factory.createTouchView(); touchView.setSwipeListener(new TouchView.SwipeListener() { // Directly transform photo-view because running the flip filter isn't fast enough. PhotoView photoView = (PhotoView) flipView.getRootView().findViewById( R.id.photo_view); @Override public void onSwipeDown() { flipFilterVertically(filter); public void onAngleChanged(float horizontalDegrees, float verticalDegrees, boolean fromUser) { if (fromUser) { horizontalFlipDegrees = horizontalDegrees; verticalFlipDegrees = verticalDegrees; updateFlipFilter(false); transformPhotoView(horizontalDegrees, verticalDegrees); } } @Override public void onSwipeLeft() { flipFilterHorizontally(filter); public void onStartTrackingTouch() { // no-op } @Override public void onSwipeRight() { flipFilterHorizontally(filter); public void onStopTrackingTouch() { roundFlipDegrees(); updateFlipFilter(false); transformPhotoView(horizontalFlipDegrees, verticalFlipDegrees); flipView.setFlippedAngles(horizontalFlipDegrees, verticalFlipDegrees); } private void transformPhotoView(final float horizontalDegrees, final float verticalDegrees) { // Remove the outdated flip change before queuing a new one. if (queuedFlipChange != null) { photoView.remove(queuedFlipChange); } queuedFlipChange = new Runnable() { @Override public void onSwipeUp() { flipFilterVertically(filter); public void run() { photoView.flipPhoto(horizontalDegrees, verticalDegrees); } }; photoView.queue(queuedFlipChange); } }); flipHorizontal = false; flipVertical = false; flipFilterHorizontally(filter); flipView.setFlippedAngles(DEFAULT_ANGLE, DEFAULT_ANGLE); flipView.setFlipSpan(DEFAULT_FLIP_SPAN); horizontalFlipDegrees = 0; verticalFlipDegrees = 0; queuedFlipChange = null; } @Override public void doEnd() { touchView.setSwipeListener(null); flipView.setOnFlipChangeListener(null); // Round the current flip degrees in case flip tracking has not stopped yet. roundFlipDegrees(); updateFlipFilter(true); } private void flipFilterHorizontally(final FlipFilter filter) { flipHorizontal = !flipHorizontal; filter.setFlip(flipHorizontal, flipVertical); notifyFilterChanged(filter, true); /** * Rounds flip degrees to multiples of 180 degrees. */ private void roundFlipDegrees() { if (horizontalFlipDegrees % 180 != 0) { horizontalFlipDegrees = Math.round(horizontalFlipDegrees / 180) * 180; } if (verticalFlipDegrees % 180 != 0) { verticalFlipDegrees = Math.round(verticalFlipDegrees / 180) * 180; } } private void flipFilterVertically(final FlipFilter filter) { flipVertical = !flipVertical; filter.setFlip(flipHorizontal, flipVertical); notifyFilterChanged(filter, true); private void updateFlipFilter(boolean outputFilter) { // Flip the filter if the flipped degrees are at the opposite directions. filter.setFlip(((int) horizontalFlipDegrees / 180) % 2 != 0, ((int) verticalFlipDegrees / 180) % 2 != 0); notifyFilterChanged(filter, outputFilter); } } Loading
res/layout/photoeditor_flip_view.xml 0 → 100644 +20 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- 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. --> <com.android.gallery3d.photoeditor.actions.FlipView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fullscreen_effect_tool" style="@style/FullscreenToolView"/>
src/com/android/gallery3d/photoeditor/PhotoView.java +24 −1 Original line number Diff line number Diff line Loading @@ -87,6 +87,13 @@ public class PhotoView extends GLSurfaceView { renderer.rotatePhoto(degrees); } /** * Flips displayed photo; this method must be queued for GL thread. */ public void flipPhoto(float horizontalDegrees, float verticalDegrees) { renderer.flipPhoto(horizontalDegrees, verticalDegrees); } /** * Renderer that renders the GL surface-view and only be called from the GL thread. */ Loading @@ -99,6 +106,8 @@ public class PhotoView extends GLSurfaceView { int viewWidth; int viewHeight; float rotatedDegrees; float flippedHorizontalDegrees; float flippedVerticalDegrees; void setPhoto(Photo photo, boolean clearTransform) { int width = (photo != null) ? photo.width() : 0; Loading @@ -115,18 +124,23 @@ public class PhotoView extends GLSurfaceView { } void updateSurface(boolean clearTransform, boolean sizeChanged) { boolean transformed = (rotatedDegrees != 0); boolean flipped = (flippedHorizontalDegrees != 0) || (flippedVerticalDegrees != 0); boolean transformed = (rotatedDegrees != 0) || flipped; if ((clearTransform && transformed) || (sizeChanged && !transformed)) { // Fit photo when clearing existing transforms or changing surface/photo sizes. if (photo != null) { RendererUtils.setRenderToFit(renderContext, photo.width(), photo.height(), viewWidth, viewHeight); rotatedDegrees = 0; flippedHorizontalDegrees = 0; flippedVerticalDegrees = 0; } } else { // Restore existing transformations for orientation changes or awaking from sleep. if (rotatedDegrees != 0) { rotatePhoto(rotatedDegrees); } else if (flipped) { flipPhoto(flippedHorizontalDegrees, flippedVerticalDegrees); } } } Loading @@ -139,6 +153,15 @@ public class PhotoView extends GLSurfaceView { } } void flipPhoto(float horizontalDegrees, float verticalDegrees) { if (photo != null) { RendererUtils.setRenderToFlip(renderContext, photo.width(), photo.height(), viewWidth, viewHeight, horizontalDegrees, verticalDegrees); flippedHorizontalDegrees = horizontalDegrees; flippedVerticalDegrees = verticalDegrees; } } @Override public void onDrawFrame(GL10 gl) { Runnable r = null; Loading
src/com/android/gallery3d/photoeditor/RendererUtils.java +73 −6 Original line number Diff line number Diff line Loading @@ -121,13 +121,13 @@ public class RendererUtils { checkGlError("glDeleteTextures"); } public static void setRenderToFit(RenderContext context, int srcWidth, int srcHeight, int dstWidth, int dstHeight) { private static float[] getFitVertices(int srcWidth, int srcHeight, int dstWidth, int dstHeight) { float srcAspectRatio = ((float) srcWidth) / srcHeight; float dstAspectRatio = ((float) dstWidth) / dstHeight; float relativeAspectRatio = dstAspectRatio / srcAspectRatio; float vertices[] = new float[8]; float[] vertices = new float[8]; System.arraycopy(POS_VERTICES, 0, vertices, 0, vertices.length); if (relativeAspectRatio > 1.0f) { // Screen is wider than the camera, scale down X Loading @@ -141,13 +141,20 @@ public class RendererUtils { vertices[5] *= relativeAspectRatio; vertices[7] *= relativeAspectRatio; } context.posVertices = createVerticesBuffer(vertices); return vertices; } public static void setRenderToFit(RenderContext context, int srcWidth, int srcHeight, int dstWidth, int dstHeight) { context.posVertices = createVerticesBuffer( getFitVertices(srcWidth, srcHeight, dstWidth, dstHeight)); } public static void setRenderToRotate(RenderContext context, int srcWidth, int srcHeight, int dstWidth, int dstHeight, float degrees) { float cosTheta = (float) Math.cos(-degrees * DEGREE_TO_RADIAN); float sinTheta = (float) Math.sin(-degrees * DEGREE_TO_RADIAN); float radian = -degrees * DEGREE_TO_RADIAN; float cosTheta = (float) Math.cos(radian); float sinTheta = (float) Math.sin(radian); float cosWidth = cosTheta * srcWidth; float sinWidth = sinTheta * srcWidth; float cosHeight = cosTheta * srcHeight; Loading @@ -174,6 +181,66 @@ public class RendererUtils { context.posVertices = createVerticesBuffer(vertices); } public static void setRenderToFlip(RenderContext context, int srcWidth, int srcHeight, int dstWidth, int dstHeight, float horizontalDegrees, float verticalDegrees) { // Calculate the base flip coordinates. float[] base = getFitVertices(srcWidth, srcHeight, dstWidth, dstHeight); int horizontalRounds = (int) horizontalDegrees / 180; if (horizontalRounds % 2 != 0) { base[0] = -base[0]; base[4] = base[0]; base[2] = -base[2]; base[6] = base[2]; } int verticalRounds = (int) verticalDegrees / 180; if (verticalRounds % 2 != 0) { base[1] = -base[1]; base[3] = base[1]; base[5] = -base[5]; base[7] = base[5]; } float length = 5; float[] vertices = new float[8]; System.arraycopy(base, 0, vertices, 0, vertices.length); if (horizontalDegrees % 180f != 0) { float radian = (horizontalDegrees - horizontalRounds * 180) * DEGREE_TO_RADIAN; float cosTheta = (float) Math.cos(radian); float sinTheta = (float) Math.sin(radian); float scale = length / (length + sinTheta * base[0]); vertices[0] = cosTheta * base[0] * scale; vertices[1] = base[1] * scale; vertices[4] = vertices[0]; vertices[5] = base[5] * scale; scale = length / (length + sinTheta * base[2]); vertices[2] = cosTheta * base[2] * scale; vertices[3] = base[3] * scale; vertices[6] = vertices[2]; vertices[7] = base[7] * scale; } if (verticalDegrees % 180f != 0) { float radian = (verticalDegrees - verticalRounds * 180) * DEGREE_TO_RADIAN; float cosTheta = (float) Math.cos(radian); float sinTheta = (float) Math.sin(radian); float scale = length / (length + sinTheta * base[1]); vertices[0] = base[0] * scale; vertices[1] = cosTheta * base[1] * scale; vertices[2] = base[2] * scale; vertices[3] = vertices[1]; scale = length / (length + sinTheta * base[5]); vertices[4] = base[4] * scale; vertices[5] = cosTheta * base[5] * scale; vertices[6] = base[6] * scale; vertices[7] = vertices[5]; } context.posVertices = createVerticesBuffer(vertices); } public static void renderBackground() { GLES20.glClearColor(0, 0, 0, 1); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); Loading
src/com/android/gallery3d/photoeditor/actions/EffectToolFactory.java +4 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,10 @@ public class EffectToolFactory { return (TouchView) createFullscreenTool(R.layout.photoeditor_touch_view); } public FlipView createFlipView() { return (FlipView) createFullscreenTool(R.layout.photoeditor_flip_view); } public RotateView createRotateView() { return (RotateView) createFullscreenTool(R.layout.photoeditor_rotate_view); } Loading
src/com/android/gallery3d/photoeditor/actions/FlipAction.java +70 −28 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.gallery3d.photoeditor.actions; import android.content.Context; import android.util.AttributeSet; import com.android.gallery3d.R; import com.android.gallery3d.photoeditor.PhotoView; import com.android.gallery3d.photoeditor.filters.FlipFilter; /** Loading @@ -26,9 +28,14 @@ import com.android.gallery3d.photoeditor.filters.FlipFilter; */ public class FlipAction extends EffectAction { private boolean flipHorizontal; private boolean flipVertical; private TouchView touchView; private static final float DEFAULT_ANGLE = 0.0f; private static final float DEFAULT_FLIP_SPAN = 180.0f; private FlipFilter filter; private float horizontalFlipDegrees; private float verticalFlipDegrees; private Runnable queuedFlipChange; private FlipView flipView; public FlipAction(Context context, AttributeSet attrs) { super(context, attrs); Loading @@ -36,51 +43,86 @@ public class FlipAction extends EffectAction { @Override public void doBegin() { final FlipFilter filter = new FlipFilter(); filter = new FlipFilter(); flipView = factory.createFlipView(); flipView.setOnFlipChangeListener(new FlipView.OnFlipChangeListener() { touchView = factory.createTouchView(); touchView.setSwipeListener(new TouchView.SwipeListener() { // Directly transform photo-view because running the flip filter isn't fast enough. PhotoView photoView = (PhotoView) flipView.getRootView().findViewById( R.id.photo_view); @Override public void onSwipeDown() { flipFilterVertically(filter); public void onAngleChanged(float horizontalDegrees, float verticalDegrees, boolean fromUser) { if (fromUser) { horizontalFlipDegrees = horizontalDegrees; verticalFlipDegrees = verticalDegrees; updateFlipFilter(false); transformPhotoView(horizontalDegrees, verticalDegrees); } } @Override public void onSwipeLeft() { flipFilterHorizontally(filter); public void onStartTrackingTouch() { // no-op } @Override public void onSwipeRight() { flipFilterHorizontally(filter); public void onStopTrackingTouch() { roundFlipDegrees(); updateFlipFilter(false); transformPhotoView(horizontalFlipDegrees, verticalFlipDegrees); flipView.setFlippedAngles(horizontalFlipDegrees, verticalFlipDegrees); } private void transformPhotoView(final float horizontalDegrees, final float verticalDegrees) { // Remove the outdated flip change before queuing a new one. if (queuedFlipChange != null) { photoView.remove(queuedFlipChange); } queuedFlipChange = new Runnable() { @Override public void onSwipeUp() { flipFilterVertically(filter); public void run() { photoView.flipPhoto(horizontalDegrees, verticalDegrees); } }; photoView.queue(queuedFlipChange); } }); flipHorizontal = false; flipVertical = false; flipFilterHorizontally(filter); flipView.setFlippedAngles(DEFAULT_ANGLE, DEFAULT_ANGLE); flipView.setFlipSpan(DEFAULT_FLIP_SPAN); horizontalFlipDegrees = 0; verticalFlipDegrees = 0; queuedFlipChange = null; } @Override public void doEnd() { touchView.setSwipeListener(null); flipView.setOnFlipChangeListener(null); // Round the current flip degrees in case flip tracking has not stopped yet. roundFlipDegrees(); updateFlipFilter(true); } private void flipFilterHorizontally(final FlipFilter filter) { flipHorizontal = !flipHorizontal; filter.setFlip(flipHorizontal, flipVertical); notifyFilterChanged(filter, true); /** * Rounds flip degrees to multiples of 180 degrees. */ private void roundFlipDegrees() { if (horizontalFlipDegrees % 180 != 0) { horizontalFlipDegrees = Math.round(horizontalFlipDegrees / 180) * 180; } if (verticalFlipDegrees % 180 != 0) { verticalFlipDegrees = Math.round(verticalFlipDegrees / 180) * 180; } } private void flipFilterVertically(final FlipFilter filter) { flipVertical = !flipVertical; filter.setFlip(flipHorizontal, flipVertical); notifyFilterChanged(filter, true); private void updateFlipFilter(boolean outputFilter) { // Flip the filter if the flipped degrees are at the opposite directions. filter.setFlip(((int) horizontalFlipDegrees / 180) % 2 != 0, ((int) verticalFlipDegrees / 180) % 2 != 0); notifyFilterChanged(filter, outputFilter); } }