cogl: Make CoglSubTexture only work for quad rendering

The sub texture backend doesn't work well as a completely general
texture backend because for example when rendering with cogl_polygon
it needs to be able to tranform arbitrary texture coordinates without
reference to the other coordintes. This can't be done when the texture
coordinates are a multiple of one because sometimes the coordinate
should represent the left or top edge and sometimes it should
represent the bottom or top edge. For example if the s coordinates are
0 and 1 then 1 represents the right edge but if they are 1 and 2 then
1 represents the left edge.

Instead the sub-textures are now documented not to support coordinates
outside the range [0,1]. The coordinates for the sub-region are now
represented as integers as this helps avoid rounding issues. The
region can no longer be a super-region of the texture as this
simplifies the code quite a lot.

There are two new texture virtual functions:

transform_quad_coords_to_gl - This transforms two pairs of coordinates
     representing a quad. It will return FALSE if the coordinates can
     not be transformed. The sub texture backend uses this to detect
     coordinates that require repeating which causes cogl-primitives
     to use manual repeating.

ensure_non_quad_rendering - This is used in cogl_polygon and
     cogl_vertex_buffer to inform the texture backend that
     transform_quad_to_gl is going to be used. The atlas backend
     migrates the texture out of the atlas when it hits this.
This commit is contained in:
Neil Roberts 2010-01-18 09:22:04 +00:00
parent b844653c64
commit 36f18e5ac5
12 changed files with 347 additions and 433 deletions

View File

@ -34,6 +34,7 @@
#include "cogl-texture-private.h"
#include "cogl-atlas-texture-private.h"
#include "cogl-texture-2d-private.h"
#include "cogl-sub-texture-private.h"
#include "cogl-context.h"
#include "cogl-handle.h"
#include "cogl-texture-driver.h"
@ -312,6 +313,17 @@ _cogl_atlas_texture_transform_coords_to_gl (CoglTexture *tex,
_cogl_texture_transform_coords_to_gl (atlas_tex->sub_texture, s, t);
}
static gboolean
_cogl_atlas_texture_transform_quad_coords_to_gl (CoglTexture *tex,
float *coords)
{
CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
/* Forward on to the sub texture */
return _cogl_texture_transform_quad_coords_to_gl (atlas_tex->sub_texture,
coords);
}
static gboolean
_cogl_atlas_texture_get_gl_texture (CoglTexture *tex,
GLuint *out_gl_handle,
@ -337,12 +349,9 @@ _cogl_atlas_texture_set_filters (CoglTexture *tex,
}
static void
_cogl_atlas_texture_ensure_mipmaps (CoglTexture *tex)
_cogl_atlas_texture_migrate_out_of_atlas (CoglAtlasTexture *atlas_tex)
{
CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
/* Mipmaps do not work well with the current atlas so instead we'll
just migrate the texture out and use a regular texture */
/* Make sure this texture is not in the atlas */
if (atlas_tex->in_atlas)
{
CoglHandle atlas_texture;
@ -382,11 +391,34 @@ _cogl_atlas_texture_ensure_mipmaps (CoglTexture *tex)
_cogl_atlas_texture_remove_from_atlas (atlas_tex);
}
}
static void
_cogl_atlas_texture_ensure_mipmaps (CoglTexture *tex)
{
CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
/* Mipmaps do not work well with the current atlas so instead we'll
just migrate the texture out and use a regular texture */
_cogl_atlas_texture_migrate_out_of_atlas (atlas_tex);
/* Forward on to the sub texture */
_cogl_texture_ensure_mipmaps (atlas_tex->sub_texture);
}
static void
_cogl_atlas_texture_ensure_non_quad_rendering (CoglTexture *tex)
{
CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
/* Sub textures can't support non-quad rendering so we'll just
migrate the texture out */
_cogl_atlas_texture_migrate_out_of_atlas (atlas_tex);
/* Forward on to the sub texture */
_cogl_texture_ensure_non_quad_rendering (atlas_tex->sub_texture);
}
static gboolean
_cogl_atlas_texture_set_region (CoglTexture *tex,
int src_x,
@ -546,14 +578,11 @@ _cogl_atlas_texture_create_sub_texture (CoglHandle full_texture,
{
/* Create a subtexture for the given rectangle not including the
1-pixel border */
gfloat tex_width = cogl_texture_get_width (full_texture);
gfloat tex_height = cogl_texture_get_height (full_texture);
gfloat tx1 = (rectangle->x + 1) / tex_width;
gfloat ty1 = (rectangle->y + 1) / tex_height;
gfloat tx2 = (rectangle->x + rectangle->width - 1) / tex_width;
gfloat ty2 = (rectangle->y + rectangle->height - 1) / tex_height;
return cogl_texture_new_from_sub_texture (full_texture, tx1, ty1, tx2, ty2);
return _cogl_sub_texture_new (full_texture,
rectangle->x + 1,
rectangle->y + 1,
rectangle->width - 2,
rectangle->height - 2);
}
typedef struct _CoglAtlasTextureRepositionData
@ -958,9 +987,11 @@ cogl_atlas_texture_vtable =
_cogl_atlas_texture_is_sliced,
_cogl_atlas_texture_can_hardware_repeat,
_cogl_atlas_texture_transform_coords_to_gl,
_cogl_atlas_texture_transform_quad_coords_to_gl,
_cogl_atlas_texture_get_gl_texture,
_cogl_atlas_texture_set_filters,
_cogl_atlas_texture_ensure_mipmaps,
_cogl_atlas_texture_ensure_non_quad_rendering,
_cogl_atlas_texture_set_wrap_mode_parameter,
_cogl_atlas_texture_get_format,
_cogl_atlas_texture_get_gl_format,

View File

@ -278,14 +278,14 @@ _cogl_multitexture_quad_single_primitive (float x_1,
the coordinates (such as in the sub texture backend). This
should be safe to call because we know that the texture only
has one slice. */
for (coord_num = 0; coord_num < 2; coord_num++)
{
float *s = out_tex_coords + coord_num * 2;
float *t = s + 1;
_cogl_texture_transform_coords_to_gl (tex_handle, s, t);
if (*s < 0.0f || *s > 1.0f || *t < 0.0f || *t > 1.0f)
need_repeat = TRUE;
}
if (!_cogl_texture_transform_quad_coords_to_gl (tex_handle,
out_tex_coords))
/* If the backend can't support these coordinates then bail out */
return FALSE;
for (coord_num = 0; coord_num < 4; coord_num++)
if (out_tex_coords[coord_num] < 0.0f ||
out_tex_coords[coord_num] > 1.0f)
need_repeat = TRUE;
/* If the texture has waste or we are using GL_TEXTURE_RECT we
* can't handle texture repeating so we can't use the layer if
@ -867,6 +867,11 @@ cogl_polygon (const CoglTextureVertex *vertices,
if (tex_handle == COGL_INVALID_HANDLE)
continue;
/* Give the texture a chance to know that we're rendering
non-quad shaped primitives. If the texture is in an atlas it
will be migrated */
_cogl_texture_ensure_non_quad_rendering (tex_handle);
if (i == 0 && cogl_texture_is_sliced (tex_handle))
{
#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2)

View File

@ -37,12 +37,11 @@ struct _CoglSubTexture
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;
/* The region represented by this sub-texture */
gint sub_x;
gint sub_y;
gint sub_width;
gint sub_height;
};
GQuark
@ -50,7 +49,7 @@ _cogl_handle_sub_texture_get_type (void);
CoglHandle
_cogl_sub_texture_new (CoglHandle full_texture,
gfloat tx1, gfloat ty1,
gfloat tx2, gfloat ty2);
gint sub_x, gint sub_y,
gint sub_width, gint sub_height);
#endif /* __COGL_SUB_TEXTURE_H */

View File

@ -46,63 +46,105 @@ 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)
_cogl_sub_texture_map_range (gfloat *t1, gfloat *t2,
gint sub_offset,
gint sub_size,
gint full_size)
{
*tx = *tx * (sub_tex->tx2 - sub_tex->tx1) + sub_tex->tx1;
*ty = *ty * (sub_tex->ty2 - sub_tex->ty1) + sub_tex->ty1;
gfloat t1_frac, t1_int, t2_frac, t2_int;
t1_frac = modff (*t1, &t1_int);
t2_frac = modff (*t2, &t2_int);
if (t1_frac < 0.0f)
{
t1_frac += 1.0f;
t1_int -= 1.0f;
}
if (t2_frac < 0.0f)
{
t2_frac += 1.0f;
t2_int -= 1.0f;
}
/* If one of the coordinates is zero we need to make sure it is
still greater than the other coordinate if it was originally so
we'll flip it to the other side */
if (*t1 < *t2)
{
if (t2_frac == 0.0f)
{
t2_frac = 1.0f;
t2_int -= 1.0f;
}
}
else
{
if (t1_frac == 0.0f)
{
t1_frac = 1.0f;
t1_int -= 1.0f;
}
}
/* Convert the fractional part leaving the integer part intact */
t1_frac = (sub_offset + t1_frac * sub_size) / full_size;
*t1 = t1_frac + t1_int;
t2_frac = (sub_offset + t2_frac * sub_size) / full_size;
*t2 = t2_frac + t2_int;
}
static void
_cogl_sub_texture_map_coordinate_set (CoglSubTexture *sub_tex,
gfloat *tx1, gfloat *ty1,
gfloat *tx2, gfloat *ty2)
_cogl_sub_texture_map_quad (CoglSubTexture *sub_tex,
gfloat *coords)
{
_cogl_sub_texture_map_coordinate_pair (sub_tex, tx1, ty1);
_cogl_sub_texture_map_coordinate_pair (sub_tex, tx2, ty2);
guint full_width = cogl_texture_get_width (sub_tex->full_texture);
guint full_height = cogl_texture_get_height (sub_tex->full_texture);
_cogl_sub_texture_map_range (coords + 0, coords + 2,
sub_tex->sub_x, sub_tex->sub_width,
full_width);
_cogl_sub_texture_map_range (coords + 1, coords + 3,
sub_tex->sub_y, sub_tex->sub_height,
full_height);
}
/* 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)
static gfloat
_cogl_sub_texture_unmap_coord (gfloat t,
gint sub_offset,
gint sub_size,
gint full_size)
{
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);
gfloat frac_part, int_part;
if (sub_tex->ty1 == sub_tex->ty2)
coords[0] = sub_tex->ty1;
/* Convert the fractional part leaving the integer part in tact */
frac_part = modff (t, &int_part);
if (signbit (frac_part))
frac_part = ((1.0f + frac_part) * full_size -
sub_offset - sub_size) / sub_size;
else
coords[1] = (coords[1] - sub_tex->ty1) / (sub_tex->ty2 - sub_tex->ty1);
frac_part = (frac_part * full_size - sub_offset) / sub_size;
return frac_part + int_part;
}
static void
_cogl_sub_texture_unmap_coordinate_set (CoglSubTexture *sub_tex,
gfloat *coords)
_cogl_sub_texture_unmap_coords (CoglSubTexture *sub_tex,
gfloat *s,
gfloat *t)
{
_cogl_sub_texture_unmap_coordinate_pair (sub_tex, coords);
_cogl_sub_texture_unmap_coordinate_pair (sub_tex, coords + 2);
}
guint full_width = cogl_texture_get_width (sub_tex->full_texture);
guint full_height = cogl_texture_get_height (sub_tex->full_texture);
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));
*s = _cogl_sub_texture_unmap_coord (*s, sub_tex->sub_x, sub_tex->sub_width,
full_width);
*t = _cogl_sub_texture_unmap_coord (*t, sub_tex->sub_y, sub_tex->sub_height,
full_height);
}
typedef struct _CoglSubTextureForeachData
@ -126,7 +168,12 @@ _cogl_sub_texture_foreach_cb (CoglHandle handle,
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);
_cogl_sub_texture_unmap_coords (data->sub_tex,
&virtual_coords[0],
&virtual_coords[1]);
_cogl_sub_texture_unmap_coords (data->sub_tex,
&virtual_coords[2],
&virtual_coords[3]);
data->callback (handle, gl_handle, gl_target,
slice_coords, virtual_coords,
@ -142,11 +189,7 @@ _cogl_sub_texture_manual_repeat_cb (const float *coords,
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_sub_texture_map_quad (data->sub_tex, mapped_coords);
_cogl_texture_foreach_sub_texture_in_region (data->sub_tex->full_texture,
mapped_coords[0],
@ -174,30 +217,10 @@ _cogl_sub_texture_foreach_sub_texture_in_region (
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);
_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
@ -219,12 +242,21 @@ _cogl_sub_texture_free (CoglSubTexture *sub_tex)
CoglHandle
_cogl_sub_texture_new (CoglHandle full_texture,
gfloat tx1, gfloat ty1,
gfloat tx2, gfloat ty2)
gint sub_x, gint sub_y,
gint sub_width, gint sub_height)
{
CoglSubTexture *sub_tex;
CoglTexture *tex;
gfloat integer_part;
guint full_width, full_height;
full_width = cogl_texture_get_width (full_texture);
full_height = cogl_texture_get_width (full_texture);
/* The region must specify a non-zero subset of the full texture */
g_return_val_if_fail (sub_x >= 0 && sub_y >= 0, COGL_INVALID_HANDLE);
g_return_val_if_fail (sub_width > 0 && sub_height > 0, COGL_INVALID_HANDLE);
g_return_val_if_fail (sub_x + sub_width <= full_width, COGL_INVALID_HANDLE);
g_return_val_if_fail (sub_y + sub_height <= full_height, COGL_INVALID_HANDLE);
sub_tex = g_new (CoglSubTexture, 1);
@ -233,18 +265,10 @@ _cogl_sub_texture_new (CoglHandle full_texture,
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);
sub_tex->sub_x = sub_x;
sub_tex->sub_y = sub_y;
sub_tex->sub_width = sub_width;
sub_tex->sub_height = sub_height;
return _cogl_sub_texture_handle_new (sub_tex);
}
@ -270,11 +294,12 @@ _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 &&
/* We can hardware repeat if the subtexture actually represents all of the
of the full texture */
return (sub_tex->sub_width ==
cogl_texture_get_width (sub_tex->full_texture) &&
sub_tex->sub_height ==
cogl_texture_get_height (sub_tex->full_texture) &&
_cogl_texture_can_hardware_repeat (sub_tex->full_texture));
}
@ -285,8 +310,34 @@ _cogl_sub_texture_transform_coords_to_gl (CoglTexture *tex,
{
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);
/* This won't work if the sub texture is not the size of the full
texture and the coordinates are outside the range [0,1] */
*s = ((*s * sub_tex->sub_width + sub_tex->sub_x) /
cogl_texture_get_width (sub_tex->full_texture));
*t = ((*t * sub_tex->sub_height + sub_tex->sub_y) /
cogl_texture_get_height (sub_tex->full_texture));
return _cogl_texture_transform_coords_to_gl (sub_tex->full_texture, s, t);
}
static gboolean
_cogl_sub_texture_transform_quad_coords_to_gl (CoglTexture *tex,
float *coords)
{
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
int i;
/* We can't support repeating with this method. In this case
cogl-primitives will resort to manual repeating */
for (i = 0; i < 4; i++)
if (coords[i] < 0.0f || coords[i] > 1.0f)
return FALSE;
_cogl_sub_texture_map_quad (sub_tex, coords);
_cogl_texture_transform_quad_coords_to_gl (sub_tex->full_texture, coords);
return TRUE;
}
static gboolean
@ -320,67 +371,8 @@ _cogl_sub_texture_ensure_mipmaps (CoglTexture *tex)
}
static void
_cogl_sub_texture_get_next_chunk (int pos, int end,
int tex_size,
int *chunk_start, int *chunk_end)
_cogl_sub_texture_ensure_non_quad_rendering (CoglTexture *tex)
{
/* 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_height = cogl_texture_get_height (sub_tex->full_texture);
*py1 = full_height * sub_tex->ty1;
*py2 = full_height * sub_tex->ty2;
if (*py1 > *py2)
{
gint temp = *py1;
*py1 = *py2;
*py2 = temp;
}
}
static gboolean
@ -397,144 +389,17 @@ _cogl_sub_texture_set_region (CoglTexture *tex,
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;
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
/* 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;
return cogl_texture_set_region (sub_tex->full_texture,
src_x, src_y,
dst_x + sub_tex->sub_x,
dst_y + sub_tex->sub_y,
dst_width, dst_height,
width, height,
format,
rowstride,
data);
}
static void
@ -571,7 +436,6 @@ _cogl_sub_texture_get_data (CoglTexture *tex,
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
@ -583,19 +447,16 @@ _cogl_sub_texture_get_data (CoglTexture *tex,
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;
rowstride = sub_tex->sub_width * bpp;
/* Return byte size if only that requested */
byte_size = (py2 - py1) * rowstride;
byte_size = sub_tex->sub_height * rowstride;
if (data == NULL)
return byte_size;
@ -606,32 +467,15 @@ _cogl_sub_texture_get_data (CoglTexture *tex,
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);
}
}
}
_cogl_sub_texture_copy_region (data, full_data,
0, 0,
sub_tex->sub_x,
sub_tex->sub_y,
sub_tex->sub_width,
sub_tex->sub_height,
rowstride,
full_rowstride,
bpp);
else
byte_size = 0;
@ -660,22 +504,16 @@ 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;
return sub_tex->sub_width;
}
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;
return sub_tex->sub_height;
}
static const CoglTextureVtable
@ -688,9 +526,11 @@ cogl_sub_texture_vtable =
_cogl_sub_texture_is_sliced,
_cogl_sub_texture_can_hardware_repeat,
_cogl_sub_texture_transform_coords_to_gl,
_cogl_sub_texture_transform_quad_coords_to_gl,
_cogl_sub_texture_get_gl_texture,
_cogl_sub_texture_set_filters,
_cogl_sub_texture_ensure_mipmaps,
_cogl_sub_texture_ensure_non_quad_rendering,
_cogl_sub_texture_set_wrap_mode_parameter,
_cogl_sub_texture_get_format,
_cogl_sub_texture_get_gl_format,

View File

@ -1266,6 +1266,19 @@ _cogl_texture_2d_sliced_transform_coords_to_gl (CoglTexture *tex,
#endif
}
static gboolean
_cogl_texture_2d_sliced_transform_quad_coords_to_gl (CoglTexture *tex,
float *coords)
{
if (_cogl_texture_2d_sliced_is_sliced (tex))
return FALSE;
_cogl_texture_2d_sliced_transform_coords_to_gl (tex, coords + 0, coords + 1);
_cogl_texture_2d_sliced_transform_coords_to_gl (tex, coords + 2, coords + 3);
return TRUE;
}
static gboolean
_cogl_texture_2d_sliced_get_gl_texture (CoglTexture *tex,
GLuint *out_gl_handle,
@ -1362,6 +1375,12 @@ _cogl_texture_2d_sliced_ensure_mipmaps (CoglTexture *tex)
tex_2ds->mipmaps_dirty = FALSE;
}
static void
_cogl_texture_2d_sliced_ensure_non_quad_rendering (CoglTexture *tex)
{
/* Nothing needs to be done */
}
static gboolean
_cogl_texture_2d_sliced_set_region (CoglTexture *tex,
int src_x,
@ -1673,9 +1692,11 @@ cogl_texture_2d_sliced_vtable =
_cogl_texture_2d_sliced_is_sliced,
_cogl_texture_2d_sliced_can_hardware_repeat,
_cogl_texture_2d_sliced_transform_coords_to_gl,
_cogl_texture_2d_sliced_transform_quad_coords_to_gl,
_cogl_texture_2d_sliced_get_gl_texture,
_cogl_texture_2d_sliced_set_filters,
_cogl_texture_2d_sliced_ensure_mipmaps,
_cogl_texture_2d_sliced_ensure_non_quad_rendering,
_cogl_texture_2d_sliced_set_wrap_mode_parameter,
_cogl_texture_2d_sliced_get_format,
_cogl_texture_2d_sliced_get_gl_format,

View File

@ -342,6 +342,15 @@ _cogl_texture_2d_transform_coords_to_gl (CoglTexture *tex,
anything */
}
static gboolean
_cogl_texture_2d_transform_quad_coords_to_gl (CoglTexture *tex,
float *coords)
{
/* The texture coordinates map directly so we don't need to do
anything */
return TRUE;
}
static gboolean
_cogl_texture_2d_get_gl_texture (CoglTexture *tex,
GLuint *out_gl_handle,
@ -399,6 +408,12 @@ _cogl_texture_2d_ensure_mipmaps (CoglTexture *tex)
tex_2d->mipmaps_dirty = FALSE;
}
static void
_cogl_texture_2d_ensure_non_quad_rendering (CoglTexture *tex)
{
/* Nothing needs to be done */
}
static gboolean
_cogl_texture_2d_set_region (CoglTexture *tex,
int src_x,
@ -612,9 +627,11 @@ cogl_texture_2d_vtable =
_cogl_texture_2d_is_sliced,
_cogl_texture_2d_can_hardware_repeat,
_cogl_texture_2d_transform_coords_to_gl,
_cogl_texture_2d_transform_quad_coords_to_gl,
_cogl_texture_2d_get_gl_texture,
_cogl_texture_2d_set_filters,
_cogl_texture_2d_ensure_mipmaps,
_cogl_texture_2d_ensure_non_quad_rendering,
_cogl_texture_2d_set_wrap_mode_parameter,
_cogl_texture_2d_get_format,
_cogl_texture_2d_get_gl_format,

View File

@ -84,6 +84,8 @@ struct _CoglTextureVtable
void (* transform_coords_to_gl) (CoglTexture *tex,
float *s,
float *t);
gboolean (* transform_quad_coords_to_gl) (CoglTexture *tex,
float *coords);
gboolean (* get_gl_texture) (CoglTexture *tex,
GLuint *out_gl_handle,
@ -94,6 +96,7 @@ struct _CoglTextureVtable
GLenum mag_filter);
void (* ensure_mipmaps) (CoglTexture *tex);
void (* ensure_non_quad_rendering) (CoglTexture *tex);
void (* set_wrap_mode_parameter) (CoglTexture *tex,
GLenum wrap_mode);
@ -137,6 +140,10 @@ void
_cogl_texture_transform_coords_to_gl (CoglHandle handle,
float *s,
float *t);
gboolean
_cogl_texture_transform_quad_coords_to_gl (CoglHandle handle,
float *coords);
GLenum
_cogl_texture_get_gl_format (CoglHandle handle);
@ -152,6 +159,9 @@ _cogl_texture_set_filters (CoglHandle handle,
void
_cogl_texture_ensure_mipmaps (CoglHandle handle);
void
_cogl_texture_ensure_non_quad_rendering (CoglHandle handle);
/* Utility functions to help uploading a bitmap. These are intended to
* be used by CoglTexture implementations or drivers... */

View File

@ -428,12 +428,13 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
CoglHandle
cogl_texture_new_from_sub_texture (CoglHandle full_texture,
gfloat tx1,
gfloat ty1,
gfloat tx2,
gfloat ty2)
gint sub_x,
gint sub_y,
gint sub_width,
gint sub_height)
{
return _cogl_sub_texture_new (full_texture, tx1, ty1, tx2, ty2);
return _cogl_sub_texture_new (full_texture, sub_x, sub_y,
sub_width, sub_height);
}
guint
@ -574,6 +575,15 @@ _cogl_texture_transform_coords_to_gl (CoglHandle handle,
tex->vtable->transform_coords_to_gl (tex, s, t);
}
gboolean
_cogl_texture_transform_quad_coords_to_gl (CoglHandle handle,
float *coords)
{
CoglTexture *tex = COGL_TEXTURE (handle);
return tex->vtable->transform_quad_coords_to_gl (tex, coords);
}
GLenum
_cogl_texture_get_gl_format (CoglHandle handle)
{
@ -625,6 +635,19 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle)
tex->vtable->ensure_mipmaps (tex);
}
void
_cogl_texture_ensure_non_quad_rendering (CoglHandle handle)
{
CoglTexture *tex;
if (!cogl_is_texture (handle))
return;
tex = COGL_TEXTURE (handle);
return tex->vtable->ensure_non_quad_rendering (tex);
}
gboolean
cogl_texture_set_region (CoglHandle handle,
gint src_x,

View File

@ -320,18 +320,18 @@ gboolean cogl_texture_set_region (CoglHandle handle,
/**
* 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
* @sub_x: X coordinate of the top-left of the subregion
* @sub_y: Y coordinate of the top-left of the subregion
* @sub_width: Width in pixels of the subregion
* @sub_height: Height in pixels 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.
* Sub textures have undefined behaviour texture coordinates outside
* of the range [0,1] are used. They also do not work with
* CoglVertexBuffers.
*
* Return value: a #CoglHandle to the new texture.
*
@ -339,10 +339,10 @@ gboolean cogl_texture_set_region (CoglHandle handle,
*/
CoglHandle cogl_texture_new_from_sub_texture
(CoglHandle full_texture,
gfloat tx1,
gfloat ty1,
gfloat tx2,
gfloat ty2);
gint sub_x,
gint sub_y,
gint sub_width,
gint sub_height);
#ifndef COGL_DISABLE_DEPRECATED

View File

@ -1637,6 +1637,11 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
if (tex_handle == COGL_INVALID_HANDLE)
continue;
/* Give the texture a chance to know that we're rendering
non-quad shaped primitives. If the texture is in an atlas it
will be migrated */
_cogl_texture_ensure_non_quad_rendering (tex_handle);
if (!_cogl_texture_can_hardware_repeat (tex_handle))
{
g_warning ("Disabling layer %d of the current source material, "

View File

@ -74,9 +74,10 @@ draw_frame (TestState *state)
/* Create a sub texture of the bottom right quarter of the texture */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
1.0f / SOURCE_DIVISIONS_X,
1.0f / SOURCE_DIVISIONS_Y,
1.0f, 1.0f);
DIVISION_WIDTH,
DIVISION_HEIGHT,
DIVISION_WIDTH,
DIVISION_HEIGHT);
/* Paint it */
cogl_set_source_texture (sub_texture);
@ -84,22 +85,19 @@ draw_frame (TestState *state)
cogl_handle_unref (sub_texture);
/* Repeat a sub texture of the top half of the full texture */
/* Repeat a sub texture of the top half of the full texture. This is
documented to be undefined so it doesn't technically have to work
but it will with the current implementation */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
0.0f, 0.0f, 1.0f, 0.5f);
0, 0,
SOURCE_SIZE,
DIVISION_HEIGHT);
cogl_set_source_texture (sub_texture);
cogl_rectangle_with_texture_coords (0.0f, SOURCE_SIZE,
SOURCE_SIZE * 2.0f, SOURCE_SIZE * 1.5f,
0.0f, 0.0f,
2.0f, 1.0f);
cogl_handle_unref (sub_texture);
/* Create a texture that repeats the source texture twice */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
0.0f, 0.0f, 2.0f, 2.0f);
cogl_set_source_texture (sub_texture);
cogl_rectangle (0.0f, SOURCE_SIZE * 2, SOURCE_SIZE * 2, SOURCE_SIZE * 4);
cogl_handle_unref (sub_texture);
}
static gboolean
@ -209,22 +207,12 @@ validate_result (TestState *state)
DIVISION_WIDTH, DIVISION_HEIGHT,
corner_colors + division_num));
/* Sub texture that repeats the texture (the opposite of a sub-texture?) */
for (y = 0; y < SOURCE_DIVISIONS_Y * 2; y++)
for (x = 0; x < SOURCE_DIVISIONS_X * 2; x++)
{
guint color_num = (y % SOURCE_DIVISIONS_Y * SOURCE_DIVISIONS_X +
x % SOURCE_DIVISIONS_X);
g_assert (validate_part (state,
x * DIVISION_WIDTH,
y * DIVISION_WIDTH + SOURCE_SIZE * 2,
DIVISION_WIDTH, DIVISION_HEIGHT,
corner_colors + color_num));
}
/* Try reading back the texture data */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
0.25f, 0.25f, 0.75f, 0.75f);
SOURCE_SIZE / 4,
SOURCE_SIZE / 4,
SOURCE_SIZE / 2,
SOURCE_SIZE / 2);
tex_width = cogl_texture_get_width (sub_texture);
tex_height = cogl_texture_get_height (sub_texture);
p = texture_data = g_malloc (tex_width * tex_height * 4);
@ -248,39 +236,14 @@ validate_result (TestState *state)
g_free (texture_data);
cogl_handle_unref (sub_texture);
/* Try reading back the repeated texture data */
sub_texture = cogl_texture_new_from_sub_texture (state->tex,
0.0f, 0.0f, 2.0f, 2.0f);
tex_width = cogl_texture_get_width (sub_texture);
tex_height = cogl_texture_get_height (sub_texture);
p = texture_data = g_malloc (tex_width * tex_height * 4);
cogl_texture_get_data (sub_texture, COGL_PIXEL_FORMAT_RGBA_8888,
tex_width * 4,
texture_data);
for (y = 0; y < tex_height; y++)
for (x = 0; x < tex_width; x++)
{
int div_x = x / DIVISION_WIDTH % SOURCE_DIVISIONS_X;
int div_y = y / DIVISION_HEIGHT % SOURCE_DIVISIONS_Y;
const ClutterColor *color = (corner_colors + div_x +
div_y * SOURCE_DIVISIONS_X);
g_assert (p[0] == color->red);
g_assert (p[1] == color->green);
g_assert (p[2] == color->blue);
p += 4;
}
g_free (texture_data);
cogl_handle_unref (sub_texture);
/* Create a 256x256 test texture */
test_tex = create_test_texture ();
/* Create a sub texture the views the bottom right and top left of
the texture by wrapping around */
/* Create a sub texture the views the center half of the texture */
sub_texture = cogl_texture_new_from_sub_texture (test_tex,
0.5f, 0.5f, 1.5f, 1.5f);
/* Update the center of the sub texture */
64, 64, 128, 128);
/* Update the center half of the sub texture */
texture_data = create_update_data ();
cogl_texture_set_region (sub_texture, 0, 0, 64, 64, 128, 128, 256, 256,
cogl_texture_set_region (sub_texture, 0, 0, 32, 32, 64, 64, 256, 256,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4,
texture_data);
g_free (texture_data);
@ -294,13 +257,13 @@ validate_result (TestState *state)
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
/* If we're in the center of the subregion.. */
if ((x < 64 || x >= 192) && (y < 64 || y >= 192))
/* If we're in the center quarter */
if (x >= 96 && x < 160 && y >= 96 && y < 160)
{
g_assert ((*p++) == 0);
g_assert ((*p++) == 0);
g_assert ((*p++) == ((x + 64) & 0xff));
g_assert ((*p++) == ((y + 64) & 0xff));
g_assert ((*p++) == x - 96);
g_assert ((*p++) == y - 96);
}
else
{

View File

@ -145,7 +145,6 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/opacity", test_paint_opacity);
TEST_CONFORM_SIMPLE ("/texture", test_texture_fbo);
TEST_CONFORM_SIMPLE ("/texture", test_cogl_sub_texture);
TEST_CONFORM_SIMPLE ("/path", test_path);
@ -189,6 +188,7 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_npot_texture);
TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_multitexture);
TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_texture_mipmaps);
TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_sub_texture);
TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_contiguous);
TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_interleved);