dae089f79e
It is no longer used anywhere. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1707>
1290 lines
34 KiB
C
1290 lines
34 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author:
|
|
* Emmanuele Bassi <ebassi@linux.intel.com>
|
|
*/
|
|
|
|
/**
|
|
* 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 #ClutterPaintNode<!-- -->s to
|
|
* the render graph.
|
|
*/
|
|
|
|
/**
|
|
* ClutterPaintNode: (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)
|
|
*
|
|
* The `ClutterPaintNode` structure contains only private data
|
|
* and it should be accessed using the provided API.
|
|
*
|
|
* Since: 1.10
|
|
*/
|
|
|
|
/**
|
|
* ClutterPaintNodeClass:
|
|
*
|
|
* The `ClutterPaintNodeClass` structure contains only private data.
|
|
*
|
|
* Since: 1.10
|
|
*/
|
|
|
|
#include "clutter-build-config.h"
|
|
|
|
#include <pango/pango.h>
|
|
#include <cogl/cogl.h>
|
|
#include <json-glib/json-glib.h>
|
|
|
|
#include "clutter-paint-node-private.h"
|
|
|
|
#include "clutter-debug.h"
|
|
#include "clutter-private.h"
|
|
|
|
#include <gobject/gvaluecollector.h>
|
|
|
|
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;
|
|
|
|
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,
|
|
ClutterPaintContext *paint_context)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
clutter_paint_node_real_draw (ClutterPaintNode *node,
|
|
ClutterPaintContext *paint_context)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clutter_paint_node_real_post_draw (ClutterPaintNode *node,
|
|
ClutterPaintContext *paint_context)
|
|
{
|
|
}
|
|
|
|
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 intern @name using g_intern_string(). If you have access to a
|
|
* static string, use clutter_paint_node_set_static_name() instead.
|
|
*
|
|
* Since: 1.10
|
|
*/
|
|
void
|
|
clutter_paint_node_set_name (ClutterPaintNode *node,
|
|
const char *name)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
|
|
|
|
node->name = g_intern_string (name);
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_node_set_static_name: (skip)
|
|
*
|
|
* Like clutter_paint_node_set_name() but uses a static or interned string
|
|
* containing the name.
|
|
*/
|
|
void
|
|
clutter_paint_node_set_static_name (ClutterPaintNode *node,
|
|
const char *name)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
|
|
|
|
node->name = 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_TEX_RECTS:
|
|
case PAINT_OP_MULTITEX_RECT:
|
|
g_clear_pointer (&op->coords, g_array_unref);
|
|
break;
|
|
|
|
case PAINT_OP_PRIMITIVE:
|
|
if (op->op.primitive != NULL)
|
|
cogl_object_unref (op->op.primitive);
|
|
break;
|
|
}
|
|
}
|
|
|
|
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_tex_rects (ClutterPaintOperation *op,
|
|
const float *coords,
|
|
unsigned int n_rects,
|
|
gboolean use_default_tex_coords)
|
|
{
|
|
const unsigned int n_floats = n_rects * 8;
|
|
|
|
clutter_paint_operation_clear (op);
|
|
|
|
op->opcode = PAINT_OP_TEX_RECTS;
|
|
op->coords = g_array_sized_new (FALSE, FALSE, sizeof (float), n_floats);
|
|
|
|
if (use_default_tex_coords)
|
|
{
|
|
const float default_tex_coords[4] = { 0.0, 0.0, 1.0, 1.0 };
|
|
int i;
|
|
|
|
for (i = 0; i < n_rects; i++)
|
|
{
|
|
g_array_append_vals (op->coords, &coords[i * 4], 4);
|
|
g_array_append_vals (op->coords, default_tex_coords, 4);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_array_append_vals (op->coords, coords, n_floats);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
clutter_paint_op_init_multitex_rect (ClutterPaintOperation *op,
|
|
const ClutterActorBox *rect,
|
|
const float *tex_coords,
|
|
unsigned int tex_coords_len)
|
|
{
|
|
clutter_paint_operation_clear (op);
|
|
|
|
op->opcode = PAINT_OP_MULTITEX_RECT;
|
|
op->coords = g_array_sized_new (FALSE, FALSE,
|
|
sizeof (float),
|
|
tex_coords_len);
|
|
|
|
g_array_append_vals (op->coords, tex_coords, tex_coords_len);
|
|
|
|
op->op.texrect[0] = rect->x1;
|
|
op->op.texrect[1] = rect->y1;
|
|
op->op.texrect[2] = rect->x2;
|
|
op->op.texrect[3] = rect->y2;
|
|
}
|
|
|
|
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 = PAINT_OP_INIT;
|
|
|
|
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 = PAINT_OP_INIT;
|
|
|
|
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_multitexture_rectangle:
|
|
* @node: a #ClutterPaintNode
|
|
* @rect: a #ClutterActorBox
|
|
* @text_coords: array of multitexture values
|
|
* @text_coords_len: number of items of @text_coords
|
|
*
|
|
* Adds a rectangle region to the @node, with multitexture coordinates.
|
|
*/
|
|
void
|
|
clutter_paint_node_add_multitexture_rectangle (ClutterPaintNode *node,
|
|
const ClutterActorBox *rect,
|
|
const float *text_coords,
|
|
unsigned int text_coords_len)
|
|
{
|
|
ClutterPaintOperation operation = PAINT_OP_INIT;
|
|
|
|
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_multitex_rect (&operation, rect, text_coords, text_coords_len);
|
|
g_array_append_val (node->operations, operation);
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_node_add_rectangles:
|
|
* @node: a #ClutterPaintNode
|
|
* @coords: (in) (array length=n_rects) (transfer none): array of
|
|
* coordinates containing groups of 4 float values: [x_1, y_1, x_2, y_2] that
|
|
* are interpreted as two position coordinates; one for the top left of the
|
|
* rectangle (x1, y1), and one for the bottom right of the rectangle
|
|
* (x2, y2).
|
|
* @n_rects: number of rectangles defined in @coords.
|
|
*
|
|
* Adds a series of rectangles to @node.
|
|
*
|
|
* As a general rule for better performance its recommended to use this API
|
|
* instead of calling clutter_paint_node_add_rectangle() separately for
|
|
* multiple rectangles if all of the rectangles will be drawn together.
|
|
*
|
|
* See cogl_framebuffer_draw_rectangles().
|
|
*/
|
|
void
|
|
clutter_paint_node_add_rectangles (ClutterPaintNode *node,
|
|
const float *coords,
|
|
unsigned int n_rects)
|
|
{
|
|
ClutterPaintOperation operation = PAINT_OP_INIT;
|
|
|
|
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
|
|
g_return_if_fail (coords != NULL);
|
|
|
|
clutter_paint_node_maybe_init_operations (node);
|
|
|
|
clutter_paint_op_init_tex_rects (&operation, coords, n_rects, TRUE);
|
|
g_array_append_val (node->operations, operation);
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_node_add_texture_rectangles:
|
|
* @node: a #ClutterPaintNode
|
|
* @coords: (in) (array length=n_rects) (transfer none): array containing
|
|
* groups of 8 float values: [x_1, y_1, x_2, y_2, s_1, t_1, s_2, t_2]
|
|
* that have the same meaning as the arguments for
|
|
* cogl_framebuffer_draw_textured_rectangle().
|
|
* @n_rects: number of rectangles defined in @coords.
|
|
*
|
|
* Adds a series of rectangles to @node.
|
|
*
|
|
* The given texture coordinates should always be normalized such that
|
|
* (0, 0) corresponds to the top left and (1, 1) corresponds to the
|
|
* bottom right. To map an entire texture across the rectangle pass
|
|
* in s_1=0, t_1=0, s_2=1, t_2=1.
|
|
*
|
|
* See cogl_framebuffer_draw_textured_rectangles().
|
|
*/
|
|
void
|
|
clutter_paint_node_add_texture_rectangles (ClutterPaintNode *node,
|
|
const float *coords,
|
|
unsigned int n_rects)
|
|
{
|
|
ClutterPaintOperation operation = PAINT_OP_INIT;
|
|
|
|
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
|
|
g_return_if_fail (coords != NULL);
|
|
|
|
clutter_paint_node_maybe_init_operations (node);
|
|
|
|
clutter_paint_op_init_tex_rects (&operation, coords, n_rects, FALSE);
|
|
g_array_append_val (node->operations, operation);
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_node_add_primitive: (skip)
|
|
* @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 = PAINT_OP_INIT;
|
|
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* 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,
|
|
ClutterPaintContext *paint_context)
|
|
{
|
|
ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node);
|
|
ClutterPaintNode *iter;
|
|
gboolean res;
|
|
|
|
res = klass->pre_draw (node, paint_context);
|
|
|
|
if (res)
|
|
{
|
|
klass->draw (node, paint_context);
|
|
}
|
|
|
|
for (iter = node->first_child;
|
|
iter != NULL;
|
|
iter = iter->next_sibling)
|
|
{
|
|
clutter_paint_node_paint (iter, paint_context);
|
|
}
|
|
|
|
if (res)
|
|
{
|
|
klass->post_draw (node, paint_context);
|
|
}
|
|
}
|
|
|
|
#ifdef CLUTTER_ENABLE_DEBUG
|
|
static JsonNode *
|
|
clutter_paint_node_serialize (ClutterPaintNode *node)
|
|
{
|
|
ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node);
|
|
|
|
if (klass->serialize != NULL)
|
|
return klass->serialize (node);
|
|
|
|
return json_node_new (JSON_NODE_NULL);
|
|
}
|
|
|
|
static JsonNode *
|
|
clutter_paint_node_to_json (ClutterPaintNode *node)
|
|
{
|
|
JsonBuilder *builder;
|
|
JsonNode *res;
|
|
|
|
builder = json_builder_new ();
|
|
|
|
json_builder_begin_object (builder);
|
|
|
|
json_builder_set_member_name (builder, "type");
|
|
json_builder_add_string_value (builder, g_type_name (G_TYPE_FROM_INSTANCE (node)));
|
|
|
|
json_builder_set_member_name (builder, "name");
|
|
json_builder_add_string_value (builder, node->name);
|
|
|
|
json_builder_set_member_name (builder, "node-data");
|
|
json_builder_add_value (builder, clutter_paint_node_serialize (node));
|
|
|
|
json_builder_set_member_name (builder, "operations");
|
|
json_builder_begin_array (builder);
|
|
|
|
if (node->operations != NULL)
|
|
{
|
|
guint i, j;
|
|
|
|
for (i = 0; i < node->operations->len; i++)
|
|
{
|
|
const ClutterPaintOperation *op;
|
|
|
|
op = &g_array_index (node->operations, ClutterPaintOperation, i);
|
|
json_builder_begin_object (builder);
|
|
|
|
switch (op->opcode)
|
|
{
|
|
case PAINT_OP_TEX_RECT:
|
|
json_builder_set_member_name (builder, "texrect");
|
|
json_builder_begin_array (builder);
|
|
json_builder_add_double_value (builder, op->op.texrect[0]);
|
|
json_builder_add_double_value (builder, op->op.texrect[1]);
|
|
json_builder_add_double_value (builder, op->op.texrect[2]);
|
|
json_builder_add_double_value (builder, op->op.texrect[3]);
|
|
json_builder_add_double_value (builder, op->op.texrect[4]);
|
|
json_builder_add_double_value (builder, op->op.texrect[5]);
|
|
json_builder_add_double_value (builder, op->op.texrect[6]);
|
|
json_builder_add_double_value (builder, op->op.texrect[7]);
|
|
json_builder_end_array (builder);
|
|
break;
|
|
|
|
case PAINT_OP_TEX_RECTS:
|
|
json_builder_set_member_name (builder, "texrects");
|
|
json_builder_begin_array (builder);
|
|
|
|
for (j = 0; i < op->coords->len; j++)
|
|
{
|
|
float coord = g_array_index (op->coords, float, j);
|
|
json_builder_add_double_value (builder, coord);
|
|
}
|
|
|
|
json_builder_end_array (builder);
|
|
break;
|
|
|
|
case PAINT_OP_MULTITEX_RECT:
|
|
json_builder_set_member_name (builder, "texrect");
|
|
json_builder_begin_array (builder);
|
|
|
|
for (j = 0; i < op->coords->len; j++)
|
|
{
|
|
float coord = g_array_index (op->coords, float, j);
|
|
json_builder_add_double_value (builder, coord);
|
|
}
|
|
|
|
json_builder_end_array (builder);
|
|
break;
|
|
|
|
case PAINT_OP_PRIMITIVE:
|
|
json_builder_set_member_name (builder, "primitive");
|
|
json_builder_add_int_value (builder, (intptr_t) op->op.primitive);
|
|
break;
|
|
|
|
case PAINT_OP_INVALID:
|
|
break;
|
|
}
|
|
|
|
json_builder_end_object (builder);
|
|
}
|
|
}
|
|
|
|
json_builder_end_array (builder);
|
|
|
|
json_builder_set_member_name (builder, "children");
|
|
json_builder_begin_array (builder);
|
|
|
|
if (node->first_child != NULL)
|
|
{
|
|
ClutterPaintNode *child;
|
|
|
|
for (child = node->first_child;
|
|
child != NULL;
|
|
child = child->next_sibling)
|
|
{
|
|
JsonNode *n = clutter_paint_node_to_json (child);
|
|
|
|
json_builder_add_value (builder, n);
|
|
}
|
|
}
|
|
|
|
json_builder_end_array (builder);
|
|
|
|
json_builder_end_object (builder);
|
|
|
|
res = json_builder_get_root (builder);
|
|
|
|
g_object_unref (builder);
|
|
|
|
return res;
|
|
}
|
|
#endif /* CLUTTER_ENABLE_DEBUG */
|
|
|
|
void
|
|
_clutter_paint_node_dump_tree (ClutterPaintNode *node)
|
|
{
|
|
#ifdef CLUTTER_ENABLE_DEBUG
|
|
JsonGenerator *gen = json_generator_new ();
|
|
char *str;
|
|
gsize len;
|
|
|
|
json_generator_set_root (gen, clutter_paint_node_to_json (node));
|
|
str = json_generator_to_data (gen, &len);
|
|
|
|
g_print ("Render tree starting from %p:\n%s\n", node, str);
|
|
|
|
g_free (str);
|
|
#endif /* CLUTTER_ENABLE_DEBUG */
|
|
}
|
|
|
|
/*< private >
|
|
* _clutter_paint_node_create:
|
|
* @gtype: a #ClutterPaintNode type
|
|
*
|
|
* Creates a new #ClutterPaintNode instance using @gtype
|
|
*
|
|
* Return value: (transfer full): the newly created #ClutterPaintNode
|
|
* sub-class instance; use clutter_paint_node_unref() when done
|
|
*/
|
|
gpointer
|
|
_clutter_paint_node_create (GType gtype)
|
|
{
|
|
g_return_val_if_fail (g_type_is_a (gtype, CLUTTER_TYPE_PAINT_NODE), NULL);
|
|
|
|
return (gpointer) g_type_create_instance (gtype);
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_node_get_framebuffer:
|
|
* @node: a #ClutterPaintNode
|
|
*
|
|
* Retrieves the #CoglFramebuffer that @node will draw
|
|
* into. If @node doesn't specify a custom framebuffer,
|
|
* the first ancestor with a custom framebuffer will be
|
|
* used.
|
|
*
|
|
* Returns: (transfer none): a #CoglFramebuffer or %NULL if no custom one is
|
|
* set.
|
|
*/
|
|
CoglFramebuffer *
|
|
clutter_paint_node_get_framebuffer (ClutterPaintNode *node)
|
|
{
|
|
ClutterPaintNodeClass *klass;
|
|
|
|
while (node)
|
|
{
|
|
klass = CLUTTER_PAINT_NODE_GET_CLASS (node);
|
|
|
|
if (klass->get_framebuffer != NULL)
|
|
return klass->get_framebuffer (node);
|
|
|
|
node = node->parent;
|
|
}
|
|
|
|
return NULL;
|
|
}
|