Apocalypse 3

Back to Clutter/Apocalypses


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.




Paint Nodes

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 *);


 ClutterPaintNode *clutter_color_node_new (const ClutterColor *);

 ClutterPaintNode *clutter_texture_node_new (CoglTexture *, const ClutterColor *, ClutterScalingFilter, ClutterScalingFilter);

 ClutterPaintNode *clutter_pipeline_node_new (CoglPipeline *);

 ClutterPaintNode *clutter_text_node_new (PangoLayout *, const ClutterColor *);

 ClutterPaintNode *clutter_clip_node_new (void);

 ClutterPaintNode *clutter_transform_node_new (const CoglMatrix *modelview);

 ClutterPaintNode *clutter_layer_node_new (const CoglMatrix *mdv, const CoglMatrix *proj, float[] viewport, int w, int h, int flags);


* 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);


 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 *);


Assigning content

 void clutter_actor_set_content (ClutterActor *, ClutterContent *);
 ClutterContent *clutter_actor_get_content (ClutterActor *);

Setting the content position within the actor

 enum ClutterContentGravity {

   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 *);

Minification and magnification filters

 enum ClutterScalingFilter {

 void clutter_actor_set_content_scaling_filters (ClutterActor *, ClutterScalingFilter , ClutterScalingFilter);
 void clutter_actor_get_content_scaling_filters (ClutterActor *, ClutterScalingFilter *, ClutterScalingFilter *);

Image content

 class Image { }

 gboolean clutter_image_set_data      (ClutterImage *,
                                       const guint8 const [],
                                       int width,
                                       int height,
                                       int stride,
                                       GError **);
 gboolean clutter_image_set_data_area (ClutterImage *,
                                       const guint8 const [],
                                       cairo_rectangle_int_t *,
                                       int stride);

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 *);

Attic/Clutter/Apocalypses/Apocalypse3 (last edited 2024-04-11 15:39:31 by EmmanueleBassi)