cogl-atlas: Rename to CoglRectangleMap
This simply renames CoglAtlas to CoglRectangleMap without making any functional changes. The old 'CoglAtlas' is just a data structure for managing unused areas of a rectangle and it doesn't neccessarily have to be used for an atlas so it wasn't a very good name.
This commit is contained in:
parent
1e45428483
commit
4989000f55
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __COGL_ATLAS_H
|
||||
#define __COGL_ATLAS_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
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 */
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#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 <cairo.h>
|
||||
|
||||
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);
|
||||
}
|
78
clutter/cogl/cogl/cogl-rectangle-map.h
Normal file
78
clutter/cogl/cogl/cogl-rectangle-map.h
Normal file
@ -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 <glib.h>
|
||||
|
||||
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 */
|
Loading…
Reference in New Issue
Block a user