1. Apocalypse 3
Back to Clutter/Apocalypses
1.1. Apocalypse
or Content is what a content does.
The only things an actor should paint are its children.
In order to paint anything else, be it an image, a Cairo surface, or a multi-textured pipeline set up with different blend modes between the layers, the application code needs to assign a Content instance to the actor.
A Content is an object that only knows how to paint itself at the geometry provided by the actor.
A Content paint sequence is composed by the following steps:
- construct pipeline primitives
- construct geometry primitives
The actor using the Content instance, and not the Content itself, will the perform the pipeline and geometry upload.
Content as an abstract class, or Content as an interface?
An abstract class gives us a default implementation that can hold some state; an interface allows us to set up a proper delegation protocol with any object, including an actor subclass itself (implement Content and override the "paint content" method).
Painting goes through a Paint Context object: no direct manipulation of the Cogl context state is allowed.
The Paint Context holds a tree of "render objects" - nodes inside the render tree that will be built by each Actor in the scene graph and iterated to create the frame.
Each "render object" is a ClutterPaintNode, a lightweight object type; instances of ClutterPaintNode can be cached and modified from within the ClutterActor::paint-node or the ClutterContent::paint-content virtual functions; modification outside the paint sequence is forbidden. The frame is rendered by iterating through the render tree composed of PaintNodes, and the render tree is the only authoritative source for the pipeline state and the geometry primitive submitted to the graphics system.
1.2. Exegesis
TBD
1.3. Synopsis
1.3.1. Paint Nodes
1.3.1.1. Basic API
ClutterPaintNode { GTypeInstance } void clutter_paint_node_add_child (ClutterPaintNode *, ClutterPaintNode *); void clutter_paint_node_remove_child (ClutterPaintNode *, ClutterPaintNode *); void clutter_paint_node_replace_child (ClutterPaintNode *, ClutterPaintNode *, ClutterPaintNode *); void clutter_paint_node_remove_all (ClutterPaintNode *); ClutterPaintNode *clutter_paint_node_get_parent (ClutterPaintNode *); ClutterPaintNode *clutter_paint_node_get_first_child (ClutterPaintNode *); ClutterPaintNode *clutter_paint_node_get_next_sibling (ClutterPaintNode *); ClutterPaintNode *clutter_paint_node_get_previous_sibling (ClutterPaintNode *); ClutterPaintNode *clutter_paint_node_get_last_child (ClutterPaintNode *); void clutter_paint_node_add_rectangle (ClutterPaintNode *, const ClutterActorBox *); void clutter_paint_node_add_texture_rectangle (ClutterPaintNode *, const ClutterActorBox *, float, float, float, float); void clutter_paint_node_add_path (ClutterPaintNode *, CoglPath *); void clutter_paint_node_add_primitive (ClutterPaintNode *, CoglPrimitive *);
1.3.1.2. Nodes
ClutterColorNode ClutterPaintNode *clutter_color_node_new (const ClutterColor *); ClutterTextureNode ClutterPaintNode *clutter_texture_node_new (CoglTexture *, const ClutterColor *, ClutterScalingFilter, ClutterScalingFilter); ClutterPipelineNode ClutterPaintNode *clutter_pipeline_node_new (CoglPipeline *); ClutterTextNode ClutterPaintNode *clutter_text_node_new (PangoLayout *, const ClutterColor *); ClutterClipNode ClutterPaintNode *clutter_clip_node_new (void); ClutterTransformNode ClutterPaintNode *clutter_transform_node_new (const CoglMatrix *modelview); ClutterLayerNode ClutterPaintNode *clutter_layer_node_new (const CoglMatrix *mdv, const CoglMatrix *proj, float[] viewport, int w, int h, int flags);
1.3.1.3. Examples
* SolidRectangle::paint-node
static void solid_rectangle_paint_node (ClutterActor *actor, ClutterPaintNode *root) { SolidRectanglePrivate *priv = SOLID_RECTANGLE (actor)->priv; ClutterPaintNode *node; ClutterActorBox box; /* retrieve the area assigned to the content */ clutter_actor_get_content_box (actor, &box); node = clutter_color_node_new (&priv->color); clutter_paint_node_add_rectangle (node, &box); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); }
* SimpleTexture::paint-node
static void simple_texture_paint_node (ClutterActor *actor, ClutterPaintNode *root) { SimpleTexture *tex = SIMPLE_TEXTURE (actor); ClutterScalingFilter min_f, mag_f; ClutterPaintNode *node; ClutterActorBox box; ClutterColor color; guint8 paint_opacity; clutter_actor_get_content_box (actor, &box); clutter_actor_get_content_scaling_filters (actor, &min_f, &mag_f); paint_opacity = clutter_actor_get_paint_opacity (actor); color.red = paint_opacity; color.green = paint_opacity; color.blue = paint_opacity; color.alpha = paint_opacity; node = clutter_texture_node_new (tex->cogl_texture, &color, min_f, mag_f); clutter_paint_node_add_texture_rectangle (node, &box, 0, 0, 1, 1); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); }
* TextLabel::paint-node
static void text_label_paint_node (ClutterActor *actor, ClutterPaintNode *root) { TextLabelPrivate *priv = TEXT_LABEL (actor)->priv; ClutterPaintContext *context = clutter_actor_get_paint_context (actor); int layout_width, layout_height; PangoRectangle logical; ClutterActorBox box = { 0, }; pango_layout_get_extents (priv->layout, NULL, &logical); pango_extents_to_pixels (&logical, NULL); adjust_box_for_xalign (&box, clutter_actor_get_x_align (actor), logical.width); adjust_box_for_yalign (&box, clutter_actor_get_y_align (actor), logical.height); node = clutter_text_node_new (layout, &priv->text_color); clutter_paint_node_add_rectangle (node, &box); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); }
1.3.2. Content
interface Content { gboolean (* get_preferred_size) (ClutterContent *, float *, float *); void (* paint_content) (ClutterContent *, ClutterActor *, ClutterPaintNode *) void (* attached) (ClutterContent *, ClutterActor *); void (* detached) (ClutterContent *, ClutterActor *); void (* invalidate) (ClutterContent *); } void clutter_content_invalidate (ClutterContent *);
1.3.3. Actor
1.3.3.1. Assigning content
void clutter_actor_set_content (ClutterActor *, ClutterContent *); ClutterContent *clutter_actor_get_content (ClutterActor *);
1.3.3.2. Setting the content position within the actor
enum ClutterContentGravity { TOP_LEFT, TOP, TOP_RIGHT, LEFT, CENTER, RIGHT, BOTTOM_LEFT, BOTTOM, BOTTOM_RIGHT, RESIZE_FILL, /* resize the content to fill the content box (default) */ RESIZE_ASPECT, /* resize the content to remain within the content box, while maintaining the aspect ratio */ }; void clutter_actor_set_content_gravity (ClutterActor *, ClutterContentGravity); ClutterContentGravity clutter_actor_get_content_gravity (ClutterActor *); void clutter_actor_get_content_box (ClutterActor *, ClutterActorBox *);
1.3.3.3. Minification and magnification filters
enum ClutterScalingFilter { LINEAR, NEAREST, TRILINEAR }; void clutter_actor_set_content_scaling_filters (ClutterActor *, ClutterScalingFilter , ClutterScalingFilter); void clutter_actor_get_content_scaling_filters (ClutterActor *, ClutterScalingFilter *, ClutterScalingFilter *);
1.3.4. Image content
class Image { } gboolean clutter_image_set_data (ClutterImage *, const guint8 const [], CoglPixelFormat, int width, int height, int stride, GError **); gboolean clutter_image_set_data_area (ClutterImage *, const guint8 const [], CoglPixelFormat, cairo_rectangle_int_t *, int stride);
1.3.5. Cairo content
Canvas { public signal draw (Canvas *, int width, int height, cairo_t *); } void clutter_canvas_invalidate_area (ClutterCanvas *, cairo_rectangle_int_t *); cairo_t *clutter_canvas_get_context (ClutterCanvas *);