blob: 626d0cfed9975716d20212ffdac119079bcf4e08 [file] [log] [blame]
Ahan Wu67e7f102019-01-14 20:38:14 +08001/*
2 * Copyright (C) 2019 The Android Open Source Project
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
17package com.android.systemui.glwallpaper;
18
19import static android.opengl.GLES20.GL_FLOAT;
20import static android.opengl.GLES20.GL_LINEAR;
21import static android.opengl.GLES20.GL_TEXTURE0;
22import static android.opengl.GLES20.GL_TEXTURE_2D;
23import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
24import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
25import static android.opengl.GLES20.GL_TRIANGLES;
26import static android.opengl.GLES20.glActiveTexture;
27import static android.opengl.GLES20.glBindTexture;
28import static android.opengl.GLES20.glDrawArrays;
29import static android.opengl.GLES20.glEnableVertexAttribArray;
30import static android.opengl.GLES20.glGenTextures;
31import static android.opengl.GLES20.glTexParameteri;
32import static android.opengl.GLES20.glUniform1i;
33import static android.opengl.GLES20.glVertexAttribPointer;
34
35import android.graphics.Bitmap;
Ahan Wue16e1fa2019-05-29 18:39:33 +080036import android.graphics.Rect;
Ahan Wu67e7f102019-01-14 20:38:14 +080037import android.opengl.GLUtils;
Ahan Wu67e7f102019-01-14 20:38:14 +080038import android.util.Log;
39
Ahan Wue16e1fa2019-05-29 18:39:33 +080040import java.io.FileDescriptor;
41import java.io.PrintWriter;
Ahan Wu67e7f102019-01-14 20:38:14 +080042import java.nio.ByteBuffer;
43import java.nio.ByteOrder;
44import java.nio.FloatBuffer;
45
46/**
47 * This class takes charge of the geometry data like vertices and texture coordinates.
48 * It delivers these data to opengl runtime and triggers draw calls if necessary.
49 */
50class ImageGLWallpaper {
51 private static final String TAG = ImageGLWallpaper.class.getSimpleName();
52
53 static final String A_POSITION = "aPosition";
54 static final String A_TEXTURE_COORDINATES = "aTextureCoordinates";
Ahan Wu4c9a5502019-03-04 15:35:28 +080055 static final String U_PER85 = "uPer85";
Ahan Wu67e7f102019-01-14 20:38:14 +080056 static final String U_REVEAL = "uReveal";
57 static final String U_AOD2OPACITY = "uAod2Opacity";
58 static final String U_TEXTURE = "uTexture";
59
60 private static final int HANDLE_UNDEFINED = -1;
61 private static final int POSITION_COMPONENT_COUNT = 2;
62 private static final int TEXTURE_COMPONENT_COUNT = 2;
63 private static final int BYTES_PER_FLOAT = 4;
64
65 // Vertices to define the square with 2 triangles.
66 private static final float[] VERTICES = {
67 -1.0f, -1.0f,
68 +1.0f, -1.0f,
69 +1.0f, +1.0f,
70 +1.0f, +1.0f,
71 -1.0f, +1.0f,
72 -1.0f, -1.0f
73 };
74
75 // Texture coordinates that maps to vertices.
76 private static final float[] TEXTURES = {
77 0f, 1f,
78 1f, 1f,
79 1f, 0f,
80 1f, 0f,
81 0f, 0f,
82 0f, 1f
83 };
84
85 private final FloatBuffer mVertexBuffer;
86 private final FloatBuffer mTextureBuffer;
87 private final ImageGLProgram mProgram;
88
89 private int mAttrPosition;
90 private int mAttrTextureCoordinates;
91 private int mUniAod2Opacity;
Ahan Wu4c9a5502019-03-04 15:35:28 +080092 private int mUniPer85;
Ahan Wu67e7f102019-01-14 20:38:14 +080093 private int mUniReveal;
94 private int mUniTexture;
95 private int mTextureId;
96
Ahan Wue16e1fa2019-05-29 18:39:33 +080097 private float[] mCurrentTexCoordinate;
98
Ahan Wu67e7f102019-01-14 20:38:14 +080099 ImageGLWallpaper(ImageGLProgram program) {
100 mProgram = program;
101
102 // Create an float array in opengles runtime (native) and put vertex data.
103 mVertexBuffer = ByteBuffer.allocateDirect(VERTICES.length * BYTES_PER_FLOAT)
104 .order(ByteOrder.nativeOrder())
105 .asFloatBuffer();
106 mVertexBuffer.put(VERTICES);
107 mVertexBuffer.position(0);
108
109 // Create an float array in opengles runtime (native) and put texture data.
110 mTextureBuffer = ByteBuffer.allocateDirect(TEXTURES.length * BYTES_PER_FLOAT)
111 .order(ByteOrder.nativeOrder())
112 .asFloatBuffer();
113 mTextureBuffer.put(TEXTURES);
114 mTextureBuffer.position(0);
115 }
116
Ahan Wu48ebbd72019-03-12 20:59:13 +0800117 void setup(Bitmap bitmap) {
Ahan Wu67e7f102019-01-14 20:38:14 +0800118 setupAttributes();
119 setupUniforms();
Ahan Wu48ebbd72019-03-12 20:59:13 +0800120 setupTexture(bitmap);
Ahan Wu67e7f102019-01-14 20:38:14 +0800121 }
122
123 private void setupAttributes() {
124 mAttrPosition = mProgram.getAttributeHandle(A_POSITION);
125 mVertexBuffer.position(0);
126 glVertexAttribPointer(mAttrPosition, POSITION_COMPONENT_COUNT, GL_FLOAT,
127 false, 0, mVertexBuffer);
128 glEnableVertexAttribArray(mAttrPosition);
129
130 mAttrTextureCoordinates = mProgram.getAttributeHandle(A_TEXTURE_COORDINATES);
131 mTextureBuffer.position(0);
132 glVertexAttribPointer(mAttrTextureCoordinates, TEXTURE_COMPONENT_COUNT, GL_FLOAT,
133 false, 0, mTextureBuffer);
134 glEnableVertexAttribArray(mAttrTextureCoordinates);
135 }
136
137 private void setupUniforms() {
138 mUniAod2Opacity = mProgram.getUniformHandle(U_AOD2OPACITY);
Ahan Wu4c9a5502019-03-04 15:35:28 +0800139 mUniPer85 = mProgram.getUniformHandle(U_PER85);
Ahan Wu67e7f102019-01-14 20:38:14 +0800140 mUniReveal = mProgram.getUniformHandle(U_REVEAL);
141 mUniTexture = mProgram.getUniformHandle(U_TEXTURE);
142 }
143
144 int getHandle(String name) {
145 switch (name) {
146 case A_POSITION:
147 return mAttrPosition;
148 case A_TEXTURE_COORDINATES:
149 return mAttrTextureCoordinates;
150 case U_AOD2OPACITY:
151 return mUniAod2Opacity;
Ahan Wu4c9a5502019-03-04 15:35:28 +0800152 case U_PER85:
153 return mUniPer85;
Ahan Wu67e7f102019-01-14 20:38:14 +0800154 case U_REVEAL:
155 return mUniReveal;
156 case U_TEXTURE:
157 return mUniTexture;
158 default:
159 return HANDLE_UNDEFINED;
160 }
161 }
162
163 void draw() {
164 glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
165 }
166
Ahan Wu48ebbd72019-03-12 20:59:13 +0800167 private void setupTexture(Bitmap bitmap) {
Ahan Wu67e7f102019-01-14 20:38:14 +0800168 final int[] tids = new int[1];
169
170 if (bitmap == null) {
171 Log.w(TAG, "setupTexture: invalid bitmap");
172 return;
173 }
174
175 // Generate one texture object and store the id in tids[0].
176 glGenTextures(1, tids, 0);
177 if (tids[0] == 0) {
178 Log.w(TAG, "setupTexture: glGenTextures() failed");
179 return;
180 }
181
Ahan Wu48ebbd72019-03-12 20:59:13 +0800182 // Bind a named texture to a target.
Ahan Wu67e7f102019-01-14 20:38:14 +0800183 glBindTexture(GL_TEXTURE_2D, tids[0]);
184 // Load the bitmap data and copy it over into the texture object that is currently bound.
185 GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
186 // Use bilinear texture filtering when minification.
187 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
188 // Use bilinear texture filtering when magnification.
189 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
190
191 mTextureId = tids[0];
192 }
193
194 void useTexture() {
195 // Set the active texture unit to texture unit 0.
196 glActiveTexture(GL_TEXTURE0);
197 // Bind the texture to this unit.
198 glBindTexture(GL_TEXTURE_2D, mTextureId);
199 // Let the texture sampler in fragment shader to read form this texture unit.
200 glUniform1i(mUniTexture, 0);
201 }
202
Ahan Wue16e1fa2019-05-29 18:39:33 +0800203 /**
204 * This method adjust s(x-axis), t(y-axis) texture coordinates to get current display area
205 * of texture and will be used during transition.
206 * The adjustment happens if either the width or height of the surface is larger than
207 * corresponding size of the display area.
208 * If both width and height are larger than corresponding size of the display area,
209 * the adjustment will happen at both s, t side.
210 *
211 * @param surface The size of the surface.
212 * @param scissor The display area.
213 * @param xOffset The offset amount along s axis.
214 * @param yOffset The offset amount along t axis.
215 */
216 void adjustTextureCoordinates(Rect surface, Rect scissor, float xOffset, float yOffset) {
217 mCurrentTexCoordinate = TEXTURES.clone();
218
219 if (surface == null || scissor == null) {
220 mTextureBuffer.put(mCurrentTexCoordinate);
221 mTextureBuffer.position(0);
222 return;
223 }
224
225 int surfaceWidth = surface.width();
226 int surfaceHeight = surface.height();
227 int scissorWidth = scissor.width();
228 int scissorHeight = scissor.height();
229
230 if (surfaceWidth > scissorWidth) {
231 // Calculate the new s pos in pixels.
232 float pixelS = (float) Math.round((surfaceWidth - scissorWidth) * xOffset);
233 // Calculate the s pos in texture coordinate.
234 float coordinateS = pixelS / surfaceWidth;
235 // Calculate the percentage occupied by the scissor width in surface width.
236 float surfacePercentageW = (float) scissorWidth / surfaceWidth;
237 // Need also consider the case if surface height is smaller than scissor height.
238 if (surfaceHeight < scissorHeight) {
239 // We will narrow the surface percentage to keep aspect ratio.
240 surfacePercentageW *= (float) surfaceHeight / scissorHeight;
241 }
242 // Determine the final s pos, also limit the legal s pos to prevent from out of range.
243 float s = coordinateS + surfacePercentageW > 1f ? 1f - surfacePercentageW : coordinateS;
244 // Traverse the s pos in texture coordinates array and adjust the s pos accordingly.
245 for (int i = 0; i < mCurrentTexCoordinate.length; i += 2) {
246 // indices 2, 4 and 6 are the end of s coordinates.
247 if (i == 2 || i == 4 || i == 6) {
248 mCurrentTexCoordinate[i] = Math.min(1f, s + surfacePercentageW);
249 } else {
250 mCurrentTexCoordinate[i] = s;
251 }
252 }
253 }
254
255 if (surfaceHeight > scissorHeight) {
256 // Calculate the new t pos in pixels.
257 float pixelT = (float) Math.round((surfaceHeight - scissorHeight) * yOffset);
258 // Calculate the t pos in texture coordinate.
259 float coordinateT = pixelT / surfaceHeight;
260 // Calculate the percentage occupied by the scissor height in surface height.
261 float surfacePercentageH = (float) scissorHeight / surfaceHeight;
262 // Need also consider the case if surface width is smaller than scissor width.
263 if (surfaceWidth < scissorWidth) {
264 // We will narrow the surface percentage to keep aspect ratio.
265 surfacePercentageH *= (float) surfaceWidth / scissorWidth;
266 }
267 // Determine the final t pos, also limit the legal t pos to prevent from out of range.
268 float t = coordinateT + surfacePercentageH > 1f ? 1f - surfacePercentageH : coordinateT;
269 // Traverse the t pos in texture coordinates array and adjust the t pos accordingly.
270 for (int i = 1; i < mCurrentTexCoordinate.length; i += 2) {
271 // indices 1, 3 and 11 are the end of t coordinates.
272 if (i == 1 || i == 3 || i == 11) {
273 mCurrentTexCoordinate[i] = Math.min(1f, t + surfacePercentageH);
274 } else {
275 mCurrentTexCoordinate[i] = t;
276 }
277 }
278 }
279
280 mTextureBuffer.put(mCurrentTexCoordinate);
281 mTextureBuffer.position(0);
282 }
283
284 /**
285 * Called to dump current state.
286 * @param prefix prefix.
287 * @param fd fd.
288 * @param out out.
289 * @param args args.
290 */
291 public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
292 StringBuilder sb = new StringBuilder();
293 sb.append('{');
294 if (mCurrentTexCoordinate != null) {
295 for (int i = 0; i < mCurrentTexCoordinate.length; i++) {
296 sb.append(mCurrentTexCoordinate[i]).append(',');
297 if (i == mCurrentTexCoordinate.length - 1) {
298 sb.deleteCharAt(sb.length() - 1);
299 }
300 }
301 }
302 sb.append('}');
303 out.print(prefix); out.print("mTexCoordinates="); out.println(sb.toString());
304 }
Ahan Wu67e7f102019-01-14 20:38:14 +0800305}