1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 #include "GLUtils.h"
16 #include <stdlib.h>
17 #include <sys/time.h>
18 
19 #include <android/asset_manager_jni.h>
20 
21 #define LOG_TAG "CTS_OPENGL"
22 #define LOG_NDEBUG 0
23 #include <android/log.h>
24 
25 static JNIEnv* sEnv = NULL;
26 static jobject sAssetManager = NULL;
27 
setEnvAndAssetManager(JNIEnv * env,jobject assetManager)28 void GLUtils::setEnvAndAssetManager(JNIEnv* env, jobject assetManager) {
29     sEnv = env;
30     sAssetManager = assetManager;
31 }
32 
loadAsset(const char * path)33 static AAsset* loadAsset(const char* path) {
34     AAssetManager* nativeManager = AAssetManager_fromJava(sEnv, sAssetManager);
35     if (nativeManager == NULL) {
36         return NULL;
37     }
38     return AAssetManager_open(nativeManager, path, AASSET_MODE_UNKNOWN);;
39 }
40 
openTextFile(const char * path)41 char* GLUtils::openTextFile(const char* path) {
42     AAsset* asset = loadAsset(path);
43     if (asset == NULL) {
44         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Couldn't load %s", path);
45         return NULL;
46     }
47     off_t length = AAsset_getLength(asset);
48     char* buffer = new char[length + 1];
49     int num = AAsset_read(asset, buffer, length);
50     AAsset_close(asset);
51     if (num != length) {
52         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Couldn't read %s", path);
53         delete[] buffer;
54         return NULL;
55     }
56     buffer[length] = '\0';
57     return buffer;
58 }
59 
loadTexture(const char * path)60 GLuint GLUtils::loadTexture(const char* path) {
61     GLuint textureId = 0;
62     jclass activityClass = sEnv->FindClass("android/opengl2/cts/reference/GLGameActivity");
63     if (activityClass == NULL) {
64         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Couldn't find activity class");
65         return -1;
66     }
67     jmethodID loadTexture = sEnv->GetStaticMethodID(activityClass, "loadTexture",
68             "(Landroid/content/res/AssetManager;Ljava/lang/String;)I");
69     if (loadTexture == NULL) {
70         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Couldn't find loadTexture method");
71         return -1;
72     }
73     jstring pathStr = sEnv->NewStringUTF(path);
74     textureId = sEnv->CallStaticIntMethod(activityClass, loadTexture, sAssetManager, pathStr);
75     sEnv->DeleteLocalRef(pathStr);
76     return textureId;
77 }
78 
readInt(char * b)79 static int readInt(char* b) {
80     unsigned char* ub = (unsigned char*) b;
81     return (((int) ub[0]) << 24) | (((int) ub[1]) << 16) | (((int) ub[2]) << 8) | ((int) ub[3]);
82 }
83 
readFloat(char * b)84 static float readFloat(char* b) {
85     union {
86         int input;
87         float output;
88     } data;
89     data.input = readInt(b);
90     return data.output;
91 }
92 
loadMesh(const char * path)93 Mesh* GLUtils::loadMesh(const char* path) {
94     char* buffer = openTextFile(path);
95     if (buffer == NULL) {
96         return NULL;
97     }
98     int index = 0;
99     int numVertices = readInt(buffer + index);
100     index += 4;
101     float* vertices = new float[numVertices * 3];
102     float* normals = new float[numVertices * 3];
103     float* texCoords = new float[numVertices * 2];
104     for (int i = 0; i < numVertices; i++) {
105         // Vertices
106         int vIndex = i * 3;
107         vertices[vIndex + 0] = readFloat(buffer + index);
108         index += 4;
109         vertices[vIndex + 1] = readFloat(buffer + index);
110         index += 4;
111         vertices[vIndex + 2] = readFloat(buffer + index);
112         index += 4;
113         // Normals
114         normals[vIndex + 0] = readFloat(buffer + index);
115         index += 4;
116         normals[vIndex + 1] = readFloat(buffer + index);
117         index += 4;
118         normals[vIndex + 2] = readFloat(buffer + index);
119         index += 4;
120         // Texture Coordinates
121         int tIndex = i * 2;
122         texCoords[tIndex + 0] = readFloat(buffer + index);
123         index += 4;
124         texCoords[tIndex + 1] = readFloat(buffer + index);
125         index += 4;
126     }
127     return new Mesh(vertices, normals, texCoords, numVertices);
128 }
129 
130 // Loads the given source code as a shader of the given type.
loadShader(GLenum shaderType,const char ** source)131 static GLuint loadShader(GLenum shaderType, const char** source) {
132     GLuint shader = glCreateShader(shaderType);
133     if (shader) {
134         glShaderSource(shader, 1, source, NULL);
135         glCompileShader(shader);
136         GLint compiled = 0;
137         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
138         if (!compiled) {
139             GLint infoLen = 0;
140             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
141             if (infoLen > 0) {
142                 char* infoLog = (char*) malloc(sizeof(char) * infoLen);
143                 glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
144                 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
145                                     "Error compiling shader:\n%s\n", infoLog);
146                 free(infoLog);
147             }
148             glDeleteShader(shader);
149             shader = 0;
150         }
151     }
152     return shader;
153 }
154 
createProgram(const char ** vertexSource,const char ** fragmentSource)155 GLuint GLUtils::createProgram(const char** vertexSource, const char** fragmentSource) {
156     GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
157     if (!vertexShader) {
158         return 0;
159     }
160 
161     GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
162     if (!fragmentShader) {
163         return 0;
164     }
165 
166     GLuint program = glCreateProgram();
167     if (program) {
168         glAttachShader(program, vertexShader);
169         glAttachShader(program, fragmentShader);
170 
171         GLint linkStatus;
172         glLinkProgram(program);
173         glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
174 
175         if (!linkStatus) {
176             GLint infoLen = 0;
177             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
178             if (infoLen > 0) {
179                 char* infoLog = (char*) malloc(sizeof(char) * infoLen);
180                 glGetProgramInfoLog(program, infoLen, NULL, infoLog);
181                 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
182                                     "Error linking program:\n%s\n", infoLog);
183                 free(infoLog);
184             }
185             glDeleteProgram(program);
186             program = 0;
187         }
188     }
189     return program;
190 }
191 
currentTimeMillis()192 double GLUtils::currentTimeMillis() {
193     struct timeval tv;
194     gettimeofday(&tv, (struct timezone *) NULL);
195     return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
196 }
197 
198 // Rounds a number up to the smallest power of 2 that is greater than or equal to x.
roundUpToSmallestPowerOf2(int x)199 int GLUtils::roundUpToSmallestPowerOf2(int x) {
200     if (x < 0) {
201         return 0;
202     }
203     --x;
204     x |= x >> 1;
205     x |= x >> 2;
206     x |= x >> 4;
207     x |= x >> 8;
208     x |= x >> 16;
209     return x + 1;
210 }
211 
genTexture(int texWidth,int texHeight,int fill)212 GLuint GLUtils::genTexture(int texWidth, int texHeight, int fill) {
213     GLuint textureId = 0;
214     int w = roundUpToSmallestPowerOf2(texWidth);
215     int h = roundUpToSmallestPowerOf2(texHeight);
216     uint32_t* m = new uint32_t[w * h];
217     if (m != NULL) {
218         uint32_t* d = m;
219         for (int y = 0; y < h; y++) {
220             for (int x = 0; x < w; x++) {
221                 if (fill == RANDOM_FILL) {
222                     *d = 0xff000000 | ((y & 0xff) << 16) | ((x & 0xff) << 8) | ((x + y) & 0xff);
223                 } else {
224                     *d = 0xff000000 | fill;
225                 }
226                 d++;
227             }
228         }
229         glGenTextures(1, &textureId);
230         glBindTexture(GL_TEXTURE_2D, textureId);
231         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
232         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
233         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
234         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
235         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
236     }
237     delete[] m;
238     return textureId;
239 }
240