2017-02-10 193 views
0

我想在使用NDK,JNI的Android Studio上制作一个简单的应用程序,以调用加载和显示图像的C++代码。我设法创建了曲面并绘制了一个简单的三角形。如何使用C++在OpenGL ES 3.0中加载和显示图像

现在,我正在寻找一种方法来加载和使用C++在OpenGL ES 3.0中显示图像。我已经完成了搜索,但它们都对我来说太复杂或过时,或者用Java编写。如果有人能够用一个简单的例子来指导我,那将是非常棒的。

回答

0

解决后,我终于做到了。以下是我的C++源代码。我使用stb_image库来加载图像。

/* 
* Copyright (C) 2009 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. 
*/ 

// OpenGL ES 3.0 code 

#include <jni.h> 
#include <android/log.h> 

#include <GLES3/gl3.h> 
#include <GLES3/gl3ext.h> 
#include <GLES3/gl3ext.h> 

#include <string> 
#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include "stb_image.h" 

#define LOG_TAG "libgl2jni" 
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) 
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) 

GLuint mTexture, VAO;// Create reference Id for the texture 
GLuint gProgram; 
GLuint gvPositionHandle; 

static void printGLString(const char *name, GLenum s) { 
    const char *v = (const char *) glGetString(s); 
    LOGI("GL %s = %s\n", name, v); 
} 

static void checkGlError(const char* op) { 
    for (GLint error = glGetError(); error; error 
      = glGetError()) { 
     LOGI("after %s() glError (0x%x)\n", op, error); 
    } 
} 

auto gVertexShader = 
"#version 300 es\n" 
"layout (location=0) in vec3 position;\n" 
"layout (location=1) in vec3 color;\n" 
"layout (location=2) in vec2 texCoord;\n" 

"out vec3 ourColor;\n" 
"out vec2 TexCoord;\n" 

"void main()\n" 
"{\n" 
    "gl_Position = vec4(position,1.0f); // Add the xOffset to the x position of the vertex position\n" 
    "ourColor = color;\n" 
    "TexCoord= vec2(texCoord.x,1.0f-texCoord.y);\n" 
"}"; 

auto gFragmentShader = 

"#version 300 es\n" 
"in vec3 ourColor;\n" 
"in vec2 TexCoord;\n" 

"out vec4 color;\n" 

"uniform sampler2D ourTexture;\n" 


"void main()\n" 
"{\n" 
    "color = texture(ourTexture , TexCoord);\n" 
"}\n"; 

GLuint loadShader(GLenum shaderType, const char* pSource) { 
    GLuint shader = glCreateShader(shaderType); 
    if (shader) { 
     glShaderSource(shader, 1, &pSource, 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) { 
       char* buf = (char*) malloc(infoLen); 
       if (buf) { 
        glGetShaderInfoLog(shader, infoLen, NULL, buf); 
        LOGE("Could not compile shader %d:\n%s\n", 
          shaderType, buf); 
        free(buf); 
       } 
       glDeleteShader(shader); 
       shader = 0; 
      } 
     } 
    } 
    return shader; 
} 

GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { // Load and Bind Fragments to Progam and link program then return result 
    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); 
    if (!vertexShader) { 
     return 0; 
    } 

    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); 
    if (!pixelShader) { 
     return 0; 
    } 

    GLuint program = glCreateProgram(); 
    if (program) { 
     glAttachShader(program, vertexShader); 
     checkGlError("glAttachShader"); 
     glAttachShader(program, pixelShader); 
     checkGlError("glAttachShader"); 
     glLinkProgram(program); 
     GLint linkStatus = GL_FALSE; 
     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 
     if (linkStatus != GL_TRUE) { 
      GLint bufLength = 0; 
      glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); 
      if (bufLength) { 
       char* buf = (char*) malloc(bufLength); 
       if (buf) { 
        glGetProgramInfoLog(program, bufLength, NULL, buf); 
        LOGE("Could not link program:\n%s\n", buf); 
        free(buf); 
       } 
      } 
      glDeleteProgram(program); 
      program = 0; 
     } 
    } 
    return program; 
} 



bool setupGraphics(int w, int h) { 
    printGLString("Version", GL_VERSION); 
    printGLString("Vendor", GL_VENDOR); 
    printGLString("Renderer", GL_RENDERER); 
    printGLString("Extensions", GL_EXTENSIONS); 

    LOGI("setupGraphics(%d, %d)", w, h); 
    gProgram = createProgram(gVertexShader, gFragmentShader); 
    if (!gProgram) { 
     LOGE("Could not create program."); 
     return false; 
    } 
    gvPositionHandle = glGetAttribLocation(gProgram, "position"); 
    checkGlError("glGetAttribLocation"); 
    LOGI("glGetAttribLocation(\"position\") = %d\n", 
      gvPositionHandle); 

    glViewport(0, 0, w, h); 
    checkGlError("glViewport"); 
    return true; 
} 

GLfloat recVertices[] = { 
     // Positions   // Colors   // Texture Coords 
     0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Top Right 
     0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Bottom Right 
     -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom Left 
     -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // Top Left 
}; 

GLuint indices[] = { // Note that we start from 0! 
     0, 1, 3, // First Triangle 
     1, 2, 3 // Second Triangle 
}; 
void initBuffers() 
{ 

    GLuint VBOs[2], EBO; // Initialize an buffer to store all the verticles and transfer them to the GPU 
    glGenVertexArrays (1,&VAO); // Generate VAO 
    glGenBuffers(1, VBOs); // Generate VBO 
    glGenBuffers(1, &EBO); // Generate EBO 
    glBindVertexArray (VAO);// Bind the Vertex Array 

    glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);//Bind verticles array for OpenGL to use 
    glBufferData(GL_ARRAY_BUFFER, sizeof(recVertices), recVertices, GL_STATIC_DRAW); 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//Bind the indices for information about drawing sequence 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 

    // 1. set the vertex attributes pointers 
    // Position Attribute 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); 
    glEnableVertexAttribArray(0); 
    // Color Attribute 
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); 
    glEnableVertexAttribArray(1); 
    //Texture Coordinate Attribute 
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); 
    glEnableVertexAttribArray(2); 

    glBindVertexArray(0);//3. Unbind VAO 

} 

void generateTexture() 
{ 

    glGenTextures(1 , &mTexture); 
    glBindTexture(GL_TEXTURE_2D, mTexture);// Bind our 2D texture so that following set up will be applied 

    //Set texture wrapping parameter 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_MIRRORED_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_MIRRORED_REPEAT); 

    //Set texture Filtering parameter 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 

    //Load the image 
    int picWidth,picHeight,n; 
    unsigned char* image = stbi_load("/storage/emulated/sdcard/Lighthouse.jpg", &picWidth, &picHeight, &n,0); 
    if (image == NULL) { 
     LOGI("Failed to load image: %s", stbi_failure_reason()); 
    } 
    //Generate the image 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB , picWidth , picHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image); 
    glGenerateMipmap(GL_TEXTURE_2D); 

    stbi_image_free(image);// Free the reference to the image 
    glBindTexture(GL_TEXTURE_2D,0); //Unbind 2D textures 

} 
void renderFrame() { 
    static float grey; 
    grey += 0.01f; 
    if (grey > 1.0f) { 
     grey = 0.0f; 
    } 

    generateTexture(); 
    glClearColor(grey+0.05f, grey-0.03f, grey+0.02f, grey-0.04f); 
    checkGlError("glClearColor"); 
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 
    checkGlError("glClear"); 

    glUseProgram(gProgram); 
    checkGlError("glUseProgram"); 

    /*glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, recVertices); 
    checkGlError("glVertexAttribPointer"); 
    glEnableVertexAttribArray(gvPositionHandle); 
    checkGlError("glEnableVertexAttribArray"); 
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
    checkGlError("glDrawArrays");*/ 
    glActiveTexture(GL_TEXTURE0); 
    checkGlError("glActiveTexture"); 
    glBindTexture(GL_TEXTURE_2D,mTexture); 
    checkGlError("glBindTexture"); 
    GLint mlocation = glGetUniformLocation(gProgram,"ourTexture"); 
    checkGlError("glGetUniformLocation"); 
    glUniform1i(mlocation,0); 
    checkGlError("glUniform1i"); 
    initBuffers(); 
    glBindVertexArray(VAO); 
    checkGlError("glBindVertexArray"); 
    glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); 

} 

extern "C" { 
    JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv * env, jobject obj, jint width, jint height); 
    JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv * env, jobject obj); 
}; 

JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv * env, jobject obj, jint width, jint height) 
{ 
    setupGraphics(width, height); 
} 

JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv * env, jobject obj) 
{ 

    renderFrame(); 
}