分析了“HelloWorldConsole”样例和PlayBook NDK的事件处理机制后让我们来看看PlayBook NDK中的第二个样例“HelloWorldDisplay”。
样例“HelloWorldDisplay”就是之前NDK Beta中的“HelloWorld”样例,之前的博文也介绍过,程序启动后在屏幕上显示一张底图和“HelloWorld”字样。
既然我们已经开始理解PlayBook NDK上的事件处理机制,就让我们更深入看看“HelloWorldDisplay”的代码。
“HelloWorldDisplay”项目中有main.c,bbutil.h,bbutil.c三个文件,其中bbutil.h和bbutil.c文件中提供了一些工具函数,用于实现一些具体的工作,本文先不作详细介绍,这里主要先看看main.c中的代码。
从main.c中的main函数开始,开始首先是对PlayBook屏幕环境的初始化,代码如下:
screen_create_context(&screen_cxt, 0);
函数screen_create_context是在头文件<screen/screen.h>中声明的,用于初始化PlayBook得屏幕环境,对于需要图形界面的程序这一步都是需要的。
其中的参数是指向screen_cxt的指针,而screen_cxt在main.c文件开头进行了声明,声明如下:
static screen_context_t screen_cxt;
初始化屏幕后就需要进行BPS的初始化工作,主要是为了后面的事件处理。如之前的博文提到的,BPS初始化工作通过调用bps_initialized()函数完成,代码如下:
bps_initialize();
完成了BPS的初始化工作后开始为屏幕设置egl,完成egl初始化工作,启动openGL。
egl的初始化过程比较复杂,样例中这些代码被放在bbutil.c中进行定义,在main.c中就简单调用bbutil_init_egl()函数完成。这里不详细讲述egl的初始化过程,有兴趣的同学可以打开bbutil.c文件仔细看看。
bbutil_init_egl()函数的调用代码如下,调用完成后会对调用结果进行判断,如果调用失败则对screen_cxt进行释放。
if (EXIT_SUCCESS != bbutil_init_egl(screen_cxt)) { fprintf(stderr, "Unable to initialize EGL\n"); screen_destroy_context(screen_cxt); return 0; }
进一步是样例本身的初始化工作,主要是加载字体,并定义顶点数组和纹理坐标数组,所有初始化代码放在main.c的init()函数中。
//Initialize app data if (EXIT_SUCCESS != init()) { fprintf(stderr, "Unable to initialize app logic\n"); bbutil_terminate(); screen_destroy_context(screen_cxt); return 0; }
然后是调用navigator_rotation_lock()函数锁定屏幕,不响应PlayBook方向变化的动作。
接着通过screen_request_events()函数和navigator_request_events()函数向BPS请求屏幕事件和“Navigator”事件。这两部分的代码是该样例事件处理的重要部分。
//Signal BPS library that navigator orientation is to be locked if (BPS_SUCCESS != navigator_rotation_lock(true)) { fprintf(stderr, "navigator_rotation_lock failed\n"); bbutil_terminate(); screen_destroy_context(screen_cxt); return 0; } //Signal BPS library that navigator and screen events will be requested if (BPS_SUCCESS != screen_request_events(screen_cxt)) { fprintf(stderr, "screen_request_events failed\n"); bbutil_terminate(); screen_destroy_context(screen_cxt); return 0; } if (BPS_SUCCESS != navigator_request_events(0)) { fprintf(stderr, "navigator_request_events failed\n"); bbutil_terminate(); screen_destroy_context(screen_cxt); return 0; }
已经完成初始化工作后就进入事件循环,在事件循环中通过bps_get_event()函数获取事件,如果事件获取成功则对事件进行处理。本例对事件的处理很简单,只响应退出事件,当退出事件发生时跳出事件循环。
事件处理完成后调用render()函数完成屏幕绘制工作,所有绘制工作在main.c的update()函数中完成,主要是通过openGL的相关函数展现顶点数组对应的矩形,同时显示纹理。
有关如何通过openGL显示图形我们在之后的文章中继续讨论。
这里还要注意一点的是调用bps_get_event时使用了0为参数,意味着如果没有事件发生,程序不会阻塞,而会继续运行。也就是说该样例一直在重画屏幕上显示的内容,虽然我们看见的只是一张静态的底图和“Hello World”字样。
for (;;) { //Request and process BPS next available event bps_event_t *event = NULL; rc = bps_get_event(&event, 0); assert(rc == BPS_SUCCESS); if ((event) && (bps_event_get_domain(event) == navigator_get_domain()) && (NAVIGATOR_EXIT == bps_event_get_code(event))) { break; } fprintf(stderr,"Trying to render \n"); render(); }
如果退出事件发生,程序会跳出事件循环继续执行下面的资源释放代码:
//Stop requesting events from libscreen screen_stop_events(screen_cxt); //Shut down BPS library for this process bps_shutdown(); //Destroy the font bbutil_destroy_font(font); //Use utility code to terminate EGL setup bbutil_terminate(); //Destroy libscreen context screen_destroy_context(screen_cxt); return 0;
通过对“HelloWorldDisplay”样例的分析我们可以完整地看到一个PlayBook NDK应用程序的运行过程,包括应用的初始化,事件循环和资源释放三个重要的部分。
有关如何使用OpenGL在PlayBook上进行绘图,我们后面继续讨论。