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