1 /*
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 
17 package com.android.systemui.glwallpaper;
18 
19 import static android.opengl.GLES20.GL_FLOAT;
20 import static android.opengl.GLES20.GL_LINEAR;
21 import static android.opengl.GLES20.GL_TEXTURE0;
22 import static android.opengl.GLES20.GL_TEXTURE_2D;
23 import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
24 import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
25 import static android.opengl.GLES20.GL_TRIANGLES;
26 import static android.opengl.GLES20.glActiveTexture;
27 import static android.opengl.GLES20.glBindTexture;
28 import static android.opengl.GLES20.glDrawArrays;
29 import static android.opengl.GLES20.glEnableVertexAttribArray;
30 import static android.opengl.GLES20.glGenTextures;
31 import static android.opengl.GLES20.glTexParameteri;
32 import static android.opengl.GLES20.glUniform1i;
33 import static android.opengl.GLES20.glVertexAttribPointer;
34 
35 import android.graphics.Bitmap;
36 import android.opengl.GLUtils;
37 import android.util.Log;
38 
39 import java.io.FileDescriptor;
40 import java.io.PrintWriter;
41 import java.nio.ByteBuffer;
42 import java.nio.ByteOrder;
43 import java.nio.FloatBuffer;
44 
45 /**
46  * This class takes charge of the geometry data like vertices and texture coordinates.
47  * It delivers these data to opengl runtime and triggers draw calls if necessary.
48  */
49 class ImageGLWallpaper {
50     private static final String TAG = ImageGLWallpaper.class.getSimpleName();
51 
52     private static final String A_POSITION = "aPosition";
53     private static final String A_TEXTURE_COORDINATES = "aTextureCoordinates";
54     private static final String U_TEXTURE = "uTexture";
55     private static final int POSITION_COMPONENT_COUNT = 2;
56     private static final int TEXTURE_COMPONENT_COUNT = 2;
57     private static final int BYTES_PER_FLOAT = 4;
58 
59     // Vertices to define the square with 2 triangles.
60     private static final float[] VERTICES = {
61             -1.0f,  -1.0f,
62             +1.0f,  -1.0f,
63             +1.0f,  +1.0f,
64             +1.0f,  +1.0f,
65             -1.0f,  +1.0f,
66             -1.0f,  -1.0f
67     };
68 
69     // Texture coordinates that maps to vertices.
70     private static final float[] TEXTURES = {
71             0f, 1f,
72             1f, 1f,
73             1f, 0f,
74             1f, 0f,
75             0f, 0f,
76             0f, 1f
77     };
78 
79     private final FloatBuffer mVertexBuffer;
80     private final FloatBuffer mTextureBuffer;
81     private final ImageGLProgram mProgram;
82 
83     private int mAttrPosition;
84     private int mAttrTextureCoordinates;
85     private int mUniTexture;
86     private int mTextureId;
87 
ImageGLWallpaper(ImageGLProgram program)88     ImageGLWallpaper(ImageGLProgram program) {
89         mProgram = program;
90 
91         // Create an float array in opengles runtime (native) and put vertex data.
92         mVertexBuffer = ByteBuffer.allocateDirect(VERTICES.length * BYTES_PER_FLOAT)
93             .order(ByteOrder.nativeOrder())
94             .asFloatBuffer();
95         mVertexBuffer.put(VERTICES);
96         mVertexBuffer.position(0);
97 
98         // Create an float array in opengles runtime (native) and put texture data.
99         mTextureBuffer = ByteBuffer.allocateDirect(TEXTURES.length * BYTES_PER_FLOAT)
100             .order(ByteOrder.nativeOrder())
101             .asFloatBuffer();
102         mTextureBuffer.put(TEXTURES);
103         mTextureBuffer.position(0);
104     }
105 
setup(Bitmap bitmap)106     void setup(Bitmap bitmap) {
107         setupAttributes();
108         setupUniforms();
109         setupTexture(bitmap);
110     }
111 
setupAttributes()112     private void setupAttributes() {
113         mAttrPosition = mProgram.getAttributeHandle(A_POSITION);
114         mVertexBuffer.position(0);
115         glVertexAttribPointer(mAttrPosition, POSITION_COMPONENT_COUNT, GL_FLOAT,
116                 false, 0, mVertexBuffer);
117         glEnableVertexAttribArray(mAttrPosition);
118 
119         mAttrTextureCoordinates = mProgram.getAttributeHandle(A_TEXTURE_COORDINATES);
120         mTextureBuffer.position(0);
121         glVertexAttribPointer(mAttrTextureCoordinates, TEXTURE_COMPONENT_COUNT, GL_FLOAT,
122                 false, 0, mTextureBuffer);
123         glEnableVertexAttribArray(mAttrTextureCoordinates);
124     }
125 
setupUniforms()126     private void setupUniforms() {
127         mUniTexture = mProgram.getUniformHandle(U_TEXTURE);
128     }
129 
draw()130     void draw() {
131         glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
132     }
133 
setupTexture(Bitmap bitmap)134     private void setupTexture(Bitmap bitmap) {
135         final int[] tids = new int[1];
136 
137         if (bitmap == null || bitmap.isRecycled()) {
138             Log.w(TAG, "setupTexture: invalid bitmap");
139             return;
140         }
141 
142         // Generate one texture object and store the id in tids[0].
143         glGenTextures(1, tids, 0);
144         if (tids[0] == 0) {
145             Log.w(TAG, "setupTexture: glGenTextures() failed");
146             return;
147         }
148 
149         try {
150             // Bind a named texture to a target.
151             glBindTexture(GL_TEXTURE_2D, tids[0]);
152             // Load the bitmap data and copy it over into the texture object
153             // that is currently bound.
154             GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
155             // Use bilinear texture filtering when minification.
156             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
157             // Use bilinear texture filtering when magnification.
158             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
159             mTextureId = tids[0];
160         } catch (IllegalArgumentException e) {
161             Log.w(TAG, "Failed uploading texture: " + e.getLocalizedMessage());
162         }
163     }
164 
useTexture()165     void useTexture() {
166         // Set the active texture unit to texture unit 0.
167         glActiveTexture(GL_TEXTURE0);
168         // Bind the texture to this unit.
169         glBindTexture(GL_TEXTURE_2D, mTextureId);
170         // Let the texture sampler in fragment shader to read form this texture unit.
171         glUniform1i(mUniTexture, 0);
172     }
173 
174     /**
175      * Called to dump current state.
176      * @param prefix prefix.
177      * @param fd fd.
178      * @param out out.
179      * @param args args.
180      */
dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args)181     public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
182     }
183 }
184