标签:opengl es 1.x ndk实例开发 旋转的纹理立方体
开发框架介绍请参见:Opengl ES NDK实例开发之一:搭建开发框架
本章在第六章(Opengl ES 1.x NDK实例开发之六:纹理贴图)的基础上绘制一个旋转的纹理立方体,原理和纹理贴图一样,需要注意的是定好正方体的顶点数组。
【实例讲解】
本实例添加了一个显示fps的小功能,在java层实现,原理是统计一分钟内屏幕刷新的次数
【实例源码】
[GLJNIActivity.java]
/* * Copyright (C) 2007 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. * * author: mnorst@foxmail.com */ package com.android.gljni; import java.text.DecimalFormat; import com.android.gljni.GLJNIView; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.ViewGroup.LayoutParams; import android.widget.TextView; public class GLJNIActivity extends Activity { GLJNIView mView; TextView mTextView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mView = new GLJNIView(getApplication()); setContentView(mView); mView.setHandler(new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); // 显示fps mTextView.setText("fps:"+msg.what); } } ); mTextView = new TextView(this); mTextView.setText("fps:0"); addContentView(mTextView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } }
/* * Copyright (C) 2007 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. * * author: mnorst@foxmail.com */ package com.android.gljni; import java.io.IOException; import java.io.InputStream; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import com.android.gljni.GLJNILib; import com.android.gljnidemo07.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLSurfaceView; import android.opengl.GLUtils; import android.os.Handler; import android.util.Log; /** * A simple GLSurfaceView sub-class that demonstrate how to perform * OpenGL ES 1.x rendering into a GL Surface. */ public class GLJNIView extends GLSurfaceView { private static final String LOG_TAG = GLJNIView.class.getSimpleName(); private Renderer renderer; public GLJNIView(Context context) { super(context); // setEGLConfigChooser会对fps产生影响 setEGLConfigChooser(8, 8, 8, 8, 16, 0); renderer = new Renderer(context); setRenderer(renderer); } public void setHandler( Handler handler){ renderer.setHandler(handler); } private static class Renderer implements GLSurfaceView.Renderer { //用于纹理映射的绑定,并把绑定后的ID传递给C++代码,供其调用 private int[] mTexture = new int[2]; //用于加载Bitmap的context private Context mContext; // 统计fps private Handler mHandler; private long mStartMili; private long mEndMili; private int mFps = 0; public Renderer(Context ctx) { mContext = ctx; mStartMili =System.currentTimeMillis(); } public void setHandler( Handler handler){ mHandler = handler; } public void onDrawFrame(GL10 gl) { GLJNILib.step(); // 以一分钟绘制的帧数来统计fps mEndMili = System.currentTimeMillis(); if( mEndMili - mStartMili > 1000 ){ mHandler.sendEmptyMessageDelayed(mFps, 100); mStartMili = mEndMili; mFps = 0; } mFps++; } public void onSurfaceChanged(GL10 gl, int width, int height) { GLJNILib.resize(width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { //用来绑定Bitmap纹理 genTexture(gl, mContext); //调用本地setTexture方法,把纹理绑定的ID传递给C++代码,以供其调用 GLJNILib.setTexture(mTexture); GLJNILib.init(); } /** * 加载Bitmap的方法, * 用来从res中加载Bitmap资源 * */ private Bitmap loadBitmap(Context context, int resourceId) { InputStream is = context.getResources().openRawResource(resourceId); Bitmap bitmap = null; try { // 利用BitmapFactory生成Bitmap bitmap = BitmapFactory.decodeStream(is); } finally { try { // 关闭流 is.close(); is = null; } catch (IOException e) { e.printStackTrace(); } } return bitmap; } /** * 绑定Bitmap纹理 * */ private void genTexture(GL10 gl, Context context) { //生成纹理 gl.glGenTextures(2, mTexture, 0); //加载Bitmap Bitmap bitmap = loadBitmap(context, R.drawable.logo); if (bitmap != null) { //如果bitmap加载成功,则生成此bitmap的纹理映射 gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexture[0]); //设置纹理映射的属性 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST); //生成纹理映射 GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); //释放bitmap资源 bitmap.recycle(); } } } }[GLJNILib.java]
/* * Copyright (C) 2007 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. * * author: mnorst@foxmail.com */ package com.android.gljni; //Wrapper for native library public class GLJNILib { static { System.loadLibrary("gljni"); } /** * @param width the current view width * @param height the current view height */ public static native void resize(int width, int height); /** * render */ public static native void step(); /** * init */ public static native void init(); /** * set the texture * @param texture texture id */ public static native void setTexture(int[] texture); }
/* * Copyright (C) 2007 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. * * author: mnorst@foxmail.com * created: 2014/10/27 * purpose: 旋转的纹理立方体 */ // OpenGL ES 1.x code #include <jni.h> #include <android/log.h> #include <GLES/gl.h> #include <GLES/glext.h> #include <stdio.h> #include <stdlib.h> #include <math.h> /************************************************************************/ /* 定义 */ /************************************************************************/ #define LOG_TAG "libgljni" #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 *gTexture = 0; // 定义π const GLfloat PI = 3.1415f; // 定义顶点坐标 #define pos 1.0f // 定义顶点坐标 // 一个正方体有8个顶点,6个面 #define one 1.0f static GLfloat gVertices[] = { one, one, -one, -one, one, -one, one, one, one, -one, one, one, one, -one,one, -one, -one, one, one, -one, -one, -one, -one, -one, one, one,one, -one, one, one, one, -one, one, -one, -one, one, one, -one,-one, -one, -one, -one, one, one, -one, -one, one, -one, -one, one,one, -one, one, -one, -one, -one, one, -one, -one, -one, one, one,-one, one, one, one, one, -one, -one, one, -one, one }; // 定义纹理坐标 // 纹理坐标原点会因不同系统环境而有所不同。 // 比如在iOS以及Android上,纹理坐标原点(0, 0)是在左上角 // 而在OS X上,纹理坐标的原点是在左下角 static GLfloat gTexCoords[] = { 0, one, one, one, 0, 0, one, 0, 0, one, one, one, 0, 0, one, 0, 0, one, one, one, 0, 0, one, 0, 0, one, one, one, 0, 0, one, 0, 0, one, one, one, 0, 0, one, 0, 0, one, one, one, 0, 0, one, 0, }; // 旋转角度 static GLfloat gAngle = 0.0f; /************************************************************************/ /* C++代码 */ /************************************************************************/ 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); } } bool init() { printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); // 启用阴影平滑 glShadeModel(GL_SMOOTH); // 黑色背景 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 设置深度缓存 glClearDepthf(1.0f); // 启用深度测试 glEnable(GL_DEPTH_TEST); // 所作深度测试的类型 glDepthFunc(GL_LEQUAL); // 对透视进行修正 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); return true; } 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); } void resize(int width, int height) { // 防止被零除 if (height==0) { height=1; } // 重置当前的视口 glViewport(0, 0, width, height); // 选择投影矩阵 glMatrixMode(GL_PROJECTION); // 重置投影矩阵 glLoadIdentity(); // 设置视口的大小 _gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); // 选择模型观察矩阵 glMatrixMode(GL_MODELVIEW); // 重置模型观察矩阵 glLoadIdentity(); } void renderFrame() { // 清除屏幕和深度缓存 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 重置当前的模型观察矩阵 glLoadIdentity(); glTranslatef(0,0,-10.0f); glRotatef(gAngle, 0, 1.0F, 0); glRotatef(gAngle, 0, 0, 1.0F); // 启用顶点数组 glEnableClientState(GL_VERTEX_ARRAY); //glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); // 启用纹理映射 glEnable(GL_TEXTURE_2D); // 选择纹理 glBindTexture(GL_TEXTURE_2D, gTexture[0]); // 绘制正方体的六个面 glVertexPointer(3,GL_FLOAT,0,gVertices); glTexCoordPointer(2, GL_FLOAT, 0, gTexCoords); for (int i = 0; i < 6; i++) { glDrawArrays(GL_TRIANGLE_STRIP, i * 4, 4); } // 关闭顶点数组 glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); //glDisableClientState(GL_OLOR_ARRAY); gAngle += 5.f; } /************************************************************************/ /* JNI代码 */ /************************************************************************/ extern "C" { JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_resize(JNIEnv * env, jobject obj, jint width, jint height); JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj); JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj); JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_setTexture(JNIEnv * env, jclass obj, jintArray tex); }; JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_resize(JNIEnv * env, jobject obj, jint width, jint height) { resize(width, height); } JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj) { renderFrame(); } JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj) { init(); } JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_setTexture(JNIEnv * env, jclass obj, jintArray tex) { gTexture = (GLuint *)env->GetIntArrayElements(tex,0); }
Opengl ES 1.x NDK实例开发之七:旋转的纹理立方体
标签:opengl es 1.x ndk实例开发 旋转的纹理立方体
原文地址:http://blog.csdn.net/mnorst/article/details/40510361