| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
| * in compliance with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| |
| #include "GLUtils.h" |
| #include <stdlib.h> |
| #include <sys/time.h> |
| |
| #include <android/asset_manager_jni.h> |
| |
| #define LOG_TAG "PTS_OPENGL" |
| #define LOG_NDEBUG 0 |
| #include <utils/Log.h> |
| |
| static JNIEnv* sEnv = NULL; |
| static jobject sAssetManager = NULL; |
| |
| void GLUtils::setEnvAndAssetManager(JNIEnv* env, jobject assetManager) { |
| sEnv = env; |
| sAssetManager = assetManager; |
| } |
| |
| static AAsset* loadAsset(const char* path) { |
| AAssetManager* nativeManager = AAssetManager_fromJava(sEnv, sAssetManager); |
| if (nativeManager == NULL) { |
| return NULL; |
| } |
| return AAssetManager_open(nativeManager, path, AASSET_MODE_UNKNOWN);; |
| } |
| |
| char* GLUtils::openTextFile(const char* path) { |
| AAsset* asset = loadAsset(path); |
| if (asset == NULL) { |
| ALOGE("Couldn't load %s", path); |
| return NULL; |
| } |
| off_t length = AAsset_getLength(asset); |
| char* buffer = new char[length + 1]; |
| int num = AAsset_read(asset, buffer, length); |
| AAsset_close(asset); |
| if (num != length) { |
| ALOGE("Couldn't read %s", path); |
| delete[] buffer; |
| return NULL; |
| } |
| buffer[length] = '\0'; |
| return buffer; |
| } |
| |
| GLuint GLUtils::loadTexture(const char* path) { |
| GLuint textureId = 0; |
| jclass activityClass = sEnv->FindClass("com/android/pts/opengl/reference/GLGameActivity"); |
| if (activityClass == NULL) { |
| ALOGE("Couldn't find activity class"); |
| return -1; |
| } |
| jmethodID loadTexture = sEnv->GetStaticMethodID(activityClass, "loadTexture", |
| "(Landroid/content/res/AssetManager;Ljava/lang/String;)I"); |
| if (loadTexture == NULL) { |
| ALOGE("Couldn't find loadTexture method"); |
| return -1; |
| } |
| jstring pathStr = sEnv->NewStringUTF(path); |
| textureId = sEnv->CallStaticIntMethod(activityClass, loadTexture, sAssetManager, pathStr); |
| sEnv->DeleteLocalRef(pathStr); |
| return textureId; |
| } |
| |
| static int readInt(char* b) { |
| return (((int) b[0]) << 24) | (((int) b[1]) << 16) | (((int) b[2]) << 8) | ((int) b[3]); |
| } |
| |
| static float readFloat(char* b) { |
| union { |
| int input; |
| float output; |
| } data; |
| data.input = readInt(b); |
| return data.output; |
| } |
| |
| Mesh* GLUtils::loadMesh(const char* path) { |
| char* buffer = openTextFile(path); |
| if (buffer == NULL) { |
| return NULL; |
| } |
| int index = 0; |
| int numVertices = readInt(buffer + index); |
| index += 4; |
| float* vertices = new float[numVertices * 3]; |
| float* normals = new float[numVertices * 3]; |
| float* texCoords = new float[numVertices * 2]; |
| for (int i = 0; i < numVertices; i++) { |
| // Vertices |
| int vIndex = i * 3; |
| vertices[vIndex + 0] = readFloat(buffer + index); |
| index += 4; |
| vertices[vIndex + 1] = readFloat(buffer + index); |
| index += 4; |
| vertices[vIndex + 2] = readFloat(buffer + index); |
| index += 4; |
| // Normals |
| normals[vIndex + 0] = readFloat(buffer + index); |
| index += 4; |
| normals[vIndex + 1] = readFloat(buffer + index); |
| index += 4; |
| normals[vIndex + 2] = readFloat(buffer + index); |
| index += 4; |
| // Texture Coordinates |
| int tIndex = i * 2; |
| texCoords[tIndex + 0] = readFloat(buffer + index); |
| index += 4; |
| texCoords[tIndex + 1] = readFloat(buffer + index); |
| index += 4; |
| } |
| return new Mesh(vertices, normals, texCoords, numVertices); |
| } |
| |
| // Loads the given source code as a shader of the given type. |
| static GLuint loadShader(GLenum shaderType, const char** source) { |
| GLuint shader = glCreateShader(shaderType); |
| if (shader) { |
| glShaderSource(shader, 1, source, NULL); |
| glCompileShader(shader); |
| GLint compiled = 0; |
| glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); |
| if (!compiled) { |
| GLint infoLen = 0; |
| glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); |
| if (infoLen > 0) { |
| char* infoLog = (char*) malloc(sizeof(char) * infoLen); |
| glGetShaderInfoLog(shader, infoLen, NULL, infoLog); |
| ALOGE("Error compiling shader:\n%s\n", infoLog); |
| free(infoLog); |
| } |
| glDeleteShader(shader); |
| shader = 0; |
| } |
| } |
| return shader; |
| } |
| |
| GLuint GLUtils::createProgram(const char** vertexSource, const char** fragmentSource) { |
| GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource); |
| if (!vertexShader) { |
| return 0; |
| } |
| |
| GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource); |
| if (!fragmentShader) { |
| return 0; |
| } |
| |
| GLuint program = glCreateProgram(); |
| if (program) { |
| glAttachShader(program, vertexShader); |
| glAttachShader(program, fragmentShader); |
| |
| GLint linkStatus; |
| glLinkProgram(program); |
| glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); |
| |
| if (!linkStatus) { |
| GLint infoLen = 0; |
| glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen); |
| if (infoLen > 0) { |
| char* infoLog = (char*) malloc(sizeof(char) * infoLen); |
| glGetProgramInfoLog(program, infoLen, NULL, infoLog); |
| ALOGE("Error linking program:\n%s\n", infoLog); |
| free(infoLog); |
| } |
| glDeleteProgram(program); |
| program = 0; |
| } |
| } |
| return program; |
| } |
| |
| double GLUtils::currentTimeMillis() { |
| struct timeval tv; |
| gettimeofday(&tv, (struct timezone *) NULL); |
| return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0; |
| } |
| |
| // Rounds a number up to the smallest power of 2 that is greater than the original number. |
| int GLUtils::roundUpToSmallestPowerOf2(int x) { |
| if (x < 0) { |
| return 0; |
| } |
| --x; |
| x |= x >> 1; |
| x |= x >> 2; |
| x |= x >> 4; |
| x |= x >> 8; |
| x |= x >> 16; |
| return x + 1; |
| } |
| |
| GLuint GLUtils::genTexture(int texWidth, int texHeight, int fill) { |
| GLuint textureId = 0; |
| int w = roundUpToSmallestPowerOf2(texWidth); |
| int h = roundUpToSmallestPowerOf2(texHeight); |
| uint32_t* m = new uint32_t[w * h]; |
| if (m != NULL) { |
| uint32_t* d = m; |
| for (int y = 0; y < h; y++) { |
| for (int x = 0; x < w; x++) { |
| if (fill == RANDOM_FILL) { |
| *d = 0xff000000 | ((y & 0xff) << 16) | ((x & 0xff) << 8) | ((x + y) & 0xff); |
| } else { |
| *d = 0xff000000 | fill; |
| } |
| d++; |
| } |
| } |
| glGenTextures(1, &textureId); |
| glBindTexture(GL_TEXTURE_2D, textureId); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); |
| } |
| delete[] m; |
| return textureId; |
| } |
| |
| bool GLUtils::createFBO(GLuint& fboId, GLuint& rboId, GLuint& cboId, int width, int height) { |
| glGenFramebuffers(1, &fboId); |
| glBindFramebuffer(GL_FRAMEBUFFER, fboId); |
| |
| glGenRenderbuffers(1, &rboId); |
| glBindRenderbuffer(GL_RENDERBUFFER, rboId); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); |
| glBindRenderbuffer(GL_RENDERBUFFER, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId); |
| |
| glGenRenderbuffers(1, &cboId); |
| glBindRenderbuffer(GL_RENDERBUFFER, cboId); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, width, height); |
| glBindRenderbuffer(GL_RENDERBUFFER, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cboId); |
| |
| GLuint err = glGetError(); |
| if (err != GL_NO_ERROR) { |
| ALOGE("GLError %d", err); |
| return false; |
| } |
| |
| return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE; |
| } |