update to 1.10.4
[profile/ivi/clutter.git] / clutter / clutter-paint-node.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2011  Intel Corporation.
7  *
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.
12  *
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.
17  *
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/>.
20  *
21  * Author:
22  *   Emmanuele Bassi <ebassi@linux.intel.com>
23  */
24
25 /**
26  * SECTION:clutter-paint-node
27  * @Title: ClutterPaintNode
28  * @Short_Description: Paint objects
29  *
30  * #ClutterPaintNode is an element in the render graph.
31  *
32  * The render graph contains all the elements that need to be painted by
33  * Clutter when submitting a frame to the graphics system.
34  *
35  * The render graph is distinct from the scene graph: the scene graph is
36  * composed by actors, which can be visible or invisible; the scene graph
37  * elements also respond to events. The render graph, instead, is only
38  * composed by nodes that will be painted.
39  *
40  * Each #ClutterActor can submit multiple #ClutterPaintNode<!-- -->s to
41  * the render graph.
42  */
43
44 /**
45  * ClutterPaintNode:
46  *
47  * The <structname>ClutterPaintNode</structname> structure contains only
48  * private data and it should be accessed using the provided API.
49  *
50  * Ref Func: clutter_paint_node_ref
51  * Unref Func: clutter_paint_node_unref
52  * Set Value Func: clutter_value_set_paint_node
53  * Get Value Func: clutter_value_get_paint_node
54  *
55  * Since: 1.10
56  */
57
58 /**
59  * ClutterPaintNodeClass:
60  *
61  * The <structname>ClutterPaintNodeClass</structname> structure contains
62  * only private data.
63  *
64  * Since: 1.10
65  */
66
67 #ifdef HAVE_CONFIG_H
68 #include "config.h"
69 #endif
70
71 #define CLUTTER_ENABLE_EXPERIMENTAL_API
72
73 #include <pango/pango.h>
74 #include <cogl/cogl.h>
75 #include <json-glib/json-glib.h>
76
77 #include "clutter-paint-node-private.h"
78
79 #include "clutter-debug.h"
80 #include "clutter-private.h"
81
82 #include <gobject/gvaluecollector.h>
83
84 static inline void      clutter_paint_operation_clear   (ClutterPaintOperation *op);
85
86 static void
87 value_paint_node_init (GValue *value)
88 {
89   value->data[0].v_pointer = NULL;
90 }
91
92 static void
93 value_paint_node_free_value (GValue *value)
94 {
95   if (value->data[0].v_pointer != NULL)
96     clutter_paint_node_unref (value->data[0].v_pointer);
97 }
98
99 static void
100 value_paint_node_copy_value (const GValue *src,
101                              GValue       *dst)
102 {
103   if (src->data[0].v_pointer != NULL)
104     dst->data[0].v_pointer = clutter_paint_node_ref (src->data[0].v_pointer);
105   else
106     dst->data[0].v_pointer = NULL;
107 }
108
109 static gpointer
110 value_paint_node_peek_pointer (const GValue *value)
111 {
112   return value->data[0].v_pointer;
113 }
114
115 static gchar *
116 value_paint_node_collect_value (GValue      *value,
117                                 guint        n_collect_values,
118                                 GTypeCValue *collect_values,
119                                 guint        collect_flags)
120 {
121   ClutterPaintNode *node;
122
123   node = collect_values[0].v_pointer;
124
125   if (node == NULL)
126     {
127       value->data[0].v_pointer = NULL;
128       return NULL;
129     }
130
131   if (node->parent_instance.g_class == NULL)
132     return g_strconcat ("invalid unclassed ClutterPaintNode pointer for "
133                         "value type '",
134                         G_VALUE_TYPE_NAME (value),
135                         "'",
136                         NULL);
137
138   value->data[0].v_pointer = clutter_paint_node_ref (node);
139
140   return NULL;
141 }
142
143 static gchar *
144 value_paint_node_lcopy_value (const GValue *value,
145                               guint         n_collect_values,
146                               GTypeCValue  *collect_values,
147                               guint         collect_flags)
148 {
149   ClutterPaintNode **node_p = collect_values[0].v_pointer;
150
151   if (node_p == NULL)
152     return g_strconcat ("value location for '",
153                         G_VALUE_TYPE_NAME (value),
154                         "' passed as NULL",
155                         NULL);
156
157   if (value->data[0].v_pointer == NULL)
158     *node_p = NULL;
159   else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
160     *node_p = value->data[0].v_pointer;
161   else
162     *node_p = clutter_paint_node_ref (value->data[0].v_pointer);
163
164   return NULL;
165 }
166
167 static void
168 clutter_paint_node_class_base_init (ClutterPaintNodeClass *klass)
169 {
170 }
171
172 static void
173 clutter_paint_node_class_base_finalize (ClutterPaintNodeClass *klass)
174 {
175 }
176
177 static void
178 clutter_paint_node_real_finalize (ClutterPaintNode *node)
179 {
180   ClutterPaintNode *iter;
181
182   g_free (node->name);
183
184   if (node->operations != NULL)
185     {
186       guint i;
187
188       for (i = 0; i < node->operations->len; i++)
189         {
190           ClutterPaintOperation *op;
191
192           op = &g_array_index (node->operations, ClutterPaintOperation, i);
193           clutter_paint_operation_clear (op);
194         }
195
196       g_array_unref (node->operations);
197     }
198
199   iter = node->first_child;
200   while (iter != NULL)
201     {
202       ClutterPaintNode *next = iter->next_sibling;
203
204       clutter_paint_node_remove_child (node, iter);
205
206       iter = next;
207     }
208
209   g_type_free_instance ((GTypeInstance *) node);
210 }
211
212 static gboolean
213 clutter_paint_node_real_pre_draw (ClutterPaintNode *node)
214 {
215   return FALSE;
216 }
217
218 static void
219 clutter_paint_node_real_draw (ClutterPaintNode *node)
220 {
221 }
222
223 static void
224 clutter_paint_node_real_post_draw (ClutterPaintNode *node)
225 {
226 }
227
228 static void
229 clutter_paint_node_class_init (ClutterPaintNodeClass *klass)
230 {
231   klass->pre_draw = clutter_paint_node_real_pre_draw;
232   klass->draw = clutter_paint_node_real_draw;
233   klass->post_draw = clutter_paint_node_real_post_draw;
234   klass->finalize = clutter_paint_node_real_finalize;
235 }
236
237 static void
238 clutter_paint_node_init (ClutterPaintNode *self)
239 {
240   self->ref_count = 1;
241 }
242
243 GType
244 clutter_paint_node_get_type (void)
245 {
246   static volatile gsize paint_node_type_id__volatile = 0;
247
248   if (g_once_init_enter (&paint_node_type_id__volatile))
249     {
250       static const GTypeFundamentalInfo finfo = {
251         (G_TYPE_FLAG_CLASSED |
252          G_TYPE_FLAG_INSTANTIATABLE |
253          G_TYPE_FLAG_DERIVABLE |
254          G_TYPE_FLAG_DEEP_DERIVABLE),
255       };
256
257       static const GTypeValueTable value_table = {
258         value_paint_node_init,
259         value_paint_node_free_value,
260         value_paint_node_copy_value,
261         value_paint_node_peek_pointer,
262         "p",
263         value_paint_node_collect_value,
264         "p",
265         value_paint_node_lcopy_value,
266       };
267
268       const GTypeInfo node_info = {
269         sizeof (ClutterPaintNodeClass),
270
271         (GBaseInitFunc) clutter_paint_node_class_base_init,
272         (GBaseFinalizeFunc) clutter_paint_node_class_base_finalize,
273         (GClassInitFunc) clutter_paint_node_class_init,
274         (GClassFinalizeFunc) NULL,
275         NULL,
276
277         sizeof (ClutterPaintNode),
278         0,
279         (GInstanceInitFunc) clutter_paint_node_init,
280
281         &value_table,
282       };
283
284       GType paint_node_type_id =
285         g_type_register_fundamental (g_type_fundamental_next (),
286                                      I_("ClutterPaintNode"),
287                                      &node_info, &finfo,
288                                      G_TYPE_FLAG_ABSTRACT);
289
290       g_once_init_leave (&paint_node_type_id__volatile, paint_node_type_id);
291     }
292
293   return paint_node_type_id__volatile;
294 }
295
296 /**
297  * clutter_paint_node_set_name:
298  * @node: a #ClutterPaintNode
299  * @name: a string annotating the @node
300  *
301  * Sets a user-readable @name for @node.
302  *
303  * The @name will be used for debugging purposes.
304  *
305  * The @node will copy the passed string.
306  *
307  * Since: 1.10
308  */
309 void
310 clutter_paint_node_set_name (ClutterPaintNode *node,
311                              const char       *name)
312 {
313   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
314
315   g_free (node->name);
316   node->name = g_strdup (name);
317 }
318
319 /**
320  * clutter_paint_node_ref:
321  * @node: a #ClutterPaintNode
322  *
323  * Acquires a reference on @node.
324  *
325  * Return value: (transfer full): the #ClutterPaintNode
326  *
327  * Since: 1.10
328  */
329 ClutterPaintNode *
330 clutter_paint_node_ref (ClutterPaintNode *node)
331 {
332   g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL);
333
334   g_atomic_int_inc (&node->ref_count);
335
336   return node;
337 }
338
339 /**
340  * clutter_paint_node_unref:
341  * @node: a #ClutterPaintNode
342  *
343  * Releases a reference on @node.
344  *
345  * Since: 1.10
346  */
347 void
348 clutter_paint_node_unref (ClutterPaintNode *node)
349 {
350   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
351
352   if (g_atomic_int_dec_and_test (&node->ref_count))
353     {
354       ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node);
355
356       klass->finalize (node);
357     }
358 }
359
360 /**
361  * clutter_paint_node_add_child:
362  * @node: a #ClutterPaintNode
363  * @child: the child #ClutterPaintNode to add
364  *
365  * Adds @child to the list of children of @node.
366  *
367  * This function will acquire a reference on @child.
368  *
369  * Since: 1.10
370  */
371 void
372 clutter_paint_node_add_child (ClutterPaintNode *node,
373                               ClutterPaintNode *child)
374 {
375   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
376   g_return_if_fail (CLUTTER_IS_PAINT_NODE (child));
377   g_return_if_fail (node != child);
378   g_return_if_fail (child->parent == NULL);
379
380   child->parent = node;
381   clutter_paint_node_ref (child);
382
383   node->n_children += 1;
384
385   child->prev_sibling = node->last_child;
386
387   if (node->last_child != NULL)
388     {
389       ClutterPaintNode *tmp = node->last_child;
390
391       tmp->next_sibling = child;
392     }
393
394   if (child->prev_sibling == NULL)
395     node->first_child = child;
396
397   if (child->next_sibling == NULL)
398     node->last_child = child;
399 }
400
401 /**
402  * clutter_paint_node_remove_child:
403  * @node: a #ClutterPaintNode
404  * @child: the #ClutterPaintNode to remove
405  *
406  * Removes @child from the list of children of @node.
407  *
408  * This function will release the reference on @child acquired by
409  * using clutter_paint_node_add_child().
410  *
411  * Since: 1.10
412  */
413 void
414 clutter_paint_node_remove_child (ClutterPaintNode *node,
415                                  ClutterPaintNode *child)
416 {
417   ClutterPaintNode *prev, *next;
418
419   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
420   g_return_if_fail (CLUTTER_IS_PAINT_NODE (child));
421   g_return_if_fail (node != child);
422   g_return_if_fail (child->parent == node);
423
424   node->n_children -= 1;
425
426   prev = child->prev_sibling;
427   next = child->next_sibling;
428
429   if (prev != NULL)
430     prev->next_sibling = next;
431
432   if (next != NULL)
433     next->prev_sibling = prev;
434
435   if (node->first_child == child)
436     node->first_child = next;
437
438   if (node->last_child == child)
439     node->last_child = prev;
440
441   child->prev_sibling = NULL;
442   child->next_sibling = NULL;
443   child->parent = NULL;
444
445   clutter_paint_node_unref (child);
446 }
447
448 /**
449  * clutter_paint_node_replace_child:
450  * @node: a #ClutterPaintNode
451  * @old_child: the child replaced by @new_child
452  * @new_child: the child that replaces @old_child
453  *
454  * Atomically replaces @old_child with @new_child in the list of
455  * children of @node.
456  *
457  * This function will release the reference on @old_child acquired
458  * by @node, and will acquire a new reference on @new_child.
459  *
460  * Since: 1.10
461  */
462 void
463 clutter_paint_node_replace_child (ClutterPaintNode *node,
464                                   ClutterPaintNode *old_child,
465                                   ClutterPaintNode *new_child)
466 {
467   ClutterPaintNode *prev, *next;
468
469   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
470   g_return_if_fail (CLUTTER_IS_PAINT_NODE (old_child));
471   g_return_if_fail (old_child->parent == node);
472   g_return_if_fail (CLUTTER_IS_PAINT_NODE (new_child));
473   g_return_if_fail (new_child->parent == NULL);
474
475   prev = old_child->prev_sibling;
476   next = old_child->next_sibling;
477
478   new_child->parent = node;
479   new_child->prev_sibling = prev;
480   new_child->next_sibling = next;
481   clutter_paint_node_ref (new_child);
482
483   if (prev != NULL)
484     prev->next_sibling = new_child;
485
486   if (next != NULL)
487     next->prev_sibling = new_child;
488
489   if (node->first_child == old_child)
490     node->first_child = new_child;
491
492   if (node->last_child == old_child)
493     node->last_child = new_child;
494
495   old_child->prev_sibling = NULL;
496   old_child->next_sibling = NULL;
497   old_child->parent = NULL;
498   clutter_paint_node_unref (old_child);
499 }
500
501 /**
502  * clutter_paint_node_remove_all:
503  * @node: a #ClutterPaintNode
504  *
505  * Removes all children of @node.
506  *
507  * This function releases the reference acquired by @node on its
508  * children.
509  *
510  * Since: 1.10
511  */
512 void
513 clutter_paint_node_remove_all (ClutterPaintNode *node)
514 {
515   ClutterPaintNode *iter;
516
517   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
518
519   iter = node->first_child;
520   while (iter != NULL)
521     {
522       ClutterPaintNode *next = iter->next_sibling;
523
524       clutter_paint_node_remove_child (node, iter);
525
526       iter = next;
527     }
528 }
529
530 /**
531  * clutter_paint_node_get_first_child:
532  * @node: a #ClutterPaintNode
533  *
534  * Retrieves the first child of the @node.
535  *
536  * Return value: (transfer none): a pointer to the first child of
537  *   the #ClutterPaintNode.
538  *
539  * Since: 1.10
540  */
541 ClutterPaintNode *
542 clutter_paint_node_get_first_child (ClutterPaintNode *node)
543 {
544   g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL);
545
546   return node->first_child;
547 }
548
549 /**
550  * clutter_paint_node_get_previous_sibling:
551  * @node: a #ClutterPaintNode
552  *
553  * Retrieves the previous sibling of @node.
554  *
555  * Return value: (transfer none): a pointer to the previous sibling
556  *   of the #ClutterPaintNode.
557  *
558  * Since: 1.10
559  */
560 ClutterPaintNode *
561 clutter_paint_node_get_previous_sibling (ClutterPaintNode *node)
562 {
563   g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL);
564
565   return node->prev_sibling;
566 }
567
568 /**
569  * clutter_paint_node_get_next_sibling:
570  * @node: a #ClutterPaintNode
571  *
572  * Retrieves the next sibling of @node.
573  *
574  * Return value: (transfer none): a pointer to the next sibling
575  *   of a #ClutterPaintNode
576  *
577  * Since: 1.10
578  */
579 ClutterPaintNode *
580 clutter_paint_node_get_next_sibling (ClutterPaintNode *node)
581 {
582   g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL);
583
584   return node->next_sibling;
585 }
586
587 /**
588  * clutter_paint_node_get_last_child:
589  * @node: a #ClutterPaintNode
590  *
591  * Retrieves the last child of @node.
592  *
593  * Return value: (transfer none): a pointer to the last child
594  *   of a #ClutterPaintNode
595  *
596  * Since: 1.10
597  */
598 ClutterPaintNode *
599 clutter_paint_node_get_last_child (ClutterPaintNode *node)
600 {
601   g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL);
602
603   return node->last_child;
604 }
605
606 /**
607  * clutter_paint_node_get_parent:
608  * @node: a #ClutterPaintNode
609  *
610  * Retrieves the parent of @node.
611  *
612  * Return value: (transfer none): a pointer to the parent of
613  *   a #ClutterPaintNode
614  *
615  * Since: 1.10
616  */
617 ClutterPaintNode *
618 clutter_paint_node_get_parent (ClutterPaintNode *node)
619 {
620   g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL);
621
622   return node->parent;
623 }
624
625 /**
626  * clutter_paint_node_get_n_children:
627  * @node: a #ClutterPaintNode
628  *
629  * Retrieves the number of children of @node.
630  *
631  * Return value: the number of children of a #ClutterPaintNode
632  *
633  * Since: 1.10
634  */
635 guint
636 clutter_paint_node_get_n_children (ClutterPaintNode *node)
637 {
638   g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), 0);
639
640   return node->n_children;
641 }
642
643 /**
644  * clutter_value_set_paint_node:
645  * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE
646  * @node: (type Clutter.PaintNode) (allow-none): a #ClutterPaintNode, or %NULL
647  *
648  * Sets the contents of a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE.
649  *
650  * This function increased the reference count of @node; if you do not wish
651  * to increase the reference count, use clutter_value_take_paint_node()
652  * instead. The reference count will be released by g_value_unset().
653  *
654  * Since: 1.10
655  */
656 void
657 clutter_value_set_paint_node (GValue   *value,
658                               gpointer  node)
659 {
660   ClutterPaintNode *old_node;
661
662   g_return_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value));
663
664   old_node = value->data[0].v_pointer;
665
666   if (node != NULL)
667     {
668       g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
669
670       value->data[0].v_pointer = clutter_paint_node_ref (node);
671     }
672   else
673     value->data[0].v_pointer = NULL;
674
675   if (old_node != NULL)
676     clutter_paint_node_unref (old_node);
677 }
678
679 /**
680  * clutter_value_take_paint_node:
681  * @value: a #GValue, initialized with %CLUTTER_TYPE_PAINT_NODE
682  * @node: (type Clutter.PaintNode) (allow-none): a #ClutterPaintNode, or %NULL
683  *
684  * Sets the contents of a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE.
685  *
686  * Unlike clutter_value_set_paint_node(), this function will not take a
687  * reference on the passed @node: instead, it will take ownership of the
688  * current reference count.
689  *
690  * Since: 1.10
691  */
692 void
693 clutter_value_take_paint_node (GValue   *value,
694                                gpointer  node)
695 {
696   ClutterPaintNode *old_node;
697
698   g_return_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value));
699
700   old_node = value->data[0].v_pointer;
701
702   if (node != NULL)
703     {
704       g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
705
706       /* take over ownership */
707       value->data[0].v_pointer = node;
708     }
709   else
710     value->data[0].v_pointer = NULL;
711
712   if (old_node != NULL)
713     clutter_paint_node_unref (old_node);
714 }
715
716 /**
717  * clutter_value_get_paint_node:
718  * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE
719  *
720  * Retrieves a pointer to the #ClutterPaintNode contained inside
721  * the passed #GValue.
722  *
723  * Return value: (transfer none) (type Clutter.PaintNode): a pointer to
724  *   a #ClutterPaintNode, or %NULL
725  *
726  * Since: 1.10
727  */
728 gpointer
729 clutter_value_get_paint_node (const GValue *value)
730 {
731   g_return_val_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value), NULL);
732
733   return value->data[0].v_pointer;
734 }
735
736 /**
737  * clutter_value_dup_paint_node:
738  * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE
739  *
740  * Retrieves a pointer to the #ClutterPaintNode contained inside
741  * the passed #GValue, and if not %NULL it will increase the
742  * reference count.
743  *
744  * Return value: (transfer full) (type Clutter.PaintNode): a pointer
745  *   to the #ClutterPaintNode, with its reference count increased,
746  *   or %NULL
747  *
748  * Since: 1.10
749  */
750 gpointer
751 clutter_value_dup_paint_node (const GValue *value)
752 {
753   g_return_val_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value), NULL);
754
755   if (value->data[0].v_pointer != NULL)
756     return clutter_paint_node_ref (value->data[0].v_pointer);
757
758   return NULL;
759 }
760
761 static inline void
762 clutter_paint_operation_clear (ClutterPaintOperation *op)
763 {
764   switch (op->opcode)
765     {
766     case PAINT_OP_INVALID:
767       break;
768
769     case PAINT_OP_TEX_RECT:
770       break;
771
772     case PAINT_OP_PATH:
773       if (op->op.path != NULL)
774         cogl_object_unref (op->op.path);
775       break;
776
777     case PAINT_OP_PRIMITIVE:
778       if (op->op.primitive != NULL)
779         cogl_object_unref (op->op.primitive);
780       break;
781     }
782 }
783
784 static inline void
785 clutter_paint_op_init_tex_rect (ClutterPaintOperation *op,
786                                 const ClutterActorBox *rect,
787                                 float                  x_1,
788                                 float                  y_1,
789                                 float                  x_2,
790                                 float                  y_2)
791 {
792   clutter_paint_operation_clear (op);
793
794   op->opcode = PAINT_OP_TEX_RECT;
795   op->op.texrect[0] = rect->x1;
796   op->op.texrect[1] = rect->y1;
797   op->op.texrect[2] = rect->x2;
798   op->op.texrect[3] = rect->y2;
799   op->op.texrect[4] = x_1;
800   op->op.texrect[5] = y_1;
801   op->op.texrect[6] = x_2;
802   op->op.texrect[7] = y_2;
803 }
804
805 static inline void
806 clutter_paint_op_init_path (ClutterPaintOperation *op,
807                             CoglPath              *path)
808 {
809   clutter_paint_operation_clear (op);
810
811   op->opcode = PAINT_OP_PATH;
812   op->op.path = cogl_object_ref (path);
813 }
814
815 static inline void
816 clutter_paint_op_init_primitive (ClutterPaintOperation *op,
817                                  CoglPrimitive         *primitive)
818 {
819   clutter_paint_operation_clear (op);
820
821   op->opcode = PAINT_OP_PRIMITIVE;
822   op->op.primitive = cogl_object_ref (primitive);
823 }
824
825 static inline void
826 clutter_paint_node_maybe_init_operations (ClutterPaintNode *node)
827 {
828   if (node->operations != NULL)
829     return;
830
831   node->operations =
832     g_array_new (FALSE, FALSE, sizeof (ClutterPaintOperation));
833 }
834
835 /**
836  * clutter_paint_node_add_rectangle:
837  * @node: a #ClutterPaintNode
838  * @rect: a #ClutterActorBox
839  *
840  * Adds a rectangle region to the @node, as described by the
841  * passed @rect.
842  *
843  * Since: 1.10
844  */
845 void
846 clutter_paint_node_add_rectangle (ClutterPaintNode      *node,
847                                   const ClutterActorBox *rect)
848 {
849   ClutterPaintOperation operation = PAINT_OP_INIT;
850
851   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
852   g_return_if_fail (rect != NULL);
853
854   clutter_paint_node_maybe_init_operations (node);
855
856   clutter_paint_op_init_tex_rect (&operation, rect, 0.0, 0.0, 1.0, 1.0);
857   g_array_append_val (node->operations, operation);
858 }
859
860 /**
861  * clutter_paint_node_add_texture_rectangle:
862  * @node: a #ClutterPaintNode
863  * @rect: a #ClutterActorBox
864  * @x_1: the left X coordinate of the texture
865  * @y_1: the top Y coordinate of the texture
866  * @x_2: the right X coordinate of the texture
867  * @y_2: the bottom Y coordinate of the texture
868  *
869  * Adds a rectangle region to the @node, with texture coordinates.
870  *
871  * Since: 1.10
872  */
873 void
874 clutter_paint_node_add_texture_rectangle (ClutterPaintNode      *node,
875                                           const ClutterActorBox *rect,
876                                           float                  x_1,
877                                           float                  y_1,
878                                           float                  x_2,
879                                           float                  y_2)
880 {
881   ClutterPaintOperation operation = PAINT_OP_INIT;
882
883   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
884   g_return_if_fail (rect != NULL);
885
886   clutter_paint_node_maybe_init_operations (node);
887
888   clutter_paint_op_init_tex_rect (&operation, rect, x_1, y_1, x_2, y_2);
889   g_array_append_val (node->operations, operation);
890 }
891
892 /**
893  * clutter_paint_node_add_path:
894  * @node: a #ClutterPaintNode
895  * @path: a Cogl path
896  *
897  * Adds a region described as a path to the @node.
898  *
899  * This function acquires a reference on the passed @path, so it
900  * is safe to call cogl_object_unref() when it returns.
901  *
902  * Since: 1.10
903  * Stability: unstable
904  */
905 void
906 clutter_paint_node_add_path (ClutterPaintNode *node,
907                              CoglPath         *path)
908 {
909   ClutterPaintOperation operation = PAINT_OP_INIT;
910
911   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
912   g_return_if_fail (cogl_is_path (path));
913
914   clutter_paint_node_maybe_init_operations (node);
915
916   clutter_paint_op_init_path (&operation, path);
917   g_array_append_val (node->operations, operation);
918 }
919
920 /**
921  * clutter_paint_node_add_primitive:
922  * @node: a #ClutterPaintNode
923  * @primitive: a Cogl primitive
924  *
925  * Adds a region described by a Cogl primitive to the @node.
926  *
927  * This function acquires a reference on @primitive, so it is safe
928  * to call cogl_object_unref() when it returns.
929  *
930  * Since: 1.10
931  */
932 void
933 clutter_paint_node_add_primitive (ClutterPaintNode *node,
934                                   CoglPrimitive    *primitive)
935 {
936   ClutterPaintOperation operation = PAINT_OP_INIT;
937
938   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
939   g_return_if_fail (cogl_is_primitive (primitive));
940
941   clutter_paint_node_maybe_init_operations (node);
942
943   clutter_paint_op_init_primitive (&operation, primitive);
944   g_array_append_val (node->operations, operation);
945 }
946
947 /*< private >
948  * _clutter_paint_node_paint:
949  * @node: a #ClutterPaintNode
950  *
951  * Paints the @node using the class implementation, traversing
952  * its children, if any.
953  */
954 void
955 _clutter_paint_node_paint (ClutterPaintNode *node)
956 {
957   ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node);
958   ClutterPaintNode *iter;
959   gboolean res;
960
961   res = klass->pre_draw (node);
962
963   if (res)
964     {
965       klass->draw (node);
966     }
967
968   for (iter = node->first_child;
969        iter != NULL;
970        iter = iter->next_sibling)
971     {
972       _clutter_paint_node_paint (iter);
973     }
974
975   if (res)
976     {
977       klass->post_draw (node);
978     }
979 }
980
981 #ifdef CLUTTER_ENABLE_DEBUG
982 static JsonNode *
983 clutter_paint_node_serialize (ClutterPaintNode *node)
984 {
985   ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node);
986
987   if (klass->serialize != NULL)
988     return klass->serialize (node);
989
990   return json_node_new (JSON_NODE_NULL);
991 }
992
993 static JsonNode *
994 clutter_paint_node_to_json (ClutterPaintNode *node)
995 {
996   JsonBuilder *builder;
997   JsonNode *res;
998
999   builder = json_builder_new ();
1000
1001   json_builder_begin_object (builder);
1002
1003   json_builder_set_member_name (builder, "type");
1004   json_builder_add_string_value (builder, g_type_name (G_TYPE_FROM_INSTANCE (node)));
1005
1006   json_builder_set_member_name (builder, "name");
1007   json_builder_add_string_value (builder, node->name);
1008
1009   json_builder_set_member_name (builder, "node-data");
1010   json_builder_add_value (builder, clutter_paint_node_serialize (node));
1011
1012   json_builder_set_member_name (builder, "operations");
1013   json_builder_begin_array (builder);
1014
1015   if (node->operations != NULL)
1016     {
1017       guint i;
1018
1019       for (i = 0; i < node->operations->len; i++)
1020         {
1021           const ClutterPaintOperation *op;
1022
1023           op = &g_array_index (node->operations, ClutterPaintOperation, i);
1024           json_builder_begin_object (builder);
1025
1026           switch (op->opcode)
1027             {
1028             case PAINT_OP_TEX_RECT:
1029               json_builder_set_member_name (builder, "texrect");
1030               json_builder_begin_array (builder);
1031               json_builder_add_double_value (builder, op->op.texrect[0]);
1032               json_builder_add_double_value (builder, op->op.texrect[1]);
1033               json_builder_add_double_value (builder, op->op.texrect[2]);
1034               json_builder_add_double_value (builder, op->op.texrect[3]);
1035               json_builder_add_double_value (builder, op->op.texrect[4]);
1036               json_builder_add_double_value (builder, op->op.texrect[5]);
1037               json_builder_add_double_value (builder, op->op.texrect[6]);
1038               json_builder_add_double_value (builder, op->op.texrect[7]);
1039               json_builder_end_array (builder);
1040               break;
1041
1042             case PAINT_OP_PATH:
1043               json_builder_set_member_name (builder, "path");
1044               json_builder_add_int_value (builder, (gint64) op->op.path);
1045               break;
1046
1047             case PAINT_OP_PRIMITIVE:
1048               json_builder_set_member_name (builder, "primitive");
1049               json_builder_add_int_value (builder, (gint64) op->op.primitive);
1050               break;
1051
1052             case PAINT_OP_INVALID:
1053               break;
1054             }
1055
1056           json_builder_end_object (builder);
1057         }
1058     }
1059
1060   json_builder_end_array (builder);
1061
1062   json_builder_set_member_name (builder, "children");
1063   json_builder_begin_array (builder);
1064
1065   if (node->first_child != NULL)
1066     {
1067       ClutterPaintNode *child;
1068
1069       for (child = node->first_child;
1070            child != NULL;
1071            child = child->next_sibling)
1072         {
1073           JsonNode *n = clutter_paint_node_to_json (child);
1074
1075           json_builder_add_value (builder, n);
1076         }
1077     }
1078
1079   json_builder_end_array (builder);
1080
1081   json_builder_end_object (builder);
1082
1083   res = json_builder_get_root (builder);
1084
1085   g_object_unref (builder);
1086
1087   return res;
1088 }
1089 #endif /* CLUTTER_ENABLE_DEBUG */
1090
1091 void
1092 _clutter_paint_node_dump_tree (ClutterPaintNode *node)
1093 {
1094 #ifdef CLUTTER_ENABLE_DEBUG
1095   JsonGenerator *gen = json_generator_new ();
1096   char *str;
1097   gsize len;
1098
1099   json_generator_set_root (gen, clutter_paint_node_to_json (node));
1100   str = json_generator_to_data (gen, &len);
1101
1102   g_print ("Render tree starting from %p:\n%s\n", node, str);
1103
1104   g_free (str);
1105 #endif /* CLUTTER_ENABLE_DEBUG */
1106 }
1107
1108 /*< private >
1109  * _clutter_paint_node_create:
1110  * @gtype: a #ClutterPaintNode type
1111  *
1112  * Creates a new #ClutterPaintNode instance using @gtype
1113  *
1114  * Return value: (transfer full): the newly created #ClutterPaintNode
1115  *   sub-class instance; use clutter_paint_node_unref() when done
1116  */
1117 gpointer
1118 _clutter_paint_node_create (GType gtype)
1119 {
1120   g_return_val_if_fail (g_type_is_a (gtype, CLUTTER_TYPE_PAINT_NODE), NULL);
1121
1122   _clutter_paint_node_init_types ();
1123
1124   return (gpointer) g_type_create_instance (gtype);
1125 }