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 <utils/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 ALOGE("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 ALOGE("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("com/android/cts/opengl/reference/GLGameActivity");
63 if (activityClass == NULL) {
64 ALOGE("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 ALOGE("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 ALOGE("Error compiling shader:\n%s\n", infoLog);
145 free(infoLog);
146 }
147 glDeleteShader(shader);
148 shader = 0;
149 }
150 }
151 return shader;
152 }
153
createProgram(const char ** vertexSource,const char ** fragmentSource)154 GLuint GLUtils::createProgram(const char** vertexSource, const char** fragmentSource) {
155 GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
156 if (!vertexShader) {
157 return 0;
158 }
159
160 GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
161 if (!fragmentShader) {
162 return 0;
163 }
164
165 GLuint program = glCreateProgram();
166 if (program) {
167 glAttachShader(program, vertexShader);
168 glAttachShader(program, fragmentShader);
169
170 GLint linkStatus;
171 glLinkProgram(program);
172 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
173
174 if (!linkStatus) {
175 GLint infoLen = 0;
176 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
177 if (infoLen > 0) {
178 char* infoLog = (char*) malloc(sizeof(char) * infoLen);
179 glGetProgramInfoLog(program, infoLen, NULL, infoLog);
180 ALOGE("Error linking program:\n%s\n", infoLog);
181 free(infoLog);
182 }
183 glDeleteProgram(program);
184 program = 0;
185 }
186 }
187 return program;
188 }
189
currentTimeMillis()190 double GLUtils::currentTimeMillis() {
191 struct timeval tv;
192 gettimeofday(&tv, (struct timezone *) NULL);
193 return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
194 }
195
196 // Rounds a number up to the smallest power of 2 that is greater than or equal to x.
roundUpToSmallestPowerOf2(int x)197 int GLUtils::roundUpToSmallestPowerOf2(int x) {
198 if (x < 0) {
199 return 0;
200 }
201 --x;
202 x |= x >> 1;
203 x |= x >> 2;
204 x |= x >> 4;
205 x |= x >> 8;
206 x |= x >> 16;
207 return x + 1;
208 }
209
genTexture(int texWidth,int texHeight,int fill)210 GLuint GLUtils::genTexture(int texWidth, int texHeight, int fill) {
211 GLuint textureId = 0;
212 int w = roundUpToSmallestPowerOf2(texWidth);
213 int h = roundUpToSmallestPowerOf2(texHeight);
214 uint32_t* m = new uint32_t[w * h];
215 if (m != NULL) {
216 uint32_t* d = m;
217 for (int y = 0; y < h; y++) {
218 for (int x = 0; x < w; x++) {
219 if (fill == RANDOM_FILL) {
220 *d = 0xff000000 | ((y & 0xff) << 16) | ((x & 0xff) << 8) | ((x + y) & 0xff);
221 } else {
222 *d = 0xff000000 | fill;
223 }
224 d++;
225 }
226 }
227 glGenTextures(1, &textureId);
228 glBindTexture(GL_TEXTURE_2D, textureId);
229 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
234 }
235 delete[] m;
236 return textureId;
237 }
238