4 * An OpenGL based 'interactive canvas' library.
6 * Copyright (C) 2011 Intel Corporation.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22 * Emmanuele Bassi <ebassi@linux.intel.com>
26 * SECTION:clutter-paint-nodes
28 * @Short_Description: ClutterPaintNode implementations
30 * Clutter provides a set of predefined #ClutterPaintNode implementations
31 * that cover all the state changes available.
38 #define CLUTTER_ENABLE_EXPERIMENTAL_API
40 #include "clutter-paint-node-private.h"
42 #include <pango/pango.h>
43 #include <cogl/cogl.h>
45 #include "clutter-actor-private.h"
46 #include "clutter-color.h"
47 #include "clutter-debug.h"
48 #include "clutter-private.h"
50 #include "clutter-paint-nodes.h"
52 static CoglPipeline *default_color_pipeline = NULL;
53 static CoglPipeline *default_texture_pipeline = NULL;
56 * _clutter_paint_node_init_types:
58 * Initializes the required types for ClutterPaintNode subclasses
61 _clutter_paint_node_init_types (void)
65 GType node_type G_GNUC_UNUSED;
67 if (G_LIKELY (default_color_pipeline != NULL))
70 ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
72 node_type = clutter_paint_node_get_type ();
74 cogl_color_init_from_4f (&cogl_color, 1.0, 1.0, 1.0, 1.0);
76 default_color_pipeline = cogl_pipeline_new (ctx);
77 cogl_pipeline_set_color (default_color_pipeline, &cogl_color);
79 default_texture_pipeline = cogl_pipeline_new (ctx);
80 cogl_pipeline_set_layer_null_texture (default_texture_pipeline, 0,
81 COGL_TEXTURE_TYPE_2D);
82 cogl_pipeline_set_color (default_texture_pipeline, &cogl_color);
83 cogl_pipeline_set_layer_wrap_mode (default_texture_pipeline, 0,
84 COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
90 * any frame can only have a since RootNode instance for each
94 #define clutter_root_node_get_type _clutter_root_node_get_type
96 typedef struct _ClutterRootNode ClutterRootNode;
97 typedef struct _ClutterPaintNodeClass ClutterRootNodeClass;
99 struct _ClutterRootNode
101 ClutterPaintNode parent_instance;
103 CoglFramebuffer *framebuffer;
105 CoglBufferBit clear_flags;
106 CoglColor clear_color;
107 CoglMatrix modelview;
110 G_DEFINE_TYPE (ClutterRootNode, clutter_root_node, CLUTTER_TYPE_PAINT_NODE)
113 clutter_root_node_pre_draw (ClutterPaintNode *node)
115 ClutterRootNode *rnode = (ClutterRootNode *) node;
119 cogl_framebuffer_set_modelview_matrix (rnode->framebuffer,
122 cogl_framebuffer_clear (rnode->framebuffer,
124 &rnode->clear_color);
130 clutter_root_node_post_draw (ClutterPaintNode *node)
136 clutter_root_node_finalize (ClutterPaintNode *node)
138 ClutterRootNode *rnode = (ClutterRootNode *) node;
140 cogl_object_unref (rnode->framebuffer);
142 CLUTTER_PAINT_NODE_CLASS (clutter_root_node_parent_class)->finalize (node);
146 clutter_root_node_class_init (ClutterRootNodeClass *klass)
148 ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass);
150 node_class->pre_draw = clutter_root_node_pre_draw;
151 node_class->post_draw = clutter_root_node_post_draw;
152 node_class->finalize = clutter_root_node_finalize;
156 clutter_root_node_init (ClutterRootNode *self)
158 cogl_matrix_init_identity (&self->modelview);
162 _clutter_root_node_new (CoglFramebuffer *framebuffer,
163 const ClutterColor *clear_color,
164 CoglBufferBit clear_flags,
165 const CoglMatrix *matrix)
167 ClutterRootNode *res;
169 res = _clutter_paint_node_create (_clutter_root_node_get_type ());
171 cogl_color_init_from_4ub (&res->clear_color,
176 cogl_color_premultiply (&res->clear_color);
178 res->framebuffer = cogl_object_ref (framebuffer);
179 res->clear_flags = clear_flags;
180 res->modelview = *matrix;
182 return (ClutterPaintNode *) res;
188 * A private PaintNode, that changes the modelview of its child
192 #define clutter_transform_node_get_type _clutter_transform_node_get_type
194 typedef struct _ClutterTransformNode {
195 ClutterPaintNode parent_instance;
197 CoglMatrix modelview;
198 } ClutterTransformNode;
200 typedef struct _ClutterPaintNodeClass ClutterTransformNodeClass;
202 G_DEFINE_TYPE (ClutterTransformNode, clutter_transform_node, CLUTTER_TYPE_PAINT_NODE)
205 clutter_transform_node_pre_draw (ClutterPaintNode *node)
207 ClutterTransformNode *tnode = (ClutterTransformNode *) node;
212 cogl_get_modelview_matrix (&matrix);
213 cogl_matrix_multiply (&matrix, &matrix, &tnode->modelview);
214 cogl_set_modelview_matrix (&matrix);
220 clutter_transform_node_post_draw (ClutterPaintNode *node)
226 clutter_transform_node_class_init (ClutterTransformNodeClass *klass)
228 ClutterPaintNodeClass *node_class;
230 node_class = CLUTTER_PAINT_NODE_CLASS (klass);
231 node_class->pre_draw = clutter_transform_node_pre_draw;
232 node_class->post_draw = clutter_transform_node_post_draw;
236 clutter_transform_node_init (ClutterTransformNode *self)
238 cogl_matrix_init_identity (&self->modelview);
242 _clutter_transform_node_new (const CoglMatrix *modelview)
244 ClutterTransformNode *res;
246 res = _clutter_paint_node_create (_clutter_transform_node_get_type ());
248 if (modelview != NULL)
249 res->modelview = *modelview;
251 return (ClutterPaintNode *) res;
255 * Dummy node, private
257 * an empty node, used temporarily until we can drop API compatibility,
258 * and we'll be able to build a full render tree for each frame.
261 #define clutter_dummy_node_get_type _clutter_dummy_node_get_type
263 typedef struct _ClutterDummyNode ClutterDummyNode;
264 typedef struct _ClutterPaintNodeClass ClutterDummyNodeClass;
266 struct _ClutterDummyNode
268 ClutterPaintNode parent_instance;
273 G_DEFINE_TYPE (ClutterDummyNode, clutter_dummy_node, CLUTTER_TYPE_PAINT_NODE)
276 clutter_dummy_node_pre_draw (ClutterPaintNode *node)
282 clutter_dummy_node_serialize (ClutterPaintNode *node)
284 ClutterDummyNode *dnode = (ClutterDummyNode *) node;
285 JsonBuilder *builder;
288 if (dnode->actor == NULL)
289 return json_node_new (JSON_NODE_NULL);
291 builder = json_builder_new ();
292 json_builder_begin_object (builder);
294 json_builder_set_member_name (builder, "actor");
295 json_builder_add_string_value (builder, _clutter_actor_get_debug_name (dnode->actor));
297 json_builder_end_object (builder);
299 res = json_builder_get_root (builder);
300 g_object_unref (builder);
306 clutter_dummy_node_class_init (ClutterDummyNodeClass *klass)
308 ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass);
310 node_class->pre_draw = clutter_dummy_node_pre_draw;
311 node_class->serialize = clutter_dummy_node_serialize;
315 clutter_dummy_node_init (ClutterDummyNode *self)
320 _clutter_dummy_node_new (ClutterActor *actor)
322 ClutterPaintNode *res;
324 res = _clutter_paint_node_create (_clutter_dummy_node_get_type ());
326 ((ClutterDummyNode *) res)->actor = actor;
335 struct _ClutterPipelineNode
337 ClutterPaintNode parent_instance;
339 CoglPipeline *pipeline;
342 struct _ClutterPipelineNodeClass
344 ClutterPaintNodeClass parent_class;
347 G_DEFINE_TYPE (ClutterPipelineNode, clutter_pipeline_node, CLUTTER_TYPE_PAINT_NODE)
350 clutter_pipeline_node_finalize (ClutterPaintNode *node)
352 ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node);
354 if (pnode->pipeline != NULL)
355 cogl_object_unref (pnode->pipeline);
357 CLUTTER_PAINT_NODE_CLASS (clutter_pipeline_node_parent_class)->finalize (node);
361 clutter_pipeline_node_pre_draw (ClutterPaintNode *node)
363 ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node);
365 if (node->operations != NULL &&
366 pnode->pipeline != NULL)
368 cogl_push_source (pnode->pipeline);
376 clutter_pipeline_node_draw (ClutterPaintNode *node)
378 ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node);
381 if (pnode->pipeline == NULL)
384 if (node->operations == NULL)
387 for (i = 0; i < node->operations->len; i++)
389 const ClutterPaintOperation *op;
391 op = &g_array_index (node->operations, ClutterPaintOperation, i);
395 case PAINT_OP_INVALID:
398 case PAINT_OP_TEX_RECT:
399 cogl_rectangle_with_texture_coords (op->op.texrect[0],
410 cogl_path_fill (op->op.path);
413 case PAINT_OP_PRIMITIVE:
415 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
417 cogl_framebuffer_draw_primitive (fb, pnode->pipeline,
426 clutter_pipeline_node_post_draw (ClutterPaintNode *node)
432 clutter_pipeline_node_serialize (ClutterPaintNode *node)
434 ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node);
435 JsonBuilder *builder;
439 if (pnode->pipeline == NULL)
440 return json_node_new (JSON_NODE_NULL);
442 builder = json_builder_new ();
443 json_builder_begin_object (builder);
445 cogl_pipeline_get_color (pnode->pipeline, &color);
446 json_builder_set_member_name (builder, "color");
447 json_builder_begin_array (builder);
448 json_builder_add_double_value (builder, cogl_color_get_red (&color));
449 json_builder_add_double_value (builder, cogl_color_get_green (&color));
450 json_builder_add_double_value (builder, cogl_color_get_blue (&color));
451 json_builder_add_double_value (builder, cogl_color_get_alpha (&color));
452 json_builder_end_array (builder);
455 json_builder_set_member_name (builder, "layers");
456 json_builder_begin_array (builder);
457 cogl_pipeline_foreach_layer (pnode->pipeline,
458 clutter_pipeline_node_serialize_layer,
460 json_builder_end_array (builder);
463 json_builder_end_object (builder);
465 res = json_builder_get_root (builder);
466 g_object_unref (builder);
472 clutter_pipeline_node_class_init (ClutterPipelineNodeClass *klass)
474 ClutterPaintNodeClass *node_class;
476 node_class = CLUTTER_PAINT_NODE_CLASS (klass);
477 node_class->pre_draw = clutter_pipeline_node_pre_draw;
478 node_class->draw = clutter_pipeline_node_draw;
479 node_class->post_draw = clutter_pipeline_node_post_draw;
480 node_class->finalize = clutter_pipeline_node_finalize;
481 node_class->serialize = clutter_pipeline_node_serialize;
485 clutter_pipeline_node_init (ClutterPipelineNode *self)
490 * clutter_pipeline_node_new:
491 * @pipeline: (allow-none): a Cogl pipeline state object, or %NULL
493 * Creates a new #ClutterPaintNode that will use the @pipeline to
494 * paint its contents.
496 * This function will acquire a reference on the passed @pipeline,
497 * so it is safe to call cogl_object_unref() when it returns.
499 * Return value: (transfer full): the newly created #ClutterPaintNode.
500 * Use clutter_paint_node_unref() when done.
505 clutter_pipeline_node_new (CoglPipeline *pipeline)
507 ClutterPipelineNode *res;
509 g_return_val_if_fail (pipeline == NULL || cogl_is_pipeline (pipeline), NULL);
511 res = _clutter_paint_node_create (CLUTTER_TYPE_PIPELINE_NODE);
513 if (pipeline != NULL)
514 res->pipeline = cogl_object_ref (pipeline);
516 return (ClutterPaintNode *) res;
526 * The <structname>ClutterColorNode</structname> structure is an opaque
527 * type whose members cannot be directly accessed.
531 struct _ClutterColorNode
533 ClutterPipelineNode parent_instance;
539 * The <structname>ClutterColorNodeClass</structname> structure is an
540 * opaque type whose members cannot be directly accessed.
544 struct _ClutterColorNodeClass
546 ClutterPipelineNodeClass parent_class;
549 G_DEFINE_TYPE (ClutterColorNode, clutter_color_node, CLUTTER_TYPE_PIPELINE_NODE)
552 clutter_color_node_class_init (ClutterColorNodeClass *klass)
558 clutter_color_node_init (ClutterColorNode *cnode)
560 ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (cnode);
562 g_assert (default_color_pipeline != NULL);
563 pnode->pipeline = cogl_pipeline_copy (default_color_pipeline);
567 * clutter_color_node_new:
568 * @color: (allow-none): the color to paint, or %NULL
570 * Creates a new #ClutterPaintNode that will paint a solid color
573 * Return value: (transfer full): the newly created #ClutterPaintNode. Use
574 * clutter_paint_node_unref() when done
579 clutter_color_node_new (const ClutterColor *color)
581 ClutterPipelineNode *cnode;
583 cnode = _clutter_paint_node_create (CLUTTER_TYPE_COLOR_NODE);
587 CoglColor cogl_color;
589 cogl_color_init_from_4ub (&cogl_color,
594 cogl_color_premultiply (&cogl_color);
596 cogl_pipeline_set_color (cnode->pipeline, &cogl_color);
599 return (ClutterPaintNode *) cnode;
607 * ClutterTextureNode:
609 * The <structname>ClutterTextureNode</structname> structure is an opaque
610 * type whose members cannot be directly accessed.
614 struct _ClutterTextureNode
616 ClutterPipelineNode parent_instance;
620 * ClutterTextureNode:
622 * The <structname>ClutterTextureNodeClass</structname> structure is an
623 * opaque type whose members cannot be directly accessed.
627 struct _ClutterTextureNodeClass
629 ClutterPipelineNodeClass parent_class;
632 G_DEFINE_TYPE (ClutterTextureNode, clutter_texture_node, CLUTTER_TYPE_PIPELINE_NODE)
635 clutter_texture_node_class_init (ClutterTextureNodeClass *klass)
640 clutter_texture_node_init (ClutterTextureNode *self)
642 ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (self);
644 g_assert (default_texture_pipeline != NULL);
645 pnode->pipeline = cogl_pipeline_copy (default_texture_pipeline);
648 static CoglPipelineFilter
649 clutter_scaling_filter_to_cogl_pipeline_filter (ClutterScalingFilter filter)
653 case CLUTTER_SCALING_FILTER_NEAREST:
654 return COGL_PIPELINE_FILTER_NEAREST;
656 case CLUTTER_SCALING_FILTER_LINEAR:
657 return COGL_PIPELINE_FILTER_LINEAR;
659 case CLUTTER_SCALING_FILTER_TRILINEAR:
660 return COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR;
663 return COGL_PIPELINE_FILTER_LINEAR;
667 * clutter_texture_node_new:
668 * @texture: a #CoglTexture
669 * @color: a #ClutterColor
670 * @min_filter: the minification filter for the texture
671 * @mag_filter: the magnification filter for the texture
673 * Creates a new #ClutterPaintNode that will paint the passed @texture.
675 * This function will take a reference on @texture, so it is safe to
676 * call cogl_object_unref() on @texture when it returns.
678 * Return value: (transfer full): the newly created #ClutterPaintNode.
679 * Use clutter_paint_node_unref() when done
684 clutter_texture_node_new (CoglTexture *texture,
685 const ClutterColor *color,
686 ClutterScalingFilter min_filter,
687 ClutterScalingFilter mag_filter)
689 ClutterPipelineNode *tnode;
690 CoglColor cogl_color;
691 CoglPipelineFilter min_f, mag_f;
693 g_return_val_if_fail (cogl_is_texture (texture), NULL);
695 tnode = _clutter_paint_node_create (CLUTTER_TYPE_TEXTURE_NODE);
697 cogl_pipeline_set_layer_texture (tnode->pipeline, 0, texture);
699 min_f = clutter_scaling_filter_to_cogl_pipeline_filter (min_filter);
700 mag_f = clutter_scaling_filter_to_cogl_pipeline_filter (mag_filter);
701 cogl_pipeline_set_layer_filters (tnode->pipeline, 0, min_f, mag_f);
703 cogl_color_init_from_4ub (&cogl_color,
708 cogl_color_premultiply (&cogl_color);
709 cogl_pipeline_set_color (tnode->pipeline, &cogl_color);
711 return (ClutterPaintNode *) tnode;
718 struct _ClutterTextNode
720 ClutterPaintNode parent_instance;
726 struct _ClutterTextNodeClass
728 ClutterPaintNodeClass parent_class;
731 G_DEFINE_TYPE (ClutterTextNode, clutter_text_node, CLUTTER_TYPE_PAINT_NODE)
734 clutter_text_node_finalize (ClutterPaintNode *node)
736 ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node);
738 if (tnode->layout != NULL)
739 g_object_unref (tnode->layout);
741 CLUTTER_PAINT_NODE_CLASS (clutter_text_node_parent_class)->finalize (node);
745 clutter_text_node_pre_draw (ClutterPaintNode *node)
747 ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node);
749 return tnode->layout != NULL;
753 clutter_text_node_draw (ClutterPaintNode *node)
755 ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node);
756 PangoRectangle extents;
759 if (node->operations == NULL)
762 pango_layout_get_pixel_extents (tnode->layout, NULL, &extents);
764 for (i = 0; i < node->operations->len; i++)
766 const ClutterPaintOperation *op;
767 float op_width, op_height;
768 gboolean clipped = FALSE;
770 op = &g_array_index (node->operations, ClutterPaintOperation, i);
774 case PAINT_OP_TEX_RECT:
775 op_width = op->op.texrect[2] - op->op.texrect[0];
776 op_height = op->op.texrect[3] - op->op.texrect[1];
778 /* if the primitive size was smaller than the layout,
779 * we clip the layout when drawin, to avoid spilling
782 if (extents.width > op_width ||
783 extents.height > op_height)
785 cogl_clip_push_rectangle (op->op.texrect[0],
792 cogl_pango_render_layout (tnode->layout,
803 case PAINT_OP_PRIMITIVE:
804 case PAINT_OP_INVALID:
811 clutter_text_node_serialize (ClutterPaintNode *node)
813 ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node);
814 JsonBuilder *builder;
817 builder = json_builder_new ();
819 json_builder_begin_object (builder);
821 json_builder_set_member_name (builder, "layout");
823 if (pango_layout_get_character_count (tnode->layout) > 12)
825 const char *text = pango_layout_get_text (tnode->layout);
828 str = g_strndup (text, 12);
829 json_builder_add_string_value (builder, str);
833 json_builder_add_string_value (builder, pango_layout_get_text (tnode->layout));
835 json_builder_set_member_name (builder, "color");
836 json_builder_begin_array (builder);
837 json_builder_add_double_value (builder, cogl_color_get_red (&tnode->color));
838 json_builder_add_double_value (builder, cogl_color_get_green (&tnode->color));
839 json_builder_add_double_value (builder, cogl_color_get_blue (&tnode->color));
840 json_builder_add_double_value (builder, cogl_color_get_alpha (&tnode->color));
841 json_builder_end_array (builder);
843 json_builder_end_object (builder);
845 res = json_builder_get_root (builder);
846 g_object_unref (builder);
852 clutter_text_node_class_init (ClutterTextNodeClass *klass)
854 ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass);
856 node_class->pre_draw = clutter_text_node_pre_draw;
857 node_class->draw = clutter_text_node_draw;
858 node_class->finalize = clutter_text_node_finalize;
859 node_class->serialize = clutter_text_node_serialize;
863 clutter_text_node_init (ClutterTextNode *self)
865 cogl_color_init_from_4f (&self->color, 0.0, 0.0, 0.0, 1.0);
869 * clutter_text_node_new:
870 * @layout: (allow-none): a #PangoLayout, or %NULL
871 * @color: (allow-none): the color used to paint the layout,
874 * Creates a new #ClutterPaintNode that will paint a #PangoLayout
875 * with the given color.
877 * This function takes a reference on the passed @layout, so it
878 * is safe to call g_object_unref() after it returns.
880 * Return value: (transfer full): the newly created #ClutterPaintNode.
881 * Use clutter_paint_node_unref() when done
886 clutter_text_node_new (PangoLayout *layout,
887 const ClutterColor *color)
889 ClutterTextNode *res;
891 g_return_val_if_fail (layout == NULL || PANGO_IS_LAYOUT (layout), NULL);
893 res = _clutter_paint_node_create (CLUTTER_TYPE_TEXT_NODE);
896 res->layout = g_object_ref (layout);
900 cogl_color_init_from_4ub (&res->color,
907 return (ClutterPaintNode *) res;
913 struct _ClutterClipNode
915 ClutterPaintNode parent_instance;
918 struct _ClutterClipNodeClass
920 ClutterPaintNodeClass parent_class;
923 G_DEFINE_TYPE (ClutterClipNode, clutter_clip_node, CLUTTER_TYPE_PAINT_NODE)
926 clutter_clip_node_pre_draw (ClutterPaintNode *node)
928 gboolean retval = FALSE;
932 if (node->operations == NULL)
935 fb = cogl_get_draw_framebuffer ();
937 for (i = 0; i < node->operations->len; i++)
939 const ClutterPaintOperation *op;
941 op = &g_array_index (node->operations, ClutterPaintOperation, i);
945 case PAINT_OP_TEX_RECT:
946 cogl_framebuffer_push_rectangle_clip (fb,
955 cogl_framebuffer_push_path_clip (fb, op->op.path);
959 case PAINT_OP_PRIMITIVE:
960 case PAINT_OP_INVALID:
969 clutter_clip_node_post_draw (ClutterPaintNode *node)
974 if (node->operations == NULL)
977 fb = cogl_get_draw_framebuffer ();
979 for (i = 0; i < node->operations->len; i++)
981 const ClutterPaintOperation *op;
983 op = &g_array_index (node->operations, ClutterPaintOperation, i);
988 case PAINT_OP_TEX_RECT:
989 cogl_framebuffer_pop_clip (fb);
992 case PAINT_OP_PRIMITIVE:
993 case PAINT_OP_INVALID:
1000 clutter_clip_node_class_init (ClutterClipNodeClass *klass)
1002 ClutterPaintNodeClass *node_class;
1004 node_class = CLUTTER_PAINT_NODE_CLASS (klass);
1005 node_class->pre_draw = clutter_clip_node_pre_draw;
1006 node_class->post_draw = clutter_clip_node_post_draw;
1010 clutter_clip_node_init (ClutterClipNode *self)
1015 * clutter_clip_node_new:
1017 * Creates a new #ClutterPaintNode that will clip its child
1018 * nodes to the 2D regions added to it.
1020 * Return value: (transfer full): the newly created #ClutterPaintNode.
1021 * Use clutter_paint_node_unref() when done.
1026 clutter_clip_node_new (void)
1028 return _clutter_paint_node_create (CLUTTER_TYPE_CLIP_NODE);
1032 * ClutterLayerNode (private)
1035 #define clutter_layer_node_get_type _clutter_layer_node_get_type
1037 struct _ClutterLayerNode
1039 ClutterPaintNode parent_instance;
1041 cairo_rectangle_t viewport;
1043 CoglMatrix projection;
1048 CoglPipeline *state;
1049 CoglFramebuffer *offscreen;
1050 CoglTexture *texture;
1055 struct _ClutterLayerNodeClass
1057 ClutterPaintNodeClass parent_class;
1060 G_DEFINE_TYPE (ClutterLayerNode, clutter_layer_node, CLUTTER_TYPE_PAINT_NODE)
1063 clutter_layer_node_pre_draw (ClutterPaintNode *node)
1065 ClutterLayerNode *lnode = (ClutterLayerNode *) node;
1068 /* if we were unable to create an offscreen buffer for this node, then
1069 * we simply ignore it
1071 if (lnode->offscreen == NULL)
1074 /* if no geometry was submitted for this node then we simply ignore it */
1075 if (node->operations == NULL)
1078 /* copy the same modelview from the current framebuffer to the one we
1081 cogl_get_modelview_matrix (&matrix);
1083 cogl_push_framebuffer (lnode->offscreen);
1085 cogl_framebuffer_set_modelview_matrix (lnode->offscreen, &matrix);
1087 cogl_framebuffer_set_viewport (lnode->offscreen,
1090 lnode->viewport.width,
1091 lnode->viewport.height);
1093 cogl_framebuffer_set_projection_matrix (lnode->offscreen,
1094 &lnode->projection);
1096 /* clear out the target framebuffer */
1097 cogl_framebuffer_clear4f (lnode->offscreen,
1098 COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH,
1099 0.f, 0.f, 0.f, 0.f);
1101 cogl_push_matrix ();
1103 /* every draw operation after this point will happen an offscreen
1111 clutter_layer_node_post_draw (ClutterPaintNode *node)
1113 ClutterLayerNode *lnode = CLUTTER_LAYER_NODE (node);
1114 CoglFramebuffer *fb;
1117 /* switch to the previous framebuffer */
1119 cogl_pop_framebuffer ();
1121 fb = cogl_get_draw_framebuffer ();
1123 for (i = 0; i < node->operations->len; i++)
1125 const ClutterPaintOperation *op;
1127 op = &g_array_index (node->operations, ClutterPaintOperation, i);
1130 case PAINT_OP_INVALID:
1133 case PAINT_OP_TEX_RECT:
1134 /* now we need to paint the texture */
1135 cogl_push_source (lnode->state);
1136 cogl_rectangle_with_texture_coords (op->op.texrect[0],
1148 cogl_push_source (lnode->state);
1149 cogl_path_fill (op->op.path);
1153 case PAINT_OP_PRIMITIVE:
1154 cogl_framebuffer_draw_primitive (fb, lnode->state, op->op.primitive);
1161 clutter_layer_node_finalize (ClutterPaintNode *node)
1163 ClutterLayerNode *lnode = CLUTTER_LAYER_NODE (node);
1165 if (lnode->state != NULL)
1166 cogl_object_unref (lnode->state);
1168 if (lnode->offscreen != NULL)
1169 cogl_object_unref (lnode->offscreen);
1171 CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node);
1175 clutter_layer_node_class_init (ClutterLayerNodeClass *klass)
1177 ClutterPaintNodeClass *node_class;
1179 node_class = CLUTTER_PAINT_NODE_CLASS (klass);
1180 node_class->pre_draw = clutter_layer_node_pre_draw;
1181 node_class->post_draw = clutter_layer_node_post_draw;
1182 node_class->finalize = clutter_layer_node_finalize;
1186 clutter_layer_node_init (ClutterLayerNode *self)
1188 cogl_matrix_init_identity (&self->projection);
1192 * clutter_layer_node_new:
1193 * @projection: the projection matrix to use to set up the layer
1194 * @viewport: (type cairo.Rectangle): the viewport to use to set up the layer
1195 * @width: the width of the layer
1196 * @height: the height of the layer
1197 * @opacity: the opacity to be used when drawing the layer
1199 * Creates a new #ClutterLayerNode.
1201 * All children of this node will be painted inside a separate
1202 * framebuffer; the framebuffer will then be painted using the
1205 * Return value: (transfer full): the newly created #ClutterLayerNode.
1206 * Use clutter_paint_node_unref() when done.
1211 _clutter_layer_node_new (const CoglMatrix *projection,
1212 const cairo_rectangle_t *viewport,
1217 ClutterLayerNode *res;
1220 res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
1222 res->projection = *projection;
1223 res->viewport = *viewport;
1224 res->fbo_width = width;
1225 res->fbo_height = height;
1226 res->opacity = opacity;
1228 /* the texture backing the FBO */
1229 res->texture = cogl_texture_new_with_size (MAX (res->fbo_width, 1),
1230 MAX (res->fbo_height, 1),
1231 COGL_TEXTURE_NO_SLICING,
1232 COGL_PIXEL_FORMAT_RGBA_8888_PRE);
1234 res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (res->texture));
1235 if (res->offscreen == NULL)
1237 g_critical ("%s: Unable to create an offscreen buffer", G_STRLOC);
1239 cogl_object_unref (res->texture);
1240 res->texture = NULL;
1245 cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
1247 /* the pipeline used to paint the texture; we use nearest
1248 * interpolation filters because the texture is always
1249 * going to be painted at a 1:1 texel:pixel ratio
1251 res->state = cogl_pipeline_copy (default_texture_pipeline);
1252 cogl_pipeline_set_layer_filters (res->state, 0,
1253 COGL_PIPELINE_FILTER_NEAREST,
1254 COGL_PIPELINE_FILTER_NEAREST);
1255 cogl_pipeline_set_layer_texture (res->state, 0, res->texture);
1256 cogl_pipeline_set_color (res->state, &color);
1257 cogl_object_unref (res->texture);
1260 return (ClutterPaintNode *) res;