diff --git a/cogl/cogl-sub-texture-private.h b/cogl/cogl-sub-texture-private.h index 16513425e..40ce68812 100644 --- a/cogl/cogl-sub-texture-private.h +++ b/cogl/cogl-sub-texture-private.h @@ -35,9 +35,22 @@ struct _CoglSubTexture { CoglTexture _parent; + /* This is the texture that was passed in to + _cogl_sub_texture_new. If this is also a sub texture then we will + use the full texture from that to render instead of making a + chain. However we want to preserve the next texture in case the + user is expecting us to keep a reference and also so that we can + later add a cogl_sub_texture_get_full_texture() function. */ + CoglHandle next_texture; + /* This is the texture that will actually be used to draw. It will + point to the end of the chain if a sub texture of a sub texture + is created */ CoglHandle full_texture; - /* The region represented by this sub-texture */ + /* The region represented by this sub-texture. This is the region of + full_texture which won't necessarily be the same as the region + passed to _cogl_sub_texture_new if next_texture is actually + already a sub texture */ int sub_x; int sub_y; int sub_width; @@ -48,7 +61,7 @@ GQuark _cogl_handle_sub_texture_get_type (void); CoglHandle -_cogl_sub_texture_new (CoglHandle full_texture, +_cogl_sub_texture_new (CoglHandle next_texture, int sub_x, int sub_y, int sub_width, diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c index d28bcf850..b63006379 100644 --- a/cogl/cogl-sub-texture.c +++ b/cogl/cogl-sub-texture.c @@ -235,34 +235,51 @@ _cogl_sub_texture_set_wrap_mode_parameter (CoglTexture *tex, static void _cogl_sub_texture_free (CoglSubTexture *sub_tex) { + cogl_handle_unref (sub_tex->next_texture); cogl_handle_unref (sub_tex->full_texture); g_free (sub_tex); } CoglHandle -_cogl_sub_texture_new (CoglHandle full_texture, +_cogl_sub_texture_new (CoglHandle next_texture, int sub_x, int sub_y, int sub_width, int sub_height) { + CoglHandle full_texture; CoglSubTexture *sub_tex; CoglTexture *tex; - unsigned int full_width, full_height; + unsigned int next_width, next_height; - full_width = cogl_texture_get_width (full_texture); - full_height = cogl_texture_get_height (full_texture); + next_width = cogl_texture_get_width (next_texture); + next_height = cogl_texture_get_height (next_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); + g_return_val_if_fail (sub_x + sub_width <= next_width, COGL_INVALID_HANDLE); + g_return_val_if_fail (sub_y + sub_height <= next_height, COGL_INVALID_HANDLE); sub_tex = g_new (CoglSubTexture, 1); tex = COGL_TEXTURE (sub_tex); tex->vtable = &cogl_sub_texture_vtable; + /* If the next texture is also a sub texture we can avoid one level + of indirection by referencing the full texture of that texture + instead. */ + if (cogl_is_sub_texture (next_texture)) + { + CoglSubTexture *other_sub_tex = + _cogl_sub_texture_pointer_from_handle (next_texture); + full_texture = other_sub_tex->full_texture; + sub_x += other_sub_tex->sub_x; + sub_y += other_sub_tex->sub_y; + } + else + full_texture = next_texture; + + sub_tex->next_texture = cogl_handle_ref (next_texture); sub_tex->full_texture = cogl_handle_ref (full_texture); sub_tex->sub_x = sub_x; diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h index 4f9a40ce8..44644059b 100644 --- a/cogl/cogl-texture.h +++ b/cogl/cogl-texture.h @@ -348,6 +348,10 @@ cogl_texture_set_region (CoglHandle handle, * of the range [0,1] are used. They also do not work with * CoglVertexBuffers. * + * The sub texture will keep a reference to the full texture so you do + * not need to keep one separately if you only want to use the sub + * texture. + * * Return value: a #CoglHandle to the new texture. * * Since: 1.2