11 |
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/PageFlip/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/PageFlip/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion '25.0.0'
6 |
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 24
10 | versionCode 2
11 | versionName "1.0.2"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | testCompile 'junit:junit:4.12'
24 | compile 'com.android.support:appcompat-v7:24.2.0'
25 | }
26 |
--------------------------------------------------------------------------------
/PageFlip/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/chao/Software/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/PageFlip/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/FoldBackVertexProgram.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.content.Context;
19 |
20 | import static android.opengl.GLES20.glGetUniformLocation;
21 |
22 | /**
23 | * FoldBack vertex shader program which is used to load:
24 | *
25 | *
fold_back_fragment_shader.glsl
26 | *
fold_back_vertex_shader.glsl
27 | *
28 | *
29 | * @author eschao
30 | */
31 |
32 | public class FoldBackVertexProgram extends VertexProgram {
33 |
34 | final static String VAR_TEXTRUE_OFFSET = "u_texXOffset";
35 | final static String VAR_MASK_COLOR = "u_maskColor";
36 | final static String VAR_SHADOW_TEXTURE = "u_shadow";
37 |
38 | int mShadowLoc;
39 | int mMaskColorLoc;
40 | int mTexXOffsetLoc;
41 |
42 | public FoldBackVertexProgram() {
43 | super();
44 |
45 | mShadowLoc = INVALID_GL_HANDLE;
46 | mMaskColorLoc = INVALID_GL_HANDLE;
47 | mTexXOffsetLoc = INVALID_GL_HANDLE;
48 | }
49 |
50 | /**
51 | * Initiate shader program
52 | *
53 | * @param context Android app context
54 | * @return self
55 | * @throws PageFlipException if fail to read and compile shader scripts
56 | */
57 | public FoldBackVertexProgram init(Context context) throws
58 | PageFlipException {
59 | super.init(context,
60 | R.raw.fold_back_vertex_shader,
61 | R.raw.fold_back_fragment_shader);
62 | return this;
63 | }
64 |
65 | /**
66 | * Get variable handles defined in shader script
67 | */
68 | protected void getVarsLocation() {
69 | super.getVarsLocation();
70 |
71 | if (mProgramRef != 0) {
72 | mShadowLoc = glGetUniformLocation(mProgramRef, VAR_SHADOW_TEXTURE);
73 | mMaskColorLoc = glGetUniformLocation(mProgramRef, VAR_MASK_COLOR);
74 | mTexXOffsetLoc = glGetUniformLocation(mProgramRef,
75 | VAR_TEXTRUE_OFFSET);
76 | }
77 | }
78 |
79 | /**
80 | * Delete all handles
81 | */
82 | public void delete() {
83 | super.delete();
84 |
85 | mShadowLoc = INVALID_GL_HANDLE;
86 | mMaskColorLoc = INVALID_GL_HANDLE;
87 | mTexXOffsetLoc = INVALID_GL_HANDLE;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/FoldBackVertexes.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.opengl.GLES20;
19 |
20 | import static android.opengl.GLES20.GL_TEXTURE_2D;
21 | import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
22 | import static android.opengl.GLES20.glActiveTexture;
23 | import static android.opengl.GLES20.glBindTexture;
24 | import static android.opengl.GLES20.glUniform1f;
25 | import static android.opengl.GLES20.glUniform1i;
26 | import static android.opengl.GLES20.glUniform4f;
27 | import static android.opengl.GLES20.glUniformMatrix4fv;
28 |
29 | /**
30 | * Vertex buffer management for back of fold page
31 | *
32 | * @author eschao
33 | */
34 | final class FoldBackVertexes extends Vertexes {
35 |
36 | private final static String TAG = "FoldBackVertexes";
37 |
38 | // mask alpha for back of fold page
39 | // mask color is in Page class since it follows the back of first bitmap
40 | float mMaskAlpha;
41 |
42 | public FoldBackVertexes() {
43 | super();
44 |
45 | mSizeOfPerVex = 4;
46 | mMaskAlpha = 0.6f;
47 | }
48 |
49 | /**
50 | * Set vertex buffer with given mesh count
51 | *
52 | * @param meshCount mesh count
53 | */
54 | public void set(int meshCount) {
55 | super.set(meshCount << 1, 4, true);
56 | mNext = 0;
57 | }
58 |
59 | /**
60 | * Set mask alpha
61 | *
62 | * @param alpha mask alpha, value is [0 .. 255]
63 | */
64 | public void setMaskAlpha(int alpha) {
65 | if (alpha < 0 || alpha > 255) {
66 | throw new IllegalArgumentException("Alpha: " + alpha + "is out of "
67 | + "[0 .. 255]!");
68 | }
69 |
70 | mMaskAlpha = alpha / 255.0f;
71 | }
72 |
73 | /**
74 | * set mask alpha
75 | *
76 | * @param alpha mask alpha, value is [0 .. 1]
77 | */
78 | public void setMaskAlpha(float alpha) {
79 | if (alpha < 0 || alpha > 1) {
80 | throw new IllegalArgumentException("Alpha: " + alpha + "is out of "
81 | + "[0 .. 1]!");
82 | }
83 |
84 | mMaskAlpha = alpha;
85 | }
86 |
87 | /**
88 | * Draw fold back and shadow
89 | *
90 | * @param program fold back vertex program
91 | * @param page the current operating page: First Page
92 | * @param hasSecondPage there has second page or not
93 | * @param gradientShadowId gradient shadow id
94 | */
95 | public void draw(FoldBackVertexProgram program,
96 | Page page,
97 | boolean hasSecondPage,
98 | int gradientShadowId) {
99 | glUniformMatrix4fv(program.mMVPMatrixLoc, 1, false,
100 | VertexProgram.MVPMatrix, 0);
101 |
102 | // load fold back texture
103 | glBindTexture(GL_TEXTURE_2D, page.getBackTextureID());
104 | glUniform1i(program.mTextureLoc, 0);
105 |
106 | // load gradient shadow texture
107 | glActiveTexture(GLES20.GL_TEXTURE1);
108 | glBindTexture(GL_TEXTURE_2D, gradientShadowId);
109 | glUniform1i(program.mShadowLoc, 1);
110 |
111 | // set x offset of texture coordinate. In single page mode, the value is
112 | // set 0 to draw the back texture with x coordinate inversely against
113 | // the first texture since they are using the same texture, but in
114 | // double page mode, the back texture is different with the first one,
115 | // it is the next page content texture and should be drawn in the same
116 | // order with the first texture, so the value is set 1. For computing
117 | // details, please see the shader script.
118 | glUniform1f(program.mTexXOffsetLoc, hasSecondPage ? 1.0f : 0);
119 |
120 | // set mask color and alpha
121 | glUniform4f(program.mMaskColorLoc,
122 | page.maskColor[0][0],
123 | page.maskColor[0][1],
124 | page.maskColor[0][2],
125 | hasSecondPage ? 0 : mMaskAlpha);
126 |
127 | // draw triangles
128 | drawWith(GL_TRIANGLE_STRIP,
129 | program.mVertexPosLoc,
130 | program.mTexCoordLoc);
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/GLPoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | /**
19 | * GLPoint includes (x,y,z) in OpenGL coordinate system and its texture
20 | * coordinates (texX, texY)
21 | *
22 | * @author eschao
23 | */
24 | public final class GLPoint {
25 | // 3D coordinate
26 | float x;
27 | float y;
28 | float z;
29 |
30 | // texutre coordinate
31 | float texX;
32 | float texY;
33 |
34 | /**
35 | * Set GLPoint with given values
36 | *
37 | * @param x x coordinate
38 | * @param y y coordinate
39 | * @param z z coordinate
40 | * @param tX x coordinate of texture
41 | * @param tY y coordinate of texture
42 | */
43 | public void set(float x, float y, float z, float tX, float tY) {
44 | this.x = x;
45 | this.y = y;
46 | this.z = z;
47 | this.texX = tX;
48 | this.texY = tY;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/GLProgram.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.content.Context;
19 |
20 | import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
21 | import static android.opengl.GLES20.GL_LINK_STATUS;
22 | import static android.opengl.GLES20.GL_VERTEX_SHADER;
23 | import static android.opengl.GLES20.glAttachShader;
24 | import static android.opengl.GLES20.glCreateProgram;
25 | import static android.opengl.GLES20.glDeleteProgram;
26 | import static android.opengl.GLES20.glGetProgramiv;
27 | import static android.opengl.GLES20.glLinkProgram;
28 | import static android.opengl.GLES20.glUseProgram;
29 |
30 | /**
31 | * GLSL program class is used to load, compile and link shader scripts
32 | *
33 | * @author eschao
34 | */
35 |
36 | public class GLProgram {
37 |
38 | // invalid GL getShaderRef including program reference and variable location
39 | protected final int INVALID_GL_HANDLE = -1;
40 |
41 | // GLSL program reference
42 | protected int mProgramRef;
43 |
44 | // Vertex shader
45 | protected GLShader mVertex;
46 |
47 | // Fragment shader
48 | protected GLShader mFragment;
49 |
50 | public GLProgram() {
51 | mProgramRef = INVALID_GL_HANDLE;
52 | mVertex = new GLShader();
53 | mFragment = new GLShader();
54 | }
55 |
56 | /**
57 | * Initiate with given vertex shader and fragment shader
58 | *
59 | * @param context android context
60 | * @param vertexResId vertex shader script id
61 | * @param fragmentResId fragment shader script id
62 | * @return self
63 | * @throws PageFlipException if fail to read or compile shader scripts
64 | */
65 | public GLProgram init(Context context, int vertexResId, int fragmentResId)
66 | throws PageFlipException {
67 | // 1. init shader
68 | try {
69 | mVertex.compile(context, GL_VERTEX_SHADER, vertexResId);
70 | mFragment.compile(context, GL_FRAGMENT_SHADER, fragmentResId);
71 | }
72 | catch (PageFlipException e) {
73 | mVertex.delete();
74 | mFragment.delete();
75 | throw e;
76 | }
77 |
78 | // 2. create texture program and link shader
79 | mProgramRef = glCreateProgram();
80 | if (mProgramRef == 0) {
81 | mVertex.delete();
82 | mFragment.delete();
83 | throw new PageFlipException("Can't create texture program");
84 | }
85 |
86 | // 3. attach vertex and fragment shader
87 | glAttachShader(mProgramRef, mVertex.getShaderRef());
88 | glAttachShader(mProgramRef, mFragment.getShaderRef());
89 | glLinkProgram(mProgramRef);
90 |
91 | // 4. check shader link status
92 | int[] result = new int[1];
93 | glGetProgramiv(mProgramRef, GL_LINK_STATUS, result, 0);
94 | if (result[0] == 0) {
95 | delete();
96 | throw new PageFlipException("Can't link program");
97 | }
98 |
99 | // 5. get all variable handles defined in scripts
100 | // subclass should implement getVarsLocation to be responsible for its
101 | // own variables in script
102 | glUseProgram(mProgramRef);
103 | getVarsLocation();
104 | return this;
105 | }
106 |
107 | /**
108 | * Delete all handles
109 | */
110 | public void delete() {
111 | mVertex.delete();
112 | mFragment.delete();
113 |
114 | if (mProgramRef != INVALID_GL_HANDLE) {
115 | glDeleteProgram(mProgramRef);
116 | mProgramRef = INVALID_GL_HANDLE;
117 | }
118 | }
119 |
120 | /**
121 | * Get program GL reference
122 | *
123 | * @return program GL reference for program
124 | */
125 | public int getProgramRef() {
126 | return mProgramRef;
127 | }
128 |
129 | /**
130 | * Subclass should implement it to get its own variable handles which are
131 | * defined in its shader scripts
132 | */
133 | protected void getVarsLocation() {
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/GLShader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.content.Context;
19 | import android.util.Log;
20 |
21 | import java.io.BufferedReader;
22 | import java.io.IOException;
23 | import java.io.InputStreamReader;
24 |
25 | import static android.opengl.GLES20.GL_COMPILE_STATUS;
26 | import static android.opengl.GLES20.glCompileShader;
27 | import static android.opengl.GLES20.glCreateShader;
28 | import static android.opengl.GLES20.glDeleteShader;
29 | import static android.opengl.GLES20.glGetError;
30 | import static android.opengl.GLES20.glGetShaderInfoLog;
31 | import static android.opengl.GLES20.glGetShaderiv;
32 | import static android.opengl.GLES20.glShaderSource;
33 |
34 | /**
35 | * GLSL shader class is used to load and compile shader script
36 | *
37 | * @author eschao
38 | */
39 |
40 | public class GLShader {
41 |
42 | private final static String TAG = "GLShader";
43 | private final int INVALID_GL_HANDLE = -1;
44 |
45 | // shader object reference
46 | int mShaderRef;
47 |
48 | /**
49 | * Default constructor
50 | */
51 | public GLShader() {
52 | mShaderRef = INVALID_GL_HANDLE;
53 | }
54 |
55 | /**
56 | * Read shader script from resources and compile
57 | *
58 | * @param context android context
59 | * @param type GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
60 | * @param resId script resource id
61 | * @return self
62 | * @throws PageFlipException if fail to compile shader script
63 | */
64 | public GLShader compile(Context context, int type, int resId)
65 | throws PageFlipException {
66 | // read shader scripts from resource
67 | String codes = readGLSLFromResource(context, resId);
68 | if (codes.length() < 1) {
69 | throw new PageFlipException("Empty GLSL shader for resource id:"
70 | + resId);
71 | }
72 |
73 | // create a shader
74 | mShaderRef = glCreateShader(type);
75 | if (mShaderRef != INVALID_GL_HANDLE) {
76 | // upload shader scripts to GL
77 | glShaderSource(mShaderRef, codes);
78 |
79 | // compile shader scripts
80 | glCompileShader(mShaderRef);
81 |
82 | // get compile results to check if it is successful
83 | final int[] result = new int[1];
84 | glGetShaderiv(mShaderRef, GL_COMPILE_STATUS, result, 0);
85 | if (result[0] == 0) {
86 | // delete shader if compile is failed
87 | Log.e(TAG, "Can'top compile shader for type: " + type +
88 | "Error: " + glGetError());
89 | Log.e(TAG, "Compile shader error: " +
90 | glGetShaderInfoLog(mShaderRef));
91 | glDeleteShader(mShaderRef);
92 | throw new PageFlipException("Can't compile shader for" +
93 | "type: " + type);
94 | }
95 | } else {
96 | throw new PageFlipException("Can't create shader. Error: " +
97 | glGetError());
98 | }
99 |
100 | return this;
101 | }
102 |
103 | /**
104 | * Delete shader
105 | */
106 | public void delete() {
107 | if (mShaderRef != INVALID_GL_HANDLE) {
108 | glDeleteShader(mShaderRef);
109 | mShaderRef = INVALID_GL_HANDLE;
110 | }
111 | }
112 |
113 | /**
114 | * Get shader object reference
115 | *
116 | * @return shader object reference in OpenGL
117 | */
118 | public int getShaderRef() {
119 | return mShaderRef;
120 | }
121 |
122 | /**
123 | * Read shader script from resources
124 | *
125 | * @param context android context
126 | * @param resId script resource id
127 | * @return shader script contents
128 | * @throws PageFlipException if fail to read script from resources
129 | */
130 | String readGLSLFromResource(Context context, int resId) throws
131 | PageFlipException {
132 | StringBuilder s = new StringBuilder();
133 | BufferedReader reader = null;
134 |
135 | try {
136 | reader = new BufferedReader(new InputStreamReader(
137 | context.getResources().openRawResource(resId)));
138 | String line;
139 |
140 | while ((line = reader.readLine()) != null) {
141 | s.append(line);
142 | s.append("\n");
143 | }
144 | }
145 | catch (IOException e) {
146 | throw new PageFlipException("Could not open resource: "
147 | + resId , e);
148 | }
149 | finally {
150 | // close
151 | try {
152 | if (reader != null) {
153 | reader.close();
154 | }
155 | }
156 | catch (IOException e) {
157 | }
158 | }
159 |
160 | return s.toString();
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/GLViewRect.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | /**
19 | * View utility
20 | *
21 | * @author eschao
22 | */
23 |
24 | public final class GLViewRect {
25 |
26 | // view left
27 | float left;
28 | // view right
29 | float right;
30 | // view top
31 | float top;
32 | // view bottom
33 | float bottom;
34 | // view width
35 | float width;
36 | // view height
37 | float height;
38 | // view half width
39 | float halfW;
40 | // view half height
41 | float halfH;
42 | // view margin left
43 | float marginL;
44 | // view margin right
45 | float marginR;
46 | // openGL surface width, it should be >= view width
47 | float surfaceW;
48 | // openGL surface height, it should be >= view height
49 | float surfaceH;
50 |
51 | /**
52 | * Default constructor
53 | */
54 | public GLViewRect() {
55 | left = 0;
56 | right = 0;
57 | top = 0;
58 | bottom = 0;
59 | width = 0;
60 | height = 0;
61 | halfW = 0;
62 | halfH = 0;
63 | marginL = 0;
64 | marginR = 0;
65 | surfaceW = 0;
66 | surfaceH = 0;
67 | }
68 |
69 | /**
70 | * Construct with surface and margin size
71 | *
72 | * @param surfaceW openGL surface width
73 | * @param surfaceH openGl surface height
74 | * @param marginL margin left
75 | * @param marginR margin right
76 | */
77 | public GLViewRect(float surfaceW, float surfaceH,
78 | float marginL, float marginR) {
79 | set(surfaceW, surfaceH, marginL, marginR);
80 | }
81 |
82 | /**
83 | * Set margin
84 | *
85 | * @param marginL margin left
86 | * @param marginR margin right
87 | * @return self
88 | */
89 | public GLViewRect setMargin(float marginL, float marginR) {
90 | return set(this.surfaceW, this.surfaceH, marginL, marginR);
91 | }
92 |
93 | /**
94 | * Set with surface size
95 | *
96 | * @param surfaceW openGL surface width
97 | * @param surfaceH openGl surface height
98 | * @return self
99 | */
100 | public GLViewRect set(float surfaceW, float surfaceH) {
101 | return set(surfaceW, surfaceH, this.marginL, this.marginR);
102 | }
103 |
104 | /**
105 | * Set with surface size and margin size
106 | *
107 | * @param surfaceW openGL surface width
108 | * @param surfaceH openGl surface height
109 | * @param marginL margin left
110 | * @param marginR margin right
111 | * @return self
112 | */
113 | public GLViewRect set(float surfaceW, float surfaceH,
114 | float marginL, float marginR) {
115 | this.surfaceW = surfaceW;
116 | this.surfaceH = surfaceH;
117 | this.marginL = marginL;
118 | this.marginR = marginR;
119 |
120 | width = surfaceW - marginL - marginR;
121 | height = surfaceH;
122 | halfW = width * 0.5f;
123 | halfH = height * 0.5f;
124 | left = -halfW + marginL;
125 | right = halfW - marginR;
126 | top = halfH;
127 | bottom = -halfH;
128 | return this;
129 | }
130 |
131 | /**
132 | * Get minimal value between width and height
133 | *
134 | * @return minimal value
135 | */
136 | public float minOfWH() {
137 | return width > height ? width : height;
138 | }
139 |
140 | /**
141 | * Translate Android coordinate to OpenGL coordinate
142 | *
143 | * Android screen coordinate:
144 | * *------------> X[0..Width]
145 | * |
146 | * |
147 | * |
148 | * V
149 | * Y[0..Height]
150 | *
151 | * OpenGL screen coordinate:
152 | * Y[0..Height/2]
153 | * ^
154 | * |
155 | * |
156 | * +-----------> X[0..Width/2]
157 | * /
158 | * /
159 | * /
160 | * Z[0..1]
161 | *
162 | */
163 | public float toOpenGLX(float x) {
164 | return x - halfW;
165 | }
166 |
167 | public float toOpenGLY(float y) {
168 | return halfH - y;
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/OnPageFlipListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | /**
19 | * Listener for page flipping
20 | *
21 | * @author eschao
22 | */
23 |
24 | public interface OnPageFlipListener {
25 |
26 | /**
27 | * Can page flip forward?
28 | *
29 | * @return true if page can flip forward
30 | */
31 | boolean canFlipForward();
32 |
33 | /**
34 | * Can page flip backward?
35 | *
36 | * @return true if page can flip backward
37 | */
38 | boolean canFlipBackward();
39 | }
40 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/Page.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.graphics.Bitmap;
19 | import android.graphics.Color;
20 | import android.graphics.PointF;
21 | import android.opengl.GLUtils;
22 |
23 | import java.nio.ByteBuffer;
24 | import java.nio.ByteOrder;
25 | import java.nio.FloatBuffer;
26 |
27 | import static android.opengl.GLES20.GL_FLOAT;
28 | import static android.opengl.GLES20.GL_LINEAR;
29 | import static android.opengl.GLES20.GL_TEXTURE0;
30 | import static android.opengl.GLES20.GL_TEXTURE_2D;
31 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
32 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
33 | import static android.opengl.GLES20.GL_TRIANGLE_FAN;
34 | import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
35 | import static android.opengl.GLES20.glActiveTexture;
36 | import static android.opengl.GLES20.glBindTexture;
37 | import static android.opengl.GLES20.glDeleteTextures;
38 | import static android.opengl.GLES20.glDrawArrays;
39 | import static android.opengl.GLES20.glEnableVertexAttribArray;
40 | import static android.opengl.GLES20.glGenTextures;
41 | import static android.opengl.GLES20.glTexParameterf;
42 | import static android.opengl.GLES20.glUniform1i;
43 | import static android.opengl.GLES20.glUniformMatrix4fv;
44 | import static android.opengl.GLES20.glVertexAttribPointer;
45 |
46 | /**
47 | * Page class
48 | *
49 | * Page holds content textures and show them on screen. In single page mode, a
50 | * page represents the whole screen area. But in double pages mode, there are
51 | * two pages to depict the entire screen size, in the left part is called left
52 | * page and the right part is called right page.
53 | * Every page has the below properties:
54 | *
55 | *
56 | *
Page size: left/right/top/bottom and width/height
57 | *
Holding 3 content textures for drawing:
58 | *
59 | *
The first texture: which is showing on screen when page is
60 | * stationary, we can relatively call it as the first 'Page' at
61 | * some extend
62 | *
The second texture: normally it can be called the second
63 | * 'Page' against the first texture. It will be appeared when page
64 | * is flipping or flip is over, in the later, the second texture
65 | * will eventually become the first one
66 | *
The back texture: in single page mode, the back texture is
67 | * always same with the first texture, thus, the caller shouldn't
68 | * set it before drawing. But in double pages mode, it should be
69 | * set with a different texture and can be called the second 'Page'
70 | * , at this time, the second texture will be called the third
71 | * 'Page' as like we're reading a book
72 | *
Every texture should be set with a bitmap by outside caller
73 | *
74 | *
75 | *
76 | *
77 | *
78 | * @author eschao
79 | */
80 |
81 | public class Page {
82 |
83 | private final static int TEXTURE_SIZE = 3;
84 | private final static int FIRST_TEXTURE_ID = 0;
85 | private final static int SECOND_TEXTURE_ID = 1;
86 | private final static int BACK_TEXTURE_ID = 2;
87 | private final static int INVALID_TEXTURE_ID = -1;
88 |
89 | /**
90 | *
91 | * 4 apexes of page has different permutation order according to original
92 | * point since original point will be changed when user click to curl page
93 | * from different direction. There are 4 kinds of order:
94 | *
95 | * A B C D
96 | * 2 1 3 0 0 3 1 2
97 | * +----+ +----+ +----+ +----+
98 | * | | | | | | | |
99 | * +----+ +----+ +----+ +----+
100 | * 3 0 2 1 1 2 0 3
101 | * From A From A From A
102 | * 0 <-> 1 0 <-> 2 0 <-> 3
103 | * 3 <-> 2 3 <-> 1 1 <-> 2
104 | *
105 | *
106 | *
0 always represents the origin point, accordingly 2 is diagonal
107 | * point
108 | *
Case A is default order: 0 -> 1 -> 2 -> 3
109 | *
Every apex data is stored in mApexes following the case A order
110 | * and never changed
111 | *
This array is mapping apex order (case A - D) to real apex data
112 | * stored in mApexes. For example:
113 | *
114 | *
Case A has same order with storing sequence of apex data in
115 | * mApexes
116 | *
Case B: the 0 apex is stored in 1 position in mApexes
117 | *
118 | *
119 | */
120 | private final static int[][] mPageApexOrders = new int[][] {
121 | new int[] {0, 1, 2, 3}, // for case A
122 | new int[] {1, 0, 3, 2}, // for case B
123 | new int[] {2, 3, 0, 1}, // for case C
124 | new int[] {3, 2, 1, 0}, // for case D
125 | };
126 |
127 | /**
128 | *
When page is curled, there are 4 kinds of vertexes orders for drawing
129 | * first texture and second texture with TRIANGLE_STRIP way
130 | * A B C D
131 | * 2 1 2 X 1 2 X 1 2 1
132 | * +-------+ +-----.-+ +-.-----+ +-------+
133 | * | | | F / | |/ | | F |
134 | * | F .Y | / | Y. S | X.-------.Y
135 | * | /| | / | | | | S |
136 | * +-----.-+ +-.-----+ +-------+ +-------+
137 | * 3 X 0 3 Y 0 3 0 3 0
138 | *
139 | *
140 | *
All cases are based on the apex order case A(0 -> 1 -> 2 -> 3)
141 | *
142 | *
F means the first texture area, S means the second texture area
143 | *
144 | *
X is xFoldX point, Y is yFoldY point
145 | *
Case A means: xFoldX and yFoldY are both in page
146 | *
Case B means: xFoldX is in page, but yFoldY is the intersecting
147 | * point with line 1->2 since yFoldY is outside the page
148 | *
Case C means: xFoldX and yFoldY are both outside the page
149 | *
Case D means: xFoldX outside page but yFoldY is in the page
150 | *
Combining {@link #mPageApexOrders} with this array, we can get
151 | * the right apex data from mApexes array which will help us quickly
152 | * organizing triangle data for openGL drawing
153 | *
The last array(Case E) in this array means: xFoldX and yFoldY
154 | * are both outside the page and the whole page will be draw with
155 | * second texture
156 | *
157 | */
158 | private final static int[][] mFoldVexOrders = new int[][] {
159 | new int[] {4, 3, 1, 2, 0}, // Case A
160 | new int[] {3, 3, 2, 0, 1}, // Case B
161 | new int[] {3, 2, 1, 3, 0}, // Case C
162 | new int[] {2, 2, 3, 1, 0}, // Case D
163 | new int[] {1, 0, 1, 3, 2}, // Case E
164 | };
165 |
166 | // page size
167 | float left;
168 | float right;
169 | float top;
170 | float bottom;
171 | float width;
172 | float height;
173 |
174 | // texture size for rendering page, normally they are same with page width
175 | // and height
176 | float texWidth;
177 | float texHeight;
178 |
179 | /**
180 | *
188 | */
189 | GLPoint originP;
190 | GLPoint diagonalP;
191 |
192 | private GLPoint mXFoldP;
193 | private GLPoint mYFoldP;
194 |
195 | // vertexes and texture coordinates buffer for full page
196 | private FloatBuffer mFullPageVexBuf;
197 | private FloatBuffer mFullPageTexCoordsBuf;
198 |
199 | // storing 4 apexes data of page
200 | private float[] mApexes;
201 | // texture coordinates for page apex
202 | private float[] mApexTexCoords;
203 | // vertex size of front of fold page and unfold page
204 | private int mFrontVertexSize;
205 | // index of apex order array for current original point
206 | private int mApexOrderIndex;
207 |
208 | // mask color of back texture
209 | float[][] maskColor;
210 |
211 | // texture(front, back and second) ids allocated by OpenGL
212 | private int[] mTexIDs;
213 | // unused texture ids, will be deleted when next OpenGL drawing
214 | private int[] mUnusedTexIDs;
215 | // actual size of mUnusedTexIDs
216 | private int mUnusedTexSize;
217 |
218 | /**
219 | * Constructor
220 | */
221 | public Page() {
222 | init(0, 0, 0, 0);
223 | }
224 |
225 | /**
226 | * Constructor with page size
227 | */
228 | public Page(float l, float r, float t, float b) {
229 | init(l, r, t, b);
230 | }
231 |
232 | private void init(float l, float r, float t, float b) {
233 | top = t;
234 | left = l;
235 | right = r;
236 | bottom = b;
237 | width = right - left;
238 | height = top - bottom;
239 | texWidth = width;
240 | texHeight = height;
241 | mFrontVertexSize = 0;
242 | mApexOrderIndex = 0;
243 |
244 | mXFoldP = new GLPoint();
245 | mYFoldP = new GLPoint();
246 | originP = new GLPoint();
247 | diagonalP = new GLPoint();
248 |
249 | maskColor = new float[][] {new float[] {0, 0, 0},
250 | new float[] {0, 0, 0},
251 | new float[] {0, 0, 0}};
252 |
253 | mTexIDs = new int[] {INVALID_TEXTURE_ID,
254 | INVALID_TEXTURE_ID,
255 | INVALID_TEXTURE_ID};
256 | mUnusedTexSize = 0;
257 | mUnusedTexIDs = new int[] {INVALID_TEXTURE_ID,
258 | INVALID_TEXTURE_ID,
259 | INVALID_TEXTURE_ID};
260 |
261 | createVertexesBuffer();
262 | buildVertexesOfFullPage();
263 | }
264 |
265 | /**
266 | * Is the left page?
267 | *
Left page represents the left screen in double pages mode
268 | *
269 | * @return true if current page is left page
270 | */
271 | public boolean isLeftPage() {
272 | return right <= 0;
273 | }
274 |
275 | /**
276 | * Is the right page?
277 | *
Right page represents the right screen in double pages mode
278 | *
279 | * @return true if current page is right page
280 | */
281 | public boolean isRightPage() {
282 | return left >= 0;
283 | }
284 |
285 | /**
286 | * Get page width
287 | *
288 | * @return page width
289 | */
290 | public float width() {
291 | return width;
292 | }
293 |
294 | /**
295 | * Gets page height
296 | *
297 | * @return page height
298 | */
299 | public float height() {
300 | return height;
301 | }
302 |
303 | /**
304 | * Is the first texture set?
305 | *
306 | * @return true if the first texture is set
307 | */
308 | public boolean isFirstTextureSet() {
309 | return mTexIDs[FIRST_TEXTURE_ID] != INVALID_TEXTURE_ID;
310 | }
311 |
312 | /**
313 | * Is the second texture set ?
314 | *
315 | * @return true if the second texture is set
316 | */
317 | public boolean isSecondTextureSet() {
318 | return mTexIDs[SECOND_TEXTURE_ID] != INVALID_TEXTURE_ID;
319 | }
320 |
321 | /**
322 | * Is the back texture set ?
323 | *
324 | * @return true if the back texture is set
325 | */
326 | public boolean isBackTextureSet() {
327 | return mTexIDs[BACK_TEXTURE_ID] != INVALID_TEXTURE_ID;
328 | }
329 |
330 | /**
331 | * Deletes unused texture ids
332 | *
It should be called in OpenGL thread
333 | */
334 | public void deleteUnusedTextures() {
335 | if (mUnusedTexSize > 0) {
336 | glDeleteTextures(mUnusedTexSize, mUnusedTexIDs, 0);
337 | mUnusedTexSize = 0;
338 | }
339 | }
340 |
341 | /**
342 | * Recycle the first texture id and set it with the second texture
343 | *
Manually call this function to set the first texture with the second
344 | * one after page forward flipped over in single page mode.
345 | *
346 | * @return self
347 | */
348 | public Page setFirstTextureWithSecond() {
349 | if (mTexIDs[FIRST_TEXTURE_ID] > INVALID_TEXTURE_ID) {
350 | mUnusedTexIDs[mUnusedTexSize++] = mTexIDs[FIRST_TEXTURE_ID];
351 | }
352 |
353 | maskColor[FIRST_TEXTURE_ID][0] = maskColor[SECOND_TEXTURE_ID][0];
354 | maskColor[FIRST_TEXTURE_ID][1] = maskColor[SECOND_TEXTURE_ID][1];
355 | maskColor[FIRST_TEXTURE_ID][2] = maskColor[SECOND_TEXTURE_ID][2];
356 | mTexIDs[FIRST_TEXTURE_ID] = mTexIDs[SECOND_TEXTURE_ID];
357 | mTexIDs[SECOND_TEXTURE_ID] = INVALID_TEXTURE_ID;
358 | return this;
359 | }
360 |
361 | /**
362 | * Recycle the second texture id and set it with the first texture
363 | *
Manually call this function to set the second texture with the first
364 | * one when page is backward flipping in single page mode.
717 | * There is only one case to draw when page is flipping vertically
718 | *
719 | *
720 | *
Page is flipping from right -> left
721 | *
Origin point: 3
722 | *
Diagonal point: 1
723 | *
xFoldP1.y: fY, xFoldP2.x: fX
724 | *
Drawing front part with the first texture(GL_TRIANGLE_STRIP):
725 | * fX -> fY -> 4 -> 1
726 | *
Drawing back part with the second texture(GL_TRIANGLE_STRIP):
727 | * 3 -> 2 -> fX -> fY
728 | *
729 | *
730 | * @param frontVertexes vertexes for drawing font part of page
731 | * @param xFoldP1 fold point on X axis
732 | */
733 | public void buildVertexesOfPageWhenVertical(Vertexes frontVertexes,
734 | PointF xFoldP1) {
735 | // if xFoldX and yFoldY are both outside the page, use the last vertex
736 | // order to draw page
737 | int index = 4;
738 |
739 | // compute xFoldX and yFoldY points
740 | if (!isXOutsidePage(xFoldP1.x)) {
741 | // use the case B of vertex order to draw page
742 | index = 1;
743 | float cx = textureX(xFoldP1.x);
744 | mXFoldP.set(xFoldP1.x, originP.y, 0, cx, originP.texY);
745 | mYFoldP.set(xFoldP1.x, diagonalP.y, 0, cx, diagonalP.texY);
746 | }
747 |
748 | // get apex order and fold vertex order
749 | final int[] apexOrder = mPageApexOrders[mApexOrderIndex];
750 | final int[] vexOrder = mFoldVexOrders[index];
751 |
752 | // need to draw first texture, add xFoldX and yFoldY first. Remember
753 | // the adding order of vertex in float buffer is X point prior to Y
754 | // point
755 | if (vexOrder[0] > 1) {
756 | frontVertexes.addVertex(mXFoldP).addVertex(mYFoldP);
757 | }
758 |
759 | // add the leftover vertexes for the first texture
760 | for (int i = 1; i < vexOrder[0]; ++i) {
761 | int k = apexOrder[vexOrder[i]];
762 | int m = k * 3;
763 | int n = k << 1;
764 | frontVertexes.addVertex(mApexes[m], mApexes[m + 1], 0,
765 | mApexTexCoords[n], mApexTexCoords[n + 1]);
766 | }
767 |
768 | // the vertex size for drawing front of fold page and first texture
769 | mFrontVertexSize = frontVertexes.mNext / 3;
770 |
771 | // if xFoldX and yFoldY are in the page, need add them for drawing the
772 | // second texture
773 | if (vexOrder[0] > 1) {
774 | mXFoldP.z = mYFoldP.z = -1;
775 | frontVertexes.addVertex(mXFoldP).addVertex(mYFoldP);
776 | }
777 |
778 | // add the remaining vertexes for the second texture
779 | for (int i = vexOrder[0]; i < vexOrder.length; ++i) {
780 | int k = apexOrder[vexOrder[i]];
781 | int m = k * 3;
782 | int n = k << 1;
783 | frontVertexes.addVertex(mApexes[m], mApexes[m + 1], -1,
784 | mApexTexCoords[n], mApexTexCoords[n + 1]);
785 | }
786 | }
787 |
788 | /**
789 | * Build vertexes of page when page flip is slope
790 | *
See {@link #mApexOrderIndex} and {@link #mFoldVexOrders} to get more
791 | * details
792 | *
793 | * @param frontVertexes vertexes for drawing front part of page
794 | * @param xFoldP1 fold point on X axis
795 | * @param yFoldP1 fold point on Y axis
796 | * @param kValue tan value of page curling angle
797 | */
798 | public void buildVertexesOfPageWhenSlope(Vertexes frontVertexes,
799 | PointF xFoldP1,
800 | PointF yFoldP1,
801 | float kValue) {
802 | // compute xFoldX point
803 | float halfH = height * 0.5f;
804 | int index = 0;
805 | mXFoldP.set(xFoldP1.x, originP.y, 0, textureX(xFoldP1.x), originP.texY);
806 | if (isXOutsidePage(xFoldP1.x)) {
807 | index = 2;
808 | mXFoldP.x = diagonalP.x;
809 | mXFoldP.y = originP.y + (xFoldP1.x - diagonalP.x) / kValue;
810 | mXFoldP.texX = diagonalP.texX;
811 | mXFoldP.texY = textureY(mXFoldP.y);
812 | }
813 |
814 | // compute yFoldY point
815 | mYFoldP.set(originP.x, yFoldP1.y, 0, originP.texX, textureY(yFoldP1.y));
816 | if (Math.abs(yFoldP1.y) > halfH) {
817 | index++;
818 | mYFoldP.x = originP.x + kValue * (yFoldP1.y - diagonalP.y);
819 | if (isXOutsidePage(mYFoldP.x)) {
820 | index++;
821 | }
822 | else {
823 | mYFoldP.y = diagonalP.y;
824 | mYFoldP.texX = textureX(mYFoldP.x);
825 | mYFoldP.texY = diagonalP.texY;
826 | }
827 | }
828 |
829 | // get apex order and fold vertex order
830 | final int[] apexOrder = mPageApexOrders[mApexOrderIndex];
831 | final int[] vexOrder = mFoldVexOrders[index];
832 |
833 | // need to draw first texture, add xFoldX and yFoldY first. Remember
834 | // the adding order of vertex in float buffer is X point prior to Y
835 | // point
836 | if (vexOrder[0] > 1) {
837 | frontVertexes.addVertex(mXFoldP).addVertex(mYFoldP);
838 | }
839 |
840 | // add the leftover vertexes for the first texture
841 | for (int i = 1; i < vexOrder[0]; ++i) {
842 | int k = apexOrder[vexOrder[i]];
843 | int m = k * 3;
844 | int n = k << 1;
845 | frontVertexes.addVertex(mApexes[m], mApexes[m + 1], 0,
846 | mApexTexCoords[n], mApexTexCoords[n + 1]);
847 | }
848 |
849 | // the vertex size for drawing front of fold page and first texture
850 | mFrontVertexSize = frontVertexes.mNext / 3;
851 |
852 | // if xFoldX and yFoldY are in the page, need add them for drawing the
853 | // second texture
854 | if (vexOrder[0] > 1) {
855 | mXFoldP.z = mYFoldP.z = -1;
856 | frontVertexes.addVertex(mXFoldP).addVertex(mYFoldP);
857 | }
858 |
859 | // add the remaining vertexes for the second texture
860 | for (int i = vexOrder[0]; i < vexOrder.length; ++i) {
861 | int k = apexOrder[vexOrder[i]];
862 | int m = k * 3;
863 | int n = k << 1;
864 | frontVertexes.addVertex(mApexes[m], mApexes[m + 1], -1,
865 | mApexTexCoords[n], mApexTexCoords[n + 1]);
866 | }
867 | }
868 |
869 | /**
870 | * Build vertexes of full page
871 | *
889 | */
890 | private void buildVertexesOfFullPage() {
891 | int i = 0;
892 | int j = 0;
893 |
894 | mApexes[i++] = right;
895 | mApexes[i++] = bottom;
896 | mApexes[i++] = 0;
897 | mApexTexCoords[j++] = textureX(right);
898 | mApexTexCoords[j++] = textureY(bottom);
899 |
900 | mApexes[i++] = right;
901 | mApexes[i++] = top;
902 | mApexes[i++] = 0;
903 | mApexTexCoords[j++] = textureX(right);
904 | mApexTexCoords[j++] = textureY(top);
905 |
906 | mApexes[i++] = left;
907 | mApexes[i++] = top;
908 | mApexes[i++] = 0;
909 | mApexTexCoords[j++] = textureX(left);
910 | mApexTexCoords[j++] = textureY(top);
911 |
912 | mApexes[i++] = left;
913 | mApexes[i++] = bottom;
914 | mApexes[i] = 0;
915 | mApexTexCoords[j++] = textureX(left);
916 | mApexTexCoords[j] = textureY(bottom);
917 |
918 | mFullPageVexBuf.put(mApexes, 0, 12).position(0);
919 | mFullPageTexCoordsBuf.put(mApexTexCoords, 0, 8).position(0);
920 | }
921 | }
922 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/PageFlipException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | /**
19 | * PageFlip exception class
20 | *
21 | * @author eschao
22 | */
23 | public class PageFlipException extends Exception {
24 |
25 | public PageFlipException() {
26 | super();
27 | }
28 |
29 | public PageFlipException(String message) {
30 | super(message);
31 | }
32 |
33 | public PageFlipException(String message, Throwable cause) {
34 | super(message, cause);
35 | }
36 |
37 | public PageFlipException(Throwable cause) {
38 | super(cause);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/PageFlipState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | /**
19 | * Animation state of page flip
20 | *
21 | * @author eschao
22 | */
23 | public enum PageFlipState {
24 | BEGIN_FLIP,
25 | FORWARD_FLIP,
26 | BACKWARD_FLIP,
27 | RESTORE_FLIP,
28 | END_FLIP,
29 | END_WITH_FORWARD,
30 | END_WITH_BACKWARD,
31 | END_WITH_RESTORE,
32 | }
33 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/PageFlipUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.graphics.Bitmap;
19 | import android.graphics.Canvas;
20 | import android.graphics.Color;
21 | import android.graphics.LinearGradient;
22 | import android.graphics.Paint;
23 | import android.graphics.Shader;
24 |
25 | /**
26 | * Utilities of page flip
27 | *
28 | * @author eschao
29 | */
30 | public class PageFlipUtils {
31 |
32 | /**
33 | * Compute average color for given bitmap
34 | *
35 | * @param bitmap bitmap object
36 | * @param pixels how many sample pixels are used to compute
37 | * @return Average color
38 | */
39 | public static int computeAverageColor(Bitmap bitmap, int pixels) {
40 | int red = 0;
41 | int green = 0;
42 | int blue = 0;
43 | int alpha = 0;
44 | int width = bitmap.getWidth();
45 | int height = bitmap.getHeight();
46 | int maxWPixels = width / 3;
47 | int maxHPixels = height / 3;
48 |
49 | if (pixels > maxWPixels) {
50 | pixels = maxWPixels;
51 | }
52 |
53 | if (pixels > maxHPixels) {
54 | pixels = maxHPixels;
55 | }
56 |
57 | int right = width - pixels;
58 | int bottom = height - pixels;
59 | int centerLeft = right / 2;
60 | int centerTop = bottom / 2;
61 |
62 | for (int i = 0; i < pixels; ++i) {
63 | // left-top
64 | int color = bitmap.getPixel(i, i);
65 | red += Color.red(color);
66 | blue += Color.blue(color);
67 | green += Color.green(color);
68 | alpha += Color.alpha(color);
69 |
70 | // center
71 | color = bitmap.getPixel(centerLeft + i, centerTop + i);
72 | red += Color.red(color);
73 | blue += Color.blue(color);
74 | green += Color.green(color);
75 | alpha += Color.alpha(color);
76 |
77 | // right-top
78 | color = bitmap.getPixel(right + i, i);
79 | red += Color.red(color);
80 | blue += Color.blue(color);
81 | green += Color.green(color);
82 | alpha += Color.alpha(color);
83 |
84 | // left-bottom
85 | color = bitmap.getPixel(i, bottom + i);
86 | red += Color.red(color);
87 | blue += Color.blue(color);
88 | green += Color.green(color);
89 | alpha += Color.alpha(color);
90 |
91 | // right-bottom
92 | color = bitmap.getPixel(right + i, bottom + i);
93 | red += Color.red(color);
94 | blue += Color.blue(color);
95 | green += Color.green(color);
96 | alpha += Color.alpha(color);
97 | }
98 |
99 | int count = pixels * 5;
100 | red /= count;
101 | blue /= count;
102 | green /= count;
103 | alpha /= count;
104 | return Color.argb(alpha, red, green, blue);
105 | }
106 |
107 | /**
108 | * Create gradient bitmap for drawing lighting effect on back of fold page
109 | *
110 | * @return gradient bitmap object
111 | */
112 | public static Bitmap createGradientBitmap() {
113 | Canvas c = new Canvas();
114 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
115 | Bitmap bitmap = Bitmap.createBitmap(256, 1, Bitmap.Config.ARGB_8888);
116 |
117 | c.setBitmap(bitmap);
118 | int[] colors = new int[]{0x00FFFFFF,
119 | 0x24000000,
120 | 0x24101010,
121 | 0x48000000};
122 | float[] positions = new float[]{0.5f, 0.9f, 0.94f, 1.0f};
123 | LinearGradient shader = new LinearGradient(0, 0, 256, 0, colors,
124 | positions,
125 | Shader.TileMode.CLAMP);
126 | paint.setShader(shader);
127 | c.drawRect(0, 0, 256, 1, paint);
128 | return bitmap;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/ShadowColor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | /**
19 | * Shadow color
20 | *
21 | * @author eschao
22 | */
23 |
24 | public final class ShadowColor {
25 |
26 | float startColor;
27 | float startAlpha;
28 | float endColor;
29 | float endAlpha;
30 |
31 | /**
32 | * Default constructor
33 | */
34 | public ShadowColor() {
35 | startColor = 0;
36 | startAlpha = 0;
37 | endColor = 0;
38 | endAlpha = 0;
39 | }
40 |
41 | /**
42 | * Constructor
43 | *
44 | * @param startColor start color, range is [0 .. 1]
45 | * @param startAlpha start alpha, range is [0 .. 1]
46 | * @param endColor end color, range is [0 .. 1]
47 | * @param endAlpha end alpha, range is [0 .. 1]
48 | */
49 | public ShadowColor(float startColor, float startAlpha,
50 | float endColor, float endAlpha) {
51 | set(startColor, startAlpha, endColor, endAlpha);
52 | }
53 |
54 | /**
55 | * Set color and alpha
56 | *
57 | * @param startColor start color, range is [0 .. 1]
58 | * @param startAlpha start alpha, range is [0 .. 1]
59 | * @param endColor end color, range is [0 .. 1]
60 | * @param endAlpha end alpha, range is [0 .. 1]
61 | */
62 | public void set(float startColor, float startAlpha,
63 | float endColor, float endAlpha) {
64 | if (startColor < 0 || startColor > 1 ||
65 | startAlpha < 0 || startAlpha > 1 ||
66 | endColor < 0 || endColor > 1 ||
67 | endAlpha < 0 || endAlpha > 1) {
68 | throw new IllegalArgumentException("Illegal color or alpha value!");
69 | }
70 |
71 | this.startColor = startColor;
72 | this.startAlpha = startAlpha;
73 | this.endColor = endColor;
74 | this.endAlpha = endAlpha;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/ShadowVertexProgram.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.content.Context;
19 |
20 | import static android.opengl.GLES20.glGetAttribLocation;
21 | import static android.opengl.GLES20.glGetUniformLocation;
22 |
23 | /**
24 | * Shadow vertex shader program which is used to load:
25 | *
26 | *
shadow_vertex_shader.glsl
27 | *
shadow_fragment_shader.glsl
28 | *
29 | *
30 | * @author eschao
31 | */
32 | public class ShadowVertexProgram extends GLProgram {
33 |
34 | // variable names defined in shader scripts
35 | final static String VAR_MVP_MATRIX = "u_MVPMatrix";
36 | final static String VAR_VERTEX_Z = "u_vexZ";
37 | final static String VAR_VERTEX_POS = "a_vexPosition";
38 |
39 | int mMVPMatrixLoc;
40 | int mVertexZLoc;
41 | int mVertexPosLoc;
42 |
43 | /**
44 | * Constructor
45 | */
46 | public ShadowVertexProgram() {
47 | super();
48 |
49 | mMVPMatrixLoc = INVALID_GL_HANDLE;
50 | mVertexZLoc = INVALID_GL_HANDLE;
51 | mVertexPosLoc = INVALID_GL_HANDLE;
52 | }
53 |
54 | /**
55 | * Initiate shader program
56 | *
57 | * @param context android context
58 | * @return self
59 | * @throws PageFlipException raise exception if fail to compile & link
60 | * program
61 | */
62 | public ShadowVertexProgram init(Context context) throws
63 | PageFlipException {
64 | super.init(context,
65 | R.raw.shadow_vertex_shader,
66 | R.raw.shadow_fragment_shader);
67 | return this;
68 | }
69 |
70 | /**
71 | * Get variable handles from linked shader program
72 | */
73 | protected void getVarsLocation() {
74 | if (mProgramRef != 0) {
75 | mVertexZLoc = glGetUniformLocation(mProgramRef, VAR_VERTEX_Z);
76 | mVertexPosLoc = glGetAttribLocation(mProgramRef, VAR_VERTEX_POS);
77 | mMVPMatrixLoc = glGetUniformLocation(mProgramRef, VAR_MVP_MATRIX);
78 | }
79 | }
80 |
81 | /**
82 | * Delete shader resources
83 | */
84 | public void delete() {
85 | super.delete();
86 |
87 | mMVPMatrixLoc = INVALID_GL_HANDLE;
88 | mVertexZLoc = INVALID_GL_HANDLE;
89 | mVertexPosLoc = INVALID_GL_HANDLE;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/ShadowVertexes.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.nio.ByteOrder;
20 | import java.nio.FloatBuffer;
21 |
22 | import static android.opengl.GLES10.GL_SRC_ALPHA;
23 | import static android.opengl.GLES20.GL_BLEND;
24 | import static android.opengl.GLES20.GL_FLOAT;
25 | import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA;
26 | import static android.opengl.GLES20.GL_TEXTURE_2D;
27 | import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
28 | import static android.opengl.GLES20.glBlendFunc;
29 | import static android.opengl.GLES20.glDisable;
30 | import static android.opengl.GLES20.glDrawArrays;
31 | import static android.opengl.GLES20.glEnable;
32 | import static android.opengl.GLES20.glEnableVertexAttribArray;
33 | import static android.opengl.GLES20.glUniform1f;
34 | import static android.opengl.GLES20.glUniformMatrix4fv;
35 | import static android.opengl.GLES20.glVertexAttribPointer;
36 |
37 | /**
38 | * Shadow vertex which is used to store vertex data of fold shadow and draw
39 | * shadow with openGL
40 | *
Every vertex has 4 float data which are:
41 | *
42 | *
x coordinate
43 | *
y coordinate
44 | *
color (start color or end color)
45 | *
alpha (start alpha or end alpha)
46 | *
47 | *
48 | * @author eschao
49 | */
50 | class ShadowVertexes {
51 |
52 | // how many vertexes in vertex float buffer will be drawn on screen
53 | int mVertexesSize;
54 |
55 | // universal Z coordinate for all shadow vertex
56 | // we will enable DEPTH_TEST while drawing fold shadow to avoid some drawing
57 | // issue
58 | float vertexZ;
59 |
60 | // float array and float buffer for storing vertexes
61 | float[] mVertexes;
62 | FloatBuffer mVertexesBuffer;
63 |
64 | // shadow color
65 | ShadowColor mColor;
66 |
67 | // the start position of backward vertexes
68 | int mMaxBackward;
69 |
70 | // reserve space between backward and forward index
71 | // need to preserver space for fold top edge shadow when compute fold edge
72 | // shadow since the top edge shadow will be computed at last
73 | //
74 | // +--------------------+------------+--------------------+
75 | // | <-- mBackward | reserved | mForward --> |
76 | // +--------------------+------------+--------------------+
77 | private int mSpaceOfFrontRear;
78 |
79 | // forward and backward index for adding vertex
80 | private int mBackward;
81 | private int mForward;
82 |
83 | /**
84 | * Default constructor
85 | */
86 | public ShadowVertexes() {
87 | release();
88 | mColor = new ShadowColor();
89 | }
90 |
91 | /**
92 | * Constructor
93 | *
94 | * @param spaceOfFrontRear reserve space for special usage
95 | * @param startColor shadow start color, range is [0 .. 1]
96 | * @param startAlpha shadow alpha, range is [0 .. 1]
97 | * @param endColor shadow end color, range is [0 .. 1]
98 | * @param endAlpha shadow end alpah, range is [0 .. 1]
99 | */
100 | public ShadowVertexes(int spaceOfFrontRear,
101 | float startColor, float startAlpha,
102 | float endColor, float endAlpha) {
103 | release();
104 | mSpaceOfFrontRear = spaceOfFrontRear;
105 | mColor = new ShadowColor(startColor, startAlpha, endColor, endAlpha);
106 | }
107 |
108 | /**
109 | * Set with vertex count
110 | *
111 | * @param meshCount mesh count
112 | * @return self
113 | */
114 | public ShadowVertexes set(int meshCount) {
115 | // every mesh need two vertexes:
116 | // (startX, startY , startColor, startAlpha) and
117 | // (endX, endY, endColor, endAlpha), that is why it is meshCount * 8
118 | mMaxBackward = meshCount << 3;
119 |
120 | // double meshCount since fold shadow has two sides, for example:
121 | // fold edge shadow has left and right edge along the fold triangle
122 | int size = (meshCount << 4) + (mSpaceOfFrontRear << 2);
123 | mVertexes = new float[size];
124 | mVertexesBuffer = ByteBuffer.allocateDirect(size << 2)
125 | .order(ByteOrder.nativeOrder())
126 | .asFloatBuffer();
127 | reset();
128 | return this;
129 | }
130 |
131 | /**
132 | * Release all resources
133 | */
134 | public void release() {
135 | mBackward = 0;
136 | mForward = 0;
137 | mMaxBackward = 0;
138 | mSpaceOfFrontRear = 0;
139 | mVertexes = null;
140 | mVertexesBuffer = null;
141 | }
142 |
143 | /**
144 | * Reset index of float array before adding vertex to buffer
145 | *
There are two index: forward and backward, all of them have to be
146 | * reset to middle position(exclude reserved space) before adding vertexes
147 | *
205 | *
206 | * @param startX start x coordinate
207 | * @param startY start y coordinate
208 | * @param endX end x coordinate
209 | * @param endY end y coordinate
210 | * @return self
211 | */
212 | public ShadowVertexes addVertexesForward(float startX, float startY,
213 | float endX, float endY) {
214 | mVertexes[mForward++] = startX;
215 | mVertexes[mForward++] = startY;
216 | mVertexes[mForward++] = mColor.startColor;
217 | mVertexes[mForward++] = mColor.startAlpha;
218 | mVertexes[mForward++] = endX;
219 | mVertexes[mForward++] = endY;
220 | mVertexes[mForward++] = mColor.endColor;
221 | mVertexes[mForward++] = mColor.endAlpha;
222 | return this;
223 | }
224 |
225 | /**
226 | * Add vertex to float buffer
227 | * Call {@link #reset()} before calling any add operations
228 | *
229 | * @param isForward is backward or forward adding
230 | * @param startX start x coordinate
231 | * @param startY start y coordinate
232 | * @param endX end x coordinate
233 | * @param endY end y coordinate
234 | * @return self
235 | */
236 | public ShadowVertexes addVertexes(boolean isForward,
237 | float startX, float startY,
238 | float endX, float endY) {
239 | return isForward ?
240 | addVertexesForward(startX, startY, endX, endY) :
241 | addVertexesBackward(startX, startY, endX, endY);
242 | }
243 |
244 | /**
245 | * Put data from float array to float buffer
246 | */
247 | public void toFloatBuffer() {
248 | mVertexesSize = (mForward - mBackward) / 4;
249 | mVertexesBuffer.put(mVertexes, mBackward, mForward - mBackward)
250 | .position(0);
251 | }
252 |
253 | /**
254 | * put given length data from float array to float buffer
255 | *
256 | * @param length data length
257 | */
258 | public void toFloatBuffer(int length) {
259 | mVertexesBuffer.put(mVertexes, 0, length).position(0);
260 | mVertexesSize = length / 4;
261 | }
262 |
263 | /**
264 | * Draw shadow
265 | *
266 | * @param program shadow vertex shader program
267 | */
268 | public void draw(ShadowVertexProgram program) {
269 | if (mVertexesSize > 0) {
270 | glUniformMatrix4fv(program.mMVPMatrixLoc, 1, false,
271 | VertexProgram.MVPMatrix, 0);
272 |
273 | glUniform1f(program.mVertexZLoc, vertexZ);
274 |
275 | // disable texture, and enable blend
276 | glDisable(GL_TEXTURE_2D);
277 | glEnable(GL_BLEND);
278 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
279 |
280 | // draw shadow
281 | glVertexAttribPointer(program.mVertexPosLoc, 4, GL_FLOAT, false, 0,
282 | mVertexesBuffer);
283 | glEnableVertexAttribArray(program.mVertexPosLoc);
284 | glDrawArrays(GL_TRIANGLE_STRIP, 0, mVertexesSize);
285 |
286 | glDisable(GL_BLEND);
287 | }
288 | }
289 | }
290 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/ShadowWidth.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | /**
19 | * Shadow width
20 | *
21 | * @author eschao
22 | */
23 |
24 | final class ShadowWidth {
25 |
26 | // minimal shadow width
27 | float mMin;
28 |
29 | // maximal shadow width
30 | float mMax;
31 |
32 | // the shadow width ratio based on fold cylinder radius
33 | // shadow width will be dynamically computed upon fold cylinder radius
34 | float mRatio;
35 |
36 | public ShadowWidth(float min, float max, float ratio) {
37 | set(min, max, ratio);
38 | }
39 |
40 | /**
41 | * Set minimal, maximal and ratio value of shadow width
42 | *
43 | * @param min minimal value
44 | * @param max maximal value
45 | * @param ratio width ratio based on fold cylinder radius
46 | */
47 | public void set(float min, float max, float ratio) {
48 | if (min < 0 || max < 0 || min > max ||
49 | ratio <= 0 || ratio > 1) {
50 | throw new IllegalArgumentException("One of Min(" + min + ") Max(" +
51 | max + ") Ration(" + ratio + ")" +
52 | "is invalid!");
53 | }
54 |
55 | mMin = min;
56 | mMax = max;
57 | mRatio = ratio;
58 | }
59 |
60 | /**
61 | * Compute shadow width upon fold cylinder radius
62 | *
if width is out of (min, max), one of them will be returned
63 | *
64 | * @param r fold cylinder radius
65 | * @return shadow width
66 | */
67 | public float width(float r) {
68 | float w = r * mRatio;
69 | if (w < mMin) {
70 | return mMin;
71 | }
72 | else if (w > mMax) {
73 | return mMax;
74 | }
75 | else {
76 | return w;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/VertexProgram.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.content.Context;
19 | import android.opengl.Matrix;
20 |
21 | import static android.opengl.GLES20.glGetAttribLocation;
22 | import static android.opengl.GLES20.glGetUniformLocation;
23 |
24 | /**
25 | * Vertex shader program which is used to load:
26 | *
27 | *
vertex_shader.glsl
28 | *
fragment_shader.glsl
29 | *
30 | *
31 | * @author eschao
32 | */
33 | class VertexProgram extends GLProgram {
34 |
35 | // variable names defined in GLSL scripts
36 | final static String VAR_MVP_MATRIX = "u_MVPMatrix";
37 | final static String VAR_VERTEX_POS = "a_vexPosition";
38 | final static String VAR_TEXTURE_COORD = "a_texCoord";
39 | final static String VAR_TEXTURE = "u_texture";
40 |
41 | // universal model-view matrix
42 | final static float[] MVMatrix = new float[16];
43 | // universal model-view-project matrix
44 | final static float[] MVPMatrix = new float[16];
45 |
46 | // variable handles after compiled & linked shader scripts
47 | int mMVPMatrixLoc;
48 | int mVertexPosLoc;
49 | int mTexCoordLoc;
50 | int mTextureLoc;
51 |
52 | public VertexProgram() {
53 | super();
54 |
55 | // init with invalid value
56 | mTextureLoc = INVALID_GL_HANDLE;
57 | mMVPMatrixLoc = INVALID_GL_HANDLE;
58 | mTexCoordLoc = INVALID_GL_HANDLE;
59 | mVertexPosLoc = INVALID_GL_HANDLE;
60 | }
61 |
62 | /**
63 | * Initiate vertex shader program
64 | *
65 | * @param context Android app context
66 | * @return self object
67 | * @throws PageFlipException raise exception if fail to initiate program
68 | */
69 | public VertexProgram init(Context context) throws PageFlipException {
70 | super.init(context, R.raw.vertex_shader, R.raw.fragment_shader);
71 | return this;
72 | }
73 |
74 | /**
75 | * Get variable handles after linked shader program
76 | */
77 | protected void getVarsLocation() {
78 | if (mProgramRef != 0) {
79 | mVertexPosLoc = glGetAttribLocation(mProgramRef, VAR_VERTEX_POS);
80 | mTexCoordLoc = glGetAttribLocation(mProgramRef, VAR_TEXTURE_COORD);
81 | mMVPMatrixLoc = glGetUniformLocation(mProgramRef, VAR_MVP_MATRIX);
82 | mTextureLoc = glGetUniformLocation(mProgramRef, VAR_TEXTURE);
83 | }
84 | }
85 |
86 | /**
87 | * Delete shader and program handlers
88 | */
89 | public void delete() {
90 | super.delete();
91 |
92 | mTextureLoc = INVALID_GL_HANDLE;
93 | mMVPMatrixLoc = INVALID_GL_HANDLE;
94 | mTexCoordLoc = INVALID_GL_HANDLE;
95 | mVertexPosLoc = INVALID_GL_HANDLE;
96 | }
97 |
98 | /**
99 | * Initiate matrix with view size
100 | *
101 | * @param left view left
102 | * @param right view right
103 | * @param bottom view bottom
104 | * @param top view top
105 | */
106 | public void initMatrix(float left, float right, float bottom, float top) {
107 | float[] projectMatrix = new float[16];
108 | Matrix.orthoM(projectMatrix, 0, left, right, bottom, top, 0, 6000);
109 | Matrix.setIdentityM(MVMatrix, 0);
110 | Matrix.setLookAtM(MVMatrix, 0, 0, 0, 3000, 0, 0, 0, 0, 1, 0);
111 | Matrix.setIdentityM(MVPMatrix, 0);
112 | Matrix.multiplyMM(MVPMatrix, 0, projectMatrix, 0, MVMatrix, 0);
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/PageFlip/src/main/java/com/eschao/android/widget/pageflip/Vertexes.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.pageflip;
17 |
18 | import android.util.Log;
19 |
20 | import java.nio.ByteBuffer;
21 | import java.nio.ByteOrder;
22 | import java.nio.FloatBuffer;
23 |
24 | import static android.opengl.GLES20.GL_FLOAT;
25 | import static android.opengl.GLES20.glDrawArrays;
26 | import static android.opengl.GLES20.glEnableVertexAttribArray;
27 | import static android.opengl.GLES20.glVertexAttribPointer;
28 |
29 | /**
30 | * Vertexes is used to manage vertex and texture data for openGL drawing
31 | *
32 | * @author eschao
33 | */
34 |
35 | class Vertexes {
36 |
37 | private static final String TAG = "Vertexes";
38 |
39 | // how many vertexes in vertex float buffer will be drawn on screen
40 | int mVertexesSize;
41 |
42 | // how many float data is used for every vertex
43 | int mSizeOfPerVex;
44 |
45 | // vertex data array
46 | float[] mVertexes;
47 |
48 | // texture coordinates array
49 | float[] mTextureCoords;
50 |
51 | // float buffer for vertexes data and texture coordinates data
52 | FloatBuffer mVertexesBuf;
53 | FloatBuffer mTextureCoordsBuf;
54 |
55 | // next index when add vertex to float array
56 | int mNext;
57 |
58 |
59 | /**
60 | * Default constructor
61 | */
62 | public Vertexes() {
63 | mNext = 0;
64 | mVertexesSize = 0;
65 | mSizeOfPerVex = 0;
66 | mVertexes = null;
67 | mVertexesBuf = null;
68 | mTextureCoords = null;
69 | mTextureCoordsBuf = null;
70 | }
71 |
72 | /**
73 | * Constructor with given vertex amount
74 | *
75 | * @param capacity vertex max amount
76 | * @param sizeOfPerVex how many float data is used for a vertex
77 | */
78 | public Vertexes(int capacity, int sizeOfPerVex) {
79 | set(capacity, sizeOfPerVex, true);
80 | }
81 |
82 | /**
83 | * Constructor with given vertex max amount and texture
84 | *
85 | * @param capacity vertex amount
86 | * @param sizeOfPerVex how many float data is used for a vertex
87 | * @param hasTexture if need texture buffer for texture coordinates
88 | */
89 | public Vertexes(int capacity, int sizeOfPerVex, boolean hasTexture) {
90 | set(capacity, sizeOfPerVex, hasTexture);
91 | }
92 |
93 | /**
94 | * Set max vertex amount and create buffer for vertex and texture
95 | *
96 | * @param capacity vertex amount
97 | * @param sizeOfPerVex how many float data is used for a vertex
98 | * @param hasTexture True if need texture buffer for texture coordinates
99 | * @return self
100 | */
101 | public Vertexes set(int capacity, int sizeOfPerVex, boolean hasTexture) {
102 | if (sizeOfPerVex < 2) {
103 | Log.w(TAG, "sizeOfPerVex is invalid: " + sizeOfPerVex);
104 | throw new IllegalArgumentException("sizeOfPerVex:" + sizeOfPerVex +
105 | "is less than 2!");
106 | }
107 |
108 | // reset all
109 | mNext = 0;
110 | mVertexes = null;
111 | mVertexesBuf = null;
112 | mTextureCoords = null;
113 | mTextureCoordsBuf = null;
114 |
115 | // create vertexes buffer
116 | mSizeOfPerVex = sizeOfPerVex;
117 | mVertexes = new float[capacity * sizeOfPerVex];
118 | mVertexesBuf = ByteBuffer.allocateDirect(capacity * sizeOfPerVex * 4)
119 | .order(ByteOrder.nativeOrder())
120 | .asFloatBuffer();
121 |
122 | // if need, create texture buffer
123 | if (hasTexture) {
124 | mTextureCoords = new float[capacity << 1];
125 | mTextureCoordsBuf = ByteBuffer.allocateDirect(capacity << 3)
126 | .order(ByteOrder.nativeOrder())
127 | .asFloatBuffer();
128 | }
129 |
130 | return this;
131 | }
132 |
133 | /**
134 | * Release all resources
135 | *
136 | * @return self
137 | */
138 | public Vertexes release() {
139 | mNext = 0;
140 | mVertexesSize = 0;
141 | mSizeOfPerVex = 0;
142 | mVertexes = null;
143 | mVertexesBuf = null;
144 | mTextureCoords = null;
145 | mTextureCoordsBuf = null;
146 | return this;
147 | }
148 |
149 | /**
150 | * Get max vertex amount
151 | *
152 | * @return max vertex amount
153 | */
154 | public int capacity() {
155 | return mVertexes == null ? 0 : mVertexes.length / mSizeOfPerVex;
156 | }
157 |
158 | /**
159 | * Reset index of float array before adding vertex to buffer
160 | */
161 | public void reset() {
162 | mNext = 0;
163 | }
164 |
165 |
166 | /**
167 | * Get float data with given index
168 | *
169 | * @param index float data position index
170 | * @return float data
171 | */
172 | public float getFloatAt(int index) {
173 | if (index >= 0 && index < mNext) {
174 | return mVertexes[index];
175 | }
176 |
177 | return 0;
178 | }
179 |
180 | /**
181 | * Set vertex coordinate(x, y, z) in given buffer position
182 | *
183 | * @param i where to start saving vertex data
184 | * @param x x value of vertex coordinate
185 | * @param y y value of vertex coordinate
186 | * @param z z value of vertex coordinate
187 | * @return self
188 | */
189 | public Vertexes setVertex(int i, float x, float y, float z) {
190 | assert(i+2 < mVertexes.length);
191 |
192 | mVertexes[i] = x;
193 | mVertexes[i + 1] = y;
194 | mVertexes[i + 2] = z;
195 | return this;
196 | }
197 |
198 | /**
199 | * Set vertex coordinate(x, y, z, width) in given buffer position
200 | *
201 | * @param i where to start saving vertex data
202 | * @param x x value of vertex coordinate
203 | * @param y y value of vertex coordinate
204 | * @param z z value of vertex coordinate
205 | * @param w width value which is normally used to pass other value to shader
206 | * @return self
207 | */
208 | public Vertexes setVertex(int i, float x, float y, float z, float w) {
209 | assert(i+3 < mVertexes.length);
210 |
211 | mVertexes[i] = x;
212 | mVertexes[i + 1] = y;
213 | mVertexes[i + 2] = z;
214 | mVertexes[i + 3] = w;
215 | return this;
216 | }
217 |
218 | /**
219 | * Set texture coordinate(x, y) in given buffer position
220 | *
221 | * @param i where to start saving texture coordinate
222 | * @param x x value of texture coordinate
223 | * @param y y value of texture coordinate
224 | * @return self
225 | */
226 | public Vertexes setTextureCoord(int i, float x, float y) {
227 | assert(i+1 < mTextureCoords.length);
228 |
229 | mTextureCoords[i] = x;
230 | mTextureCoords[i + 1] = y;
231 | return this;
232 | }
233 |
234 | /**
235 | * Add vertex coordinate to buffer
236 | *
237 | * @param x x value of vertex coordinate
238 | * @param y y value of vertex coordinate
239 | * @param z z value of vertex coordinate
240 | * @return self
241 | */
242 | public Vertexes addVertex(float x, float y, float z) {
243 | mVertexes[mNext++] = x;
244 | mVertexes[mNext++] = y;
245 | mVertexes[mNext++] = z;
246 | return this;
247 | }
248 |
249 | /**
250 | * Add vertex and texture coordinates
251 | *
252 | * @param x x value of vertex coordinate
253 | * @param y y value of vertex coordinate
254 | * @param z z value of vertex coordinate
255 | * @param coordX x value of texture coordinate
256 | * @param coordY y value of texture coordinate
257 | * @return self
258 | */
259 | public Vertexes addVertex(float x, float y, float z,
260 | float coordX, float coordY) {
261 | int j = mNext / mSizeOfPerVex * 2;
262 | mVertexes[mNext++] = x;
263 | mVertexes[mNext++] = y;
264 | mVertexes[mNext++] = z;
265 |
266 | mTextureCoords[j++] = coordX;
267 | mTextureCoords[j] = coordY;
268 | return this;
269 | }
270 |
271 | /**
272 | * Add vertex coordinate to buffer
273 | *
274 | * @param x x value of vertex coordinate
275 | * @param y y value of vertex coordinate
276 | * @param z z value of vertex coordinate
277 | * @param w width value which is normally used to pass other value to shader
278 | * @return self
279 | */
280 | public Vertexes addVertex(float x, float y, float z, float w) {
281 | mVertexes[mNext++] = x;
282 | mVertexes[mNext++] = y;
283 | mVertexes[mNext++] = z;
284 | mVertexes[mNext++] = w;
285 | return this;
286 | }
287 |
288 | /**
289 | * Add vertex and texture coordinates
290 | *
291 | * @param x x value of vertex coordinate
292 | * @param y y value of vertex coordinate
293 | * @param z z value of vertex coordinate
294 | * @param w width value which is normally used to pass other value to shader
295 | * @param coordX x value of texture coordinate
296 | * @param coordY y value of texture coordinate
297 | * @return self
298 | */
299 | public Vertexes addVertex(float x, float y, float z, float w,
300 | float coordX, float coordY) {
301 | int j = mNext / mSizeOfPerVex * 2;
302 | mVertexes[mNext++] = x;
303 | mVertexes[mNext++] = y;
304 | mVertexes[mNext++] = z;
305 | mVertexes[mNext++] = w;
306 |
307 | mTextureCoords[j++] = coordX;
308 | mTextureCoords[j] = coordY;
309 | return this;
310 | }
311 |
312 | /**
313 | * Add GLPoint to float buffer
314 | *
315 | * @param point GLPoint object
316 | * @return self
317 | */
318 | public Vertexes addVertex(GLPoint point) {
319 | int j = mNext / mSizeOfPerVex * 2;
320 | mVertexes[mNext++] = point.x;
321 | mVertexes[mNext++] = point.y;
322 | mVertexes[mNext++] = point.z;
323 |
324 | mTextureCoords[j++] = point.texX;
325 | mTextureCoords[j] = point.texY;
326 | return this;
327 | }
328 |
329 | /**
330 | * Put data from float array to float buffer
331 | *
332 | * @param offset data start offset in float array
333 | * @param length data length to be put
334 | */
335 | public void toFloatBuffer(int offset, int length) {
336 | mVertexesBuf.put(mVertexes, offset, length).position(0);
337 | mVertexesSize = length / mSizeOfPerVex;
338 |
339 | // has texture? put again
340 | if (mTextureCoords != null) {
341 | final int o = offset / mSizeOfPerVex * 2;
342 | final int l = mVertexesSize * 2;
343 | mTextureCoordsBuf.put(mTextureCoords, o, l).position(0);
344 | }
345 | }
346 |
347 | /**
348 | * Put all data from float array to float buffer
349 | *
350 | * The offset is 0 and the length is determined by mNext which is increased
351 | * after calling {@link #addVertex}
352 | *
353 | */
354 | public void toFloatBuffer() {
355 | mVertexesBuf.put(mVertexes, 0, mNext).position(0);
356 | mVertexesSize = mNext / mSizeOfPerVex;
357 |
358 | if (mTextureCoords != null) {
359 | mTextureCoordsBuf.put(mTextureCoords, 0, mVertexesSize << 1)
360 | .position(0);
361 | }
362 | }
363 |
364 | /**
365 | * Draw vertexes
366 | *
367 | * @param type openGL drawing type: TRIANGLE, STRIP, FAN
368 | * @param hVertexPos vertex position var in shader program
369 | * @param hTextureCoord texture var in shader program
370 | */
371 | public void drawWith(int type, int hVertexPos, int hTextureCoord) {
372 | // pass vertex data
373 | glVertexAttribPointer(hVertexPos, mSizeOfPerVex, GL_FLOAT, false, 0,
374 | mVertexesBuf);
375 | glEnableVertexAttribArray(hVertexPos);
376 |
377 | // pass texture data
378 | glVertexAttribPointer(hTextureCoord, 2, GL_FLOAT, false, 0,
379 | mTextureCoordsBuf);
380 | glEnableVertexAttribArray(hTextureCoord);
381 |
382 | // draw triangles
383 | glDrawArrays(type, 0, mVertexesSize);
384 | }
385 |
386 | /**
387 | * Draw vertexes with given offset and length
388 | *
389 | * @param type openGL drawing type: TRIANGLE, STRIP, FAN
390 | * @param hVertexPos vertex var in shader program
391 | * @param hTextureCoord texture var in shader program
392 | * @param offset vertex start offset in buffer
393 | * @param length vertex length to be drawn
394 | */
395 | public void drawWith(int type, int hVertexPos, int hTextureCoord,
396 | int offset, int length) {
397 | glVertexAttribPointer(hVertexPos, mSizeOfPerVex, GL_FLOAT, false, 0,
398 | mVertexesBuf);
399 | glEnableVertexAttribArray(hVertexPos);
400 |
401 | glVertexAttribPointer(hTextureCoord, 2, GL_FLOAT, false, 0,
402 | mTextureCoordsBuf);
403 | glEnableVertexAttribArray(hTextureCoord);
404 |
405 | glDrawArrays(type, offset, length);
406 | }
407 | }
408 |
--------------------------------------------------------------------------------
/PageFlip/src/main/res/raw/fold_back_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform sampler2D u_texture;
3 | uniform sampler2D u_shadow;
4 | uniform vec4 u_maskColor;
5 | varying vec2 v_texCoord;
6 | varying float v_shadowX;
7 |
8 | void main() {
9 | vec4 texture = texture2D(u_texture, v_texCoord);
10 | vec2 shadowCoord = vec2(v_shadowX, 0);
11 | vec4 shadow = texture2D(u_shadow, shadowCoord);
12 | vec4 maskedTexture = vec4(mix(texture.rgb, u_maskColor.rgb, u_maskColor.a), 1.0);
13 | gl_FragColor = vec4(maskedTexture.rgb * (1.0 - shadow.a) + shadow.rgb, maskedTexture.a);
14 | }
15 |
--------------------------------------------------------------------------------
/PageFlip/src/main/res/raw/fold_back_vertex_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform mat4 u_MVPMatrix;
3 | uniform float u_texXOffset;
4 | attribute vec4 a_vexPosition;
5 | attribute vec2 a_texCoord;
6 | varying vec2 v_texCoord;
7 | varying float v_shadowX;
8 |
9 | void main() {
10 | v_texCoord = vec2(abs(a_texCoord.x - u_texXOffset), a_texCoord.y);
11 | v_shadowX = clamp(abs(a_vexPosition.w), 0.01, 1.0);
12 | vec4 vertex = vec4(a_vexPosition.xyz, 1.0);
13 | gl_Position = u_MVPMatrix * vertex;
14 | }
--------------------------------------------------------------------------------
/PageFlip/src/main/res/raw/fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform sampler2D u_texture;
3 | varying vec2 v_texCoord;
4 |
5 | void main() {
6 | gl_FragColor = texture2D(u_texture, v_texCoord);
7 | }
8 |
--------------------------------------------------------------------------------
/PageFlip/src/main/res/raw/shadow_fragment_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | varying vec4 v_texColor;
3 |
4 | void main()
5 | {
6 | gl_FragColor = v_texColor;
7 | }
--------------------------------------------------------------------------------
/PageFlip/src/main/res/raw/shadow_vertex_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform mat4 u_MVPMatrix;
3 | uniform float u_vexZ;
4 | attribute vec4 a_vexPosition;
5 | varying vec4 v_texColor;
6 |
7 | void main() {
8 | vec4 vexPos = vec4(a_vexPosition.xy, u_vexZ, 1.0);
9 | v_texColor = vec4(a_vexPosition.z, a_vexPosition.z, a_vexPosition.z, a_vexPosition.w);
10 | gl_Position = u_MVPMatrix * vexPos;
11 | }
--------------------------------------------------------------------------------
/PageFlip/src/main/res/raw/vertex_shader.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform mat4 u_MVPMatrix;
3 | attribute vec4 a_vexPosition;
4 | attribute vec2 a_texCoord;
5 | varying vec2 v_texCoord;
6 |
7 | void main() {
8 | gl_Position = u_MVPMatrix * a_vexPosition;
9 | v_texCoord = a_texCoord;
10 | }
--------------------------------------------------------------------------------
/PageFlip/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PageFlip
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | []()
2 |
3 | # PageFlip
4 | This project is aimed to implement 3D style page flip on Android system based on OpenGL 2.0.
5 |
6 | For **JNI** version, please visit: [**android-PageFlip-JNI**](https://github.com/eschao/android-PageFlip-JNI)
7 |
8 | ## Table of Contents
9 |
10 | * [Preview](#preview)
11 | * [Installation](#installation)
12 | - [Gradle](#gradle)
13 | * [Android Version Support](#android-version-support)
14 | * [Usage](#usage)
15 | - [Introduce PageFlip Into Your Project](#i-simple-steps-for-introducing-pageflip-into-your-project)
16 | - [Configure PageFilp](#ii-configure-pageflip)
17 | + [Page Mode](#1-page-mode)
18 | + [Click Screen To Flip](#2-click-screen-to-flip)
19 | + [Area Of Clicking To Flip](#3-area-of-clicking-to-flip)
20 | + [PageFlip Listener](#4-pageflip-listener)
21 | + [Mesh Pixels](#5-mesh-pixels)
22 | + [Ratio Of Semi-peremeter](#6-ratio-of-semi-peremeter)
23 | + [Mask Alpha For The Back Of Fold Page](#7-mask-alpha-for-the-back-of-fold-page)
24 | + [Edge Shadow Color/Alpha Of Fold Page](#8-edge-shadow-coloralpha-of-fold-page)
25 | + [Base Shadow Color/Alpha Of Fold Page](#9-base-shadow-coloralpha-of-fold-page)
26 | + [Edge Shadow Width Of Fold Page](#10-edge-shadow-width-of-fold-page)
27 | + [Base Shadow Width Of Fold Page](#11-base-shadow-width-of-fold-page)
28 | + [Duration Of Flip Animating](#12-duration-of-flip-animating)
29 |
30 | * [License](#license)
31 |
32 | ## Preview
33 |
34 |  
35 |
36 | ## Installation
37 |
38 | #### Gradle
39 |
40 | Add it to your build.gradle with:
41 | ```gradle
42 | allprojects {
43 | repositories {
44 | maven { url "https://jitpack.io" }
45 | }
46 | }
47 | ```
48 | and:
49 |
50 | ```gradle
51 | dependencies {
52 | compile 'com.github.eschao:android-PageFlip:1.0.2'
53 | }
54 | ```
55 | ## Android Version Support
56 |
57 | The following versions have been tested on emulator:
58 |
59 | Android version | API version | Support |
60 | ----------------|-------------|---------|
61 | 3.2 | API 13 | x |
62 | 4.1 | API 16 | √ |
63 | 4.2 | API 17 | √ |
64 | 4.3 | API 18 | √ |
65 | 4.4 | API 19 | √ |
66 | 5.0 | API 21 | √ |
67 | 5.1 | API 22 | √ |
68 | 6.0 | API 23 | √ |
69 | 7.0 | API 24 | √ |
70 | 7.1.1 | API 25 | √ |
71 | 7.+ | API 26 | √ |
72 |
73 | ## Usage
74 |
75 | ### I. Simple steps for introducing PageFlip into your project
76 |
77 | * Creates a surface view class extending from **GLSurfaceView**
78 | * Implements android **Renderer** interface to draw your content on a bitmap and set it as a texture of **PageFlip**
79 | * Instanitiates a **PageFlip** object in the constructor of your surface view
80 | * Configures **PageFlip**, For example: set animating duration, page mode or mesh pixels
81 | * Handles the below android events:
82 |
83 | * **onFingerDown**: notify *PageFlip* object to prepare flip
84 | * **onFingerMove**: notify *PageFlip* object to compute data for drawing flip frame
85 | * **onFingerUp**: notify *PageFlip* object to determine whether or not launching a flip animation
86 | * **onSurfaceCreated**: notify *PageFlip* object to handle usreface creating event
87 | * **onSurfaceChanged**: notify *PageFlip* object to handle surface changing event
88 |
89 | * You may need a message handler to send/receive an drawing message. Please refer to **PageFlipView** in sample application.
90 | * You may need a lock to avoid conflicts between main thread and OpenGL rendering thread. Please refer to **PageFlipView** in sample application.
91 |
92 | More details, please take a look **PageFlipView** in sample application.
93 |
94 | ### II. Configure PageFlip
95 |
96 | **PageFlip** library provides some configurations for customizing its behaviors. For example: shadow color and alpha, mesh pixels and page mode.
97 |
98 | #### 1. Page Mode
99 |
100 | There are two page modes provided by **PageFlip**:
101 |
102 | * **Auto Page Mode**: In this mode, **PageFlip** will automatically decide to use single page or double pages to present content on screen. That means single page is used for portrait mode and double pages is used for lanscape mode.
103 | * **Single Page Mode**: No matter screen is portait or landscape mode, **PageFlip** always use single page to show content
104 |
105 |
106 | You can use **enableAutoPage** to enable auto page mode or disable it(equally enable single page mode).
107 |
108 | Example:
109 | ```java
110 | // enable auto page mode
111 | mPageFlip.enableAutopage(true);
112 | ```
113 |
114 | #### 2. Click screen to flip
115 |
116 | You can enable/disable clicking screen to flip
117 |
118 | Example:
119 | ```java
120 | // enable clicking to flip
121 | mPageFlip.enableClickToFlip(true);
122 | ```
123 |
124 | #### 3. Area of clicking to flip
125 |
126 | You can give a ratio of page width from 0 to 0.5f to set an area for reponsing click event to trigger a page flip. The default value is **0.5f**, which means the backfward flip will happen if you click the left half of screen and forward flip will start if you click the right half of screen in single page mode.
127 |
128 | Example:
129 | ```java
130 | // set ratio with 0.3
131 | mPageFlip.setWidthRatioOfClickToFlip(0.3f);
132 | ```
133 |
134 | #### 4. PageFlip listener
135 |
136 | You can set a listener to tell **PageFlip** if the forward flip or backward flip could happen.
137 |
138 | Example:
139 | ```java
140 | mPageFlip.setListener(mListener);
141 | ```
142 |
143 | #### 5. Mesh pixels
144 |
145 | Set how many pixels are used for a mesh. The less pxiels the mesh uses, the more fine the drawing is and the lower the performance is. The default value is 10 pixels.
146 |
147 | Example:
148 | ```java
149 | mPageFlip.setPixelsOfMesh(5);
150 | ```
151 |
152 | #### 6. Ratio of semi-peremeter
153 |
154 | When page is curled, it is actually tackled as a semi-cylinder by **PageFlip**. You can set size of the semi-cylinder to change the flip shap. Since the semi-cylinder dependeds on the line length from the touch point to original point(see the below illustration), you need to provide a ratio of this line length to tell **PageFlip** the peremeter of the semi-cylinder. The default value is 0.8f.
155 |
156 | ```
157 | +----------------+
158 | | touchP |
159 | | . |
160 | | \ |
161 | | + p0 |
162 | | \ |
163 | | \ |
164 | | p1 + |
165 | | \ |
166 | +----------------+
167 | original point, that means you drag the page from here to touch point(touchP)
168 |
169 | The length from p0 to p1 is peremeter of semi-cylinder and determined by ratio your giving
170 | ```
171 |
172 | Example:
173 | ```java
174 | mPageFlip.setSemiPerimeterRatio(0.6f);
175 | ```
176 |
177 | #### 7. Mask alpha for the back of fold page
178 |
179 | You can set the mask alpha for the back of fold page when page is curled in single page mode. The default value is 0.6f.
180 |
181 | Example:
182 | ```java
183 | mPageFlip.setMaskAlphaOfFold(0.5f);
184 | ```
185 |
186 | #### 8. Edge shadow color/alpha of fold page
187 |
188 | You can set start/end color and start/end alpha for edge shadow of fold page.
189 |
190 | Example:
191 | ```java
192 | // set start color with 0.1f, start alpha with 0.2f, end color with 0.5f
193 | // and end alpha with 1f
194 | mPageFlip.setShadowColorOfFoldBase(0.1f, 0.2f, 0.5f, 1f);
195 | ```
196 |
197 | #### 9. Base shadow color/alpha of fold page
198 |
199 | You can set start/end color and start/end alpha for base shadow of fold page.
200 |
201 | Example:
202 | ```java
203 | mPageFlip.setShadowColorOfFoldBase(0.05f, 0.2f, 0.5f, 1f);
204 | ```
205 |
206 | #### 10. Edge shadow width of fold page
207 |
208 | When page is curled, the size of fold page will follow the finger movement to be changed and its edge shadow width should be changed accordingly. You can set an appropriate width range for shadow width.
209 |
210 | Example:
211 | ```java
212 | // set the minimal width is 5 pixels and maximum width is 40 pixels.
213 | // set the ratio is 0.3f which means the width will be firstly computed by formula:
214 | // width = diameter of semi-cylinder * 0.3f, and then compare it with minimal
215 | // and maximal value to make sure the width is in range.
216 | mPageFlip.setShadowWidthOfFoldEdges(5, 40, 0.3f);
217 | ```
218 |
219 | #### 11. Base shadow width of fold page
220 |
221 | Like **[Edge shadow width of fold page](10-edge-shadow-width-of-fold-page)**, You can set an appropriate width range for base shadow of fold page.
222 |
223 | Example:
224 | ```java
225 | // see {@link #setShadowWidthOfFoldEdges} function
226 | mPageFlip.setShadowWidthOfFoldBase(5, 40, 0.4f);
227 | ```
228 |
229 | #### 12. Duration of flip animating
230 |
231 | You can give a duration for flip animating when you call **onFingerUp** function to handle the finger up event.
232 |
233 | Example:
234 | ```java
235 | // the last parameter is duration with millisecond unit, here we set it with 2 seconds.
236 | mPageFlip.onFingerUp(x, y, 2000);
237 | ```
238 |
239 | ## License
240 | This project is licensed under the Apache License Version 2.0.
241 |
--------------------------------------------------------------------------------
/Sample/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/Sample/src/main/java/com/eschao/android/widget/sample/pageflip/Constants.java:
--------------------------------------------------------------------------------
1 | package com.eschao.android.widget.sample.pageflip;
2 |
3 | /**
4 | * Created by chao on 20/11/2016.
5 | */
6 |
7 | public class Constants {
8 | public final static String PREF_MESH_PIXELS = "MeshPixels";
9 | public final static String PREF_DURATION = "Duration";
10 | public final static String PREF_PAGE_MODE = "PageMode";
11 | }
12 |
--------------------------------------------------------------------------------
/Sample/src/main/java/com/eschao/android/widget/sample/pageflip/DoublePagesRender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.sample.pageflip;
17 |
18 | import android.content.Context;
19 | import android.graphics.Bitmap;
20 | import android.graphics.Color;
21 | import android.graphics.Paint;
22 | import android.graphics.Rect;
23 | import android.os.Handler;
24 | import android.os.Message;
25 | import android.widget.Toast;
26 |
27 | import com.eschao.android.widget.pageflip.Page;
28 | import com.eschao.android.widget.pageflip.PageFlip;
29 | import com.eschao.android.widget.pageflip.PageFlipState;
30 |
31 | /**
32 | * Double pages render
33 | *
34 | * Some key points here:
35 | *
36 | *
First page is which page user is clicking on or moving by finger
37 | * Sometimes it is left page on screen, sometimes it is right page.
38 | * Second page is leftover page against the first page
39 | *
40 | *
mPageNo is always the number of left page instead of first page
41 | *
42 | *
43 | *
44 | * Every screen 'Page' contains 3 page contents, so it need 3 textures:
45 | *
46 | *
First texture: first page content of this 'Page'
47 | *
Back texture: the second page content of this 'Page'
48 | *
Second texture: the third page content of this 'Page'
49 | *
50 | *
51 | *
52 | * @author eschao
53 | */
54 |
55 | public class DoublePagesRender extends PageRender {
56 |
57 | /**
58 | * Constructor
59 | * @see {@link #PageRender(Context, PageFlip, Handler, int)}
60 | */
61 | public DoublePagesRender(Context context, PageFlip pageFlip,
62 | Handler handler, int pageNo) {
63 | super(context, pageFlip, handler, pageNo);
64 | }
65 |
66 | /**
67 | * Draw page frame
68 | */
69 | public void onDrawFrame() {
70 | // 1. delete unused textures to save memory
71 | mPageFlip.deleteUnusedTextures();
72 |
73 | // 2. there are two pages for representing the whole screen, we need to
74 | // draw them one by one
75 | final Page first = mPageFlip.getFirstPage();
76 | final Page second = mPageFlip.getSecondPage();
77 |
78 | // 3. check if the first texture is valid for first page, if not,
79 | // create it with relative content
80 | if (!first.isFirstTextureSet()) {
81 | drawPage(first.isLeftPage() ? mPageNo : mPageNo + 1);
82 | first.setFirstTexture(mBitmap);
83 | }
84 |
85 | // 4. check if the first texture is valid for second page
86 | if (!second.isFirstTextureSet()) {
87 | drawPage(second.isLeftPage() ? mPageNo : mPageNo + 1);
88 | second.setFirstTexture(mBitmap);
89 | }
90 |
91 | // 5. handle drawing command triggered from finger moving and animating
92 | if (mDrawCommand == DRAW_MOVING_FRAME ||
93 | mDrawCommand == DRAW_ANIMATING_FRAME) {
94 | // before drawing, check if back texture of first page is valid
95 | // Remember: the first page is always the fold page
96 | if (!first.isBackTextureSet()) {
97 | drawPage(first.isLeftPage() ? mPageNo - 1 : mPageNo + 2);
98 | first.setBackTexture(mBitmap);
99 | }
100 |
101 | // check the second texture of first page is valid.
102 | if (!first.isSecondTextureSet()) {
103 | drawPage(first.isLeftPage() ? mPageNo - 2 : mPageNo + 3);
104 | first.setSecondTexture(mBitmap);
105 | }
106 |
107 | // draw frame for page flip
108 | mPageFlip.drawFlipFrame();
109 | }
110 | // draw stationary page without flipping
111 | else if (mDrawCommand == DRAW_FULL_PAGE){
112 | mPageFlip.drawPageFrame();
113 | }
114 |
115 | // 6. send message to main thread to notify drawing is ended so that
116 | // we can continue to calculate next animation frame if need.
117 | // Remember: the drawing operation is always in GL thread instead of
118 | // main thread
119 | Message msg = Message.obtain();
120 | msg.what = MSG_ENDED_DRAWING_FRAME;
121 | msg.arg1 = mDrawCommand;
122 | mHandler.sendMessage(msg);
123 | }
124 |
125 | /**
126 | * Handle GL surface is changed
127 | *
128 | * @param width surface width
129 | * @param height surface height
130 | */
131 | public void onSurfaceChanged(int width, int height) {
132 | // recycle bitmap resources if need
133 | if (mBackgroundBitmap != null) {
134 | mBackgroundBitmap.recycle();
135 | }
136 |
137 | if (mBitmap != null) {
138 | mBitmap.recycle();
139 | }
140 |
141 | // create bitmap and canvas for page
142 | //mBackgroundBitmap = background;
143 | Page page = mPageFlip.getFirstPage();
144 | int pageW = (int)page.width();
145 | int pageH = (int)page.height();
146 | mBitmap = Bitmap.createBitmap(pageW, pageH, Bitmap.Config.ARGB_8888);
147 | mCanvas.setBitmap(mBitmap);
148 | LoadBitmapTask.get(mContext).set(pageW, pageH, 2);
149 | }
150 |
151 | /**
152 | * Handle ended drawing event
153 | * In here, we only tackle the animation drawing event, If we need to
154 | * continue requesting render, please return true. Remember this function
155 | * will be called in main thread
156 | *
157 | * @param what event type
158 | * @return ture if need render again
159 | */
160 | public boolean onEndedDrawing(int what) {
161 | if (what == DRAW_ANIMATING_FRAME) {
162 | boolean isAnimating = mPageFlip.animating();
163 | // continue animating
164 | if (isAnimating) {
165 | mDrawCommand = DRAW_ANIMATING_FRAME;
166 | return true;
167 | }
168 | // animation is finished
169 | else {
170 | // should handle forward flip to update page number and exchange
171 | // textures between first and second pages. Don't have to handle
172 | // backward flip since there is no such state happened in double
173 | // page mode
174 | if (mPageFlip.getFlipState() == PageFlipState.END_WITH_FORWARD)
175 | {
176 | final Page first = mPageFlip.getFirstPage();
177 | final Page second = mPageFlip.getSecondPage();
178 | second.swapTexturesWithPage(first);
179 |
180 | // update page number for left page
181 | if (first.isLeftPage()) {
182 | mPageNo -= 2;
183 | }
184 | else {
185 | mPageNo += 2;
186 | }
187 | }
188 |
189 | mDrawCommand = DRAW_FULL_PAGE;
190 | return true;
191 | }
192 | }
193 | return false;
194 | }
195 |
196 | /**
197 | * Draw page content
198 | *
199 | * @param number page number
200 | */
201 | private void drawPage(int number) {
202 | final int width = mCanvas.getWidth();
203 | final int height = mCanvas.getHeight();
204 | Paint p = new Paint();
205 | p.setFilterBitmap(true);
206 |
207 | // 1. draw background bitmap
208 | Bitmap background = LoadBitmapTask.get(mContext).getBitmap();
209 | Rect rect = new Rect(0, 0, width, height);
210 | // if (width > height) {
211 | // mCanvas.rotate(90);
212 | // mCanvas.drawBitmap(background, null, rect, p);
213 | // mCanvas.rotate(-90);
214 | // }
215 | // else {
216 | mCanvas.drawBitmap(background, null, rect, p);
217 | // }
218 |
219 | background.recycle();
220 | background = null;
221 |
222 | // 2. draw page number
223 | int fontSize = (int)(80 * mContext.getResources().getDisplayMetrics()
224 | .scaledDensity);
225 | p.setColor(Color.WHITE);
226 | p.setStrokeWidth(1);
227 | p.setAntiAlias(true);
228 | p.setShadowLayer(5.0f, 8.0f, 8.0f, Color.BLACK);
229 | p.setTextSize(fontSize);
230 |
231 | String text = String.valueOf(number);
232 | if (number < 1) {
233 | text = "Preface";
234 | }
235 | else if (number > MAX_PAGES) {
236 | text = "End";
237 | }
238 | float textWidth = p.measureText(text);
239 | float y = height - p.getTextSize() - 20;
240 | mCanvas.drawText(text, (width - textWidth) / 2, y, p);
241 |
242 | if (number == 1) {
243 | String firstPage = "The First Page";
244 | p.setTextSize(calcFontSize(16));
245 | float w = p.measureText(firstPage);
246 | float h = p.getTextSize();
247 | mCanvas.drawText(firstPage, (width - w) / 2, y + 5 + h, p);
248 | }
249 | else if (number == MAX_PAGES) {
250 | String lastPage = "The Last Page";
251 | p.setTextSize(calcFontSize(16));
252 | float w = p.measureText(lastPage);
253 | float h = p.getTextSize();
254 | mCanvas.drawText(lastPage, (width - w) / 2, y + 5 + h, p);
255 | }
256 | }
257 |
258 | /**
259 | * If page can flip forward
260 | *
261 | * @return true if it can flip forward
262 | */
263 | public boolean canFlipForward() {
264 | final Page page = mPageFlip.getFirstPage();
265 | // current page is left page
266 | if (page.isLeftPage()) {
267 | return (mPageNo > 1);
268 | }
269 |
270 | // current page is right page
271 | return (mPageNo + 2 <= MAX_PAGES);
272 | }
273 |
274 | /**
275 | * Don't need to handle backward flip
276 | *
277 | * @return always false
278 | */
279 | public boolean canFlipBackward() {
280 | return false;
281 | }
282 | }
283 |
--------------------------------------------------------------------------------
/Sample/src/main/java/com/eschao/android/widget/sample/pageflip/LoadBitmapTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.sample.pageflip;
17 |
18 | import android.content.Context;
19 | import android.content.res.Resources;
20 | import android.graphics.Bitmap;
21 | import android.graphics.BitmapFactory;
22 | import android.graphics.Matrix;
23 | import android.util.Log;
24 |
25 | import java.util.LinkedList;
26 | import java.util.Random;
27 |
28 | /**
29 | * A singleton thread task to load bitmap
30 | *
Attempt to load bitmap in separate thread to get better performance.
Set mStop flag with true and notify task thread, at last, it will
150 | * check if task is alive every 500ms with 3 times to make sure the thread
151 | * stop
152 | */
153 | public void stop() {
154 | synchronized (this) {
155 | mStop = true;
156 | notify();
157 | }
158 |
159 | // wait for thread stopping
160 | for (int i = 0; i < 3 && mThread.isAlive(); ++i) {
161 | Log.d(TAG, "Waiting thread to stop ...");
162 | try {
163 | Thread.sleep(500);
164 | }
165 | catch (InterruptedException e) {
166 |
167 | }
168 | }
169 |
170 | if (mThread.isAlive()) {
171 | Log.d(TAG, "Thread is still alive after waited 1.5s!");
172 | }
173 | }
174 |
175 | /**
176 | * Set bitmap width , height and maximum size of cache queue
177 | *
178 | * @param w width of bitmap
179 | * @param h height of bitmap
180 | * @param maxCached maximum size of cache queue
181 | */
182 | public void set(int w, int h, int maxCached) {
183 | int newIndex = LARGE_BG;
184 | if ((w <= 480 && h <= 854) ||
185 | (w <= 854 && h <= 480)) {
186 | newIndex = SMALL_BG;
187 | }
188 | else if ((w <= 800 && h <= 1280) ||
189 | (h <= 800 && w <= 1280)) {
190 | newIndex = MEDIUM_BG;
191 | }
192 |
193 | mIsLandscape = w > h;
194 |
195 | if (maxCached != mQueueMaxSize) {
196 | mQueueMaxSize = maxCached;
197 | }
198 |
199 | if (newIndex != mBGSizeIndex) {
200 | mBGSizeIndex = newIndex;
201 | synchronized (this) {
202 | cleanQueue();
203 | notify();
204 | }
205 | }
206 | }
207 |
208 | /**
209 | * Load bitmap from resources randomly
210 | *
211 | * @return bitmap object
212 | */
213 | private Bitmap getRandomBitmap() {
214 | int newNo = mPreRandomNo;
215 | while (newNo == mPreRandomNo) {
216 | newNo = mBGRandom.nextInt(BG_COUNT);
217 | }
218 |
219 | mPreRandomNo = newNo;
220 | int resId = mPortraitBGs[mBGSizeIndex][newNo];
221 | Bitmap b = BitmapFactory.decodeResource(mResources, resId);
222 | // if (mIsLandscape) {
223 | // Matrix matrix = new Matrix();
224 | // matrix.postRotate(90);
225 | // Bitmap lb = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
226 | // matrix, true);
227 | // b.recycle();
228 | // return lb;
229 | // }
230 |
231 | return b;
232 | }
233 |
234 | /**
235 | * Clear cache queue
236 | */
237 | private void cleanQueue() {
238 | for (int i = 0; i < mQueue.size(); ++i) {
239 | mQueue.get(i).recycle();
240 | }
241 | mQueue.clear();
242 | }
243 |
244 | public void run() {
245 | while (true) {
246 | synchronized (this) {
247 | // check if ask thread stopping
248 | if (mStop) {
249 | cleanQueue();
250 | break;
251 | }
252 |
253 | // load bitmap only when no cached bitmap in queue
254 | int size = mQueue.size();
255 | if (size < 1) {
256 | for (int i = 0; i < mQueueMaxSize; ++i) {
257 | Log.d(TAG, "Load Queue:" + i + " in background!");
258 | mQueue.push(getRandomBitmap());
259 | }
260 | }
261 |
262 | // wait to be awaken
263 | try {
264 | wait();
265 | }
266 | catch (InterruptedException e) {
267 | }
268 | }
269 | }
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/Sample/src/main/java/com/eschao/android/widget/sample/pageflip/PageFlipView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.sample.pageflip;
17 |
18 | import android.content.Context;
19 | import android.content.SharedPreferences;
20 | import android.opengl.GLSurfaceView;
21 | import android.opengl.GLSurfaceView.Renderer;
22 | import android.os.Handler;
23 | import android.os.Message;
24 | import android.preference.PreferenceManager;
25 | import android.util.AttributeSet;
26 | import android.util.Log;
27 |
28 | import com.eschao.android.widget.pageflip.PageFlip;
29 | import com.eschao.android.widget.pageflip.PageFlipException;
30 |
31 | import java.util.concurrent.locks.ReentrantLock;
32 |
33 | import javax.microedition.khronos.egl.EGLConfig;
34 | import javax.microedition.khronos.opengles.GL10;
35 |
36 | /**
37 | * Page flip view
38 | *
39 | * @author eschao
40 | */
41 |
42 | public class PageFlipView extends GLSurfaceView implements Renderer {
43 |
44 | private final static String TAG = "PageFlipView";
45 |
46 | int mPageNo;
47 | int mDuration;
48 | Handler mHandler;
49 | PageFlip mPageFlip;
50 | PageRender mPageRender;
51 | ReentrantLock mDrawLock;
52 |
53 | public PageFlipView(Context context) {
54 | super(context);
55 | init(context);
56 | }
57 |
58 | public PageFlipView(Context context, AttributeSet attrs) {
59 | super(context, attrs);
60 | init(context);
61 | }
62 | private void init(Context context) {
63 | // create handler to tackle message
64 | newHandler();
65 |
66 | // load preferences
67 | SharedPreferences pref = PreferenceManager
68 | .getDefaultSharedPreferences(context);
69 | mDuration = pref.getInt(Constants.PREF_DURATION, 1000);
70 | int pixelsOfMesh = pref.getInt(Constants.PREF_MESH_PIXELS, 10);
71 | boolean isAuto = pref.getBoolean(Constants.PREF_PAGE_MODE, true);
72 |
73 | // create PageFlip
74 | mPageFlip = new PageFlip(context);
75 | mPageFlip.setSemiPerimeterRatio(0.8f)
76 | .setShadowWidthOfFoldEdges(5, 60, 0.3f)
77 | .setShadowWidthOfFoldBase(5, 80, 0.4f)
78 | .setPixelsOfMesh(pixelsOfMesh)
79 | .enableAutoPage(isAuto);
80 | setEGLContextClientVersion(2);
81 |
82 | // init others
83 | mPageNo = 1;
84 | mDrawLock = new ReentrantLock();
85 | mPageRender = new SinglePageRender(context, mPageFlip,
86 | mHandler, mPageNo);
87 | // configure render
88 | setRenderer(this);
89 | setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
90 | }
91 |
92 |
93 | /**
94 | * Is auto page mode enabled?
95 | *
96 | * @return true if auto page mode enabled
97 | */
98 | public boolean isAutoPageEnabled() {
99 | return mPageFlip.isAutoPageEnabled();
100 | }
101 |
102 | /**
103 | * Enable/Disable auto page mode
104 | *
105 | * @param enable true is enable
106 | */
107 | public void enableAutoPage(boolean enable) {
108 | if (mPageFlip.enableAutoPage(enable)) {
109 | try {
110 | mDrawLock.lock();
111 | if (mPageFlip.getSecondPage() != null &&
112 | mPageRender instanceof SinglePageRender) {
113 | mPageRender = new DoublePagesRender(getContext(),
114 | mPageFlip,
115 | mHandler,
116 | mPageNo);
117 | mPageRender.onSurfaceChanged(mPageFlip.getSurfaceWidth(),
118 | mPageFlip.getSurfaceHeight());
119 | }
120 | else if (mPageFlip.getSecondPage() == null &&
121 | mPageRender instanceof DoublePagesRender) {
122 | mPageRender = new SinglePageRender(getContext(),
123 | mPageFlip,
124 | mHandler,
125 | mPageNo);
126 | mPageRender.onSurfaceChanged(mPageFlip.getSurfaceWidth(),
127 | mPageFlip.getSurfaceHeight());
128 | }
129 | requestRender();
130 | }
131 | finally {
132 | mDrawLock.unlock();
133 | }
134 | }
135 | }
136 |
137 | /**
138 | * Get duration of animating
139 | *
140 | * @return duration of animating
141 | */
142 | public int getAnimateDuration() {
143 | return mDuration;
144 | }
145 |
146 | /**
147 | * Set animate duration
148 | *
149 | * @param duration duration of animating
150 | */
151 | public void setAnimateDuration(int duration) {
152 | mDuration = duration;
153 | }
154 |
155 | /**
156 | * Get pixels of mesh
157 | *
158 | * @return pixels of mesh
159 | */
160 | public int getPixelsOfMesh() {
161 | return mPageFlip.getPixelsOfMesh();
162 | }
163 |
164 | /**
165 | * Handle finger down event
166 | *
167 | * @param x finger x coordinate
168 | * @param y finger y coordinate
169 | */
170 | public void onFingerDown(float x, float y) {
171 | // if the animation is going, we should ignore this event to avoid
172 | // mess drawing on screen
173 | if (!mPageFlip.isAnimating() &&
174 | mPageFlip.getFirstPage() != null) {
175 | mPageFlip.onFingerDown(x, y);
176 | }
177 | }
178 |
179 | /**
180 | * Handle finger moving event
181 | *
182 | * @param x finger x coordinate
183 | * @param y finger y coordinate
184 | */
185 | public void onFingerMove(float x, float y) {
186 | if (mPageFlip.isAnimating()) {
187 | // nothing to do during animating
188 | }
189 | else if (mPageFlip.canAnimate(x, y)) {
190 | // if the point is out of current page, try to start animating
191 | onFingerUp(x, y);
192 | }
193 | // move page by finger
194 | else if (mPageFlip.onFingerMove(x, y)) {
195 | try {
196 | mDrawLock.lock();
197 | if (mPageRender != null &&
198 | mPageRender.onFingerMove(x, y)) {
199 | requestRender();
200 | }
201 | }
202 | finally {
203 | mDrawLock.unlock();
204 | }
205 | }
206 | }
207 |
208 | /**
209 | * Handle finger up event and start animating if need
210 | *
211 | * @param x finger x coordinate
212 | * @param y finger y coordinate
213 | */
214 | public void onFingerUp(float x, float y) {
215 | if (!mPageFlip.isAnimating()) {
216 | mPageFlip.onFingerUp(x, y, mDuration);
217 | try {
218 | mDrawLock.lock();
219 | if (mPageRender != null &&
220 | mPageRender.onFingerUp(x, y)) {
221 | requestRender();
222 | }
223 | }
224 | finally {
225 | mDrawLock.unlock();
226 | }
227 | }
228 | }
229 |
230 | /**
231 | * Draw frame
232 | *
233 | * @param gl OpenGL handle
234 | */
235 | @Override
236 | public void onDrawFrame(GL10 gl) {
237 | try {
238 | mDrawLock.lock();
239 | if (mPageRender != null) {
240 | mPageRender.onDrawFrame();
241 | }
242 | }
243 | finally {
244 | mDrawLock.unlock();
245 | }
246 | }
247 |
248 | /**
249 | * Handle surface is changed
250 | *
251 | * @param gl OpenGL handle
252 | * @param width new width of surface
253 | * @param height new height of surface
254 | */
255 | @Override
256 | public void onSurfaceChanged(GL10 gl, int width, int height) {
257 | try {
258 | mPageFlip.onSurfaceChanged(width, height);
259 |
260 | // if there is the second page, create double page render when need
261 | int pageNo = mPageRender.getPageNo();
262 | if (mPageFlip.getSecondPage() != null && width > height) {
263 | if (!(mPageRender instanceof DoublePagesRender)) {
264 | mPageRender.release();
265 | mPageRender = new DoublePagesRender(getContext(),
266 | mPageFlip,
267 | mHandler,
268 | pageNo);
269 | }
270 | }
271 | // if there is only one page, create single page render when need
272 | else if(!(mPageRender instanceof SinglePageRender)) {
273 | mPageRender.release();
274 | mPageRender = new SinglePageRender(getContext(),
275 | mPageFlip,
276 | mHandler,
277 | pageNo);
278 | }
279 |
280 | // let page render handle surface change
281 | mPageRender.onSurfaceChanged(width, height);
282 | }
283 | catch (PageFlipException e) {
284 | Log.e(TAG, "Failed to run PageFlipFlipRender:onSurfaceChanged");
285 | }
286 | }
287 |
288 | /**
289 | * Handle surface is created
290 | *
291 | * @param gl OpenGL handle
292 | * @param config EGLConfig object
293 | */
294 | @Override
295 | public void onSurfaceCreated(GL10 gl, EGLConfig config) {
296 | try {
297 | mPageFlip.onSurfaceCreated();
298 | }
299 | catch (PageFlipException e) {
300 | Log.e(TAG, "Failed to run PageFlipFlipRender:onSurfaceCreated");
301 | }
302 | }
303 |
304 | /**
305 | * Create message handler to cope with messages from page render,
306 | * Page render will send message in GL thread, but we want to handle those
307 | * messages in main thread that why we need handler here
308 | */
309 | private void newHandler() {
310 | mHandler = new Handler() {
311 | public void handleMessage(Message msg) {
312 | switch (msg.what) {
313 | case PageRender.MSG_ENDED_DRAWING_FRAME:
314 | try {
315 | mDrawLock.lock();
316 | // notify page render to handle ended drawing
317 | // message
318 | if (mPageRender != null &&
319 | mPageRender.onEndedDrawing(msg.arg1)) {
320 | requestRender();
321 | }
322 | }
323 | finally {
324 | mDrawLock.unlock();
325 | }
326 | break;
327 |
328 | default:
329 | break;
330 | }
331 | }
332 | };
333 | }
334 | }
335 |
--------------------------------------------------------------------------------
/Sample/src/main/java/com/eschao/android/widget/sample/pageflip/PageRender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.sample.pageflip;
17 |
18 | import android.content.Context;
19 | import android.graphics.Bitmap;
20 | import android.graphics.Canvas;
21 | import android.os.Handler;
22 |
23 | import com.eschao.android.widget.pageflip.OnPageFlipListener;
24 | import com.eschao.android.widget.pageflip.PageFlip;
25 |
26 | /**
27 | * Abstract Page Render
28 | *
29 | * @author eschao
30 | */
31 |
32 | public abstract class PageRender implements OnPageFlipListener {
33 |
34 | public final static int MSG_ENDED_DRAWING_FRAME = 1;
35 | private final static String TAG = "PageRender";
36 |
37 | final static int DRAW_MOVING_FRAME = 0;
38 | final static int DRAW_ANIMATING_FRAME = 1;
39 | final static int DRAW_FULL_PAGE = 2;
40 |
41 | final static int MAX_PAGES = 30;
42 |
43 | int mPageNo;
44 | int mDrawCommand;
45 | Bitmap mBitmap;
46 | Canvas mCanvas;
47 | Bitmap mBackgroundBitmap;
48 | Context mContext;
49 | Handler mHandler;
50 | PageFlip mPageFlip;
51 |
52 | public PageRender(Context context, PageFlip pageFlip,
53 | Handler handler, int pageNo) {
54 | mContext = context;
55 | mPageFlip = pageFlip;
56 | mPageNo = pageNo;
57 | mDrawCommand = DRAW_FULL_PAGE;
58 | mCanvas = new Canvas();
59 | mPageFlip.setListener(this);
60 | mHandler = handler;
61 | }
62 |
63 | /**
64 | * Get page number
65 | *
66 | * @return page number
67 | */
68 | public int getPageNo() {
69 | return mPageNo;
70 | }
71 |
72 | /**
73 | * Release resources
74 | */
75 | public void release() {
76 | if (mBitmap != null) {
77 | mBitmap.recycle();
78 | mBitmap = null;
79 | }
80 |
81 | mPageFlip.setListener(null);
82 | mCanvas = null;
83 | mBackgroundBitmap = null;
84 | }
85 |
86 | /**
87 | * Handle finger moving event
88 | *
89 | * @param x x coordinate of finger moving
90 | * @param y y coordinate of finger moving
91 | * @return true if event is handled
92 | */
93 | public boolean onFingerMove(float x, float y) {
94 | mDrawCommand = DRAW_MOVING_FRAME;
95 | return true;
96 | }
97 |
98 | /**
99 | * Handle finger up event
100 | *
101 | * @param x x coordinate of finger up
102 | * @param y y coordinate of inger up
103 | * @return true if event is handled
104 | */
105 | public boolean onFingerUp(float x, float y) {
106 | if (mPageFlip.animating()) {
107 | mDrawCommand = DRAW_ANIMATING_FRAME;
108 | return true;
109 | }
110 |
111 | return false;
112 | }
113 |
114 | /**
115 | * Calculate font size by given SP unit
116 | */
117 | protected int calcFontSize(int size) {
118 | return (int)(size * mContext.getResources().getDisplayMetrics()
119 | .scaledDensity);
120 | }
121 |
122 | /**
123 | * Render page frame
124 | */
125 | abstract void onDrawFrame();
126 |
127 | /**
128 | * Handle surface changing event
129 | *
130 | * @param width surface width
131 | * @param height surface height
132 | */
133 | abstract void onSurfaceChanged(int width, int height);
134 |
135 | /**
136 | * Handle drawing ended event
137 | *
138 | * @param what draw command
139 | * @return true if render is needed
140 | */
141 | abstract boolean onEndedDrawing(int what);
142 | }
143 |
--------------------------------------------------------------------------------
/Sample/src/main/java/com/eschao/android/widget/sample/pageflip/SampleActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.sample.pageflip;
17 |
18 | import android.app.Activity;
19 | import android.app.AlertDialog;
20 | import android.content.SharedPreferences;
21 | import android.content.SharedPreferences.Editor;
22 | import android.os.Build;
23 | import android.os.Bundle;
24 |
25 | import android.preference.PreferenceManager;
26 | import android.text.Html;
27 | import android.text.method.LinkMovementMethod;
28 | import android.view.GestureDetector;
29 |
30 | import android.view.GestureDetector.OnGestureListener;
31 | import android.view.Menu;
32 | import android.view.MenuInflater;
33 | import android.view.MenuItem;
34 | import android.view.MotionEvent;
35 | import android.view.View;
36 | import android.view.WindowManager;
37 | import android.widget.TextView;
38 |
39 | /**
40 | * Sample Activity
41 | *
42 | * @author eschao
43 | */
44 | public class SampleActivity extends Activity implements OnGestureListener {
45 |
46 | PageFlipView mPageFlipView;
47 | GestureDetector mGestureDetector;
48 |
49 | @Override
50 | public void onCreate(Bundle savedInstanceState) {
51 | super.onCreate(savedInstanceState);
52 |
53 | mPageFlipView = new PageFlipView(this);
54 | setContentView(mPageFlipView);
55 | mGestureDetector = new GestureDetector(this, this);
56 |
57 | if (Build.VERSION.SDK_INT < 16) {
58 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
59 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
60 | } else {
61 | mPageFlipView.setSystemUiVisibility(
62 | View.SYSTEM_UI_FLAG_FULLSCREEN |
63 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
64 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
65 | View.SYSTEM_UI_FLAG_IMMERSIVE |
66 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
67 | }
68 | }
69 |
70 | @Override
71 | protected void onResume() {
72 | super.onResume();
73 |
74 | LoadBitmapTask.get(this).start();
75 | mPageFlipView.onResume();
76 | }
77 |
78 | @Override
79 | protected void onPause() {
80 | super.onPause();
81 |
82 | mPageFlipView.onPause();
83 | LoadBitmapTask.get(this).stop();
84 | }
85 |
86 | @Override
87 | public boolean onCreateOptionsMenu(Menu menu) {
88 | MenuInflater inflater = getMenuInflater();
89 | inflater.inflate(R.menu.optionmenus, menu);
90 |
91 | int duration = mPageFlipView.getAnimateDuration();
92 | if (duration == 1000) {
93 | menu.findItem(R.id.animation_1s).setChecked(true);
94 | }
95 | else if (duration == 2000) {
96 | menu.findItem(R.id.animation_2s).setChecked(true);
97 | }
98 | else if (duration == 5000) {
99 | menu.findItem(R.id.animation_5s).setChecked(true);
100 | }
101 |
102 | if (mPageFlipView.isAutoPageEnabled()) {
103 | menu.findItem(R.id.auoto_page).setChecked(true);
104 | }
105 | else {
106 | menu.findItem(R.id.single_page).setChecked(true);
107 | }
108 |
109 | SharedPreferences pref = PreferenceManager
110 | .getDefaultSharedPreferences(this);
111 | int pixels = pref.getInt("MeshPixels", mPageFlipView.getPixelsOfMesh());
112 | switch (pixels) {
113 | case 2:
114 | menu.findItem(R.id.mesh_2p).setChecked(true);
115 | break;
116 | case 5:
117 | menu.findItem(R.id.mesh_5p).setChecked(true);
118 | break;
119 | case 10:
120 | menu.findItem(R.id.mesh_10p).setChecked(true);
121 | break;
122 | case 20:
123 | menu.findItem(R.id.mesh_20p).setChecked(true);
124 | break;
125 | default:
126 | break;
127 | }
128 |
129 | return true;
130 | }
131 |
132 | @Override
133 | public boolean onOptionsItemSelected(MenuItem item) {
134 | boolean isHandled = true;
135 | SharedPreferences pref = PreferenceManager
136 | .getDefaultSharedPreferences(this);
137 | Editor editor = pref.edit();
138 | switch (item.getItemId()) {
139 | case R.id.animation_1s:
140 | mPageFlipView.setAnimateDuration(1000);
141 | editor.putInt(Constants.PREF_DURATION, 1000);
142 | break;
143 | case R.id.animation_2s:
144 | mPageFlipView.setAnimateDuration(2000);
145 | editor.putInt(Constants.PREF_DURATION, 2000);
146 | break;
147 | case R.id.animation_5s:
148 | mPageFlipView.setAnimateDuration(5000);
149 | editor.putInt(Constants.PREF_DURATION, 5000);
150 | break;
151 | case R.id.auoto_page:
152 | mPageFlipView.enableAutoPage(true);
153 | editor.putBoolean(Constants.PREF_PAGE_MODE, true);
154 | break;
155 | case R.id.single_page:
156 | mPageFlipView.enableAutoPage(false);
157 | editor.putBoolean(Constants.PREF_PAGE_MODE, false);
158 | break;
159 | case R.id.mesh_2p:
160 | editor.putInt(Constants.PREF_MESH_PIXELS, 2);
161 | break;
162 | case R.id.mesh_5p:
163 | editor.putInt(Constants.PREF_MESH_PIXELS, 5);
164 | break;
165 | case R.id.mesh_10p:
166 | editor.putInt(Constants.PREF_MESH_PIXELS, 10);
167 | break;
168 | case R.id.mesh_20p:
169 | editor.putInt(Constants.PREF_MESH_PIXELS, 20);
170 | break;
171 | case R.id.about_menu:
172 | showAbout();
173 | return true;
174 | default:
175 | isHandled = false;
176 | break;
177 | }
178 |
179 | if (isHandled) {
180 | item.setChecked(true);
181 | editor.apply();
182 | return true;
183 | }
184 | return super.onOptionsItemSelected(item);
185 | }
186 |
187 | @Override
188 | public boolean onTouchEvent(MotionEvent event) {
189 | if (event.getAction() == MotionEvent.ACTION_UP) {
190 | mPageFlipView.onFingerUp(event.getX(), event.getY());
191 | return true;
192 | }
193 |
194 | return mGestureDetector.onTouchEvent(event);
195 | }
196 |
197 | @Override
198 | public boolean onDown(MotionEvent e) {
199 | mPageFlipView.onFingerDown(e.getX(), e.getY());
200 | return true;
201 | }
202 |
203 | @Override
204 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
205 | float velocityY) {
206 | return false;
207 | }
208 |
209 |
210 | @Override
211 | public void onLongPress(MotionEvent e) {
212 | }
213 |
214 | @Override
215 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
216 | float distanceY) {
217 | mPageFlipView.onFingerMove(e2.getX(), e2.getY());
218 | return true;
219 | }
220 |
221 | @Override
222 | public void onShowPress(MotionEvent e) {
223 | }
224 |
225 | public boolean onSingleTapUp(MotionEvent e) {
226 | return false;
227 | }
228 |
229 | private void showAbout() {
230 | View aboutView = getLayoutInflater().inflate(R.layout.about, null,
231 | false);
232 |
233 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
234 | builder.setIcon(R.mipmap.ic_launcher);
235 | builder.setTitle(R.string.app_name);
236 | builder.setView(aboutView);
237 | builder.create();
238 | builder.show();
239 | }
240 | }
241 |
--------------------------------------------------------------------------------
/Sample/src/main/java/com/eschao/android/widget/sample/pageflip/SinglePageRender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 eschao
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.eschao.android.widget.sample.pageflip;
17 |
18 | import android.content.Context;
19 | import android.graphics.Bitmap;
20 | import android.graphics.Color;
21 | import android.graphics.Paint;
22 | import android.graphics.Rect;
23 | import android.os.Handler;
24 | import android.os.Message;
25 | import android.widget.Toast;
26 |
27 | import com.eschao.android.widget.pageflip.Page;
28 | import com.eschao.android.widget.pageflip.PageFlip;
29 | import com.eschao.android.widget.pageflip.PageFlipState;
30 |
31 | /**
32 | * Single page render
33 | *
34 | * Every page need 2 texture in single page mode:
35 | *
36 | *
First texture: current page content
37 | *
Back texture: back of front content, it is same with first texture
38 | *
39 | *
Second texture: next page content
40 | *
41 | *
42 | *
43 | * @author eschao
44 | */
45 |
46 | public class SinglePageRender extends PageRender {
47 |
48 | /**
49 | * Constructor
50 | * @see {@link #PageRender(Context, PageFlip, Handler, int)}
51 | */
52 | public SinglePageRender(Context context, PageFlip pageFlip,
53 | Handler handler, int pageNo) {
54 | super(context, pageFlip, handler, pageNo);
55 | }
56 |
57 | /**
58 | * Draw frame
59 | */
60 | public void onDrawFrame() {
61 | // 1. delete unused textures
62 | mPageFlip.deleteUnusedTextures();
63 | Page page = mPageFlip.getFirstPage();
64 |
65 | // 2. handle drawing command triggered from finger moving and animating
66 | if (mDrawCommand == DRAW_MOVING_FRAME ||
67 | mDrawCommand == DRAW_ANIMATING_FRAME) {
68 | // is forward flip
69 | if (mPageFlip.getFlipState() == PageFlipState.FORWARD_FLIP) {
70 | // check if second texture of first page is valid, if not,
71 | // create new one
72 | if (!page.isSecondTextureSet()) {
73 | drawPage(mPageNo + 1);
74 | page.setSecondTexture(mBitmap);
75 | }
76 | }
77 | // in backward flip, check first texture of first page is valid
78 | else if (!page.isFirstTextureSet()) {
79 | drawPage(--mPageNo);
80 | page.setFirstTexture(mBitmap);
81 | }
82 |
83 | // draw frame for page flip
84 | mPageFlip.drawFlipFrame();
85 | }
86 | // draw stationary page without flipping
87 | else if (mDrawCommand == DRAW_FULL_PAGE) {
88 | if (!page.isFirstTextureSet()) {
89 | drawPage(mPageNo);
90 | page.setFirstTexture(mBitmap);
91 | }
92 |
93 | mPageFlip.drawPageFrame();
94 | }
95 |
96 | // 3. send message to main thread to notify drawing is ended so that
97 | // we can continue to calculate next animation frame if need.
98 | // Remember: the drawing operation is always in GL thread instead of
99 | // main thread
100 | Message msg = Message.obtain();
101 | msg.what = MSG_ENDED_DRAWING_FRAME;
102 | msg.arg1 = mDrawCommand;
103 | mHandler.sendMessage(msg);
104 | }
105 |
106 | /**
107 | * Handle GL surface is changed
108 | *
109 | * @param width surface width
110 | * @param height surface height
111 | */
112 | public void onSurfaceChanged(int width, int height) {
113 | // recycle bitmap resources if need
114 | if (mBackgroundBitmap != null) {
115 | mBackgroundBitmap.recycle();
116 | }
117 |
118 | if (mBitmap != null) {
119 | mBitmap.recycle();
120 | }
121 |
122 | // create bitmap and canvas for page
123 | //mBackgroundBitmap = background;
124 | Page page = mPageFlip.getFirstPage();
125 | mBitmap = Bitmap.createBitmap((int)page.width(), (int)page.height(),
126 | Bitmap.Config.ARGB_8888);
127 | mCanvas.setBitmap(mBitmap);
128 | LoadBitmapTask.get(mContext).set(width, height, 1);
129 | }
130 |
131 | /**
132 | * Handle ended drawing event
133 | * In here, we only tackle the animation drawing event, If we need to
134 | * continue requesting render, please return true. Remember this function
135 | * will be called in main thread
136 | *
137 | * @param what event type
138 | * @return ture if need render again
139 | */
140 | public boolean onEndedDrawing(int what) {
141 | if (what == DRAW_ANIMATING_FRAME) {
142 | boolean isAnimating = mPageFlip.animating();
143 | // continue animating
144 | if (isAnimating) {
145 | mDrawCommand = DRAW_ANIMATING_FRAME;
146 | return true;
147 | }
148 | // animation is finished
149 | else {
150 | final PageFlipState state = mPageFlip.getFlipState();
151 | // update page number for backward flip
152 | if (state == PageFlipState.END_WITH_BACKWARD) {
153 | // don't do anything on page number since mPageNo is always
154 | // represents the FIRST_TEXTURE no;
155 | }
156 | // update page number and switch textures for forward flip
157 | else if (state == PageFlipState.END_WITH_FORWARD) {
158 | mPageFlip.getFirstPage().setFirstTextureWithSecond();
159 | mPageNo++;
160 | }
161 |
162 | mDrawCommand = DRAW_FULL_PAGE;
163 | return true;
164 | }
165 | }
166 | return false;
167 | }
168 |
169 | /**
170 | * Draw page content
171 | *
172 | * @param number page number
173 | */
174 | private void drawPage(int number) {
175 | final int width = mCanvas.getWidth();
176 | final int height = mCanvas.getHeight();
177 | Paint p = new Paint();
178 | p.setFilterBitmap(true);
179 |
180 | // 1. draw background bitmap
181 | Bitmap background = LoadBitmapTask.get(mContext).getBitmap();
182 | Rect rect = new Rect(0, 0, width, height);
183 | mCanvas.drawBitmap(background, null, rect, p);
184 | background.recycle();
185 | background = null;
186 |
187 | // 2. draw page number
188 | int fontSize = calcFontSize(80);
189 | p.setColor(Color.WHITE);
190 | p.setStrokeWidth(1);
191 | p.setAntiAlias(true);
192 | p.setShadowLayer(5.0f, 8.0f, 8.0f, Color.BLACK);
193 | p.setTextSize(fontSize);
194 | String text = String.valueOf(number);
195 | float textWidth = p.measureText(text);
196 | float y = height - p.getTextSize() - 20;
197 | mCanvas.drawText(text, (width - textWidth) / 2, y, p);
198 |
199 | if (number <= 1) {
200 | String firstPage = "The First Page";
201 | p.setTextSize(calcFontSize(16));
202 | float w = p.measureText(firstPage);
203 | float h = p.getTextSize();
204 | mCanvas.drawText(firstPage, (width - w) / 2, y + 5 + h, p);
205 | }
206 | else if (number >= MAX_PAGES) {
207 | String lastPage = "The Last Page";
208 | p.setTextSize(calcFontSize(16));
209 | float w = p.measureText(lastPage);
210 | float h = p.getTextSize();
211 | mCanvas.drawText(lastPage, (width - w) / 2, y + 5 + h, p);
212 | }
213 | }
214 |
215 | /**
216 | * If page can flip forward
217 | *
218 | * @return true if it can flip forward
219 | */
220 | public boolean canFlipForward() {
221 | return (mPageNo < MAX_PAGES);
222 | }
223 |
224 | /**
225 | * If page can flip backward
226 | *
227 | * @return true if it can flip backward
228 | */
229 | public boolean canFlipBackward() {
230 | if (mPageNo > 1) {
231 | mPageFlip.getFirstPage().setSecondTextureWithFirst();
232 | return true;
233 | }
234 | else {
235 | return false;
236 | }
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p10_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p10_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p10_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p10_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p10_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p10_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p1_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p1_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p1_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p1_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p1_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p1_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p2_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p2_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p2_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p2_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p2_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p2_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p3_1080.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p3_1080.png
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p3_480.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p3_480.png
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p3_720.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p3_720.png
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p4_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p4_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p4_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p4_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p4_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p4_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p5_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p5_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p5_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p5_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p5_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p5_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p6_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p6_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p6_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p6_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p6_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p6_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p7_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p7_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p7_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p7_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p7_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p7_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p8_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p8_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p8_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p8_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p8_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p8_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p9_1080.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p9_1080.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p9_480.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p9_480.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable/p9_720.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/Sample/src/main/res/drawable/p9_720.jpg
--------------------------------------------------------------------------------
/Sample/src/main/res/layout/about.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
19 |
20 |
31 |
32 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Sample/src/main/res/menu/optionmenus.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.2'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Sat Dec 24 22:22:36 CST 2016
16 | systemProp.http.proxyHost=127.0.0.1
17 | systemProp.http.proxyPort=1080
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 13 13:58:50 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion '25.0.0'
6 |
7 | defaultConfig {
8 | applicationId "com.eschao.android.widget.sample"
9 | minSdkVersion 15
10 | targetSdkVersion 24
11 | versionCode 2
12 | versionName "1.0.2"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:24.2.0'
26 | compile project(':PageFlip')
27 | }
28 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/chao/Software/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/sample_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eschao/android-PageFlip/6c361e0932c80c360fdf5f7de06963031e8c26d2/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PageFlip
3 | PageFlip Demo
4 |
5 | 1. Changing "Mesh Pixels" will only take effect in next time!
6 |
7 |
8 | 2. The codes are under Apache License 2.0. You can get it from
9 | https://github.com/eschao/android-PageFlip and use freely.
10 |
11 |
12 | 3. Any question please mailto: esc.chao@gmail.com or file issue in github.
13 |
14 |
15 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':Sample', ':PageFlip'
2 |
--------------------------------------------------------------------------------