From 9752493272b39e6a8aeb1b8d667667d53de439fb Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 27 Nov 2009 16:39:16 +0000 Subject: [PATCH] cogl: Add a sub texture backend This adds a new texture backend which represents a sub texture of a larger texture. The texture is created with a reference to the full texture and a set of coordinates describing the region. The backend simply defers to the full texture for all operations and maps the coordinates to the other range. You can also use coordinates outside the range [0,1] to create a repeated version of the full texture. A new public API function called cogl_texture_new_from_sub_texture is available to create the sub texture. --- clutter/cogl/cogl/Makefile.am | 2 + clutter/cogl/cogl/cogl-sub-texture-private.h | 56 ++ clutter/cogl/cogl/cogl-sub-texture.c | 699 +++++++++++++++++++ clutter/cogl/cogl/cogl-texture.c | 15 +- clutter/cogl/cogl/cogl-texture.h | 27 + doc/reference/cogl/cogl-sections.txt | 1 + 6 files changed, 798 insertions(+), 2 deletions(-) create mode 100644 clutter/cogl/cogl/cogl-sub-texture-private.h create mode 100644 clutter/cogl/cogl/cogl-sub-texture.c diff --git a/clutter/cogl/cogl/Makefile.am b/clutter/cogl/cogl/Makefile.am index c3b19c424..02ab16601 100644 --- a/clutter/cogl/cogl/Makefile.am +++ b/clutter/cogl/cogl/Makefile.am @@ -122,9 +122,11 @@ libclutter_cogl_la_SOURCES = \ $(srcdir)/cogl-blend-string.c \ $(srcdir)/cogl-blend-string.h \ $(srcdir)/cogl-debug.c \ + $(srcdir)/cogl-sub-texture-private.h \ $(srcdir)/cogl-texture-private.h \ $(srcdir)/cogl-texture-2d-sliced-private.h \ $(srcdir)/cogl-texture-driver.h \ + $(srcdir)/cogl-sub-texture.c \ $(srcdir)/cogl-texture.c \ $(srcdir)/cogl-texture-2d-sliced.c \ $(srcdir)/cogl-spans.h \ diff --git a/clutter/cogl/cogl/cogl-sub-texture-private.h b/clutter/cogl/cogl/cogl-sub-texture-private.h new file mode 100644 index 000000000..899f61e8c --- /dev/null +++ b/clutter/cogl/cogl/cogl-sub-texture-private.h @@ -0,0 +1,56 @@ +/* + * 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_SUB_TEXTURE_H +#define __COGL_SUB_TEXTURE_H + +#include "cogl-handle.h" +#include "cogl-texture-private.h" + +#define COGL_SUB_TEXTURE(tex) ((CoglSubTexture *) tex) + +typedef struct _CoglSubTexture CoglSubTexture; + +struct _CoglSubTexture +{ + CoglTexture _parent; + + CoglHandle full_texture; + + /* The texture coordinates of the subregion of full_texture */ + gfloat tx1, ty1; + gfloat tx2, ty2; + + /* Are all of the texture coordinates a multiple of one? */ + gboolean tex_coords_are_a_multiple; +}; + +GQuark +_cogl_handle_sub_texture_get_type (void); + +CoglHandle +_cogl_sub_texture_new (CoglHandle full_texture, + gfloat tx1, gfloat ty1, + gfloat tx2, gfloat ty2); + +#endif /* __COGL_SUB_TEXTURE_H */ diff --git a/clutter/cogl/cogl/cogl-sub-texture.c b/clutter/cogl/cogl/cogl-sub-texture.c new file mode 100644 index 000000000..a8e164160 --- /dev/null +++ b/clutter/cogl/cogl/cogl-sub-texture.c @@ -0,0 +1,699 @@ +/* + * 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. + * + * Authors: + * Neil Roberts + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl.h" +#include "cogl-internal.h" +#include "cogl-util.h" +#include "cogl-texture-private.h" +#include "cogl-sub-texture-private.h" +#include "cogl-context.h" +#include "cogl-handle.h" +#include "cogl-texture-driver.h" + +#include +#include + +static void _cogl_sub_texture_free (CoglSubTexture *sub_tex); + +COGL_HANDLE_DEFINE (SubTexture, sub_texture); + +static const CoglTextureVtable cogl_sub_texture_vtable; + +/* Maps from the texture coordinates of this texture to the texture + coordinates of the full texture */ + +static void +_cogl_sub_texture_map_coordinate_pair (CoglSubTexture *sub_tex, + gfloat *tx, gfloat *ty) +{ + *tx = *tx * (sub_tex->tx2 - sub_tex->tx1) + sub_tex->tx1; + *ty = *ty * (sub_tex->ty2 - sub_tex->ty1) + sub_tex->ty1; +} + +static void +_cogl_sub_texture_map_coordinate_set (CoglSubTexture *sub_tex, + gfloat *tx1, gfloat *ty1, + gfloat *tx2, gfloat *ty2) +{ + _cogl_sub_texture_map_coordinate_pair (sub_tex, tx1, ty1); + _cogl_sub_texture_map_coordinate_pair (sub_tex, tx2, ty2); +} + +/* Maps from the texture coordinates of the full texture to the + texture coordinates of the sub texture */ +static void +_cogl_sub_texture_unmap_coordinate_pair (CoglSubTexture *sub_tex, + gfloat *coords) +{ + if (sub_tex->tx1 == sub_tex->tx2) + coords[0] = sub_tex->tx1; + else + coords[0] = (coords[0] - sub_tex->tx1) / (sub_tex->tx2 - sub_tex->tx1); + + if (sub_tex->ty1 == sub_tex->ty2) + coords[0] = sub_tex->ty1; + else + coords[1] = (coords[1] - sub_tex->ty1) / (sub_tex->ty2 - sub_tex->ty1); +} + +static void +_cogl_sub_texture_unmap_coordinate_set (CoglSubTexture *sub_tex, + gfloat *coords) +{ + _cogl_sub_texture_unmap_coordinate_pair (sub_tex, coords); + _cogl_sub_texture_unmap_coordinate_pair (sub_tex, coords + 2); +} + +static gboolean +_cogl_sub_texture_same_int_part (float t1, float t2) +{ + float int_part1, int_part2; + float frac_part1, frac_part2; + + frac_part1 = modff (t1, &int_part1); + frac_part2 = modff (t2, &int_part2); + + return (int_part1 == int_part2 || + ((frac_part1 == 0.0f || frac_part2 == 0.0f) && + ABS (int_part1 - int_part2) == 1.0f)); +} + +typedef struct _CoglSubTextureForeachData +{ + CoglSubTexture *sub_tex; + CoglTextureSliceCallback callback; + void *user_data; +} CoglSubTextureForeachData; + +static void +_cogl_sub_texture_foreach_cb (CoglHandle handle, + GLuint gl_handle, + GLenum gl_target, + const float *slice_coords, + const float *full_virtual_coords, + void *user_data) +{ + CoglSubTextureForeachData *data = user_data; + float virtual_coords[4]; + + memcpy (virtual_coords, full_virtual_coords, sizeof (virtual_coords)); + /* Convert the virtual coords from the full-texture space to the sub + texture space */ + _cogl_sub_texture_unmap_coordinate_set (data->sub_tex, virtual_coords); + + data->callback (handle, gl_handle, gl_target, + slice_coords, virtual_coords, + data->user_data); +} + +static void +_cogl_sub_texture_manual_repeat_cb (const float *coords, + void *user_data) +{ + CoglSubTextureForeachData *data = user_data; + float mapped_coords[4]; + + memcpy (mapped_coords, coords, sizeof (mapped_coords)); + + _cogl_sub_texture_map_coordinate_set (data->sub_tex, + &mapped_coords[0], + &mapped_coords[1], + &mapped_coords[2], + &mapped_coords[3]); + + _cogl_texture_foreach_sub_texture_in_region (data->sub_tex->full_texture, + mapped_coords[0], + mapped_coords[1], + mapped_coords[2], + mapped_coords[3], + _cogl_sub_texture_foreach_cb, + user_data); +} + +static void +_cogl_sub_texture_foreach_sub_texture_in_region ( + CoglTexture *tex, + float virtual_tx_1, + float virtual_ty_1, + float virtual_tx_2, + float virtual_ty_2, + CoglTextureSliceCallback callback, + void *user_data) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + CoglSubTextureForeachData data; + + data.sub_tex = sub_tex; + data.callback = callback; + data.user_data = user_data; + + /* If there is no repeating or the sub texture coordinates are a + multiple of the whole texture then we can just directly map the + texture coordinates */ + if (sub_tex->tex_coords_are_a_multiple || + (_cogl_sub_texture_same_int_part (virtual_tx_1, virtual_tx_2) && + _cogl_sub_texture_same_int_part (virtual_ty_1, virtual_ty_2))) + { + _cogl_sub_texture_map_coordinate_set (sub_tex, + &virtual_tx_1, + &virtual_ty_1, + &virtual_tx_2, + &virtual_ty_2); + + _cogl_texture_foreach_sub_texture_in_region + (sub_tex->full_texture, + virtual_tx_1, virtual_ty_1, + virtual_tx_2, virtual_ty_2, + _cogl_sub_texture_foreach_cb, &data); + } + else + _cogl_texture_iterate_manual_repeats (_cogl_sub_texture_manual_repeat_cb, + virtual_tx_1, virtual_ty_1, + virtual_tx_2, virtual_ty_2, + &data); +} + +static void +_cogl_sub_texture_set_wrap_mode_parameter (CoglTexture *tex, + GLenum wrap_mode) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + _cogl_texture_set_wrap_mode_parameter (sub_tex->full_texture, wrap_mode); +} + +static void +_cogl_sub_texture_free (CoglSubTexture *sub_tex) +{ + cogl_handle_unref (sub_tex->full_texture); + + g_free (sub_tex); +} + +CoglHandle +_cogl_sub_texture_new (CoglHandle full_texture, + gfloat tx1, gfloat ty1, + gfloat tx2, gfloat ty2) +{ + CoglSubTexture *sub_tex; + CoglTexture *tex; + gfloat integer_part; + + sub_tex = g_new (CoglSubTexture, 1); + + tex = COGL_TEXTURE (sub_tex); + tex->vtable = &cogl_sub_texture_vtable; + + sub_tex->full_texture = cogl_handle_ref (full_texture); + + sub_tex->tx1 = tx1; + sub_tex->ty1 = ty1; + sub_tex->tx2 = tx2; + sub_tex->ty2 = ty2; + + /* Track whether the texture coords are a multiple of one because in + that case we can use hardware repeating */ + sub_tex->tex_coords_are_a_multiple + = (modff (tx1, &integer_part) == 0.0f && + modff (ty1, &integer_part) == 0.0f && + modff (tx2, &integer_part) == 0.0f && + modff (ty2, &integer_part) == 0.0f); + + return _cogl_sub_texture_handle_new (sub_tex); +} + +static gint +_cogl_sub_texture_get_max_waste (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + return cogl_texture_get_max_waste (sub_tex->full_texture); +} + +static gboolean +_cogl_sub_texture_is_sliced (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + return cogl_texture_is_sliced (sub_tex->full_texture); +} + +static gboolean +_cogl_sub_texture_can_hardware_repeat (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + /* We can hardware repeat if the full texture can hardware repeat + and the coordinates for the subregion are all a multiple of the + full size of the texture (ie, they have no fractional part) */ + + return (sub_tex->tex_coords_are_a_multiple && + _cogl_texture_can_hardware_repeat (sub_tex->full_texture)); +} + +static void +_cogl_sub_texture_transform_coords_to_gl (CoglTexture *tex, + float *s, + float *t) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + _cogl_sub_texture_map_coordinate_pair (sub_tex, s, t); + _cogl_texture_transform_coords_to_gl (sub_tex->full_texture, s, t); +} + +static gboolean +_cogl_sub_texture_get_gl_texture (CoglTexture *tex, + GLuint *out_gl_handle, + GLenum *out_gl_target) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + return cogl_texture_get_gl_texture (sub_tex->full_texture, + out_gl_handle, + out_gl_target); +} + +static void +_cogl_sub_texture_set_filters (CoglTexture *tex, + GLenum min_filter, + GLenum mag_filter) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + _cogl_texture_set_filters (sub_tex->full_texture, min_filter, mag_filter); +} + +static void +_cogl_sub_texture_ensure_mipmaps (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + _cogl_texture_ensure_mipmaps (sub_tex->full_texture); +} + +static void +_cogl_sub_texture_get_next_chunk (int pos, int end, + int tex_size, + int *chunk_start, int *chunk_end) +{ + /* pos and end may be negative or greater than the size of the + texture. We want to calculate the next largest range we can copy + in one chunk */ + + if (pos < 0) + /* The behaviour of % for negative numbers is implementation + dependant in C89 so we have to do this */ + *chunk_start = (tex_size - pos) % tex_size; + else + *chunk_start = pos % tex_size; + + /* If the region is larger than the remaining size of the texture + then we need to crop it */ + if (end - pos > tex_size - *chunk_start) + end = pos + tex_size - *chunk_start; + + if (end < 0) + *chunk_end = (tex_size - end) % tex_size; + else + *chunk_end = end % tex_size; + + if (*chunk_end == 0) + *chunk_end = tex_size; +} + +static void +_cogl_sub_texture_get_x_pixel_pos (CoglSubTexture *sub_tex, + gint *px1, gint *px2) +{ + gint full_width = cogl_texture_get_width (sub_tex->full_texture); + + *px1 = full_width * sub_tex->tx1; + *px2 = full_width * sub_tex->tx2; + + if (*px1 > *px2) + { + gint temp = *px1; + *px1 = *px2; + *px2 = temp; + } +} + +static void +_cogl_sub_texture_get_y_pixel_pos (CoglSubTexture *sub_tex, + gint *py1, gint *py2) +{ + gint full_width = cogl_texture_get_width (sub_tex->full_texture); + + *py1 = full_width * sub_tex->ty1; + *py2 = full_width * sub_tex->ty2; + + if (*py1 > *py2) + { + gint temp = *py1; + *py1 = *py2; + *py2 = temp; + } +} + +static gboolean +_cogl_sub_texture_set_region (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int dst_width, + unsigned int dst_height, + int width, + int height, + CoglPixelFormat format, + unsigned int rowstride, + const guint8 *data) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + gint full_tex_width, full_tex_height; + gint bpp; + gint px1, py1, px2, py2; + gint it_x, it_y; + gint src_x1, src_y1, src_x2, src_y2; + CoglBitmap source_bmp; + CoglBitmap temp_bmp; + gboolean source_bmp_owner = FALSE; + CoglPixelFormat closest_format; + GLenum closest_gl_format; + GLenum closest_gl_type; + gboolean success; + CoglPixelFormat tex_format; + + /* Check for valid format */ + if (format == COGL_PIXEL_FORMAT_ANY) + return FALSE; + + /* Shortcut out early if the image is empty */ + if (width == 0 || height == 0) + return TRUE; + + /* FIXME: If the sub texture coordinates are swapped around then we + should flip the bitmap */ + + _cogl_sub_texture_get_x_pixel_pos (sub_tex, &px1, &px2); + _cogl_sub_texture_get_y_pixel_pos (sub_tex, &py1, &py2); + + full_tex_width = cogl_texture_get_width (sub_tex->full_texture); + full_tex_height = cogl_texture_get_height (sub_tex->full_texture); + + /* Init source bitmap */ + source_bmp.width = width; + source_bmp.height = height; + source_bmp.format = format; + source_bmp.data = (guchar*) data; + + /* Rowstride from texture width if none specified */ + bpp = _cogl_get_format_bpp (format); + source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; + + /* Find closest format to internal that's supported by GL */ + tex_format = cogl_texture_get_format (sub_tex->full_texture); + closest_format = _cogl_pixel_format_to_gl (tex_format, + NULL, /* don't need */ + &closest_gl_format, + &closest_gl_type); + + /* If no direct match, convert */ + if (closest_format != format) + { + /* Convert to required format */ + success = _cogl_bitmap_convert_and_premult (&source_bmp, + &temp_bmp, + closest_format); + + /* Swap bitmaps if succeeded */ + if (!success) return FALSE; + source_bmp = temp_bmp; + source_bmp_owner = TRUE; + } + + for (it_y = py1; it_y < py2; it_y += src_y2 - src_y1) + { + _cogl_sub_texture_get_next_chunk (it_y, py2, full_tex_width, + &src_y1, &src_y2); + + for (it_x = px1; it_x < px2; it_x += src_x2 - src_x1) + { + gint virt_x_1, virt_y_1, virt_width, virt_height; + gint copy_dst_x, copy_dst_y, copy_dst_width, copy_dst_height; + + _cogl_sub_texture_get_next_chunk (it_x, px2, full_tex_height, + &src_x1, &src_x2); + + /* Offset of the chunk from the left edge in the virtual sub + texture coordinates */ + virt_x_1 = it_x - px1; + /* Pixel width covered by this chunk */ + virt_width = src_x2 - src_x1; + /* Offset of the chunk from the top edge in the virtual sub + texture coordinates */ + virt_y_1 = it_y - py1; + /* Pixel height covered by this chunk */ + virt_height = src_y2 - src_y1; + + /* Check if this chunk intersects with the update region */ + if (dst_x + dst_width <= virt_x_1 || + dst_x >= virt_x_1 + virt_width || + dst_y + dst_height <= it_y - py1 || + dst_y >= virt_y_1 + virt_height) + continue; + + /* Calculate the intersection in virtual coordinates */ + copy_dst_width = dst_width; + if (dst_x < virt_x_1) + { + copy_dst_width -= virt_x_1 - dst_x; + copy_dst_x = virt_x_1; + } + else + copy_dst_x = dst_x; + if (copy_dst_width + copy_dst_x > virt_x_1 + virt_width) + copy_dst_width = virt_x_1 + virt_width - copy_dst_x; + + copy_dst_height = dst_height; + if (dst_y < virt_y_1) + { + copy_dst_height -= virt_y_1 - dst_y; + copy_dst_y = virt_y_1; + } + else + copy_dst_y = dst_y; + if (copy_dst_height + copy_dst_y > virt_y_1 + virt_height) + copy_dst_height = virt_y_1 + virt_height - copy_dst_y; + + /* Update the region in the full texture */ + cogl_texture_set_region (sub_tex->full_texture, + src_x + copy_dst_x - dst_x, + src_y + copy_dst_y - dst_y, + src_x1 + copy_dst_x - virt_x_1, + src_y1 + copy_dst_y - virt_y_1, + copy_dst_width, + copy_dst_height, + width, + height, + format, + rowstride, + data); + } + } + + /* Free data if owner */ + if (source_bmp_owner) + g_free (source_bmp.data); + + return TRUE; +} + +static void +_cogl_sub_texture_copy_region (guchar *dst, + const guchar *src, + gint dst_x, gint dst_y, + gint src_x, gint src_y, + gint width, gint height, + gint dst_rowstride, + gint src_rowstride, + gint bpp) +{ + int y; + + dst += dst_x * bpp + dst_y * dst_rowstride; + src += src_x * bpp + src_y * src_rowstride; + + for (y = 0; y < height; y++) + { + memcpy (dst, src, bpp * width); + dst += dst_rowstride; + src += src_rowstride; + } +} + +static int +_cogl_sub_texture_get_data (CoglTexture *tex, + CoglPixelFormat format, + unsigned int rowstride, + guint8 *data) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + unsigned int full_rowstride; + guint8 *full_data; + int byte_size, full_size; + gint bpp; + gint px1, py1, px2, py2; + gint full_tex_width, full_tex_height; + + /* FIXME: This gets the full data from the full texture and then + copies a subregion of that. It would be better if there was a + texture_get_sub_data virtual and it can just munge the texture + coordinates */ + + /* Default to internal format if none specified */ + if (format == COGL_PIXEL_FORMAT_ANY) + format = cogl_texture_get_format (sub_tex->full_texture); + + _cogl_sub_texture_get_x_pixel_pos (sub_tex, &px1, &px2); + _cogl_sub_texture_get_y_pixel_pos (sub_tex, &py1, &py2); + + full_tex_width = cogl_texture_get_width (sub_tex->full_texture); + full_tex_height = cogl_texture_get_height (sub_tex->full_texture); + + /* Rowstride from texture width if none specified */ + bpp = _cogl_get_format_bpp (format); + if (rowstride == 0) + rowstride = px2 - px1; + + /* Return byte size if only that requested */ + byte_size = (py2 - py1) * rowstride; + if (data == NULL) + return byte_size; + + full_rowstride = _cogl_get_format_bpp (format) * full_tex_width; + full_data = g_malloc (full_rowstride * full_tex_height); + + full_size = cogl_texture_get_data (sub_tex->full_texture, format, + full_rowstride, full_data); + + if (full_size) + { + int dst_x, dst_y; + int src_x1, src_y1; + int src_x2, src_y2; + + for (dst_y = py1; dst_y < py2; dst_y += src_y2 - src_y1) + { + _cogl_sub_texture_get_next_chunk (dst_y, py2, full_tex_width, + &src_y1, &src_y2); + + for (dst_x = px1; dst_x < px2; dst_x += src_x2 - src_x1) + { + _cogl_sub_texture_get_next_chunk (dst_x, px2, full_tex_height, + &src_x1, &src_x2); + + _cogl_sub_texture_copy_region (data, full_data, + dst_x - px1, dst_y - py1, + src_x1, src_y1, + src_x2 - src_x1, + src_y2 - src_y1, + rowstride, + full_rowstride, + bpp); + } + } + } + else + byte_size = 0; + + g_free (full_data); + + return byte_size; +} + +static CoglPixelFormat +_cogl_sub_texture_get_format (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + return cogl_texture_get_format (sub_tex->full_texture); +} + +static GLenum +_cogl_sub_texture_get_gl_format (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + return _cogl_texture_get_gl_format (sub_tex->full_texture); +} + +static gint +_cogl_sub_texture_get_width (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + gint px1, px2; + + _cogl_sub_texture_get_x_pixel_pos (sub_tex, &px1, &px2); + + return px2 - px1; +} + +static gint +_cogl_sub_texture_get_height (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + gint py1, py2; + + _cogl_sub_texture_get_y_pixel_pos (sub_tex, &py1, &py2); + + return py2 - py1; +} + +static const CoglTextureVtable +cogl_sub_texture_vtable = + { + _cogl_sub_texture_set_region, + _cogl_sub_texture_get_data, + _cogl_sub_texture_foreach_sub_texture_in_region, + _cogl_sub_texture_get_max_waste, + _cogl_sub_texture_is_sliced, + _cogl_sub_texture_can_hardware_repeat, + _cogl_sub_texture_transform_coords_to_gl, + _cogl_sub_texture_get_gl_texture, + _cogl_sub_texture_set_filters, + _cogl_sub_texture_ensure_mipmaps, + _cogl_sub_texture_set_wrap_mode_parameter, + _cogl_sub_texture_get_format, + _cogl_sub_texture_get_gl_format, + _cogl_sub_texture_get_width, + _cogl_sub_texture_get_height + }; diff --git a/clutter/cogl/cogl/cogl-texture.c b/clutter/cogl/cogl/cogl-texture.c index e4eff2e06..5fc0892cb 100644 --- a/clutter/cogl/cogl/cogl-texture.c +++ b/clutter/cogl/cogl/cogl-texture.c @@ -38,6 +38,7 @@ #include "cogl-texture-private.h" #include "cogl-texture-driver.h" #include "cogl-texture-2d-sliced-private.h" +#include "cogl-sub-texture-private.h" #include "cogl-material.h" #include "cogl-context.h" #include "cogl-handle.h" @@ -62,8 +63,8 @@ cogl_is_texture (CoglHandle handle) if (handle == COGL_INVALID_HANDLE) return FALSE; - return obj->klass->type == _cogl_handle_texture_2d_sliced_get_type (); - //|| obj->klass->type == _cogl_handle_texture_3d_get_type (); + return (obj->klass->type == _cogl_handle_texture_2d_sliced_get_type () || + obj->klass->type == _cogl_handle_sub_texture_get_type ()); } CoglHandle @@ -367,6 +368,16 @@ cogl_texture_new_from_foreign (GLuint gl_handle, format); } +CoglHandle +cogl_texture_new_from_sub_texture (CoglHandle full_texture, + gfloat tx1, + gfloat ty1, + gfloat tx2, + gfloat ty2) +{ + return _cogl_sub_texture_new (full_texture, tx1, ty1, tx2, ty2); +} + guint cogl_texture_get_width (CoglHandle handle) { diff --git a/clutter/cogl/cogl/cogl-texture.h b/clutter/cogl/cogl/cogl-texture.h index b831d1ae1..5e4910f31 100644 --- a/clutter/cogl/cogl/cogl-texture.h +++ b/clutter/cogl/cogl/cogl-texture.h @@ -316,6 +316,33 @@ gboolean cogl_texture_set_region (CoglHandle handle, guint rowstride, const guchar *data); +/** + * cogl_texture_new_from_sub_texture: + * @full_texture: a #CoglHandle to an existing texture + * @tx1: X coordinate of the top-left of the subregion + * @ty1: Y coordinate of the top-left of the subregion + * @tx2: X coordinate of the bottom-right of the subregion + * @ty2: Y coordinate of the bottom-right of the subregion + * + * Creates a new texture which represents a subregion of another + * texture. The GL resources will be shared so that no new texture + * data is actually allocated. + * + * You can also specify texture coordinates outside the range of [0,1] + * to make a texture that represents a repeated version of another + * texture. + * + * Return value: a #CoglHandle to the new texture. + * + * Since: 1.2 + */ +CoglHandle cogl_texture_new_from_sub_texture + (CoglHandle full_texture, + gfloat tx1, + gfloat ty1, + gfloat tx2, + gfloat ty2); + #ifndef COGL_DISABLE_DEPRECATED /** diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 336f9ad03..eda10b462 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -192,6 +192,7 @@ cogl_texture_new_from_file cogl_texture_new_from_data cogl_texture_new_from_foreign cogl_texture_new_from_bitmap +cogl_texture_new_from_sub_texture cogl_is_texture cogl_texture_ref cogl_texture_unref