blob: 19d85b155cbace479e4b5d7d8f6c014da8bf68cc [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;
36import android.opengl.GLUtils;
37import android.os.Build;
38import android.util.Log;
39
40import java.nio.ByteBuffer;
41import java.nio.ByteOrder;
42import java.nio.FloatBuffer;
43
44/**
45 * This class takes charge of the geometry data like vertices and texture coordinates.
46 * It delivers these data to opengl runtime and triggers draw calls if necessary.
47 */
48class ImageGLWallpaper {
49 private static final String TAG = ImageGLWallpaper.class.getSimpleName();
50
51 static final String A_POSITION = "aPosition";
52 static final String A_TEXTURE_COORDINATES = "aTextureCoordinates";
53 static final String U_CENTER_REVEAL = "uCenterReveal";
54 static final String U_REVEAL = "uReveal";
55 static final String U_AOD2OPACITY = "uAod2Opacity";
56 static final String U_TEXTURE = "uTexture";
57
58 private static final int HANDLE_UNDEFINED = -1;
59 private static final int POSITION_COMPONENT_COUNT = 2;
60 private static final int TEXTURE_COMPONENT_COUNT = 2;
61 private static final int BYTES_PER_FLOAT = 4;
62
63 // Vertices to define the square with 2 triangles.
64 private static final float[] VERTICES = {
65 -1.0f, -1.0f,
66 +1.0f, -1.0f,
67 +1.0f, +1.0f,
68 +1.0f, +1.0f,
69 -1.0f, +1.0f,
70 -1.0f, -1.0f
71 };
72
73 // Texture coordinates that maps to vertices.
74 private static final float[] TEXTURES = {
75 0f, 1f,
76 1f, 1f,
77 1f, 0f,
78 1f, 0f,
79 0f, 0f,
80 0f, 1f
81 };
82
83 private final FloatBuffer mVertexBuffer;
84 private final FloatBuffer mTextureBuffer;
85 private final ImageGLProgram mProgram;
86
87 private int mAttrPosition;
88 private int mAttrTextureCoordinates;
89 private int mUniAod2Opacity;
90 private int mUniCenterReveal;
91 private int mUniReveal;
92 private int mUniTexture;
93 private int mTextureId;
94
95 ImageGLWallpaper(ImageGLProgram program) {
96 mProgram = program;
97
98 // Create an float array in opengles runtime (native) and put vertex data.
99 mVertexBuffer = ByteBuffer.allocateDirect(VERTICES.length * BYTES_PER_FLOAT)
100 .order(ByteOrder.nativeOrder())
101 .asFloatBuffer();
102 mVertexBuffer.put(VERTICES);
103 mVertexBuffer.position(0);
104
105 // Create an float array in opengles runtime (native) and put texture data.
106 mTextureBuffer = ByteBuffer.allocateDirect(TEXTURES.length * BYTES_PER_FLOAT)
107 .order(ByteOrder.nativeOrder())
108 .asFloatBuffer();
109 mTextureBuffer.put(TEXTURES);
110 mTextureBuffer.position(0);
111 }
112
113 void setup() {
114 setupAttributes();
115 setupUniforms();
116 }
117
118 private void setupAttributes() {
119 mAttrPosition = mProgram.getAttributeHandle(A_POSITION);
120 mVertexBuffer.position(0);
121 glVertexAttribPointer(mAttrPosition, POSITION_COMPONENT_COUNT, GL_FLOAT,
122 false, 0, mVertexBuffer);
123 glEnableVertexAttribArray(mAttrPosition);
124
125 mAttrTextureCoordinates = mProgram.getAttributeHandle(A_TEXTURE_COORDINATES);
126 mTextureBuffer.position(0);
127 glVertexAttribPointer(mAttrTextureCoordinates, TEXTURE_COMPONENT_COUNT, GL_FLOAT,
128 false, 0, mTextureBuffer);
129 glEnableVertexAttribArray(mAttrTextureCoordinates);
130 }
131
132 private void setupUniforms() {
133 mUniAod2Opacity = mProgram.getUniformHandle(U_AOD2OPACITY);
134 mUniCenterReveal = mProgram.getUniformHandle(U_CENTER_REVEAL);
135 mUniReveal = mProgram.getUniformHandle(U_REVEAL);
136 mUniTexture = mProgram.getUniformHandle(U_TEXTURE);
137 }
138
139 int getHandle(String name) {
140 switch (name) {
141 case A_POSITION:
142 return mAttrPosition;
143 case A_TEXTURE_COORDINATES:
144 return mAttrTextureCoordinates;
145 case U_AOD2OPACITY:
146 return mUniAod2Opacity;
147 case U_CENTER_REVEAL:
148 return mUniCenterReveal;
149 case U_REVEAL:
150 return mUniReveal;
151 case U_TEXTURE:
152 return mUniTexture;
153 default:
154 return HANDLE_UNDEFINED;
155 }
156 }
157
158 void draw() {
159 glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
160 }
161
162 void setupTexture(Bitmap bitmap) {
163 final int[] tids = new int[1];
164
165 if (bitmap == null) {
166 Log.w(TAG, "setupTexture: invalid bitmap");
167 return;
168 }
169
170 // Generate one texture object and store the id in tids[0].
171 glGenTextures(1, tids, 0);
172 if (tids[0] == 0) {
173 Log.w(TAG, "setupTexture: glGenTextures() failed");
174 return;
175 }
176
177 // Bind a named texture to a texturing target.
178 glBindTexture(GL_TEXTURE_2D, tids[0]);
179 // Load the bitmap data and copy it over into the texture object that is currently bound.
180 GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
181 // Use bilinear texture filtering when minification.
182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
183 // Use bilinear texture filtering when magnification.
184 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
185
186 mTextureId = tids[0];
187 }
188
189 void useTexture() {
190 // Set the active texture unit to texture unit 0.
191 glActiveTexture(GL_TEXTURE0);
192 // Bind the texture to this unit.
193 glBindTexture(GL_TEXTURE_2D, mTextureId);
194 // Let the texture sampler in fragment shader to read form this texture unit.
195 glUniform1i(mUniTexture, 0);
196 }
197
198 void adjustTextureCoordinates(Bitmap bitmap, int surfaceWidth, int surfaceHeight,
199 float xOffset, float yOffset) {
200 if (bitmap == null) {
201 Log.d(TAG, "adjustTextureCoordinates: invalid bitmap");
202 return;
203 }
204
205 int bitmapWidth = bitmap.getWidth();
206 int bitmapHeight = bitmap.getHeight();
207 float ratioW = 1f;
208 float ratioH = 1f;
209 float rX = 0f;
210 float rY = 0f;
211 float[] coordinates = null;
212
213 final boolean adjustWidth = bitmapWidth > surfaceWidth;
214 final boolean adjustHeight = bitmapHeight > surfaceHeight;
215
216 if (adjustWidth || adjustHeight) {
217 coordinates = TEXTURES.clone();
218 }
219
220 if (adjustWidth) {
221 float x = (float) Math.round((bitmapWidth - surfaceWidth) * xOffset) / bitmapWidth;
222 ratioW = (float) surfaceWidth / bitmapWidth;
223 float referenceX = x + ratioW > 1f ? 1f - ratioW : x;
224 for (int i = 0; i < coordinates.length; i += 2) {
225 if (i == 2 || i == 4 || i == 6) {
226 coordinates[i] = Math.min(1f, referenceX + ratioW);
227 } else {
228 coordinates[i] = referenceX;
229 }
230 }
231 rX = referenceX;
232 }
233
234
235 if (adjustHeight) {
236 float y = (float) Math.round((bitmapHeight - surfaceHeight) * yOffset) / bitmapHeight;
237 ratioH = (float) surfaceHeight / bitmapHeight;
238 float referenceY = y + ratioH > 1f ? 1f - ratioH : y;
239 for (int i = 1; i < coordinates.length; i += 2) {
240 if (i == 1 || i == 3 || i == 11) {
241 coordinates[i] = Math.min(1f, referenceY + ratioH);
242 } else {
243 coordinates[i] = referenceY;
244 }
245 }
246 rY = referenceY;
247 }
248
249 if (adjustWidth || adjustHeight) {
250 if (Build.IS_DEBUGGABLE) {
251 Log.d(TAG, "adjustTextureCoordinates: sW=" + surfaceWidth + ", sH=" + surfaceHeight
252 + ", bW=" + bitmapWidth + ", bH=" + bitmapHeight
253 + ", rW=" + ratioW + ", rH=" + ratioH + ", rX=" + rX + ", rY=" + rY);
254 }
255 mTextureBuffer.put(coordinates);
256 mTextureBuffer.position(0);
257 }
258 }
259}