/* * 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 #include #include #define LOG_TAG "CTS_OPENGL" #define LOG_NDEBUG 0 #include 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) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "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) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "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("android/opengl2/cts/reference/GLGameActivity"); if (activityClass == NULL) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Couldn't find activity class"); return -1; } jmethodID loadTexture = sEnv->GetStaticMethodID(activityClass, "loadTexture", "(Landroid/content/res/AssetManager;Ljava/lang/String;)I"); if (loadTexture == NULL) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "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) { unsigned char* ub = (unsigned char*) b; return (((int) ub[0]) << 24) | (((int) ub[1]) << 16) | (((int) ub[2]) << 8) | ((int) ub[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); __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "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); __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "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 or equal to x. 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; }