Previously, when I was learning Android, I wrote that if I used OpenGL in Android, all of them were implemented in Java. Now we use ndk to implement it once.
The idea is to implement ondrawframe, onsurfacechanged, and onsurfacecreated in the Renderer in C, compile C into A. So file, and then directly call the corresponding function in Java.
The steps are not described in detail. paste the code.
Main activity:
package com.empty.ndkgl;import com.example.ndkgl.R;import android.opengl.GLSurfaceView;import android.os.Bundle;import android.app.Activity;import android.view.Menu;public class NdkGlActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GLSurfaceView surface = new GLSurfaceView(this); surface.setRenderer(new NdkGlRender()); setContentView(surface); }static { //load library System.loadLibrary("NdkGLRenderer"); } @Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_ndkgl, menu);return true;}}
Render class code:
package com.empty.ndkgl;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import android.opengl.GLSurfaceView.Renderer;public class NdkGlRender implements Renderer{//declare native function native private void onNdkSurfaceCreated (); native private void onNdkSurfaceChanged (int width, int height); native private void onNdkDrawFrame();@Overridepublic void onDrawFrame(GL10 arg0) {// TODO Auto-generated method stubonNdkDrawFrame (); }@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {// TODO Auto-generated method stubonNdkSurfaceChanged (width, height);}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// TODO Auto-generated method stubonNdkSurfaceCreated ();}}
Create a JNI folder in the project directory and generate a. h file using the following command.
javah -classpath bin/classes -d jni com.empty.ndkgl.NdkGlRender
Create a. c file based on the header file.
Note: although. the H file does not work during compilation, but we recommend that you do this step because. the function name in the C file must be the same as that in the C file. if the function names in the H file are the same, the final program can run normally. Otherwise
Java. Lang. unsatisfiedlinkerror bug.
# Include <JNI. h> # include <gles/GL. h> unsigned int VBO [2]; float positions [12] = {1,-, 0,-1,-,-, 0 }; short indices [4] = {0, 1, 2, 3}; jniexport void jnicall handle (jnienv * ENV, jobject OBJ) {// generate two cache zone objects glgenbuffers (2, VBO ); // bind the first cache object glbindbuffer (gl_array_buffer, VBO [0]); // create and initialize the data glbufferdata (gl_array_buffer, 4*12, positions, gl_static_draw); // bind the second cache object glbindbuffer (cached, VBO [1]); // create and initialize the data glbufferdata (gl_element_array_buffer, 2*4, indices, gl_static_draw);} jniexport void jnicall java_com_empty_ndkgl_ndkglrender_onndksurfacechanged (jnienv * ENV, jobject OBJ, jint width, jheight INT) {// The position, length, and width of the final display image to the area on the screen glviewport (, width, height); // specify the matrix glmatrixmode (gl_projection ); // set the current matrix to the glloadidentity () matrix specified by glmatrixmode; glorthof (-2, 2,-2, 2,-2, 2 );} jniexport void jnicall initialize (jnienv * ENV, jobject OBJ) {// enable the vertex setting function. You must disable the function after that, and glableclientstate (gl_vertex_array); // clear the screen glclearcolor ); glclear (vertex | vertex); glmatrixmode (gl_modelview); glloadidentity (); glbindbuffer (gl_array_buffer, VBO [0]); // defines the vertex coordinate glvertexpointer (3, gl_float, 0, 0); glbindbuffer (gl_element_array_buffer, VBO [1]); // draw a gldrawelements (gl_triangle_strip, 4, gl_unsigned_short, 0) based on the value given by the parameter ); // disable the vertex setting function gldisableclientstate (gl_vertex_array );}
Write Android. mk
#FileName:Android.mk#Description:makefile of NdkGlLOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := NdkGLRendererLOCAL_SRC_FILES := com_empty_ndkgl_NdkGlRender.c LOCAL_LDLIBS := -lGLESv1_CMinclude $(BUILD_SHARED_LIBRARY)
Compile Library
$NDK_ROOT/ndk-build
Run the program in eclipse
By modifying the implementation of. C, we can draw different images.
For example, the grid sphere:
# Include <JNI. h> # include <unistd. h> # include <stdlib. h> # include <stdio. h> # include <math. h> # include <gles/GL. h> typedef unsigned char byte; typedef struct {glfloat x, y, z;} XYZ; float rotatequad; # define PI 3.14159265 # define dtor PI/180 static byte indices [8] = {,}; // Index Array void createunitsphere (INT dtheta, int dphi) {int N; int Theta, Phi; xyz p [4]; for (theta =-90; Theta <= 90-dtheta; Theta + = dtheta) {for (Phi = 0; phi <= 360-dphi; Phi + = dphi) {n = 0; P [N]. X = cos (theta * dtor) * Cos (PHI * dtor); P [N]. y = cos (theta * dtor) * sin (PHI * dtor); P [N]. z = sin (theta * dtor); N ++; P [N]. X = cos (theta + dtheta) * dtor) * Cos (PHI * dtor); P [N]. y = cos (theta + dtheta) * dtor) * sin (PHI * dtor); P [N]. z = sin (theta + dtheta) * dtor); N ++; P [N]. X = cos (theta + dtheta) * dtor) * Cos (PHI + dphi) * dtor); P [N]. y = cos (theta + dtheta) * dtor) * sin (PHI + dphi) * dtor); P [N]. z = sin (theta + dtheta) * dtor); N ++; If (theta> =-90 & Theta <= 90) {P [N]. X = cos (theta * dtor) * Cos (PHI + dphi) * dtor); P [N]. y = cos (theta * dtor) * sin (PHI + dphi) * dtor); P [N]. z = sin (theta * dtor); N ++;}/* do something with the N vertex facet p */glvertexpointer (3, gl_float, 0, P ); gldrawelements (gl_lines, 8, numbers, indices) ;}} jniexport void jnicall labels (jnienv * ENV, jobject OBJ) {// enable shadow smooth glshademodel (gl_smooth ); // black background glclearcolor (0, 0, 0, 0); // set the deep cache glcleardepthf (1.0f); // enable the deep test glenable (gl_depth_test ); // gldepthfunc (gl_lequal) of the type of deep test; // notify the system to modify glhint (random, gl_fastest) for perspective;} jniexport void jnicall trim (jnienv * ENV, jobject OBJ, jint width, jint height) {// position, length, and width of the final display image to the screen glviewport (, width, height); // specify the glmatrixmode (gl_projection) matrix ); // set the current matrix to the glloadidentity () matrix specified by glmatrixmode; glorthof (-2, 2,-2, 2,-2, 2 );} jniexport void jnicall initialize (jnienv * ENV, jobject OBJ) {// enable the vertex setting function. You must disable the function after that ); glmatrixmode (gl_modelview); glloadidentity (); glfrontface (gl_cw); glrotatef (rotatequad, 1.0f, 1.0f, 0.0f); // createunitsphere (10, 10 ); // disable the vertex setting function gldisableclientstate (gl_vertex_array); rotatequad-= 1.5f ;}
Cube
# Include <JNI. h> # include <unistd. h> # include <stdlib. h> # include <stdio. h> # include <math. h> # include <gles/GL. h> # define Col 1.0f # define POS 1.0f # define PI 3.14159265 static glfloat vertex [] = {-pos,/* 0 */-pos, -pos, POs,/* 1 */POS,-pos, POs,/* 2 */POS,-pos,-pos,/* 3 */-pos, POs, -pos,/* 4 */-pos, POs, POs,/* 5 */POS, POs, POs,/* 6 */POS, POs,-pos, /* 7 */}; static glfloat colors [] = {Col, Col, 0, Col, 0, Col, 0, col, Col, 0, Col, Col, 0, Col, 0, 0, Col ,}; static glubyte mindex [] =, 6, 4, 6, 7,}; static glfloat angle = 0.0f; jniexport void jnicall inline (jnienv * ENV, jobject OBJ) {// enable shadow smooth glshademodel (gl_smooth ); // black background glclearcolor (0, 0, 0, 0); // set the deep cache glcleardepthf (1.0f); // enable the deep test glenable (gl_depth_test ); // gldepthfunc (gl_lequal) of the type of deep test; // notify the system to modify glhint (random, gl_fastest) for perspective;} static void _ gluperspective (glfloat fovy, glfloat aspect, glfloat znear, glfloat zfar) {glfloat Top = znear * (glfloat) Tan (fovy * PI/360.0); glfloat Bottom =-top; glfloat left = bottom * aspect; glfloat right = top * aspect; glfrustumf (left, right, bottom, top, znear, zfar);} jniexport void jnicall trim (jnienv * ENV, jobject OBJ, jint width, jint height) {If (Height = 0) // prevents division by zero {Height = 1; // set height to 1} glviewport (0, 0, width, height); // reset the current glmatrixmode (gl_projection); // select the projection matrix glloadidentity (); // reset the projection matrix glfloat ratio = (glfloat) width/(glfloat) height; // set the size of the viewport _ gluperspective (45.0f, (glfloat) width/(glfloat) height, 0.1f, 100366f); // glorthof (-2.0f, 2.0f,-2.0f, 2.0f,-2.0f, 2.0f); glmatrixmode (gl_modelview); // select the model observation matrix glloadidentity (); // reset the model observation matrix} jniexport void jnicall evaluate (jnienv * ENV, jobject OBJ) {glclear (gl_color_buffer_bit | percent); glmatrixmode (gl_modelview); glloadidentity (); gltranslatef (0, 0,-8.0f); glrotatef (angle, 0, 1.0f, 0); glrotatef (angle, 0, 0, 1.0f); glableclientstate (gradient); glableclientstate (gl_color_array); glvertexpointer (3, gl_float, 0, vertex); glcolorpointer (4, gl_float, 0, colors); gldrawelements (gl_triangles, 36, cosine, mindex); gldisableclientstate (gl_vertex_array); gldisableclientstate (gl_color_array); angle + = 1.2f ;}
Close the job.
Updated on January 15:
A stronger demo is found in the samples folder of ndk, just San-Angeles!
San Angeles observation, the champion of the XX competition. The original program was only 4 kb and was included in the ndk demo by Google. Let's run it.
Directly create an android project in eclipse and select Android project from exiting code.
If you run it directly, an error is reported, indicating that initialization fails. We must first compile C into. So.
Run the following command to enter the project folder: ndk-build
Modify the activity to make it real on the screen. You only need to modify the oncreate function.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLView = new DemoGLSurfaceView(this); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(mGLView); }
Running result: