2. Drawing 2D graphics onto a texture

2.1. Problem

You want to draw 2D graphics inside a Clutter application.

2.2. Solution

Create a ClutterCairoTexture, then draw onto the Cairo context it wraps using the Cairo API:

ClutterActor *texture;
cairo_t *cr;

guint width, height;
width = 800;
height = 600;

texture = clutter_cairo_texture_new (width, height);

cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (texture));

/*
 * write onto the Cairo context cr using the Cairo API;
 * see the Cairo API reference for details
 */
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, 800, 600);
cairo_stroke (cr);

/* does the actual drawing onto the texture */
cairo_destroy (cr);

Here's a useful Cairo tutorial if you want to learn more about the Cairo API itself.

2.3. Discussion

A ClutterCairoTexture is a standard ClutterActor, so it can be added to a ClutterContainer (e.g. a ClutterStage or ClutterGroup), animated, resized etc. in the usual ways.

Other useful operations:

  • To draw on part of the texture: use clutter_cairo_texture_create_region() to retrieve a Cairo context for the region you want to draw on.

  • To clear existing content from a texture: use clutter_cairo_texture_clear().

    You may need to do this as the texture reuses the same Cairo context each time you call clutter_cairo_texture_create() or clutter_cairo_texture_create_region().

  • To resize the Cairo context wrapped by a texture, use clutter_cairo_texture_set_surface_size().

2.3.1. Drawing pages from a PDF onto a ClutterCairoContext

Other libraries may provide an API for writing onto a Cairo context; you can make use of these APIs on the exposed Cairo context of a ClutterCairoTexture. For example, you can use the poppler-glib API to display pages from a PopplerDocument inside a Clutter application:

#include <poppler/glib/poppler.h>

/* snipped setup code (as above) */

/*
 * cast to CLUTTER_CAIRO_TEXTURE, as the functions
 * used below require that type
 */
ClutterCairoTexture *cc_texture = CLUTTER_CAIRO_TEXTURE (texture);

clutter_cairo_texture_clear (cc_texture);

gchar *file_uri = "file:///path/to/file.pdf";
guint page_num = 0;
double page_width, page_height;

PopplerDocument *doc;
PopplerPage *page;
GError *error = NULL;

doc = poppler_document_new_from_file (file_uri, NULL, &error);

page = poppler_document_get_page (doc, page_num);

poppler_page_get_size (page, &page_width, &page_height);

cr = clutter_cairo_texture_create (cc_texture);

/* render the page to the context */
poppler_page_render (page, cr);

cairo_destroy (cr);

Note

If the page is larger than the Cairo context, some of it might not be visible. Similarly, if the ClutterCairoTexture is larger than the stage, some of that might not be visible. So you may need to do some work to make the ClutterCairoTexture fit inside the stage properly (e.g. resize the stage), and/or some work to make the PDF page sit inside the Cairo context (e.g. scale the PDF page or put it inside a scrollable actor).