Setting up Native OpenGL ES* on Android* Platforms final.docx
BSD2.0.txt
ParticleSystemNDK.zip
README.txt

摘要

本文具体介绍了在 Android 平台上创建原生 OpenGL ES 2.0 图形应用的基本步骤。 首先将讨论使用 Java* API 设置 OpenGL ES 2.0 应用的流程,随后将介绍在共享库中使用原生渲染来转换应用。

注:为了尽可能向更多的受众提供支持,本文中未使用 IDE。 所有的项目创建、维护和部署均将通过 Google 提供的命令行工具集执行。

项目设置

如要创建默认的 Android 项目,当出现命令提示符时执行下列命令。

android 创建项目 --target <TID> \
--name <ProjName> \
--path <FolderPath> \
--activity <ActivityName> \
--package <Package>

注:具体的目标 ID 将取决于如何配置 Android SDK。 出现命令提示符时通过运行android list targets检索可用目标列表。

下列设置将用于该项目:

--name DemoProject
--activity DemoProjectActivity
--package demo.project

Android 实用程序生成的项目是默认的“Hello World”项目。 在项目的根目录中时,如果出现命令提示符,通过运行ant debug来确认项目是否正常初始化。

添加 OpenGL ES 支持

Android 可直接向 Java 曝露 OpenGL ES API 以便应用开发人员使用。 我们将使用设置 OpenGL 的分类和方法来利用 Java API 或执行原生渲染。

因此,我们将会预先讨论使用 Java API 渲染简单场景的详细情况。 接下来,我们将会对示例应用进行修改以使用原生渲染。

卸载标题栏

运行 Hello World 应用时,该应用的标题栏在运行中可见。 一般而言,这种运行状况在编写 OpenGL ES 应用时不需要。

通过在 AndroidManifest.xml 文件中添加适当的活动标记主题属性可禁用该运行状况。

android:theme=�@android:style/Theme.NoTitleBar.Fullscreen�

或者,也可以在活动类的 onCreate 方法内运行下列代码。

requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

更换默认视图

Hello World 项目使用了 setContentView 的超载,向 XML 资源中添加了资源标识符以压缩并设置为当前的活动视图。 必须使用能够渲染 OpenGL ES 文本的视图接口来更换该操作。 Android 可提供 Java 类 GLSurfaceView,它可以压缩渲染接口和 EGL 显示。

您可以将 “res/layout/main.xml”文件从项目中删除,因为该视图可通过编程方式创建。

GLSurfaceView

适用于 GLSurfaceView 的两种导入方法是 setEGLContextClientVersion 和 setRenderer。

setEGLContextClientVersion 方法可设置需要使用的 ES 版本。 对于该项目,我们使用了 OpenGL ES 2.0。

渲染至环境由从 GLSurfaceView.Renderer 继承的类实例来控制。渲染器示例通过调用 setRenderer 方法来设置。

必须将 Activity 类的 onPause 和 onResume 覆盖才能够在 GLSurfaceView 类上分别调用方法来暂停/恢复渲染线程。

下列是完整的包含 GLSurfaceView 的 DemoActivity 类:

public class DemoActivity extends Activity
{private GLSurfaceView view;@Overridepublic void onCreate(Bundle savedInstanceState)
{super.onCreate(savedInstanceState);view = new GLSurfaceView();// Tell EGL to use a ES 2.0 Contextview.setupEGLContextClientVersion(2);// Set the rendererview.setRenderer(new DemoProjectRenderer());setContentView(view);}@Overrideprotected void onPause()
{super.onPause();view.onPause();}@Overrideprotected void onResume()
{super.onResume();view.onResume();}
}

GLSurfaceView.Renderer

从 GLSurfaceView.Renderer 继承的类负责向 OpenGL 环境中绘制。 GLSurfaceView.Renderer 曝露了三种必须在继承的类中执行的摘要方法: onSurfaceCreated、onSurfaceChanged 和 onDrawFrame。

Android 应用暂停或挂起时,OpenGL 环境以及所有与其相关的资源都将被破坏。 因此,针对应用的初始化和资源加载应在 onSurfaceCreated 功能中处理。

注:有一种方法 — setPreserveEGLContextOnPause — 可以让 EGL 跨越暂停/恢复界限来尝试和保存环境。 但是请注意,这种功能依赖于硬件对多 EGL 环境的支持,因此,调用它并不能确保一定将环境保存。

演示项目将使用 Java OpenGL ES API 来清除颜色缓冲区的品红色。

针对演示项目从 GLSurfaceView.Renderer 得出的类如下所示:

class DemoProjectRenderer implements GLSurfaceView.Renderer
{public void onDrawFrame(GL10 gl)
{gl.glClear(gl.GL_COLOR_BUFFER_BIT);}public void onSurfaceChanged(GL10 gl, int width, int height)
{       gl.glViewport(0, 0, width, height);}public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
gl.glClearColor(1.0f, 0.0f, 1.0f, 1.0f);}
}

AndroidManifest.xml

清单文件应通过在清单元素下添加下列 XML 元素来指定对 OpenGL ES 2 的需求。

<uses-feature android:glEsVersion=``0x00020000'' android:required=``true'' />

迁移至原生渲染

无需重新实现现有的代码部分来使用 Java 接口,可以通过从 Java 类调用原生代码来利用现有的 C/C++ 代码库。 原生代码已编译至共享库,并使用 APK 文件部署。

所有的原生代码都位于项目根目录中的 jni 文件夹下。

JNI 基础

原生代码通过 JNI 框架曝露至 Java 各类。 如欲了解 JNI 框架的具体解释,请参阅http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html。

必须在载入程序中遵守 JNI 命名规则,以便能够正确找到原生方法。 所有的原生方法:

  • 必须以前缀Java_开始
  • 然后使用完全限定的 mangled 类名
  • 然后使用完全限定的 mangled 方法名

例如,以下是一个简单的原生 C 函数:

void nativeLibraryFunction(int width, int height);

如要在不修改现有函数的情况下将该方法暴露至 Java 代码,请加入 JNI 头文件并创建可调用现有原生方法的封装方法。

#include <jni.h>
JNIEXPORT void JNICALL Java_demo_project_LibraryClass_LibraryFunctionWrapper(JNIEnv* env, jobject obj, jint width, jint height)
{
nativeLibraryFunction(width, height);
}

上述函数假定面向项目的软件包是 demo.project,并将使用名为 LibraryClass 的 Java 类来暴露原生函数。

在所有导出的 JNI 函数中第一个参数属于“JNIEnv*.”类型。该参数有多种功能,其中最重要的是支持原生代码回调至 Java 代码。 本文中暂不讨论这种运行状况。

对于静态函数, jobject 参数是调用 Java 类的参数。

其他的参数类型从 JNI 框架暴露。 对于内置 C 类型,JNI 框架可自动控制转换。 对于阵列和复杂的类型,请参考文档。

在 Java 端上必须导入共享库。 这可通过调用至 System.loadLibrary 来实现。这一般在面向该类的静态初始化器中完成。

此外,类必须声明适用于导出方法的接口。 这些方法为静态,并声明为本地。

class LibraryClass
{
static
{
System.loadLibrary("demo");
}
public static native void LibraryFunctionWrapper(int width, int height);
}

重要的一点是,LibraryClass 名称与导出的原生方法暴露的名称一致。 此外,需要将导出的功能的定义标记为本地。

此处,库应遵守目标平台上的共享库规则。 对于基于 Unix 的目标(如 Android),库名称应以 “lib”为前缀并附加 “.so”。 对于基于 Windows* 的目标,应附加扩展名“dll”。

注:对于复杂的函数声明,Java 可提供实用程序 javah,为原生函数生成头文件定义(考虑到 Java 类文件)。

现在,您可从代码中的任何位置将该方法调用为静态 Java 方法。 对于具体的示例,DemoProject 现可迁移至原生渲染。

迁移初始化代码

在项目 jni 文件夹中创建 C 文件。 此处,该文件为“nativelibrary.c.”。

文件将会使用所有的原生 OpenGL ES 调用。

void InitializeOpenGL()
{glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
}
void resizeViewport(int newWidth, int newHeight)
{glViewport(0, 0, newWidth, newHeight);
}
void renderFrame()
{glClear(GL_COLOR_BUFFER_BIT);
}

假定这些方法已存在于项目或静态库中。 如要使用这些方法 JNI,需要为这三种方法中的每一种方法创建 JNI 封装方法。 这些方法可采用另一种 C 文件 jniExports.c。

JNIEXPORT void JNICALL Java_demo_project_SomeClass_init(JNIEnv*)
{InitializeOpenGL();
}
JNIEXPORT void JNICALL Java_demo_project_SomeClass_resize(JNIEnv*, jint width, jint height)
{resizeViewport(width, height);
}
JNIEXPORT void JNICALL Java_demo_project_SomeClass_render(JNIEnv*)
{renderFrame();
}

在 Java 端上,导出的方法在库类中被声明。

class LibraryClass
{static
{System.loadLibrary("demo");}public static native void init();public static native void resize(int width, int height);public static native void render();
}

现在,GLSurfaceView.Renderer 派生类已进行了修改以调用原生方法:

class DemoProjectRenderer extends GLSurfaceView.Renderer
{public void onDrawFrame(GL10 gl)
{LibraryClass.render();}public void onSurfaceChanged(GL10 gl, int width, int height)
{LibraryClass.resize(width, height);}public void onSurfaceCreated(GL10 gl, EGLConfig config)
{LibraryClass.init();}
}

配置原生 Build

Android.mk

在 “jni”文件夹中,创建了 “Android.mk”文件以指导 NDK 编译原生模块。 在粒子示例项目中使用的示例 Android.mk 如下所示:

# Tell Android where to locate source files
# "my-dir" is a macro function which will return the path of the current
directory(where Android.mk resides)
LOCAL_PATH := $(call my-dir)# Clear contents of the LOCAL_* variables
include $(CLEAR_VARS)# All the source files to include in this module
LOCAL_SRC_FILES := nativeLibrary.c \jniExports.c # The name of the module
LOCAL_MODULE := libdemo# Compilation flags
LOCAL_CFLAGS := -Werror# Static libraries to link with
LOCAL_LDLIBS := -llog –landroid -lGLESv2# Build the module
include $(BUILD_SHARED_LIBRARY)

从命令提示符运行ndk-build命令以构建共享库。 这一步应在使用 ant 构建 Android 应用之前完成。

读取 APK 中的资产

访问资产是迁移至本地渲染需要特别关注的一个领域。 资产管理器从 Java 传送至原生代码。 例如,在活动 onCreate 方法中,添加了下列代码行:

@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

assetManager = getAssets();
LibraryClass.initializeAssetManager(assetManager);

view = new GLSurfaceView();

// Tell EGL to use a ES 2.0 Context
view.setupEGLContextClientVersion(2);

// Set the renderer
view.setRenderer(new DemoProjectRenderer());

setContentView(view);
}

JNIEXPORT void JNICALL Java_demo_project_LibraryClass_initializeAssetManager(JNIEnv* env, jobject obj, jobject assetManager)
{
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
}

AAssetManager_fromJava 函数由 NDK 提供,可获取原生指针至资产管理器实例。 APK 中存储的资产可通过 AAssetManager API 访问。 关于使用 AAssetManager API 读取文件的示例,请参阅粒子示例源代码中的 util/file.c。

粒子示例代码

上述文本详细介绍了在 Android 平台上启用原生 OpenGL ES 工作负载的一套基础步骤。 如欲了解更完整的示例,适用于原生 OpenGL ES 2.0 粒子系统源代码可通过http://software.intel.com/en-us/articles/Android-code-samples获得。 与文档相关的源代码部分将在下文中进行介绍。

ParticlesActivity.java

本类储存了主要的应用活动。 它负责创建 GLSurfaceView 派生类,以及通过调用 createAssetManager 将应用的资产管理器传送至原生 C 代码。

ParticlesView.java

在粒子示例中,从 GLSurfaceView 中继承了一个明确的类来设置 OpenGL ES 客户端版本。 此外,接口渲染作为内部类来实现。

ParticlesLib.java

本类可导入共享库并声明示例使用的三种原生方法: init、step 和 createAssetManager。

Shared Library Code

示例中使用的共享库的代码位于 jni 目录下。

导出的 C 函数钩子位于 jni/gl_code.cpp 中。它们可暴露初始化、帧步骤和资产创建函数。 这些方法的实现位于 jni/App.c 中。

示例中使用的粒子系统位于 jni/Particles.c and jni/Particles.h 中。

位于示例中的其他文件是适用于数学函数、简单几何创建和纹理加载的实用程序方法。 该代码位于 jni/util 目录下。

值得特别关注的一个文件是读取资产数据的简单实用程序函数,它可在 util/file.c 中找到。

关于作者

Chris Kirkpatrick 是就职于英特尔软件与服务事业部的软件应用工程师,在个人设备外形(Personal Form Factors)部提供英特尔显卡解决方案支持。 他拥有俄勒冈州立大学计算机科学学士学位。

声明

本文件中包含关于英特尔产品的信息。 本文件不构成对任何知识产权的授权,包括明示的、暗示的,也无论是基于禁止反言的原则或其他。 英特尔不承担任何其他责任。英特尔在此作出免责声明:本文件不构成英特尔关于其产品的使用和/或销售的任何明示或暗示的保证,包括不就其产品的(i)对某一特定用途的适用性、(ii)适销性以及(iii)对任何专利、版权或其他知识产权的侵害的承担任何责任或作出任何担保。

除非经过英特尔的书面同意认可,英特尔的产品无意被设计用于或被用于以下应用:即在这样的应用中可因英特尔产品的故障而导致人身伤亡。

英特尔有权随时更改产品的规格和描述而毋需发出通知。 设计者不应信赖任何英特产品所不具有的特性,设计者亦不应信赖任何标有“保留权利”或“未定义”的说明或特性描述。 对此,英特尔保留将来对其进行定义的权利,同时,英特尔不应为因其日后更改该等说明或特性描述而产生的冲突和不相容承担任何责任。 此处的信息可能随时更改,恕不另行通知。 请勿使用本文信息完成一项产品设计。

本文件所描述的产品可能包含使其与宣称的规格不符的设计缺陷或失误。 这些缺陷或失误已收录于勘误表中,可索取获得。

在发出订单之前,请联系当地的英特尔营业部或分销商以获取最新的产品规格。

索取本文件中或英特尔的其他材料中提的、包含订单号的文件的复印件,可拨打1-800-548-4725,或登陆http://www.intel.com/design/literature.htm

在性能检测过程中涉及的软件及其性能只有在英特尔微处理器的架构下方能得到优化。 诸如SYSmark和MobileMark等测试均系基于特定计算机系统、硬件、软件、操作系统及功能。 上述任何要素的变动都有可能导致测试结果的变化。 请参考其他信息及性能测试(包括结合其他产品使用时的运行性能)以对目标产品进行全面评估。

对本文件中包含的软件源代码的提供均依据相关软件许可而做出,任何对该等源代码的使用和复制均应按照相关软件许可的条款执行。

英特尔和 Intel 标识是英特尔在美国和/或其他国家的商标。

OpenGL 是注册商标,OpenGL ES 标识是 Silicon Graphics Inc. 的注册商标,需获 Khronos 的许可方能使用。

英特尔公司© 2013 年版权所有。 保留所有权利。

*其他的名称和品牌可能是其他所有者的资产。

在 Android* 平台上设置原生 OpenGL ES*相关推荐

  1. Android Camera API 2使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜)

    这段时间有点忙,一直没时间写第三篇教程,其实代码很早之前就写好了.本系列教程会有三篇文章讲解Android平台滤镜的实现方式,希望在阅读本文之前先阅读前面两篇文档. 第一篇 Android Camer ...

  2. Freeline - Android平台上的秒级编译方案

    Freeline 技术揭秘 Freeline是什么? Freeline是蚂蚁金服旗下一站式理财平台蚂蚁聚宝团队15年10月在Android平台上的量身定做的一个基于动态替换的编译方案,5月阿里集团内部 ...

  3. MVP在Android平台上的应用

    2019独角兽企业重金招聘Python工程师标准>>> MVP在Android平台上的应用 原文链接 : Introduction to Model-View-Presenter o ...

  4. cocos2d js调用java_【cocos2d-js官方文档】二十四、如何在android平台上使用js直接调用Java方法...

    在cocos2d-js 3.0beta中加入了一个新特性,在android平台上我们可以通过反射直接在js中调用java的静态方法.它的使用方法很简单: var o = jsb.reflection. ...

  5. cocos2dx在Android studio运行 以及在 Android 平台上使用 JavaScript 直接调用 Java 方法

    cocos2dx在Android studio运行 以及在 Android 平台上使用 JavaScript 直接调用 Java 方法 cocos2dx在Android studio运行 使用Andr ...

  6. Android 平台下的原生 Markdown 解析器

    Markdown 项目地址:zzhoujay/Markdown 简介:Android 平台下的原生 Markdown 解析器 Android 平台的原生 Markdown 解析器,已整合进 RichT ...

  7. Android平台上集成萤石SDK

    这篇文章,就Android平台上如何集成萤石SDK进行讲解. 前言: 萤石是海康威视集团旗下的一家做视频云的公司.我们接入萤石设备,实现实时预览.远程回放.抓图.切换画质等功能. 关于具体如何接入,包 ...

  8. Android平台上集成海康SDK(二)

    Android平台上集成海康SDK 以上是我之前写的一篇Android平台上集成海康SDK的文章,其中对于Android平台上集成海康SDK.基于海康SDK进行二次开发基本上进行了详细地介绍. 这篇文 ...

  9. Android平台上实现身份证识别(通过阿里云Api-印刷文字识别_身份证识别)

    Android平台上实现身份证识别(通过阿里云Api-印刷文字识别_身份证识别) 一: 前言 继上一篇文章有段时间了,上一篇文章的身份证和银行卡的识别时通过本地的opencv库,tess-two库识别 ...

最新文章

  1. 算法:枚举法---kotlin
  2. tf.broadcast_dynamic_shape
  3. 编程笔试(解析及代码实现):求出一个整数中各位数上所包含全部质数之和
  4. 菜鸟弹性调度系统的架构设计——阅读心得
  5. oracle ora-22288,向oracle的blob字段导入文件
  6. 微课|中学生可以这样学Python(5.7节):序列解包
  7. centos设置启动mysql,Centos设置开机启动Apache和Mysql
  8. javaweb java代码写在哪里_写了那么多年 Java 代码,终于 debug 到 JVM 了
  9. ROS-3DSLAM(4):lidar_odometry包浅析
  10. 最新 Transformer 预训练模型综述!
  11. 关于IE7半透明背景问题
  12. linux安装ps软件教程,如何在Linux上安装Adobe Photoshop | MOS86
  13. 计算机想ping一下网络,怎么ping网速(详细教您ping网络的方法)
  14. 算法策略 | MACD跨周期短线交易策略开发(股指+商品双版)
  15. android 图片画圆,在Android中画圆形图片的几种办法
  16. Jmeter:java.net.URISyntaxException: Illegal character in fragment at index XX问题解决方法
  17. 常见的三种字符编码ASCII、Unicode、UTF-8
  18. 微软发布Win11 2022最大更新22H2 版本号为 22621.521
  19. win7怎么关闭计算机的预览,win7系统工具栏预览功能怎么关闭?win7关闭工具栏预览功能的详细步骤...
  20. linux arm关闭光栅,基于Linux的光栅检测系统的软件设计与实现.pdf

热门文章

  1. haproxy acl访问限制IP
  2. 转:浅析C++中的this指针
  3. js 对象及空对象或数组及空数组的判断与比较
  4. vue.js的学习中的简单案例
  5. Android反编译方法
  6. bash的快捷键、特殊参数、历史命令、相关文件
  7. phalcon:model 事件与事件管理器
  8. CodeForces 706A Beru-taxi
  9. Android开发自定义View之滑动按钮与自定义属性
  10. css之左边div固定宽度右边div自适应布局