1c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner/*
2c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * Copyright (C) 2009 The Android Open Source Project
3c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner *
4c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * Licensed under the Apache License, Version 2.0 (the "License");
5c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * you may not use this file except in compliance with the License.
6c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * You may obtain a copy of the License at
7c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner *
8c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner *      http://www.apache.org/licenses/LICENSE-2.0
9c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner *
10c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * Unless required by applicable law or agreed to in writing, software
11c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * distributed under the License is distributed on an "AS IS" BASIS,
12c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * See the License for the specific language governing permissions and
14c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner * limitations under the License.
15c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner */
16c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
17c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner// OpenGL ES 2.0 code
18c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
19c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#include <jni.h>
20c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#include <android/log.h>
21c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
22c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#include <GLES2/gl2.h>
23c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#include <GLES2/gl2ext.h>
24c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
25c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#include <stdio.h>
26c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#include <stdlib.h>
27c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#include <math.h>
28c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
29c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#define  LOG_TAG    "libgl2jni"
30c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
31c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
32c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
33c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turnerstatic void printGLString(const char *name, GLenum s) {
34c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    const char *v = (const char *) glGetString(s);
35c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    LOGI("GL %s = %s\n", name, v);
36c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner}
37c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
38c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turnerstatic void checkGlError(const char* op) {
39c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    for (GLint error = glGetError(); error; error
40c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            = glGetError()) {
41c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        LOGI("after %s() glError (0x%x)\n", op, error);
42c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    }
43c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner}
44c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
45c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turnerstatic const char gVertexShader[] =
46c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    "attribute vec4 vPosition;\n"
47c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    "void main() {\n"
48c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    "  gl_Position = vPosition;\n"
49c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    "}\n";
50c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
51c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turnerstatic const char gFragmentShader[] =
52c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    "precision mediump float;\n"
53c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    "void main() {\n"
54c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
55c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    "}\n";
56c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
57c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' TurnerGLuint loadShader(GLenum shaderType, const char* pSource) {
58c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    GLuint shader = glCreateShader(shaderType);
59c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    if (shader) {
60c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        glShaderSource(shader, 1, &pSource, NULL);
61c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        glCompileShader(shader);
62c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        GLint compiled = 0;
63c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
64c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        if (!compiled) {
65c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            GLint infoLen = 0;
66c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
67c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            if (infoLen) {
68c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                char* buf = (char*) malloc(infoLen);
69c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                if (buf) {
70c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
71c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                    LOGE("Could not compile shader %d:\n%s\n",
72c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                            shaderType, buf);
73c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                    free(buf);
74c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                }
75c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                glDeleteShader(shader);
76c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                shader = 0;
77c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            }
78c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        }
79c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    }
80c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    return shader;
81c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner}
82c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
83c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' TurnerGLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
84c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
85c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    if (!vertexShader) {
86c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        return 0;
87c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    }
88c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
89c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
90c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    if (!pixelShader) {
91c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        return 0;
92c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    }
93c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
94c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    GLuint program = glCreateProgram();
95c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    if (program) {
96c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        glAttachShader(program, vertexShader);
97c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        checkGlError("glAttachShader");
98c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        glAttachShader(program, pixelShader);
99c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        checkGlError("glAttachShader");
100c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        glLinkProgram(program);
101c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        GLint linkStatus = GL_FALSE;
102c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
103c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        if (linkStatus != GL_TRUE) {
104c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            GLint bufLength = 0;
105c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
106c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            if (bufLength) {
107c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                char* buf = (char*) malloc(bufLength);
108c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                if (buf) {
109c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                    glGetProgramInfoLog(program, bufLength, NULL, buf);
110c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                    LOGE("Could not link program:\n%s\n", buf);
111c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                    free(buf);
112c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner                }
113c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            }
114c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            glDeleteProgram(program);
115c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            program = 0;
116c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        }
117c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    }
118c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    return program;
119c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner}
120c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
121c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' TurnerGLuint gProgram;
122c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' TurnerGLuint gvPositionHandle;
123c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
124c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turnerbool setupGraphics(int w, int h) {
125c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    printGLString("Version", GL_VERSION);
126c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    printGLString("Vendor", GL_VENDOR);
127c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    printGLString("Renderer", GL_RENDERER);
128c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    printGLString("Extensions", GL_EXTENSIONS);
129c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
130c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    LOGI("setupGraphics(%d, %d)", w, h);
131c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    gProgram = createProgram(gVertexShader, gFragmentShader);
132c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    if (!gProgram) {
133c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        LOGE("Could not create program.");
134c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        return false;
135c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    }
136c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
137c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    checkGlError("glGetAttribLocation");
138c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    LOGI("glGetAttribLocation(\"vPosition\") = %d\n",
139c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner            gvPositionHandle);
140c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
141c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    glViewport(0, 0, w, h);
142c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    checkGlError("glViewport");
143c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    return true;
144c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner}
145c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
146c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turnerconst GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
147c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        0.5f, -0.5f };
148c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
149c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turnervoid renderFrame() {
150c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    static float grey;
151c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    grey += 0.01f;
152c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    if (grey > 1.0f) {
153c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner        grey = 0.0f;
154c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    }
155c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    glClearColor(grey, grey, grey, 1.0f);
156c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    checkGlError("glClearColor");
157c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
158c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    checkGlError("glClear");
159c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
160c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    glUseProgram(gProgram);
161c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    checkGlError("glUseProgram");
162c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
163c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
164c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    checkGlError("glVertexAttribPointer");
165c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    glEnableVertexAttribArray(gvPositionHandle);
166c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    checkGlError("glEnableVertexAttribArray");
167c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    glDrawArrays(GL_TRIANGLES, 0, 3);
168c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    checkGlError("glDrawArrays");
169c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner}
170c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
171c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turnerextern "C" {
172c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height);
173c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj);
174c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner};
175c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
176c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' TurnerJNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height)
177c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner{
178c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    setupGraphics(width, height);
179c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner}
180c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner
181c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' TurnerJNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj)
182c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner{
183c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner    renderFrame();
184c817c5210e4207908b83faaf08a2c5b95251f871David 'Digit' Turner}
185