• Android OpenGL ES 2.0画立方体JNI实现


    前面实现了Android有关OpenGL ES 2.0的一些例子,现在,把它改成用JNI实现。

    以立方体为例。代码主要变化发生在Renderer里,以前直接用JAVA的,现在都移到C++里了。

    代码和JAVA的实质上是一样的。

    下面来看看主要的代码。

    先看看工程结构:

    上代码。

    OpenGLJniActivity.java:

     1 package com.jayce.eopengljni;
     2 
     3 import android.app.Activity;
     4 import android.app.ActivityManager;
     5 import android.content.Context;
     6 import android.content.pm.ConfigurationInfo;
     7 import android.opengl.GLSurfaceView;
     8 import android.os.Bundle;
     9 
    10 public class OpenGLJniActivity extends Activity
    11 {
    12     private GLSurfaceView mGLSurfaceView;
    13     
    14     public void onCreate(Bundle savedInstanceState)
    15     {
    16         super.onCreate(savedInstanceState);
    17         mGLSurfaceView = new GLSurfaceView(this);
    18         final ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    19         final ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
    20         if(configInfo.reqGlEsVersion >= 0x20000)
    21         {
    22             mGLSurfaceView.setEGLContextClientVersion(2);
    23             OpenGLJniRenderer renderer = new OpenGLJniRenderer();
    24             mGLSurfaceView.setRenderer(renderer);
    25         }
    26         
    27         setContentView(mGLSurfaceView);
    28     }
    29     
    30     @Override
    31     protected void onResume() 
    32     {
    33         // The activity must call the GL surface view's onResume() on activity onResume().
    34         super.onResume();
    35         mGLSurfaceView.onResume();
    36     }
    37 
    38     @Override
    39     protected void onPause() 
    40     {
    41         // The activity must call the GL surface view's onPause() on activity onPause().
    42         super.onPause();
    43         mGLSurfaceView.onPause();
    44     }    
    45 }

    上面这个和普通JAVA版的一模一样的。

    然后是OpenGLJniRenderer.java:

     1 package com.jayce.eopengljni;
     2 
     3 import javax.microedition.khronos.egl.EGLConfig;
     4 import javax.microedition.khronos.opengles.GL10;
     5 import android.opengl.GLSurfaceView;
     6 
     7 public class OpenGLJniRenderer implements GLSurfaceView.Renderer
     8 {
     9     
    10     @Override
    11     public void onDrawFrame(GL10 gl) {
    12         // TODO Auto-generated method stub
    13         OpenGLJniLib.step();
    14     }
    15 
    16     @Override
    17     public void onSurfaceChanged(GL10 gl, int width, int height) {
    18         OpenGLJniLib.init(width, height);
    19     }
    20 
    21     @Override
    22     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    23         OpenGLJniLib.create();
    24     }
    25 }

    这个发生了不小的变化,主要的三个方法都换由C++实现了。

    然后是native方法的包装类了。

    OpenGLJniLib.java:

     1 package com.jayce.eopengljni;
     2 
     3 public class OpenGLJniLib {
     4 
     5      static {
     6          System.loadLibrary("gljni");
     7      }
     8 
     9      public static native void init(int width, int height);
    10      public static native void create();
    11      public static native void step();
    12 }

    然后主要工作都在C++里做了。

    opengljni.cpp:

      1 #include <jni.h>
      2 #include <android/log.h>
      3 
      4 #include <GLES2/gl2.h>
      5 #include <GLES2/gl2ext.h>
      6 
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <math.h>
     10 #include <string.h>
     11 #include "common/Matrix.h"
     12 
     13 #define  LOG_TAG    "libgljni"
     14 #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
     15 #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
     16 
     17 #define POSITION_DATA_SIZE 3
     18 #define COLOR_DATA_SIZE 4
     19 
     20 GLfloat gMVPMatrix[16] = {0.0f};
     21 GLfloat gViewMatrix[16] = {0.0f};
     22 GLfloat gModelMatrix[16] = {0.0f};
     23 GLfloat gProjectionMatrix[16] = {0.0f};
     24 
     25 GLuint gMVPMatrixHandle = 0;
     26 GLuint gPositionHandle = 0;
     27 GLuint gColorHandle = 0;
     28 GLuint gProgram = 0;
     29 
     30 const GLfloat cubePosition[] =
     31 {
     32     -1.0f, 1.0f, 1.0f,
     33     -1.0f, -1.0f, 1.0f,
     34     1.0f, 1.0f, 1.0f,
     35     -1.0f, -1.0f, 1.0f,
     36     1.0f, -1.0f, 1.0f,
     37     1.0f, 1.0f, 1.0f,
     38 
     39     1.0f, 1.0f, 1.0f,
     40     1.0f, -1.0f, 1.0f,
     41     1.0f, 1.0f, -1.0f,
     42     1.0f, -1.0f, 1.0f,
     43     1.0f, -1.0f, -1.0f,
     44     1.0f, 1.0f, -1.0f,
     45 
     46     1.0f, 1.0f, -1.0f,
     47     1.0f, -1.0f, -1.0f,
     48     -1.0f, 1.0f, -1.0f,
     49     1.0f, -1.0f, -1.0f,
     50     -1.0f, -1.0f, -1.0f,
     51     -1.0f, 1.0f, -1.0f,
     52 
     53     -1.0f, 1.0f, -1.0f,
     54     -1.0f, -1.0f, -1.0f,
     55     -1.0f, 1.0f, 1.0f,
     56     -1.0f, -1.0f, -1.0f,
     57     -1.0f, -1.0f, 1.0f,
     58     -1.0f, 1.0f, 1.0f,
     59 
     60     -1.0f, 1.0f, -1.0f,
     61     -1.0f, 1.0f, 1.0f,
     62     1.0f, 1.0f, -1.0f,
     63     -1.0f, 1.0f, 1.0f,
     64     1.0f, 1.0f, 1.0f,
     65     1.0f, 1.0f, -1.0f,
     66 
     67     1.0f, -1.0f, -1.0f,
     68     1.0f, -1.0f, 1.0f,
     69     -1.0f, -1.0f, -1.0f,
     70     1.0f, -1.0f, 1.0f,
     71     -1.0f, -1.0f, 1.0f,
     72     -1.0f, -1.0f, -1.0f
     73 };
     74 
     75 const GLfloat cubeColor[] =
     76 {
     77     1.0f, 0.0f, 0.0f, 1.0f,
     78     1.0f, 0.0f, 0.0f, 1.0f,
     79     1.0f, 0.0f, 0.0f, 1.0f,
     80     1.0f, 0.0f, 0.0f, 1.0f,
     81     1.0f, 0.0f, 0.0f, 1.0f,
     82     1.0f, 0.0f, 0.0f, 1.0f,
     83 
     84     0.0f, 1.0f, 0.0f, 1.0f,
     85     0.0f, 1.0f, 0.0f, 1.0f,
     86     0.0f, 1.0f, 0.0f, 1.0f,
     87     0.0f, 1.0f, 0.0f, 1.0f,
     88     0.0f, 1.0f, 0.0f, 1.0f,
     89     0.0f, 1.0f, 0.0f, 1.0f,
     90 
     91     0.0f, 0.0f, 1.0f, 1.0f,
     92     0.0f, 0.0f, 1.0f, 1.0f,
     93     0.0f, 0.0f, 1.0f, 1.0f,
     94     0.0f, 0.0f, 1.0f, 1.0f,
     95     0.0f, 0.0f, 1.0f, 1.0f,
     96     0.0f, 0.0f, 1.0f, 1.0f,
     97 
     98     1.0f, 1.0f, 0.0f, 1.0f,
     99     1.0f, 1.0f, 0.0f, 1.0f,
    100     1.0f, 1.0f, 0.0f, 1.0f,
    101     1.0f, 1.0f, 0.0f, 1.0f,
    102     1.0f, 1.0f, 0.0f, 1.0f,
    103     1.0f, 1.0f, 0.0f, 1.0f,
    104 
    105     0.0f, 1.0f, 1.0f, 1.0f,
    106     0.0f, 1.0f, 1.0f, 1.0f,
    107     0.0f, 1.0f, 1.0f, 1.0f,
    108     0.0f, 1.0f, 1.0f, 1.0f,
    109     0.0f, 1.0f, 1.0f, 1.0f,
    110     0.0f, 1.0f, 1.0f, 1.0f,
    111 
    112     1.0f, 0.0f, 1.0f, 1.0f,
    113     1.0f, 0.0f, 1.0f, 1.0f,
    114     1.0f, 0.0f, 1.0f, 1.0f,
    115     1.0f, 0.0f, 1.0f, 1.0f,
    116     1.0f, 0.0f, 1.0f, 1.0f,
    117     1.0f, 0.0f, 1.0f, 1.0f
    118 };
    119 
    120 static const char gVertexShader[] =
    121 {
    122     "uniform mat4 u_MVPMatrix;      \n"
    123     "attribute vec4 a_Position;     \n"
    124     "attribute vec4 a_Color;        \n"
    125 
    126     "varying vec4 v_Color;          \n"
    127 
    128     "void main()                    \n"
    129     "{                              \n"
    130     "   v_Color = a_Color;          \n"
    131     "   gl_Position = u_MVPMatrix   \n"
    132     "               * a_Position;   \n"
    133     "}                              \n"
    134 };
    135 
    136 static const char gFragmentShader[] =
    137 {
    138     "precision mediump float;       \n"
    139     "varying vec4 v_Color;          \n"
    140     "void main()                    \n"
    141     "{                              \n"
    142     "   gl_FragColor = v_Color;     \n"
    143     "}                              \n"
    144 };
    145 
    146 GLuint loadShader(GLenum type, const char* source)
    147 {
    148     GLuint shader = glCreateShader(type);
    149     if(shader)
    150     {
    151         glShaderSource(shader, 1, &source, NULL);
    152         glCompileShader(shader);
    153         GLint compileStatus = 0;
    154         glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
    155         if(!compileStatus)
    156         {
    157             GLint info_length = 0;
    158             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_length);
    159             if(info_length)
    160             {
    161                 char* buf = (char*)malloc(info_length * sizeof(char));
    162                 if(buf)
    163                 {
    164                     glGetShaderInfoLog(shader, info_length, NULL, buf);
    165                     LOGE("Create shader %d failed\n%s\n", type, buf);
    166                 }
    167             }
    168             glDeleteShader(shader);
    169             shader = 0;
    170         }
    171     }
    172     return shader;
    173 }
    174 
    175 GLuint createProgram(const char* pVertexSource, const char* pFragmentSource)
    176 {
    177     GLuint vshader = loadShader(GL_VERTEX_SHADER, pVertexSource);
    178     if(!vshader)
    179     {
    180         return 0;
    181     }
    182     GLuint fshader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
    183     if(!fshader)
    184     {
    185         return 0;
    186     }
    187     GLuint program = glCreateProgram();
    188     if(program)
    189     {
    190         glAttachShader(program, vshader);
    191         glAttachShader(program, fshader);
    192         glBindAttribLocation(program, 0, "a_Position");
    193         glBindAttribLocation(program, 1, "a_Color");
    194 
    195         glLinkProgram(program);
    196 
    197         GLint status = 0;
    198         glGetProgramiv(program, GL_LINK_STATUS, &status);
    199 
    200         if(!status)
    201         {
    202             GLint info_length = 0;
    203             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_length);
    204             if(info_length)
    205             {
    206                 char* buf = (char*)malloc(info_length * sizeof(char));
    207                 glGetProgramInfoLog(program, info_length, NULL, buf);
    208                 LOGE("create program failed\n%s\n", buf);
    209             }
    210             glDeleteProgram(program);
    211             program = 0;
    212         }
    213     }
    214     return program;
    215 }
    216 
    217 static GLfloat angleInDegrees = 0.1;
    218 
    219 void drawCube(const GLfloat* positions, const GLfloat* colors)
    220 {
    221     glVertexAttribPointer(gPositionHandle, POSITION_DATA_SIZE, GL_FLOAT, GL_FALSE, 0, positions);
    222     glEnableVertexAttribArray(gPositionHandle);
    223     glVertexAttribPointer(gColorHandle, COLOR_DATA_SIZE, GL_FLOAT, GL_FALSE, 0, colors);
    224     glEnableVertexAttribArray(gColorHandle);
    225     Matrix::multiplyMM(gMVPMatrix, 0, gViewMatrix, 0, gModelMatrix, 0);
    226     Matrix::multiplyMM(gMVPMatrix, 0, gProjectionMatrix, 0, gMVPMatrix, 0);
    227 
    228     glUniformMatrix4fv(gMVPMatrixHandle, 1, GL_FALSE, gMVPMatrix);
    229     glDrawArrays(GL_TRIANGLES, 0, 36);
    230 }
    231 
    232 void renderFrame()
    233 {
    234     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    235     glUseProgram(gProgram);
    236     gMVPMatrixHandle = glGetUniformLocation(gProgram, "u_MVPMatrix");
    237     gPositionHandle = glGetAttribLocation(gProgram, "a_Position");
    238     gColorHandle = glGetAttribLocation(gProgram, "a_Color");
    239 
    240     Matrix::setIdentityM(gModelMatrix, 0);
    241     Matrix::translateM(gModelMatrix, 0, 0.0f, 0.0f, -5.0f);
    242     if(359.0 <= angleInDegrees)
    243     {
    244         angleInDegrees = 0.1;
    245     }
    246     else
    247     {
    248         angleInDegrees = angleInDegrees + 1.0;
    249     }
    250 
    251     Matrix::rotateM(gModelMatrix, 0, angleInDegrees, 1.0f, 1.0f, 0.0f);
    252 
    253     drawCube(cubePosition, cubeColor);
    254 }
    255 
    256 extern "C"
    257 {
    258     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_create(JNIEnv * env, jobject object);
    259     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_init(JNIEnv * env, jobject object, jint width, jint height);
    260     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_step(JNIEnv * env, jobject object);
    261 }
    262 
    263 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_create(JNIEnv * env, jobject object)
    264 {
    265     LOGI("create");
    266     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    267     glEnable(GL_CULL_FACE);
    268     glEnable(GL_DEPTH_TEST);
    269     const GLfloat eyeX = 0.0f;
    270     const GLfloat eyeY = 0.0f;
    271     const GLfloat eyeZ = -0.5f;
    272 
    273     const GLfloat lookX = 0.0f;
    274     const GLfloat lookY = 0.0f;
    275     const GLfloat lookZ = -5.0f;
    276 
    277     const GLfloat upX = 0.0f;
    278     const GLfloat upY = 1.0f;
    279     const GLfloat upZ = 0.0f;
    280 
    281     Matrix::setLookAtM(gViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
    282     gProgram = createProgram(gVertexShader, gFragmentShader);
    283 }
    284 
    285 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_init(JNIEnv * env, jobject object, jint width, jint height)
    286 {
    287     LOGI("init");
    288     glViewport(0, 0, width, height);
    289     const GLfloat ratio = (GLfloat) width / height;
    290     const GLfloat left = -ratio;
    291     const GLfloat right = ratio;
    292     const GLfloat bottom = -1.0f;
    293     const GLfloat top = 1.0f;
    294     const GLfloat near = 1.0f;
    295     const GLfloat far = 10.0f;
    296 
    297     Matrix::frustumM(gProjectionMatrix, 0, left, right, bottom, top, near, far);
    298 }
    299 
    300 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_step(JNIEnv * env, jobject object)
    301 {
    302     LOGI("step");
    303     renderFrame();
    304 }

    这里面实现了三个native方法,还有一些辅助的函数。

    这里用到的Matrix类是我根据android源码里的Matrix类进行改写。

    内容和Matrix.java大同小异,只是语法上的差异,功能和Matrix.java完全一样。

    还有一点,Matrix类我里面有些有关数组越界的问题我没有做严格的检测,如果要运用在实际项目里应该加上的。

    好了,下面就是Make文件了,很简单,参考NDK里的例子应该很容易写出来。

    Android.mk:

     1 # Copyright (C) 2009 The Android Open Source Project
     2 #
     3 # Licensed under the Apache License, Version 2.0 (the "License");
     4 # you may not use this file except in compliance with the License.
     5 # 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
    10 # distributed under the License is distributed on an "AS IS" BASIS,
    11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12 # See the License for the specific language governing permissions and
    13 # limitations under the License.
    14 #
    15 LOCAL_PATH:= $(call my-dir)
    16 
    17 include $(CLEAR_VARS)
    18 
    19 LOCAL_MODULE    := gljni
    20 LOCAL_CFLAGS    := -Werror
    21 LOCAL_SRC_FILES := opengljni.cpp common/Matrix.cpp
    22 LOCAL_LDLIBS    := -llog -lGLESv2
    23 
    24 include $(BUILD_SHARED_LIBRARY)

    如果NDK环境已安好,ndk-build命令就能正确编译出库了。

    当然,也可以用eclipse的NDK,cdt辅助,看个人喜好。

    最后,效果图,是一个旋转的立方体,跟纯JAVA版的是完全一样的。

  • 相关阅读:
    CodeForces Round #521 (Div.3) B. Disturbed People
    CodeForces Round #521 (Div.3) A. Frog Jumping
    Lyft Level 5 Challenge 2018-Final Round(Open Div.2) B. Taxi drivers and Lyft
    #Leetcode# 2. Add Two Numbers
    #Leetcode# 29. Divide Two Integers
    #Leetcode# 122. Best Time to Buy and Sell Stock II
    #Leetcode# 121. Best Time to Buy and Sell Stock
    #LeetCode# 48. Rotate Image
    #Leetcode# 5. Longest Palindromic Substring
    原理优先的重要性_就signal探讨
  • 原文地址:https://www.cnblogs.com/jayceli/p/2564144.html
Copyright © 2020-2023  润新知