cogl: Add a texture utility function for manually repeating

Given a region of texture coordinates this utility invokes a callback
enough times to cover the region with a subregion that spans the
texture at most once. Eg, if called with tx1 and tx2 as 0.5 and 3.0 it
it would invoke the callback with:

0.5,1.0  1.0,2.0  2.0,3.0

Manual repeating is needed by all texture backends regardless of
whether they can support hardware repeating because when Cogl calls
the foreach_sub_texture_in_region method then it sets the wrap mode to
GL_CLAMP_TO_EDGE and no hardware repeating is possible.
This commit is contained in:
Neil Roberts 2009-12-02 13:41:49 +00:00
parent 5fcb29c916
commit 1a1de0e278
2 changed files with 116 additions and 0 deletions

View File

@ -41,6 +41,9 @@ typedef void (*CoglTextureSliceCallback) (CoglHandle handle,
float *virtual_coords,
void *user_data);
typedef void (* CoglTextureManualRepeatCallback) (const float *coords,
void *user_data);
struct _CoglTextureVtable
{
/* Virtual functions that must be implemented for a texture
@ -169,6 +172,17 @@ _cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride);
void
_cogl_texture_prep_gl_alignment_for_pixels_download (int pixels_rowstride);
/* Utility function for implementing manual repeating. Even texture
backends that always support hardware repeating need this because
when foreach_sub_texture_in_region is invoked Cogl will set the
wrap mode to GL_CLAMP_TO_EDGE so hardware repeating can't be
done */
void
_cogl_texture_iterate_manual_repeats (CoglTextureManualRepeatCallback callback,
float tx_1, float ty_1,
float tx_2, float ty_2,
void *user_data);
/* Utility function to use as a fallback for getting the data of any
texture via the framebuffer */

View File

@ -195,6 +195,108 @@ _cogl_texture_upload_data_prepare (CoglTextureUploadData *data,
return TRUE;
}
gboolean
_cogl_texture_upload_data_prepare (CoglTextureUploadData *data,
CoglPixelFormat internal_format)
{
return (_cogl_texture_upload_data_prepare_format (data, &internal_format) &&
_cogl_texture_upload_data_convert (data, internal_format));
}
/* This is like CoglSpanIter except it deals with floats and it
effectively assumes there is only one span from 0.0 to 1.0 */
typedef struct _CoglTextureIter
{
gfloat pos, end, next_pos;
gboolean flipped;
gfloat t_1, t_2;
} CoglTextureIter;
static void
_cogl_texture_iter_update (CoglTextureIter *iter)
{
gfloat t_2;
modff (iter->pos, &iter->next_pos);
/* modff rounds the int part towards zero so we need to add one if
we're meant to be heading away from zero */
if (iter->pos >= 0.0f)
iter->next_pos += 1.0f;
if (iter->next_pos > iter->end)
t_2 = iter->end;
else
t_2 = iter->next_pos;
if (iter->flipped)
{
iter->t_1 = t_2;
iter->t_2 = iter->pos;
}
else
{
iter->t_1 = iter->pos;
iter->t_2 = t_2;
}
}
static void
_cogl_texture_iter_begin (CoglTextureIter *iter,
gfloat t_1, gfloat t_2)
{
if (t_1 <= t_2)
{
iter->pos = t_1;
iter->end = t_2;
iter->flipped = FALSE;
}
else
{
iter->pos = t_2;
iter->end = t_1;
iter->flipped = TRUE;
}
_cogl_texture_iter_update (iter);
}
static void
_cogl_texture_iter_next (CoglTextureIter *iter)
{
iter->pos = iter->next_pos;
_cogl_texture_iter_update (iter);
}
static gboolean
_cogl_texture_iter_end (CoglTextureIter *iter)
{
return iter->pos >= iter->end;
}
/* This invokes the callback with enough quads to cover the manually
repeated range specified by the virtual texture coordinates without
emitting coordinates outside the range [0,1] */
void
_cogl_texture_iterate_manual_repeats (CoglTextureManualRepeatCallback callback,
float tx_1, float ty_1,
float tx_2, float ty_2,
void *user_data)
{
CoglTextureIter x_iter, y_iter;
for (_cogl_texture_iter_begin (&y_iter, ty_1, ty_2);
!_cogl_texture_iter_end (&y_iter);
_cogl_texture_iter_next (&y_iter))
for (_cogl_texture_iter_begin (&x_iter, tx_1, tx_2);
!_cogl_texture_iter_end (&x_iter);
_cogl_texture_iter_next (&x_iter))
{
float coords[4] = { x_iter.t_1, y_iter.t_1, x_iter.t_2, y_iter.t_2 };
callback (coords, user_data);
}
}
CoglHandle
cogl_texture_new_with_size (guint width,
guint height,