diff --git a/clutter/cogl/cogl/Makefile.am b/clutter/cogl/cogl/Makefile.am index 9ea001cc0..d0ed8498a 100644 --- a/clutter/cogl/cogl/Makefile.am +++ b/clutter/cogl/cogl/Makefile.am @@ -144,8 +144,8 @@ cogl_sources_c = \ $(srcdir)/cogl-texture-3d.c \ $(srcdir)/cogl-texture-rectangle-private.h \ $(srcdir)/cogl-texture-rectangle.c \ - $(srcdir)/cogl-atlas.h \ - $(srcdir)/cogl-atlas.c \ + $(srcdir)/cogl-rectangle-map.h \ + $(srcdir)/cogl-rectangle-map.c \ $(srcdir)/cogl-atlas-texture-private.h \ $(srcdir)/cogl-atlas-texture.c \ $(srcdir)/cogl-spans.h \ diff --git a/clutter/cogl/cogl/cogl-atlas-texture-private.h b/clutter/cogl/cogl/cogl-atlas-texture-private.h index f4fdb7201..c2c9fbd88 100644 --- a/clutter/cogl/cogl/cogl-atlas-texture-private.h +++ b/clutter/cogl/cogl/cogl-atlas-texture-private.h @@ -26,7 +26,7 @@ #include "cogl-handle.h" #include "cogl-texture-private.h" -#include "cogl-atlas.h" +#include "cogl-rectangle-map.h" #define COGL_ATLAS_TEXTURE(tex) ((CoglAtlasTexture *) tex) @@ -34,23 +34,23 @@ typedef struct _CoglAtlasTexture CoglAtlasTexture; struct _CoglAtlasTexture { - CoglTexture _parent; + CoglTexture _parent; /* The format that the texture is in. This isn't necessarily the same format as the atlas texture because we can store pre-multiplied and non-pre-multiplied textures together */ - CoglPixelFormat format; + CoglPixelFormat format; /* The rectangle that was used to add this texture to the atlas. This includes the 1-pixel border */ - CoglAtlasRectangle rectangle; + CoglRectangleMapEntry rectangle; /* The texture might need to be migrated out in which case this will be set to TRUE and sub_texture will actually be a real texture */ - gboolean in_atlas; + gboolean in_atlas; /* A CoglSubTexture representing the region for easy rendering */ - CoglHandle sub_texture; + CoglHandle sub_texture; }; GQuark diff --git a/clutter/cogl/cogl/cogl-atlas-texture.c b/clutter/cogl/cogl/cogl-atlas-texture.c index 5d60476f4..4afba0fc5 100644 --- a/clutter/cogl/cogl/cogl-atlas-texture.c +++ b/clutter/cogl/cogl/cogl-atlas-texture.c @@ -39,7 +39,7 @@ #include "cogl-context.h" #include "cogl-handle.h" #include "cogl-texture-driver.h" -#include "cogl-atlas.h" +#include "cogl-rectangle-map.h" #include "cogl-journal-private.h" #include "cogl-material-opengl-private.h" @@ -254,18 +254,18 @@ _cogl_atlas_texture_remove_from_atlas (CoglAtlasTexture *atlas_tex) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_atlas_remove_rectangle (ctx->atlas, &atlas_tex->rectangle); + _cogl_rectangle_map_remove (ctx->rectangle_map, &atlas_tex->rectangle); COGL_NOTE (ATLAS, "Removed rectangle sized %ix%i", atlas_tex->rectangle.width, atlas_tex->rectangle.height); COGL_NOTE (ATLAS, "Atlas is %ix%i, has %i textures and is %i%% waste", - _cogl_atlas_get_width (ctx->atlas), - _cogl_atlas_get_height (ctx->atlas), - _cogl_atlas_get_n_rectangles (ctx->atlas), - _cogl_atlas_get_remaining_space (ctx->atlas) * 100 / - (_cogl_atlas_get_width (ctx->atlas) * - _cogl_atlas_get_height (ctx->atlas))); + _cogl_rectangle_map_get_width (ctx->rectangle_map), + _cogl_rectangle_map_get_height (ctx->rectangle_map), + _cogl_rectangle_map_get_n_rectangles (ctx->rectangle_map), + _cogl_rectangle_map_get_remaining_space (ctx->rectangle_map) * + 100 / (_cogl_rectangle_map_get_width (ctx->rectangle_map) * + _cogl_rectangle_map_get_height (ctx->rectangle_map))); atlas_tex->in_atlas = FALSE; } @@ -599,7 +599,7 @@ _cogl_atlas_texture_get_height (CoglTexture *tex) static CoglHandle _cogl_atlas_texture_create_sub_texture (CoglHandle full_texture, - const CoglAtlasRectangle *rectangle) + const CoglRectangleMapEntry *rectangle) { /* Create a subtexture for the given rectangle not including the 1-pixel border */ @@ -615,7 +615,7 @@ typedef struct _CoglAtlasTextureRepositionData /* The current texture which already has a position */ CoglAtlasTexture *texture; /* The new position of the texture */ - CoglAtlasRectangle new_position; + CoglRectangleMapEntry new_position; } CoglAtlasTextureRepositionData; static void @@ -679,32 +679,32 @@ typedef struct _CoglAtlasTextureGetRectanglesData } CoglAtlasTextureGetRectanglesData; static void -_cogl_atlas_texture_get_rectangles_cb (const CoglAtlasRectangle *rectangle, - gpointer rectangle_data, - gpointer user_data) +_cogl_atlas_texture_get_rectangles_cb (const CoglRectangleMapEntry *rectangle, + gpointer rect_data, + gpointer user_data) { CoglAtlasTextureGetRectanglesData *data = user_data; - data->textures[data->n_textures++].texture = rectangle_data; + data->textures[data->n_textures++].texture = rect_data; } static void -_cogl_atlas_texture_get_next_size (unsigned int *atlas_width, - unsigned int *atlas_height) +_cogl_atlas_texture_get_next_size (unsigned int *map_width, + unsigned int *map_height) { /* Double the size of the texture by increasing whichever dimension is smaller */ - if (*atlas_width < *atlas_height) - *atlas_width <<= 1; + if (*map_width < *map_height) + *map_width <<= 1; else - *atlas_height <<= 1; + *map_height <<= 1; } -static CoglAtlas * -_cogl_atlas_texture_create_atlas (unsigned int atlas_width, - unsigned int atlas_height, - unsigned int n_textures, - CoglAtlasTextureRepositionData *textures) +static CoglRectangleMap * +_cogl_atlas_texture_create_map (unsigned int map_width, + unsigned int map_height, + unsigned int n_textures, + CoglAtlasTextureRepositionData *textures) { GLint max_texture_size = 1024; @@ -717,18 +717,20 @@ _cogl_atlas_texture_create_atlas (unsigned int atlas_width, /* Keep trying increasingly larger atlases until we can fit all of the textures */ - while (atlas_width < max_texture_size && atlas_height < max_texture_size) + while (map_width < max_texture_size && map_height < max_texture_size) { - CoglAtlas *new_atlas = _cogl_atlas_new (atlas_width, atlas_height, NULL); + CoglRectangleMap *new_atlas = _cogl_rectangle_map_new (map_width, + map_height, + NULL); unsigned int i; /* Add all of the textures and keep track of the new position */ for (i = 0; i < n_textures; i++) - if (!_cogl_atlas_add_rectangle (new_atlas, - textures[i].texture->rectangle.width, - textures[i].texture->rectangle.height, - textures[i].texture, - &textures[i].new_position)) + if (!_cogl_rectangle_map_add (new_atlas, + textures[i].texture->rectangle.width, + textures[i].texture->rectangle.height, + textures[i].texture, + &textures[i].new_position)) break; /* If the atlas can contain all of the textures then we have a @@ -736,8 +738,8 @@ _cogl_atlas_texture_create_atlas (unsigned int atlas_width, if (i >= n_textures) return new_atlas; - _cogl_atlas_free (new_atlas); - _cogl_atlas_texture_get_next_size (&atlas_width, &atlas_height); + _cogl_rectangle_map_free (new_atlas); + _cogl_atlas_texture_get_next_size (&map_width, &map_height); } /* If we get here then there's no atlas that can accommodate all of @@ -766,25 +768,26 @@ _cogl_atlas_texture_reserve_space (CoglAtlasTexture *new_sub_tex, unsigned int height) { CoglAtlasTextureGetRectanglesData data; - CoglAtlas *new_atlas; + CoglRectangleMap *new_map; CoglHandle new_tex; - unsigned int atlas_width, atlas_height; + unsigned int map_width, map_height; gboolean ret; _COGL_GET_CONTEXT (ctx, FALSE); /* Check if we can fit the rectangle into the existing atlas */ - if (ctx->atlas && _cogl_atlas_add_rectangle (ctx->atlas, width, height, - new_sub_tex, - &new_sub_tex->rectangle)) + if (ctx->rectangle_map && + _cogl_rectangle_map_add (ctx->rectangle_map, width, height, + new_sub_tex, + &new_sub_tex->rectangle)) { COGL_NOTE (ATLAS, "Atlas is %ix%i, has %i textures and is %i%% waste", - _cogl_atlas_get_width (ctx->atlas), - _cogl_atlas_get_height (ctx->atlas), - _cogl_atlas_get_n_rectangles (ctx->atlas), - _cogl_atlas_get_remaining_space (ctx->atlas) * 100 / - (_cogl_atlas_get_width (ctx->atlas) * - _cogl_atlas_get_height (ctx->atlas))); + _cogl_rectangle_map_get_width (ctx->rectangle_map), + _cogl_rectangle_map_get_height (ctx->rectangle_map), + _cogl_rectangle_map_get_n_rectangles (ctx->rectangle_map), + _cogl_rectangle_map_get_remaining_space (ctx->rectangle_map) * + 100 / (_cogl_rectangle_map_get_width (ctx->rectangle_map) * + _cogl_rectangle_map_get_height (ctx->rectangle_map))); return TRUE; } @@ -792,15 +795,17 @@ _cogl_atlas_texture_reserve_space (CoglAtlasTexture *new_sub_tex, /* We need to reorganise the atlas so we'll get an array of all the textures currently in the atlas. */ data.n_textures = 0; - if (ctx->atlas == NULL) + if (ctx->rectangle_map == NULL) data.textures = g_malloc (sizeof (CoglAtlasTextureRepositionData)); else { - data.textures = - g_malloc (sizeof (CoglAtlasTextureRepositionData) * - (_cogl_atlas_get_n_rectangles (ctx->atlas) + 1)); - _cogl_atlas_foreach (ctx->atlas, _cogl_atlas_texture_get_rectangles_cb, - &data); + unsigned int n_rectangles = + _cogl_rectangle_map_get_n_rectangles (ctx->rectangle_map); + data.textures = g_malloc (sizeof (CoglAtlasTextureRepositionData) * + (n_rectangles + 1)); + _cogl_rectangle_map_foreach (ctx->rectangle_map, + _cogl_atlas_texture_get_rectangles_cb, + &data); } /* Add the new rectangle as a dummy texture so that it can be @@ -815,59 +820,61 @@ _cogl_atlas_texture_reserve_space (CoglAtlasTexture *new_sub_tex, _cogl_atlas_texture_compare_size_cb); /* Try to create a new atlas that can contain all of the textures */ - if (ctx->atlas) + if (ctx->rectangle_map) { - atlas_width = _cogl_atlas_get_width (ctx->atlas); - atlas_height = _cogl_atlas_get_height (ctx->atlas); + map_width = _cogl_rectangle_map_get_width (ctx->rectangle_map); + map_height = _cogl_rectangle_map_get_height (ctx->rectangle_map); /* If there is enough space in the existing for the new rectangle in the existing atlas we'll start with the same size, otherwise we'll immediately double it */ - if (_cogl_atlas_get_remaining_space (ctx->atlas) < width * height) - _cogl_atlas_texture_get_next_size (&atlas_width, &atlas_height); + if (_cogl_rectangle_map_get_remaining_space (ctx->rectangle_map) < + width * height) + _cogl_atlas_texture_get_next_size (&map_width, &map_height); } else { /* Start with an initial size of 256x256 */ - atlas_width = 256; - atlas_height = 256; + map_width = 256; + map_height = 256; } - new_atlas = _cogl_atlas_texture_create_atlas (atlas_width, atlas_height, - data.n_textures, data.textures); + new_map = _cogl_atlas_texture_create_map (map_width, map_height, + data.n_textures, data.textures); + map_width = _cogl_rectangle_map_get_width (new_map); + map_height = _cogl_rectangle_map_get_height (new_map); - /* If we can't create an atlas with the texture then give up */ - if (new_atlas == NULL) + /* If we can't create a map with the texture then give up */ + if (new_map == NULL) { COGL_NOTE (ATLAS, "Could not fit texture in the atlas"); ret = FALSE; } /* We need to migrate the existing textures into a new texture */ else if ((new_tex = - _cogl_texture_2d_new_with_size (_cogl_atlas_get_width (new_atlas), - _cogl_atlas_get_height (new_atlas), + _cogl_texture_2d_new_with_size (map_width, map_height, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGBA_8888)) == COGL_INVALID_HANDLE) { COGL_NOTE (ATLAS, "Could not create a CoglTexture2D"); - _cogl_atlas_free (new_atlas); + _cogl_rectangle_map_free (new_map); ret = FALSE; } else { COGL_NOTE (ATLAS, "Atlas %s with size %ix%i", - ctx->atlas == NULL || - _cogl_atlas_get_width (ctx->atlas) != - _cogl_atlas_get_width (new_atlas) || - _cogl_atlas_get_height (ctx->atlas) != - _cogl_atlas_get_height (new_atlas) ? + ctx->rectangle_map == NULL || + _cogl_rectangle_map_get_width (ctx->rectangle_map) != + _cogl_rectangle_map_get_width (new_map) || + _cogl_rectangle_map_get_height (ctx->rectangle_map) != + _cogl_rectangle_map_get_height (new_map) ? "resized" : "reorganized", - _cogl_atlas_get_width (new_atlas), - _cogl_atlas_get_height (new_atlas)); + _cogl_rectangle_map_get_width (new_map), + _cogl_rectangle_map_get_height (new_map)); - if (ctx->atlas) + if (ctx->rectangle_map) { /* Move all the textures to the right position in the new texture. This will also update the texture's rectangle */ @@ -876,7 +883,7 @@ _cogl_atlas_texture_reserve_space (CoglAtlasTexture *new_sub_tex, ctx->atlas_texture, new_tex, new_sub_tex); - _cogl_atlas_free (ctx->atlas); + _cogl_rectangle_map_free (ctx->rectangle_map); cogl_handle_unref (ctx->atlas_texture); } else @@ -884,16 +891,16 @@ _cogl_atlas_texture_reserve_space (CoglAtlasTexture *new_sub_tex, update the rectangle from its new position */ data.textures[0].texture->rectangle = data.textures[0].new_position; - ctx->atlas = new_atlas; + ctx->rectangle_map = new_map; ctx->atlas_texture = new_tex; COGL_NOTE (ATLAS, "Atlas is %ix%i, has %i textures and is %i%% waste", - _cogl_atlas_get_width (ctx->atlas), - _cogl_atlas_get_height (ctx->atlas), - _cogl_atlas_get_n_rectangles (ctx->atlas), - _cogl_atlas_get_remaining_space (ctx->atlas) * 100 / - (_cogl_atlas_get_width (ctx->atlas) * - _cogl_atlas_get_height (ctx->atlas))); + _cogl_rectangle_map_get_width (ctx->rectangle_map), + _cogl_rectangle_map_get_height (ctx->rectangle_map), + _cogl_rectangle_map_get_n_rectangles (ctx->rectangle_map), + _cogl_rectangle_map_get_remaining_space (ctx->rectangle_map) * + 100 / (_cogl_rectangle_map_get_width (ctx->rectangle_map) * + _cogl_rectangle_map_get_height (ctx->rectangle_map))); ret = TRUE; } @@ -1003,7 +1010,7 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, if (dst_bmp == NULL) { - _cogl_atlas_remove_rectangle (ctx->atlas, &atlas_tex->rectangle); + _cogl_rectangle_map_remove (ctx->rectangle_map, &atlas_tex->rectangle); g_free (atlas_tex); return COGL_INVALID_HANDLE; } diff --git a/clutter/cogl/cogl/cogl-atlas.h b/clutter/cogl/cogl/cogl-atlas.h deleted file mode 100644 index 15d269938..000000000 --- a/clutter/cogl/cogl/cogl-atlas.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2009 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 . - * - * - */ - -#ifndef __COGL_ATLAS_H -#define __COGL_ATLAS_H - -#include - -typedef struct _CoglAtlas CoglAtlas; -typedef struct _CoglAtlasRectangle CoglAtlasRectangle; - -typedef void (* CoglAtlasCallback) (const CoglAtlasRectangle *rectangle, - gpointer rectangle_data, - gpointer user_data); - -struct _CoglAtlasRectangle -{ - unsigned int x, y; - unsigned int width, height; -}; - -CoglAtlas * -_cogl_atlas_new (unsigned int width, - unsigned int height, - GDestroyNotify value_destroy_func); - -gboolean -_cogl_atlas_add_rectangle (CoglAtlas *atlas, - unsigned int width, - unsigned int height, - gpointer data, - CoglAtlasRectangle *rectangle); - -void -_cogl_atlas_remove_rectangle (CoglAtlas *atlas, - const CoglAtlasRectangle *rectangle); - -unsigned int -_cogl_atlas_get_width (CoglAtlas *atlas); - -unsigned int -_cogl_atlas_get_height (CoglAtlas *atlas); - -unsigned int -_cogl_atlas_get_remaining_space (CoglAtlas *atlas); - -unsigned int -_cogl_atlas_get_n_rectangles (CoglAtlas *atlas); - -void -_cogl_atlas_foreach (CoglAtlas *atlas, - CoglAtlasCallback callback, - gpointer data); - -void -_cogl_atlas_free (CoglAtlas *atlas); - -#endif /* __COGL_ATLAS_H */ diff --git a/clutter/cogl/cogl/cogl-context.c b/clutter/cogl/cogl/cogl-context.c index 80ef46130..2668043c2 100644 --- a/clutter/cogl/cogl/cogl-context.c +++ b/clutter/cogl/cogl/cogl-context.c @@ -214,7 +214,7 @@ cogl_create_context (void) _cogl_enable (enable_flags); _cogl_flush_face_winding (); - _context->atlas = NULL; + _context->rectangle_map = NULL; _context->atlas_texture = COGL_INVALID_HANDLE; /* As far as I can tell, GL_POINT_SPRITE doesn't have any effect @@ -273,8 +273,9 @@ _cogl_destroy_context (void) if (_context->default_layer_0) cogl_handle_unref (_context->default_layer_0); - if (_context->atlas) - _cogl_atlas_free (_context->atlas); + if (_context->rectangle_map) + _cogl_rectangle_map_free (_context->rectangle_map); + if (_context->atlas_texture) cogl_handle_unref (_context->atlas_texture); diff --git a/clutter/cogl/cogl/cogl-context.h b/clutter/cogl/cogl/cogl-context.h index 1d1d0745d..b89ee057f 100644 --- a/clutter/cogl/cogl/cogl-context.h +++ b/clutter/cogl/cogl/cogl-context.h @@ -31,7 +31,7 @@ #include "cogl-clip-stack.h" #include "cogl-matrix-stack.h" #include "cogl-material-private.h" -#include "cogl-atlas.h" +#include "cogl-rectangle-map.h" #include "cogl-buffer-private.h" #include "cogl-bitmask.h" @@ -143,7 +143,7 @@ typedef struct CoglMaterial *texture_download_material; - CoglAtlas *atlas; + CoglRectangleMap *rectangle_map; CoglHandle atlas_texture; /* This debugging variable is used to pick a colour for visually diff --git a/clutter/cogl/cogl/cogl-atlas.c b/clutter/cogl/cogl/cogl-rectangle-map.c similarity index 51% rename from clutter/cogl/cogl/cogl-atlas.c rename to clutter/cogl/cogl/cogl-rectangle-map.c index d381589b4..77f1d066c 100644 --- a/clutter/cogl/cogl/cogl-atlas.c +++ b/clutter/cogl/cogl/cogl-rectangle-map.c @@ -30,7 +30,7 @@ #include -#include "cogl-atlas.h" +#include "cogl-rectangle-map.h" #include "cogl-debug.h" /* Implements a data structure which keeps track of unused @@ -46,26 +46,26 @@ the atlas */ #include -static void _cogl_atlas_dump_image (CoglAtlas *atlas); +static void _cogl_rectangle_map_dump_image (CoglRectangleMap *map); #endif /* COGL_ENABLE_DEBUG */ -typedef struct _CoglAtlasNode CoglAtlasNode; -typedef struct _CoglAtlasStackEntry CoglAtlasStackEntry; +typedef struct _CoglRectangleMapNode CoglRectangleMapNode; +typedef struct _CoglRectangleMapStackEntry CoglRectangleMapStackEntry; -typedef void (* CoglAtlasInternalForeachCb) (CoglAtlasNode *node, - gpointer data); +typedef void (* CoglRectangleMapInternalForeachCb) (CoglRectangleMapNode *node, + void *data); typedef enum { - COGL_ATLAS_BRANCH, - COGL_ATLAS_FILLED_LEAF, - COGL_ATLAS_EMPTY_LEAF -} CoglAtlasNodeType; + COGL_RECTANGLE_MAP_BRANCH, + COGL_RECTANGLE_MAP_FILLED_LEAF, + COGL_RECTANGLE_MAP_EMPTY_LEAF +} CoglRectangleMapNodeType; -struct _CoglAtlas +struct _CoglRectangleMap { - CoglAtlasNode *root; + CoglRectangleMapNode *root; unsigned int space_remaining; unsigned int n_rectangles; @@ -73,80 +73,81 @@ struct _CoglAtlas GDestroyNotify value_destroy_func; }; -struct _CoglAtlasNode +struct _CoglRectangleMapNode { - CoglAtlasNodeType type; + CoglRectangleMapNodeType type; - CoglAtlasRectangle rectangle; + CoglRectangleMapEntry rectangle; - CoglAtlasNode *parent; + CoglRectangleMapNode *parent; union { /* Fields used when this is a branch */ struct { - CoglAtlasNode *left; - CoglAtlasNode *right; + CoglRectangleMapNode *left; + CoglRectangleMapNode *right; } branch; /* Field used when this is a filled leaf */ - gpointer data; + void *data; } d; }; -struct _CoglAtlasStackEntry +struct _CoglRectangleMapStackEntry { /* The node to search */ - CoglAtlasNode *node; + CoglRectangleMapNode *node; /* Index of next branch of this node to explore. Basically either 0 to go left or 1 to go right */ gboolean next_index; /* Next entry in the stack */ - CoglAtlasStackEntry *next; + CoglRectangleMapStackEntry *next; }; -static CoglAtlasNode * -_cogl_atlas_node_new (void) +static CoglRectangleMapNode * +_cogl_rectangle_map_node_new (void) { - return g_slice_new (CoglAtlasNode); + return g_slice_new (CoglRectangleMapNode); } static void -_cogl_atlas_node_free (CoglAtlasNode *node) +_cogl_rectangle_map_node_free (CoglRectangleMapNode *node) { - g_slice_free (CoglAtlasNode, node); + g_slice_free (CoglRectangleMapNode, node); } -CoglAtlas * -_cogl_atlas_new (unsigned int width, - unsigned int height, - GDestroyNotify value_destroy_func) +CoglRectangleMap * +_cogl_rectangle_map_new (unsigned int width, + unsigned int height, + GDestroyNotify value_destroy_func) { - CoglAtlas *atlas = g_new (CoglAtlas, 1); - CoglAtlasNode *root = _cogl_atlas_node_new (); + CoglRectangleMap *map = g_new (CoglRectangleMap, 1); + CoglRectangleMapNode *root = _cogl_rectangle_map_node_new (); - root->type = COGL_ATLAS_EMPTY_LEAF; + root->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; root->parent = NULL; root->rectangle.x = 0; root->rectangle.y = 0; root->rectangle.width = width; root->rectangle.height = height; - atlas->root = root; - atlas->space_remaining = width * height; - atlas->n_rectangles = 0; - atlas->value_destroy_func = value_destroy_func; + map->root = root; + map->space_remaining = width * height; + map->n_rectangles = 0; + map->value_destroy_func = value_destroy_func; - return atlas; + return map; } -static CoglAtlasStackEntry * -_cogl_atlas_stack_push (CoglAtlasStackEntry *stack, - CoglAtlasNode *node, - gboolean next_index) +static CoglRectangleMapStackEntry * +_cogl_rectangle_map_stack_push (CoglRectangleMapStackEntry *stack, + CoglRectangleMapNode *node, + gboolean next_index) { - CoglAtlasStackEntry *new_entry = g_slice_new (CoglAtlasStackEntry); + CoglRectangleMapStackEntry *new_entry = + g_slice_new (CoglRectangleMapStackEntry); new_entry->node = node; new_entry->next_index = next_index; @@ -155,19 +156,19 @@ _cogl_atlas_stack_push (CoglAtlasStackEntry *stack, return new_entry; } -static CoglAtlasStackEntry * -_cogl_atlas_stack_pop (CoglAtlasStackEntry *stack) +static CoglRectangleMapStackEntry * +_cogl_rectangle_map_stack_pop (CoglRectangleMapStackEntry *stack) { - CoglAtlasStackEntry *next = stack->next; + CoglRectangleMapStackEntry *next = stack->next; - g_slice_free (CoglAtlasStackEntry, stack); + g_slice_free (CoglRectangleMapStackEntry, stack); return next; } -static CoglAtlasNode * -_cogl_atlas_node_split_horizontally (CoglAtlasNode *node, - unsigned int left_width) +static CoglRectangleMapNode * +_cogl_rectangle_map_node_split_horizontally (CoglRectangleMapNode *node, + unsigned int left_width) { /* Splits the node horizontally (according to emacs' definition, not vim) by converting it to a branch and adding two new leaf @@ -175,13 +176,13 @@ _cogl_atlas_node_split_horizontally (CoglAtlasNode *node, will be returned. If the node is already just the right size it won't do anything */ - CoglAtlasNode *left_node, *right_node; + CoglRectangleMapNode *left_node, *right_node; if (node->rectangle.width == left_width) return node; - left_node = _cogl_atlas_node_new (); - left_node->type = COGL_ATLAS_EMPTY_LEAF; + left_node = _cogl_rectangle_map_node_new (); + left_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; left_node->parent = node; left_node->rectangle.x = node->rectangle.x; left_node->rectangle.y = node->rectangle.y; @@ -189,8 +190,8 @@ _cogl_atlas_node_split_horizontally (CoglAtlasNode *node, left_node->rectangle.height = node->rectangle.height; node->d.branch.left = left_node; - right_node = _cogl_atlas_node_new (); - right_node->type = COGL_ATLAS_EMPTY_LEAF; + right_node = _cogl_rectangle_map_node_new (); + right_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; right_node->parent = node; right_node->rectangle.x = node->rectangle.x + left_width; right_node->rectangle.y = node->rectangle.y; @@ -198,14 +199,14 @@ _cogl_atlas_node_split_horizontally (CoglAtlasNode *node, right_node->rectangle.height = node->rectangle.height; node->d.branch.right = right_node; - node->type = COGL_ATLAS_BRANCH; + node->type = COGL_RECTANGLE_MAP_BRANCH; return left_node; } -static CoglAtlasNode * -_cogl_atlas_node_split_vertically (CoglAtlasNode *node, - unsigned int top_height) +static CoglRectangleMapNode * +_cogl_rectangle_map_node_split_vertically (CoglRectangleMapNode *node, + unsigned int top_height) { /* Splits the node vertically (according to emacs' definition, not vim) by converting it to a branch and adding two new leaf @@ -213,13 +214,13 @@ _cogl_atlas_node_split_vertically (CoglAtlasNode *node, will be returned. If the node is already just the right size it won't do anything */ - CoglAtlasNode *top_node, *bottom_node; + CoglRectangleMapNode *top_node, *bottom_node; if (node->rectangle.height == top_height) return node; - top_node = _cogl_atlas_node_new (); - top_node->type = COGL_ATLAS_EMPTY_LEAF; + top_node = _cogl_rectangle_map_node_new (); + top_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; top_node->parent = node; top_node->rectangle.x = node->rectangle.x; top_node->rectangle.y = node->rectangle.y; @@ -227,8 +228,8 @@ _cogl_atlas_node_split_vertically (CoglAtlasNode *node, top_node->rectangle.height = top_height; node->d.branch.left = top_node; - bottom_node = _cogl_atlas_node_new (); - bottom_node->type = COGL_ATLAS_EMPTY_LEAF; + bottom_node = _cogl_rectangle_map_node_new (); + bottom_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; bottom_node->parent = node; bottom_node->rectangle.x = node->rectangle.x; bottom_node->rectangle.y = node->rectangle.y + top_height; @@ -236,36 +237,36 @@ _cogl_atlas_node_split_vertically (CoglAtlasNode *node, bottom_node->rectangle.height = node->rectangle.height - top_height; node->d.branch.right = bottom_node; - node->type = COGL_ATLAS_BRANCH; + node->type = COGL_RECTANGLE_MAP_BRANCH; return top_node; } gboolean -_cogl_atlas_add_rectangle (CoglAtlas *atlas, - unsigned int width, - unsigned int height, - gpointer data, - CoglAtlasRectangle *rectangle) +_cogl_rectangle_map_add (CoglRectangleMap *map, + unsigned int width, + unsigned int height, + void *data, + CoglRectangleMapEntry *rectangle) { /* Stack of nodes to search in */ - CoglAtlasStackEntry *node_stack; - CoglAtlasNode *found_node = NULL; + CoglRectangleMapStackEntry *node_stack; + CoglRectangleMapNode *found_node = NULL; /* Zero-sized rectangles break the algorithm for removing rectangles so we'll disallow them */ g_return_val_if_fail (width > 0 && height > 0, FALSE); /* Start with the root node */ - node_stack = _cogl_atlas_stack_push (NULL, atlas->root, FALSE); + node_stack = _cogl_rectangle_map_stack_push (NULL, map->root, FALSE); /* Depth-first search for an empty node that is big enough */ while (node_stack) { /* Pop an entry off the stack */ - CoglAtlasNode *node = node_stack->node; + CoglRectangleMapNode *node = node_stack->node; int next_index = node_stack->next_index; - node_stack = _cogl_atlas_stack_pop (node_stack); + node_stack = _cogl_rectangle_map_stack_pop (node_stack); /* Regardless of the type of the node, there's no point descending any further if the new rectangle won't fit within @@ -273,30 +274,33 @@ _cogl_atlas_add_rectangle (CoglAtlas *atlas, if (node->rectangle.width >= width && node->rectangle.height >= height) { - if (node->type == COGL_ATLAS_EMPTY_LEAF) + if (node->type == COGL_RECTANGLE_MAP_EMPTY_LEAF) { /* We've found a node we can use */ found_node = node; break; } - else if (node->type == COGL_ATLAS_BRANCH) + else if (node->type == COGL_RECTANGLE_MAP_BRANCH) { if (next_index) /* Try the right branch */ - node_stack = _cogl_atlas_stack_push (node_stack, - node->d.branch.right, - 0); + node_stack = + _cogl_rectangle_map_stack_push (node_stack, + node->d.branch.right, + 0); else { /* Make sure we remember to try the right branch once we've finished descending the left branch */ - node_stack = _cogl_atlas_stack_push (node_stack, - node, - 1); + node_stack = + _cogl_rectangle_map_stack_push (node_stack, + node, + 1); /* Try the left branch */ - node_stack = _cogl_atlas_stack_push (node_stack, - node->d.branch.left, - 0); + node_stack = + _cogl_rectangle_map_stack_push (node_stack, + node->d.branch.left, + 0); } } } @@ -304,7 +308,7 @@ _cogl_atlas_add_rectangle (CoglAtlas *atlas, /* Free the stack */ while (node_stack) - node_stack = _cogl_atlas_stack_pop (node_stack); + node_stack = _cogl_rectangle_map_stack_pop (node_stack); if (found_node) { @@ -313,29 +317,33 @@ _cogl_atlas_add_rectangle (CoglAtlas *atlas, if (found_node->rectangle.width - width > found_node->rectangle.height - height) { - found_node = _cogl_atlas_node_split_horizontally (found_node, width); - found_node = _cogl_atlas_node_split_vertically (found_node, height); + found_node = + _cogl_rectangle_map_node_split_horizontally (found_node, width); + found_node = + _cogl_rectangle_map_node_split_vertically (found_node, height); } else { - found_node = _cogl_atlas_node_split_vertically (found_node, height); - found_node = _cogl_atlas_node_split_horizontally (found_node, width); + found_node = + _cogl_rectangle_map_node_split_vertically (found_node, height); + found_node = + _cogl_rectangle_map_node_split_horizontally (found_node, width); } - found_node->type = COGL_ATLAS_FILLED_LEAF; + found_node->type = COGL_RECTANGLE_MAP_FILLED_LEAF; found_node->d.data = data; if (rectangle) *rectangle = found_node->rectangle; /* Record how much empty space is remaining after this rectangle is added */ - g_assert (width * height <= atlas->space_remaining); - atlas->space_remaining -= width * height; - atlas->n_rectangles++; + g_assert (width * height <= map->space_remaining); + map->space_remaining -= width * height; + map->n_rectangles++; #ifdef COGL_ENABLE_DEBUG if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DUMP_ATLAS_IMAGE)) - _cogl_atlas_dump_image (atlas); + _cogl_rectangle_map_dump_image (map); #endif return TRUE; @@ -345,15 +353,15 @@ _cogl_atlas_add_rectangle (CoglAtlas *atlas, } void -_cogl_atlas_remove_rectangle (CoglAtlas *atlas, - const CoglAtlasRectangle *rectangle) +_cogl_rectangle_map_remove (CoglRectangleMap *map, + const CoglRectangleMapEntry *rectangle) { - CoglAtlasNode *node = atlas->root; + CoglRectangleMapNode *node = map->root; /* We can do a binary-chop down the search tree to find the rectangle */ - while (node->type == COGL_ATLAS_BRANCH) + while (node->type == COGL_RECTANGLE_MAP_BRANCH) { - CoglAtlasNode *left_node = node->d.branch.left; + CoglRectangleMapNode *left_node = node->d.branch.left; /* 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 @@ -368,103 +376,103 @@ _cogl_atlas_remove_rectangle (CoglAtlas *atlas, } /* Make sure we found the right node */ - if (node->type != COGL_ATLAS_FILLED_LEAF || + if (node->type != COGL_RECTANGLE_MAP_FILLED_LEAF || 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 - that was not in the atlas so something has gone wrong */ + that was not in the map so something has gone wrong */ g_return_if_reached (); else { /* Convert the node back to an empty node */ - if (atlas->value_destroy_func) - atlas->value_destroy_func (node->d.data); - node->type = COGL_ATLAS_EMPTY_LEAF; + if (map->value_destroy_func) + map->value_destroy_func (node->d.data); + node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; /* 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 */ - g_assert (node->type == COGL_ATLAS_BRANCH); + g_assert (node->type == COGL_RECTANGLE_MAP_BRANCH); - if (node->d.branch.left->type == COGL_ATLAS_EMPTY_LEAF && - node->d.branch.right->type == COGL_ATLAS_EMPTY_LEAF) + if (node->d.branch.left->type == COGL_RECTANGLE_MAP_EMPTY_LEAF && + node->d.branch.right->type == COGL_RECTANGLE_MAP_EMPTY_LEAF) { - _cogl_atlas_node_free (node->d.branch.left); - _cogl_atlas_node_free (node->d.branch.right); - node->type = COGL_ATLAS_EMPTY_LEAF; + _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; } else break; } /* There is now more free space and one less rectangle */ - atlas->space_remaining += rectangle->width * rectangle->height; - g_assert (atlas->n_rectangles > 0); - atlas->n_rectangles--; + map->space_remaining += rectangle->width * rectangle->height; + g_assert (map->n_rectangles > 0); + map->n_rectangles--; } #ifdef COGL_ENABLE_DEBUG if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DUMP_ATLAS_IMAGE)) - _cogl_atlas_dump_image (atlas); + _cogl_rectangle_map_dump_image (map); #endif } unsigned int -_cogl_atlas_get_width (CoglAtlas *atlas) +_cogl_rectangle_map_get_width (CoglRectangleMap *map) { - return atlas->root->rectangle.width; + return map->root->rectangle.width; } unsigned int -_cogl_atlas_get_height (CoglAtlas *atlas) +_cogl_rectangle_map_get_height (CoglRectangleMap *map) { - return atlas->root->rectangle.height; + return map->root->rectangle.height; } unsigned int -_cogl_atlas_get_remaining_space (CoglAtlas *atlas) +_cogl_rectangle_map_get_remaining_space (CoglRectangleMap *map) { - return atlas->space_remaining; + return map->space_remaining; } unsigned int -_cogl_atlas_get_n_rectangles (CoglAtlas *atlas) +_cogl_rectangle_map_get_n_rectangles (CoglRectangleMap *map) { - return atlas->n_rectangles; + return map->n_rectangles; } static void -_cogl_atlas_internal_foreach (CoglAtlas *atlas, - CoglAtlasInternalForeachCb callback, - gpointer data) +_cogl_rectangle_map_internal_foreach (CoglRectangleMap *map, + CoglRectangleMapInternalForeachCb func, + void *data) { /* Stack of nodes to search in */ - CoglAtlasStackEntry *node_stack; + CoglRectangleMapStackEntry *node_stack; /* Start with the root node */ - node_stack = _cogl_atlas_stack_push (NULL, atlas->root, 0); + node_stack = _cogl_rectangle_map_stack_push (NULL, map->root, 0); /* Iterate all nodes depth-first */ while (node_stack) { - CoglAtlasNode *node = node_stack->node; + CoglRectangleMapNode *node = node_stack->node; switch (node->type) { - case COGL_ATLAS_BRANCH: + case COGL_RECTANGLE_MAP_BRANCH: if (node_stack->next_index == 0) { /* Next time we come back to this node, go to the right */ node_stack->next_index = 1; /* Explore the left branch next */ - node_stack = _cogl_atlas_stack_push (node_stack, - node->d.branch.left, - 0); + node_stack = _cogl_rectangle_map_stack_push (node_stack, + node->d.branch.left, + 0); } else if (node_stack->next_index == 1) { @@ -472,22 +480,22 @@ _cogl_atlas_internal_foreach (CoglAtlas *atlas, node_stack->next_index = 2; /* Explore the right branch next */ - node_stack = _cogl_atlas_stack_push (node_stack, - node->d.branch.right, - 0); + node_stack = _cogl_rectangle_map_stack_push (node_stack, + node->d.branch.right, + 0); } else { /* We're finished with this node so we can call the callback */ - callback (node, data); - node_stack = _cogl_atlas_stack_pop (node_stack); + func (node, data); + node_stack = _cogl_rectangle_map_stack_pop (node_stack); } break; default: /* Some sort of leaf node, just call the callback */ - callback (node, data); - node_stack = _cogl_atlas_stack_pop (node_stack); + func (node, data); + node_stack = _cogl_rectangle_map_stack_pop (node_stack); break; } } @@ -496,65 +504,69 @@ _cogl_atlas_internal_foreach (CoglAtlas *atlas, g_assert (node_stack == NULL); } -typedef struct _CoglAtlasForeachClosure +typedef struct _CoglRectangleMapForeachClosure { - CoglAtlasCallback callback; - gpointer data; -} CoglAtlasForeachClosure; + CoglRectangleMapCallback callback; + void *data; +} CoglRectangleMapForeachClosure; static void -_cogl_atlas_foreach_cb (CoglAtlasNode *node, gpointer data) +_cogl_rectangle_map_foreach_cb (CoglRectangleMapNode *node, void *data) { - CoglAtlasForeachClosure *closure = data; + CoglRectangleMapForeachClosure *closure = data; - if (node->type == COGL_ATLAS_FILLED_LEAF) + if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF) closure->callback (&node->rectangle, node->d.data, closure->data); } void -_cogl_atlas_foreach (CoglAtlas *atlas, - CoglAtlasCallback callback, - gpointer data) +_cogl_rectangle_map_foreach (CoglRectangleMap *map, + CoglRectangleMapCallback callback, + void *data) { - CoglAtlasForeachClosure closure; + CoglRectangleMapForeachClosure closure; closure.callback = callback; closure.data = data; - _cogl_atlas_internal_foreach (atlas, _cogl_atlas_foreach_cb, &closure); + _cogl_rectangle_map_internal_foreach (map, + _cogl_rectangle_map_foreach_cb, + &closure); } static void -_cogl_atlas_free_cb (CoglAtlasNode *node, gpointer data) +_cogl_rectangle_map_free_cb (CoglRectangleMapNode *node, void *data) { - CoglAtlas *atlas = data; + CoglRectangleMap *map = data; - if (node->type == COGL_ATLAS_FILLED_LEAF && atlas->value_destroy_func) - atlas->value_destroy_func (node->d.data); + if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF && map->value_destroy_func) + map->value_destroy_func (node->d.data); - _cogl_atlas_node_free (node); + _cogl_rectangle_map_node_free (node); } void -_cogl_atlas_free (CoglAtlas *atlas) +_cogl_rectangle_map_free (CoglRectangleMap *map) { - _cogl_atlas_internal_foreach (atlas, _cogl_atlas_free_cb, atlas); - g_free (atlas); + _cogl_rectangle_map_internal_foreach (map, + _cogl_rectangle_map_free_cb, + map); + g_free (map); } #ifdef COGL_ENABLE_DEBUG static void -_cogl_atlas_dump_image_cb (CoglAtlasNode *node, gpointer data) +_cogl_rectangle_map_dump_image_cb (CoglRectangleMapNode *node, void *data) { cairo_t *cr = data; - if (node->type == COGL_ATLAS_FILLED_LEAF || - node->type == COGL_ATLAS_EMPTY_LEAF) + if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF || + node->type == COGL_RECTANGLE_MAP_EMPTY_LEAF) { /* Fill the rectangle using a different colour depending on whether the rectangle is used */ - if (node->type == COGL_ATLAS_FILLED_LEAF) + if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF) cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); else cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); @@ -574,23 +586,25 @@ _cogl_atlas_dump_image_cb (CoglAtlasNode *node, gpointer data) } static void -_cogl_atlas_dump_image (CoglAtlas *atlas) +_cogl_rectangle_map_dump_image (CoglRectangleMap *map) { - /* This dumps a png to help visualize the atlas. Each leaf rectangle + /* This dumps a png to help visualize the map. Each leaf rectangle 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, - _cogl_atlas_get_width (atlas), - _cogl_atlas_get_height (atlas)); + _cogl_rectangle_map_get_width (map), + _cogl_rectangle_map_get_height (map)); cairo_t *cr = cairo_create (surface); - _cogl_atlas_internal_foreach (atlas, _cogl_atlas_dump_image_cb, cr); + _cogl_rectangle_map_internal_foreach (map, + _cogl_rectangle_map_dump_image_cb, + cr); cairo_destroy (cr); - cairo_surface_write_to_png (surface, "cogl-atlas-dump.png"); + cairo_surface_write_to_png (surface, "cogl-rectangle-map-dump.png"); cairo_surface_destroy (surface); } diff --git a/clutter/cogl/cogl/cogl-rectangle-map.h b/clutter/cogl/cogl/cogl-rectangle-map.h new file mode 100644 index 000000000..51b92608c --- /dev/null +++ b/clutter/cogl/cogl/cogl-rectangle-map.h @@ -0,0 +1,78 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2009 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __COGL_RECTANGLE_MAP_H +#define __COGL_RECTANGLE_MAP_H + +#include + +typedef struct _CoglRectangleMap CoglRectangleMap; +typedef struct _CoglRectangleMapEntry CoglRectangleMapEntry; + +typedef void (* CoglRectangleMapCallback) (const CoglRectangleMapEntry *entry, + void *rectangle_data, + void *user_data); + +struct _CoglRectangleMapEntry +{ + unsigned int x, y; + unsigned int width, height; +}; + +CoglRectangleMap * +_cogl_rectangle_map_new (unsigned int width, + unsigned int height, + GDestroyNotify value_destroy_func); + +gboolean +_cogl_rectangle_map_add (CoglRectangleMap *map, + unsigned int width, + unsigned int height, + void *data, + CoglRectangleMapEntry *rectangle); + +void +_cogl_rectangle_map_remove (CoglRectangleMap *map, + const CoglRectangleMapEntry *rectangle); + +unsigned int +_cogl_rectangle_map_get_width (CoglRectangleMap *map); + +unsigned int +_cogl_rectangle_map_get_height (CoglRectangleMap *map); + +unsigned int +_cogl_rectangle_map_get_remaining_space (CoglRectangleMap *map); + +unsigned int +_cogl_rectangle_map_get_n_rectangles (CoglRectangleMap *map); + +void +_cogl_rectangle_map_foreach (CoglRectangleMap *map, + CoglRectangleMapCallback callback, + void *data); + +void +_cogl_rectangle_map_free (CoglRectangleMap *map); + +#endif /* __COGL_RECTANGLE_MAP_H */