开发框架介绍请参见:Opengl ES NDK实例开发之一:搭建开发框架
本章在第三章(Opengl ES 1.x NDK实例开发之三:多边形的旋转)的基础上演示如何使用纹理贴图,分别实现了三角形纹理贴图和正方形纹理贴图。
【实例讲解】
OpenglES要求生成纹理的图片长宽为2的n次方,支持各种格式(BMP, GIF, JPEG, PNG...)
本例中使用的图片为png格式,尺寸为128*128
本例中,在上层GLJNIView.java中生成纹理,将纹理句柄传递给Native层进行绘制,详见
private void genTexture(GL10 gl, Context context)
【实例源码】
[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.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.gljnidemo06.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLSurfaceView; import android.opengl.GLUtils; 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); } private static class Renderer implements GLSurfaceView.Renderer { //用于纹理映射的绑定,并把绑定后的ID传递给C++代码,供其调用 private int[] mTexture = new int[2]; //用于加载Bitmap的context private Context mContext; public Renderer(Context ctx) { mContext = ctx; } public void onDrawFrame(GL10 gl) { GLJNILib.step(); } 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/20 * 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; // 旋转角度 static GLfloat gAngle = 0.0f; // 顶点数组 const GLfloat gVertices[] = { 0.0f, 1.0f, 0.0f, // 上 -1.0f,-1.0f, 0.0f, // 左下 1.0f,-1.0f, 0.0f, // 右下 }; const GLfloat gVerticesSquare[] = { -1.0f, -1.0f, 0.0f, // 左下 1.0f, -1.0f, 0.0f, // 右下 -1.0f, 1.0f, 0.0f, // 左上 1.0f, 1.0f, 0.0f // 右上 }; // 纹理坐标 // 纹理坐标原点会因不同系统环境而有所不同。 // 比如在iOS以及Android上,纹理坐标原点(0, 0)是在左上角 // 而在OS X上,纹理坐标的原点是在左下角 const GLfloat gTextureCoord[] = { 0.5f,0.0f, 0.0f,1.0f, 1.0f,1.0f, }; const GLfloat gTextureSquareCoord[] = { 0.0f,1.0f, 1.0f,1.0f, 0.0f,0.0f, 1.0f,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); // 设置背景颜色为黑色 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 重置当前的模型观察矩阵 glLoadIdentity(); // 启用顶点数组 glEnableClientState(GL_VERTEX_ARRAY); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // 纹理设置 glEnable(GL_TEXTURE_2D); // 启用纹理映射 glBindTexture(GL_TEXTURE_2D, gTexture[0]); // 选择纹理 glEnableClientState(GL_TEXTURE_COORD_ARRAY); // 启用纹理坐标数组 // 绘制三角形 glTranslatef(0.0f,2.0f,-10.0f); // 设置三角形位置 glRotatef(gAngle,0.0f,1.0f,0.0f); // 旋转三角形 glVertexPointer(3, GL_FLOAT, 0, gVertices); // 指定顶点数组 glTexCoordPointer(2, GL_FLOAT, 0, gTextureCoord); // 设置纹理坐标 glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形 // 绘制正方形 glTranslatef(0.0f,-4.0f,0.0f); // 设置正方形位置 glRotatef(-gAngle*2,0.0f,1.0f,0.0f); // 旋转正方形 glVertexPointer(3, GL_FLOAT, 0, gVerticesSquare); // 指定顶点数组 glTexCoordPointer(2, GL_FLOAT, 0, gTextureSquareCoord); // 设置纹理坐标 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // 绘制正方形 // 关闭顶点数组 glDisableClientState(GL_VERTEX_ARRAY); // 关闭纹理数组 glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); // 增加旋转角度 gAngle += 2.0f; } /************************************************************************/ /* 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); }
原文地址:http://blog.csdn.net/mnorst/article/details/40346641