3 OpenGL样例结构分析
运行OpenGL样例之后,需要进一步分析样例中代码,才能更好地理解样例的工作机制。在开发环境中打开包“com.rim.samples.device.opengldemo”,可以看到其中有五个类,分别是Cube、CubeRenderer、OpenGLDemo、OpenGLScreen和Renderer。另外,在目录“res\img”中还有两个图像文件,BlackBerry.png和icon_jde.png,分别用于纹理帖图和应用图标。
图像文件的作用比较简单,BlackBerry.png作为纹理帖图使用,旋转立方体表面的BlackBerry图标就是通过对BlackBerry.png文件的处理实现的;icon_jde.png用作应用的图标,使应用在“Downloads”目录中显示时可以显示成一个灰色的窗口图标。
开发人员需要详细了解的是Cube、CubeRenderer、OpenGLDemo、OpenGLScreen和Renderer这五个类,和它们之间的关系。其中Renderer是定义的接口,CubeRenderer是Renderer接口的具体实现,所以Renderer接口基本不需要关注。
对于Cube、CubeRenderer、OpenGLDemo、OpenGLScreen四个类。首先可以明确的是OpenGLDemo是程序的入口,OpenGLScreen是程序进入后所显示的屏幕,这种结构对于BlackBerry开发人员来讲是非常熟悉的。然后Cube是3D模型的定义,CubeRenderer负责从Cube中获取数据,然后将数据进行转换和显示。
然而,在OpenGLDemo中,程序并没有完全按照常见的BlackBerry方式运行,对于刚接触的开人员而言可能会有一些困扰。为了更好地理解OpenGLDemo程序的运行过程,我们通过一个时序示意图来说明OpenGLDemo的初始化过程。如图18-4:
图18-4 OpenGLDemo应用的初始化过程
OpenGLDemo应用程序的初始化过程如下:
1. OpenGLDemo应用程序以OpenGLDemo类作为入口,在该类的静态main方法里新建了一个OpenGLDemo实例。
2. 在OpengLDemo的构造函数里首先判断当前设备是否支持OpenGL,如果不支持OpenGL则弹出对话框提示用户并退出应用程序,如果支持OpenGL才继续执行初始化过程。
3. 在设备支持OpenGL情况下创建一个OpenGLScreen实例。
4. 在创建OpenGLScreen实例的过程中创建了一个CubeRender实例。
5. 将第3步创建的OpenGLScreen实例显示出来。
6. 调用OpenGLDemo的EnterEventDispatcher()方法进行事件循环。
OpenGLDemo应用程序初始化的主要代码在OpenGLDemo类的构造函数OpenGLDemo()中,具体代码见代码清单18-1。
代码清单18-1
public OpenGLDemo()
{
// 检查当前设备是否支持OpenGL
if(GLUtils.isSupported())
{ // 如果支持OpenGL则新建OpenGLScreen实例并显示该实例
OpenGLScreen screen = new OpenGLScreen(new CubeRenderer());
pushScreen(screen);
}
else
{ // 如果不支持OpenGL则弹出对话框提示用户并退出应用
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("This device does not support OpenGL, exiting OpenGL Demo application...");
System.exit(0);
}
});
}
}
从初始化过程上看,这个应用程序的基本运行框架和普通BlackBerry程序没有太大差别,其中有一个细节上的差别是在OpenGLScreen初始化过程中没有在Screen中加入子元素。OpenGLScreen的构造函数的具体代码如代码清单18-2,在这个函数中除了调用父类的构造函数和保存CuberRender实例以外并没有做其它工作。
但是这个细小的差别所带来的影响却很大,熟悉BlackBerry程序运行机制的开发人员会意识到,这个程序运行后屏幕上不会显示任何内容。一般的BlackBerry程序会在Screen的构造函数里加入字段、按钮、菜单等元素,程序通过字段显示内容,用户通过按钮或者是菜单与程序交互。那么,在OpenGLDemo应用程序中,OpenGLScreen显示出来之后不显示任何内容,样例中显示的立方体是如何出现的呢?要回答这个问题需要进一步分析OpenGLScreen的其它方法。
代码清单18-2
public OpenGLScreen(Renderer renderer)
{
super(FullScreen.DEFAULT_MENU | FullScreen.DEFAULT_CLOSE);
_renderer = renderer;
}
为了在合适的时机启动立方体的显示线程,样例开发人员实现了OpenGLScreen的onVisibilityChange()方法,该方法在程序的可视情况发生变化时会被系统调用,如点击图标打开程序时系统会调用这个方法,程序被置于后台时系统也会调用这个方法。该方法首先判断程序是进入可视状态还是进入不可视状态。如果进入可视状态的话进一步判断后台线程是否已经运行,确定后台线程没有运行的话会调用start()方法启动后台线程,如果后台线程之前曾经启动,则调用resume()方法让后台线程从暂停状态进入重新运行状态。如果程序进入不可视状态,则调用pause()方法让后台线程进行暂停状态。onVisibilityChange()方法的具体代码如代码清单18-3。
代码清单18-3
protected void onVisibilityChange(boolean visible)
{
if (visible)
{
if (!_running)
{ start(); }
else
{ resume(); }
}
else
{ pause(true); }
}
onVisibilityChange()方法中最关键的就是调用start()方法, start()方法完成了OpenGL环境的初始化工作,创建一个后台线程并进入该线程的循环状态,开始不断地对3D模型进行更新和显示。调用start()方法的主要过程如图18-5。
图18-5 调用start()方法启动后台线程
Start()方法调用的具体过程如下:
1. 当程序的可视状态发生变化时系统调用了OpenGLScreen实例的onVisibilityChange()方法。
2. 如果程序进入可视状态,同时后台线程之前没有启动过,则调用OpenGLScreen实例的start()方法开始创建并启动后台线程。
3. 创建OpenGLScreen的一个新实例,并以OpenGLScreen为主体创建和启动一个新的线程。因为OpenGLScreen类本身实现了Runnable接口, 所以它可以作为一个线程开始运行。为了更直观的说明程序运行过程,时序图中将新的OpenGLScreen线程作为一个新的实例放在CubeRenderer实例右方。
4. OpenGLScreen的run()方法开始执行,调用了initializeEGL()方法对OpenGL环境进行初始化工作。
5. 在initializeEGL()方法中创建了一个EGL11实例。
6. 通过对EGL11实例的操作完成各种初始化工作,包括EGLSurface,EGLContext和EGLDisplay的初始化工作。
7. 通过EGLContext获得了GL10实例。
8. 完成OpenGL 环境的初始化工作后调用了CubeRenderer实例的initialize()方法对CubeRenderer进行初始化工作。
9. CubeRenderer实例的initialize()方法主要内容就是调用Cube类的不同静态方法获得Cube类中对立方体模型的定义数据,包括顶点数组、法向量数组和帖图参数数组。调用之后Cube类就不起什么作用了。有关顶点数组和法向量数组等在以后的小节会进一步讨论。
10. 从第10步开始进入了while循环,只要程序仍处于可视状态,就一直重复第10步到第14步的动作。第10步完成的工作是调用CubeRenderer的update()方法,让立方体转动一定的角度。
11. 转动立方体后调用OpenGLScreen的renderFrame()方法开始绘制立方体。
12. renderFrame()方法调用了CubeRenderer的render()方法对立方体模型进行绘制。
13. 在CubeRenderer的render()方法中通过对GL10实例的操作在缓存中完成立方体模型的绘制,这一步是OpenGLDemo程序的关键,开发人员可以修改这里的代码完成自己的3D绘制。
14. CubeRenderer的render()方法是在缓存中完成了立方体的绘制,并没有真正显示到屏幕上。要将缓存中绘制好的内容显示出来,需要调用 eglCopyBuffers()或者是eglSwapBuffers()方法。两者的作用有所不同。eglCopyBuffers的作用是将缓存中的图像拷贝出来,保存到指定的变量中以供使用,而eglSwapBuffers的作用是直接将缓存切换到绑定的屏幕中。所以,程序在调用eglCopyBuffers或者是eglSwapBuffers方法之前先判断应用处于什么状态。如果处于停顿状态,比如用户点击菜单键显示了菜单,这时屏幕中的3D图形不再转动,则程序调用eglCopyBuffers方法将缓存中的图像拷贝出来保存在一个变量中,由OpenGLScreen的paint方法将这个变量中的图像显示到屏幕上。如果处于正常运行状态,则程序直接调用eglSwapBuffers方法将缓存中的内容显示出来。使用这种策略的目的是在应用处于停顿状态时停止后台的3D计算,以节省CPU使用量。同时,为了保证应用切换后依然可以显示正确的图像(比如3D图像停止转动后用户接了一个电话,在电话结束时切换回本应用),程序将最后一帧静止的图像保存下来,一旦屏幕需要刷新则显示该图像。
15. 只有跳出while循环以后才能运行到这一步, 这一步的工作是调用OpenGLScreen的unloadEGL()方法完成OpenGL环境的清理工作。
OpenGLDemo样例中的环境初始化,立方体旋转,立方体绘制,还有绘制结果的显示都发生成后台OpenGLScreen线程中。所以其关键代码在OpenGLScreen类的run()方法中,基本框架如代码清单18-4。
代码清单18-4:
public void run()
{
// 刚开始运行的时候休眠一小段时间让前台Screen完成初始化的工作
try
{ Thread.sleep(250); }
catch (InterruptedException ie)
{ }
try
{
// 调用initializeEGL()方法对OpenGL环境进行初始化工作
initializeEGL();
// 调用CubeRenderer的initialize()方法载入立方体模型的数据。
_renderer.initialize();
int throttle = 0;
// 进入while循环,直到_running变量被主线程置为false。
while (_running)
{ // 记录当前时间
throttle = (int)System.currentTimeMillis();
// 调用CubeRenderer的update()方法让立方体转动
_renderer.update();
// 对立方体进行绘制
renderFrame();
if (_idle)
{
// 将进入暂停状态,将EGLSurface中的内容拷贝到_backBuffer中
// 保存起来,在主屏幕Screen的update方法中直接使用
//_backBuffer中保留的图像。
_egl.eglCopyBuffers(_eglDisplay, _eglSurface, _backBuffer);
//其它代码省略……
}
else
{
// 一般状态,将_eglSurface中的内容显示到屏幕上。
_egl.eglSwapBuffers(_eglDisplay, _eglSurface);
//其它代码省略……
}
}
//跳出循环后清除EGL环境
unloadEGL();
}
catch(final Exception e)
{ //异常处理,当出现异常时提醒用户并退出程序。
Application.getApplication().invokeAndWait(new Runnable()
{
public void run()
{
Dialog.alert(e.toString());
}
});
System.exit(1);
}
}
分享到:
相关推荐
1.解压BaiduInput_blackberry_v1.0.0.7.zip文件,用黑莓桌面管理器加载baiduinput.alx,在安装时务必把默认的四个选项都打上勾。 2.安装完毕后会在出现一个百度记事本和一个百度输入法图标。 3.百度记事本是用在第三...
##Supported 平台本书中的示例代码可用于以下平台: 苹果手机(Microsoft Visual Studio) 使用 AMD OpenGL ES 2.0 Emulator 或 PowerVR Khronos OpenGL ES 2.0 SDK WebGL 安卓 2.2+ Linux 黑莓##iPhone ###...
源码非常齐全,Android、iOS、BlackBerry、LinuxX11,Windows,WebGL全平台同步代码
opengl es 2.0 programming guide source code, including android blackberry iphone linux11 webgl windows
Google Sync现在支持blackberry,iPhone、Windows Mobile手机,稍后会支持其他类型的手机,使用Google Sync后,系统会自动同步用户的Gmail联系人、Google Calendar时间到你的手机中,Sync使用Push技术,你在通讯录...
在黑莓上使用的农历软件,适用所有型号。如:9000
MiniExcel,黑莓上使用的excel工具. MiniExcel,黑莓上使用的excel工具.
黑莓新注566个域名:98系列杂米近500个.docx
Blackberry黑莓PRIV使用说明书.pdf
•2009年4月1日在美国、加拿大和英国发布 •2009年7月31日扩展至另外10个国家 •法语、意大利语、德语和西班牙语的本地化支持 •2009年秋季扩展至拉美和亚太地区 •巴西西班牙语的本地化支持 •2010年4月发布...
(TTS) 样例BlackBerry 10应用程序演示了如何通过Read Out集成语音合成(TTS)! (TTS) 该示例应用程序包含此博客文章中的所有代码片段,并将其放入工作示例应用程序中: : 执照MIT许可证(MIT) 版权所有(c)...
Learn BlackBerry Games Development Paperback: 504 pages Publisher: Apress; 1 edition (March 30, 2010) Language: English ISBN-10: 1430227184 ISBN-13: 978-1430227182 Format: PDF You can buy this book: ...
BlackBerry 平台的加密机制 BlackBerry 平台自身带有完整的加密机制。所有数据从BES(BlackBerry Enterprise ...BlackBerry 平台上,从BES 服务器端到BlackBerry 智能手机端都是受平台的加密保护的。其 架构如下图:
黑莓BlackBerry主题制作使用教程 Just Theme It! - BlackBerry 主题制作指南
主分支在GitHub上使用OpenGL ES 2.0渲染,而旧版gles11分支则使用OpenGL ES 1.1渲染。 支持iOS、Android、Windows Phone 8、Bada、BlackBerry、Marmalade、Windows、Linux等多个平台。支持C++、Lua、JavaScript编程...
老黑莓OS经典软件合集大全,独家整理,适合黑莓blackberry 7XXX 8XXX 9XXX等黑莓老机型,格式为cod , alx,jad等格式;;怀旧经典,软件清单如下 Twitter70.zip WacaiBlackberry.zip [BerryCN.com_DZH_v5.18] XECurrency-...
7290 bb blackberry黑莓7290 bb blackberry黑莓7290 bb blackberry黑莓7290 bb blackberry黑莓7290 bb blackberry黑莓7290 bb blackberry黑莓7290 bb blackberry黑莓7290 bb blackberry黑莓7290 bb blackberry黑莓...
首先,你需要有最新的Java...使用“完整”这个安装选项可以安装整个文档、代码样例和程序文件,同时也安装了客户端和服务器的模拟器。当你将应用程序下载到BlackBerry(黑莓)设备后,你就能用客户端模拟器进行测试了。
MobileSSH,黑莓上使用的SSH客户端工具,在windows或者linux服务器上安装好SSH Server,然后就可以使用你的BB来远程控制它了,是不是很酷?
如果要确保应用程序使用uses BlackBerry MDS Services 作为它的连接路径,需要在 URL 最后加上参数“deviceside=false”,这也是我们推荐的方式,如下: 例2: (HttpConnection)Connector.open(...