Home | History | Annotate | Download | only in graphics
      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 
     28 void GLUtils::setEnvAndAssetManager(JNIEnv* env, jobject assetManager) {
     29     sEnv = env;
     30     sAssetManager = assetManager;
     31 }
     32 
     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 
     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 
     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 
     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 
     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 
     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.
    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 
    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 
    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.
    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 
    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