凌乱的舞台
在 Clutter 场景中显示 PDF 页面

五个演员

Garfileo posted @ 2011年7月16日 17:15 in Clutter 笔记 with tags clutter cairo , 4354 阅读

这篇文章的标题并非暗示我要写一篇影视娱乐方面的文章,它只是表示我将“Actor”这个英文单词翻译成了中文。本文主要介绍 Clutter 库提供的五个基本的 Actor 的用法。

矩形

ClutterRectangle [1] 的主要功能是在 Stage 上显示一个有边框可填充的的矩形。看下面的示例:

#include <clutter/clutter.h>

int
main(int argc, char *argv[])
{
        if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
                return 1;
        
        ClutterColor stage_color       = { 0x21, 0x43, 0x5e, 0xff };
        ClutterColor rect_area_color   = { 0xff, 0xe6, 0xe6, 0xff };
        ClutterColor rect_border_color = { 0xa0, 0x00, 0x00, 0xff };
         
        /* 获取默认的 Stage 并设置其尺寸与颜色 */
        ClutterActor *stage = clutter_stage_get_default ();
        clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Rectangle!");
        clutter_actor_set_size (stage, 400, 200);
        clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);

        /* 构建矩形 Actor */
        ClutterActor *rectangle = clutter_rectangle_new_with_color (&rect_area_color);
        clutter_actor_set_size (rectangle, 100, 50);
        clutter_actor_set_position (rectangle, 150, 75);
        clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle), 4);
        clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (rectangle), &rect_border_color);
        clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle);
        
        /* 显示 Stage 及其子对象(矩形 Actor) */
        clutter_actor_show_all (stage);

        /* 开启 Clutter 主循环,响应事件 */
        clutter_main ();
         
        return 0;
}

上述代码构建了一个长为 400,宽为 200 的 Stage,并在其上(垂直屏幕向外的方向)摆放了一个位置居中(通过丑陋的硬编码实现)的长为 100,宽为 50 的矩形 Actor,如下图所示:

上述代码中构建 Stage 的部分与文献 [2] 大同小异。

代码块:

ClutterActor *rectangle = clutter_rectangle_new_with_color (&rectangle_color);

用于构建一个填充了颜色的矩形 Actor。

由于 ClutterRectangle 也是 ClutterActor 的子类,因此可以使用 ClutterActor 的的大部分方法,例如可使用 clutter_actor_set_size() 函数与 clutter_actor_set_position() 函数设置矩形 Actor 的尺寸与位置,即:

clutter_actor_set_size (rectangle, 100, 50);
clutter_actor_set_position (rectangle, 150, 75);

ClutterRectangle 类也实现了自己的一些方法,例如 clutter_rectangle_set_border_width() 和 clutter_rectangle_set_border_color() 函数可以设置矩形 Actor 对象的边界宽度与颜色:

clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle), 4);
clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (rectangle), &rect_border_color);

对于所有需要在 Stage 上显示的 Actor,都需要使用 ClutterContainer 接口 [3] 提供的 clutter_container_add_actor() 函数将 Actor 添加到 Stage 中,例如:

clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle);

之所以能够对 Stage 对象使用 ClutterContainer 接口,是因为 ClutterStage 实现了 ClutterContainer 接口,若要深入了解其中原理,可能你需要阅读 [4, 5]。

需要注意的是,上述示例使用了 clutter_actor_show_all() 函数显示 Stage 和矩形 Actor,而不是像文献 [1] 中使用 clutter_actor_show() 函数。那么 clutter_actor_show() 与 clutter_actor_show_all() 有什么区别?

clutter_actor_show() 只是用于标定一个 Actor 可以被显示,它的对立者是 clutter_actor_hide() 函数,后者是用于标定一个 Actor 不会被显示。事实上,Actor 默认就是可以被显示的,所以无需要每构建一个 Actor 之后就使用 clutter_actor_show() 来标定它。但是,当 clutter_actor_show() 遇到的 Actor 是 Stage 时,那么它就会将 Stage 及其所包含的各个可被显示的子 Actor 对象(即 clutter_container_add_actor() 所添加的 Actor 对象)一并显示。

clutter_actor_show_all () 是用于将一个实现了 ClutterContainer 接口的对象(例如 Stage)及其子 Actor 对象全部显示出来,即便其中某个子 Actor 对象使用了 clutter_actor_hide() 将其标定为不被显示,它也无法遁形。

文本

ClutterText [6] 的主要功能显示与编辑文本。看下面的示例:

#include <clutter/clutter.h>

int
main(int argc, char *argv[])
{
        if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
                return 1;
        
        ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff };
        ClutterColor text_color  = { 0xff, 0xe6, 0xe6, 0xff };
         
        /* 获取默认的 Stage 并设置其尺寸与颜色 */
        ClutterActor *stage = clutter_stage_get_default ();
        clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Text!");
        clutter_actor_set_size (stage, 400, 200);
        clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);

        /* 构建文本 Actor */
        ClutterActor *text = clutter_text_new_with_text ("Sans 12",
                                                         "中国人指望政府\n"
                                                         "美国人指望 X 战警");
        clutter_actor_set_position (text, 140, 70);
        clutter_text_set_color (CLUTTER_TEXT (text), &text_color);
        clutter_text_set_line_alignment (CLUTTER_TEXT (text), PANGO_ALIGN_CENTER);
        clutter_container_add_actor (CLUTTER_CONTAINER (stage), text);

        /* 显示 Stage 及其子 Actor 对象 */
        clutter_actor_show_all (stage);
        
        /* 开启 Clutter 主循环,响应事件 */
        clutter_main ();
         
        return 0;
}

上面的代码在构建及显示 Stage 部分与上一节的示例差不多,只是将矩形 Actor 的构建部分替换为了文本 Actor 的构建,关键代码如下:

ClutterActor *text = clutter_text_new_with_text ("Sans 12",
                                                 "中国人指望政府\n"
                                                 "美国人指望 X 战警");
clutter_actor_set_position (text, 140, 70);
clutter_text_set_color (CLUTTER_TEXT (text), &text_color);
clutter_text_set_line_alignment (CLUTTER_TEXT (text), PANGO_ALIGN_CENTER);

其中 clutter_text_new_with_text() 用于创建一个文本 Actor 对象并赋予它要使用的字体及文本数据;clutter_actor_set_position() 对文本 Actor 在其父 Actor 对象(本例是 Stage)上寻找摆放位置;clutter_text_set_color() 与 clutter_text_set_line_alignment() 分别用于设定文本颜色与对齐格式。

上例构建的 Stage 与文本 Actor 如下图所示:

注意代码中 clutter_text_set_line_alignment() 的第二个参数“PANGO_ALIGN_CENTER”,该参数表示将文本行设为居中对齐,并且暗示了 Clutter 库在文本 Actor 的实现中借助了 Pango 库 [7]。

纹理

在 OpenGL 的概念里,纹理就是附着在几何模型表面的图片。Clutter 的 ClutterTexture [8] 利用了 OpenGL 的纹理映射功能,可以实现图片(像素格式)的显示和操作。看下面的示例:

#include <clutter/clutter.h>

int
main(int argc, char *argv[])
{
        if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
                return 1;
        
        ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff };
         
        /* 获取默认的 Stage 并设置其尺寸与颜色 */
        ClutterActor *stage = clutter_stage_get_default ();
        clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Texture!");
        clutter_actor_set_size (stage, 400, 200);
        clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);

        /* 构建纹理 Actor */
        ClutterActor *image = clutter_texture_new_from_file ("v.jpg", NULL);
        clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (image), TRUE);
        clutter_actor_set_request_mode (image, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT);
        clutter_actor_set_height (image, 150);
        clutter_actor_set_position (image, 83, 25);
        clutter_container_add_actor (CLUTTER_CONTAINER (stage), image);

        /* 显示 Stage 及其子 Actor 对象 */
        clutter_actor_show_all (stage);
        
        /* 开启 Clutter 主循环,响应事件 */
        clutter_main ();
         
        return 0;
}

上述代码是在 Stage 中显示『V 字仇杀队』的一张剧照素材图片见 [9],效果如下图所示:

程序中与构建纹理 Actor 相关的代码主要是:

ClutterActor *image = clutter_texture_new_from_file ("v.jpg", NULL);
clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (image), TRUE);
clutter_actor_set_request_mode (image, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT);
clutter_actor_set_height (image, 150);
clutter_actor_set_position (image, 83, 25);

其中,clutter_texture_new_from_file() 可以从图片文件创建纹理 Actor 对象;clutter_texture_set_keep_aspect_ratio() 用于设定纹理 Actor 对象的纵横比保持与原始图片相同,并通过与 clutter_actor_set_request_mode() 与 clutter_actor_set_height() 的配合,可以实现将纹理 Actor 对象在不发生拉伸或压缩的前提下,在 Stage 中显示与原始图片成比例的图形。最后,根据图片的纵横比和纹理 Actor 对象的宽度和高度,计算出可以让纹理 Actor 对象居于 Stage 中心的坐标位置 (83, 25),使用 clutter_actor_set_position() 对纹理 Actor 对象进行定位。

克隆

考虑这样一个问题:对于上一节通过载入图片文件而构成的纹理 Actor 对象,如何将其复制一份,构成一个新的 Actor 对象,并进行一些操作(例如平移、旋转等)?

当然,如果再次载入一次图片文件以构建一个新的纹理 Actor 对象可以解决上述问题,但是文件的读取是非常耗费资源。为了更好的解决这个问题,Clutter 库提供了 ClutterClone 类 [10],它可以有效的复制各种 Actor 对象。看下面的示例:

#include <clutter/clutter.h>

int
main(int argc, char *argv[])
{
        if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
                return 1;
        
        ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff };
         
        /* 获取默认的 Stage 并设置其尺寸与颜色 */
        ClutterActor *stage = clutter_stage_get_default ();
        clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Clone!");
        clutter_actor_set_size (stage, 400, 200);
        clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);

        /* 构建纹理 Actor */
        ClutterActor *image = clutter_texture_new_from_file ("v.jpg", NULL);
        clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (image), TRUE);
        clutter_actor_set_request_mode (image, CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
        clutter_actor_set_width (image, 200);
        clutter_actor_set_position (image, 0, 36.5);
        clutter_container_add_actor (CLUTTER_CONTAINER (stage), image);

        /* 复制 Texture Actor */
        ClutterActor *image_clone = clutter_clone_new (image);
        clutter_actor_set_position (image_clone, 200, 36.5);
        clutter_container_add_actor (CLUTTER_CONTAINER (stage), image_clone);
        
        /* 显示 Stage 及其子 Actor 对象 */
        clutter_actor_show_all (stage);
        
        /* 开启 Clutter 主循环,响应事件 */
        clutter_main ();
         
        return 0;
}

上面的代码与 ClutterClone 相关的代码主要如下:

ClutterActor *image_clone = clutter_clone_new (image);
clutter_actor_set_position (image_clone, 200, 36.5);

其中 clutter_clone_new() 可从已建立的纹理 Actor 对象 image 那里建立一个复本,但是这个复本不再是 ClutterTexture 对象,而是 ClutterClone 对象。由于 ClutterClone 也是 ClutterActor 的子类,所以可以使用 ClutterActor 的方法对其进行操作,例如代码中使用了 clutter_actor_set_position() 对其进行了重新定位。

上述程序的运行结果如下图所示。

通过 ClutterClone,你可以复制成千上万的 V 面具,从而建立属于你的 V 字仇杀队,可惜现实中我们似乎没有这样有效的技术。

Cairo 纹理

最后一个演员是 ClutterCairoTexture [11],它是 ClutterTexture 的子类,用于将 Cairo 图形转化为纹理 Actor。这意味着我们可以使用 Cairo 比较强大的 2D 矢量图绘制功能创建 Clutter Actor 对象。看下面的示例:

#include <clutter/clutter.h>

static void
draw_round_rectangle (cairo_t * cr,
                      double x, double y,
                      double width, double height, double r)
{
        cairo_move_to (cr, x + r, y);
        cairo_line_to (cr, x + width - r, y);

        cairo_move_to (cr, x + width, y + r);
        cairo_line_to (cr, x + width, y + height - r);

        cairo_move_to (cr, x + width - r, y + height);
        cairo_line_to (cr, x + r, y + height);

        cairo_move_to (cr, x, y + height - r);
        cairo_line_to (cr, x, y + r);

        cairo_arc (cr, x + r, y + r, r, G_PI, 3 * G_PI / 2.0);
        cairo_arc (cr, x + width - r, y + r, r, 3 * G_PI / 2, 2 * G_PI);
        cairo_arc (cr, x + width - r, y + height - r, r, 0, G_PI / 2);
        cairo_arc (cr, x + r, y + height - r, r, G_PI / 2, G_PI);
}

int
main(int argc, char *argv[])
{
        if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
                return 1;
        
        gfloat width = 400, height = 200;
        
        ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff };
         
        /* 获取默认的 Stage 并设置其尺寸与颜色 */
        ClutterActor *stage = clutter_stage_get_default ();
        clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Cairo!");
        clutter_actor_set_size (stage, width, height);
        clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);

        /* 构建 Cairo 纹理 */
        ClutterActor *cairo_texture = clutter_cairo_texture_new (width, height);
        cairo_t *cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (cairo_texture));

        gfloat w, h, x, y, r;
        
        x = width / 5.0;
        y = height / 5.0;
        w = 3 * width / 5.0;
        h = 3 * height / 5.0;
        r = h / 8.0;
        
        cairo_set_source_rgb (cr, 0.8, 0.4, 0);
        cairo_set_line_width (cr, 6);

        draw_round_rectangle (cr, x, y, w, h, r);
        cairo_stroke_preserve (cr);
        cairo_set_source_rgb (cr, 0.8, 0.8, 0.2);
        cairo_fill (cr);
        
        cairo_destroy (cr);

        clutter_container_add_actor (CLUTTER_CONTAINER (stage), cairo_texture);
        
        /* 显示 Stage 及其子 Actor 对象 */
        clutter_actor_show_all (stage);
        
        /* 开启 Clutter 主循环,响应事件 */
        clutter_main ();
         
        return 0;
}

上面这个示例的代码虽然比前面示例要多一些,但是它的结构却很简单,前提是你需要对 Cairo 绘图有所了解。关键的代码是:

ClutterActor *cairo_texture = clutter_cairo_texture_new (width, height);
cairo_t *cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (cairo_texture));

/* 在此处绘制 Cairo 图形 */
... ...
        
cairo_destroy (cr);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), cairo_texture);

其中 clutter_cairo_texture_new() 用于构建一个带有宽度与高度的 Cairo 纹理 Actor; clutter_cairo_texture_create() 从 Cairo 纹理 Actor 对象中获取相关联的 Cairo 渲染环境。一旦有了 Cairo 渲染环境,那么便可以绘制 Cairo 图形了,例如上例绘制的是一个圆角矩形,如下图所示:

待 Cairo 图形绘制完毕,使用 cairo_destroy() 释放 Cairo 渲染环境,无须担心所绘制的图形会因此消失,因为在 cairo_destroy() 运行之时,Clutter 会将 Cairo 图形保存到 Cairo 纹理 Actor 之中。随后使用 clutter_container_add_actor() 将 Cairo 纹理 Actor 添加到 Stage 中即可。

参考文献

[1] ClutterRectangle 的文档

[2] 凌乱的舞台

[3] ClutterContainer 接口的文档

[4] 继承与接口

[5] GObject 对接口的模拟

[6] ClutterText 的文档

[7] http://www.pango.org/

[8] ClutterTexture 的文档

[9]『V 字仇杀队』剧照

[10] ClutterClone 的文档

[11] ClutterCairoTexture 的文档

[12] Cairo 项目

转载时,希望不要链接文中图片,另外请保留本文原始出处:http://garfileo.is-programmer.com


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter