2009-12-04 13:06:32 +00:00
|
|
|
/*
|
|
|
|
* Cogl
|
|
|
|
*
|
2014-02-22 01:28:54 +00:00
|
|
|
* A Low Level GPU Graphics and Utilities API
|
2009-12-04 13:06:32 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2009 Intel Corporation.
|
|
|
|
*
|
2014-02-22 01:28:54 +00:00
|
|
|
* Permission is hereby granted, free of charge, to any person
|
|
|
|
* obtaining a copy of this software and associated documentation
|
|
|
|
* files (the "Software"), to deal in the Software without
|
|
|
|
* restriction, including without limitation the rights to use, copy,
|
|
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
|
|
* of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be
|
|
|
|
* included in all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
2010-03-01 12:56:10 +00:00
|
|
|
*
|
|
|
|
*
|
2009-12-04 13:06:32 +00:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Neil Roberts <neil@linux.intel.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
2011-10-13 21:34:30 +00:00
|
|
|
#include "cogl-util.h"
|
2010-08-02 14:24:03 +00:00
|
|
|
#include "cogl-rectangle-map.h"
|
2009-12-04 19:43:39 +00:00
|
|
|
#include "cogl-debug.h"
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Implements a data structure which keeps track of unused
|
|
|
|
sub-rectangles within a larger rectangle using a binary tree
|
|
|
|
structure. The algorithm for this is based on the description here:
|
|
|
|
|
|
|
|
http://www.blackpawn.com/texts/lightmaps/default.html
|
|
|
|
*/
|
|
|
|
|
2011-05-16 16:50:49 +00:00
|
|
|
#if defined (COGL_ENABLE_DEBUG) && defined (HAVE_CAIRO)
|
2009-12-04 19:43:39 +00:00
|
|
|
|
|
|
|
/* The cairo header is only used for debugging to generate an image of
|
|
|
|
the atlas */
|
|
|
|
#include <cairo.h>
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
static void _cogl_rectangle_map_dump_image (CoglRectangleMap *map);
|
2009-12-04 19:43:39 +00:00
|
|
|
|
2011-05-16 16:50:49 +00:00
|
|
|
#endif /* COGL_ENABLE_DEBUG && HAVE_CAIRO */
|
2009-12-04 19:43:39 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
typedef struct _CoglRectangleMapNode CoglRectangleMapNode;
|
|
|
|
typedef struct _CoglRectangleMapStackEntry CoglRectangleMapStackEntry;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
typedef void (* CoglRectangleMapInternalForeachCb) (CoglRectangleMapNode *node,
|
|
|
|
void *data);
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
COGL_RECTANGLE_MAP_BRANCH,
|
|
|
|
COGL_RECTANGLE_MAP_FILLED_LEAF,
|
|
|
|
COGL_RECTANGLE_MAP_EMPTY_LEAF
|
|
|
|
} CoglRectangleMapNodeType;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
struct _CoglRectangleMap
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *root;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
unsigned int n_rectangles;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-11 14:08:00 +00:00
|
|
|
unsigned int space_remaining;
|
|
|
|
|
2009-12-04 13:06:32 +00:00
|
|
|
GDestroyNotify value_destroy_func;
|
2010-08-06 16:40:52 +00:00
|
|
|
|
|
|
|
/* Stack used for walking the structure. This is only used during
|
|
|
|
the lifetime of a single function call but it is kept here as an
|
|
|
|
optimisation to avoid reallocating it every time it is needed */
|
|
|
|
GArray *stack;
|
2009-12-04 13:06:32 +00:00
|
|
|
};
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
struct _CoglRectangleMapNode
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNodeType type;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapEntry rectangle;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-11 14:08:00 +00:00
|
|
|
unsigned int largest_gap;
|
2010-08-06 15:13:20 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *parent;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
/* Fields used when this is a branch */
|
|
|
|
struct
|
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *left;
|
|
|
|
CoglRectangleMapNode *right;
|
2009-12-04 13:06:32 +00:00
|
|
|
} branch;
|
|
|
|
|
|
|
|
/* Field used when this is a filled leaf */
|
2010-08-02 14:24:03 +00:00
|
|
|
void *data;
|
2009-12-04 13:06:32 +00:00
|
|
|
} d;
|
|
|
|
};
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
struct _CoglRectangleMapStackEntry
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
|
|
|
/* The node to search */
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *node;
|
2009-12-04 13:06:32 +00:00
|
|
|
/* Index of next branch of this node to explore. Basically either 0
|
|
|
|
to go left or 1 to go right */
|
Switch use of primitive glib types to c99 equivalents
The coding style has for a long time said to avoid using redundant glib
data types such as gint or gchar etc because we feel that they make the
code look unnecessarily foreign to developers coming from outside of the
Gnome developer community.
Note: When we tried to find the historical rationale for the types we
just found that they were apparently only added for consistent syntax
highlighting which didn't seem that compelling.
Up until now we have been continuing to use some of the platform
specific type such as gint{8,16,32,64} and gsize but this patch switches
us over to using the standard c99 equivalents instead so we can further
ensure that our code looks familiar to the widest range of C developers
who might potentially contribute to Cogl.
So instead of using the gint{8,16,32,64} and guint{8,16,32,64} types this
switches all Cogl code to instead use the int{8,16,32,64}_t and
uint{8,16,32,64}_t c99 types instead.
Instead of gsize we now use size_t
For now we are not going to use the c99 _Bool type and instead we have
introduced a new CoglBool type to use instead of gboolean.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
(cherry picked from commit 5967dad2400d32ca6319cef6cb572e81bf2c15f0)
2012-04-16 20:56:40 +00:00
|
|
|
CoglBool next_index;
|
2009-12-04 13:06:32 +00:00
|
|
|
};
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
static CoglRectangleMapNode *
|
|
|
|
_cogl_rectangle_map_node_new (void)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
return g_slice_new (CoglRectangleMapNode);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_node_free (CoglRectangleMapNode *node)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
g_slice_free (CoglRectangleMapNode, node);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMap *
|
|
|
|
_cogl_rectangle_map_new (unsigned int width,
|
|
|
|
unsigned int height,
|
|
|
|
GDestroyNotify value_destroy_func)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMap *map = g_new (CoglRectangleMap, 1);
|
|
|
|
CoglRectangleMapNode *root = _cogl_rectangle_map_node_new ();
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
root->type = COGL_RECTANGLE_MAP_EMPTY_LEAF;
|
2009-12-04 13:06:32 +00:00
|
|
|
root->parent = NULL;
|
|
|
|
root->rectangle.x = 0;
|
|
|
|
root->rectangle.y = 0;
|
|
|
|
root->rectangle.width = width;
|
|
|
|
root->rectangle.height = height;
|
2010-08-11 14:08:00 +00:00
|
|
|
root->largest_gap = width * height;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
map->root = root;
|
|
|
|
map->n_rectangles = 0;
|
|
|
|
map->value_destroy_func = value_destroy_func;
|
2010-08-11 14:08:00 +00:00
|
|
|
map->space_remaining = width * height;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-06 16:40:52 +00:00
|
|
|
map->stack = g_array_new (FALSE, FALSE, sizeof (CoglRectangleMapStackEntry));
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
return map;
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
2010-08-06 16:40:52 +00:00
|
|
|
static void
|
|
|
|
_cogl_rectangle_map_stack_push (GArray *stack,
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *node,
|
Switch use of primitive glib types to c99 equivalents
The coding style has for a long time said to avoid using redundant glib
data types such as gint or gchar etc because we feel that they make the
code look unnecessarily foreign to developers coming from outside of the
Gnome developer community.
Note: When we tried to find the historical rationale for the types we
just found that they were apparently only added for consistent syntax
highlighting which didn't seem that compelling.
Up until now we have been continuing to use some of the platform
specific type such as gint{8,16,32,64} and gsize but this patch switches
us over to using the standard c99 equivalents instead so we can further
ensure that our code looks familiar to the widest range of C developers
who might potentially contribute to Cogl.
So instead of using the gint{8,16,32,64} and guint{8,16,32,64} types this
switches all Cogl code to instead use the int{8,16,32,64}_t and
uint{8,16,32,64}_t c99 types instead.
Instead of gsize we now use size_t
For now we are not going to use the c99 _Bool type and instead we have
introduced a new CoglBool type to use instead of gboolean.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
(cherry picked from commit 5967dad2400d32ca6319cef6cb572e81bf2c15f0)
2012-04-16 20:56:40 +00:00
|
|
|
CoglBool next_index)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-06 16:40:52 +00:00
|
|
|
CoglRectangleMapStackEntry *new_entry;
|
|
|
|
|
|
|
|
g_array_set_size (stack, stack->len + 1);
|
|
|
|
|
|
|
|
new_entry = &g_array_index (stack, CoglRectangleMapStackEntry,
|
|
|
|
stack->len - 1);
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
new_entry->node = node;
|
|
|
|
new_entry->next_index = next_index;
|
2010-08-06 16:40:52 +00:00
|
|
|
}
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-06 16:40:52 +00:00
|
|
|
static void
|
|
|
|
_cogl_rectangle_map_stack_pop (GArray *stack)
|
|
|
|
{
|
|
|
|
g_array_set_size (stack, stack->len - 1);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
static CoglRectangleMapStackEntry *
|
2010-08-06 16:40:52 +00:00
|
|
|
_cogl_rectangle_map_stack_get_top (GArray *stack)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-06 16:40:52 +00:00
|
|
|
return &g_array_index (stack, CoglRectangleMapStackEntry,
|
|
|
|
stack->len - 1);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
static CoglRectangleMapNode *
|
|
|
|
_cogl_rectangle_map_node_split_horizontally (CoglRectangleMapNode *node,
|
|
|
|
unsigned int left_width)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
|
|
|
/* Splits the node horizontally (according to emacs' definition, not
|
|
|
|
vim) by converting it to a branch and adding two new leaf
|
|
|
|
nodes. The leftmost branch will have the width left_width and
|
|
|
|
will be returned. If the node is already just the right size it
|
|
|
|
won't do anything */
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *left_node, *right_node;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
if (node->rectangle.width == left_width)
|
|
|
|
return node;
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
left_node = _cogl_rectangle_map_node_new ();
|
|
|
|
left_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF;
|
2009-12-04 13:06:32 +00:00
|
|
|
left_node->parent = node;
|
|
|
|
left_node->rectangle.x = node->rectangle.x;
|
|
|
|
left_node->rectangle.y = node->rectangle.y;
|
|
|
|
left_node->rectangle.width = left_width;
|
|
|
|
left_node->rectangle.height = node->rectangle.height;
|
2010-08-11 14:08:00 +00:00
|
|
|
left_node->largest_gap = (left_node->rectangle.width *
|
|
|
|
left_node->rectangle.height);
|
2009-12-04 13:06:32 +00:00
|
|
|
node->d.branch.left = left_node;
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
right_node = _cogl_rectangle_map_node_new ();
|
|
|
|
right_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF;
|
2009-12-04 13:06:32 +00:00
|
|
|
right_node->parent = node;
|
|
|
|
right_node->rectangle.x = node->rectangle.x + left_width;
|
|
|
|
right_node->rectangle.y = node->rectangle.y;
|
|
|
|
right_node->rectangle.width = node->rectangle.width - left_width;
|
|
|
|
right_node->rectangle.height = node->rectangle.height;
|
2010-08-11 14:08:00 +00:00
|
|
|
right_node->largest_gap = (right_node->rectangle.width *
|
|
|
|
right_node->rectangle.height);
|
2009-12-04 13:06:32 +00:00
|
|
|
node->d.branch.right = right_node;
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
node->type = COGL_RECTANGLE_MAP_BRANCH;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
return left_node;
|
|
|
|
}
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
static CoglRectangleMapNode *
|
|
|
|
_cogl_rectangle_map_node_split_vertically (CoglRectangleMapNode *node,
|
|
|
|
unsigned int top_height)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
|
|
|
/* Splits the node vertically (according to emacs' definition, not
|
|
|
|
vim) by converting it to a branch and adding two new leaf
|
|
|
|
nodes. The topmost branch will have the height top_height and
|
|
|
|
will be returned. If the node is already just the right size it
|
|
|
|
won't do anything */
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *top_node, *bottom_node;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
if (node->rectangle.height == top_height)
|
|
|
|
return node;
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
top_node = _cogl_rectangle_map_node_new ();
|
|
|
|
top_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF;
|
2009-12-04 13:06:32 +00:00
|
|
|
top_node->parent = node;
|
|
|
|
top_node->rectangle.x = node->rectangle.x;
|
|
|
|
top_node->rectangle.y = node->rectangle.y;
|
|
|
|
top_node->rectangle.width = node->rectangle.width;
|
|
|
|
top_node->rectangle.height = top_height;
|
2010-08-11 14:08:00 +00:00
|
|
|
top_node->largest_gap = (top_node->rectangle.width *
|
|
|
|
top_node->rectangle.height);
|
2009-12-04 13:06:32 +00:00
|
|
|
node->d.branch.left = top_node;
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
bottom_node = _cogl_rectangle_map_node_new ();
|
|
|
|
bottom_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF;
|
2009-12-04 13:06:32 +00:00
|
|
|
bottom_node->parent = node;
|
|
|
|
bottom_node->rectangle.x = node->rectangle.x;
|
|
|
|
bottom_node->rectangle.y = node->rectangle.y + top_height;
|
|
|
|
bottom_node->rectangle.width = node->rectangle.width;
|
|
|
|
bottom_node->rectangle.height = node->rectangle.height - top_height;
|
2010-08-11 14:08:00 +00:00
|
|
|
bottom_node->largest_gap = (bottom_node->rectangle.width *
|
|
|
|
bottom_node->rectangle.height);
|
2009-12-04 13:06:32 +00:00
|
|
|
node->d.branch.right = bottom_node;
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
node->type = COGL_RECTANGLE_MAP_BRANCH;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
return top_node;
|
|
|
|
}
|
|
|
|
|
2010-08-06 15:13:20 +00:00
|
|
|
#ifdef COGL_ENABLE_DEBUG
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
_cogl_rectangle_map_verify_recursive (CoglRectangleMapNode *node)
|
|
|
|
{
|
|
|
|
/* This is just used for debugging the data structure. It
|
2010-08-11 14:08:00 +00:00
|
|
|
recursively walks the tree to verify that the largest gap values
|
|
|
|
all add up */
|
2010-08-06 15:13:20 +00:00
|
|
|
|
|
|
|
switch (node->type)
|
|
|
|
{
|
|
|
|
case COGL_RECTANGLE_MAP_BRANCH:
|
|
|
|
{
|
|
|
|
int sum =
|
|
|
|
_cogl_rectangle_map_verify_recursive (node->d.branch.left) +
|
|
|
|
_cogl_rectangle_map_verify_recursive (node->d.branch.right);
|
2010-08-11 14:08:00 +00:00
|
|
|
g_assert (node->largest_gap ==
|
|
|
|
MAX (node->d.branch.left->largest_gap,
|
|
|
|
node->d.branch.right->largest_gap));
|
2010-08-06 15:13:20 +00:00
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
case COGL_RECTANGLE_MAP_EMPTY_LEAF:
|
2010-08-11 14:08:00 +00:00
|
|
|
g_assert (node->largest_gap ==
|
2010-08-06 15:13:20 +00:00
|
|
|
node->rectangle.width * node->rectangle.height);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case COGL_RECTANGLE_MAP_FILLED_LEAF:
|
2010-08-11 14:08:00 +00:00
|
|
|
g_assert (node->largest_gap == 0);
|
2010-08-06 15:13:20 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-11 14:08:00 +00:00
|
|
|
static unsigned int
|
|
|
|
_cogl_rectangle_map_get_space_remaining_recursive (CoglRectangleMapNode *node)
|
|
|
|
{
|
|
|
|
/* This is just used for debugging the data structure. It
|
|
|
|
recursively walks the tree to verify that the remaining space
|
|
|
|
value adds up */
|
|
|
|
|
|
|
|
switch (node->type)
|
|
|
|
{
|
|
|
|
case COGL_RECTANGLE_MAP_BRANCH:
|
|
|
|
{
|
|
|
|
CoglRectangleMapNode *l = node->d.branch.left;
|
|
|
|
CoglRectangleMapNode *r = node->d.branch.right;
|
|
|
|
|
|
|
|
return (_cogl_rectangle_map_get_space_remaining_recursive (l) +
|
|
|
|
_cogl_rectangle_map_get_space_remaining_recursive (r));
|
|
|
|
}
|
|
|
|
|
|
|
|
case COGL_RECTANGLE_MAP_EMPTY_LEAF:
|
|
|
|
return node->rectangle.width * node->rectangle.height;
|
|
|
|
|
|
|
|
case COGL_RECTANGLE_MAP_FILLED_LEAF:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-06 15:13:20 +00:00
|
|
|
static void
|
|
|
|
_cogl_rectangle_map_verify (CoglRectangleMap *map)
|
|
|
|
{
|
|
|
|
unsigned int actual_n_rectangles =
|
|
|
|
_cogl_rectangle_map_verify_recursive (map->root);
|
2010-08-11 14:08:00 +00:00
|
|
|
unsigned int actual_space_remaining =
|
|
|
|
_cogl_rectangle_map_get_space_remaining_recursive (map->root);
|
2010-08-06 15:13:20 +00:00
|
|
|
|
|
|
|
g_assert_cmpuint (actual_n_rectangles, ==, map->n_rectangles);
|
2010-08-11 14:08:00 +00:00
|
|
|
g_assert_cmpuint (actual_space_remaining, ==, map->space_remaining);
|
2010-08-06 15:13:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* COGL_ENABLE_DEBUG */
|
|
|
|
|
Switch use of primitive glib types to c99 equivalents
The coding style has for a long time said to avoid using redundant glib
data types such as gint or gchar etc because we feel that they make the
code look unnecessarily foreign to developers coming from outside of the
Gnome developer community.
Note: When we tried to find the historical rationale for the types we
just found that they were apparently only added for consistent syntax
highlighting which didn't seem that compelling.
Up until now we have been continuing to use some of the platform
specific type such as gint{8,16,32,64} and gsize but this patch switches
us over to using the standard c99 equivalents instead so we can further
ensure that our code looks familiar to the widest range of C developers
who might potentially contribute to Cogl.
So instead of using the gint{8,16,32,64} and guint{8,16,32,64} types this
switches all Cogl code to instead use the int{8,16,32,64}_t and
uint{8,16,32,64}_t c99 types instead.
Instead of gsize we now use size_t
For now we are not going to use the c99 _Bool type and instead we have
introduced a new CoglBool type to use instead of gboolean.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
(cherry picked from commit 5967dad2400d32ca6319cef6cb572e81bf2c15f0)
2012-04-16 20:56:40 +00:00
|
|
|
CoglBool
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_add (CoglRectangleMap *map,
|
|
|
|
unsigned int width,
|
|
|
|
unsigned int height,
|
|
|
|
void *data,
|
|
|
|
CoglRectangleMapEntry *rectangle)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-06 15:13:20 +00:00
|
|
|
unsigned int rectangle_size = width * height;
|
2009-12-04 13:06:32 +00:00
|
|
|
/* Stack of nodes to search in */
|
2010-08-06 16:40:52 +00:00
|
|
|
GArray *stack = map->stack;
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *found_node = NULL;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Zero-sized rectangles break the algorithm for removing rectangles
|
|
|
|
so we'll disallow them */
|
2011-10-13 21:34:30 +00:00
|
|
|
_COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, FALSE);
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Start with the root node */
|
2010-08-06 16:40:52 +00:00
|
|
|
g_array_set_size (stack, 0);
|
|
|
|
_cogl_rectangle_map_stack_push (stack, map->root, FALSE);
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Depth-first search for an empty node that is big enough */
|
2010-08-06 16:40:52 +00:00
|
|
|
while (stack->len > 0)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-06 16:40:52 +00:00
|
|
|
CoglRectangleMapStackEntry *stack_top;
|
|
|
|
CoglRectangleMapNode *node;
|
|
|
|
int next_index;
|
|
|
|
|
2009-12-04 13:06:32 +00:00
|
|
|
/* Pop an entry off the stack */
|
2010-08-06 16:40:52 +00:00
|
|
|
stack_top = _cogl_rectangle_map_stack_get_top (stack);
|
|
|
|
node = stack_top->node;
|
|
|
|
next_index = stack_top->next_index;
|
|
|
|
_cogl_rectangle_map_stack_pop (stack);
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Regardless of the type of the node, there's no point
|
|
|
|
descending any further if the new rectangle won't fit within
|
|
|
|
it */
|
|
|
|
if (node->rectangle.width >= width &&
|
2010-08-06 15:13:20 +00:00
|
|
|
node->rectangle.height >= height &&
|
2010-08-11 14:08:00 +00:00
|
|
|
node->largest_gap >= rectangle_size)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
if (node->type == COGL_RECTANGLE_MAP_EMPTY_LEAF)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
|
|
|
/* We've found a node we can use */
|
|
|
|
found_node = node;
|
|
|
|
break;
|
|
|
|
}
|
2010-08-02 14:24:03 +00:00
|
|
|
else if (node->type == COGL_RECTANGLE_MAP_BRANCH)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
|
|
|
if (next_index)
|
|
|
|
/* Try the right branch */
|
2010-08-06 16:40:52 +00:00
|
|
|
_cogl_rectangle_map_stack_push (stack,
|
|
|
|
node->d.branch.right,
|
|
|
|
0);
|
2009-12-04 13:06:32 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Make sure we remember to try the right branch once
|
|
|
|
we've finished descending the left branch */
|
2010-08-06 16:40:52 +00:00
|
|
|
_cogl_rectangle_map_stack_push (stack,
|
|
|
|
node,
|
|
|
|
1);
|
2009-12-04 13:06:32 +00:00
|
|
|
/* Try the left branch */
|
2010-08-06 16:40:52 +00:00
|
|
|
_cogl_rectangle_map_stack_push (stack,
|
|
|
|
node->d.branch.left,
|
|
|
|
0);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found_node)
|
|
|
|
{
|
2010-08-06 15:13:20 +00:00
|
|
|
CoglRectangleMapNode *node;
|
|
|
|
|
2009-12-04 13:06:32 +00:00
|
|
|
/* Split according to whichever axis will leave us with the
|
|
|
|
largest space */
|
|
|
|
if (found_node->rectangle.width - width >
|
|
|
|
found_node->rectangle.height - height)
|
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
found_node =
|
|
|
|
_cogl_rectangle_map_node_split_horizontally (found_node, width);
|
|
|
|
found_node =
|
|
|
|
_cogl_rectangle_map_node_split_vertically (found_node, height);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
found_node =
|
|
|
|
_cogl_rectangle_map_node_split_vertically (found_node, height);
|
|
|
|
found_node =
|
|
|
|
_cogl_rectangle_map_node_split_horizontally (found_node, width);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
found_node->type = COGL_RECTANGLE_MAP_FILLED_LEAF;
|
2009-12-04 13:06:32 +00:00
|
|
|
found_node->d.data = data;
|
2010-08-11 14:08:00 +00:00
|
|
|
found_node->largest_gap = 0;
|
2009-12-04 13:06:32 +00:00
|
|
|
if (rectangle)
|
|
|
|
*rectangle = found_node->rectangle;
|
|
|
|
|
2010-08-11 14:08:00 +00:00
|
|
|
/* Walk back up the tree and update the stored largest gap for
|
|
|
|
the node's sub tree */
|
2010-08-06 15:13:20 +00:00
|
|
|
for (node = found_node->parent; node; node = node->parent)
|
|
|
|
{
|
|
|
|
/* This node is a parent so it should always be a branch */
|
|
|
|
g_assert (node->type == COGL_RECTANGLE_MAP_BRANCH);
|
|
|
|
|
2010-08-11 14:08:00 +00:00
|
|
|
node->largest_gap = MAX (node->d.branch.left->largest_gap,
|
|
|
|
node->d.branch.right->largest_gap);
|
2010-08-06 15:13:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* There is now an extra rectangle in the map */
|
2010-08-02 14:24:03 +00:00
|
|
|
map->n_rectangles++;
|
2010-08-11 14:08:00 +00:00
|
|
|
/* and less space */
|
|
|
|
map->space_remaining -= rectangle_size;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2009-12-04 19:43:39 +00:00
|
|
|
#ifdef COGL_ENABLE_DEBUG
|
2011-01-24 14:28:00 +00:00
|
|
|
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DUMP_ATLAS_IMAGE)))
|
2010-08-06 15:13:20 +00:00
|
|
|
{
|
2011-05-16 16:50:49 +00:00
|
|
|
#ifdef HAVE_CAIRO
|
2010-08-06 15:13:20 +00:00
|
|
|
_cogl_rectangle_map_dump_image (map);
|
2011-05-16 16:50:49 +00:00
|
|
|
#endif
|
2010-08-06 15:13:20 +00:00
|
|
|
/* Dumping the rectangle map is really slow so we might as well
|
|
|
|
verify the space remaining here as it is also quite slow */
|
|
|
|
_cogl_rectangle_map_verify (map);
|
|
|
|
}
|
2009-12-04 19:43:39 +00:00
|
|
|
#endif
|
|
|
|
|
2009-12-04 13:06:32 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_remove (CoglRectangleMap *map,
|
|
|
|
const CoglRectangleMapEntry *rectangle)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *node = map->root;
|
2010-08-06 15:13:20 +00:00
|
|
|
unsigned int rectangle_size = rectangle->width * rectangle->height;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* We can do a binary-chop down the search tree to find the rectangle */
|
2010-08-02 14:24:03 +00:00
|
|
|
while (node->type == COGL_RECTANGLE_MAP_BRANCH)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapNode *left_node = node->d.branch.left;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* If and only if the rectangle is in the left node then the x,y
|
|
|
|
position of the rectangle will be within the node's
|
|
|
|
rectangle */
|
|
|
|
if (rectangle->x < left_node->rectangle.x + left_node->rectangle.width &&
|
|
|
|
rectangle->y < left_node->rectangle.y + left_node->rectangle.height)
|
|
|
|
/* Go left */
|
|
|
|
node = left_node;
|
|
|
|
else
|
|
|
|
/* Go right */
|
|
|
|
node = node->d.branch.right;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure we found the right node */
|
2010-08-02 14:24:03 +00:00
|
|
|
if (node->type != COGL_RECTANGLE_MAP_FILLED_LEAF ||
|
2009-12-04 13:06:32 +00:00
|
|
|
node->rectangle.x != rectangle->x ||
|
|
|
|
node->rectangle.y != rectangle->y ||
|
|
|
|
node->rectangle.width != rectangle->width ||
|
|
|
|
node->rectangle.height != rectangle->height)
|
|
|
|
/* This should only happen if someone tried to remove a rectangle
|
2010-08-02 14:24:03 +00:00
|
|
|
that was not in the map so something has gone wrong */
|
2009-12-04 13:06:32 +00:00
|
|
|
g_return_if_reached ();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Convert the node back to an empty node */
|
2010-08-02 14:24:03 +00:00
|
|
|
if (map->value_destroy_func)
|
|
|
|
map->value_destroy_func (node->d.data);
|
|
|
|
node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF;
|
2010-08-11 14:08:00 +00:00
|
|
|
node->largest_gap = rectangle_size;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Walk back up the tree combining branch nodes that have two
|
|
|
|
empty leaves back into a single empty leaf */
|
|
|
|
for (node = node->parent; node; node = node->parent)
|
|
|
|
{
|
|
|
|
/* This node is a parent so it should always be a branch */
|
2010-08-02 14:24:03 +00:00
|
|
|
g_assert (node->type == COGL_RECTANGLE_MAP_BRANCH);
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
if (node->d.branch.left->type == COGL_RECTANGLE_MAP_EMPTY_LEAF &&
|
|
|
|
node->d.branch.right->type == COGL_RECTANGLE_MAP_EMPTY_LEAF)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_node_free (node->d.branch.left);
|
|
|
|
_cogl_rectangle_map_node_free (node->d.branch.right);
|
|
|
|
node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF;
|
2010-08-11 14:08:00 +00:00
|
|
|
|
|
|
|
node->largest_gap = (node->rectangle.width *
|
|
|
|
node->rectangle.height);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-08-06 15:13:20 +00:00
|
|
|
/* Reduce the amount of space remaining in all of the parents
|
|
|
|
further up the chain */
|
|
|
|
for (; node; node = node->parent)
|
2010-08-11 14:08:00 +00:00
|
|
|
node->largest_gap = MAX (node->d.branch.left->largest_gap,
|
|
|
|
node->d.branch.right->largest_gap);
|
2010-08-06 15:13:20 +00:00
|
|
|
|
|
|
|
/* There is now one less rectangle */
|
2010-08-02 14:24:03 +00:00
|
|
|
g_assert (map->n_rectangles > 0);
|
|
|
|
map->n_rectangles--;
|
2010-08-11 14:08:00 +00:00
|
|
|
/* and more space */
|
|
|
|
map->space_remaining += rectangle_size;
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
2009-12-04 19:43:39 +00:00
|
|
|
|
|
|
|
#ifdef COGL_ENABLE_DEBUG
|
2011-01-24 14:28:00 +00:00
|
|
|
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DUMP_ATLAS_IMAGE)))
|
2010-08-06 15:13:20 +00:00
|
|
|
{
|
2011-05-16 16:50:49 +00:00
|
|
|
#ifdef HAVE_CAIRO
|
2010-08-06 15:13:20 +00:00
|
|
|
_cogl_rectangle_map_dump_image (map);
|
2011-05-16 16:50:49 +00:00
|
|
|
#endif
|
2010-08-06 15:13:20 +00:00
|
|
|
/* Dumping the rectangle map is really slow so we might as well
|
|
|
|
verify the space remaining here as it is also quite slow */
|
|
|
|
_cogl_rectangle_map_verify (map);
|
|
|
|
}
|
2009-12-04 19:43:39 +00:00
|
|
|
#endif
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
unsigned int
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_get_width (CoglRectangleMap *map)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
return map->root->rectangle.width;
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
unsigned int
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_get_height (CoglRectangleMap *map)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
return map->root->rectangle.height;
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
unsigned int
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_get_remaining_space (CoglRectangleMap *map)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-11 14:08:00 +00:00
|
|
|
return map->space_remaining;
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
unsigned int
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_get_n_rectangles (CoglRectangleMap *map)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
return map->n_rectangles;
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_internal_foreach (CoglRectangleMap *map,
|
|
|
|
CoglRectangleMapInternalForeachCb func,
|
|
|
|
void *data)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
|
|
|
/* Stack of nodes to search in */
|
2010-08-06 16:40:52 +00:00
|
|
|
GArray *stack = map->stack;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Start with the root node */
|
2010-08-06 16:40:52 +00:00
|
|
|
g_array_set_size (stack, 0);
|
|
|
|
_cogl_rectangle_map_stack_push (stack, map->root, 0);
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Iterate all nodes depth-first */
|
2010-08-06 16:40:52 +00:00
|
|
|
while (stack->len > 0)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-06 16:40:52 +00:00
|
|
|
CoglRectangleMapStackEntry *stack_top =
|
|
|
|
_cogl_rectangle_map_stack_get_top (stack);
|
|
|
|
CoglRectangleMapNode *node = stack_top->node;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
switch (node->type)
|
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
case COGL_RECTANGLE_MAP_BRANCH:
|
2010-08-06 16:40:52 +00:00
|
|
|
if (stack_top->next_index == 0)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
|
|
|
/* Next time we come back to this node, go to the right */
|
2010-08-06 16:40:52 +00:00
|
|
|
stack_top->next_index = 1;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Explore the left branch next */
|
2010-08-06 16:40:52 +00:00
|
|
|
_cogl_rectangle_map_stack_push (stack,
|
|
|
|
node->d.branch.left,
|
|
|
|
0);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
2010-08-06 16:40:52 +00:00
|
|
|
else if (stack_top->next_index == 1)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
|
|
|
/* Next time we come back to this node, stop processing it */
|
2010-08-06 16:40:52 +00:00
|
|
|
stack_top->next_index = 2;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
/* Explore the right branch next */
|
2010-08-06 16:40:52 +00:00
|
|
|
_cogl_rectangle_map_stack_push (stack,
|
|
|
|
node->d.branch.right,
|
|
|
|
0);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We're finished with this node so we can call the callback */
|
2010-08-02 14:24:03 +00:00
|
|
|
func (node, data);
|
2010-08-06 16:40:52 +00:00
|
|
|
_cogl_rectangle_map_stack_pop (stack);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Some sort of leaf node, just call the callback */
|
2010-08-02 14:24:03 +00:00
|
|
|
func (node, data);
|
2010-08-06 16:40:52 +00:00
|
|
|
_cogl_rectangle_map_stack_pop (stack);
|
2009-12-04 13:06:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The stack should now be empty */
|
2010-08-06 16:40:52 +00:00
|
|
|
g_assert (stack->len == 0);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
typedef struct _CoglRectangleMapForeachClosure
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapCallback callback;
|
|
|
|
void *data;
|
|
|
|
} CoglRectangleMapForeachClosure;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
static void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_foreach_cb (CoglRectangleMapNode *node, void *data)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapForeachClosure *closure = data;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF)
|
2009-12-04 13:06:32 +00:00
|
|
|
closure->callback (&node->rectangle, node->d.data, closure->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_foreach (CoglRectangleMap *map,
|
|
|
|
CoglRectangleMapCallback callback,
|
|
|
|
void *data)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMapForeachClosure closure;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
|
|
|
closure.callback = callback;
|
|
|
|
closure.data = data;
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_internal_foreach (map,
|
|
|
|
_cogl_rectangle_map_foreach_cb,
|
|
|
|
&closure);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_free_cb (CoglRectangleMapNode *node, void *data)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
CoglRectangleMap *map = data;
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF && map->value_destroy_func)
|
|
|
|
map->value_destroy_func (node->d.data);
|
2009-12-04 13:06:32 +00:00
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_node_free (node);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_free (CoglRectangleMap *map)
|
2009-12-04 13:06:32 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_internal_foreach (map,
|
|
|
|
_cogl_rectangle_map_free_cb,
|
|
|
|
map);
|
2010-08-06 16:40:52 +00:00
|
|
|
|
|
|
|
g_array_free (map->stack, TRUE);
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
g_free (map);
|
2009-12-04 13:06:32 +00:00
|
|
|
}
|
2009-12-04 19:43:39 +00:00
|
|
|
|
2011-05-16 16:50:49 +00:00
|
|
|
#if defined (COGL_ENABLE_DEBUG) && defined (HAVE_CAIRO)
|
2009-12-04 19:43:39 +00:00
|
|
|
|
|
|
|
static void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_dump_image_cb (CoglRectangleMapNode *node, void *data)
|
2009-12-04 19:43:39 +00:00
|
|
|
{
|
|
|
|
cairo_t *cr = data;
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF ||
|
|
|
|
node->type == COGL_RECTANGLE_MAP_EMPTY_LEAF)
|
2009-12-04 19:43:39 +00:00
|
|
|
{
|
|
|
|
/* Fill the rectangle using a different colour depending on
|
|
|
|
whether the rectangle is used */
|
2010-08-02 14:24:03 +00:00
|
|
|
if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF)
|
2009-12-04 19:43:39 +00:00
|
|
|
cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
|
|
|
|
else
|
|
|
|
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
|
|
|
|
|
|
|
|
cairo_rectangle (cr,
|
|
|
|
node->rectangle.x,
|
|
|
|
node->rectangle.y,
|
|
|
|
node->rectangle.width,
|
|
|
|
node->rectangle.height);
|
|
|
|
|
|
|
|
cairo_fill_preserve (cr);
|
|
|
|
|
|
|
|
/* Draw a white outline around the rectangle */
|
|
|
|
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
|
|
|
cairo_stroke (cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_dump_image (CoglRectangleMap *map)
|
2009-12-04 19:43:39 +00:00
|
|
|
{
|
2010-08-02 14:24:03 +00:00
|
|
|
/* This dumps a png to help visualize the map. Each leaf rectangle
|
2009-12-04 19:43:39 +00:00
|
|
|
is drawn with a white outline. Unused leaves are filled in black
|
|
|
|
and used leaves are blue */
|
|
|
|
|
|
|
|
cairo_surface_t *surface =
|
|
|
|
cairo_image_surface_create (CAIRO_FORMAT_RGB24,
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_get_width (map),
|
|
|
|
_cogl_rectangle_map_get_height (map));
|
2009-12-04 19:43:39 +00:00
|
|
|
cairo_t *cr = cairo_create (surface);
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
_cogl_rectangle_map_internal_foreach (map,
|
|
|
|
_cogl_rectangle_map_dump_image_cb,
|
|
|
|
cr);
|
2009-12-04 19:43:39 +00:00
|
|
|
|
|
|
|
cairo_destroy (cr);
|
|
|
|
|
2010-08-02 14:24:03 +00:00
|
|
|
cairo_surface_write_to_png (surface, "cogl-rectangle-map-dump.png");
|
2009-12-04 19:43:39 +00:00
|
|
|
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
}
|
|
|
|
|
2011-05-16 16:50:49 +00:00
|
|
|
#endif /* COGL_ENABLE_DEBUG && HAVE_CAIRO */
|