diff --git a/clutter/Makefile.am b/clutter/Makefile.am index b1c9e0598..6c22c42ad 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -100,6 +100,8 @@ source_h = \ $(srcdir)/clutter-model.h \ $(srcdir)/clutter-offscreen-effect.h \ $(srcdir)/clutter-page-turn-effect.h \ + $(srcdir)/clutter-paint-nodes.h \ + $(srcdir)/clutter-paint-node.h \ $(srcdir)/clutter-path-constraint.h \ $(srcdir)/clutter-path.h \ $(srcdir)/clutter-property-transition.h \ @@ -173,6 +175,8 @@ source_c = \ $(srcdir)/clutter-model.c \ $(srcdir)/clutter-offscreen-effect.c \ $(srcdir)/clutter-page-turn-effect.c \ + $(srcdir)/clutter-paint-nodes.c \ + $(srcdir)/clutter-paint-node.c \ $(srcdir)/clutter-path-constraint.c \ $(srcdir)/clutter-path.c \ $(srcdir)/clutter-property-transition.c \ @@ -216,6 +220,7 @@ source_h_priv = \ $(srcdir)/clutter-master-clock.h \ $(srcdir)/clutter-model-private.h \ $(srcdir)/clutter-offscreen-effect-private.h \ + $(srcdir)/clutter-paint-node-private.h \ $(srcdir)/clutter-paint-volume-private.h \ $(srcdir)/clutter-private.h \ $(srcdir)/clutter-profile.h \ diff --git a/clutter/clutter-paint-node-private.h b/clutter/clutter-paint-node-private.h new file mode 100644 index 000000000..346bda8f3 --- /dev/null +++ b/clutter/clutter-paint-node-private.h @@ -0,0 +1,115 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#ifndef __CLUTTER_PAINT_NODE_PRIVATE_H__ +#define __CLUTTER_PAINT_NODE_PRIVATE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define CLUTTER_PAINT_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_PAINT_NODE, ClutterPaintNodeClass)) +#define CLUTTER_IS_PAINT_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_PAINT_NODE)) +#define CLUTTER_PAINT_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_PAINT_NODE, ClutterPaintNodeClass)) + +typedef struct _ClutterPaintOperation ClutterPaintOperation; + +struct _ClutterPaintNode +{ + GTypeInstance parent_instance; + + ClutterPaintNode *parent; + + ClutterPaintNode *first_child; + ClutterPaintNode *prev_sibling; + ClutterPaintNode *next_sibling; + ClutterPaintNode *last_child; + + guint n_children; + + GArray *operations; + + gchar *name; + + volatile int ref_count; +}; + +struct _ClutterPaintNodeClass +{ + GTypeClass base_class; + + void (* finalize) (ClutterPaintNode *node); + + gboolean (* pre_draw) (ClutterPaintNode *node); + void (* draw) (ClutterPaintNode *node); + void (* post_draw) (ClutterPaintNode *node); +}; + +typedef enum { + PAINT_OP_INVALID = 0, + PAINT_OP_TEX_RECT, + PAINT_OP_PATH, + PAINT_OP_PRIMITIVE +} PaintOpCode; + +struct _ClutterPaintOperation +{ + PaintOpCode opcode; + + union { + float texrect[8]; + + CoglPath *path; + + CoglPrimitive *primitive; + } op; +}; + +GType _clutter_root_node_get_type (void) G_GNUC_CONST; +GType _clutter_transform_node_get_type (void) G_GNUC_CONST; +GType _clutter_dummy_node_get_type (void) G_GNUC_CONST; + +void _clutter_paint_operation_paint_rectangle (const ClutterPaintOperation *op); +void _clutter_paint_operation_clip_rectangle (const ClutterPaintOperation *op); +void _clutter_paint_operation_paint_path (const ClutterPaintOperation *op); +void _clutter_paint_operation_clip_path (const ClutterPaintOperation *op); +void _clutter_paint_operation_paint_primitive (const ClutterPaintOperation *op); + +void _clutter_paint_node_init_types (void); +gpointer _clutter_paint_node_internal (GType gtype); + +ClutterPaintNode * _clutter_root_node_new (CoglFramebuffer *framebuffer, + const ClutterColor *clear_color, + CoglBufferBit clear_flags, + const CoglMatrix *matrix); +ClutterPaintNode * _clutter_transform_node_new (const CoglMatrix *matrix); +ClutterPaintNode * _clutter_dummy_node_new (void); + +void _clutter_paint_node_paint (ClutterPaintNode *root); +void _clutter_paint_node_dump_tree (ClutterPaintNode *root); + +G_END_DECLS + +#endif /* __CLUTTER_PAINT_NODE_PRIVATE_H__ */ diff --git a/clutter/clutter-paint-node.c b/clutter/clutter-paint-node.c new file mode 100644 index 000000000..dc11191ea --- /dev/null +++ b/clutter/clutter-paint-node.c @@ -0,0 +1,1137 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +/** + * SECTION:clutter-paint-node + * @Title: ClutterPaintNode + * @Short_Description: Paint objects + * + * #ClutterPaintNode is an element in the render graph. + * + * The render graph contains all the elements that need to be painted by + * Clutter when submitting a frame to the graphics system. + * + * The render graph is distinct from the scene graph: the scene graph is + * composed by actors, which can be visible or invisible; the scene graph + * elements also respond to events. The render graph, instead, is only + * composed by nodes that will be painted. + * + * Each #ClutterActor can submit multiple #ClutterPaintNodes to + * the render graph. + */ + +/** + * ClutterPaintNode: + * + * The ClutterPaintNode structure contains only + * private data and it should be accessed using the provided API. + * + * Ref Func: clutter_paint_node_ref + * Unref Func: clutter_paint_node_unref + * Set Value Func: clutter_value_set_paint_node + * Get Value Func: clutter_value_get_paint_node + * + * Since: 1.10 + */ + +/** + * ClutterPaintNodeClass: + * + * The ClutterPaintNodeClass structure contains + * only private data. + * + * Since: 1.10 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "clutter-paint-node-private.h" + +#include "clutter-debug.h" +#include "clutter-private.h" + +#include + +static inline void clutter_paint_operation_clear (ClutterPaintOperation *op); + +static void +value_paint_node_init (GValue *value) +{ + value->data[0].v_pointer = NULL; +} + +static void +value_paint_node_free_value (GValue *value) +{ + if (value->data[0].v_pointer != NULL) + clutter_paint_node_unref (value->data[0].v_pointer); +} + +static void +value_paint_node_copy_value (const GValue *src, + GValue *dst) +{ + if (src->data[0].v_pointer != NULL) + dst->data[0].v_pointer = clutter_paint_node_ref (src->data[0].v_pointer); + else + dst->data[0].v_pointer = NULL; +} + +static gpointer +value_paint_node_peek_pointer (const GValue *value) +{ + return value->data[0].v_pointer; +} + +static gchar * +value_paint_node_collect_value (GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + ClutterPaintNode *node; + + node = collect_values[0].v_pointer; + + if (node == NULL) + { + value->data[0].v_pointer = NULL; + return NULL; + } + + if (node->parent_instance.g_class == NULL) + return g_strconcat ("invalid unclassed ClutterPaintNode pointer for " + "value type '", + G_VALUE_TYPE_NAME (value), + "'", + NULL); + + value->data[0].v_pointer = clutter_paint_node_ref (node); + + return NULL; +} + +static gchar * +value_paint_node_lcopy_value (const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + ClutterPaintNode **node_p = collect_values[0].v_pointer; + + if (node_p == NULL) + return g_strconcat ("value location for '", + G_VALUE_TYPE_NAME (value), + "' passed as NULL", + NULL); + + if (value->data[0].v_pointer == NULL) + *node_p = NULL; + else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) + *node_p = value->data[0].v_pointer; + else + *node_p = clutter_paint_node_ref (value->data[0].v_pointer); + + return NULL; +} + +static void +clutter_paint_node_class_base_init (ClutterPaintNodeClass *klass) +{ +} + +static void +clutter_paint_node_class_base_finalize (ClutterPaintNodeClass *klass) +{ +} + +static void +clutter_paint_node_real_finalize (ClutterPaintNode *node) +{ + ClutterPaintNode *iter; + + g_free (node->name); + + if (node->operations != NULL) + { + guint i; + + for (i = 0; i < node->operations->len; i++) + { + ClutterPaintOperation *op; + + op = &g_array_index (node->operations, ClutterPaintOperation, i); + clutter_paint_operation_clear (op); + } + + g_array_unref (node->operations); + } + + iter = node->first_child; + while (iter != NULL) + { + ClutterPaintNode *next = iter->next_sibling; + + clutter_paint_node_remove_child (node, iter); + + iter = next; + } + + g_type_free_instance ((GTypeInstance *) node); +} + +static gboolean +clutter_paint_node_real_pre_draw (ClutterPaintNode *node) +{ + return FALSE; +} + +static void +clutter_paint_node_real_draw (ClutterPaintNode *node) +{ +} + +static void +clutter_paint_node_real_post_draw (ClutterPaintNode *node) +{ +} + +static void +clutter_paint_node_class_init (ClutterPaintNodeClass *klass) +{ + klass->pre_draw = clutter_paint_node_real_pre_draw; + klass->draw = clutter_paint_node_real_draw; + klass->post_draw = clutter_paint_node_real_post_draw; + klass->finalize = clutter_paint_node_real_finalize; +} + +static void +clutter_paint_node_init (ClutterPaintNode *self) +{ + self->ref_count = 1; +} + +GType +clutter_paint_node_get_type (void) +{ + static volatile gsize paint_node_type_id__volatile = 0; + + if (g_once_init_enter (&paint_node_type_id__volatile)) + { + static const GTypeFundamentalInfo finfo = { + (G_TYPE_FLAG_CLASSED | + G_TYPE_FLAG_INSTANTIATABLE | + G_TYPE_FLAG_DERIVABLE | + G_TYPE_FLAG_DEEP_DERIVABLE), + }; + + static const GTypeValueTable value_table = { + value_paint_node_init, + value_paint_node_free_value, + value_paint_node_copy_value, + value_paint_node_peek_pointer, + "p", + value_paint_node_collect_value, + "p", + value_paint_node_lcopy_value, + }; + + const GTypeInfo node_info = { + sizeof (ClutterPaintNodeClass), + + (GBaseInitFunc) clutter_paint_node_class_base_init, + (GBaseFinalizeFunc) clutter_paint_node_class_base_finalize, + (GClassInitFunc) clutter_paint_node_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (ClutterPaintNode), + 0, + (GInstanceInitFunc) clutter_paint_node_init, + + &value_table, + }; + + GType paint_node_type_id = + g_type_register_fundamental (g_type_fundamental_next (), + I_("ClutterPaintNode"), + &node_info, &finfo, + G_TYPE_FLAG_ABSTRACT); + + g_once_init_leave (&paint_node_type_id__volatile, paint_node_type_id); + } + + return paint_node_type_id__volatile; +} + +/** + * clutter_paint_node_set_name: + * @node: a #ClutterPaintNode + * @name: a string annotating the @node + * + * Sets a user-readable @name for @node. + * + * The @name will be used for debugging purposes. + * + * The @node will copy the passed string. + * + * Since: 1.10 + */ +void +clutter_paint_node_set_name (ClutterPaintNode *node, + const char *name) +{ + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + + g_free (node->name); + node->name = g_strdup (name); +} + +/** + * clutter_paint_node_ref: + * @node: a #ClutterPaintNode + * + * Acquires a reference on @node. + * + * Return value: (transfer full): the #ClutterPaintNode + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_paint_node_ref (ClutterPaintNode *node) +{ + g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); + + g_atomic_int_inc (&node->ref_count); + + return node; +} + +/** + * clutter_paint_node_unref: + * @node: a #ClutterPaintNode + * + * Releases a reference on @node. + * + * Since: 1.10 + */ +void +clutter_paint_node_unref (ClutterPaintNode *node) +{ + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + + if (g_atomic_int_dec_and_test (&node->ref_count)) + { + ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node); + + klass->finalize (node); + } +} + +/** + * clutter_paint_node_add_child: + * @node: a #ClutterPaintNode + * @child: the child #ClutterPaintNode to add + * + * Adds @child to the list of children of @node. + * + * This function will acquire a reference on @child. + * + * Since: 1.10 + */ +void +clutter_paint_node_add_child (ClutterPaintNode *node, + ClutterPaintNode *child) +{ + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (CLUTTER_IS_PAINT_NODE (child)); + g_return_if_fail (node != child); + g_return_if_fail (child->parent == NULL); + + child->parent = node; + clutter_paint_node_ref (child); + + node->n_children += 1; + + child->prev_sibling = node->last_child; + + if (node->last_child != NULL) + { + ClutterPaintNode *tmp = node->last_child; + + tmp->next_sibling = child; + } + + if (child->prev_sibling == NULL) + node->first_child = child; + + if (child->next_sibling == NULL) + node->last_child = child; +} + +/** + * clutter_paint_node_remove_child: + * @node: a #ClutterPaintNode + * @child: the #ClutterPaintNode to remove + * + * Removes @child from the list of children of @node. + * + * This function will release the reference on @child acquired by + * using clutter_paint_node_add_child(). + * + * Since: 1.10 + */ +void +clutter_paint_node_remove_child (ClutterPaintNode *node, + ClutterPaintNode *child) +{ + ClutterPaintNode *prev, *next; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (CLUTTER_IS_PAINT_NODE (child)); + g_return_if_fail (node != child); + g_return_if_fail (child->parent == node); + + node->n_children -= 1; + + prev = child->prev_sibling; + next = child->next_sibling; + + if (prev != NULL) + prev->next_sibling = next; + + if (next != NULL) + next->prev_sibling = prev; + + if (node->first_child == child) + node->first_child = next; + + if (node->last_child == child) + node->last_child = prev; + + child->prev_sibling = NULL; + child->next_sibling = NULL; + child->parent = NULL; + + clutter_paint_node_unref (child); +} + +/** + * clutter_paint_node_replace_child: + * @node: a #ClutterPaintNode + * @old_child: the child replaced by @new_child + * @new_child: the child that replaces @old_child + * + * Atomically replaces @old_child with @new_child in the list of + * children of @node. + * + * This function will release the reference on @old_child acquired + * by @node, and will acquire a new reference on @new_child. + * + * Since: 1.10 + */ +void +clutter_paint_node_replace_child (ClutterPaintNode *node, + ClutterPaintNode *old_child, + ClutterPaintNode *new_child) +{ + ClutterPaintNode *prev, *next; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (CLUTTER_IS_PAINT_NODE (old_child)); + g_return_if_fail (old_child->parent == node); + g_return_if_fail (CLUTTER_IS_PAINT_NODE (new_child)); + g_return_if_fail (new_child->parent == NULL); + + prev = old_child->prev_sibling; + next = old_child->next_sibling; + + new_child->parent = node; + new_child->prev_sibling = prev; + new_child->next_sibling = next; + clutter_paint_node_ref (new_child); + + if (prev != NULL) + prev->next_sibling = new_child; + + if (next != NULL) + next->prev_sibling = new_child; + + if (node->first_child == old_child) + node->first_child = new_child; + + if (node->last_child == old_child) + node->last_child = new_child; + + old_child->prev_sibling = NULL; + old_child->next_sibling = NULL; + old_child->parent = NULL; + clutter_paint_node_unref (old_child); +} + +/** + * clutter_paint_node_remove_all: + * @node: a #ClutterPaintNode + * + * Removes all children of @node. + * + * This function releases the reference acquired by @node on its + * children. + * + * Since: 1.10 + */ +void +clutter_paint_node_remove_all (ClutterPaintNode *node) +{ + ClutterPaintNode *iter; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + + iter = node->first_child; + while (iter != NULL) + { + ClutterPaintNode *next = iter->next_sibling; + + clutter_paint_node_remove_child (node, iter); + + iter = next; + } +} + +/** + * clutter_paint_node_get_first_child: + * @node: a #ClutterPaintNode + * + * Retrieves the first child of the @node. + * + * Return value: (transfer none): a pointer to the first child of + * the #ClutterPaintNode. + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_paint_node_get_first_child (ClutterPaintNode *node) +{ + g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); + + return node->first_child; +} + +/** + * clutter_paint_node_get_previous_sibling: + * @node: a #ClutterPaintNode + * + * Retrieves the previous sibling of @node. + * + * Return value: (transfer none): a pointer to the previous sibling + * of the #ClutterPaintNode. + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_paint_node_get_previous_sibling (ClutterPaintNode *node) +{ + g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); + + return node->prev_sibling; +} + +/** + * clutter_paint_node_get_next_sibling: + * @node: a #ClutterPaintNode + * + * Retrieves the next sibling of @node. + * + * Return value: (transfer none): a pointer to the next sibling + * of a #ClutterPaintNode + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_paint_node_get_next_sibling (ClutterPaintNode *node) +{ + g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); + + return node->next_sibling; +} + +/** + * clutter_paint_node_get_last_child: + * @node: a #ClutterPaintNode + * + * Retrieves the last child of @node. + * + * Return value: (transfer none): a pointer to the last child + * of a #ClutterPaintNode + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_paint_node_get_last_child (ClutterPaintNode *node) +{ + g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); + + return node->last_child; +} + +/** + * clutter_paint_node_get_parent: + * @node: a #ClutterPaintNode + * + * Retrieves the parent of @node. + * + * Return value: (transfer none): a pointer to the parent of + * a #ClutterPaintNode + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_paint_node_get_parent (ClutterPaintNode *node) +{ + g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); + + return node->parent; +} + +/** + * clutter_paint_node_get_n_children: + * @node: a #ClutterPaintNode + * + * Retrieves the number of children of @node. + * + * Return value: the number of children of a #ClutterPaintNode + * + * Since: 1.10 + */ +guint +clutter_paint_node_get_n_children (ClutterPaintNode *node) +{ + g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), 0); + + return node->n_children; +} + +/** + * clutter_value_set_paint_node: + * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE + * @node: (type Clutter.PaintNode) (allow-none): a #ClutterPaintNode, or %NULL + * + * Sets the contents of a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE. + * + * This function increased the reference count of @node; if you do not wish + * to increase the reference count, use clutter_value_take_paint_node() + * instead. The reference count will be released by g_value_unset(). + * + * Since: 1.10 + */ +void +clutter_value_set_paint_node (GValue *value, + gpointer node) +{ + ClutterPaintNode *old_node; + + g_return_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value)); + + old_node = value->data[0].v_pointer; + + if (node != NULL) + { + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + + value->data[0].v_pointer = clutter_paint_node_ref (node); + } + else + value->data[0].v_pointer = NULL; + + if (old_node != NULL) + clutter_paint_node_unref (old_node); +} + +/** + * clutter_value_take_paint_node: + * @value: a #GValue, initialized with %CLUTTER_TYPE_PAINT_NODE + * @node: (type Clutter.PaintNode) (allow-none): a #ClutterPaintNode, or %NULL + * + * Sets the contents of a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE. + * + * Unlike clutter_value_set_paint_node(), this function will not take a + * reference on the passed @node: instead, it will take ownership of the + * current reference count. + * + * Since: 1.10 + */ +void +clutter_value_take_paint_node (GValue *value, + gpointer node) +{ + ClutterPaintNode *old_node; + + g_return_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value)); + + old_node = value->data[0].v_pointer; + + if (node != NULL) + { + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + + /* take over ownership */ + value->data[0].v_pointer = node; + } + else + value->data[0].v_pointer = NULL; + + if (old_node != NULL) + clutter_paint_node_unref (old_node); +} + +/** + * clutter_value_get_paint_node: + * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE + * + * Retrieves a pointer to the #ClutterPaintNode contained inside + * the passed #GValue. + * + * Return value: (transfer none) (type Clutter.PaintNode): a pointer to + * a #ClutterPaintNode, or %NULL + * + * Since: 1.10 + */ +gpointer +clutter_value_get_paint_node (const GValue *value) +{ + g_return_val_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value), NULL); + + return value->data[0].v_pointer; +} + +/** + * clutter_value_dup_paint_node: + * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE + * + * Retrieves a pointer to the #ClutterPaintNode contained inside + * the passed #GValue, and if not %NULL it will increase the + * reference count. + * + * Return value: (transfer full) (type Clutter.PaintNode): a pointer + * to the #ClutterPaintNode, with its reference count increased, + * or %NULL + * + * Since: 1.10 + */ +gpointer +clutter_value_dup_paint_node (const GValue *value) +{ + g_return_val_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value), NULL); + + if (value->data[0].v_pointer != NULL) + return clutter_paint_node_ref (value->data[0].v_pointer); + + return NULL; +} + +static inline void +clutter_paint_operation_clear (ClutterPaintOperation *op) +{ + switch (op->opcode) + { + case PAINT_OP_INVALID: + break; + + case PAINT_OP_TEX_RECT: + break; + + case PAINT_OP_PATH: + if (op->op.path != NULL) + cogl_object_unref (op->op.path); + break; + + case PAINT_OP_PRIMITIVE: + if (op->op.primitive != NULL) + cogl_object_unref (op->op.primitive); + break; + } +} + +static void +clutter_paint_operation_to_string (const ClutterPaintOperation *op, + GString *buf, + int level) +{ + int i; + + for (i = 0; i < level; i++) + g_string_append (buf, " "); + + g_string_append (buf, "{ "); + + switch (op->opcode) + { + case PAINT_OP_INVALID: + break; + + case PAINT_OP_TEX_RECT: + g_string_append_printf (buf, "\"texrect\" : [ %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f ]", + op->op.texrect[0], + op->op.texrect[1], + op->op.texrect[2], + op->op.texrect[3], + op->op.texrect[4], + op->op.texrect[5], + op->op.texrect[6], + op->op.texrect[7]); + break; + + case PAINT_OP_PATH: + g_string_append_printf (buf, "\"path\" : \"0x%p\"", op->op.path); + break; + + case PAINT_OP_PRIMITIVE: + g_string_append_printf (buf, "\"primitive\" : \"0x%p\"", op->op.primitive); + break; + } + + g_string_append (buf, " }"); +} + +static inline void +clutter_paint_op_init_tex_rect (ClutterPaintOperation *op, + const ClutterActorBox *rect, + float x_1, + float y_1, + float x_2, + float y_2) +{ + clutter_paint_operation_clear (op); + + op->opcode = PAINT_OP_TEX_RECT; + op->op.texrect[0] = rect->x1; + op->op.texrect[1] = rect->y1; + op->op.texrect[2] = rect->x2; + op->op.texrect[3] = rect->y2; + op->op.texrect[4] = x_1; + op->op.texrect[5] = y_1; + op->op.texrect[6] = x_2; + op->op.texrect[7] = y_2; +} + +static inline void +clutter_paint_op_init_path (ClutterPaintOperation *op, + CoglPath *path) +{ + clutter_paint_operation_clear (op); + + op->opcode = PAINT_OP_PATH; + op->op.path = cogl_object_ref (path); +} + +static inline void +clutter_paint_op_init_primitive (ClutterPaintOperation *op, + CoglPrimitive *primitive) +{ + clutter_paint_operation_clear (op); + + op->opcode = PAINT_OP_PRIMITIVE; + op->op.primitive = cogl_object_ref (primitive); +} + +static inline void +clutter_paint_node_maybe_init_operations (ClutterPaintNode *node) +{ + if (node->operations != NULL) + return; + + node->operations = + g_array_new (FALSE, FALSE, sizeof (ClutterPaintOperation)); +} + +/** + * clutter_paint_node_add_rectangle: + * @node: a #ClutterPaintNode + * @rect: a #ClutterActorBox + * + * Adds a rectangle region to the @node, as described by the + * passed @rect. + * + * Since: 1.10 + */ +void +clutter_paint_node_add_rectangle (ClutterPaintNode *node, + const ClutterActorBox *rect) +{ + ClutterPaintOperation operation; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (rect != NULL); + + clutter_paint_node_maybe_init_operations (node); + + clutter_paint_op_init_tex_rect (&operation, rect, 0.0, 0.0, 1.0, 1.0); + g_array_append_val (node->operations, operation); +} + +/** + * clutter_paint_node_add_texture_rectangle: + * @node: a #ClutterPaintNode + * @rect: a #ClutterActorBox + * @x_1: the left X coordinate of the texture + * @y_1: the top Y coordinate of the texture + * @x_2: the right X coordinate of the texture + * @y_2: the bottom Y coordinate of the texture + * + * Adds a rectangle region to the @node, with texture coordinates. + * + * Since: 1.10 + */ +void +clutter_paint_node_add_texture_rectangle (ClutterPaintNode *node, + const ClutterActorBox *rect, + float x_1, + float y_1, + float x_2, + float y_2) +{ + ClutterPaintOperation operation; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (rect != NULL); + + clutter_paint_node_maybe_init_operations (node); + + clutter_paint_op_init_tex_rect (&operation, rect, x_1, y_1, x_2, y_2); + g_array_append_val (node->operations, operation); +} + +/** + * clutter_paint_node_add_path: + * @node: a #ClutterPaintNode + * @path: a Cogl path + * + * Adds a region described as a path to the @node. + * + * This function acquires a reference on the passed @path, so it + * is safe to call cogl_object_unref() when it returns. + * + * Since: 1.10 + * Stability: unstable + */ +void +clutter_paint_node_add_path (ClutterPaintNode *node, + CoglPath *path) +{ + ClutterPaintOperation operation; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (cogl_is_path (path)); + + clutter_paint_node_maybe_init_operations (node); + + clutter_paint_op_init_path (&operation, path); + g_array_append_val (node->operations, operation); +} + +/** + * clutter_paint_node_add_primitive: + * @node: a #ClutterPaintNode + * @primitive: a Cogl primitive + * + * Adds a region described by a Cogl primitive to the @node. + * + * This function acquires a reference on @primitive, so it is safe + * to call cogl_object_unref() when it returns. + * + * Since: 1.10 + */ +void +clutter_paint_node_add_primitive (ClutterPaintNode *node, + CoglPrimitive *primitive) +{ + ClutterPaintOperation operation; + + g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); + g_return_if_fail (cogl_is_primitive (primitive)); + + clutter_paint_node_maybe_init_operations (node); + + clutter_paint_op_init_primitive (&operation, primitive); + g_array_append_val (node->operations, operation); +} + +/*< private > + * _clutter_paint_node_paint: + * @node: a #ClutterPaintNode + * + * Paints the @node using the class implementation, traversing + * its children, if any. + */ +void +_clutter_paint_node_paint (ClutterPaintNode *node) +{ + ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node); + ClutterPaintNode *iter; + gboolean res; + + res = klass->pre_draw (node); + + if (res) + { + klass->draw (node); + } + + for (iter = node->first_child; + iter != NULL; + iter = iter->next_sibling) + { + _clutter_paint_node_paint (iter); + } + + if (res) + { + klass->post_draw (node); + } +} + +static void +clutter_paint_node_to_string (ClutterPaintNode *node, + GString *buf, + int level) +{ + ClutterPaintNode *iter; + int i; + + for (i = 0; i < level; i++) + g_string_append (buf, " "); + + g_string_append_c (buf, '"'); + g_string_append (buf, g_type_name (G_TYPE_FROM_INSTANCE (node))); + g_string_append_c (buf, '"'); + + g_string_append (buf, " : {\n"); + + if (node->name != NULL) + { + for (i = 0; i < level + 1; i++) + g_string_append (buf, " "); + + g_string_append_printf (buf, "\"name\" : \"%s\"", node->name); + + if (node->operations != NULL || + node->first_child != NULL) + g_string_append_c (buf, ','); + + g_string_append_c (buf, '\n'); + } + + if (node->operations != NULL) + { + guint o; + + for (i = 0; i < level + 1; i++) + g_string_append (buf, " "); + + g_string_append (buf, "\"operations\" : [\n"); + + for (o = 0; o < node->operations->len; o++) + { + const ClutterPaintOperation *op; + + op = &g_array_index (node->operations, ClutterPaintOperation, o); + clutter_paint_operation_to_string (op, buf, level + 2); + + if ((o + 1) != node->operations->len) + g_string_append_c (buf, ','); + + g_string_append_c (buf, '\n'); + } + + for (i = 0; i < level + 1; i++) + g_string_append (buf, " "); + + g_string_append (buf, "]"); + + if (node->first_child != NULL) + g_string_append_c (buf, ','); + + g_string_append_c (buf, '\n'); + } + + if (node->first_child == NULL) + goto out; + + for (i = 0; i < level + 1; i++) + g_string_append (buf, " "); + + g_string_append (buf, "\"children\" : [\n"); + + for (iter = node->first_child; + iter != NULL; + iter = iter->next_sibling) + { + clutter_paint_node_to_string (iter, buf, level + 2); + + if (iter->next_sibling != NULL) + g_string_append (buf, ",\n"); + else + g_string_append (buf, "\n"); + } + + for (i = 0; i < level + 1; i++) + g_string_append (buf, " "); + + g_string_append (buf, "]\n"); + +out: + for (i = 0; i < level; i++) + g_string_append (buf, " "); + + g_string_append (buf, "}"); +} + +void +_clutter_paint_node_dump_tree (ClutterPaintNode *node) +{ +#ifdef CLUTTER_ENABLE_DEBUG + GString *buf = g_string_sized_new (1024); + + clutter_paint_node_to_string (node, buf, 0); + + CLUTTER_NOTE (PAINT, "Render tree:\n%s", buf->str); + + g_string_free (buf, TRUE); +#endif /* CLUTTER_ENABLE_DEBUG */ +} + +gpointer +_clutter_paint_node_internal (GType gtype) +{ + g_return_val_if_fail (g_type_is_a (gtype, CLUTTER_TYPE_PAINT_NODE), NULL); + + _clutter_paint_node_init_types (); + + return (gpointer) g_type_create_instance (gtype); +} diff --git a/clutter/clutter-paint-node.h b/clutter/clutter-paint-node.h new file mode 100644 index 000000000..46cc7d30a --- /dev/null +++ b/clutter/clutter-paint-node.h @@ -0,0 +1,95 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_PAINT_NODE_H__ +#define __CLUTTER_PAINT_NODE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_PAINT_NODE (clutter_paint_node_get_type ()) +#define CLUTTER_PAINT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PAINT_NODE, ClutterPaintNode)) +#define CLUTTER_IS_PAINT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PAINT_NODE)) + +typedef struct _ClutterPaintNodePrivate ClutterPaintNodePrivate; +typedef struct _ClutterPaintNodeClass ClutterPaintNodeClass; + +GType clutter_paint_node_get_type (void) G_GNUC_CONST; + +ClutterPaintNode * clutter_paint_node_ref (ClutterPaintNode *node); +void clutter_paint_node_unref (ClutterPaintNode *node); + +void clutter_paint_node_set_name (ClutterPaintNode *node, + const char *name); + +void clutter_paint_node_add_child (ClutterPaintNode *node, + ClutterPaintNode *child); +void clutter_paint_node_remove_child (ClutterPaintNode *node, + ClutterPaintNode *child); +void clutter_paint_node_replace_child (ClutterPaintNode *node, + ClutterPaintNode *old_child, + ClutterPaintNode *new_child); +void clutter_paint_node_remove_all (ClutterPaintNode *node); + +guint clutter_paint_node_get_n_children (ClutterPaintNode *node); + +ClutterPaintNode * clutter_paint_node_get_first_child (ClutterPaintNode *node); +ClutterPaintNode * clutter_paint_node_get_previous_sibling (ClutterPaintNode *node); +ClutterPaintNode * clutter_paint_node_get_next_sibling (ClutterPaintNode *node); +ClutterPaintNode * clutter_paint_node_get_last_child (ClutterPaintNode *node); +ClutterPaintNode * clutter_paint_node_get_parent (ClutterPaintNode *node); + +void clutter_paint_node_add_rectangle (ClutterPaintNode *node, + const ClutterActorBox *rect); +void clutter_paint_node_add_texture_rectangle (ClutterPaintNode *node, + const ClutterActorBox *rect, + float x_1, + float y_1, + float x_2, + float y_2); +#if defined(COGL_ENABLE_EXPERIMENTAL_2_0_API) && defined(CLUTTER_ENABLE_EXPERIMENTAL_API) +void clutter_paint_node_add_path (ClutterPaintNode *node, + CoglPath *path); +void clutter_paint_node_add_primitive (ClutterPaintNode *node, + CoglPrimitive *primitive); +#endif /* COGL_ENABLE_EXPERIMENTAL_2_0_API && CLUTTER_ENABLE_EXPERIMENTAL_API */ + +#define CLUTTER_VALUE_HOLDS_PAINT_NODE(value) (G_VALUE_HOLDS (value, CLUTTER_TYPE_PAINT_NODE)) + +void clutter_value_set_paint_node (GValue *value, + gpointer node); +void clutter_value_take_paint_node (GValue *value, + gpointer node); +gpointer clutter_value_get_paint_node (const GValue *value); +gpointer clutter_value_dup_paint_node (const GValue *value); + +G_END_DECLS + +#endif /* __CLUTTER_PAINT_NODE_H__ */ diff --git a/clutter/clutter-paint-nodes.c b/clutter/clutter-paint-nodes.c new file mode 100644 index 000000000..c0868b3b5 --- /dev/null +++ b/clutter/clutter-paint-nodes.c @@ -0,0 +1,1124 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +/** + * SECTION:clutter-paint-nodes + * @Title: Paint Nodes + * @Short_Description: ClutterPaintNode implementations + * + * Clutter provides a set of predefined #ClutterPaintNode implementations + * that cover all the state changes available. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CLUTTER_ENABLE_EXPERIMENTAL_API + +#include "clutter-paint-node-private.h" + +#include +#include + +#include "clutter-color.h" +#include "clutter-debug.h" +#include "clutter-private.h" + +#include "clutter-paint-nodes.h" + +static CoglPipeline *default_color_pipeline = NULL; +static CoglPipeline *default_texture_pipeline = NULL; + +/*< private > + * _clutter_paint_node_init_types: + * + * Initializes the required types for ClutterPaintNode subclasses + */ +void +_clutter_paint_node_init_types (void) +{ + CoglContext *ctx; + CoglColor cogl_color; + GType node_type G_GNUC_UNUSED; + + if (G_LIKELY (default_color_pipeline != NULL)) + return; + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + + node_type = clutter_paint_node_get_type (); + + cogl_color_init_from_4f (&cogl_color, 1.0, 1.0, 1.0, 1.0); + + default_color_pipeline = cogl_pipeline_new (ctx); + cogl_pipeline_set_color (default_color_pipeline, &cogl_color); + + default_texture_pipeline = cogl_pipeline_new (ctx); + cogl_pipeline_set_layer_null_texture (default_texture_pipeline, 0, + COGL_TEXTURE_TYPE_2D); + cogl_pipeline_set_color (default_texture_pipeline, &cogl_color); +} + +/* + * Root node, private + * + * any frame can only have a since RootNode instance for each + * top-level actor. + */ + +#define clutter_root_node_get_type _clutter_root_node_get_type + +typedef struct _ClutterRootNode ClutterRootNode; +typedef struct _ClutterPaintNodeClass ClutterRootNodeClass; + +struct _ClutterRootNode +{ + ClutterPaintNode parent_instance; + + CoglFramebuffer *framebuffer; + + CoglBufferBit clear_flags; + CoglColor clear_color; + CoglMatrix modelview; +}; + +GType _clutter_root_node_get_type (void) G_GNUC_CONST; + +G_DEFINE_TYPE (ClutterRootNode, clutter_root_node, CLUTTER_TYPE_PAINT_NODE) + +static gboolean +clutter_root_node_pre_draw (ClutterPaintNode *node) +{ + ClutterRootNode *rnode = (ClutterRootNode *) node; + + cogl_push_matrix (); + + cogl_framebuffer_set_modelview_matrix (rnode->framebuffer, + &rnode->modelview); + + cogl_framebuffer_clear (rnode->framebuffer, + rnode->clear_flags, + &rnode->clear_color); + + return TRUE; +} + +static void +clutter_root_node_post_draw (ClutterPaintNode *node) +{ + cogl_pop_matrix (); +} + +static void +clutter_root_node_finalize (ClutterPaintNode *node) +{ + ClutterRootNode *rnode = (ClutterRootNode *) node; + + cogl_object_unref (rnode->framebuffer); + + CLUTTER_PAINT_NODE_CLASS (clutter_root_node_parent_class)->finalize (node); +} + +static void +clutter_root_node_class_init (ClutterRootNodeClass *klass) +{ + ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass); + + node_class->pre_draw = clutter_root_node_pre_draw; + node_class->post_draw = clutter_root_node_post_draw; + node_class->finalize = clutter_root_node_finalize; +} + +static void +clutter_root_node_init (ClutterRootNode *self) +{ + cogl_matrix_init_identity (&self->modelview); +} + +ClutterPaintNode * +_clutter_root_node_new (CoglFramebuffer *framebuffer, + const ClutterColor *clear_color, + CoglBufferBit clear_flags, + const CoglMatrix *matrix) +{ + ClutterRootNode *res; + + res = _clutter_paint_node_internal (_clutter_root_node_get_type ()); + + cogl_color_init_from_4ub (&res->clear_color, + clear_color->red, + clear_color->green, + clear_color->blue, + clear_color->alpha); + cogl_color_premultiply (&res->clear_color); + + res->framebuffer = cogl_object_ref (framebuffer); + res->clear_flags = clear_flags; + res->modelview = *matrix; + + return (ClutterPaintNode *) res; +} + +/* + * Transform node + * + * A private PaintNode, that changes the modelview of its child + * nodes. + */ + +#define clutter_transform_node_get_type _clutter_transform_node_get_type + +typedef struct _ClutterTransformNode { + ClutterPaintNode parent_instance; + + CoglMatrix modelview; +} ClutterTransformNode; + +typedef struct _ClutterPaintNodeClass ClutterTransformNodeClass; + +GType _clutter_transform_node_get_type (void) G_GNUC_CONST; + +G_DEFINE_TYPE (ClutterTransformNode, clutter_transform_node, CLUTTER_TYPE_PAINT_NODE) + +static gboolean +clutter_transform_node_pre_draw (ClutterPaintNode *node) +{ + ClutterTransformNode *tnode = (ClutterTransformNode *) node; + CoglMatrix matrix; + + cogl_push_matrix (); + + cogl_get_modelview_matrix (&matrix); + cogl_matrix_multiply (&matrix, &matrix, &tnode->modelview); + cogl_set_modelview_matrix (&matrix); + + return TRUE; +} + +static void +clutter_transform_node_post_draw (ClutterPaintNode *node) +{ + cogl_pop_matrix (); +} + +static void +clutter_transform_node_class_init (ClutterTransformNodeClass *klass) +{ + ClutterPaintNodeClass *node_class; + + node_class = CLUTTER_PAINT_NODE_CLASS (klass); + node_class->pre_draw = clutter_transform_node_pre_draw; + node_class->post_draw = clutter_transform_node_post_draw; +} + +static void +clutter_transform_node_init (ClutterTransformNode *self) +{ + cogl_matrix_init_identity (&self->modelview); +} + +ClutterPaintNode * +_clutter_transform_node_new (const CoglMatrix *modelview) +{ + ClutterTransformNode *res; + + res = _clutter_paint_node_internal (_clutter_transform_node_get_type ()); + + if (modelview != NULL) + res->modelview = *modelview; + + return (ClutterPaintNode *) res; +} + +/* + * Dummy node, private + * + * an empty node, used temporarily until we can drop API compatibility, + * and we'll be able to build a full render tree for each frame. + */ + +#define clutter_dummy_node_get_type _clutter_dummy_node_get_type + +typedef struct _ClutterDummyNode ClutterDummyNode; +typedef struct _ClutterPaintNodeClass ClutterDummyNodeClass; + +struct _ClutterDummyNode +{ + ClutterPaintNode parent_instance; +}; + +GType _clutter_dummy_node_get_type (void) G_GNUC_CONST; + +G_DEFINE_TYPE (ClutterDummyNode, clutter_dummy_node, CLUTTER_TYPE_PAINT_NODE) + +static gboolean +clutter_dummy_node_pre_draw (ClutterPaintNode *node) +{ + return TRUE; +} + +static void +clutter_dummy_node_class_init (ClutterDummyNodeClass *klass) +{ + ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass); + + node_class->pre_draw = clutter_dummy_node_pre_draw; +} + +static void +clutter_dummy_node_init (ClutterDummyNode *self) +{ +} + +ClutterPaintNode * +_clutter_dummy_node_new (void) +{ + return _clutter_paint_node_internal (_clutter_dummy_node_get_type ()); +} + +/* + * Pipeline node + */ + +struct _ClutterPipelineNode +{ + ClutterPaintNode parent_instance; + + CoglPipeline *pipeline; +}; + +struct _ClutterPipelineNodeClass +{ + ClutterPaintNodeClass parent_class; +}; + +G_DEFINE_TYPE (ClutterPipelineNode, clutter_pipeline_node, CLUTTER_TYPE_PAINT_NODE) + +static void +clutter_pipeline_node_finalize (ClutterPaintNode *node) +{ + ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node); + + if (pnode->pipeline != NULL) + cogl_object_unref (pnode->pipeline); + + CLUTTER_PAINT_NODE_CLASS (clutter_pipeline_node_parent_class)->finalize (node); +} + +static gboolean +clutter_pipeline_node_pre_draw (ClutterPaintNode *node) +{ + ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node); + + if (node->operations != NULL && + pnode->pipeline != NULL) + { + cogl_push_source (pnode->pipeline); + return TRUE; + } + + return FALSE; +} + +static void +clutter_pipeline_node_draw (ClutterPaintNode *node) +{ + ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node); + guint i; + + if (pnode->pipeline == NULL) + return; + + if (node->operations == NULL) + return; + + for (i = 0; i < node->operations->len; i++) + { + const ClutterPaintOperation *op; + + op = &g_array_index (node->operations, ClutterPaintOperation, i); + + switch (op->opcode) + { + case PAINT_OP_INVALID: + break; + + case PAINT_OP_TEX_RECT: + cogl_rectangle_with_texture_coords (op->op.texrect[0], + op->op.texrect[1], + op->op.texrect[2], + op->op.texrect[3], + op->op.texrect[4], + op->op.texrect[5], + op->op.texrect[6], + op->op.texrect[7]); + break; + + case PAINT_OP_PATH: + cogl_path_fill (op->op.path); + break; + + case PAINT_OP_PRIMITIVE: + { + CoglFramebuffer *fb = cogl_get_draw_framebuffer (); + + cogl_framebuffer_draw_primitive (fb, pnode->pipeline, + op->op.primitive); + } + break; + } + } +} + +static void +clutter_pipeline_node_post_draw (ClutterPaintNode *node) +{ + cogl_pop_source (); +} + +static void +clutter_pipeline_node_class_init (ClutterPipelineNodeClass *klass) +{ + ClutterPaintNodeClass *node_class; + + node_class = CLUTTER_PAINT_NODE_CLASS (klass); + node_class->pre_draw = clutter_pipeline_node_pre_draw; + node_class->draw = clutter_pipeline_node_draw; + node_class->post_draw = clutter_pipeline_node_post_draw; + node_class->finalize = clutter_pipeline_node_finalize; +} + +static void +clutter_pipeline_node_init (ClutterPipelineNode *self) +{ +} + +/** + * clutter_pipeline_node_new: + * @pipeline: (allow-none): a Cogl pipeline state object, or %NULL + * + * Creates a new #ClutterPaintNode that will use the @pipeline to + * paint its contents. + * + * This function will acquire a reference on the passed @pipeline, + * so it is safe to call cogl_object_unref() when it returns. + * + * Return value: (transfer full): the newly created #ClutterPaintNode. + * Use clutter_paint_node_unref() when done. + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_pipeline_node_new (CoglPipeline *pipeline) +{ + ClutterPipelineNode *res; + + g_return_val_if_fail (pipeline == NULL || cogl_is_pipeline (pipeline), NULL); + + res = _clutter_paint_node_internal (CLUTTER_TYPE_PIPELINE_NODE); + + if (pipeline != NULL) + res->pipeline = cogl_object_ref (pipeline); + + return (ClutterPaintNode *) res; +} + +/* + * Color node + */ + +/** + * ClutterColorNode: + * + * The ClutterColorNode structure is an opaque + * type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +struct _ClutterColorNode +{ + ClutterPipelineNode parent_instance; +}; + +/** + * ClutterColorNode: + * + * The ClutterColorNodeClass structure is an + * opaque type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +struct _ClutterColorNodeClass +{ + ClutterPipelineNodeClass parent_class; +}; + +G_DEFINE_TYPE (ClutterColorNode, clutter_color_node, CLUTTER_TYPE_PIPELINE_NODE) + +static void +clutter_color_node_class_init (ClutterColorNodeClass *klass) +{ + +} + +static void +clutter_color_node_init (ClutterColorNode *cnode) +{ + ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (cnode); + + g_assert (default_color_pipeline != NULL); + pnode->pipeline = cogl_pipeline_copy (default_color_pipeline); +} + +/** + * clutter_color_node_new: + * @color: (allow-none): the color to paint, or %NULL + * + * Creates a new #ClutterPaintNode that will paint a solid color + * fill using @color. + * + * Return value: (transfer full): the newly created #ClutterPaintNode. Use + * clutter_paint_node_unref() when done + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_color_node_new (const ClutterColor *color) +{ + ClutterPipelineNode *cnode; + + cnode = _clutter_paint_node_internal (CLUTTER_TYPE_COLOR_NODE); + + if (color != NULL) + { + CoglColor cogl_color; + + cogl_color_init_from_4ub (&cogl_color, + color->red, + color->green, + color->blue, + color->alpha); + cogl_color_premultiply (&cogl_color); + + cogl_pipeline_set_color (cnode->pipeline, &cogl_color); + } + + return (ClutterPaintNode *) cnode; +} + +/* + * Texture node + */ + +/** + * ClutterTextureNode: + * + * The ClutterTextureNode structure is an opaque + * type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +struct _ClutterTextureNode +{ + ClutterPipelineNode parent_instance; +}; + +/** + * ClutterTextureNode: + * + * The ClutterTextureNodeClass structure is an + * opaque type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +struct _ClutterTextureNodeClass +{ + ClutterPipelineNodeClass parent_class; +}; + +G_DEFINE_TYPE (ClutterTextureNode, clutter_texture_node, CLUTTER_TYPE_PIPELINE_NODE) + +static void +clutter_texture_node_class_init (ClutterTextureNodeClass *klass) +{ +} + +static void +clutter_texture_node_init (ClutterTextureNode *self) +{ + ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (self); + + g_assert (default_texture_pipeline != NULL); + pnode->pipeline = cogl_pipeline_copy (default_texture_pipeline); +} + +/** + * clutter_texture_node_new: + * @texture: (allow-none): a #CoglTexture + * @color: (allow-none): a #ClutterColor + * + * Creates a new #ClutterPaintNode that will paint the passed @texture. + * + * This function will take a reference on @texture, so it is safe to + * call cogl_object_unref() on @texture when it returns. + * + * Return value: (transfer full): the newly created #ClutterPaintNode. + * Use clutter_paint_node_unref() when done + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_texture_node_new (CoglTexture *texture, + const ClutterColor *color) +{ + ClutterPipelineNode *tnode; + + g_return_val_if_fail (texture == NULL || cogl_is_texture (texture), NULL); + + tnode = _clutter_paint_node_internal (CLUTTER_TYPE_TEXTURE_NODE); + + if (texture != NULL) + cogl_pipeline_set_layer_texture (tnode->pipeline, 0, texture); + + if (color != NULL) + { + CoglColor cogl_color; + + cogl_color_init_from_4ub (&cogl_color, + color->red, + color->green, + color->blue, + color->alpha); + cogl_color_premultiply (&cogl_color); + cogl_pipeline_set_color (tnode->pipeline, &cogl_color); + } + + return (ClutterPaintNode *) tnode; +} + +/* + * Text node + */ + +struct _ClutterTextNode +{ + ClutterPaintNode parent_instance; + + PangoLayout *layout; + CoglColor color; +}; + +struct _ClutterTextNodeClass +{ + ClutterPaintNodeClass parent_class; +}; + +G_DEFINE_TYPE (ClutterTextNode, clutter_text_node, CLUTTER_TYPE_PAINT_NODE) + +static void +clutter_text_node_finalize (ClutterPaintNode *node) +{ + ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node); + + if (tnode->layout != NULL) + g_object_unref (tnode->layout); + + CLUTTER_PAINT_NODE_CLASS (clutter_text_node_parent_class)->finalize (node); +} + +static gboolean +clutter_text_node_pre_draw (ClutterPaintNode *node) +{ + ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node); + + return tnode->layout != NULL; +} + +static void +clutter_text_node_draw (ClutterPaintNode *node) +{ + ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node); + PangoRectangle ink_extents; + guint i; + + if (node->operations == NULL) + return; + + pango_layout_get_pixel_extents (tnode->layout, &ink_extents, NULL); + + for (i = 0; i < node->operations->len; i++) + { + const ClutterPaintOperation *op; + float op_width, op_height; + gboolean clipped = FALSE; + + op = &g_array_index (node->operations, ClutterPaintOperation, i); + + switch (op->opcode) + { + case PAINT_OP_TEX_RECT: + op_width = op->op.texrect[2] - op->op.texrect[0]; + op_height = op->op.texrect[3] - op->op.texrect[1]; + + /* if the primitive size was smaller than the layout, + * we clip the layout when drawin, to avoid spilling + * it out + */ + if (ink_extents.width > op_width || + ink_extents.height > op_height) + { + cogl_clip_push_rectangle (op->op.texrect[0], + op->op.texrect[1], + op->op.texrect[2], + op->op.texrect[3]); + clipped = TRUE; + } + + cogl_pango_render_layout (tnode->layout, + op->op.texrect[0], + op->op.texrect[1], + &tnode->color, + 0); + + if (clipped) + cogl_clip_pop (); + break; + + case PAINT_OP_PATH: + case PAINT_OP_PRIMITIVE: + case PAINT_OP_INVALID: + break; + } + } +} + +static void +clutter_text_node_class_init (ClutterTextNodeClass *klass) +{ + ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass); + + node_class->pre_draw = clutter_text_node_pre_draw; + node_class->draw = clutter_text_node_draw; + node_class->finalize = clutter_text_node_finalize; +} + +static void +clutter_text_node_init (ClutterTextNode *self) +{ + cogl_color_init_from_4f (&self->color, 0.0, 0.0, 0.0, 1.0); +} + +/** + * clutter_text_node_new: + * @layout: (allow-none): a #PangoLayout, or %NULL + * @color: (allow-none): the color used to paint the layout, + * or %NULL + * + * Creates a new #ClutterPaintNode that will paint a #PangoLayout + * with the given color. + * + * This function takes a reference on the passed @layout, so it + * is safe to call g_object_unref() after it returns. + * + * Return value: (transfer full): the newly created #ClutterPaintNode. + * Use clutter_paint_node_unref() when done + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_text_node_new (PangoLayout *layout, + const ClutterColor *color) +{ + ClutterTextNode *res; + + g_return_val_if_fail (layout == NULL || PANGO_IS_LAYOUT (layout), NULL); + + res = _clutter_paint_node_internal (CLUTTER_TYPE_TEXT_NODE); + + if (layout != NULL) + res->layout = g_object_ref (layout); + + if (color != NULL) + { + cogl_color_init_from_4ub (&res->color, + color->red, + color->green, + color->blue, + color->alpha); + } + + return (ClutterPaintNode *) res; +} + +/* + * Clip node + */ +struct _ClutterClipNode +{ + ClutterPaintNode parent_instance; +}; + +struct _ClutterClipNodeClass +{ + ClutterPaintNodeClass parent_class; +}; + +G_DEFINE_TYPE (ClutterClipNode, clutter_clip_node, CLUTTER_TYPE_PAINT_NODE) + +static gboolean +clutter_clip_node_pre_draw (ClutterPaintNode *node) +{ + gboolean retval = FALSE; + CoglFramebuffer *fb; + guint i; + + if (node->operations == NULL) + return FALSE; + + fb = cogl_get_draw_framebuffer (); + + for (i = 0; i < node->operations->len; i++) + { + const ClutterPaintOperation *op; + + op = &g_array_index (node->operations, ClutterPaintOperation, i); + + switch (op->opcode) + { + case PAINT_OP_TEX_RECT: + cogl_framebuffer_push_rectangle_clip (fb, + op->op.texrect[0], + op->op.texrect[1], + op->op.texrect[2], + op->op.texrect[3]); + retval = TRUE; + break; + + case PAINT_OP_PATH: + cogl_framebuffer_push_path_clip (fb, op->op.path); + retval = TRUE; + break; + + case PAINT_OP_PRIMITIVE: + case PAINT_OP_INVALID: + break; + } + } + + return retval; +} + +static void +clutter_clip_node_post_draw (ClutterPaintNode *node) +{ + CoglFramebuffer *fb; + guint i; + + if (node->operations == NULL) + return; + + fb = cogl_get_draw_framebuffer (); + + for (i = 0; i < node->operations->len; i++) + { + const ClutterPaintOperation *op; + + op = &g_array_index (node->operations, ClutterPaintOperation, i); + + switch (op->opcode) + { + case PAINT_OP_PATH: + case PAINT_OP_TEX_RECT: + cogl_framebuffer_pop_clip (fb); + break; + + case PAINT_OP_PRIMITIVE: + case PAINT_OP_INVALID: + break; + } + } +} + +static void +clutter_clip_node_class_init (ClutterClipNodeClass *klass) +{ + ClutterPaintNodeClass *node_class; + + node_class = CLUTTER_PAINT_NODE_CLASS (klass); + node_class->pre_draw = clutter_clip_node_pre_draw; + node_class->post_draw = clutter_clip_node_post_draw; +} + +static void +clutter_clip_node_init (ClutterClipNode *self) +{ +} + +/** + * clutter_clip_node_new: + * + * Creates a new #ClutterPaintNode that will clip its child + * nodes to the 2D regions added to it. + * + * Return value: (transfer full): the newly created #ClutterPaintNode. + * Use clutter_paint_node_unref() when done. + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_clip_node_new (void) +{ + return _clutter_paint_node_internal (CLUTTER_TYPE_CLIP_NODE); +} + +/* + * ClutterLayerNode + */ + +struct _ClutterLayerNode +{ + ClutterPaintNode parent_instance; + + cairo_rectangle_t viewport; + + CoglMatrix projection; + + float fbo_width; + float fbo_height; + + CoglPipeline *state; + CoglFramebuffer *offscreen; + CoglTexture *texture; + + guint8 opacity; +}; + +struct _ClutterLayerNodeClass +{ + ClutterPaintNodeClass parent_class; +}; + +G_DEFINE_TYPE (ClutterLayerNode, clutter_layer_node, CLUTTER_TYPE_PAINT_NODE) + +static gboolean +clutter_layer_node_pre_draw (ClutterPaintNode *node) +{ + ClutterLayerNode *lnode = (ClutterLayerNode *) node; + CoglMatrix matrix; + + /* if we were unable to create an offscreen buffer for this node, then + * we simply ignore it + */ + if (lnode->offscreen == NULL) + return FALSE; + + /* if no geometry was submitted for this node then we simply ignore it */ + if (node->operations == NULL) + return FALSE; + + /* copy the same modelview from the current framebuffer to the one we + * are going to use + */ + cogl_get_modelview_matrix (&matrix); + + cogl_push_framebuffer (lnode->offscreen); + + cogl_framebuffer_set_modelview_matrix (lnode->offscreen, &matrix); + + cogl_framebuffer_set_viewport (lnode->offscreen, + lnode->viewport.x, + lnode->viewport.y, + lnode->viewport.width, + lnode->viewport.height); + + cogl_framebuffer_set_projection_matrix (lnode->offscreen, + &lnode->projection); + + /* clear out the target framebuffer */ + cogl_framebuffer_clear4f (lnode->offscreen, + COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH, + 0.f, 0.f, 0.f, 0.f); + + cogl_push_matrix (); + + /* every draw operation after this point will happen an offscreen + * framebuffer + */ + + return TRUE; +} + +static void +clutter_layer_node_post_draw (ClutterPaintNode *node) +{ + ClutterLayerNode *lnode = CLUTTER_LAYER_NODE (node); + CoglFramebuffer *fb; + guint i; + + /* switch to the previous framebuffer */ + cogl_pop_matrix (); + cogl_pop_framebuffer (); + + fb = cogl_get_draw_framebuffer (); + + for (i = 0; i < node->operations->len; i++) + { + const ClutterPaintOperation *op; + + op = &g_array_index (node->operations, ClutterPaintOperation, i); + switch (op->opcode) + { + case PAINT_OP_INVALID: + break; + + case PAINT_OP_TEX_RECT: + /* now we need to paint the texture */ + cogl_push_source (lnode->state); + cogl_rectangle_with_texture_coords (op->op.texrect[0], + op->op.texrect[1], + op->op.texrect[2], + op->op.texrect[3], + op->op.texrect[4], + op->op.texrect[5], + op->op.texrect[6], + op->op.texrect[7]); + cogl_pop_source (); + break; + + case PAINT_OP_PATH: + cogl_push_source (lnode->state); + cogl_path_fill (op->op.path); + cogl_pop_source (); + break; + + case PAINT_OP_PRIMITIVE: + cogl_framebuffer_draw_primitive (fb, lnode->state, op->op.primitive); + break; + } + } +} + +static void +clutter_layer_node_finalize (ClutterPaintNode *node) +{ + ClutterLayerNode *lnode = CLUTTER_LAYER_NODE (node); + + if (lnode->state != NULL) + cogl_object_unref (lnode->state); + + if (lnode->offscreen != NULL) + cogl_object_unref (lnode->offscreen); + + CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node); +} + +static void +clutter_layer_node_class_init (ClutterLayerNodeClass *klass) +{ + ClutterPaintNodeClass *node_class; + + node_class = CLUTTER_PAINT_NODE_CLASS (klass); + node_class->pre_draw = clutter_layer_node_pre_draw; + node_class->post_draw = clutter_layer_node_post_draw; + node_class->finalize = clutter_layer_node_finalize; +} + +static void +clutter_layer_node_init (ClutterLayerNode *self) +{ + cogl_matrix_init_identity (&self->projection); +} + +/** + * clutter_layer_node_new: + * @projection: the projection matrix to use to set up the layer + * @viewport: (type cairo.Rectangle): the viewport to use to set up the layer + * @width: the width of the layer + * @height: the height of the layer + * @opacity: the opacity to be used when drawing the layer + * + * Creates a new #ClutterLayerNode. + * + * All children of this node will be painted inside a separate + * framebuffer; the framebuffer will then be painted using the + * given @opacity. + * + * Return value: (transfer full): the newly created #ClutterLayerNode. + * Use clutter_paint_node_unref() when done. + * + * Since: 1.10 + */ +ClutterPaintNode * +clutter_layer_node_new (const CoglMatrix *projection, + const cairo_rectangle_t *viewport, + float width, + float height, + guint8 opacity) +{ + ClutterLayerNode *res; + CoglColor color; + + res = _clutter_paint_node_internal (CLUTTER_TYPE_LAYER_NODE); + + res->projection = *projection; + res->viewport = *viewport; + res->fbo_width = width; + res->fbo_height = height; + res->opacity = opacity; + + /* the texture backing the FBO */ + res->texture = cogl_texture_new_with_size (MAX (res->fbo_width, 1), + MAX (res->fbo_height, 1), + COGL_TEXTURE_NO_SLICING, + COGL_PIXEL_FORMAT_RGBA_8888_PRE); + + res->offscreen = cogl_offscreen_new_to_texture (res->texture); + if (res->offscreen == NULL) + { + g_critical ("%s: Unable to create an offscreen buffer", G_STRLOC); + + cogl_object_unref (res->texture); + res->texture = NULL; + + goto out;; + } + + cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); + + /* the pipeline used to paint the texture; we use nearest + * interpolation filters because the texture is always + * going to be painted at a 1:1 texel:pixel ratio + */ + res->state = cogl_pipeline_copy (default_texture_pipeline); + cogl_pipeline_set_layer_filters (res->state, 0, + COGL_PIPELINE_FILTER_NEAREST, + COGL_PIPELINE_FILTER_NEAREST); + cogl_pipeline_set_layer_texture (res->state, 0, res->texture); + cogl_pipeline_set_color (res->state, &color); + cogl_object_unref (res->texture); + +out: + return (ClutterPaintNode *) res; +} diff --git a/clutter/clutter-paint-nodes.h b/clutter/clutter-paint-nodes.h new file mode 100644 index 000000000..8305e47cc --- /dev/null +++ b/clutter/clutter-paint-nodes.h @@ -0,0 +1,161 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_PAINT_NODES_H__ +#define __CLUTTER_PAINT_NODES_H__ + +#include +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_COLOR_NODE (clutter_color_node_get_type ()) +#define CLUTTER_COLOR_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_COLOR_NODE, ClutterColorNode)) +#define CLUTTER_IS_COLOR_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_COLOR_NODE)) + +/** + * ClutterColorNode: + * + * The ClutterTextNode structure is an opaque + * type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +typedef struct _ClutterColorNode ClutterColorNode; +typedef struct _ClutterColorNodeClass ClutterColorNodeClass; + +GType clutter_color_node_get_type (void) G_GNUC_CONST; + +ClutterPaintNode * clutter_color_node_new (const ClutterColor *color); + +#define CLUTTER_TYPE_TEXTURE_NODE (clutter_texture_node_get_type ()) +#define CLUTTER_TEXTURE_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXTURE_NODE, ClutterTextureNode)) +#define CLUTTER_IS_TEXTURE_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TEXTURE_NODE)) + +/** + * ClutterTextureNode: + * + * The ClutterTextNode structure is an opaque + * type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +typedef struct _ClutterTextureNode ClutterTextureNode; +typedef struct _ClutterTextureNodeClass ClutterTextureNodeClass; + +GType clutter_texture_node_get_type (void) G_GNUC_CONST; + +ClutterPaintNode * clutter_texture_node_new (CoglTexture *texture, + const ClutterColor *color); + +#define CLUTTER_TYPE_CLIP_NODE (clutter_clip_node_get_type ()) +#define CLUTTER_CLIP_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CLIP_NODE, ClutterClipNode)) +#define CLUTTER_IS_CLIP_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CLIP_NODE)) + +/** + * ClutterClipNode: + * + * The ClutterTextNode structure is an opaque + * type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +typedef struct _ClutterClipNode ClutterClipNode; +typedef struct _ClutterClipNodeClass ClutterClipNodeClass; + +GType clutter_clip_node_get_type (void) G_GNUC_CONST; + +ClutterPaintNode * clutter_clip_node_new (void); + +#define CLUTTER_TYPE_PIPELINE_NODE (clutter_pipeline_node_get_type ()) +#define CLUTTER_PIPELINE_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PIPELINE_NODE, ClutterPipelineNode)) +#define CLUTTER_IS_PIPELINE_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PIPELINE_NODE)) + +/** + * ClutterPipelineNode: + * + * The ClutterTextNode structure is an opaque + * type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +typedef struct _ClutterPipelineNode ClutterPipelineNode; +typedef struct _ClutterPipelineNodeClass ClutterPipelineNodeClass; + +GType clutter_pipeline_node_get_type (void) G_GNUC_CONST; + +#if defined(COGL_ENABLE_EXPERIMENTAL_2_0_API) && defined(CLUTTER_ENABLE_EXPERIMENTAL_API) +ClutterPaintNode * clutter_pipeline_node_new (CoglPipeline *pipeline); +#endif /* COGL_ENABLE_EXPERIMENTAL_2_0_API && CLUTTER_ENABLE_EXPERIMENTAL_API */ + +#define CLUTTER_TYPE_TEXT_NODE (clutter_text_node_get_type ()) +#define CLUTTER_TEXT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXT_NODE, ClutterTextNode)) +#define CLUTTER_IS_TEXT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TEXT_NODE)) + +/** + * ClutterTextNode: + * + * The ClutterTextNode structure is an opaque + * type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +typedef struct _ClutterTextNode ClutterTextNode; +typedef struct _ClutterTextNodeClass ClutterTextNodeClass; + +GType clutter_text_node_get_type (void) G_GNUC_CONST; + +ClutterPaintNode * clutter_text_node_new (PangoLayout *layout, + const ClutterColor *color); + +#define CLUTTER_TYPE_LAYER_NODE (clutter_layer_node_get_type ()) +#define CLUTTER_LAYER_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYER_NODE, ClutterLayerNode)) +#define CLUTTER_IS_LAYER_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LAYER_NODE)) + +/** + * ClutterLayerNode: + * + * The ClutterLayerNode structure is an opaque + * type whose members cannot be directly accessed. + * + * Since: 1.10 + */ +typedef struct _ClutterLayerNode ClutterLayerNode; +typedef struct _ClutterLayerNodeClass ClutterLayerNodeClass; + +GType clutter_layer_node_get_type (void) G_GNUC_CONST; + +ClutterPaintNode * clutter_layer_node_new (const CoglMatrix *projection, + const cairo_rectangle_t *viewport, + float width, + float height, + guint8 opacity); + +G_END_DECLS + +#endif /* __CLUTTER_PAINT_NODES_H__ */ diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h index 226e2e812..3fd93350e 100644 --- a/clutter/clutter-types.h +++ b/clutter/clutter-types.h @@ -53,6 +53,7 @@ typedef struct _ClutterLayoutMeta ClutterLayoutMeta; typedef struct _ClutterActorMeta ClutterActorMeta; typedef struct _ClutterLayoutManager ClutterLayoutManager; typedef struct _ClutterActorIter ClutterActorIter; +typedef struct _ClutterPaintNode ClutterPaintNode; typedef struct _ClutterAlpha ClutterAlpha; typedef struct _ClutterAnimatable ClutterAnimatable; /* dummy */ diff --git a/clutter/clutter.h b/clutter/clutter.h index 0d8befff9..52d443fa8 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -80,6 +80,8 @@ #include "clutter-model.h" #include "clutter-offscreen-effect.h" #include "clutter-page-turn-effect.h" +#include "clutter-paint-nodes.h" +#include "clutter-paint-node.h" #include "clutter-path-constraint.h" #include "clutter-path.h" #include "clutter-property-transition.h"