From 1a1de0e278de7c06b528ae74a31580dfd576d041 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Wed, 2 Dec 2009 13:41:49 +0000 Subject: [PATCH] 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. --- clutter/cogl/cogl/cogl-texture-private.h | 14 ++++ clutter/cogl/cogl/cogl-texture.c | 102 +++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/clutter/cogl/cogl/cogl-texture-private.h b/clutter/cogl/cogl/cogl-texture-private.h index d8edb2865..9ea5fbfb2 100644 --- a/clutter/cogl/cogl/cogl-texture-private.h +++ b/clutter/cogl/cogl/cogl-texture-private.h @@ -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 */ diff --git a/clutter/cogl/cogl/cogl-texture.c b/clutter/cogl/cogl/cogl-texture.c index c3e256fd3..e4eff2e06 100644 --- a/clutter/cogl/cogl/cogl-texture.c +++ b/clutter/cogl/cogl/cogl-texture.c @@ -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,