diff --git a/app/build.gradle b/app/build.gradle index a38993d15..cc4248213 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,6 +66,8 @@ dependencies { compile 'com.github.seven332:conaco:0.1.5-eh' compile 'com.github.seven332:drawerlayout:0.1.0' compile 'com.github.seven332:easyrecyclerview:0.1.0' + compile 'com.github.seven332:glview:0.1.0' + compile 'com.github.seven332:glview-image:0.1.0' compile 'com.github.seven332:hotspot:0.1.0' compile 'com.github.seven332:image:0.1.8-jpeg-png-gif' compile 'com.github.seven332:okhttp:3.2.0-eh' @@ -74,7 +76,7 @@ dependencies { compile 'com.github.seven332:streampipe:0.1.0' compile 'com.github.seven332:tuxiang:0.1.2' compile 'com.github.seven332:unifile:0.1.3' - compile 'com.github.seven332:yorozuya:0.1.1' + compile 'com.github.seven332:yorozuya:0.1.2' compile 'com.github.seven332:yorozuya-thread:0.1.1' compile 'com.github.seven332:yorozuya-collect:0.1.4' compile 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.8.7' diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/GalleryProvider.java b/app/src/main/java/com/hippo/ehviewer/gallery/GalleryProvider.java index 1b4c466d2..9d3886159 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/GalleryProvider.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/GalleryProvider.java @@ -22,9 +22,9 @@ import android.support.annotation.Nullable; import android.support.annotation.UiThread; import com.hippo.beerbelly.LruCache; -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.glrenderer.ImageWrapper; -import com.hippo.gl.view.GLRoot; +import com.hippo.glview.glrenderer.GLCanvas; +import com.hippo.glview.image.ImageWrapper; +import com.hippo.glview.view.GLRoot; import com.hippo.image.Image; import com.hippo.unifile.UniFile; import com.hippo.yorozuya.ConcurrentPool; diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/GalleryProviderListener.java b/app/src/main/java/com/hippo/ehviewer/gallery/GalleryProviderListener.java index d6b3a1244..72cf98732 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/GalleryProviderListener.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/GalleryProviderListener.java @@ -16,7 +16,7 @@ package com.hippo.ehviewer.gallery; -import com.hippo.gl.glrenderer.ImageWrapper; +import com.hippo.glview.image.ImageWrapper; public interface GalleryProviderListener { diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/gl/Fling.java b/app/src/main/java/com/hippo/ehviewer/gallery/gl/Fling.java index e39459af1..6549b0dae 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/gl/Fling.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/gl/Fling.java @@ -21,7 +21,7 @@ import android.hardware.SensorManager; import android.view.ViewConfiguration; import android.view.animation.Interpolator; -import com.hippo.gl.anim.Animation; +import com.hippo.glview.anim.Animation; public abstract class Fling extends Animation { diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/gl/GalleryPageView.java b/app/src/main/java/com/hippo/ehviewer/gallery/gl/GalleryPageView.java index ac20b6471..d1bf9bf78 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/gl/GalleryPageView.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/gl/GalleryPageView.java @@ -18,16 +18,17 @@ package com.hippo.ehviewer.gallery.gl; import android.content.Context; -import com.hippo.gl.glrenderer.BasicTexture; -import com.hippo.gl.glrenderer.ImageMovableTextTexture; -import com.hippo.gl.glrenderer.ImageTexture; -import com.hippo.gl.glrenderer.Texture; -import com.hippo.gl.view.Gravity; -import com.hippo.gl.widget.GLFrameLayout; -import com.hippo.gl.widget.GLLinearLayout; -import com.hippo.gl.widget.GLMovableTextView; -import com.hippo.gl.widget.GLProgressView; -import com.hippo.gl.widget.GLTextureView; +import com.hippo.glview.glrenderer.BasicTexture; +import com.hippo.glview.glrenderer.Texture; +import com.hippo.glview.image.GLImageMovableTextView; +import com.hippo.glview.image.ImageMovableTextTexture; +import com.hippo.glview.image.ImageTexture; +import com.hippo.glview.view.Gravity; +import com.hippo.glview.widget.GLFrameLayout; +import com.hippo.glview.widget.GLLinearLayout; +import com.hippo.glview.widget.GLMovableTextView; +import com.hippo.glview.widget.GLProgressView; +import com.hippo.glview.widget.GLTextureView; import com.hippo.yorozuya.LayoutUtils; public class GalleryPageView extends GLFrameLayout { @@ -41,7 +42,7 @@ public class GalleryPageView extends GLFrameLayout { private final ImageView mImage; private final GLLinearLayout mInfo; - private final GLMovableTextView mPage; + private final GLImageMovableTextView mPage; private final GLTextureView mError; private final GLProgressView mProgress; @@ -67,7 +68,7 @@ public class GalleryPageView extends GLFrameLayout { addComponent(mInfo, glp); // Add page - mPage = new GLMovableTextView(); + mPage = new GLImageMovableTextView(); mPage.setTextTexture(pageTextTexture); GLLinearLayout.LayoutParams lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/gl/GalleryView.java b/app/src/main/java/com/hippo/ehviewer/gallery/gl/GalleryView.java index abc0454af..5f22140a8 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/gl/GalleryView.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/gl/GalleryView.java @@ -25,19 +25,19 @@ import android.support.annotation.Nullable; import android.view.MotionEvent; import com.hippo.ehviewer.R; -import com.hippo.gl.annotation.RenderThread; -import com.hippo.gl.glrenderer.BasicTexture; -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.glrenderer.ImageMovableTextTexture; -import com.hippo.gl.glrenderer.StringTexture; -import com.hippo.gl.glrenderer.Texture; -import com.hippo.gl.util.GalleryUtils; -import com.hippo.gl.view.AnimationTime; -import com.hippo.gl.view.GLRoot; -import com.hippo.gl.view.GLView; -import com.hippo.gl.widget.GLEdgeView; -import com.hippo.gl.widget.GLProgressView; -import com.hippo.gl.widget.GLTextureView; +import com.hippo.glview.annotation.RenderThread; +import com.hippo.glview.glrenderer.BasicTexture; +import com.hippo.glview.glrenderer.GLCanvas; +import com.hippo.glview.glrenderer.StringTexture; +import com.hippo.glview.glrenderer.Texture; +import com.hippo.glview.image.ImageMovableTextTexture; +import com.hippo.glview.util.GalleryUtils; +import com.hippo.glview.view.AnimationTime; +import com.hippo.glview.view.GLRoot; +import com.hippo.glview.view.GLView; +import com.hippo.glview.widget.GLEdgeView; +import com.hippo.glview.widget.GLProgressView; +import com.hippo.glview.widget.GLTextureView; import com.hippo.yorozuya.LayoutUtils; import com.hippo.yorozuya.MathUtils; import com.hippo.yorozuya.Pool; @@ -149,7 +149,9 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener { mContext = context; mAdapter = adapter; mListener = listener; - mEdgeView = new GLEdgeView(context); + final int themeColor = ResourcesUtils.getAttrColor(context, R.attr.colorPrimary); + final int edgeColor = (themeColor & 0xffffff) | 0x33000000; + mEdgeView = new GLEdgeView(edgeColor); mGestureRecognizer = new GestureRecognizer(context, this); adapter.setGalleryView(this); diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/gl/ImageView.java b/app/src/main/java/com/hippo/ehviewer/gallery/gl/ImageView.java index f22a6dd08..a00569d61 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/gl/ImageView.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/gl/ImageView.java @@ -20,11 +20,11 @@ import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.IntDef; -import com.hippo.gl.anim.AlphaAnimation; -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.glrenderer.ImageTexture; -import com.hippo.gl.glrenderer.Texture; -import com.hippo.gl.view.GLView; +import com.hippo.glview.anim.AlphaAnimation; +import com.hippo.glview.glrenderer.GLCanvas; +import com.hippo.glview.glrenderer.Texture; +import com.hippo.glview.image.ImageTexture; +import com.hippo.glview.view.GLView; import com.hippo.yorozuya.AnimationUtils; import com.hippo.yorozuya.MathUtils; diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/gl/PagerLayoutManager.java b/app/src/main/java/com/hippo/ehviewer/gallery/gl/PagerLayoutManager.java index d870bf016..68b4cd5fc 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/gl/PagerLayoutManager.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/gl/PagerLayoutManager.java @@ -24,11 +24,11 @@ import android.util.Log; import android.view.animation.Interpolator; import com.hippo.ehviewer.gallery.GalleryProvider; -import com.hippo.gl.anim.Animation; -import com.hippo.gl.view.GLView; -import com.hippo.gl.widget.GLEdgeView; -import com.hippo.gl.widget.GLProgressView; -import com.hippo.gl.widget.GLTextureView; +import com.hippo.glview.anim.Animation; +import com.hippo.glview.view.GLView; +import com.hippo.glview.widget.GLEdgeView; +import com.hippo.glview.widget.GLProgressView; +import com.hippo.glview.widget.GLTextureView; import com.hippo.yorozuya.AnimationUtils; import com.hippo.yorozuya.AssertUtils; import com.hippo.yorozuya.LayoutUtils; diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/gl/ScrollLayoutManager.java b/app/src/main/java/com/hippo/ehviewer/gallery/gl/ScrollLayoutManager.java index c844f2e15..345f4fe27 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/gl/ScrollLayoutManager.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/gl/ScrollLayoutManager.java @@ -22,11 +22,11 @@ import android.support.annotation.NonNull; import android.util.Log; import com.hippo.ehviewer.gallery.GalleryProvider; -import com.hippo.gl.anim.Animation; -import com.hippo.gl.view.GLView; -import com.hippo.gl.widget.GLEdgeView; -import com.hippo.gl.widget.GLProgressView; -import com.hippo.gl.widget.GLTextureView; +import com.hippo.glview.anim.Animation; +import com.hippo.glview.view.GLView; +import com.hippo.glview.widget.GLEdgeView; +import com.hippo.glview.widget.GLProgressView; +import com.hippo.glview.widget.GLTextureView; import com.hippo.yorozuya.AnimationUtils; import com.hippo.yorozuya.AssertUtils; import com.hippo.yorozuya.LayoutUtils; diff --git a/app/src/main/java/com/hippo/ehviewer/ui/GalleryActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/GalleryActivity.java index a502f823e..bf9d3b271 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/GalleryActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/GalleryActivity.java @@ -60,9 +60,9 @@ import com.hippo.ehviewer.gallery.gl.GalleryView; import com.hippo.ehviewer.gallery.gl.ImageView; import com.hippo.ehviewer.widget.GalleryGuideView; import com.hippo.ehviewer.widget.ReversibleSeekBar; -import com.hippo.gl.glrenderer.ImageTexture; -import com.hippo.gl.glrenderer.ImageWrapper; -import com.hippo.gl.view.GLRootView; +import com.hippo.glview.image.ImageTexture; +import com.hippo.glview.image.ImageWrapper; +import com.hippo.glview.view.GLRootView; import com.hippo.unifile.UniFile; import com.hippo.util.SystemUiHelper; import com.hippo.widget.ColorView; diff --git a/app/src/main/java/com/hippo/gl/anim/AlphaAnimation.java b/app/src/main/java/com/hippo/gl/anim/AlphaAnimation.java deleted file mode 100644 index a033a173b..000000000 --- a/app/src/main/java/com/hippo/gl/anim/AlphaAnimation.java +++ /dev/null @@ -1,48 +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.hippo.gl.anim; - -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.yorozuya.MathUtils; - -public class AlphaAnimation extends CanvasAnimation { - private final float mStartAlpha; - private final float mEndAlpha; - private float mCurrentAlpha; - - public AlphaAnimation(float from, float to) { - mStartAlpha = from; - mEndAlpha = to; - mCurrentAlpha = from; - } - - @Override - public void apply(GLCanvas canvas) { - canvas.multiplyAlpha(mCurrentAlpha); - } - - @Override - public int getCanvasSaveFlags() { - return GLCanvas.SAVE_FLAG_ALPHA; - } - - @Override - protected void onCalculate(float progress) { - mCurrentAlpha = MathUtils.clamp(mStartAlpha + - (mEndAlpha - mStartAlpha) * progress, 0f, 1f); - } -} diff --git a/app/src/main/java/com/hippo/gl/anim/Animation.java b/app/src/main/java/com/hippo/gl/anim/Animation.java deleted file mode 100644 index 896ea59b2..000000000 --- a/app/src/main/java/com/hippo/gl/anim/Animation.java +++ /dev/null @@ -1,167 +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.hippo.gl.anim; - -import android.os.SystemClock; -import android.view.animation.Interpolator; - -import com.hippo.yorozuya.MathUtils; - -// Animation calculates a value according to the current input time. -// -// 1. First we need to use setDuration(int) to set the duration of the -// animation. The duration is in milliseconds. -// 2. Then we should call start(). The actual start time is the first value -// passed to calculate(long). -// 3. Each time we want to get an animation value, we call -// calculate(long currentTimeMillis) to ask the Animation to calculate it. -// The parameter passed to calculate(long) should be nonnegative. -// 4. Use get() to get that value. -// -// In step 3, onCalculate(float progress) is called so subclasses can calculate -// the value according to progress (progress is a value in [0,1]). -// -// Before onCalculate(float) is called, There is an optional interpolator which -// can change the progress value. The interpolator can be set by -// setInterpolator(Interpolator). If the interpolator is used, the value passed -// to onCalculate may be (for example, the overshoot effect). -// -// The isActive() method returns true after the animation start() is called and -// before calculate is passed a value which reaches the duration of the -// animation. -// -// The start() method can be called again to restart the Animation. -// -abstract public class Animation { - private static final long ANIMATION_START = -1; - private static final long NO_ANIMATION = -2; - - /** - * When the animation reaches the end and repeatCount is INFINITE - * or a positive value, the animation restarts from the beginning. - */ - public static final int RESTART = 1; - /** - * When the animation reaches the end and repeatCount is INFINITE - * or a positive value, the animation reverses direction on every iteration. - */ - public static final int REVERSE = 2; - /** - * This value used used with the {@link #setRepeatCount(int)} property to repeat - * the animation indefinitely. - */ - public static final int INFINITE = -1; - - private long mStartTime = NO_ANIMATION; - private long mDuration; - private Interpolator mInterpolator; - private int mRepeatCount; - private int mRepeatMode; - - private int mRunnedCount; - private long mLastFrameTime; - - public void setInterpolator(Interpolator interpolator) { - mInterpolator = interpolator; - } - - public void setDuration(long duration) { - mDuration = duration; - } - - public void setRepeatCount(int repeatCount) { - mRepeatCount = repeatCount; - } - - public void setRepeatMode(int repeatMode) { - mRepeatMode = repeatMode; - } - - public boolean isRunning() { - return mStartTime > 0 || mStartTime == ANIMATION_START; - } - - public long getLastFrameTime() { - return mLastFrameTime; - } - - public void start() { - if (mStartTime == NO_ANIMATION) { - mStartTime = ANIMATION_START; - mRunnedCount = 0; - mLastFrameTime = 0; - } - } - - public void startAt(long time) { - start(); - setStartTime(time); - } - - public void startNow() { - start(); - setStartTime(SystemClock.uptimeMillis()); - } - - public void setStartTime(long time) { - mStartTime = time; - } - - public void cancel() { - mStartTime = NO_ANIMATION; - } - - public void reset() { - mStartTime = ANIMATION_START; - mRunnedCount = 0; - mLastFrameTime = 0; - } - - // TODO mRepeatMode - public boolean calculate(long currentTimeMillis) { - if (mStartTime == NO_ANIMATION) { - return false; - } - if (mStartTime == ANIMATION_START) { - mStartTime = currentTimeMillis; - } - mLastFrameTime = currentTimeMillis; - - long elapse = currentTimeMillis - mStartTime; - float x = MathUtils.clamp(mDuration == 0.0f ? 1.0f : (float) elapse / mDuration, 0.0f, 1.0f); // Avoid NaN - Interpolator i = mInterpolator; - onCalculate(i != null ? i.getInterpolation(x) : x); - - // It is ok to call cancel() in onCalculate() - if (mStartTime != NO_ANIMATION && elapse >= mDuration) { - mRunnedCount++; - if (mRunnedCount >= mRepeatCount && mRepeatCount != INFINITE) { - onFinish(); - mStartTime = NO_ANIMATION; - } else { - mStartTime += elapse; - } - } - - return mStartTime != NO_ANIMATION; - } - - abstract protected void onCalculate(float progress); - - protected void onFinish() { - } -} diff --git a/app/src/main/java/com/hippo/gl/anim/CanvasAnimation.java b/app/src/main/java/com/hippo/gl/anim/CanvasAnimation.java deleted file mode 100644 index 74f1b4570..000000000 --- a/app/src/main/java/com/hippo/gl/anim/CanvasAnimation.java +++ /dev/null @@ -1,25 +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.hippo.gl.anim; - -import com.hippo.gl.glrenderer.GLCanvas; - -public abstract class CanvasAnimation extends Animation { - - public abstract int getCanvasSaveFlags(); - public abstract void apply(GLCanvas canvas); -} diff --git a/app/src/main/java/com/hippo/gl/anim/FloatAnimation.java b/app/src/main/java/com/hippo/gl/anim/FloatAnimation.java deleted file mode 100644 index c2908e09b..000000000 --- a/app/src/main/java/com/hippo/gl/anim/FloatAnimation.java +++ /dev/null @@ -1,40 +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.hippo.gl.anim; - -import com.hippo.yorozuya.MathUtils; - -public class FloatAnimation extends Animation { - - private float mFrom; - private float mTo; - private float mCurrent; - - public void setRange(float from, float to) { - mFrom = from; - mTo = to; - } - - @Override - protected void onCalculate(float progress) { - mCurrent = MathUtils.lerp(mFrom, mTo, progress); - } - - public float get() { - return mCurrent; - } -} diff --git a/app/src/main/java/com/hippo/gl/annotation/RenderThread.java b/app/src/main/java/com/hippo/gl/annotation/RenderThread.java deleted file mode 100644 index 344d7a67e..000000000 --- a/app/src/main/java/com/hippo/gl/annotation/RenderThread.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.SOURCE) -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE}) -public @interface RenderThread { -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/BasicTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/BasicTexture.java deleted file mode 100644 index 9a8da6c40..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/BasicTexture.java +++ /dev/null @@ -1,222 +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.hippo.gl.glrenderer; - -import android.graphics.RectF; -import android.util.Log; - -import com.hippo.yorozuya.MathUtils; - -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. -public 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 = -1; - 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 final static WeakHashMap sAllTextures - = new WeakHashMap<>(); - private static final 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. - */ - public void setSize(int width, int height) { - mWidth = width; - mHeight = height; - mTextureWidth = width > 0 ? MathUtils.nextPowerOf2(width) : 0; - mTextureHeight = height > 0 ? MathUtils.nextPowerOf2(height) : 0; - 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 boolean isFlippedVertically() { - return false; - } - - 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); - } - - @Override - public void draw(GLCanvas canvas, RectF source, RectF target) { - canvas.drawTexture(this, source, target); - } - - // 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 && mId != -1) { - canvas.unloadTexture(this); - mId = -1; // Don't free it again. - } - mState = STATE_UNLOADED; - setAssociatedCanvas(null); - } - - @Override - protected void finalize() throws Throwable { - try { - sInFinalizer.set(BasicTexture.class); - recycle(); - sInFinalizer.set(null); - } finally { - super.finalize(); - } - } - - // 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/app/src/main/java/com/hippo/gl/glrenderer/BitmapTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/BitmapTexture.java deleted file mode 100644 index f29270920..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/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.hippo.gl.glrenderer; - -import android.graphics.Bitmap; - -import com.hippo.yorozuya.AssertUtils; - -// 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); - AssertUtils.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/app/src/main/java/com/hippo/gl/glrenderer/CanvasTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/CanvasTexture.java deleted file mode 100644 index 52e394e8d..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/CanvasTexture.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.hippo.gl.glrenderer; - -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 { - 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); - Canvas canvas = new Canvas(bitmap); - onDraw(canvas, bitmap); - return bitmap; - } - - @Override - protected void onFreeBitmap(Bitmap bitmap) { - if (!inFinalizer()) { - bitmap.recycle(); - } - } - - abstract protected void onDraw(Canvas canvas, Bitmap backing); -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/ColorTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/ColorTexture.java deleted file mode 100644 index 7e926aae1..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/ColorTexture.java +++ /dev/null @@ -1,74 +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.hippo.gl.glrenderer; - -import android.graphics.RectF; - -import com.hippo.yorozuya.ColorUtils; - -// ColorTexture is a texture which fills the rectangle with the specified color. -public class ColorTexture implements Texture { - - private final int mColor; - private int mWidth = 0; - private int mHeight = 0; - - public ColorTexture(int color) { - mColor = color; - } - - private boolean isValidSize() { - return mWidth > 0 && mHeight > 0; - } - - @Override - public void draw(GLCanvas canvas, int x, int y) { - if (isValidSize()) { - 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 void draw(GLCanvas canvas, RectF source, RectF target) { - canvas.fillRect(target.left, target.top, target.width(), target.height(), mColor); - } - - @Override - public boolean isOpaque() { - return ColorUtils.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/app/src/main/java/com/hippo/gl/glrenderer/ExtTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/ExtTexture.java deleted file mode 100644 index 34437b43c..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/ExtTexture.java +++ /dev/null @@ -1,60 +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.hippo.gl.glrenderer; - -// ExtTexture is a texture whose content comes from a external texture. -// Before drawing, setSize() should be called. -public class ExtTexture extends BasicTexture { - - private final int mTarget; - - public ExtTexture(GLCanvas canvas, int target) { - GLId glId = canvas.getGLId(); - mId = glId.generateTexture(); - mTarget = target; - } - - private void uploadToCanvas(GLCanvas canvas) { - canvas.setTextureParameters(this); - 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/app/src/main/java/com/hippo/gl/glrenderer/FadeInTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/FadeInTexture.java deleted file mode 100644 index 5e6435018..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/FadeInTexture.java +++ /dev/null @@ -1,54 +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.hippo.gl.glrenderer; - - -import android.graphics.RectF; - -// 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); - } - } - - @Override - public void draw(GLCanvas canvas, RectF source, RectF target) { - if (isAnimating()) { - mTexture.drawMixed(canvas, mColor, getRatio(), source, target); - } else { - mTexture.draw(canvas, source, target); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/FadeOutTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/FadeOutTexture.java deleted file mode 100644 index ba6f6b609..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/FadeOutTexture.java +++ /dev/null @@ -1,54 +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.hippo.gl.glrenderer; - - -import android.graphics.RectF; - -// 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(); - } - } - - @Override - public void draw(GLCanvas canvas, RectF source, RectF target) { - if (isAnimating()) { - canvas.save(GLCanvas.SAVE_FLAG_ALPHA); - canvas.setAlpha(getRatio()); - mTexture.draw(canvas, source, target); - canvas.restore(); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/FadeTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/FadeTexture.java deleted file mode 100644 index 0c543984b..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/FadeTexture.java +++ /dev/null @@ -1,81 +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.hippo.gl.glrenderer; - -import com.hippo.gl.view.AnimationTime; -import com.hippo.yorozuya.MathUtils; - -// 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 MathUtils.clamp(1.0f - r, 0.0f, 1.0f); - } - - private long now() { - return AnimationTime.get(); - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/GLCanvas.java b/app/src/main/java/com/hippo/gl/glrenderer/GLCanvas.java deleted file mode 100644 index cf17e15c8..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/GLCanvas.java +++ /dev/null @@ -1,223 +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.hippo.gl.glrenderer; - -import android.graphics.Bitmap; -import android.graphics.Rect; -import android.graphics.RectF; - -// -// 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 { - - GLId getGLId(); - - // 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. - void setSize(int width, int height); - - // Clear the drawing buffers. This should only be used by GLRoot. - void clearBuffer(); - - void clearBuffer(float[] argb); - - // Sets and gets the current alpha, alpha must be in [0, 1]. - void setAlpha(float alpha); - - float getAlpha(); - - // (current alpha) = (current alpha) * alpha - void multiplyAlpha(float alpha); - - // Change the current transform matrix. - void translate(float x, float y, float z); - - void translate(float x, float y); - - void scale(float sx, float sy, float sz); - - void rotate(float angle, float x, float y, float z); - - void multiplyMatrix(float[] mMatrix, int offset); - - // Pushes the configuration state (matrix, and alpha) onto - // a private stack. - void save(); - - // Same as save(), but only save those specified in saveFlags. - void save(int saveFlags); - - int SAVE_FLAG_ALL = 0xFFFFFFFF; - int SAVE_FLAG_ALPHA = 0x01; - 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. - void restore(); - - // Draws a line using the specified paint from (x1, y1) to (x2, y2). - // (Both end points are included). - 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). - void drawRect(float x1, float y1, float x2, float y2, GLPaint paint); - - // Draws a oval using the specified paint for (cx, cy, radiusX, radiusY) - // (Both end points are included). - void drawOval(float cx, float cy, float radiusX, float radiusY, - GLPaint paint); - - // Draw a arc inside a rect - void drawArc(float cx, float cy, float radiusX, float radiusY, - float sweepAngle, GLPaint paint); - - // Fills the specified rectangle with the specified color. - void fillRect(float x, float y, float width, float height, int color); - - // Fills the specified oval with the specified color. - void fillOval(float cx, float cy, float radiusX, float radiusY, int color); - - // Fills the specified sector with the specified color. - void fillSector(float cx, float cy, float radiusX, float radiusY, float sweepAngle, int color); - - // Draws a texture to the specified rectangle. - void drawTexture(BasicTexture texture, int x, int y, int width, int height); - - 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. - void drawTexture(BasicTexture texture, RectF source, RectF target); - - // Draw a texture with a specified texture transform. - 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. - 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". - void drawMixed(BasicTexture from, int toColor, float ratio, RectF src, RectF target); - - // 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 - boolean unloadTexture(BasicTexture texture); - - // Delete the specified buffer object, similar to unloadTexture. - void deleteBuffer(int bufferId); - - // Delete the textures and buffers in GL side. This function should only be - // called in the GL thread. - void deleteRecycledResources(); - - // Dump statistics information and clear the counters. For debug only. - void dumpStatisticsAndClear(); - - void beginRenderTarget(RawTexture texture); - - void endRenderTarget(); - - /** - * Sets texture parameters to use GL_CLAMP_TO_EDGE for both - * GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T. Sets texture parameters to be - * GL_LINEAR for GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER. - * bindTexture() must be called prior to this. - * - * @param texture The texture to set parameters on. - */ - void setTextureParameters(BasicTexture texture); - - /** - * Initializes the texture to a size by calling texImage2D on it. - * - * @param texture The texture to initialize the size. - * @param format The texture format (e.g. GL_RGBA) - * @param type The texture type (e.g. GL_UNSIGNED_BYTE) - */ - void initializeTextureSize(BasicTexture texture, int format, int type); - - /** - * Initializes the texture to a size by calling texImage2D on it. - * - * @param texture The texture to initialize the size. - * @param bitmap The bitmap to initialize the bitmap with. - */ - void initializeTexture(BasicTexture texture, Bitmap bitmap); - - /** - * Calls glTexSubImage2D to upload a bitmap to the texture. - * - * @param texture The target texture to write to. - * @param xOffset Specifies a texel offset in the x direction within the - * texture array. - * @param yOffset Specifies a texel offset in the y direction within the - * texture array. - * @param format The texture format (e.g. GL_RGBA) - * @param type The texture type (e.g. GL_UNSIGNED_BYTE) - */ - void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap, int format, int type); - - /** - * Generates buffers and uploads the buffer data. - * - * @param buffer The buffer to upload - * @return The buffer ID that was generated. - */ - int uploadBuffer(java.nio.FloatBuffer buffer); - - /** - * Generates buffers and uploads the element array buffer data. - * - * @param buffer The buffer to upload - * @return The buffer ID that was generated. - */ - int uploadBuffer(java.nio.ByteBuffer buffer); - - /** - * After LightCycle makes GL calls, this method is called to restore the GL - * configuration to the one expected by GLCanvas. - */ - void recoverFromLightCycle(); - - /** - * Gets the bounds given by x, y, width, and height as well as the internal - * matrix state. There is no special handling for non-90-degree rotations. - * It only considers the lower-left and upper-right corners as the bounds. - * - * @param bounds The output bounds to write to. - * @param x The left side of the input rectangle. - * @param y The bottom of the input rectangle. - * @param width The width of the input rectangle. - * @param height The height of the input rectangle. - */ - void getBounds(Rect bounds, int x, int y, int width, int height); -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/GLES20Canvas.java b/app/src/main/java/com/hippo/gl/glrenderer/GLES20Canvas.java deleted file mode 100644 index efa0c716a..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/GLES20Canvas.java +++ /dev/null @@ -1,1076 +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.hippo.gl.glrenderer; - -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.RectF; -import android.opengl.GLES20; -import android.opengl.GLUtils; -import android.opengl.Matrix; -import android.util.Log; - -import com.hippo.yorozuya.MathUtils; -import com.hippo.yorozuya.collect.IntList; - -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - -public class GLES20Canvas implements GLCanvas { - // ************** Constants ********************** - private static final String TAG = GLES20Canvas.class.getSimpleName(); - private static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE; - private static final float OPAQUE_ALPHA = 0.95f; - - private static final int COORDS_PER_VERTEX = 2; - private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * FLOAT_SIZE; - - private static final int COUNT_FILL_VERTEX = 4; - private static final int COUNT_LINE_VERTEX = 2; - private static final int COUNT_RECT_VERTEX = 4; - private static final int COUNT_CIRCLE_VERTEX = 120; // multiple of 4 - private static final int OFFSET_FILL_RECT = 0; - private static final int OFFSET_DRAW_LINE = OFFSET_FILL_RECT + COUNT_FILL_VERTEX; - private static final int OFFSET_DRAW_RECT = OFFSET_DRAW_LINE + COUNT_LINE_VERTEX; - private static final int OFFSET_FILL_CIRCLE = OFFSET_DRAW_RECT + COUNT_RECT_VERTEX; - private static final int OFFSET_DRAW_CIRCLE = OFFSET_FILL_CIRCLE + 1; - private static final int OFFSET_LAST = OFFSET_DRAW_CIRCLE + COUNT_CIRCLE_VERTEX + 1; - - private static final float[] BOX_COORDINATES = new float[OFFSET_LAST * 2]; - - static { - float[] temp = { - 0, 0, // Fill rectangle - 1, 0, - 0, 1, - 1, 1, - 0, 0, // Draw line - 1, 1, - 0, 0, // Draw rectangle outline - 0, 1, - 1, 1, - 1, 0, - 0.5f, 0.5f // Fill circle - }; - System.arraycopy(temp, 0, BOX_COORDINATES, 0, temp.length); - - // Draw circle - int arrayOffset = OFFSET_DRAW_CIRCLE * 2; - for (int i = 0, n = COUNT_CIRCLE_VERTEX / 4; i <= n; i++) { - float value = (float) Math.sin(MathUtils.radians(90f / n * i)) / 2; - float positive = value + 0.5f; - float negative = -value + 0.5f; - BOX_COORDINATES[arrayOffset + n * 0 + i * 2 + 1] = positive; - BOX_COORDINATES[arrayOffset + n * 2 - i * 2 + 0] = positive; - BOX_COORDINATES[arrayOffset + n * 2 + i * 2 + 0] = negative; - BOX_COORDINATES[arrayOffset + n * 4 - i * 2 + 1] = positive; - BOX_COORDINATES[arrayOffset + n * 4 + i * 2 + 1] = negative; - BOX_COORDINATES[arrayOffset + n * 6 - i * 2 + 0] = negative; - BOX_COORDINATES[arrayOffset + n * 6 + i * 2 + 0] = positive; - BOX_COORDINATES[arrayOffset + n * 8 - i * 2 + 1] = negative; - } - } - - private static final float[] BOUNDS_COORDINATES = { - 0, 0, 0, 1, - 1, 1, 0, 1, - }; - - private static final String POSITION_ATTRIBUTE = "aPosition"; - private static final String COLOR_UNIFORM = "uColor"; - private static final String MATRIX_UNIFORM = "uMatrix"; - private static final String TEXTURE_MATRIX_UNIFORM = "uTextureMatrix"; - private static final String TEXTURE_SAMPLER_UNIFORM = "uTextureSampler"; - private static final String ALPHA_UNIFORM = "uAlpha"; - private static final String TEXTURE_COORD_ATTRIBUTE = "aTextureCoordinate"; - - private static final String DRAW_VERTEX_SHADER = "" - + "uniform mat4 " + MATRIX_UNIFORM + ";\n" - + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n" - + "void main() {\n" - + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n" - + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n" - + "}\n"; - - private static final String DRAW_FRAGMENT_SHADER = "" - + "precision mediump float;\n" - + "uniform vec4 " + COLOR_UNIFORM + ";\n" - + "void main() {\n" - + " gl_FragColor = " + COLOR_UNIFORM + ";\n" - + "}\n"; - - private static final String TEXTURE_VERTEX_SHADER = "" - + "uniform mat4 " + MATRIX_UNIFORM + ";\n" - + "uniform mat4 " + TEXTURE_MATRIX_UNIFORM + ";\n" - + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n" - + "varying vec2 vTextureCoord;\n" - + "void main() {\n" - + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n" - + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n" - + " vTextureCoord = (" + TEXTURE_MATRIX_UNIFORM + " * pos).xy;\n" - + "}\n"; - - private static final String MESH_VERTEX_SHADER = "" - + "uniform mat4 " + MATRIX_UNIFORM + ";\n" - + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n" - + "attribute vec2 " + TEXTURE_COORD_ATTRIBUTE + ";\n" - + "varying vec2 vTextureCoord;\n" - + "void main() {\n" - + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n" - + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n" - + " vTextureCoord = " + TEXTURE_COORD_ATTRIBUTE + ";\n" - + "}\n"; - - private static final String TEXTURE_FRAGMENT_SHADER = "" - + "precision mediump float;\n" - + "varying vec2 vTextureCoord;\n" - + "uniform float " + ALPHA_UNIFORM + ";\n" - + "uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n" - + "void main() {\n" - + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n" - + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n" - + "}\n"; - - private static final String OES_TEXTURE_FRAGMENT_SHADER = "" - + "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "varying vec2 vTextureCoord;\n" - + "uniform float " + ALPHA_UNIFORM + ";\n" - + "uniform samplerExternalOES " + TEXTURE_SAMPLER_UNIFORM + ";\n" - + "void main() {\n" - + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n" - + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n" - + "}\n"; - - private static final int INITIAL_RESTORE_STATE_SIZE = 8; - private static final int MATRIX_SIZE = 16; - - // Keep track of restore state - private float[] mMatrices = new float[INITIAL_RESTORE_STATE_SIZE * MATRIX_SIZE]; - private float[] mAlphas = new float[INITIAL_RESTORE_STATE_SIZE]; - private final IntList mSaveFlags = new IntList(); - - private int mCurrentAlphaIndex = 0; - private int mCurrentMatrixIndex = 0; - - // Viewport size - private int mWidth; - private int mHeight; - - // Projection matrix - private final float[] mProjectionMatrix = new float[MATRIX_SIZE]; - - // Screen size for when we aren't bound to a texture - private int mScreenWidth; - private int mScreenHeight; - - // GL programs - private final int mDrawProgram; - private final int mTextureProgram; - private final int mOesTextureProgram; - private final int mMeshProgram; - - // GL buffer containing BOX_COORDINATES - private final int mBoxCoordinates; - - // Handle indices -- common - private static final int INDEX_POSITION = 0; - private static final int INDEX_MATRIX = 1; - - // Handle indices -- draw - private static final int INDEX_COLOR = 2; - - // Handle indices -- texture - private static final int INDEX_TEXTURE_MATRIX = 2; - private static final int INDEX_TEXTURE_SAMPLER = 3; - private static final int INDEX_ALPHA = 4; - - // Handle indices -- mesh - private static final int INDEX_TEXTURE_COORD = 2; - - private abstract static class ShaderParameter { - public int handle; - protected final String mName; - - public ShaderParameter(String name) { - mName = name; - } - - public abstract void loadHandle(int program); - } - - private static class UniformShaderParameter extends ShaderParameter { - public UniformShaderParameter(String name) { - super(name); - } - - @Override - public void loadHandle(int program) { - handle = GLES20.glGetUniformLocation(program, mName); - checkError(); - } - } - - private static class AttributeShaderParameter extends ShaderParameter { - public AttributeShaderParameter(String name) { - super(name); - } - - @Override - public void loadHandle(int program) { - handle = GLES20.glGetAttribLocation(program, mName); - checkError(); - } - } - - ShaderParameter[] mDrawParameters = { - new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION - new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX - new UniformShaderParameter(COLOR_UNIFORM), // INDEX_COLOR - }; - ShaderParameter[] mTextureParameters = { - new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION - new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX - new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX - new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER - new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA - }; - ShaderParameter[] mOesTextureParameters = { - new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION - new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX - new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX - new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER - new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA - }; - ShaderParameter[] mMeshParameters = { - new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION - new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX - new AttributeShaderParameter(TEXTURE_COORD_ATTRIBUTE), // INDEX_TEXTURE_COORD - new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER - new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA - }; - - private final IntList mUnboundTextures = new IntList(); - private final IntList mDeleteBuffers = new IntList(); - - // Keep track of statistics for debugging - private int mCountDrawMesh = 0; - private int mCountTextureRect = 0; - private int mCountFillRect = 0; - private int mCountDrawLine = 0; - - // Buffer for framebuffer IDs -- we keep track so we can switch the attached - // texture. - private final int[] mFrameBuffer = new int[1]; - - // Bound textures. - private final ArrayList mTargetTextures = new ArrayList<>(); - - // Temporary variables used within calculations - private final float[] mTempMatrix = new float[32]; - private final float[] mTempColor = new float[4]; - private final RectF mTempSourceRect = new RectF(); - private final RectF mTempTargetRect = new RectF(); - private final float[] mTempTextureMatrix = new float[MATRIX_SIZE]; - private final int[] mTempIntArray = new int[1]; - - private static final GLId mGLId = new GLES20IdImpl(); - - public GLES20Canvas() { - Matrix.setIdentityM(mTempTextureMatrix, 0); - Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex); - mAlphas[mCurrentAlphaIndex] = 1f; - mTargetTextures.add(null); - - FloatBuffer boxBuffer = createBuffer(BOX_COORDINATES); - mBoxCoordinates = uploadBuffer(boxBuffer); - - int drawVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DRAW_VERTEX_SHADER); - int textureVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, TEXTURE_VERTEX_SHADER); - int meshVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, MESH_VERTEX_SHADER); - int drawFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DRAW_FRAGMENT_SHADER); - int textureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, TEXTURE_FRAGMENT_SHADER); - int oesTextureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, - OES_TEXTURE_FRAGMENT_SHADER); - - mDrawProgram = assembleProgram(drawVertexShader, drawFragmentShader, mDrawParameters); - mTextureProgram = assembleProgram(textureVertexShader, textureFragmentShader, - mTextureParameters); - mOesTextureProgram = assembleProgram(textureVertexShader, oesTextureFragmentShader, - mOesTextureParameters); - mMeshProgram = assembleProgram(meshVertexShader, textureFragmentShader, mMeshParameters); - GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); - checkError(); - } - - private static FloatBuffer createBuffer(float[] values) { - // First create an nio buffer, then create a VBO from it. - int size = values.length * FLOAT_SIZE; - FloatBuffer buffer = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()) - .asFloatBuffer(); - buffer.put(values, 0, values.length).position(0); - return buffer; - } - - private int assembleProgram(int vertexShader, int fragmentShader, ShaderParameter[] params) { - int program = GLES20.glCreateProgram(); - checkError(); - if (program == 0) { - throw new RuntimeException("Cannot create GL program: " + GLES20.glGetError()); - } - GLES20.glAttachShader(program, vertexShader); - checkError(); - GLES20.glAttachShader(program, fragmentShader); - checkError(); - GLES20.glLinkProgram(program); - checkError(); - int[] mLinkStatus = mTempIntArray; - GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, mLinkStatus, 0); - if (mLinkStatus[0] != GLES20.GL_TRUE) { - Log.e(TAG, "Could not link program: "); - Log.e(TAG, GLES20.glGetProgramInfoLog(program)); - GLES20.glDeleteProgram(program); - program = 0; - } - for (int i = 0; i < params.length; i++) { - params[i].loadHandle(program); - } - return program; - } - - private static int loadShader(int type, String shaderCode) { - // create a vertex shader type (GLES20.GL_VERTEX_SHADER) - // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) - int shader = GLES20.glCreateShader(type); - - // add the source code to the shader and compile it - GLES20.glShaderSource(shader, shaderCode); - checkError(); - GLES20.glCompileShader(shader); - checkError(); - - return shader; - } - - @Override - public void setSize(int width, int height) { - mWidth = width; - mHeight = height; - GLES20.glViewport(0, 0, mWidth, mHeight); - checkError(); - Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex); - Matrix.orthoM(mProjectionMatrix, 0, 0, width, 0, height, -1, 1); - if (getTargetTexture() == null) { - mScreenWidth = width; - mScreenHeight = height; - Matrix.translateM(mMatrices, mCurrentMatrixIndex, 0, height, 0); - Matrix.scaleM(mMatrices, mCurrentMatrixIndex, 1, -1, 1); - } - } - - @Override - public void clearBuffer() { - GLES20.glClearColor(0f, 0f, 0f, 1f); - checkError(); - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - checkError(); - } - - @Override - public void clearBuffer(float[] argb) { - GLES20.glClearColor(argb[1], argb[2], argb[3], argb[0]); - checkError(); - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - checkError(); - } - - @Override - public float getAlpha() { - return mAlphas[mCurrentAlphaIndex]; - } - - @Override - public void setAlpha(float alpha) { - mAlphas[mCurrentAlphaIndex] = alpha; - } - - @Override - public void multiplyAlpha(float alpha) { - setAlpha(getAlpha() * alpha); - } - - @Override - public void translate(float x, float y, float z) { - Matrix.translateM(mMatrices, mCurrentMatrixIndex, 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) { - int index = mCurrentMatrixIndex; - float[] m = mMatrices; - m[index + 12] += m[index + 0] * x + m[index + 4] * y; - m[index + 13] += m[index + 1] * x + m[index + 5] * y; - m[index + 14] += m[index + 2] * x + m[index + 6] * y; - m[index + 15] += m[index + 3] * x + m[index + 7] * y; - } - - @Override - public void scale(float sx, float sy, float sz) { - Matrix.scaleM(mMatrices, mCurrentMatrixIndex, sx, sy, sz); - } - - @Override - public void rotate(float angle, float x, float y, float z) { - if (angle == 0f) { - return; - } - float[] temp = mTempMatrix; - Matrix.setRotateM(temp, 0, angle, x, y, z); - float[] matrix = mMatrices; - int index = mCurrentMatrixIndex; - Matrix.multiplyMM(temp, MATRIX_SIZE, matrix, index, temp, 0); - System.arraycopy(temp, MATRIX_SIZE, matrix, index, MATRIX_SIZE); - } - - @Override - public void multiplyMatrix(float[] matrix, int offset) { - float[] temp = mTempMatrix; - float[] currentMatrix = mMatrices; - int index = mCurrentMatrixIndex; - Matrix.multiplyMM(temp, 0, currentMatrix, index, matrix, offset); - System.arraycopy(temp, 0, currentMatrix, index, 16); - } - - @Override - public void save() { - save(SAVE_FLAG_ALL); - } - - @Override - public void save(int saveFlags) { - boolean saveAlpha = (saveFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA; - if (saveAlpha) { - float currentAlpha = getAlpha(); - mCurrentAlphaIndex++; - if (mAlphas.length <= mCurrentAlphaIndex) { - mAlphas = Arrays.copyOf(mAlphas, mAlphas.length * 2); - } - mAlphas[mCurrentAlphaIndex] = currentAlpha; - } - boolean saveMatrix = (saveFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX; - if (saveMatrix) { - int currentIndex = mCurrentMatrixIndex; - mCurrentMatrixIndex += MATRIX_SIZE; - if (mMatrices.length <= mCurrentMatrixIndex) { - mMatrices = Arrays.copyOf(mMatrices, mMatrices.length * 2); - } - System.arraycopy(mMatrices, currentIndex, mMatrices, mCurrentMatrixIndex, MATRIX_SIZE); - } - mSaveFlags.add(saveFlags); - } - - @Override - public void restore() { - int restoreFlags = mSaveFlags.removeAt(mSaveFlags.size() - 1); - boolean restoreAlpha = (restoreFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA; - if (restoreAlpha) { - mCurrentAlphaIndex--; - } - boolean restoreMatrix = (restoreFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX; - if (restoreMatrix) { - mCurrentMatrixIndex -= MATRIX_SIZE; - } - } - - @Override - public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) { - draw(GLES20.GL_LINE_STRIP, OFFSET_DRAW_LINE, COUNT_LINE_VERTEX, x1, y1, x2 - x1, y2 - y1, - paint); - mCountDrawLine++; - } - - @Override - public void drawRect(float x, float y, float width, float height, GLPaint paint) { - draw(GLES20.GL_LINE_LOOP, OFFSET_DRAW_RECT, COUNT_RECT_VERTEX, x, y, width, height, paint); - mCountDrawLine++; - } - - @Override - public void drawOval(float cx, float cy, float radiusX, float radiusY, GLPaint paint) { - float halfLineWidth = paint.getLineWidth() / 2; - fillOval(cx, cy, radiusX + halfLineWidth, radiusY + halfLineWidth, paint.getColor()); - fillOval(cx, cy, radiusX - halfLineWidth, radiusY - halfLineWidth, paint.getBackgroundColor()); - } - - @Override - public void drawArc(float cx, float cy, float radiusX, float radiusY, - float sweepAngle, GLPaint paint) { - float halfLineWidth = paint.getLineWidth() / 2; - fillSector(cx, cy, radiusX + halfLineWidth, radiusY + halfLineWidth, sweepAngle, paint.getColor()); - fillOval(cx, cy, radiusX - halfLineWidth, radiusY - halfLineWidth, paint.getBackgroundColor()); - } - - private void draw(int type, int offset, int count, float x, float y, float width, float height, - GLPaint paint) { - draw(type, offset, count, x, y, width, height, paint.getColor(), paint.getLineWidth()); - } - - private void draw(int type, int offset, int count, float x, float y, float width, float height, - int color, float lineWidth) { - prepareDraw(offset, color, lineWidth); - draw(mDrawParameters, type, count, x, y, width, height); - } - - private void prepareDraw(int offset, int color, float lineWidth) { - GLES20.glUseProgram(mDrawProgram); - checkError(); - if (lineWidth > 0) { - GLES20.glLineWidth(lineWidth); - checkError(); - } - float[] colorArray = getColor(color); - boolean blendingEnabled = (colorArray[3] < 1f); - enableBlending(blendingEnabled); - if (blendingEnabled) { - GLES20.glBlendColor(colorArray[0], colorArray[1], colorArray[2], colorArray[3]); - checkError(); - } - - GLES20.glUniform4fv(mDrawParameters[INDEX_COLOR].handle, 1, colorArray, 0); - setPosition(mDrawParameters, offset); - checkError(); - } - - private float[] getColor(int color) { - float alpha = ((color >>> 24) & 0xFF) / 255f * getAlpha(); - float red = ((color >>> 16) & 0xFF) / 255f * alpha; - float green = ((color >>> 8) & 0xFF) / 255f * alpha; - float blue = (color & 0xFF) / 255f * alpha; - mTempColor[0] = red; - mTempColor[1] = green; - mTempColor[2] = blue; - mTempColor[3] = alpha; - return mTempColor; - } - - private void enableBlending(boolean enableBlending) { - if (enableBlending) { - GLES20.glEnable(GLES20.GL_BLEND); - checkError(); - } else { - GLES20.glDisable(GLES20.GL_BLEND); - checkError(); - } - } - - private void setPosition(ShaderParameter[] params, int offset) { - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mBoxCoordinates); - checkError(); - GLES20.glVertexAttribPointer(params[INDEX_POSITION].handle, COORDS_PER_VERTEX, - GLES20.GL_FLOAT, false, VERTEX_STRIDE, offset * VERTEX_STRIDE); - checkError(); - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); - checkError(); - } - - private void draw(ShaderParameter[] params, int type, int count, float x, float y, float width, - float height) { - setMatrix(params, x, y, width, height); - int positionHandle = params[INDEX_POSITION].handle; - GLES20.glEnableVertexAttribArray(positionHandle); - checkError(); - GLES20.glDrawArrays(type, 0, count); - checkError(); - GLES20.glDisableVertexAttribArray(positionHandle); - checkError(); - } - - private void setMatrix(ShaderParameter[] params, float x, float y, float width, float height) { - Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f); - Matrix.scaleM(mTempMatrix, 0, width, height, 1f); - Matrix.multiplyMM(mTempMatrix, MATRIX_SIZE, mProjectionMatrix, 0, mTempMatrix, 0); - GLES20.glUniformMatrix4fv(params[INDEX_MATRIX].handle, 1, false, mTempMatrix, MATRIX_SIZE); - checkError(); - } - - @Override - public void fillRect(float x, float y, float width, float height, int color) { - draw(GLES20.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, COUNT_FILL_VERTEX, x, y, width, height, - color, 0f); - mCountFillRect++; - } - - @Override - public void fillOval(float cx, float cy, float radiusX, float radiusY, int color) { - draw(GLES20.GL_TRIANGLE_FAN, OFFSET_FILL_CIRCLE, OFFSET_LAST - OFFSET_FILL_CIRCLE, - cx - radiusX, cy - radiusY, radiusX * 2, radiusY * 2, color, 0f); - mCountFillRect++; - } - - @Override - public void fillSector(float cx, float cy, float radiusX, float radiusY, float sweepAngle, int color) { - float conjugateAngle = Math.abs(360 - MathUtils.positiveModulo(sweepAngle, 360)); - int conjugateCount = Math.round(COUNT_CIRCLE_VERTEX * conjugateAngle / 360); - if (conjugateCount == 0) { - // It is a circle - fillOval(cx, cy, radiusX, radiusY, color); - } else if (conjugateCount < COUNT_CIRCLE_VERTEX) { - draw(GLES20.GL_TRIANGLE_FAN, OFFSET_FILL_CIRCLE, OFFSET_LAST - OFFSET_FILL_CIRCLE - conjugateCount, - cx - radiusX, cy - radiusY, radiusX * 2, radiusY * 2, color, 0f); - mCountFillRect++; - } - } - - @Override - public void drawTexture(BasicTexture texture, int x, int y, int width, int height) { - if (width <= 0 || height <= 0) { - return; - } - copyTextureCoordinates(texture, mTempSourceRect); - mTempTargetRect.set(x, y, x + width, y + height); - convertCoordinate(mTempSourceRect, mTempTargetRect, texture); - drawTextureRect(texture, mTempSourceRect, mTempTargetRect); - } - - private static void copyTextureCoordinates(BasicTexture texture, RectF outRect) { - int left = 0; - int top = 0; - int right = texture.getWidth(); - int bottom = texture.getHeight(); - if (texture.hasBorder()) { - left = 1; - top = 1; - right -= 1; - bottom -= 1; - } - outRect.set(left, top, right, bottom); - } - - @Override - public void drawTexture(BasicTexture texture, RectF source, RectF target) { - if (target.width() <= 0 || target.height() <= 0) { - return; - } - mTempSourceRect.set(source); - mTempTargetRect.set(target); - - convertCoordinate(mTempSourceRect, mTempTargetRect, texture); - drawTextureRect(texture, mTempSourceRect, mTempTargetRect); - } - - @Override - public void drawTexture(BasicTexture texture, float[] textureTransform, int x, int y, int w, - int h) { - if (w <= 0 || h <= 0) { - return; - } - mTempTargetRect.set(x, y, x + w, y + h); - drawTextureRect(texture, textureTransform, mTempTargetRect); - } - - private void drawTextureRect(BasicTexture texture, RectF source, RectF target) { - setTextureMatrix(source); - drawTextureRect(texture, mTempTextureMatrix, target); - } - - private void setTextureMatrix(RectF source) { - mTempTextureMatrix[0] = source.width(); - mTempTextureMatrix[5] = source.height(); - mTempTextureMatrix[12] = source.left; - mTempTextureMatrix[13] = source.top; - } - - // 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; - } - } - - private void drawTextureRect(BasicTexture texture, float[] textureMatrix, RectF target) { - ShaderParameter[] params = prepareTexture(texture); - setPosition(params, OFFSET_FILL_RECT); - GLES20.glUniformMatrix4fv(params[INDEX_TEXTURE_MATRIX].handle, 1, false, textureMatrix, 0); - checkError(); - if (texture.isFlippedVertically()) { - save(SAVE_FLAG_MATRIX); - translate(0, target.centerY()); - scale(1, -1, 1); - translate(0, -target.centerY()); - } - draw(params, GLES20.GL_TRIANGLE_STRIP, COUNT_FILL_VERTEX, target.left, target.top, - target.width(), target.height()); - if (texture.isFlippedVertically()) { - restore(); - } - mCountTextureRect++; - } - - private ShaderParameter[] prepareTexture(BasicTexture texture) { - ShaderParameter[] params; - int program; - if (texture.getTarget() == GLES20.GL_TEXTURE_2D) { - params = mTextureParameters; - program = mTextureProgram; - } else { - params = mOesTextureParameters; - program = mOesTextureProgram; - } - prepareTexture(texture, program, params); - return params; - } - - private void prepareTexture(BasicTexture texture, int program, ShaderParameter[] params) { - GLES20.glUseProgram(program); - checkError(); - enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA); - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - checkError(); - texture.onBind(this); - GLES20.glBindTexture(texture.getTarget(), texture.getId()); - checkError(); - GLES20.glUniform1i(params[INDEX_TEXTURE_SAMPLER].handle, 0); - checkError(); - GLES20.glUniform1f(params[INDEX_ALPHA].handle, getAlpha()); - checkError(); - } - - @Override - public void drawMesh(BasicTexture texture, int x, int y, int xyBuffer, int uvBuffer, - int indexBuffer, int indexCount) { - prepareTexture(texture, mMeshProgram, mMeshParameters); - - GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer); - checkError(); - - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, xyBuffer); - checkError(); - int positionHandle = mMeshParameters[INDEX_POSITION].handle; - GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, - VERTEX_STRIDE, 0); - checkError(); - - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, uvBuffer); - checkError(); - int texCoordHandle = mMeshParameters[INDEX_TEXTURE_COORD].handle; - GLES20.glVertexAttribPointer(texCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, - false, VERTEX_STRIDE, 0); - checkError(); - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); - checkError(); - - GLES20.glEnableVertexAttribArray(positionHandle); - checkError(); - GLES20.glEnableVertexAttribArray(texCoordHandle); - checkError(); - - setMatrix(mMeshParameters, x, y, 1, 1); - GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexCount, GLES20.GL_UNSIGNED_BYTE, 0); - checkError(); - - GLES20.glDisableVertexAttribArray(positionHandle); - checkError(); - GLES20.glDisableVertexAttribArray(texCoordHandle); - checkError(); - GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); - checkError(); - mCountDrawMesh++; - } - - @Override - public void drawMixed(BasicTexture texture, int toColor, float ratio, int x, int y, int w, int h) { - copyTextureCoordinates(texture, mTempSourceRect); - mTempTargetRect.set(x, y, x + w, y + h); - drawMixed(texture, toColor, ratio, mTempSourceRect, mTempTargetRect); - } - - @Override - public void drawMixed(BasicTexture texture, int toColor, float ratio, RectF source, RectF target) { - if (target.width() <= 0 || target.height() <= 0) { - return; - } - save(SAVE_FLAG_ALPHA); - - float currentAlpha = getAlpha(); - float cappedRatio = Math.min(1f, Math.max(0f, ratio)); - - float textureAlpha = (1f - cappedRatio) * currentAlpha; - setAlpha(textureAlpha); - drawTexture(texture, source, target); - - if (0 != Color.alpha(toColor)) { - float colorAlpha = cappedRatio * currentAlpha; - setAlpha(colorAlpha); - fillRect(target.left, target.top, target.width(), target.height(), toColor); - } - - restore(); - } - - @Override - public boolean unloadTexture(BasicTexture texture) { - boolean unload = texture.isLoaded(); - if (unload) { - synchronized (mUnboundTextures) { - mUnboundTextures.add(texture.getId()); - } - } - return unload; - } - - @Override - public void deleteBuffer(int bufferId) { - synchronized (mUnboundTextures) { - mDeleteBuffers.add(bufferId); - } - } - - @Override - public void deleteRecycledResources() { - synchronized (mUnboundTextures) { - IntList ids = mUnboundTextures; - if (mUnboundTextures.size() > 0) { - mGLId.glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0); - ids.clear(); - } - - ids = mDeleteBuffers; - if (ids.size() > 0) { - mGLId.glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0); - ids.clear(); - } - } - } - - @Override - public void dumpStatisticsAndClear() { - String line = String.format(Locale.US, "MESH:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d", mCountDrawMesh, - mCountTextureRect, mCountFillRect, mCountDrawLine); - mCountDrawMesh = 0; - mCountTextureRect = 0; - mCountFillRect = 0; - mCountDrawLine = 0; - Log.d(TAG, line); - } - - @Override - public void endRenderTarget() { - RawTexture oldTexture = mTargetTextures.remove(mTargetTextures.size() - 1); - RawTexture texture = getTargetTexture(); - setRenderTarget(oldTexture, texture); - restore(); // restore matrix and alpha - } - - @Override - public void beginRenderTarget(RawTexture texture) { - save(); // save matrix and alpha and blending - RawTexture oldTexture = getTargetTexture(); - mTargetTextures.add(texture); - setRenderTarget(oldTexture, texture); - } - - private RawTexture getTargetTexture() { - return mTargetTextures.get(mTargetTextures.size() - 1); - } - - private void setRenderTarget(BasicTexture oldTexture, RawTexture texture) { - if (oldTexture == null && texture != null) { - GLES20.glGenFramebuffers(1, mFrameBuffer, 0); - checkError(); - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer[0]); - checkError(); - } else if (oldTexture != null && texture == null) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); - checkError(); - GLES20.glDeleteFramebuffers(1, mFrameBuffer, 0); - checkError(); - } - - if (texture == null) { - setSize(mScreenWidth, mScreenHeight); - } else { - setSize(texture.getWidth(), texture.getHeight()); - - if (!texture.isLoaded()) { - texture.prepare(this); - } - - GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, - texture.getTarget(), texture.getId(), 0); - checkError(); - - checkFramebufferStatus(); - } - } - - private static void checkFramebufferStatus() { - int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); - if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) { - String msg = ""; - switch (status) { - case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - msg = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; - break; - case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - msg = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; - break; - case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - msg = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; - break; - case GLES20.GL_FRAMEBUFFER_UNSUPPORTED: - msg = "GL_FRAMEBUFFER_UNSUPPORTED"; - break; - } - throw new RuntimeException(msg + ":" + Integer.toHexString(status)); - } - } - - @Override - public void setTextureParameters(BasicTexture texture) { - int target = texture.getTarget(); - GLES20.glBindTexture(target, texture.getId()); - checkError(); - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - } - - @Override - public void initializeTextureSize(BasicTexture texture, int format, int type) { - int target = texture.getTarget(); - GLES20.glBindTexture(target, texture.getId()); - checkError(); - int width = texture.getTextureWidth(); - int height = texture.getTextureHeight(); - GLES20.glTexImage2D(target, 0, format, width, height, 0, format, type, null); - } - - @Override - public void initializeTexture(BasicTexture texture, Bitmap bitmap) { - int target = texture.getTarget(); - GLES20.glBindTexture(target, texture.getId()); - checkError(); - GLUtils.texImage2D(target, 0, bitmap, 0); - } - - @Override - public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap, - int format, int type) { - int target = texture.getTarget(); - GLES20.glBindTexture(target, texture.getId()); - checkError(); - GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type); - } - - @Override - public int uploadBuffer(FloatBuffer buf) { - return uploadBuffer(buf, FLOAT_SIZE); - } - - @Override - public int uploadBuffer(ByteBuffer buf) { - return uploadBuffer(buf, 1); - } - - private int uploadBuffer(Buffer buffer, int elementSize) { - mGLId.glGenBuffers(1, mTempIntArray, 0); - checkError(); - int bufferId = mTempIntArray[0]; - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId); - checkError(); - GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity() * elementSize, buffer, - GLES20.GL_STATIC_DRAW); - checkError(); - return bufferId; - } - - public static void checkError() { - int error = GLES20.glGetError(); - if (error != 0) { - Throwable t = new Throwable(); - Log.e(TAG, "GL error: " + error, t); - } - } - - @SuppressWarnings("unused") - private static void printMatrix(String message, float[] m, int offset) { - StringBuilder b = new StringBuilder(message); - for (int i = 0; i < MATRIX_SIZE; i++) { - b.append(' '); - if (i % 4 == 0) { - b.append('\n'); - } - b.append(m[offset + i]); - } - Log.v(TAG, b.toString()); - } - - @Override - public void recoverFromLightCycle() { - GLES20.glViewport(0, 0, mWidth, mHeight); - GLES20.glDisable(GLES20.GL_DEPTH_TEST); - GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); - checkError(); - } - - @Override - public void getBounds(Rect bounds, int x, int y, int width, int height) { - Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f); - Matrix.scaleM(mTempMatrix, 0, width, height, 1f); - Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE, mTempMatrix, 0, BOUNDS_COORDINATES, 0); - Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE + 4, mTempMatrix, 0, BOUNDS_COORDINATES, 4); - bounds.left = Math.round(mTempMatrix[MATRIX_SIZE]); - bounds.right = Math.round(mTempMatrix[MATRIX_SIZE + 4]); - bounds.top = Math.round(mTempMatrix[MATRIX_SIZE + 1]); - bounds.bottom = Math.round(mTempMatrix[MATRIX_SIZE + 5]); - bounds.sort(); - } - - @Override - public GLId getGLId() { - return mGLId; - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/GLES20IdImpl.java b/app/src/main/java/com/hippo/gl/glrenderer/GLES20IdImpl.java deleted file mode 100644 index 27d040dd9..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/GLES20IdImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.hippo.gl.glrenderer; - -import android.opengl.GLES20; - -import javax.microedition.khronos.opengles.GL11; -import javax.microedition.khronos.opengles.GL11ExtensionPack; - -public class GLES20IdImpl implements GLId { - private final int[] mTempIntArray = new int[1]; - - @Override - public int generateTexture() { - GLES20.glGenTextures(1, mTempIntArray, 0); - GLES20Canvas.checkError(); - return mTempIntArray[0]; - } - - @Override - public void glGenBuffers(int n, int[] buffers, int offset) { - GLES20.glGenBuffers(n, buffers, offset); - GLES20Canvas.checkError(); - } - - @Override - public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset) { - GLES20.glDeleteTextures(n, textures, offset); - GLES20Canvas.checkError(); - } - - - @Override - public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset) { - GLES20.glDeleteBuffers(n, buffers, offset); - GLES20Canvas.checkError(); - } - - @Override - public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset) { - GLES20.glDeleteFramebuffers(n, buffers, offset); - GLES20Canvas.checkError(); - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/GLId.java b/app/src/main/java/com/hippo/gl/glrenderer/GLId.java deleted file mode 100644 index bb06aa32c..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/GLId.java +++ /dev/null @@ -1,33 +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.hippo.gl.glrenderer; - -import javax.microedition.khronos.opengles.GL11; -import javax.microedition.khronos.opengles.GL11ExtensionPack; - -// This mimics corresponding GL functions. -public interface GLId { - int generateTexture(); - - void glGenBuffers(int n, int[] buffers, int offset); - - void glDeleteTextures(GL11 gl, int n, int[] textures, int offset); - - void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset); - - void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset); -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/GLPaint.java b/app/src/main/java/com/hippo/gl/glrenderer/GLPaint.java deleted file mode 100644 index 1e9f37773..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/GLPaint.java +++ /dev/null @@ -1,50 +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.hippo.gl.glrenderer; - -import junit.framework.Assert; - -public class GLPaint { - private float mLineWidth = 1f; - private int mColor = 0; - private int mBackgroundColor = 0; - - public void setColor(int color) { - mColor = color; - } - - public int getColor() { - return mColor; - } - - public void setBackgroundColor(int backgroundColor) { - mBackgroundColor = backgroundColor; - } - - public int getBackgroundColor() { - return mBackgroundColor; - } - - public void setLineWidth(float width) { - Assert.assertTrue(width >= 0); - mLineWidth = width; - } - - public float getLineWidth() { - return mLineWidth; - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/ImageMovableTextTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/ImageMovableTextTexture.java deleted file mode 100644 index 4aa928e4d..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/ImageMovableTextTexture.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.glrenderer; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Typeface; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import com.hippo.image.Image; - -import java.util.Arrays; - -public class ImageMovableTextTexture extends ImageSpriteTexture { - - private final char[] mCharacters; - private final float[] mWidths; - private final float mHeight; - private final float mMaxWidth; - - public ImageMovableTextTexture(@NonNull ImageWrapper image, int count, int[] rects, - char[] characters, float[] widths, float height, float maxWidth) { - super(image, count, rects); - - mCharacters = characters; - mWidths = widths; - mHeight = height; - mMaxWidth = maxWidth; - } - - public int[] getTextIndexes(String text) { - char[] characters = mCharacters; - - int length = text.length(); - int[] indexes = new int[length]; - for (int i = 0; i < length; i++) { - char ch = text.charAt(i); - indexes[i] = Arrays.binarySearch(characters, ch); - } - - return indexes; - } - - public float getTextWidth(String text) { - char[] characters = mCharacters; - float[] widths = mWidths; - float width = 0.0f; - - for (int i = 0, n = text.length(); i < n; i++) { - char ch = text.charAt(i); - int index = Arrays.binarySearch(characters, ch); - if (index >= 0) { - width += widths[index]; - } else { - width += mMaxWidth; - } - } - - return width; - } - - public float getTextWidth(int[] indexes) { - float[] widths = mWidths; - float width = 0.0f; - int length = indexes.length; - for (int i = 0; i < length; i++) { - int index = indexes[i]; - if (index >= 0) { - width += widths[index]; - } else { - width += mMaxWidth; - } - } - - return width; - } - - public float getMaxWidth() { - return mMaxWidth; - } - - public float getTextHeight() { - return mHeight; - } - - public void drawText(GLCanvas canvas, String text, int x, int y) { - char[] characters = mCharacters; - float[] widths = mWidths; - - for (int i = 0, n = text.length(); i < n; i++) { - char ch = text.charAt(i); - int index = Arrays.binarySearch(characters, ch); - if (index >= 0) { - drawSprite(canvas, index, x, y); - x += widths[index]; - } else { - x += mMaxWidth; - } - } - } - - public void drawText(GLCanvas canvas, int[] indexes, int x, int y) { - float[] widths = mWidths; - - for (int i = 0, n = indexes.length; i < n; i++) { - int index = indexes[i]; - if (index >= 0) { - drawSprite(canvas, index, x, y); - x += widths[index]; - } else { - x += mMaxWidth; - } - } - } - - /** - * Create a TextTexture to draw text - * - * @param typeface the typeface - * @param size text size - * @param characters all Characters - * @return the TextTexture - */ - @Nullable - public static ImageMovableTextTexture create(Typeface typeface, int size, int color, char[] characters) { - Paint paint = new Paint(); - paint.setAntiAlias(true); - paint.setTextSize(size); - paint.setColor(color); - paint.setTypeface(typeface); - - Paint.FontMetricsInt fmi = paint.getFontMetricsInt(); - int fixed = fmi.bottom; - int height = fmi.bottom - fmi.top; - - int length = characters.length; - float[] widths = new float[length]; - paint.getTextWidths(characters, 0, length, widths); - - // Calculate bitmap size - float maxWidth = 0.0f; - for (float f : widths) { - maxWidth = Math.max(maxWidth, f); - } - int hCount = (int) Math.ceil(Math.sqrt(height / maxWidth * length)); - int vCount = (int) Math.ceil(Math.sqrt(maxWidth / height * length)); - if (hCount * (vCount - 1) > length) { - vCount--; - } - if ((hCount - 1) * vCount > length) { - hCount--; - } - - Bitmap bitmap = Bitmap.createBitmap((int) Math.ceil(hCount * maxWidth), - (int) Math.ceil(vCount * height), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - canvas.translate(0, height - fixed); - - // Draw - int[] rects = new int[length * 4]; - int x = 0; - int y = 0; - for (int i = 0; i < length; i++) { - int offset = i * 4; - rects[offset + 0] = x; - rects[offset + 1] = y; - rects[offset + 2] = (int) widths[i]; - rects[offset + 3] = height; - - canvas.drawText(characters, i, 1, x, y, paint); - - if (i % hCount == hCount - 1) { - // The end of row - x = 0; - y += height; - } else { - x += maxWidth; - } - } - - Image image = Image.create(bitmap); - bitmap.recycle(); - if (image == null) { - return null; - } - ImageWrapper imageWrapper = new ImageWrapper(image); - if (imageWrapper.obtain()) { - return new ImageMovableTextTexture(imageWrapper, length, rects, characters, widths, height, maxWidth); - } else { - return null; - } - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/ImageSpriteTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/ImageSpriteTexture.java deleted file mode 100644 index bdc90fc1d..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/ImageSpriteTexture.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.glrenderer; - -import android.graphics.RectF; -import android.support.annotation.NonNull; - -import com.hippo.yorozuya.AssertUtils; - -public class ImageSpriteTexture extends ImageTexture { - - private final int mCount; - private final int[] mRects; - - private final RectF mTempSource = new RectF(); - private final RectF mTempTarget = new RectF(); - - public ImageSpriteTexture(@NonNull ImageWrapper image, int count, int[] rects) { - super(image); - - AssertUtils.assertEquals("rects.length must be count * 4", count * 4, rects.length); - mCount = count; - mRects = rects; - } - - public int getCount() { - return mCount; - } - - public void drawSprite(GLCanvas canvas, int index, int x, int y) { - int[] rects = mRects; - int offset = index * 4; - int sourceX = rects[offset]; - int sourceY = rects[offset + 1]; - int sourceWidth = rects[offset + 2]; - int sourceHeight = rects[offset + 3]; - mTempSource.set(sourceX, sourceY, sourceX + sourceWidth, sourceY + sourceHeight); - mTempTarget.set(x, y, x + sourceWidth, y + sourceHeight); - draw(canvas, mTempSource, mTempTarget); - } - - public void drawSprite(GLCanvas canvas, int index, int x, int y, int width, int height) { - int[] rects = mRects; - int offset = index * 4; - int sourceX = rects[offset]; - int sourceY = rects[offset + 1]; - mTempSource.set(sourceX, sourceY, sourceX + rects[offset + 2], sourceY + rects[offset + 3]); - mTempTarget.set(x, y, x + width, y + height); - draw(canvas, mTempSource, mTempTarget); - } - - public void drawSpriteMixed(GLCanvas canvas, int index, int color, float ratio, int x, int y) { - int[] rects = mRects; - int offset = index * 4; - int sourceX = rects[offset]; - int sourceY = rects[offset + 1]; - int sourceWidth = rects[offset + 2]; - int sourceHeight = rects[offset + 3]; - mTempSource.set(sourceX, sourceY, sourceX + sourceWidth, sourceY + sourceHeight); - mTempTarget.set(x, y, x + sourceWidth, y + sourceHeight); - drawMixed(canvas, color, ratio, mTempSource, mTempTarget); - } - - public void drawSpriteMixed(GLCanvas canvas, int index, int color, float ratio, - int x, int y, int width, int height) { - int[] rects = mRects; - int offset = index * 4; - int sourceX = rects[offset]; - int sourceY = rects[offset + 1]; - mTempSource.set(sourceX, sourceY, sourceX + rects[offset + 2], - sourceY + rects[offset + 3]); - mTempTarget.set(x, y, x + width, y + height); - drawMixed(canvas, color, ratio, mTempSource, mTempTarget); - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/ImageTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/ImageTexture.java deleted file mode 100644 index 72b1dfd06..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/ImageTexture.java +++ /dev/null @@ -1,677 +0,0 @@ -/* - * Copyright (C) 2015 Hippo Seven - * - * 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.hippo.gl.glrenderer; - -import android.graphics.RectF; -import android.graphics.drawable.Animatable; -import android.os.Process; -import android.os.SystemClock; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; - -import com.hippo.gl.annotation.RenderThread; -import com.hippo.gl.view.GLRoot; -import com.hippo.yorozuya.thread.InfiniteThreadExecutor; -import com.hippo.yorozuya.thread.PVLock; -import com.hippo.yorozuya.thread.PriorityThreadFactory; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.ref.WeakReference; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; - -public class ImageTexture implements Texture, Animatable { - - @IntDef({TILE_SMALL, TILE_LARGE}) - @Retention(RetentionPolicy.SOURCE) - private @interface TileType {} - - private static final int TILE_SMALL = 0; - private static final int TILE_LARGE = 1; - - private static final int SMALL_CONTENT_SIZE = 254; - private static final int SMALL_BORDER_SIZE = 1; - private static final int SMALL_TILE_SIZE = SMALL_CONTENT_SIZE + 2 * SMALL_BORDER_SIZE; - - private static final int LARGE_CONTENT_SIZE = SMALL_CONTENT_SIZE * 2; - private static final int LARGE_BORDER_SIZE = SMALL_BORDER_SIZE * 2; - private static final int LARGE_TILE_SIZE = LARGE_CONTENT_SIZE + 2 * LARGE_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 final Executor sThreadExecutor; - private static final PVLock sPVLock; - - private static Tile sSmallFreeTileHead = null; - private static Tile sLargeFreeTileHead = null; - private static final Object sFreeTileLock = new Object(); - - private final ImageWrapper mImage; - 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 boolean mOpaque; - private final RectF mSrcRect = new RectF(); - private final RectF mDestRect = new RectF(); - - private boolean mImageBusy = false; - private final AtomicBoolean mRunning = new AtomicBoolean(); - private final AtomicBoolean mFrameDirty = new AtomicBoolean(); - private final AtomicBoolean mNeedRelease = new AtomicBoolean(); - private final AtomicBoolean mReleased = new AtomicBoolean(); - - private Runnable mAnimateRunnable = null; - - private WeakReference mCallback; - - static { - sThreadExecutor = new InfiniteThreadExecutor(10 * 1000, new LinkedList(), - new PriorityThreadFactory("ImageTexture$AnimateTask", Process.THREAD_PRIORITY_BACKGROUND)); - sPVLock = new PVLock(3); - } - - public static class Uploader implements GLRoot.OnGLIdleListener { - private final ArrayDeque mTextures = - new ArrayDeque<>(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(ImageTexture 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 deque = mTextures; - synchronized (this) { - long now = SystemClock.uptimeMillis(); - long dueTime = now + UPLOAD_TILE_LIMIT; - while (now < dueTime && !deque.isEmpty()) { - ImageTexture 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 NativeTexture { - - @TileType - private int mTileType; - public int offsetX; - public int offsetY; - public ImageWrapper image; - public Tile nextFreeTile; - public int contentWidth; - public int contentHeight; - public int borderSize; - - public void setSize(@TileType int tileType, int width, int height) { - mTileType = tileType; - int tileSize; - if (tileType == TILE_SMALL) { - borderSize = SMALL_BORDER_SIZE; - tileSize = SMALL_TILE_SIZE; - } else if (tileType == TILE_LARGE) { - borderSize = LARGE_BORDER_SIZE; - tileSize = LARGE_TILE_SIZE; - } else { - throw new IllegalStateException("Not support tile type: " + tileType); - } - contentWidth = width; - contentHeight = height; - - mWidth = width + 2 * borderSize; - mHeight = height + 2 * borderSize; - mTextureWidth = tileSize; - mTextureHeight = tileSize; - } - - @Override - protected void texImage(boolean init) { - if (image != null && !image.isRecycled()) { - int w, h; - if (init) { - w = mTextureWidth; - h = mTextureHeight; - } else { - w = mWidth; - h = mHeight; - } - image.texImage(init, offsetX - borderSize, offsetY - borderSize, w, h); - } - } - - private void invalidate() { - invalidateContent(); - image = null; - } - - public void free() { - switch (mTileType) { - case TILE_SMALL: - freeSmallTile(this); - break; - case TILE_LARGE: - freeLargeTile(this); - break; - default: - throw new IllegalStateException("Not support tile type: " + mTileType); - } - } - - private static void freeSmallTile(Tile tile) { - tile.invalidate(); - synchronized (sFreeTileLock) { - tile.nextFreeTile = sSmallFreeTileHead; - sSmallFreeTileHead = tile; - } - } - - private static void freeLargeTile(Tile tile) { - tile.invalidate(); - synchronized (sFreeTileLock) { - tile.nextFreeTile = sLargeFreeTileHead; - sLargeFreeTileHead = tile; - } - } - } - - private static Tile obtainSmallTile() { - synchronized (sFreeTileLock) { - Tile result = sSmallFreeTileHead; - if (result == null) { - return new Tile(); - } else { - sSmallFreeTileHead = result.nextFreeTile; - result.nextFreeTile = null; - } - return result; - } - } - - private static Tile obtainLargeTile() { - synchronized (sFreeTileLock) { - Tile result = sLargeFreeTileHead; - if (result == null) { - return new Tile(); - } else { - sLargeFreeTileHead = result.nextFreeTile; - result.nextFreeTile = null; - } - return result; - } - } - - private class AnimateRunnable implements Runnable { - - public void doRun() { - long lastTime = System.nanoTime(); - long lastDelay = -1L; - - synchronized (mImage) { - // Check released, image busy, Need release - if (mReleased.get() || mImageBusy || mNeedRelease.get()) { - mAnimateRunnable = null; - return; - } - // Obtain image - mImageBusy = true; - } - - if (!mImage.isCompleted()) { - try { - sPVLock.p(); - } catch (InterruptedException e) { - // Ignore - } - if (!mNeedRelease.get()) { - mImage.complete(); - } - sPVLock.v(); - } - - int frameCount = mImage.getFrameCount(); - - synchronized (mImage) { - // Release image - mImageBusy = false; - // Check need release, frameCount <= 1 - if (mNeedRelease.get() || frameCount <= 1) { - mAnimateRunnable = null; - return; - } - } - - for (;;) { - // Obtain - synchronized (mImage) { - // Check released, image busy, Need release, not running - if (mReleased.get() || mImageBusy || mNeedRelease.get() || !mRunning.get()) { - mAnimateRunnable = null; - return; - } - // Obtain image - mImageBusy = true; - } - - mImage.advance(); - long delay = mImage.getDelay(); - long time = System.nanoTime(); - if (-1L != lastDelay) { - delay -= (time - lastTime) / 1000000 - lastDelay; - } - lastTime = time; - lastDelay = delay; - mFrameDirty.lazySet(true); - invalidateSelf(); - - synchronized (mImage) { - // Release image - mImageBusy = false; - } - - if (delay > 0) { - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - // Ignore - } - } - } - } - - @Override - public void run() { - doRun(); - - while (mNeedRelease.get()) { - // Obtain - synchronized (mImage) { - // Check released - if (mReleased.get()) { - break; - } - // Check image busy - if (mImageBusy) { - // Image is busy, means it is recycling - break; - } - // Obtain image - mImageBusy = true; - } - - mImage.release(); - mReleased.lazySet(true); - - synchronized (mImage) { - // Release image - mImageBusy = false; - } - } - } - } - - /** - * Call {@link ImageWrapper#obtain()} first - */ - public ImageTexture(@NonNull ImageWrapper image) { - mImage = image; - int width = mWidth = image.getWidth(); - int height = mHeight = image.getHeight(); - boolean opaque = mOpaque = image.isOpaque(); - ArrayList list = new ArrayList<>(); - - for (int x = 0; x < width; x += LARGE_CONTENT_SIZE) { - for (int y = 0; y < height; y += LARGE_CONTENT_SIZE) { - int w = Math.min(LARGE_CONTENT_SIZE, width - x); - int h = Math.min(LARGE_CONTENT_SIZE, height - y); - - if (w <= SMALL_CONTENT_SIZE) { - Tile tile = obtainSmallTile(); - tile.offsetX = x; - tile.offsetY = y; - tile.image = image; - tile.setSize(TILE_SMALL, w, Math.min(SMALL_CONTENT_SIZE, h)); - tile.setOpaque(opaque); - list.add(tile); - - int nextHeight = h - SMALL_CONTENT_SIZE; - if (nextHeight > 0) { - Tile nextTile = obtainSmallTile(); - nextTile.offsetX = x; - nextTile.offsetY = y + SMALL_CONTENT_SIZE; - nextTile.image = image; - nextTile.setSize(TILE_SMALL, w, nextHeight); - nextTile.setOpaque(opaque); - list.add(nextTile); - } - } else if (h <= SMALL_CONTENT_SIZE) { - Tile tile = obtainSmallTile(); - tile.offsetX = x; - tile.offsetY = y; - tile.image = image; - tile.setSize(TILE_SMALL, Math.min(SMALL_CONTENT_SIZE, w), h); - tile.setOpaque(opaque); - list.add(tile); - - int nextWidth = w - SMALL_CONTENT_SIZE; - if (nextWidth > 0) { - Tile nextTile = obtainSmallTile(); - nextTile.offsetX = x + SMALL_CONTENT_SIZE; - nextTile.offsetY = y; - nextTile.image = image; - nextTile.setSize(TILE_SMALL, nextWidth, h); - nextTile.setOpaque(opaque); - list.add(nextTile); - } - } else { - Tile tile = obtainLargeTile(); - tile.offsetX = x; - tile.offsetY = y; - tile.image = image; - tile.setSize(TILE_LARGE, w, h); - tile.setOpaque(opaque); - list.add(tile); - } - } - } - - mTiles = list.toArray(new Tile[list.size()]); - - if (!mImage.isCompleted()) { - Runnable runnable = new AnimateRunnable(); - mAnimateRunnable = runnable; - sThreadExecutor.execute(runnable); - } - } - - public final void setCallback(Callback cb) { - mCallback = new WeakReference<>(cb); - } - - public Callback getCallback() { - if (mCallback != null) { - return mCallback.get(); - } - return null; - } - - public void invalidateSelf() { - final Callback callback = getCallback(); - if (callback != null) { - callback.invalidateImageTexture(this); - } - } - - @Override - public void start() { - if (mReleased.get() || mNeedRelease.get() || (mImage.isCompleted() && mImage.getFrameCount() <= 1) || - mRunning.get()) { - return; - } - - mRunning.lazySet(true); - - synchronized (mImage) { - if (mAnimateRunnable == null) { - Runnable runnable = new AnimateRunnable(); - mAnimateRunnable = runnable; - sThreadExecutor.execute(runnable); - } - } - } - - @Override - public void stop() { - mRunning.lazySet(false); - } - - @Override - public boolean isRunning() { - return mRunning.get(); - } - - 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.image != 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; - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } - - // 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); - } - - @RenderThread - private void syncFrame() { - if (mFrameDirty.getAndSet(false)) { - // invalid tiles - for (Tile tile : mTiles) { - tile.invalidateContent(); - } - } - } - - @Override - public void draw(GLCanvas canvas, int x, int y) { - draw(canvas, x, y, mWidth, mHeight); - } - - // Draws the texture on to the specified rectangle. - @Override - public void draw(GLCanvas canvas, int x, int y, int w, int h) { - RectF src = mSrcRect; - RectF dest = mDestRect; - float scaleX = (float) w / mWidth; - float scaleY = (float) h / mHeight; - - syncFrame(); - for (Tile t : mTiles) { - 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(t.borderSize - t.offsetX, t.borderSize - t.offsetY); - canvas.drawTexture(t, src, dest); - } - } - - // Draws a sub region of this texture on to the specified rectangle. - @Override - 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(); - - syncFrame(); - for (Tile t : mTiles) { - 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(t.borderSize - t.offsetX, t.borderSize - t.offsetY); - canvas.drawTexture(t, src, dest); - } - } - - // 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; - - syncFrame(); - for (Tile t : mTiles) { - 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(t.borderSize - t.offsetX, t.borderSize - t.offsetY); - canvas.drawMixed(t, color, ratio, src, dest); - } - } - - public void drawMixed(GLCanvas canvas, int color, float ratio, - 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(); - - syncFrame(); - for (Tile t : mTiles) { - 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(t.borderSize - t.offsetX, t.borderSize - t.offsetY); - canvas.drawMixed(t, color, ratio, src, dest); - } - } - - @Override - public boolean isOpaque() { - return mOpaque; - } - - public boolean isReady() { - return mUploadIndex == mTiles.length; - } - - public void recycle() { - mRunning.lazySet(false); - - for (Tile mTile : mTiles) { - mTile.free(); - } - - boolean releaseNow; - - synchronized (mImage) { - if (!mImageBusy) { - releaseNow = true; - mImageBusy = true; - } else { - releaseNow = false; - mNeedRelease.set(true); - } - } - - if (releaseNow) { - mImage.release(); - mReleased.set(true); - synchronized (mImage) { - mImageBusy = false; - } - } - } - - public interface Callback { - void invalidateImageTexture(ImageTexture who); - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/ImageWrapper.java b/app/src/main/java/com/hippo/gl/glrenderer/ImageWrapper.java deleted file mode 100644 index 4641f4d56..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/ImageWrapper.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.glrenderer; - -import android.graphics.Bitmap; -import android.support.annotation.NonNull; - -import com.hippo.image.Image; - -/** - * A wrapper for {@link Image}. It is useful for multi-usage. - * It handles image recycle automatically. - */ -public class ImageWrapper { - - private final Image mImage; - private int mReferences; - - /** - * Create ImageWrapper - * - * @param image the image should not be obtained or recycled. - */ - public ImageWrapper(@NonNull Image image) { - mImage = image; - } - - /** - * Obtain the image - * - * @return false for the image is recycled and obtain failed - */ - public synchronized boolean obtain() { - if (mImage.isRecycled()) { - return false; - } else { - ++mReferences; - return true; - } - } - - /** - * Release the image - */ - public synchronized void release() { - --mReferences; - if (mReferences <= 0 && !mImage.isRecycled()) { - mImage.recycle(); - } - } - - /** - * @see Image#getFormat() - */ - public int getFormat() { - return mImage.getFormat(); - } - - /** - * @see Image#getFormat() - */ - public int getWidth() { - return mImage.getWidth(); - } - - /** - * @see Image#getHeight() - */ - public int getHeight() { - return mImage.getHeight(); - } - - /** - * @see Image#complete() - */ - public boolean complete() { - synchronized (mImage) { - return mImage.complete(); - } - } - - /** - * @see Image#isCompleted() - */ - public boolean isCompleted() { - return mImage.isCompleted(); - } - - /** - * @see Image#render(int, int, Bitmap, int, int, int, int, boolean, int) - */ - public void render(int srcX, int srcY, Bitmap dst, int dstX, int dstY, - int width, int height, boolean fillBlank, int defaultColor) { - mImage.render(srcX, srcY, dst, dstX, dstY, - width, height, fillBlank, defaultColor); - } - - /** - * @see Image#texImage(boolean, int, int, int, int) - */ - public void texImage(boolean init, int offsetX, int offsetY, int width, int height) { - mImage.texImage(init, offsetX, offsetY, width, height); - } - - /** - * @see Image#advance() - */ - public void advance() { - mImage.advance(); - } - - /** - * @see Image#getDelay() - */ - public int getDelay() { - return mImage.getDelay(); - } - - /** - * @see Image#getFrameCount() - */ - public int getFrameCount() { - return mImage.getFrameCount(); - } - - /** - * @see Image#isOpaque() - */ - public boolean isOpaque() { - return mImage.isOpaque(); - } - - /** - * @see Image#isRecycled() - */ - public boolean isRecycled() { - return mImage.isRecycled(); - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/MovableTextTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/MovableTextTexture.java deleted file mode 100644 index 60e970f79..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/MovableTextTexture.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.hippo.gl.glrenderer; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Typeface; - -import java.util.Arrays; - -// TODO support multiline -/** - * Works like movable type.
- *
- * Only support single line now - */ -public final class MovableTextTexture extends SpriteTexture { - - private final char[] mCharacters; - private final float[] mWidths; - private final float mHeight; - private final float mMaxWidth; - - private MovableTextTexture(Bitmap bitmap, int count, int[] rects, char[] characters, - float[] widths, float height, float maxWidth) { - super(bitmap, false, count, rects); - mCharacters = characters; - mWidths = widths; - mHeight = height; - mMaxWidth = maxWidth; - } - - public int[] getTextIndexes(String text) { - char[] characters = mCharacters; - - int length = text.length(); - int[] indexes = new int[length]; - for (int i = 0; i < length; i++) { - char ch = text.charAt(i); - indexes[i] = Arrays.binarySearch(characters, ch); - } - - return indexes; - } - - public float getTextWidth(String text) { - char[] characters = mCharacters; - float[] widths = mWidths; - float width = 0.0f; - - for (int i = 0, n = text.length(); i < n; i++) { - char ch = text.charAt(i); - int index = Arrays.binarySearch(characters, ch); - if (index >= 0) { - width += widths[index]; - } else { - width += mMaxWidth; - } - } - - return width; - } - - public float getTextWidth(int[] indexes) { - float[] widths = mWidths; - float width = 0.0f; - int length = indexes.length; - for (int i = 0; i < length; i++) { - int index = indexes[i]; - if (index >= 0) { - width += widths[index]; - } else { - width += mMaxWidth; - } - } - - return width; - } - - public float getMaxWidth() { - return mMaxWidth; - } - - public float getTextHeight() { - return mHeight; - } - - public void drawText(GLCanvas canvas, String text, int x, int y) { - char[] characters = mCharacters; - float[] widths = mWidths; - - for (int i = 0, n = text.length(); i < n; i++) { - char ch = text.charAt(i); - int index = Arrays.binarySearch(characters, ch); - if (index >= 0) { - drawSprite(canvas, index, x, y); - x += widths[index]; - } else { - x += mMaxWidth; - } - } - } - - public void drawText(GLCanvas canvas, int[] indexes, int x, int y) { - float[] widths = mWidths; - - for (int i = 0, n = indexes.length; i < n; i++) { - int index = indexes[i]; - if (index >= 0) { - drawSprite(canvas, index, x, y); - x += widths[index]; - } else { - x += mMaxWidth; - } - } - } - - /** - * Create a TextTexture to draw text - * - * @param typeface the typeface - * @param size text size - * @param characters all Characters - * @return the TextTexture - */ - public static MovableTextTexture create(Typeface typeface, int size, int color, char[] characters) { - Paint paint = new Paint(); - paint.setAntiAlias(true); - paint.setTextSize(size); - paint.setColor(color); - paint.setTypeface(typeface); - - Paint.FontMetricsInt fmi = paint.getFontMetricsInt(); - int fixed = fmi.bottom; - int height = fmi.bottom - fmi.top; - - int length = characters.length; - float[] widths = new float[length]; - paint.getTextWidths(characters, 0, length, widths); - - // Calculate bitmap size - float maxWidth = 0.0f; - for (float f : widths) { - maxWidth = Math.max(maxWidth, f); - } - int hCount = (int) Math.ceil(Math.sqrt(height / maxWidth * length)); - int vCount = (int) Math.ceil(Math.sqrt(maxWidth / height * length)); - if (hCount * (vCount - 1) > length) { - vCount--; - } - if ((hCount - 1) * vCount > length) { - hCount--; - } - - Bitmap bitmap = Bitmap.createBitmap((int) Math.ceil(hCount * maxWidth), - (int) Math.ceil(vCount * height), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - canvas.translate(0, height - fixed); - - // Draw - int[] rects = new int[length * 4]; - int x = 0; - int y = 0; - for (int i = 0; i < length; i++) { - int offset = i * 4; - rects[offset + 0] = x; - rects[offset + 1] = y; - rects[offset + 2] = (int) widths[i]; - rects[offset + 3] = height; - - canvas.drawText(characters, i, 1, x, y, paint); - - if (i % hCount == hCount - 1) { - // The end of row - x = 0; - y += height; - } else { - x += maxWidth; - } - } - - return new MovableTextTexture(bitmap, length, rects, characters, widths, height, maxWidth); - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/MultiLineTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/MultiLineTexture.java deleted file mode 100644 index a357401ed..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/MultiLineTexture.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.hippo.gl.glrenderer; - -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/app/src/main/java/com/hippo/gl/glrenderer/NativeTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/NativeTexture.java deleted file mode 100644 index 268e30143..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/NativeTexture.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.glrenderer; - -import android.opengl.GLES20; -import android.util.Log; - -import javax.microedition.khronos.opengles.GL11; - -public abstract class NativeTexture extends BasicTexture { - - private static final String TAG = NativeTexture.class.getSimpleName(); - - private boolean mContentValid = true; - - private boolean mOpaque = true; - - public void invalidateContent() { - mContentValid = false; - } - - public static void checkError() { - int error = GLES20.glGetError(); - if (error != 0) { - Throwable t = new Throwable(); - Log.e(TAG, "GL error: " + error, t); - } - } - - protected abstract void texImage(boolean init); - - private void uploadToCanvas(GLCanvas canvas) { - // Get id - mId = canvas.getGLId().generateTexture(); - - // Prepare - canvas.setTextureParameters(this); - - // Call glTexImage2D - GLES20.glBindTexture(getTarget(), mId); - checkError(); - texImage(true); - checkError(); - - setAssociatedCanvas(canvas); - mState = STATE_LOADED; - mContentValid = true; - } - - public void updateContent(GLCanvas canvas) { - if (!isLoaded()) { - uploadToCanvas(canvas); - } else if (!mContentValid) { - // Call glTexSubImage2D - GLES20.glBindTexture(getTarget(), mId); - checkError(); - texImage(false); - checkError(); - mContentValid = true; - } - } - - /** - * Whether the content on GPU is valid. - */ - public boolean isContentValid() { - return isLoaded() && mContentValid; - } - - @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; - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/NinePatchChunk.java b/app/src/main/java/com/hippo/gl/glrenderer/NinePatchChunk.java deleted file mode 100644 index d1c5845f9..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/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.hippo.gl.glrenderer; - -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; - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/NinePatchTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/NinePatchTexture.java deleted file mode 100644 index b616aacf7..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/NinePatchTexture.java +++ /dev/null @@ -1,424 +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.hippo.gl.glrenderer; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Rect; - -import com.hippo.yorozuya.MathUtils; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -// 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 mInstanceCache - = new SmallCache(); - - 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 { - 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 mXyBufferName = -1; - private int mUvBufferName; - private int mIndexBufferName; - - 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. - * - *
-     *                      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
-     * 
- * - * @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 = MathUtils.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) { - mXyBufferName = canvas.uploadBuffer(mXyBuffer); - mUvBufferName = canvas.uploadBuffer(mUvBuffer); - mIndexBufferName = canvas.uploadBuffer(mIndexBuffer); - - // These buffers are never used again. - mXyBuffer = null; - mUvBuffer = null; - mIndexBuffer = null; - } - - public void draw(GLCanvas canvas, NinePatchTexture tex, int x, int y) { - if (mXyBufferName == -1) { - prepareBuffers(canvas); - } - canvas.drawMesh(tex, x, y, mXyBufferName, mUvBufferName, mIndexBufferName, mIdxCount); - } - - public void recycle(GLCanvas canvas) { - if (mXyBuffer == null) { - canvas.deleteBuffer(mXyBufferName); - canvas.deleteBuffer(mUvBufferName); - canvas.deleteBuffer(mIndexBufferName); - mXyBufferName = -1; - } - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/RawTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/RawTexture.java deleted file mode 100644 index a58c6cc6d..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/RawTexture.java +++ /dev/null @@ -1,73 +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.hippo.gl.glrenderer; - -import android.util.Log; - -import javax.microedition.khronos.opengles.GL11; - -public class RawTexture extends BasicTexture { - private static final String TAG = "RawTexture"; - - private final boolean mOpaque; - private boolean mIsFlipped; - - public RawTexture(int width, int height, boolean opaque) { - mOpaque = opaque; - setSize(width, height); - } - - @Override - public boolean isOpaque() { - return mOpaque; - } - - @Override - public boolean isFlippedVertically() { - return mIsFlipped; - } - - public void setIsFlippedVertically(boolean isFlipped) { - mIsFlipped = isFlipped; - } - - protected void prepare(GLCanvas canvas) { - GLId glId = canvas.getGLId(); - mId = glId.generateTexture(); - canvas.initializeTextureSize(this, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE); - canvas.setTextureParameters(this); - 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/app/src/main/java/com/hippo/gl/glrenderer/ResourceTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/ResourceTexture.java deleted file mode 100644 index 3aaf1e317..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/ResourceTexture.java +++ /dev/null @@ -1,53 +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.hippo.gl.glrenderer; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - -import junit.framework.Assert; - -// 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) { - Assert.assertNotNull(context); - mContext = 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/app/src/main/java/com/hippo/gl/glrenderer/SpriteTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/SpriteTexture.java deleted file mode 100644 index c470e54dc..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/SpriteTexture.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.hippo.gl.glrenderer; - -import android.graphics.Bitmap; -import android.graphics.RectF; - -import com.hippo.yorozuya.AssertUtils; - -public class SpriteTexture extends TiledTexture { - - private final int mCount; - private final int[] mRects; - - private final RectF mTempSource = new RectF(); - private final RectF mTempTarget = new RectF(); - - public SpriteTexture(Bitmap bitmap, boolean isOpaque, int count, int[] rects) { - super(bitmap, isOpaque); - - AssertUtils.assertEquals("rects.length must be count * 4", count * 4, rects.length); - mCount = count; - mRects = rects; - } - - public int getCount() { - return mCount; - } - - public void drawSprite(GLCanvas canvas, int index, int x, int y) { - int[] rects = mRects; - int offset = index * 4; - int sourceX = rects[offset]; - int sourceY = rects[offset + 1]; - int sourceWidth = rects[offset + 2]; - int sourceHeight = rects[offset + 3]; - mTempSource.set(sourceX, sourceY, sourceX + sourceWidth, sourceY + sourceHeight); - mTempTarget.set(x, y, x + sourceWidth, y + sourceHeight); - draw(canvas, mTempSource, mTempTarget); - } - - public void drawSprite(GLCanvas canvas, int index, int x, int y, int width, int height) { - int[] rects = mRects; - int offset = index * 4; - int sourceX = rects[offset]; - int sourceY = rects[offset + 1]; - mTempSource.set(sourceX, sourceY, sourceX + rects[offset + 2], sourceY + rects[offset + 3]); - mTempTarget.set(x, y, x + width, y + height); - draw(canvas, mTempSource, mTempTarget); - } - - public void drawSpriteMixed(GLCanvas canvas, int index, int color, float ratio, int x, int y) { - int[] rects = mRects; - int offset = index * 4; - int sourceX = rects[offset]; - int sourceY = rects[offset + 1]; - int sourceWidth = rects[offset + 2]; - int sourceHeight = rects[offset + 3]; - mTempSource.set(sourceX, sourceY, sourceX + sourceWidth, sourceY + sourceHeight); - mTempTarget.set(x, y, x + sourceWidth, y + sourceHeight); - drawMixed(canvas, color, ratio, mTempSource, mTempTarget); - } - - public void drawSpriteMixed(GLCanvas canvas, int index, int color, float ratio, - int x, int y, int width, int height) { - int[] rects = mRects; - int offset = index * 4; - int sourceX = rects[offset]; - int sourceY = rects[offset + 1]; - mTempSource.set(sourceX, sourceY, sourceX + rects[offset + 2], - sourceY + rects[offset + 3]); - mTempTarget.set(x, y, x + width, y + height); - drawMixed(canvas, color, ratio, mTempSource, mTempTarget); - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/StringTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/StringTexture.java deleted file mode 100644 index 609e79509..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/StringTexture.java +++ /dev/null @@ -1,87 +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.hippo.gl.glrenderer; - -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; - -// 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. -public 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) Math.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/app/src/main/java/com/hippo/gl/glrenderer/Texture.java b/app/src/main/java/com/hippo/gl/glrenderer/Texture.java deleted file mode 100644 index 23a5ddf8f..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/Texture.java +++ /dev/null @@ -1,47 +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.hippo.gl.glrenderer; - - -import android.graphics.RectF; - -// 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 { - int getWidth(); - int getHeight(); - void draw(GLCanvas canvas, int x, int y); - void draw(GLCanvas canvas, int x, int y, int w, int h); - void draw(GLCanvas canvas, RectF source, RectF target); - boolean isOpaque(); -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/TextureUploader.java b/app/src/main/java/com/hippo/gl/glrenderer/TextureUploader.java deleted file mode 100644 index a3f72f022..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/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.hippo.gl.glrenderer; - -import com.hippo.gl.view.GLRoot; - -import java.util.ArrayDeque; - -public class TextureUploader implements GLRoot.OnGLIdleListener { - private static final int INIT_CAPACITY = 64; - private static final int QUOTA_PER_FRAME = 1; - - private final ArrayDeque mFgTextures = - new ArrayDeque<>(INIT_CAPACITY); - private final ArrayDeque mBgTextures = - new ArrayDeque<>(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 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/app/src/main/java/com/hippo/gl/glrenderer/TiledTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/TiledTexture.java deleted file mode 100644 index 4ee23c94a..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/TiledTexture.java +++ /dev/null @@ -1,373 +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.hippo.gl.glrenderer; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.RectF; -import android.os.SystemClock; - -import com.hippo.gl.view.GLRoot; - -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 final Bitmap sUploadBitmap; - private static final Canvas sCanvas; - private static final Paint sBitmapPaint; - private static final 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(); - - static { - sUploadBitmap = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE, Bitmap.Config.ARGB_8888); - sCanvas = new Canvas(sUploadBitmap); - sBitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); - sBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); - sPaint = new Paint(); - sPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); - sPaint.setColor(Color.TRANSPARENT); - } - - public static class Uploader implements GLRoot.OnGLIdleListener { - private final ArrayDeque mTextures = - new ArrayDeque<>(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 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() { - // make a local copy of the reference to the bitmap, - // since it might be null'd in a different thread. b/8694871 - Bitmap localBitmapRef = bitmap; - bitmap = null; - - if (localBitmapRef != null) { - int x = BORDER_SIZE - offsetX; - int y = BORDER_SIZE - offsetY; - int r = localBitmapRef.getWidth() + x; - int b = localBitmapRef.getHeight() + y; - sCanvas.drawBitmap(localBitmapRef, x, y, sBitmapPaint); - localBitmapRef = 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, boolean isOpaque) { - mWidth = bitmap.getWidth(); - mHeight = bitmap.getHeight(); - ArrayList list = new ArrayList<>(); - - 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)); - tile.setOpaque(isOpaque); - 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]); - } - } - } - - // 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); - } - } - } - - public void drawMixed(GLCanvas canvas, int color, float ratio, - 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.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. - @Override - 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/app/src/main/java/com/hippo/gl/glrenderer/UploadedTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/UploadedTexture.java deleted file mode 100644 index 79ed2dfaf..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/UploadedTexture.java +++ /dev/null @@ -1,296 +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.hippo.gl.glrenderer; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.opengl.GLUtils; - -import junit.framework.Assert; - -import java.util.HashMap; - -import javax.microedition.khronos.opengles.GL11; - -// 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(). -public 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 final HashMap sBorderLines = - new HashMap<>(); - private static final 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(); - if (mWidth == UNSPECIFIED) { - int w = mBitmap.getWidth() + mBorder * 2; - int h = mBitmap.getHeight() + mBorder * 2; - setSize(w, h); - } - } - return mBitmap; - } - - private void freeBitmap() { - Assert.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); - - public 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.texSubImage2D(this, mBorder, mBorder, bitmap, format, type); - freeBitmap(); - mContentValid = true; - } - } - - public static void resetUploadLimit() { - sUploadedCount = 0; - } - - public static boolean uploadLimitReached() { - return sUploadedCount > UPLOAD_LIMIT; - } - - private void uploadToCanvas(GLCanvas canvas) { - - Bitmap bitmap = getBitmap(); - if (bitmap != null) { - try { - int bWidth = bitmap.getWidth(); - int bHeight = bitmap.getHeight(); - int texWidth = getTextureWidth(); - int texHeight = getTextureHeight(); - - Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight); - - // Upload the bitmap to a new texture. - mId = canvas.getGLId().generateTexture(); - canvas.setTextureParameters(this); - - if (bWidth == texWidth && bHeight == texHeight) { - canvas.initializeTexture(this, bitmap); - } else { - int format = GLUtils.getInternalFormat(bitmap); - int type = GLUtils.getType(bitmap); - Config config = bitmap.getConfig(); - - canvas.initializeTextureSize(this, format, type); - canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type); - - if (mBorder > 0) { - // Left border - Bitmap line = getBorderLine(true, config, texHeight); - canvas.texSubImage2D(this, 0, 0, line, format, type); - - // Top border - line = getBorderLine(false, config, texWidth); - canvas.texSubImage2D(this, 0, 0, line, format, type); - } - - // Right border - if (mBorder + bWidth < texWidth) { - Bitmap line = getBorderLine(true, config, texHeight); - canvas.texSubImage2D(this, mBorder + bWidth, 0, line, format, type); - } - - // Bottom border - if (mBorder + bHeight < texHeight) { - Bitmap line = getBorderLine(false, config, texWidth); - canvas.texSubImage2D(this, 0, mBorder + bHeight, line, format, type); - } - } - } finally { - freeBitmap(); - } - // Update texture state. - setAssociatedCanvas(canvas); - 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(); - } -} diff --git a/app/src/main/java/com/hippo/gl/glrenderer/XmlResourceTexture.java b/app/src/main/java/com/hippo/gl/glrenderer/XmlResourceTexture.java deleted file mode 100644 index 9c8afc120..000000000 --- a/app/src/main/java/com/hippo/gl/glrenderer/XmlResourceTexture.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2015 Hippo Seven - * - * 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.hippo.gl.glrenderer; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.support.annotation.DrawableRes; -import android.support.v4.content.ContextCompat; - -public class XmlResourceTexture extends UploadedTexture { - - private final Context mContext; - private final int mResId; - private int mWidth; - private int mHeight; - - public XmlResourceTexture(Context context, @DrawableRes int resId) { - mContext = context; - mResId = resId; - setOpaque(false); - } - - public void setBound(int width, int height) { - mWidth = width; - mHeight = height; - invalidateContent(); - } - - @Override - protected Bitmap onGetBitmap() { - Drawable drawable = ContextCompat.getDrawable(mContext, mResId); - - int width = mWidth; - int height = mHeight; - if (width <= 0) { - width = drawable.getIntrinsicWidth(); - } - if (height <= 0) { - height = drawable.getIntrinsicHeight(); - } - if (width <= 0) { - width = 1; - } - if (height <= 0) { - height = 1; - } - - drawable.setBounds(0, 0, width, height); - - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - drawable.draw(canvas); - - return bitmap; - } - - @Override - protected void onFreeBitmap(Bitmap bitmap) { - if (!inFinalizer()) { - bitmap.recycle(); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/util/ApiHelper.java b/app/src/main/java/com/hippo/gl/util/ApiHelper.java deleted file mode 100644 index 5cb3dd856..000000000 --- a/app/src/main/java/com/hippo/gl/util/ApiHelper.java +++ /dev/null @@ -1,234 +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.hippo.gl.util; - -import android.app.admin.DevicePolicyManager; -import android.content.ComponentName; -import android.hardware.Camera; -import android.os.Build; -import android.provider.MediaStore.MediaColumns; -import android.view.View; -import android.view.WindowManager; - -import java.lang.reflect.Field; - -public class ApiHelper { - public interface VERSION_CODES { - // These value are copied from Build.VERSION_CODES - int GINGERBREAD_MR1 = 10; - int HONEYCOMB = 11; - int HONEYCOMB_MR1 = 12; - int HONEYCOMB_MR2 = 13; - int ICE_CREAM_SANDWICH = 14; - int ICE_CREAM_SANDWICH_MR1 = 15; - int JELLY_BEAN = 16; - int JELLY_BEAN_MR1 = 17; - int JELLY_BEAN_MR2 = 18; - } - - public static final boolean AT_LEAST_16 = Build.VERSION.SDK_INT >= 16; - - public static final boolean USE_888_PIXEL_FORMAT = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean ENABLE_PHOTO_EDITOR = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE = - hasField(View.class, "SYSTEM_UI_FLAG_LAYOUT_STABLE"); - - public static final boolean HAS_VIEW_SYSTEM_UI_FLAG_HIDE_NAVIGATION = - hasField(View.class, "SYSTEM_UI_FLAG_HIDE_NAVIGATION"); - - public static final boolean HAS_MEDIA_COLUMNS_WIDTH_AND_HEIGHT = - hasField(MediaColumns.class, "WIDTH"); - - public static final boolean HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_REUSING_BITMAP_IN_BITMAP_FACTORY = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_SET_BEAM_PUSH_URIS = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_SET_DEFALT_BUFFER_SIZE = hasMethod( - "android.graphics.SurfaceTexture", "setDefaultBufferSize", - int.class, int.class); - - public static final boolean HAS_RELEASE_SURFACE_TEXTURE = hasMethod( - "android.graphics.SurfaceTexture", "release"); - - public static final boolean HAS_SURFACE_TEXTURE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_MTP = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1; - - public static final boolean HAS_AUTO_FOCUS_MOVE_CALLBACK = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_REMOTE_VIEWS_SERVICE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_INTENT_EXTRA_LOCAL_ONLY = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_SET_SYSTEM_UI_VISIBILITY = - hasMethod(View.class, "setSystemUiVisibility", int.class); - - public static final boolean HAS_FACE_DETECTION; - static { - boolean hasFaceDetection = false; - try { - Class listenerClass = Class.forName( - "android.hardware.Camera$FaceDetectionListener"); - hasFaceDetection = - hasMethod(Camera.class, "setFaceDetectionListener", listenerClass) && - hasMethod(Camera.class, "startFaceDetection") && - hasMethod(Camera.class, "stopFaceDetection") && - hasMethod(Camera.Parameters.class, "getMaxNumDetectedFaces"); - } catch (Throwable t) { - } - HAS_FACE_DETECTION = hasFaceDetection; - } - - public static final boolean HAS_GET_CAMERA_DISABLED = - hasMethod(DevicePolicyManager.class, "getCameraDisabled", ComponentName.class); - - public static final boolean HAS_MEDIA_ACTION_SOUND = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_TIME_LAPSE_RECORDING = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_ZOOM_WHEN_RECORDING = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_CAMERA_FOCUS_AREA = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_CAMERA_METERING_AREA = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_MOTION_EVENT_TRANSFORM = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_EFFECTS_RECORDING = false; - - // "Background" filter does not have "context" input port in jelly bean. - public static final boolean HAS_EFFECTS_RECORDING_CONTEXT_INPUT = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1; - - public static final boolean HAS_GET_SUPPORTED_VIDEO_SIZE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_SET_ICON_ATTRIBUTE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_MEDIA_PROVIDER_FILES_TABLE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_SURFACE_TEXTURE_RECORDING = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_ACTION_BAR = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - // Ex: View.setTranslationX. - public static final boolean HAS_VIEW_TRANSFORM_PROPERTIES = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_CAMERA_HDR = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1; - - public static final boolean HAS_OPTIONS_IN_MUTABLE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean CAN_START_PREVIEW_IN_JPEG_CALLBACK = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_VIEW_PROPERTY_ANIMATOR = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1; - - public static final boolean HAS_POST_ON_ANIMATION = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_ANNOUNCE_FOR_ACCESSIBILITY = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_OBJECT_ANIMATION = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_GLES20_REQUIRED = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_ROTATION_ANIMATION = - hasField(WindowManager.LayoutParams.class, "rotationAnimation"); - - public static final boolean HAS_ORIENTATION_LOCK = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2; - - public static final boolean HAS_CANCELLATION_SIGNAL = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_MEDIA_MUXER = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2; - - public static final boolean HAS_DISPLAY_LISTENER = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1; - - public static int getIntFieldIfExists(Class klass, String fieldName, - Class obj, int defaultVal) { - try { - Field f = klass.getDeclaredField(fieldName); - return f.getInt(obj); - } catch (Exception e) { - return defaultVal; - } - } - - private static boolean hasField(Class klass, String fieldName) { - try { - klass.getDeclaredField(fieldName); - return true; - } catch (NoSuchFieldException e) { - return false; - } - } - - private static boolean hasMethod(String className, String methodName, - Class... parameterTypes) { - try { - Class klass = Class.forName(className); - klass.getDeclaredMethod(methodName, parameterTypes); - return true; - } catch (Throwable th) { - return false; - } - } - - private static boolean hasMethod( - Class klass, String methodName, Class ... paramTypes) { - try { - klass.getDeclaredMethod(methodName, paramTypes); - return true; - } catch (NoSuchMethodException e) { - return false; - } - } -} diff --git a/app/src/main/java/com/hippo/gl/util/GalleryUtils.java b/app/src/main/java/com/hippo/gl/util/GalleryUtils.java deleted file mode 100644 index a55d88d0c..000000000 --- a/app/src/main/java/com/hippo/gl/util/GalleryUtils.java +++ /dev/null @@ -1,58 +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.hippo.gl.util; - -import android.graphics.Color; - -import com.hippo.yorozuya.AssertError; - -public class GalleryUtils { - - private static final String TAG = "GalleryUtils"; - - public static float[] intColorToFloatARGBArray(int from) { - return new float[] { - Color.alpha(from) / 255f, - Color.red(from) / 255f, - Color.green(from) / 255f, - Color.blue(from) / 255f - }; - } - - public static int floatARGBArrayTointColor(float[] from) { - return Color.argb((int) (from[0] * 255), (int) (from[1] * 255), (int) (from[2] * 255), (int) (from[3] * 255)); - } - - // Below are used the detect using database in the render thread. It only - // works most of the time, but that's ok because it's for debugging only. - - private static volatile Thread sCurrentThread; - - public static void setRenderThread() { - sCurrentThread = Thread.currentThread(); - } - - public static boolean isRenderThread() { - return sCurrentThread == Thread.currentThread(); - } - - public static void assertInRenderThread() { - if (sCurrentThread != Thread.currentThread()) { - throw new AssertError("Should not do this in render thread"); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/util/MotionEventHelper.java b/app/src/main/java/com/hippo/gl/util/MotionEventHelper.java deleted file mode 100644 index ac757db06..000000000 --- a/app/src/main/java/com/hippo/gl/util/MotionEventHelper.java +++ /dev/null @@ -1,117 +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.hippo.gl.util; - -import android.annotation.TargetApi; -import android.graphics.Matrix; -import android.view.MotionEvent; -import android.view.MotionEvent.PointerCoords; - -public final class MotionEventHelper { - private MotionEventHelper() {} - - public static MotionEvent transformEvent(MotionEvent e, Matrix m) { - // We try to use the new transform method if possible because it uses - // less memory. - if (ApiHelper.HAS_MOTION_EVENT_TRANSFORM) { - return transformEventNew(e, m); - } else { - return transformEventOld(e, m); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) - private static MotionEvent transformEventNew(MotionEvent e, Matrix m) { - MotionEvent newEvent = MotionEvent.obtain(e); - newEvent.transform(m); - return newEvent; - } - - // This is copied from Input.cpp in the android framework. - private static MotionEvent transformEventOld(MotionEvent e, Matrix m) { - long downTime = e.getDownTime(); - long eventTime = e.getEventTime(); - int action = e.getAction(); - int pointerCount = e.getPointerCount(); - int[] pointerIds = getPointerIds(e); - PointerCoords[] pointerCoords = getPointerCoords(e); - int metaState = e.getMetaState(); - float xPrecision = e.getXPrecision(); - float yPrecision = e.getYPrecision(); - int deviceId = e.getDeviceId(); - int edgeFlags = e.getEdgeFlags(); - int source = e.getSource(); - int flags = e.getFlags(); - - // Copy the x and y coordinates into an array, map them, and copy back. - float[] xy = new float[pointerCoords.length * 2]; - for (int i = 0; i < pointerCount;i++) { - xy[2 * i] = pointerCoords[i].x; - xy[2 * i + 1] = pointerCoords[i].y; - } - m.mapPoints(xy); - for (int i = 0; i < pointerCount;i++) { - pointerCoords[i].x = xy[2 * i]; - pointerCoords[i].y = xy[2 * i + 1]; - pointerCoords[i].orientation = transformAngle( - m, pointerCoords[i].orientation); - } - - MotionEvent n = MotionEvent.obtain(downTime, eventTime, action, - pointerCount, pointerIds, pointerCoords, metaState, xPrecision, - yPrecision, deviceId, edgeFlags, source, flags); - - return n; - } - - private static int[] getPointerIds(MotionEvent e) { - int n = e.getPointerCount(); - int[] r = new int[n]; - for (int i = 0; i < n; i++) { - r[i] = e.getPointerId(i); - } - return r; - } - - private static PointerCoords[] getPointerCoords(MotionEvent e) { - int n = e.getPointerCount(); - PointerCoords[] r = new PointerCoords[n]; - for (int i = 0; i < n; i++) { - r[i] = new PointerCoords(); - e.getPointerCoords(i, r[i]); - } - return r; - } - - private static float transformAngle(Matrix m, float angleRadians) { - // Construct and transform a vector oriented at the specified clockwise - // angle from vertical. Coordinate system: down is increasing Y, right is - // increasing X. - float[] v = new float[2]; - v[0] = (float) Math.sin(angleRadians); - v[1] = (float) -Math.cos(angleRadians); - m.mapVectors(v); - - // Derive the transformed vector's clockwise angle from vertical. - float result = (float) Math.atan2(v[0], -v[1]); - if (result < -Math.PI / 2) { - result += Math.PI; - } else if (result > Math.PI / 2) { - result -= Math.PI; - } - return result; - } -} diff --git a/app/src/main/java/com/hippo/gl/view/AnimationTime.java b/app/src/main/java/com/hippo/gl/view/AnimationTime.java deleted file mode 100644 index 5ea601ec9..000000000 --- a/app/src/main/java/com/hippo/gl/view/AnimationTime.java +++ /dev/null @@ -1,45 +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.hippo.gl.view; - -import android.os.SystemClock; - -// -// The animation time should ideally be the vsync time the frame will be -// displayed, but that is an unknown time in the future. So we use the system -// time just after eglSwapBuffers (when GLSurfaceView.onDrawFrame is called) -// as a approximation. -// -public class AnimationTime { - private static volatile long sTime; - - // Sets current time as the animation time. - public static void update() { - sTime = SystemClock.uptimeMillis(); - } - - // Returns the animation time. - public static long get() { - return sTime; - } - - public static long startTime() { - sTime = SystemClock.uptimeMillis(); - return sTime; - } -} diff --git a/app/src/main/java/com/hippo/gl/view/GLRoot.java b/app/src/main/java/com/hippo/gl/view/GLRoot.java deleted file mode 100644 index d4dc4077f..000000000 --- a/app/src/main/java/com/hippo/gl/view/GLRoot.java +++ /dev/null @@ -1,55 +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.hippo.gl.view; - -import android.content.Context; -import android.graphics.Matrix; - -import com.hippo.gl.anim.CanvasAnimation; -import com.hippo.gl.glrenderer.GLCanvas; - -public interface GLRoot { - - // Listener will be called when GL is idle AND before each frame. - // Mainly used for uploading textures. - interface OnGLIdleListener { - boolean onGLIdle(GLCanvas canvas, boolean renderRequested); - } - - void addOnGLIdleListener(OnGLIdleListener listener); - void registerLaunchedAnimation(CanvasAnimation animation); - void requestRenderForced(); - void requestRender(); - void requestLayoutContentPane(); - - void lockRenderThread(); - void unlockRenderThread(); - - void setContentPane(GLView content); - void setOrientationSource(OrientationSource source); - int getDisplayRotation(); - int getCompensation(); - Matrix getCompensationMatrix(); - void freeze(); - void unfreeze(); - void setLightsOutMode(boolean enabled); - - Context getContext(); - - int getWidth(); - int getHeight(); -} diff --git a/app/src/main/java/com/hippo/gl/view/GLRootView.java b/app/src/main/java/com/hippo/gl/view/GLRootView.java deleted file mode 100644 index 3d03d5fbb..000000000 --- a/app/src/main/java/com/hippo/gl/view/GLRootView.java +++ /dev/null @@ -1,634 +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.hippo.gl.view; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Matrix; -import android.graphics.PixelFormat; -import android.os.Build; -import android.os.Parcelable; -import android.os.Process; -import android.os.SystemClock; -import android.support.annotation.NonNull; -import android.util.AttributeSet; -import android.util.Log; -import android.util.SparseArray; -import android.view.MotionEvent; -import android.view.SurfaceHolder; - -import com.hippo.gl.anim.CanvasAnimation; -import com.hippo.gl.glrenderer.BasicTexture; -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.glrenderer.GLES20Canvas; -import com.hippo.gl.glrenderer.UploadedTexture; -import com.hippo.gl.util.ApiHelper; -import com.hippo.gl.util.GalleryUtils; -import com.hippo.gl.util.MotionEventHelper; -import com.hippo.tuxiang.BestConfigChooser; -import com.hippo.tuxiang.GLSurfaceView; -import com.hippo.tuxiang.Renderer; -import com.hippo.yorozuya.AssertUtils; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; -import javax.microedition.khronos.opengles.GL11; - -// TODO Call attachToRoot and detachFromRoot in render thread -// The root component of all GLViews. The rendering is done in GL -// thread while the event handling is done in the main thread. To synchronize -// the two threads, the entry points of this package need to synchronize on the -// GLRootView instance unless it can be proved that the rendering -// thread won't access the same thing as the method. The entry points include: -// (1) The public methods of HeadUpDisplay -// (2) The public methods of CameraHeadUpDisplay -// (3) The overridden methods in GLRootView. -public class GLRootView extends GLSurfaceView - implements GLRoot { - private static final String TAG = "GLRootView"; - - private static final boolean DEBUG_FPS = false; - private int mFrameCount = 0; - private long mFrameCountingStart = 0; - - private static final boolean DEBUG_INVALIDATE = false; - private int mInvalidateColor = 0; - - private static final boolean DEBUG_DRAWING_STAT = false; - - private static final int FLAG_INITIALIZED = 1; - private static final int FLAG_NEED_LAYOUT = 2; - - private GL11 mGL; - private GLCanvas mCanvas; - private GLView mContentView; - - private OrientationSource mOrientationSource; - // mCompensation is the difference between the UI orientation on GLCanvas - // and the framework orientation. See OrientationManager for details. - private int mCompensation; - // mCompensationMatrix maps the coordinates of touch events. It is kept sync - // with mCompensation. - private final Matrix mCompensationMatrix = new Matrix(); - private int mDisplayRotation; - - private int mFlags = FLAG_NEED_LAYOUT; - private volatile boolean mRenderRequested = false; - - private final ArrayList mAnimations = - new ArrayList<>(); - - private final ArrayDeque mIdleListeners = - new ArrayDeque<>(); - - private final IdleRunner mIdleRunner = new IdleRunner(); - - private final ReentrantLock mRenderLock = new ReentrantLock(); - private final Condition mFreezeCondition = - mRenderLock.newCondition(); - private boolean mFreeze; - - private boolean mInDownState = false; - - private class GLRootRenderer implements Renderer { - - /** - * Called when the context is created, possibly after automatic destruction. - */ - @Override - public void onSurfaceCreated(GL10 gl1, EGLConfig config) { - GL11 gl = (GL11) gl1; - if (mGL != null) { - // The GL Object has changed - Log.i(TAG, "GLObject has changed from " + mGL + " to " + gl); - } - mRenderLock.lock(); - try { - mGL = gl; - mCanvas = new GLES20Canvas(); - BasicTexture.invalidateAllTextures(); - } finally { - mRenderLock.unlock(); - } - - if (DEBUG_FPS) { - setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); - } else { - setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); - } - } - - /** - * Called when the OpenGL surface is recreated without destroying the - * context. - */ - @Override - public void onSurfaceChanged(GL10 gl1, int width, int height) { - Log.i(TAG, "onSurfaceChanged: " + width + "x" + height + ", gl10: " + gl1.toString()); - Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); - GalleryUtils.setRenderThread(); - GL11 gl = (GL11) gl1; - AssertUtils.assertTrue(mGL == gl); - - mCanvas.setSize(width, height); - } - - @Override - public void onDrawFrame(GL10 gl) { - AnimationTime.update(); - - long t0 = System.nanoTime(); - - mRenderLock.lock(); - - while (mFreeze) { - mFreezeCondition.awaitUninterruptibly(); - } - - try { - onDrawFrameLocked(gl); - } finally { - mRenderLock.unlock(); - } - - long t = System.nanoTime(); - long duration = (t - t0) / 1000000; - - if (duration > 8) { - Log.v(TAG, "--- " + duration + " ---"); - } - } - - @Override - public void onSurfaceDestroyed() { - if (mContentView != null && mContentView.isAttachedToRoot()) { - mContentView.detachFromRoot(); - } - } - - @Override - public void onPause() { - if (mContentView != null) { - mContentView.pause(); - } - } - - @Override - public void onResume() { - if (mContentView != null) { - mContentView.resume(); - } - } - } - - public GLRootView(Context context) { - this(context, null); - } - - @SuppressWarnings("deprecation") - public GLRootView(Context context, AttributeSet attrs) { - super(context, attrs); - mFlags |= FLAG_INITIALIZED; - setBackgroundDrawable(null); - - final int eglContextClientVersion = 2; - setEGLContextClientVersion(eglContextClientVersion); - setEGLConfigChooser(new BestConfigChooser(eglContextClientVersion)); - setRenderer(new GLRootRenderer()); - getHolder().setFormat(PixelFormat.RGB_888); - - // Uncomment this to enable gl error check. - // setDebugFlags(DEBUG_CHECK_GL_ERROR); - } - - @Override - public void registerLaunchedAnimation(CanvasAnimation animation) { - // Register the newly launched animation so that we can set the start - // time more precisely. (Usually, it takes much longer for first - // rendering, so we set the animation start time as the time we - // complete rendering) - mAnimations.add(animation); - } - - @Override - public void addOnGLIdleListener(OnGLIdleListener listener) { - synchronized (mIdleListeners) { - mIdleListeners.addLast(listener); - if (mCanvas != null) { - // Wait for onSurfaceCreated - mIdleRunner.enable(); - } - } - } - - @Override - public void setContentPane(GLView content) { - if (mContentView == content) return; - if (mContentView != null) { - if (mInDownState) { - long now = SystemClock.uptimeMillis(); - MotionEvent cancelEvent = MotionEvent.obtain( - now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); - mContentView.dispatchTouchEvent(cancelEvent); - cancelEvent.recycle(); - mInDownState = false; - } - mContentView.detachFromRoot(); - BasicTexture.yieldAllTextures(); - } - mContentView = content; - if (content != null) { - content.attachToRoot(this); - requestLayoutContentPane(); - } - } - - @Override - public void requestRenderForced() { - superRequestRender(); - } - - @Override - public void requestRender() { - if (DEBUG_INVALIDATE) { - StackTraceElement e = Thread.currentThread().getStackTrace()[4]; - String caller = e.getFileName() + ":" + e.getLineNumber() + " "; - Log.d(TAG, "invalidate: " + caller); - } - if (mRenderRequested) return; - mRenderRequested = true; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - postOnAnimation(mRequestRenderOnAnimationFrame); - } else { - super.requestRender(); - } - } - - private final Runnable mRequestRenderOnAnimationFrame = new Runnable() { - @Override - public void run() { - superRequestRender(); - } - }; - - private void superRequestRender() { - super.requestRender(); - } - - @Override - public void requestLayoutContentPane() { - mRenderLock.lock(); - try { - if (mContentView == null || (mFlags & FLAG_NEED_LAYOUT) != 0) return; - - // "View" system will invoke onLayout() for initialization(bug ?), we - // have to ignore it since the GLThread is not ready yet. - if ((mFlags & FLAG_INITIALIZED) == 0) return; - - mFlags |= FLAG_NEED_LAYOUT; - requestRender(); - } finally { - mRenderLock.unlock(); - } - } - - private void layoutContentPane() { - mFlags &= ~FLAG_NEED_LAYOUT; - - int w = getWidth(); - int h = getHeight(); - int displayRotation; - int compensation; - - // Get the new orientation values - if (mOrientationSource != null) { - displayRotation = mOrientationSource.getDisplayRotation(); - compensation = mOrientationSource.getCompensation(); - } else { - displayRotation = 0; - compensation = 0; - } - - if (mCompensation != compensation) { - mCompensation = compensation; - if (mCompensation % 180 != 0) { - mCompensationMatrix.setRotate(mCompensation); - // move center to origin before rotation - mCompensationMatrix.preTranslate(-w / 2, -h / 2); - // align with the new origin after rotation - mCompensationMatrix.postTranslate(h / 2, w / 2); - } else { - mCompensationMatrix.setRotate(mCompensation, w / 2, h / 2); - } - } - mDisplayRotation = displayRotation; - - // Do the actual layout. - if (mCompensation % 180 != 0) { - int tmp = w; - w = h; - h = tmp; - } - Log.i(TAG, "layout content pane " + w + "x" + h + " (compensation " + mCompensation + ")"); - if (mContentView != null && w != 0 && h != 0) { - mContentView.measure(GLView.MeasureSpec.makeMeasureSpec(w, GLView.MeasureSpec.EXACTLY), - GLView.MeasureSpec.makeMeasureSpec(h, GLView.MeasureSpec.EXACTLY)); - mContentView.layout(0, 0, w, h); - } - // Uncomment this to dump the view hierarchy. - //mContentView.dumpTree(""); - } - - @Override - protected void onLayout( - boolean changed, int left, int top, int right, int bottom) { - if (changed) requestLayoutContentPane(); - } - - private void outputFps() { - long now = System.nanoTime(); - if (mFrameCountingStart == 0) { - mFrameCountingStart = now; - } else if ((now - mFrameCountingStart) > 1000000000) { - Log.d(TAG, "fps: " + (double) mFrameCount - * 1000000000 / (now - mFrameCountingStart)); - mFrameCountingStart = now; - mFrameCount = 0; - } - ++mFrameCount; - } - - private void onDrawFrameLocked(GL10 gl) { - if (DEBUG_FPS) outputFps(); - // release the unbound textures and deleted buffers. - mCanvas.deleteRecycledResources(); - - // reset texture upload limit - UploadedTexture.resetUploadLimit(); - - mRenderRequested = false; - - if ((mOrientationSource != null - && mDisplayRotation != mOrientationSource.getDisplayRotation()) - || (mFlags & FLAG_NEED_LAYOUT) != 0) { - layoutContentPane(); - } - - mCanvas.save(GLCanvas.SAVE_FLAG_ALL); - rotateCanvas(-mCompensation); - if (mContentView != null) { - mContentView.render(mCanvas); - } else { - // Make sure we always draw something to prevent displaying garbage - mCanvas.clearBuffer(); - } - mCanvas.restore(); - - if (!mAnimations.isEmpty()) { - long now = AnimationTime.get(); - for (int i = 0, n = mAnimations.size(); i < n; i++) { - mAnimations.get(i).setStartTime(now); - } - mAnimations.clear(); - } - - if (UploadedTexture.uploadLimitReached()) { - requestRender(); - } - - synchronized (mIdleListeners) { - if (!mIdleListeners.isEmpty()) mIdleRunner.enable(); - } - - if (DEBUG_INVALIDATE) { - mCanvas.fillRect(10, 10, 5, 5, mInvalidateColor); - mInvalidateColor = ~mInvalidateColor; - } - - if (DEBUG_DRAWING_STAT) { - mCanvas.dumpStatisticsAndClear(); - } - } - - private void rotateCanvas(int degrees) { - if (degrees == 0) return; - int w = getWidth(); - int h = getHeight(); - int cx = w / 2; - int cy = h / 2; - mCanvas.translate(cx, cy); - mCanvas.rotate(degrees, 0, 0, 1); - if (degrees % 180 != 0) { - mCanvas.translate(-cy, -cx); - } else { - mCanvas.translate(-cx, -cy); - } - } - - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - if (!isEnabled()) return false; - - int action = event.getAction(); - if (action == MotionEvent.ACTION_CANCEL - || action == MotionEvent.ACTION_UP) { - mInDownState = false; - } else if (!mInDownState && action != MotionEvent.ACTION_DOWN) { - return false; - } - - if (mCompensation != 0) { - event = MotionEventHelper.transformEvent(event, mCompensationMatrix); - } - - mRenderLock.lock(); - try { - // If this has been detached from root, we don't need to handle event - boolean handled = mContentView != null - && mContentView.dispatchTouchEvent(event); - if (action == MotionEvent.ACTION_DOWN && handled) { - mInDownState = true; - } - return handled; - } finally { - mRenderLock.unlock(); - } - } - - private class IdleRunner implements Runnable { - // true if the idle runner is in the queue - private boolean mActive = false; - - @Override - public void run() { - OnGLIdleListener listener; - synchronized (mIdleListeners) { - mActive = false; - if (mIdleListeners.isEmpty()) return; - listener = mIdleListeners.removeFirst(); - } - mRenderLock.lock(); - boolean keepInQueue; - try { - keepInQueue = listener.onGLIdle(mCanvas, mRenderRequested); - } finally { - mRenderLock.unlock(); - } - synchronized (mIdleListeners) { - if (keepInQueue) mIdleListeners.addLast(listener); - if (!mRenderRequested && !mIdleListeners.isEmpty()) enable(); - } - } - - public void enable() { - // Who gets the flag can add it to the queue - if (mActive) return; - mActive = true; - queueEvent(this); - } - } - - @Override - public void lockRenderThread() { - mRenderLock.lock(); - } - - @Override - public void unlockRenderThread() { - mRenderLock.unlock(); - } - - @Override - public void onPause() { - unfreeze(); - super.onPause(); - } - - @Override - public void setOrientationSource(OrientationSource source) { - mOrientationSource = source; - } - - @Override - public int getDisplayRotation() { - return mDisplayRotation; - } - - @Override - public int getCompensation() { - return mCompensation; - } - - @Override - public Matrix getCompensationMatrix() { - return mCompensationMatrix; - } - - @Override - public void freeze() { - mRenderLock.lock(); - mFreeze = true; - mRenderLock.unlock(); - } - - @Override - public void unfreeze() { - mRenderLock.lock(); - mFreeze = false; - mFreezeCondition.signalAll(); - mRenderLock.unlock(); - } - - @Override - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public void setLightsOutMode(boolean enabled) { - if (!ApiHelper.HAS_SET_SYSTEM_UI_VISIBILITY) return; - - int flags = 0; - if (enabled) { - flags = STATUS_BAR_HIDDEN; - if (ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE) { - flags |= (SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_STABLE); - } - } - setSystemUiVisibility(flags); - } - - // We need to unfreeze in the following methods and in onPause(). - // These methods will wait on GLThread. If we have freezed the GLRootView, - // the GLThread will wait on main thread to call unfreeze and cause dead - // lock. - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - unfreeze(); - super.surfaceChanged(holder, format, w, h); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - unfreeze(); - super.surfaceCreated(holder); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - unfreeze(); - super.surfaceDestroyed(holder); - } - - @Override - protected void onDetachedFromWindow() { - unfreeze(); - super.onDetachedFromWindow(); - } - - /** - * {@inheritDoc} - */ - @Override - protected void dispatchSaveInstanceState(@NonNull SparseArray container) { - super.dispatchSaveInstanceState(container); - if (mContentView != null) { - mContentView.saveHierarchyState(container); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void dispatchRestoreInstanceState(@NonNull SparseArray container) { - super.dispatchRestoreInstanceState(container); - if (mContentView != null) { - mContentView.restoreHierarchyState(container); - } - } - - @Override - protected void finalize() throws Throwable { - try { - unfreeze(); - } finally { - super.finalize(); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/view/GLView.java b/app/src/main/java/com/hippo/gl/view/GLView.java deleted file mode 100644 index edfdfa369..000000000 --- a/app/src/main/java/com/hippo/gl/view/GLView.java +++ /dev/null @@ -1,1366 +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.hippo.gl.view; - -import android.graphics.Color; -import android.graphics.Rect; -import android.os.Parcelable; -import android.os.SystemClock; -import android.support.annotation.IntDef; -import android.util.Log; -import android.util.SparseArray; -import android.view.MotionEvent; - -import com.hippo.gl.anim.CanvasAnimation; -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.glrenderer.GLPaint; -import com.hippo.yorozuya.AssertUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; - -// GLView is a UI component. It can render to a GLCanvas and accept touch -// events. A GLView may have zero or more child GLView and they form a tree -// structure. The rendering and event handling will pass through the tree -// structure. -// -// A GLView tree should be attached to a GLRoot before event dispatching and -// rendering happens. GLView asks GLRoot to re-render or re-layout the -// GLView hierarchy using requestRender() and requestLayoutContentPane(). -// -// The render() method is called in a separate thread. Before calling -// dispatchTouchEvent() and layout(), GLRoot acquires a lock to avoid the -// rendering thread running at the same time. If there are other entry points -// from main thread (like a Handler) in your GLView, you need to call -// lockRendering() if the rendering thread should not run at the same time. -// -public class GLView implements TouchOwner { - private static final String TAG = "GLView"; - - private static final boolean DEBUG_DRAW_BOUNDS = false; - - @IntDef({VISIBLE, INVISIBLE, GONE}) - @Retention(RetentionPolicy.SOURCE) - public @interface Visibility {} - - public static final int VISIBLE = 0b00000000; - public static final int INVISIBLE = 0b00000001; - public static final int GONE = 0b00000010; - public static final int VISIBILITY_INVALID = 0b00000011; - - private static final int FLAG_INVISIBLE = 0b00000011; - private static final int FLAG_SET_MEASURED_SIZE = 0b00000100; - private static final int FLAG_LAYOUT_REQUESTED = 0b00001000; - - /** - * Used to mark a GlView that has no ID. - */ - public static final int NO_ID = -1; - - public interface OnClickListener { - boolean onClick(GLView v); - } - - public interface OnLongClickListener { - boolean onLongClick(GLView v); - } - - protected final static GLPaint mDrawBoundsPaint; - - static { - mDrawBoundsPaint = new GLPaint(); - mDrawBoundsPaint.setColor(Color.RED); - mDrawBoundsPaint.setLineWidth(2); - } - - /** - * Position in parent, just like left, top, right, bottom in {@link android.view.View} - */ - protected final Rect mBounds = new Rect(); - /** - * Position in root - */ - private final int[] mPositionInRoot = new int[2]; - protected final Rect mPaddings = new Rect(); - private final Rect mTempRect = new Rect(); - - private GLRoot mRoot; - protected GLView mParent; - private ArrayList mComponents; - private GLView mMotionTarget; - - private CanvasAnimation mAnimation; - - private int mViewFlags = 0; - - protected int mMeasuredWidth = 0; - protected int mMeasuredHeight = 0; - - private int mLastWidthSpec = -1; - private int mLastHeightSpec = -1; - - protected int mScrollY = 0; - protected int mScrollX = 0; - protected int mScrollHeight = 0; - protected int mScrollWidth = 0; - - /** - * The GlView's identifier. - * - * @see #setId(int) - * @see #getId() - */ - private int mID = NO_ID; - - /** - * The minimum height of the view. We'll try our best to have the height - * of this view to at least this amount. - */ - private int mMinHeight; - - /** - * The minimum width of the view. We'll try our best to have the width - * of this view to at least this amount. - */ - private int mMinWidth; - - private LayoutParams mLayoutParams; - - private int mBackgroundColor = Color.TRANSPARENT; - - private TouchHelper mTouchHelper; - - private float mHotspotX; - private float mHotspotY; - - private boolean mPressed; - - private OnClickListener mOnClickListener; - private OnLongClickListener mOnLongClickListener; - - public void startAnimation(CanvasAnimation animation, boolean atOnce) { - GLRoot root = getGLRoot(); - if (root == null) throw new IllegalStateException(); - mAnimation = animation; - if (mAnimation != null) { - mAnimation.start(); - if (atOnce) { - mAnimation.setStartTime(AnimationTime.get()); - } else { - root.registerLaunchedAnimation(mAnimation); - } - } - invalidate(); - } - - /** - * Set the enabled state of this view. - * - * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. - */ - public void setVisibility(@Visibility int visibility) { - @Visibility - int oldVisibility = getVisibility(); - if (visibility == oldVisibility) { - return; - } - - mViewFlags &= ~FLAG_INVISIBLE; - mViewFlags |= visibility; - - onVisibilityChanged(this, visibility); - - if (oldVisibility == GLView.GONE || visibility == GLView.GONE) { - requestLayout(); - } else { - invalidate(); - } - } - - /** - * Returns the visibility status for this view. - * - * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. - */ - @Visibility - @SuppressWarnings("WrongConstant") - public int getVisibility() { - int visibility = mViewFlags & FLAG_INVISIBLE; - - if (visibility == VISIBILITY_INVALID) { - visibility = VISIBLE; - mViewFlags &= ~FLAG_INVISIBLE; - mViewFlags |= visibility; - } - - return visibility; - } - - // This should only be called on the content pane (the topmost GLView). - void attachToRoot(GLRoot root) { - AssertUtils.assertTrue(mParent == null && mRoot == null); - onAttachToRoot(root); - } - - // This should only be called on the content pane (the topmost GLView). - void detachFromRoot() { - AssertUtils.assertTrue(mParent == null && mRoot != null); - onDetachFromRoot(); - } - - // This should only be called on the content pane (the topmost GLView). - void pause() { - onPause(); - } - - // This should only be called on the content pane (the topmost GLView). - void resume() { - onResume(); - } - - public boolean isAttachedToRoot() { - return mRoot != null; - } - - // Returns the number of children of the GLView. - public int getComponentCount() { - return mComponents == null ? 0 : mComponents.size(); - } - - // Returns the children for the given index. - public GLView getComponent(int index) { - if (mComponents == null) { - throw new ArrayIndexOutOfBoundsException(index); - } - return mComponents.get(index); - } - - // Adds a child to this GLView. - public void addComponent(GLView component) { - addComponent(component, -1, null); - } - - public void addComponent(GLView component, int index) { - addComponent(component, index, null); - } - - public void addComponent(GLView component, LayoutParams params) { - addComponent(component, -1, params); - } - - public void addComponent(GLView component, int index, LayoutParams params) { - // Make component is not null - if (component == null) { - throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); - } - // Make sure the component doesn't have a parent currently. - if (component.mParent != null) { - throw new IllegalStateException( - "Component " + this + " being added, but it already has a parent"); - } - - // Ensure index is valid - if (index < 0) { - index = getComponentCount(); - } - - // Ensure params is valid - if (params == null) { - params = generateDefaultLayoutParams(); - } else if (!checkLayoutParams(params)) { - params = generateLayoutParams(params); - } - - // Build parent-child links - if (mComponents == null) { - mComponents = new ArrayList<>(); - } - - mComponents.add(index, component); - component.mParent = this; - component.setLayoutParams(params); - - // If this is added after we have a root, tell the component. - if (mRoot != null) { - component.onAttachToRoot(mRoot); - } - } - - // Removes a child from this GLView. - public boolean removeComponent(GLView component) { - if (mComponents == null) return false; - if (mComponents.remove(component)) { - removeOneComponent(component); - return true; - } - return false; - } - - public boolean removeComponentAt(int index) { - if (mComponents == null) { - return false; - } - if (index >= 0 && index < getComponentCount()) { - GLView component = mComponents.remove(index); - removeOneComponent(component); - return true; - } else { - return false; - } - } - - // Removes all children of this GLView. - public void removeAllComponents() { - for (int i = 0, n = mComponents.size(); i < n; ++i) { - removeOneComponent(mComponents.get(i)); - } - mComponents.clear(); - } - - private void removeOneComponent(GLView component) { - if (mMotionTarget == component) { - long now = SystemClock.uptimeMillis(); - MotionEvent cancelEvent = MotionEvent.obtain( - now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); - dispatchTouchEvent(cancelEvent); - cancelEvent.recycle(); - } - component.onDetachFromRoot(); - component.mParent = null; - } - - /** - * Sets the identifier for this GlView. The identifier does not have to be - * unique in this GlView's hierarchy. The identifier should be a positive - * number. - * - * @param id a number used to identify the view - */ - public void setId(int id) { - mID = id; - } - - /** - * Returns this GlView's identifier. - * - * @return a positive integer used to identify the view or {@link #NO_ID} - * if the view has no ID - */ - public int getId() { - return mID; - } - - public Rect bounds() { - return mBounds; - } - - @Override - public void setHotspot(float x, float y) { - mHotspotX = x; - mHotspotY = y; - } - - public float getHotspotX() { - return mHotspotX; - } - - public float getHotspotY() { - return mHotspotY; - } - - @Override - public boolean isEnabled() { - return true; // TODO - } - - @Override - public boolean isPressed() { - return mPressed; - } - - @Override - public void setPressed(boolean pressed) { - mPressed = pressed; - } - - @Override - public boolean isClickable() { - return mOnClickListener != null; - } - - @Override - public boolean isLongClickable() { - return mOnLongClickListener != null; - } - - @Override - public boolean performClick() { - if (mOnClickListener != null) { - return mOnClickListener.onClick(this); - } else { - return false; - } - } - - @Override - public boolean performLongClick() { - if (mOnLongClickListener != null) { - return mOnLongClickListener.onLongClick(this); - } else { - return false; - } - } - - public void setOnClickListener(OnClickListener listener) { - mOnClickListener = listener; - } - - public void setOnLongClickListener(OnLongClickListener listener) { - mOnLongClickListener = listener; - } - - @Override - public int getWidth() { - return mBounds.right - mBounds.left; - } - - @Override - public int getHeight() { - return mBounds.bottom - mBounds.top; - } - - /** - * Offset this GLView's vertical location by the specified number of pixels. - * - * @param offset the number of pixels to offset the view by - */ - public void offsetTopAndBottom(int offset) { - if (offset != 0){ - mBounds.offset(0, offset); - dispatchNotifyPositionInRoot(); - invalidate(); - } - } - - /** - * Offset this GLView's horizontal location by the specified amount of pixels. - * - * @param offset the number of pixels to offset the view by - */ - public void offsetLeftAndRight(int offset) { - if (offset != 0){ - mBounds.offset(offset, 0); - dispatchNotifyPositionInRoot(); - invalidate(); - } - } - - public GLRoot getGLRoot() { - return mRoot; - } - - // Request re-rendering of the view hierarchy. - // This is used for animation or when the contents changed. - public void invalidate() { - GLRoot root = getGLRoot(); - if (root != null) root.requestRender(); - } - - // Request re-layout of the view hierarchy. - public void requestLayout() { - mViewFlags |= FLAG_LAYOUT_REQUESTED; - mLastWidthSpec = -1; - mLastHeightSpec = -1; - if (mParent != null) { - mParent.requestLayout(); - } else { - // Is this a content pane ? - GLRoot root = getGLRoot(); - if (root != null) root.requestLayoutContentPane(); - } - } - - public void render(GLCanvas canvas) { - // render background color - if (Color.alpha(mBackgroundColor) != 0) { - canvas.fillRect(0, 0, getWidth(), getHeight(), mBackgroundColor); - } - - // render content - onRender(canvas); - - // render child - canvas.save(); - for (int i = 0, n = getComponentCount(); i < n; ++i) { - renderChild(canvas, getComponent(i)); - } - canvas.restore(); - - // render bounds - if (DEBUG_DRAW_BOUNDS) { - canvas.drawRect(0, 0, getWidth(), getHeight(), mDrawBoundsPaint); - } - } - - public void onRender(GLCanvas canvas) { - } - - public void setBackgroundColor(int color) { - mBackgroundColor = color; - } - - protected void renderChild(GLCanvas canvas, GLView component) { - if (component.getVisibility() != GLView.VISIBLE) { - return; - } - - getValidRect(mTempRect); - if (mTempRect.isEmpty()) { - return; - } - - int xOffset = component.mBounds.left - mScrollX; - int yOffset = component.mBounds.top - mScrollY; - - canvas.translate(xOffset, yOffset); - - CanvasAnimation anim = component.mAnimation; - if (anim != null) { - canvas.save(anim.getCanvasSaveFlags()); - if (anim.calculate(AnimationTime.get())) { - invalidate(); - } else { - component.mAnimation = null; - } - anim.apply(canvas); - } - component.render(canvas); - if (anim != null) canvas.restore(); - canvas.translate(-xOffset, -yOffset); - } - - protected boolean onTouch(MotionEvent event) { - if (mTouchHelper == null) { - mTouchHelper = new TouchHelper(this); - } - return mTouchHelper.onTouch(event); - } - - protected boolean dispatchTouchEvent(MotionEvent event, - int x, int y, GLView component, boolean checkBounds) { - Rect rect = component.mBounds; - int left = rect.left; - int top = rect.top; - if (!checkBounds || rect.contains(x, y)) { - event.offsetLocation(-left, -top); - if (component.dispatchTouchEvent(event)) { - event.offsetLocation(left, top); - return true; - } - event.offsetLocation(left, top); - } - return false; - } - - protected boolean dispatchTouchEvent(MotionEvent event) { - int x = (int) event.getX(); - int y = (int) event.getY(); - int action = event.getAction(); - if (mMotionTarget != null) { - if (action == MotionEvent.ACTION_DOWN) { - MotionEvent cancel = MotionEvent.obtain(event); - cancel.setAction(MotionEvent.ACTION_CANCEL); - dispatchTouchEvent(cancel, x, y, mMotionTarget, false); - mMotionTarget = null; - } else { - dispatchTouchEvent(event, x, y, mMotionTarget, false); - if (action == MotionEvent.ACTION_CANCEL - || action == MotionEvent.ACTION_UP) { - mMotionTarget = null; - } - return true; - } - } - if (action == MotionEvent.ACTION_DOWN) { - // in the reverse rendering order - for (int i = getComponentCount() - 1; i >= 0; --i) { - GLView component = getComponent(i); - if (component.getVisibility() != GLView.VISIBLE) continue; - if (dispatchTouchEvent(event, x, y, component, true)) { - mMotionTarget = component; - return true; - } - } - } - return onTouch(event); - } - - /** - * Called by {@link GLRootView#dispatchSaveInstanceState(SparseArray)} to - * store this GlView hierarchy's frozen state into the given container. - * - * @param container The SparseArray in which to save the view's state. - */ - public void saveHierarchyState(SparseArray container) { - dispatchSaveInstanceState(container); - } - - protected void dispatchSaveInstanceState(SparseArray container) { - if (mID != NO_ID) { - Parcelable state = onSaveInstanceState(); - if (state != null) { - container.put(mID, state); - } - } - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).dispatchSaveInstanceState(container); - } - } - - protected Parcelable onSaveInstanceState() { - return null; - } - - /** - * Called by {@link GLRootView#dispatchRestoreInstanceState(SparseArray)} to - * restore this view hierarchy's frozen state from the given container. - * - * @param container The SparseArray which holds previously frozen states. - */ - public void restoreHierarchyState(SparseArray container) { - dispatchRestoreInstanceState(container); - } - - protected void dispatchRestoreInstanceState(SparseArray container) { - if (mID != NO_ID) { - Parcelable state = container.get(mID); - if (state != null) { - onRestoreInstanceState(state); - } - } - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).dispatchRestoreInstanceState(container); - } - } - - protected void onRestoreInstanceState(Parcelable state) { - if (state != null) { - throw new IllegalArgumentException("Please override onRestoreInstanceState"); - } - } - - public void setPaddings(int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { - mPaddings.set(paddingLeft, paddingTop, paddingRight, paddingBottom); - } - - public void setPaddingLeft(int paddingLeft) { - mPaddings.left = paddingLeft; - } - - public void setPaddingTop(int paddingTop) { - mPaddings.top = paddingTop; - } - - public void setPaddingRight(int paddingRight) { - mPaddings.right = paddingRight; - } - - public void setPaddingBottom(int paddingBottom) { - mPaddings.bottom = paddingBottom; - } - - public Rect getPaddings() { - return mPaddings; - } - - // There is a little different between GLView.layout() and View.layout(). - // onMeasure() is not called in GLView.layout(). - // For the content view of GLRootView, GLView.measure() is called before GLView.layout(). - // For component, GLView.measure() in called in parent's GLView.onMeasure(). - // So it is OK. - public void layout(int left, int top, int right, int bottom) { - boolean sizeChanged = setBounds(left, top, right, bottom); - final boolean forceLayout = (mViewFlags & FLAG_LAYOUT_REQUESTED) == FLAG_LAYOUT_REQUESTED; - if (sizeChanged || forceLayout) { - notifyPositionInRoot(); - onLayout(sizeChanged, left, top, right, bottom); - } else { - dispatchNotifyPositionInRoot(); - } - mViewFlags &= ~FLAG_LAYOUT_REQUESTED; - } - - public void dispatchNotifyPositionInRoot() { - if (notifyPositionInRoot()) { - for (int i = 0, size = getComponentCount(); i < size; i++) { - getComponent(i).dispatchNotifyPositionInRoot(); - } - } - } - - public boolean notifyPositionInRoot() { - // Update position in root - int[] position = mPositionInRoot; - int oldX = position[0]; - int oldY = position[1]; - if (mParent == null) { - position[0] = 0; - position[1] = 0; - } else { - mParent.getPositionInRoot(position); - // Apply offset in parent - position[0] += mBounds.left; - position[1] += mBounds.top; - } - int x = position[0]; - int y = position[1]; - if (x != oldX || y != oldY) { - onPositionInRootChanged(x, y, oldX, oldY); - return true; - } else { - return false; - } - } - - private boolean setBounds(int left, int top, int right, int bottom) { - Rect bounds = mBounds; - int oldW = bounds.right - bounds.left; - int oldH = bounds.bottom - bounds.top; - int newW = right - left; - int newH = bottom - top; - - boolean sizeChanged = oldW != newW || oldH != newH; - bounds.set(left, top, right, bottom); - - if (sizeChanged) { - onSizeChanged(newW, newH, oldW, oldH); - } - - return sizeChanged; - } - - protected void onSizeChanged(int newW, int newH, int oldW, int oldH) { - } - - protected void onPositionInRootChanged(int x, int y, int oldX, int oldY) { - } - - public void getPositionInRoot(int[] position) { - AssertUtils.assertEquals("position should be 2 length int array", position.length, 2); - position[0] = mPositionInRoot[0]; - position[1] = mPositionInRoot[1]; - } - - /** - * Get the rect of the view clipped by root rect - * @param rect the result - */ - public void getValidRect(Rect rect) { - GLRoot root = mRoot; - if (root == null) { - rect.setEmpty(); - return; - } - - int x = mPositionInRoot[0]; - int y = mPositionInRoot[1]; - rect.set(x, y, x + getWidth(), y + getHeight()); - if (!rect.intersect(0, 0, root.getWidth(), root.getHeight())) { - rect.setEmpty(); - return; - } - - rect.offset(-x, -y); - } - - public void measure(int widthSpec, int heightSpec) { - final boolean forceLayout = (mViewFlags & FLAG_LAYOUT_REQUESTED) == FLAG_LAYOUT_REQUESTED; - final boolean isExactly = MeasureSpec.getMode(widthSpec) == MeasureSpec.EXACTLY && - MeasureSpec.getMode(heightSpec) == MeasureSpec.EXACTLY; - final boolean matchingSize = isExactly && - getMeasuredWidth() == MeasureSpec.getSize(widthSpec) && - getMeasuredHeight() == MeasureSpec.getSize(heightSpec); - if (forceLayout || !matchingSize && - (widthSpec != mLastWidthSpec || - heightSpec != mLastHeightSpec)) { - mLastWidthSpec = widthSpec; - mLastHeightSpec = heightSpec; - - mViewFlags &= ~FLAG_SET_MEASURED_SIZE; - onMeasure(widthSpec, heightSpec); - if ((mViewFlags & FLAG_SET_MEASURED_SIZE) == 0) { - throw new IllegalStateException(getClass().getName() - + " should call setMeasuredSize() in onMeasure()"); - } - } - } - - protected void onMeasure(int widthSpec, int heightSpec) { - setMeasuredSize(getDefaultSize(getSuggestedMinimumWidth(), widthSpec), - getDefaultSize(getSuggestedMinimumHeight(), heightSpec)); - } - - protected int getSuggestedMinimumHeight() { - return getMinimumHeight() + mPaddings.top + mPaddings.bottom; - } - - protected int getSuggestedMinimumWidth() { - return getMinimumWidth() + mPaddings.left + mPaddings.right; - } - - /** - * Returns the minimum height of the view. - * - * @return the minimum height the view will try to be. - * - * @see #setMinimumHeight(int) - */ - public int getMinimumHeight() { - return mMinHeight; - } - - /** - * Sets the minimum height of the view. It is not guaranteed the view will - * be able to achieve this minimum height (for example, if its parent layout - * constrains it with less available height). - * - * @param minHeight The minimum height the view will try to be. - * - * @see #getMinimumHeight() - */ - public void setMinimumHeight(int minHeight) { - mMinHeight = minHeight; - requestLayout(); - } - - /** - * Returns the minimum width of the view. - * - * @return the minimum width the view will try to be. - * - * @see #setMinimumWidth(int) - */ - public int getMinimumWidth() { - return mMinWidth; - } - - /** - * Sets the minimum width of the view. It is not guaranteed the view will - * be able to achieve this minimum width (for example, if its parent layout - * constrains it with less available width). - * - * @param minWidth The minimum width the view will try to be. - * - * @see #getMinimumWidth() - */ - public void setMinimumWidth(int minWidth) { - mMinWidth = minWidth; - requestLayout(); - } - - protected void setMeasuredSize(int width, int height) { - mViewFlags |= FLAG_SET_MEASURED_SIZE; - mMeasuredWidth = width; - mMeasuredHeight = height; - } - - public int getMeasuredWidth() { - return mMeasuredWidth; - } - - public int getMeasuredHeight() { - return mMeasuredHeight; - } - - protected void onLayout( - boolean changeSize, int left, int top, int right, int bottom) { - } - - /** - * Utility to return a default begin. Uses the supplied number as left or top. - * - * @param size the parent size - * @param specSize the child size - * @param paddingBeign the padding begin - * @param paddingFinish the padding finish - * @param position the {@link Gravity#POSITION_BEGIN} or {@link Gravity#POSITION_CENTER} or - * {@link Gravity#POSITION_FINISH} - * @return the begin size - */ - public static int getDefaultBegin(int size, int specSize, int paddingBeign, int paddingFinish, - @Gravity.PositionMode int position) { - if (position == Gravity.POSITION_FINISH) { - return size - paddingFinish - specSize; - } else if (position == Gravity.POSITION_CENTER) { - return ((size - paddingBeign - paddingFinish) / 2) - (specSize / 2) + paddingBeign; - } else { - return paddingBeign; - } - } - - /** - * Utility to return a default size. Uses the supplied size if the - * MeasureSpec imposed no constraints. Will get larger if allowed - * by the MeasureSpec. - * - * It works differently from {@link android.view.View#getDefaultSize(int, int)}. - * For {@link MeasureSpec#AT_MOST}, size is suggestion size - * if it is small then spec size or it is not zero, - * otherwise spec size. - * - * @param size Default size for this view - * @param measureSpec Constraints imposed by the parent - * @return The size this view should be. - */ - public static int getDefaultSize(int size, int measureSpec) { - int result = size; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - switch (specMode) { - case MeasureSpec.UNSPECIFIED: - result = size; - break; - case MeasureSpec.EXACTLY: - result = specSize; - break; - case MeasureSpec.AT_MOST: - return size == 0 ? specSize : Math.min(size, specSize); - } - return result; - } - - /** - * Utility to return a max size. Uses the supplied size if the - * MeasureSpec imposed no constraints. Will get larger if allowed - * by the MeasureSpec. - * - * It works the same as {@link android.view.View#getDefaultSize(int, int)}. - * - * @param size Default size for this view - * @param measureSpec Constraints imposed by the parent - * @return The size this view should be. - */ - public static int getMaxSize(int size, int measureSpec) { - int result = size; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - switch (specMode) { - case MeasureSpec.UNSPECIFIED: - result = size; - break; - case MeasureSpec.EXACTLY: - case MeasureSpec.AT_MOST: - result = specSize; - break; - } - return result; - } - - public static int getComponentSpec(int spec, int childSize) { - int specMode = MeasureSpec.getMode(spec); - int specSize = MeasureSpec.getSize(spec); - - int size = Math.max(0, specSize); - - int resultSize = 0; - int resultMode = 0; - - switch (specMode) { - // Parent has imposed an exact size on us - case MeasureSpec.EXACTLY: - if (childSize >= 0) { - resultSize = childSize; - resultMode = MeasureSpec.EXACTLY; - } else if (childSize == LayoutParams.MATCH_PARENT) { - // Child wants to be our size. So be it. - resultSize = size; - resultMode = MeasureSpec.EXACTLY; - } else if (childSize == LayoutParams.WRAP_CONTENT) { - // Child wants to determine its own size. It can't be - // bigger than us. - resultSize = size; - resultMode = MeasureSpec.AT_MOST; - } - break; - - // Parent has imposed a maximum size on us - case MeasureSpec.AT_MOST: - if (childSize >= 0) { - // Child wants a specific size... so be it - resultSize = childSize; - resultMode = MeasureSpec.EXACTLY; - } else if (childSize == LayoutParams.MATCH_PARENT) { - // Child wants to be our size, but our size is not fixed. - // Constrain child to not be bigger than us. - resultSize = size; - resultMode = MeasureSpec.AT_MOST; - } else if (childSize == LayoutParams.WRAP_CONTENT) { - // Child wants to determine its own size. It can't be - // bigger than us. - resultSize = size; - resultMode = MeasureSpec.AT_MOST; - } - break; - - // Parent asked to see how big we want to be - case MeasureSpec.UNSPECIFIED: - if (childSize >= 0) { - // Child wants a specific size... let him have it - resultSize = childSize; - resultMode = MeasureSpec.EXACTLY; - } else if (childSize == LayoutParams.MATCH_PARENT) { - // Child wants to be our size... find out how big it should - // be - resultSize = 0; - resultMode = MeasureSpec.UNSPECIFIED; - } else if (childSize == LayoutParams.WRAP_CONTENT) { - // Child wants to determine its own size.... find out how - // big it should be - resultSize = 0; - resultMode = MeasureSpec.UNSPECIFIED; - } - break; - } - return MeasureSpec.makeMeasureSpec(resultSize, resultMode); - } - - public static void measureComponent(GLView component, int widthSpec, int heightSpec) { - final LayoutParams lp = component.getLayoutParams(); - final int componentWidthSpec = getComponentSpec(widthSpec, lp.width); - final int componentHeightSpec = getComponentSpec(heightSpec, lp.height); - component.measure(componentWidthSpec, componentHeightSpec); - } - - public static void measureAllComponents(GLView parent, int widthSpec, int heightSpec) { - for (int i = 0, n = parent.getComponentCount(); i < n; i++) { - GLView component = parent.getComponent(i); - if (component.getVisibility() == GONE) { - continue; - } - measureComponent(component, widthSpec, heightSpec); - } - } - - public LayoutParams getLayoutParams() { - return mLayoutParams; - } - - public void setLayoutParams(LayoutParams params) { - if (params == null) { - if (mParent == null) { - throw new NullPointerException("Layout parameters cannot be null"); - } else { - params = mParent.generateDefaultLayoutParams(); - } - } - mLayoutParams = params; - requestLayout(); - } - - protected boolean checkLayoutParams(LayoutParams p) { - return p != null; - } - - protected LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - } - - protected LayoutParams generateLayoutParams(LayoutParams p) { - return new LayoutParams(p); - } - - /** - * Gets the bounds of the given descendant that relative to this view. - */ - public boolean getBoundsOf(GLView descendant, Rect out) { - int xOffset = 0; - int yOffset = 0; - GLView view = descendant; - while (view != this) { - if (view == null) return false; - Rect bounds = view.mBounds; - xOffset += bounds.left; - yOffset += bounds.top; - view = view.mParent; - } - out.set(xOffset, yOffset, xOffset + descendant.getWidth(), - yOffset + descendant.getHeight()); - return true; - } - - protected void onVisibilityChanged(GLView changedView, @Visibility int visibility) { - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).onVisibilityChanged(changedView, visibility); - } - } - - public void onAttachToRoot(GLRoot root) { - mRoot = root; - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).onAttachToRoot(root); - } - } - - public void onDetachFromRoot() { - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).onDetachFromRoot(); - } - mRoot = null; - } - - public void onPause() { - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).onPause(); - } - } - - public void onResume() { - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).onResume(); - } - } - - public void lockRendering() { - if (mRoot != null) { - mRoot.lockRenderThread(); - } - } - - public void unlockRendering() { - if (mRoot != null) { - mRoot.unlockRenderThread(); - } - } - - // This is for debugging only. - // Dump the view hierarchy into log. - void dumpTree(String prefix) { - Log.d(TAG, prefix + getClass().getSimpleName()); - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).dumpTree(prefix + "...."); - } - } - - /** - * A MeasureSpec encapsulates the layout requirements passed from parent to child. - * Each MeasureSpec represents a requirement for either the width or the height. - * A MeasureSpec is comprised of a size and a mode. There are three possible - * modes: - *
- *
UNSPECIFIED
- *
- * The parent has not imposed any constraint on the child. It can be whatever size - * it wants. - *
- * - *
EXACTLY
- *
- * The parent has determined an exact size for the child. The child is going to be - * given those bounds regardless of how big it wants to be. - *
- * - *
AT_MOST
- *
- * The child can be as large as it wants up to the specified size. - *
- *
- * - * MeasureSpecs are implemented as ints to reduce object allocation. This class - * is provided to pack and unpack the <size, mode> tuple into the int. - */ - public static class MeasureSpec { - private static final int MODE_SHIFT = 30; - private static final int MODE_MASK = 0x3 << MODE_SHIFT; - - /** - * Measure specification mode: The parent has not imposed any constraint - * on the child. It can be whatever size it wants. - */ - public static final int UNSPECIFIED = 0 << MODE_SHIFT; - - /** - * Measure specification mode: The parent has determined an exact size - * for the child. The child is going to be given those bounds regardless - * of how big it wants to be. - */ - public static final int EXACTLY = 1 << MODE_SHIFT; - - /** - * Measure specification mode: The child can be as large as it wants up - * to the specified size. - */ - public static final int AT_MOST = 2 << MODE_SHIFT; - - /** - * The max size allowed - */ - public static final int MAX_SIZE = ~MODE_MASK; - - /** - * Creates a measure specification based on the supplied size and mode. - * - * The mode must always be one of the following: - *
    - *
  • {@link #UNSPECIFIED}
  • - *
  • {@link #EXACTLY}
  • - *
  • {@link #AT_MOST}
  • - *
- * - *

Note: On API level 17 and lower, makeMeasureSpec's - * implementation was such that the order of arguments did not matter - * and overflow in either value could impact the resulting MeasureSpec. - * {@link android.widget.RelativeLayout} was affected by this bug. - * Apps targeting API levels greater than 17 will get the fixed, more strict - * behavior.

- * - * @param size the size of the measure specification - * @param mode the mode of the measure specification - * @return the measure specification based on size and mode - */ - public static int makeMeasureSpec(int size, int mode) { - return (size & ~MODE_MASK) | (mode & MODE_MASK); - } - - /** - * Extracts the mode from the supplied measure specification. - * - * @param measureSpec the measure specification to extract the mode from - * @return {@link #UNSPECIFIED}, - * {@link #AT_MOST} or - * {@link #EXACTLY} - */ - public static int getMode(int measureSpec) { - return (measureSpec & MODE_MASK); - } - - /** - * Extracts the size from the supplied measure specification. - * - * @param measureSpec the measure specification to extract the size from - * @return the size in pixels defined in the supplied measure specification - */ - public static int getSize(int measureSpec) { - return (measureSpec & ~MODE_MASK); - } - - /** - * Returns a String representation of the specified measure - * specification. - * - * @param measureSpec the measure specification to convert to a String - * @return a String with the following format: "MeasureSpec: MODE SIZE" - */ - public static String toString(int measureSpec) { - int mode = getMode(measureSpec); - int size = getSize(measureSpec); - - StringBuilder sb = new StringBuilder("MeasureSpec: "); - - if (mode == UNSPECIFIED) - sb.append("UNSPECIFIED "); - else if (mode == EXACTLY) - sb.append("EXACTLY "); - else if (mode == AT_MOST) - sb.append("AT_MOST "); - else - sb.append(mode).append(" "); - - sb.append(size); - return sb.toString(); - } - } - - /** - * The LayoutParams look like {@link android.view.ViewGroup.LayoutParams}, - * and work like it. - */ - public static class LayoutParams { - - /** - * Special value for the height or width requested by a View. - * MATCH_PARENT means that the view wants to be as big as its parent, - * minus the parent's padding, if any. Introduced in API Level 8. - */ - public static final int MATCH_PARENT = -1; - - /** - * Special value for the height or width requested by a View. - * WRAP_CONTENT means that the view wants to be just large enough to fit - * its own internal content, taking its own padding into account. - */ - public static final int WRAP_CONTENT = -2; - - /** - * Information about how wide the view wants to be. Can be one of the - * constants {@link #MATCH_PARENT} or {@link #WRAP_CONTENT} or an exact size. - */ - public int width; - - /** - * Information about how tall the view wants to be. Can be one of the - * constants {@link #MATCH_PARENT} or {@link #WRAP_CONTENT} or an exact size. - */ - public int height; - - /** - * Creates a new set of layout parameters with the specified width - * and height. - * - * @param width the width, either {@link #WRAP_CONTENT}, - * {@link #MATCH_PARENT}, or a fixed size in pixels - * @param height the height, either {@link #WRAP_CONTENT}, - * {@link #MATCH_PARENT}, or a fixed size in pixels - */ - public LayoutParams(int width, int height) { - this.width = width; - this.height = height; - } - - /** - * Copy constructor. Clones the width and height values of the source. - * - * @param source The layout params to copy from. - */ - public LayoutParams(LayoutParams source) { - this.width = source.width; - this.height = source.height; - } - } - - /** - * LayoutParams with gravity inside - */ - public static class GravityLayoutParams extends LayoutParams { - - public int gravity = Gravity.NO_GRAVITY; - - public GravityLayoutParams(GLView.LayoutParams source) { - super(source); - - if (source instanceof GravityLayoutParams) { - gravity = ((GravityLayoutParams) source).gravity; - } - } - - public GravityLayoutParams(int width, int height) { - super(width, height); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/view/Gravity.java b/app/src/main/java/com/hippo/gl/view/Gravity.java deleted file mode 100644 index 3fd670338..000000000 --- a/app/src/main/java/com/hippo/gl/view/Gravity.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.hippo.gl.view; - -import android.support.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -public class Gravity { - - @IntDef({POSITION_BEGIN, POSITION_CENTER, POSITION_FINISH}) - @Retention(RetentionPolicy.SOURCE) - public @interface PositionMode {} - - @IntDef({HORIZONTAL, VERTICAL}) - @Retention(RetentionPolicy.SOURCE) - public @interface DirectionMode {} - - public static final int NO_GRAVITY = 0x0000; - - public static final int LEFT = 0x0001; - public static final int TOP = 0x0002; - public static final int RIGHT = 0x0004; - public static final int BOTTOM = 0x0008; - - public static final int CENTER_HORIZONTAL = LEFT | RIGHT; - public static final int CENTER_VERTICAL = TOP | BOTTOM; - public static final int CENTER = CENTER_VERTICAL|CENTER_HORIZONTAL; - - public static final int HORIZONTAL_MASK = CENTER_HORIZONTAL; - public static final int VERTICAL_MASK = CENTER_VERTICAL; - - public static final int POSITION_BEGIN = 0; - public static final int POSITION_CENTER = 1; - public static final int POSITION_FINISH = 2; - - public static final int HORIZONTAL = 0; - public static final int VERTICAL = 1; - - public static boolean centerHorizontal(int gravity) { - return (gravity & HORIZONTAL_MASK) == CENTER_HORIZONTAL; - } - - public static boolean right(int gravity) { - return (gravity & HORIZONTAL_MASK) == RIGHT; - } - - public static boolean left(int gravity) { - return (gravity & HORIZONTAL_MASK) == LEFT; - } - - public static boolean centerVertical(int gravity) { - return (gravity & VERTICAL_MASK) == CENTER_VERTICAL; - } - - public static boolean top(int gravity) { - return (gravity & VERTICAL_MASK) == TOP; - } - - public static boolean bottom(int gravity) { - return (gravity & VERTICAL_MASK) == BOTTOM; - } - - public static @PositionMode int getPosition(int gravity, @DirectionMode int direction) { - if (direction == HORIZONTAL) { - if (right(gravity)) { - return POSITION_FINISH; - } else if (centerHorizontal(gravity)) { - return POSITION_CENTER; - } else { - return POSITION_BEGIN; - } - } else { - if (bottom(gravity)) { - return POSITION_FINISH; - } else if (centerVertical(gravity)) { - return POSITION_CENTER; - } else { - return POSITION_BEGIN; - } - } - } -} diff --git a/app/src/main/java/com/hippo/gl/view/OrientationSource.java b/app/src/main/java/com/hippo/gl/view/OrientationSource.java deleted file mode 100644 index a8b6f8967..000000000 --- a/app/src/main/java/com/hippo/gl/view/OrientationSource.java +++ /dev/null @@ -1,22 +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.hippo.gl.view; - -public interface OrientationSource { - int getDisplayRotation(); - int getCompensation(); -} diff --git a/app/src/main/java/com/hippo/gl/view/TouchHelper.java b/app/src/main/java/com/hippo/gl/view/TouchHelper.java deleted file mode 100644 index 42e307e35..000000000 --- a/app/src/main/java/com/hippo/gl/view/TouchHelper.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright 2015 Hippo Seven - * - * 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.hippo.gl.view; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.view.MotionEvent; -import android.view.ViewConfiguration; - -import com.hippo.yorozuya.LayoutUtils; -import com.hippo.yorozuya.SimpleHandler; - -public class TouchHelper { - - private TouchOwner mOwner; - - private boolean mPrePressed = false; - private boolean mHasPerformedLongPress = false; - - private CheckForLongPress mPendingCheckForLongPress = null; - private CheckForTap mPendingCheckForTap = null; - private PerformClick mPerformClick = null; - private UnsetPressedState mUnsetPressedState = null; - - /** - * Cache the touch slop from the context that created the view. - */ - private static int sTouchSlop = 8; - - public static void initialize(Context context) { - sTouchSlop = LayoutUtils.dp2pix(context, 8); // 8dp - } - - public TouchHelper(@NonNull TouchOwner owner) { - mOwner = owner; - } - - public boolean onTouch(MotionEvent event) { - TouchOwner owner = mOwner; - final float x = event.getX(); - final float y = event.getY(); - - if (event.getAction() == MotionEvent.ACTION_DOWN || - event.getAction() == MotionEvent.ACTION_MOVE) - owner.setHotspot(x, y); - - if (!owner.isEnabled()) { - if (event.getAction() == MotionEvent.ACTION_UP && owner.isPressed()) { - owner.setPressed(false); - } - // A disabled view that is clickable still consumes the touch - // events, it just doesn't respond to them. - return (owner.isClickable() || owner.isLongClickable()); - } - - if (owner.isClickable() || owner.isLongClickable()) { - switch (event.getAction()) { - case MotionEvent.ACTION_UP: - if (owner.isPressed() || mPrePressed) { - if (mPrePressed) { - // The button is being released before we actually - // showed it as pressed. Make it show the pressed - // state now (before scheduling the click) to ensure - // the user sees it. - setPressed(true, x, y); - } - - if (!mHasPerformedLongPress) { - // This is a tap, so remove the longpress check - removeLongPressCallback(); - - // Use a Runnable and post this rather than calling - // performClick directly. This lets other visual state - // of the view update before click actions start. - if (mPerformClick == null) { - mPerformClick = new PerformClick(); - } - if (!SimpleHandler.getInstance().post(mPerformClick)) { - owner.performClick(); - } - } - - if (mUnsetPressedState == null) { - mUnsetPressedState = new UnsetPressedState(); - } - - if (mPrePressed) { - SimpleHandler.getInstance().postDelayed(mUnsetPressedState, - ViewConfiguration.getPressedStateDuration()); - } else if (!SimpleHandler.getInstance().post(mUnsetPressedState)) { - // If the post failed, unpress right now - mUnsetPressedState.run(); - } - - removeTapCallback(); - } - break; - - case MotionEvent.ACTION_DOWN: - mHasPerformedLongPress = false; - - mPrePressed = true; - if (mPendingCheckForTap == null) { - mPendingCheckForTap = new CheckForTap(); - } - mPendingCheckForTap.x = event.getX(); - mPendingCheckForTap.y = event.getY(); - SimpleHandler.getInstance().postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); - break; - - case MotionEvent.ACTION_CANCEL: - owner.setPressed(false); - removeTapCallback(); - removeLongPressCallback(); - break; - - case MotionEvent.ACTION_MOVE: - owner.setHotspot(x, y); - - // Be lenient about moving outside of buttons - if (!pointInView(x, y, sTouchSlop)) { - // Outside button - removeTapCallback(); - if (owner.isPressed()) { - // Remove any future long press/tap checks - removeLongPressCallback(); - - owner.setPressed(false); - } - } - break; - } - - return true; - } - - return false; - } - - private void setPressed(boolean pressed, float x, float y){ - mOwner.setPressed(pressed); - if (pressed) { - mOwner.setHotspot(x, y); - } - } - - /** - * Utility method to determine whether the given point, in local coordinates, - * is inside the view, where the area of the view is expanded by the slop factor. - * This method is called while processing touch-move events to determine if the event - * is still within the view. - */ - public boolean pointInView(float localX, float localY, float slop) { - return localX >= -slop && localY >= -slop && localX < (mOwner.getWidth() + slop) && - localY < (mOwner.getHeight() + slop); - } - - /** - * Remove the longpress detection timer. - */ - private void removeLongPressCallback() { - if (mPendingCheckForLongPress != null) { - SimpleHandler.getInstance().removeCallbacks(mPendingCheckForLongPress); - } - } - - /** - * Remove the tap detection timer. - */ - private void removeTapCallback() { - if (mPendingCheckForTap != null) { - mPrePressed = false; - SimpleHandler.getInstance().removeCallbacks(mPendingCheckForTap); - } - } - - private void checkForLongClick(int delayOffset) { - if (mOwner.isLongClickable()) { - mHasPerformedLongPress = false; - - if (mPendingCheckForLongPress == null) { - mPendingCheckForLongPress = new CheckForLongPress(); - } - SimpleHandler.getInstance().postDelayed(mPendingCheckForLongPress, - ViewConfiguration.getLongPressTimeout() - delayOffset); - } - } - - private final class CheckForLongPress implements Runnable { - - @Override - public void run() { - if (mOwner.isPressed()) { - if (mOwner.performLongClick()) { - mHasPerformedLongPress = true; - } - } - } - } - - private final class CheckForTap implements Runnable { - public float x; - public float y; - - @Override - public void run() { - mPrePressed = false; - setPressed(true, x, y); - checkForLongClick(ViewConfiguration.getTapTimeout()); - } - } - - private final class PerformClick implements Runnable { - - @Override - public void run() { - mOwner.performClick(); - } - } - - private final class UnsetPressedState implements Runnable { - - @Override - public void run() { - mOwner.setPressed(false); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/view/TouchOwner.java b/app/src/main/java/com/hippo/gl/view/TouchOwner.java deleted file mode 100644 index 338652a64..000000000 --- a/app/src/main/java/com/hippo/gl/view/TouchOwner.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 Hippo Seven - * - * 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.hippo.gl.view; - -public interface TouchOwner { - - void setHotspot(float x, float y); - - boolean isEnabled(); - - boolean isPressed(); - - void setPressed(boolean pressed); - - boolean isClickable(); - - boolean isLongClickable(); - - boolean performClick(); - - boolean performLongClick(); - - int getWidth(); - - int getHeight(); -} diff --git a/app/src/main/java/com/hippo/gl/widget/GLEdgeEffect.java b/app/src/main/java/com/hippo/gl/widget/GLEdgeEffect.java deleted file mode 100644 index a8a9fb098..000000000 --- a/app/src/main/java/com/hippo/gl/widget/GLEdgeEffect.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.widget; - -import android.graphics.Rect; -import android.view.animation.AnimationUtils; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -import com.hippo.gl.glrenderer.GLCanvas; - -/** - * Material design edge effect - */ -public class GLEdgeEffect { - - // Time it will take the effect to fully recede in ms - private static final int RECEDE_TIME = 600; - - // Time it will take before a pulled glow begins receding in ms - private static final int PULL_TIME = 167; - - // Time it will take in ms for a pulled glow to decay to partial strength before release - private static final int PULL_DECAY_TIME = 2000; - - private static final float MAX_ALPHA = 0.5f; - - private static final float MAX_GLOW_SCALE = 2.f; - - private static final float PULL_GLOW_BEGIN = 0.f; - - // Minimum velocity that will be absorbed - private static final int MIN_VELOCITY = 100; - // Maximum velocity, clamps at this value - private static final int MAX_VELOCITY = 10000; - - private static final float EPSILON = 0.001f; - - private static final double ANGLE = Math.PI / 6; - private static final float SIN = (float) Math.sin(ANGLE); - private static final float COS = (float) Math.cos(ANGLE); - - private float mGlowAlpha; - private float mGlowScaleY; - - private float mGlowAlphaStart; - private float mGlowAlphaFinish; - private float mGlowScaleYStart; - private float mGlowScaleYFinish; - - private long mStartTime; - private float mDuration; - - private final Interpolator mInterpolator; - - private static final int STATE_IDLE = 0; - private static final int STATE_PULL = 1; - private static final int STATE_ABSORB = 2; - private static final int STATE_RECEDE = 3; - private static final int STATE_PULL_DECAY = 4; - - private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f; - - private static final int VELOCITY_GLOW_FACTOR = 6; - - private int mState = STATE_IDLE; - - private float mPullDistance; - - private final Rect mBounds = new Rect(); - private int mColor; - private float mRadius; - private float mBaseGlowScale; - private float mDisplacement = 0.5f; - private float mTargetDisplacement = 0.5f; - - /** - * Construct a new EdgeEffect with a theme appropriate for the provided context. - */ - public GLEdgeEffect(int color) { - mColor = color; - mInterpolator = new DecelerateInterpolator(); - } - - /** - * Set the size of this edge effect in pixels. - * - * @param width Effect width in pixels - * @param height Effect height in pixels - */ - public void setSize(int width, int height) { - final float r = width * 0.75f / SIN; - final float y = COS * r; - final float h = r - y; - final float or = height * 0.75f / SIN; - final float oy = COS * or; - final float oh = or - oy; - - mRadius = r; - mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f; - - mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h)); - } - - /** - * Reports if this EdgeEffect's animation is finished. If this method returns false - * after a call to {@link #draw(GLCanvas)} the host widget should schedule another - * drawing pass to continue the animation. - * - * @return true if animation is finished, false if drawing should continue on the next frame. - */ - public boolean isFinished() { - return mState == STATE_IDLE; - } - - /** - * Immediately finish the current animation. - * After this call {@link #isFinished()} will return true. - */ - public void finish() { - mState = STATE_IDLE; - } - - /** - * A view should call this when content is pulled away from an edge by the user. - * This will update the state of the current visual effect and its associated animation. - * The host view should always {@link android.view.View#invalidate()} after this - * and draw the results accordingly. - * - *

Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement - * of the pull point is known.

- * - * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to - * 1.f (full length of the view) or negative values to express change - * back toward the edge reached to initiate the effect. - */ - public void onPull(float deltaDistance) { - onPull(deltaDistance, 0.5f); - } - - /** - * A view should call this when content is pulled away from an edge by the user. - * This will update the state of the current visual effect and its associated animation. - * The host view should always {@link android.view.View#invalidate()} after this - * and draw the results accordingly. - * - * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to - * 1.f (full length of the view) or negative values to express change - * back toward the edge reached to initiate the effect. - * @param displacement The displacement from the starting side of the effect of the point - * initiating the pull. In the case of touch this is the finger position. - * Values may be from 0-1. - */ - public void onPull(float deltaDistance, float displacement) { - final long now = AnimationUtils.currentAnimationTimeMillis(); - mTargetDisplacement = displacement; - if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) { - return; - } - if (mState != STATE_PULL) { - mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY); - } - mState = STATE_PULL; - - mStartTime = now; - mDuration = PULL_TIME; - - mPullDistance += deltaDistance; - - final float absdd = Math.abs(deltaDistance); - mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, - mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR)); - - if (mPullDistance == 0) { - mGlowScaleY = mGlowScaleYStart = 0; - } else { - final float scale = Math.max(0, 1 - 1 / - (float) Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f; - - mGlowScaleY = mGlowScaleYStart = scale; - } - - mGlowAlphaFinish = mGlowAlpha; - mGlowScaleYFinish = mGlowScaleY; - } - - /** - * Call when the object is released after being pulled. - * This will begin the "decay" phase of the effect. After calling this method - * the host view should {@link android.view.View#invalidate()} and thereby - * draw the results accordingly. - */ - public void onRelease() { - mPullDistance = 0; - - if (mState != STATE_PULL && mState != STATE_PULL_DECAY) { - return; - } - - mState = STATE_RECEDE; - mGlowAlphaStart = mGlowAlpha; - mGlowScaleYStart = mGlowScaleY; - - mGlowAlphaFinish = 0.f; - mGlowScaleYFinish = 0.f; - - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDuration = RECEDE_TIME; - } - - /** - * Call when the effect absorbs an impact at the given velocity. - * Used when a fling reaches the scroll boundary. - * - *

When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller}, - * the method getCurrVelocity will provide a reasonable approximation - * to use here.

- * - * @param velocity Velocity at impact in pixels per second. - */ - public void onAbsorb(int velocity) { - mState = STATE_ABSORB; - velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY); - - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDuration = 0.15f + (velocity * 0.02f); - - // The glow depends more on the velocity, and therefore starts out - // nearly invisible. - mGlowAlphaStart = 0.3f; - mGlowScaleYStart = Math.max(mGlowScaleY, 0.f); - - - // Growth for the size of the glow should be quadratic to properly - // respond - // to a user's scrolling speed. The faster the scrolling speed, the more - // intense the effect should be for both the size and the saturation. - mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f); - // Alpha should change for the glow as well as size. - mGlowAlphaFinish = Math.max( - mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); - mTargetDisplacement = 0.5f; - } - - /** - * Set the color of this edge effect in argb. - * - * @param color Color in argb - */ - public void setColor(int color) { - mColor = color; - } - - /** - * Return the color of this edge effect in argb. - * @return The color of this edge effect in argb - */ - public int getColor() { - return mColor; - } - - /** - * Draw into the provided canvas. Assumes that the canvas has been rotated - * accordingly and the size has been set. The effect will be drawn the full - * width of X=0 to X=width, beginning from Y=0 and extending to some factor < - * 1.f of height. - * - * @param canvas Canvas to draw into - * @return true if drawing should continue beyond this frame to continue the - * animation - */ - public boolean draw(GLCanvas canvas) { - update(); - - canvas.save(); - - final float centerX = mBounds.centerX(); - final float centerY = mBounds.height() - mRadius; - - canvas.translate(-centerX, 0f); - canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, 0); - canvas.translate(centerX, 0f); - - final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f; - float translateX = mBounds.width() * displacement / 2; - - canvas.translate(translateX, 0); - canvas.fillOval(centerX, centerY, mRadius, mRadius, mColor); - canvas.restore(); - - boolean oneLastFrame = false; - if (mState == STATE_RECEDE && mGlowScaleY == 0) { - mState = STATE_IDLE; - oneLastFrame = true; - } - - return mState != STATE_IDLE || oneLastFrame; - } - - /** - * Return the maximum height that the edge effect will be drawn at given the original - * {@link #setSize(int, int) input size}. - * @return The maximum height of the edge effect - */ - public int getMaxHeight() { - return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f); - } - - private void update() { - final long time = AnimationUtils.currentAnimationTimeMillis(); - final float t = Math.min((time - mStartTime) / mDuration, 1.f); - - final float interp = mInterpolator.getInterpolation(t); - - mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; - mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; - mDisplacement = (mDisplacement + mTargetDisplacement) / 2; - - if (t >= 1.f - EPSILON) { - switch (mState) { - case STATE_ABSORB: - mState = STATE_RECEDE; - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDuration = RECEDE_TIME; - - mGlowAlphaStart = mGlowAlpha; - mGlowScaleYStart = mGlowScaleY; - - // After absorb, the glow should fade to nothing. - mGlowAlphaFinish = 0.f; - mGlowScaleYFinish = 0.f; - break; - case STATE_PULL: - mState = STATE_PULL_DECAY; - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDuration = PULL_DECAY_TIME; - - mGlowAlphaStart = mGlowAlpha; - mGlowScaleYStart = mGlowScaleY; - - // After pull, the glow should fade to nothing. - mGlowAlphaFinish = 0.f; - mGlowScaleYFinish = 0.f; - break; - case STATE_PULL_DECAY: - mState = STATE_RECEDE; - break; - case STATE_RECEDE: - mState = STATE_IDLE; - break; - } - } - } -} diff --git a/app/src/main/java/com/hippo/gl/widget/GLEdgeView.java b/app/src/main/java/com/hippo/gl/widget/GLEdgeView.java deleted file mode 100644 index d09210bbf..000000000 --- a/app/src/main/java/com/hippo/gl/widget/GLEdgeView.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.widget; - -import android.content.Context; -import android.opengl.Matrix; -import android.support.annotation.IntDef; - -import com.hippo.ehviewer.R; -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.view.GLView; -import com.hippo.yorozuya.ResourcesUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -public final class GLEdgeView extends GLView { - - @IntDef({TOP, LEFT, BOTTOM, RIGHT}) - @Retention(RetentionPolicy.SOURCE) - private @interface Direction {} - - @SuppressWarnings("unused") - private static final String TAG = "EdgeView"; - - public static final int TOP = 0; - public static final int LEFT = 1; - public static final int BOTTOM = 2; - public static final int RIGHT = 3; - - // Each edge effect has a transform matrix, and each matrix has 16 elements. - // We put all the elements in one array. These constants specify the - // starting index of each matrix. - private static final int TOP_M = TOP * 16; - private static final int LEFT_M = LEFT * 16; - private static final int BOTTOM_M = BOTTOM * 16; - private static final int RIGHT_M = RIGHT * 16; - - private GLEdgeEffect[] mEffect = new GLEdgeEffect[4]; - private float[] mMatrix = new float[4 * 16]; - - public GLEdgeView(Context context) { - final int themeColor = ResourcesUtils.getAttrColor(context, R.attr.colorPrimary); - int color = (themeColor & 0xffffff) | 0x33000000; - for (int i = 0; i < 4; i++) { - mEffect[i] = new GLEdgeEffect(color); - } - } - - @Override - protected void onLayout( - boolean changeSize, int left, int top, int right, int bottom) { - if (!changeSize) return; - - int w = right - left; - int h = bottom - top; - for (int i = 0; i < 4; i++) { - if ((i & 1) == 0) { // top or bottom - mEffect[i].setSize(w, h); - } else { // left or right - mEffect[i].setSize(h, w); - } - } - - // Set up transforms for the four edges. Without transforms an - // EdgeEffect draws the TOP edge from (0, 0) to (w, Y * h) where Y - // is some factor < 1. For other edges we need to move, rotate, and - // flip the effects into proper places. - Matrix.setIdentityM(mMatrix, TOP_M); - Matrix.setIdentityM(mMatrix, LEFT_M); - Matrix.setIdentityM(mMatrix, BOTTOM_M); - Matrix.setIdentityM(mMatrix, RIGHT_M); - - Matrix.rotateM(mMatrix, LEFT_M, 90, 0, 0, 1); - Matrix.scaleM(mMatrix, LEFT_M, 1, -1, 1); - - Matrix.translateM(mMatrix, BOTTOM_M, 0, h, 0); - Matrix.scaleM(mMatrix, BOTTOM_M, 1, -1, 1); - - Matrix.translateM(mMatrix, RIGHT_M, w, 0, 0); - Matrix.rotateM(mMatrix, RIGHT_M, 90, 0, 0, 1); - } - - @Override - public void render(GLCanvas canvas) { - boolean more = false; - for (int i = 0; i < 4; i++) { - canvas.save(GLCanvas.SAVE_FLAG_MATRIX); - canvas.multiplyMatrix(mMatrix, i * 16); - more |= mEffect[i].draw(canvas); - canvas.restore(); - } - if (more) { - invalidate(); - } - } - - // Called when the content is pulled away from the edge. - // offset is in pixels. direction is one of {TOP, LEFT, BOTTOM, RIGHT}. - public void onPull(float offset, @Direction int direction) { - int fullLength = ((direction & 1) == 0) ? getWidth() : getHeight(); - mEffect[direction].onPull(offset / fullLength); - if (!mEffect[direction].isFinished()) { - invalidate(); - } - } - - public void onPull(float offset, float position, @Direction int direction) { - int fullLength = ((direction & 1) == 0) ? getHeight() : getWidth(); - int fullPosition = ((direction & 1) == 0) ? getWidth() : getHeight(); - mEffect[direction].onPull(offset / fullLength, position / fullPosition); - if (!mEffect[direction].isFinished()) { - invalidate(); - } - } - - // Call when the object is released after being pulled. - public void onRelease() { - boolean more = false; - for (int i = 0; i < 4; i++) { - mEffect[i].onRelease(); - more |= !mEffect[i].isFinished(); - } - if (more) { - invalidate(); - } - } - - public void onRelease(@Direction int direction) { - GLEdgeEffect edgeEffect = mEffect[direction]; - edgeEffect.onRelease(); - if (!edgeEffect.isFinished()) { - invalidate(); - } - } - - // Call when the effect absorbs an impact at the given velocity. - // Used when a fling reaches the scroll boundary. velocity is in pixels - // per second. direction is one of {TOP, LEFT, BOTTOM, RIGHT}. - public void onAbsorb(int velocity, int direction) { - mEffect[direction].onAbsorb(velocity); - if (!mEffect[direction].isFinished()) { - invalidate(); - } - } - - public boolean isFinished(int direction) { - return mEffect[direction].isFinished(); - } -} diff --git a/app/src/main/java/com/hippo/gl/widget/GLFrameLayout.java b/app/src/main/java/com/hippo/gl/widget/GLFrameLayout.java deleted file mode 100644 index f37584292..000000000 --- a/app/src/main/java/com/hippo/gl/widget/GLFrameLayout.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.widget; - -import com.hippo.gl.view.GLView; -import com.hippo.gl.view.Gravity; - -public class GLFrameLayout extends GLView { - - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - int maxWidth = 0; - int maxHeight = 0; - for (int i = 0, n = getComponentCount(); i < n; i++) { - GLView component = getComponent(i); - if (component.getVisibility() == GONE) { - continue; - } - measureComponent(component, widthSpec, heightSpec); - maxWidth = Math.max(maxWidth, component.getMeasuredWidth()); - maxHeight = Math.max(maxHeight, component.getMeasuredHeight()); - } - - // Consider min - maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); - maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); - - // The final - maxWidth = getDefaultSize(maxWidth, widthSpec); - maxHeight = getDefaultSize(maxHeight, heightSpec); - - setMeasuredSize(maxWidth, maxHeight); - - if (MeasureSpec.getSize(widthSpec) != MeasureSpec.EXACTLY || - MeasureSpec.getSize(heightSpec) != MeasureSpec.EXACTLY) { - // Measure again - measureAllComponents(this, MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY)); - } - } - - @Override - protected void onLayout(boolean changeSize, int left, int top, int right, int bottom) { - int width = getWidth(); - int height = getHeight(); - - for (int i = 0, n = getComponentCount(); i < n; i++) { - GLView component = getComponent(i); - if (component.getVisibility() == GONE) { - continue; - } - int measureWidth = component.getMeasuredWidth(); - int measureHeight = component.getMeasuredHeight(); - int componentLeft; - int componentTop; - - GravityLayoutParams lp = (GravityLayoutParams) component.getLayoutParams(); - int gravity = lp.gravity; - if (Gravity.centerHorizontal(gravity)) { - componentLeft = (width / 2) - (measureWidth / 2); - } else if (Gravity.right(gravity)) { - componentLeft = width - measureWidth; - } else { - componentLeft = 0; - } - if (Gravity.centerVertical(gravity)) { - componentTop = (height / 2) - (measureHeight / 2); - } else if (Gravity.bottom(gravity)) { - componentTop = height - measureHeight; - } else { - componentTop = 0; - } - - component.layout(componentLeft, componentTop, - componentLeft + measureWidth, componentTop + measureHeight); - } - } - - @Override - protected boolean checkLayoutParams(GLView.LayoutParams p) { - return p instanceof GravityLayoutParams; - } - - @Override - protected LayoutParams generateDefaultLayoutParams() { - return new GravityLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - } - - @Override - protected LayoutParams generateLayoutParams(GLView.LayoutParams p) { - return p == null ? generateDefaultLayoutParams() : new GravityLayoutParams(p); - } -} diff --git a/app/src/main/java/com/hippo/gl/widget/GLLinearLayout.java b/app/src/main/java/com/hippo/gl/widget/GLLinearLayout.java deleted file mode 100644 index 3b74cdd90..000000000 --- a/app/src/main/java/com/hippo/gl/widget/GLLinearLayout.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.widget; - -import android.graphics.Rect; -import android.support.annotation.IntDef; - -import com.hippo.gl.view.GLView; -import com.hippo.gl.view.Gravity; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; - -public class GLLinearLayout extends GLView { - - @IntDef({HORIZONTAL, VERTICAL}) - @Retention(RetentionPolicy.SOURCE) - public @interface OrientationMode {} - - public static final int HORIZONTAL = 0; - public static final int VERTICAL = 1; - - private int mInterval = 0; - private int mOrientation = VERTICAL; - - private final List mTempList = new ArrayList<>(); - - public void setInterval(int interval) { - if (mInterval != interval) { - mInterval = interval; - requestLayout(); - } - } - - /** - * Should the layout be a column or a row. - * @param orientation Pass {@link #HORIZONTAL} or {@link #VERTICAL}. Default - * value is {@link #HORIZONTAL}. - */ - public void setOrientation(@OrientationMode int orientation) { - if (mOrientation != orientation) { - mOrientation = orientation; - requestLayout(); - } - } - - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - int layoutWidthSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthSpec) - mPaddings.left - mPaddings.right, - MeasureSpec.getMode(widthSpec)); - int layoutHeightSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightSpec) - mPaddings.top - mPaddings.bottom, - MeasureSpec.getMode(heightSpec)); - - if (mOrientation == HORIZONTAL && MeasureSpec.getMode(widthSpec) == MeasureSpec.EXACTLY) { - int width = MeasureSpec.getSize(layoutWidthSpec); - float sumWeight = 0.0f; - - for (int i = 0, n = getComponentCount(); i < n; i++) { - final GLView component = getComponent(i); - if (component.getVisibility() == GONE) { - continue; - } - final LayoutParams lp = (LayoutParams) component.getLayoutParams(); - - if (lp.weight > 0.0f) { - sumWeight += lp.weight; - mTempList.add(component); - } else { - measureComponent(component, layoutWidthSpec, layoutHeightSpec); - width -= component.getMeasuredWidth(); - } - } - - for (GLView component : mTempList) { - final LayoutParams lp = (LayoutParams) component.getLayoutParams(); - final int componentWidthSpec = MeasureSpec.makeMeasureSpec( - (int) (width * lp.weight / sumWeight), MeasureSpec.EXACTLY); - final int componentHeightSpec = getComponentSpec(layoutHeightSpec, lp.height); - component.measure(componentWidthSpec, componentHeightSpec); - } - - mTempList.clear(); - } else if (mOrientation == VERTICAL && MeasureSpec.getMode(heightSpec) == MeasureSpec.EXACTLY) { - int height = MeasureSpec.getSize(layoutHeightSpec); - float sumWeight = 0.0f; - - for (int i = 0, n = getComponentCount(); i < n; i++) { - final GLView component = getComponent(i); - if (component.getVisibility() == GONE) { - continue; - } - final LayoutParams lp = (LayoutParams) component.getLayoutParams(); - - if (lp.weight > 0.0f) { - sumWeight += lp.weight; - mTempList.add(component); - } else { - measureComponent(component, layoutWidthSpec, layoutHeightSpec); - height -= component.getMeasuredHeight(); - } - } - - for (GLView component : mTempList) { - final LayoutParams lp = (LayoutParams) component.getLayoutParams(); - final int componentWidthSpec = getComponentSpec(layoutWidthSpec, lp.width); - final int componentHeightSpec = MeasureSpec.makeMeasureSpec( - (int) (height * lp.weight / sumWeight), MeasureSpec.EXACTLY); - component.measure(componentWidthSpec, componentHeightSpec); - } - - mTempList.clear(); - } else { - measureAllComponents(this, layoutWidthSpec, layoutHeightSpec); - } - - int maxWidth = 0; - int maxHeight = 0; - for (int i = 0, n = getComponentCount(); i < n; i++) { - GLView component = getComponent(i); - if (component.getVisibility() == GONE) { - continue; - } - - if (mOrientation == VERTICAL) { - maxWidth = Math.max(maxWidth, component.getMeasuredWidth()); - if (i != 0) { - maxHeight += mInterval; - } - maxHeight += component.getMeasuredHeight(); - } else if (mOrientation == HORIZONTAL) { - maxHeight = Math.max(maxHeight, component.getMeasuredHeight()); - if (i != 0) { - maxWidth += mInterval; - } - maxWidth += component.getMeasuredWidth(); - } - } - - Rect paddings = getPaddings(); - maxWidth = maxWidth + paddings.left + paddings.right; - maxHeight = maxHeight + paddings.top + paddings.bottom; - - setMeasuredSize(getDefaultSize(maxWidth, widthSpec), getDefaultSize(maxHeight, heightSpec)); - } - - @Override - protected void onLayout(boolean changeSize, int left, int top, int right, int bottom) { - int width = getWidth(); - int height = getHeight(); - Rect paddings = getPaddings(); - int componentLeft; - int componentTop; - - if (mOrientation == VERTICAL) { - componentTop = paddings.top; - - for (int i = 0, n = getComponentCount(); i < n; i++) { - GLView component = getComponent(i); - if (component.getVisibility() == GONE) { - continue; - } - int measureWidth = component.getMeasuredWidth(); - int measureHeight = component.getMeasuredHeight(); - - LayoutParams lp = (LayoutParams) component.getLayoutParams(); - componentLeft = getDefaultBegin(width, measureWidth, paddings.left, paddings.right, - Gravity.getPosition(lp.gravity, Gravity.HORIZONTAL)); - component.layout(componentLeft, componentTop, - componentLeft + measureWidth, componentTop + measureHeight); - - componentTop += measureHeight + mInterval; - } - } else if (mOrientation == HORIZONTAL) { - componentLeft = paddings.left; - - for (int i = 0, n = getComponentCount(); i < n; i++) { - GLView component = getComponent(i); - if (component.getVisibility() == GONE) { - continue; - } - int measureWidth = component.getMeasuredWidth(); - int measureHeight = component.getMeasuredHeight(); - - LayoutParams lp = (LayoutParams) component.getLayoutParams(); - componentTop = getDefaultBegin(height, measureHeight, paddings.top, paddings.bottom, - Gravity.getPosition(lp.gravity, Gravity.VERTICAL)); - component.layout(componentLeft, componentTop, - componentLeft + measureWidth, componentTop + measureHeight); - - componentLeft += measureWidth + mInterval; - } - } - } - - @Override - protected boolean checkLayoutParams(GLView.LayoutParams p) { - return p instanceof LayoutParams; - } - - @Override - protected GLView.LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - } - - @Override - protected GLView.LayoutParams generateLayoutParams(GLView.LayoutParams p) { - return p == null ? generateDefaultLayoutParams() : new LayoutParams(p); - } - - public static class LayoutParams extends GravityLayoutParams { - - public float weight = 0.0f; - - public LayoutParams(GLView.LayoutParams source) { - super(source); - - if (source instanceof LayoutParams) { - weight = ((LayoutParams) source).weight; - } - } - - public LayoutParams(int width, int height) { - super(width, height); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/widget/GLMovableTextView.java b/app/src/main/java/com/hippo/gl/widget/GLMovableTextView.java deleted file mode 100644 index 1132b5059..000000000 --- a/app/src/main/java/com/hippo/gl/widget/GLMovableTextView.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.widget; - -import android.graphics.Rect; -import android.text.TextUtils; - -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.glrenderer.ImageMovableTextTexture; -import com.hippo.gl.view.GLView; -import com.hippo.gl.view.Gravity; -import com.hippo.yorozuya.collect.CollectionUtils; - -public class GLMovableTextView extends GLView { - - ImageMovableTextTexture mTextTexture; - - private String mText = ""; - private int[] mIndexes = CollectionUtils.EMPTY_INT_ARRAY; - - private int mGravity = Gravity.NO_GRAVITY; - - private void generateIndexes() { - if (mTextTexture == null || TextUtils.isEmpty(mText)) { - mIndexes = CollectionUtils.EMPTY_INT_ARRAY; - } else { - mIndexes = mTextTexture.getTextIndexes(mText); - } - } - - public void setTextTexture(ImageMovableTextTexture textTexture) { - if (mTextTexture == textTexture) { - return; - } - mTextTexture = textTexture; - - generateIndexes(); - requestLayout(); - } - - public void setText(String text) { - if (text == null) { - text = ""; - } - if (text.equals(mText)) { - return; - } - mText = text; - - generateIndexes(); - requestLayout(); - } - - public void setGravity(int gravity) { - if (mGravity != gravity) { - mGravity = gravity; - invalidate(); - } - } - - @Override - protected int getSuggestedMinimumWidth() { - if (mTextTexture == null) { - return super.getSuggestedMinimumWidth(); - } else { - return Math.max((int) mTextTexture.getTextWidth(mIndexes) + mPaddings.left + mPaddings.right, - super.getSuggestedMinimumWidth()); - } - } - - @Override - protected int getSuggestedMinimumHeight() { - if (mTextTexture == null) { - return super.getSuggestedMinimumHeight(); - } else { - return Math.max((int) mTextTexture.getTextHeight() + mPaddings.top + mPaddings.bottom, - super.getSuggestedMinimumHeight()); - } - } - - @Override - public void onRender(GLCanvas canvas) { - if (mTextTexture == null || mIndexes == null) { - return; - } - - Rect paddings = getPaddings(); - int x = getDefaultBegin(getWidth(), (int) mTextTexture.getTextWidth(mIndexes), - paddings.left, paddings.right, Gravity.getPosition(mGravity, Gravity.HORIZONTAL)); - int y = getDefaultBegin(getHeight(), (int) mTextTexture.getTextHeight(), - paddings.top, paddings.bottom, Gravity.getPosition(mGravity, Gravity.VERTICAL)); - mTextTexture.drawText(canvas, mIndexes, x, y); - } -} diff --git a/app/src/main/java/com/hippo/gl/widget/GLProgressView.java b/app/src/main/java/com/hippo/gl/widget/GLProgressView.java deleted file mode 100644 index 22e8c5bf4..000000000 --- a/app/src/main/java/com/hippo/gl/widget/GLProgressView.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.widget; - -import android.graphics.Color; -import android.graphics.Path; -import android.support.v4.view.animation.PathInterpolatorCompat; -import android.view.animation.Interpolator; -import android.view.animation.LinearInterpolator; - -import com.hippo.gl.anim.Animation; -import com.hippo.gl.anim.FloatAnimation; -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.glrenderer.GLPaint; -import com.hippo.gl.view.AnimationTime; -import com.hippo.gl.view.GLView; - -import java.util.ArrayList; -import java.util.List; - -public class GLProgressView extends GLView { - - private static final Interpolator TRIM_START_INTERPOLATOR; - private static final Interpolator TRIM_END_INTERPOLATOR; - private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); - - static { - Path trimStartPath = new Path(); - trimStartPath.moveTo(0.0f, 0.0f); - trimStartPath.lineTo(0.5f, 0.0f); - trimStartPath.cubicTo(0.7f, 0.0f, 0.6f, 1f, 1f, 1f); - TRIM_START_INTERPOLATOR = PathInterpolatorCompat.create(trimStartPath); - - Path trimEndPath = new Path(); - trimEndPath.moveTo(0.0f, 0.0f); - trimEndPath.cubicTo(0.2f, 0.0f, 0.1f, 1f, 0.5f, 1f); - trimEndPath.lineTo(1f, 1f); - TRIM_END_INTERPOLATOR = PathInterpolatorCompat.create(trimEndPath); - } - - private final GLPaint mGLPaint; - - private float mCx; - private float mCy; - private float mRadiusX; - private float mRadiusY; - - private float mTrimStart = 0.0f; - private float mTrimEnd = 0.0f; - private float mTrimOffset = 0.0f; - private float mTrimRotation = 0.0f; - - private boolean mIndeterminate = false; - - private List mAnimations; - - public GLProgressView() { - mGLPaint = new GLPaint(); - mGLPaint.setColor(Color.WHITE); - mGLPaint.setBackgroundColor(Color.BLACK); - mAnimations = new ArrayList<>(); - - setupAnimations(); - } - - public void setupAnimations() { - FloatAnimation trimStart = new FloatAnimation() { - @Override - protected void onCalculate(float progress) { - super.onCalculate(progress); - mTrimStart = get(); - } - }; - trimStart.setRange(0.0f, 0.75f); - trimStart.setDuration(1333L); - trimStart.setInterpolator(TRIM_START_INTERPOLATOR); - trimStart.setRepeatCount(Animation.INFINITE); - - FloatAnimation trimEnd = new FloatAnimation() { - @Override - protected void onCalculate(float progress) { - super.onCalculate(progress); - mTrimEnd = get(); - } - }; - trimEnd.setRange(0.0f, 0.75f); - trimEnd.setDuration(1333L); - trimEnd.setInterpolator(TRIM_END_INTERPOLATOR); - trimEnd.setRepeatCount(Animation.INFINITE); - - FloatAnimation trimOffset = new FloatAnimation() { - @Override - protected void onCalculate(float progress) { - super.onCalculate(progress); - mTrimOffset = get(); - } - }; - trimOffset.setRange(0.0f, 0.25f); - trimOffset.setDuration(1333L); - trimOffset.setInterpolator(LINEAR_INTERPOLATOR); - trimOffset.setRepeatCount(Animation.INFINITE); - - FloatAnimation trimRotation = new FloatAnimation() { - @Override - protected void onCalculate(float progress) { - super.onCalculate(progress); - mTrimRotation = get(); - } - }; - trimRotation.setRange(0.0f, 720.0f); - trimRotation.setDuration(6665L); - trimRotation.setInterpolator(LINEAR_INTERPOLATOR); - trimRotation.setRepeatCount(Animation.INFINITE); - - mAnimations.add(trimStart); - mAnimations.add(trimEnd); - mAnimations.add(trimOffset); - mAnimations.add(trimRotation); - } - - private void startAnimations() { - List animations = mAnimations; - for (int i = 0, n = animations.size(); i < n; i++) { - animations.get(i).reset(); - } - } - - private void stopAnimations() { - List animations = mAnimations; - for (int i = 0, n = animations.size(); i < n; i++) { - animations.get(i).cancel(); - } - } - - @Override - protected void onLayout(boolean changeSize, int left, int top, int right, - int bottom) { - super.onLayout(changeSize, left, top, right, bottom); - - int width = right - left; - int height = bottom - top; - mGLPaint.setLineWidth(Math.min(width, height) / 12.0f); - mCx = width / 2; - mCy = height / 2; - mRadiusX = width / 48.0f * 19.0f; - mRadiusY = height / 48.0f * 19.0f; - } - - public void setColor(int color) { - mGLPaint.setColor(color); - invalidate(); - } - - public void setBgColor(int color) { - mGLPaint.setBackgroundColor(color); - invalidate(); - } - - public void setIndeterminate(boolean indeterminate) { - if (mIndeterminate != indeterminate) { - mIndeterminate = indeterminate; - if (indeterminate) { - startAnimations(); - } else { - stopAnimations(); - } - invalidate(); - } - } - - public boolean isIndeterminate() { - return mIndeterminate; - } - - public void setProgress(float progress) { - if (!mIndeterminate) { - mTrimStart = 0.0f; - mTrimEnd = progress; - mTrimOffset = 0.0f; - mTrimRotation = 0.0f; - invalidate(); - } - } - - @Override - public void onRender(GLCanvas canvas) { - update(); - - int width = getWidth(); - int height = getHeight(); - int cx = width / 2; - int cy = height / 2; - - float startAngle = (mTrimStart + mTrimOffset) * 360.0f - 90; - float sweepAngle = Math.max(12.0f, (mTrimEnd - mTrimStart) * 360.0f); - float rotation = mTrimRotation + startAngle; - - canvas.save(); - - canvas.translate(cx, cy); - canvas.rotate(rotation, 0, 0, 1); - if (rotation % 180 != 0) { - canvas.translate(-cy, -cx); - } else { - canvas.translate(-cx, -cy); - } - - canvas.drawArc(mCx, mCy, mRadiusX, mRadiusY, sweepAngle, mGLPaint); - - canvas.restore(); - } - - private void update() { - boolean invalidate = false; - - if (mIndeterminate) { - long currentTime = AnimationTime.get(); - List animations = mAnimations; - for (int i = 0, n = animations.size(); i < n; i++) { - invalidate |= animations.get(i).calculate(currentTime); - } - } - - if (invalidate) { - invalidate(); - } - } -} diff --git a/app/src/main/java/com/hippo/gl/widget/GLTextureView.java b/app/src/main/java/com/hippo/gl/widget/GLTextureView.java deleted file mode 100644 index 36342d8b9..000000000 --- a/app/src/main/java/com/hippo/gl/widget/GLTextureView.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * 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.hippo.gl.widget; - -import android.graphics.RectF; - -import com.hippo.gl.glrenderer.GLCanvas; -import com.hippo.gl.glrenderer.Texture; -import com.hippo.gl.view.GLView; - -public class GLTextureView extends GLView { - - private final RectF mSrc = new RectF(); - private final RectF mDst = new RectF(); - - private Texture mTexture; - - public void setTexture(Texture texture) { - mTexture = texture; - if (texture != null) { - mSrc.set(0.0f, 0.0f, texture.getWidth(), texture.getHeight()); - } else { - mSrc.setEmpty(); - } - invalidate(); - } - - public Texture getTexture() { - return mTexture; - } - - @Override - protected int getSuggestedMinimumWidth() { - return mTexture == null ? super.getSuggestedMinimumWidth() : mTexture.getWidth() + mPaddings.width(); - } - - @Override - protected int getSuggestedMinimumHeight() { - return mTexture == null ? super.getSuggestedMinimumWidth() : mTexture.getHeight() + mPaddings.height(); - } - - @Override - public void onRender(GLCanvas canvas) { - if (mTexture == null || mSrc.isEmpty()) { - return; - } - - mDst.set(mPaddings.left, mPaddings.top, getWidth() - mPaddings.right, getHeight() - mPaddings.bottom); - if (mDst.isEmpty()) { - return; - } - - mTexture.draw(canvas, mSrc, mDst); - } -} diff --git a/app/src/main/res/layout/activity_gallery.xml b/app/src/main/res/layout/activity_gallery.xml index d0c4c83c9..2abe6e831 100644 --- a/app/src/main/res/layout/activity_gallery.xml +++ b/app/src/main/res/layout/activity_gallery.xml @@ -21,7 +21,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> -