mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 19:42:05 +00:00
meta-texture: Support CLAMP_TO_EDGE
cogl_meta_texture_foreach_in_region() now directly supports CLAMP_TO_EDGE wrap modes. This means the cogl_rectangle code will be able to build on this and makes the logic accessible to anyone developing custom primitives that need to support meta textures. Reviewed-by: Neil Roberts <neil@linux.intel.com>
This commit is contained in:
parent
8cf76ee36b
commit
4c49f83056
@ -217,6 +217,224 @@ create_grid_and_repeat_cb (CoglTexture *slice_texture,
|
|||||||
data->padded_textures[n_y_spans * y_real_index + x_real_index] = NULL;
|
data->padded_textures[n_y_spans * y_real_index + x_real_index] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0)
|
||||||
|
|
||||||
|
typedef struct _ClampData
|
||||||
|
{
|
||||||
|
float start;
|
||||||
|
float end;
|
||||||
|
gboolean s_flipped;
|
||||||
|
gboolean t_flipped;
|
||||||
|
CoglMetaTextureCallback callback;
|
||||||
|
void *user_data;
|
||||||
|
} ClampData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
clamp_s_cb (CoglTexture *sub_texture,
|
||||||
|
const float *sub_texture_coords,
|
||||||
|
const float *meta_coords,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
ClampData *clamp_data = user_data;
|
||||||
|
float mapped_meta_coords[4] = {
|
||||||
|
clamp_data->start,
|
||||||
|
meta_coords[1],
|
||||||
|
clamp_data->end,
|
||||||
|
meta_coords[3]
|
||||||
|
};
|
||||||
|
if (clamp_data->s_flipped)
|
||||||
|
SWAP (mapped_meta_coords[0], mapped_meta_coords[2]);
|
||||||
|
/* NB: we never need to flip the t coords when dealing with
|
||||||
|
* s-axis clamping so no need to check if ->t_flipped */
|
||||||
|
clamp_data->callback (sub_texture,
|
||||||
|
sub_texture_coords, mapped_meta_coords,
|
||||||
|
clamp_data->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clamp_t_cb (CoglTexture *sub_texture,
|
||||||
|
const float *sub_texture_coords,
|
||||||
|
const float *meta_coords,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
ClampData *clamp_data = user_data;
|
||||||
|
float mapped_meta_coords[4] = {
|
||||||
|
meta_coords[0],
|
||||||
|
clamp_data->start,
|
||||||
|
meta_coords[2],
|
||||||
|
clamp_data->end,
|
||||||
|
};
|
||||||
|
if (clamp_data->s_flipped)
|
||||||
|
SWAP (mapped_meta_coords[0], mapped_meta_coords[2]);
|
||||||
|
if (clamp_data->t_flipped)
|
||||||
|
SWAP (mapped_meta_coords[1], mapped_meta_coords[3]);
|
||||||
|
clamp_data->callback (sub_texture,
|
||||||
|
sub_texture_coords, mapped_meta_coords,
|
||||||
|
clamp_data->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
foreach_clamped_region (CoglMetaTexture *meta_texture,
|
||||||
|
float *tx_1,
|
||||||
|
float *ty_1,
|
||||||
|
float *tx_2,
|
||||||
|
float *ty_2,
|
||||||
|
CoglPipelineWrapMode wrap_s,
|
||||||
|
CoglPipelineWrapMode wrap_t,
|
||||||
|
CoglMetaTextureCallback callback,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
float width = cogl_texture_get_width (COGL_TEXTURE (meta_texture));
|
||||||
|
ClampData clamp_data;
|
||||||
|
|
||||||
|
/* Consider that *tx_1 may be > *tx_2 and to simplify things
|
||||||
|
* we just flip them around if that's the case and keep a note
|
||||||
|
* of the fact that they are flipped. */
|
||||||
|
if (*tx_1 > *tx_2)
|
||||||
|
{
|
||||||
|
SWAP (*tx_1, *tx_2);
|
||||||
|
clamp_data.s_flipped = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
clamp_data.s_flipped = FALSE;
|
||||||
|
|
||||||
|
/* The same goes for ty_1 and ty_2... */
|
||||||
|
if (*ty_1 > *ty_2)
|
||||||
|
{
|
||||||
|
SWAP (*ty_1, *ty_2);
|
||||||
|
clamp_data.t_flipped = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
clamp_data.t_flipped = FALSE;
|
||||||
|
|
||||||
|
clamp_data.callback = callback;
|
||||||
|
clamp_data.user_data = user_data;
|
||||||
|
|
||||||
|
if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
|
||||||
|
{
|
||||||
|
float max_s_coord;
|
||||||
|
float half_texel_width;
|
||||||
|
|
||||||
|
/* Consider that rectangle textures have non-normalized
|
||||||
|
* coordinates... */
|
||||||
|
if (cogl_is_texture_rectangle (meta_texture))
|
||||||
|
max_s_coord = width;
|
||||||
|
else
|
||||||
|
max_s_coord = 1.0;
|
||||||
|
|
||||||
|
half_texel_width = max_s_coord / (width * 2);
|
||||||
|
|
||||||
|
/* Handle any left clamped region */
|
||||||
|
if (*tx_1 < 0)
|
||||||
|
{
|
||||||
|
clamp_data.start = *tx_1;
|
||||||
|
clamp_data.end = MIN (0, *tx_2);;
|
||||||
|
cogl_meta_texture_foreach_in_region (meta_texture,
|
||||||
|
half_texel_width, *ty_1,
|
||||||
|
half_texel_width, *ty_2,
|
||||||
|
COGL_PIPELINE_WRAP_MODE_REPEAT,
|
||||||
|
wrap_t,
|
||||||
|
clamp_s_cb,
|
||||||
|
&clamp_data);
|
||||||
|
/* Have we handled everything? */
|
||||||
|
if (tx_2 <= 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* clamp tx_1 since we've handled everything with x < 0 */
|
||||||
|
*tx_1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle any right clamped region - including the corners */
|
||||||
|
if (*tx_2 > max_s_coord)
|
||||||
|
{
|
||||||
|
clamp_data.start = MAX (max_s_coord, *tx_1);
|
||||||
|
clamp_data.end = *tx_2;
|
||||||
|
cogl_meta_texture_foreach_in_region (meta_texture,
|
||||||
|
max_s_coord - half_texel_width,
|
||||||
|
*ty_1,
|
||||||
|
max_s_coord - half_texel_width,
|
||||||
|
*ty_2,
|
||||||
|
COGL_PIPELINE_WRAP_MODE_REPEAT,
|
||||||
|
wrap_t,
|
||||||
|
clamp_s_cb,
|
||||||
|
&clamp_data);
|
||||||
|
/* Have we handled everything? */
|
||||||
|
if (*tx_1 >= max_s_coord)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* clamp tx_2 since we've handled everything with x >
|
||||||
|
* max_s_coord */
|
||||||
|
*tx_2 = max_s_coord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
|
||||||
|
{
|
||||||
|
float height = cogl_texture_get_height (COGL_TEXTURE (meta_texture));
|
||||||
|
float max_t_coord;
|
||||||
|
float half_texel_height;
|
||||||
|
|
||||||
|
/* Consider that rectangle textures have non-normalized
|
||||||
|
* coordinates... */
|
||||||
|
if (cogl_is_texture_rectangle (meta_texture))
|
||||||
|
max_t_coord = height;
|
||||||
|
else
|
||||||
|
max_t_coord = 1.0;
|
||||||
|
|
||||||
|
half_texel_height = max_t_coord / (height * 2);
|
||||||
|
|
||||||
|
/* Handle any top clamped region */
|
||||||
|
if (*ty_1 < 0)
|
||||||
|
{
|
||||||
|
clamp_data.start = *ty_1;
|
||||||
|
clamp_data.end = MIN (0, *ty_2);;
|
||||||
|
cogl_meta_texture_foreach_in_region (meta_texture,
|
||||||
|
*tx_1, half_texel_height,
|
||||||
|
*tx_2, half_texel_height,
|
||||||
|
wrap_s,
|
||||||
|
COGL_PIPELINE_WRAP_MODE_REPEAT,
|
||||||
|
clamp_t_cb,
|
||||||
|
&clamp_data);
|
||||||
|
/* Have we handled everything? */
|
||||||
|
if (tx_2 <= 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* clamp ty_1 since we've handled everything with y < 0 */
|
||||||
|
*ty_1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle any bottom clamped region */
|
||||||
|
if (*ty_2 > max_t_coord)
|
||||||
|
{
|
||||||
|
clamp_data.start = MAX (max_t_coord, *ty_1);;
|
||||||
|
clamp_data.end = *ty_2;
|
||||||
|
cogl_meta_texture_foreach_in_region (meta_texture,
|
||||||
|
*tx_1,
|
||||||
|
max_t_coord - half_texel_height,
|
||||||
|
*tx_2,
|
||||||
|
max_t_coord - half_texel_height,
|
||||||
|
wrap_s,
|
||||||
|
COGL_PIPELINE_WRAP_MODE_REPEAT,
|
||||||
|
clamp_t_cb,
|
||||||
|
&clamp_data);
|
||||||
|
/* Have we handled everything? */
|
||||||
|
if (*ty_1 >= max_t_coord)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* clamp ty_2 since we've handled everything with y >
|
||||||
|
* max_t_coord */
|
||||||
|
*ty_2 = max_t_coord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clamp_data.s_flipped)
|
||||||
|
SWAP (*tx_1, *tx_2);
|
||||||
|
if (clamp_data.t_flipped)
|
||||||
|
SWAP (*ty_1, *ty_2);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct _NormalizeData
|
typedef struct _NormalizeData
|
||||||
{
|
{
|
||||||
CoglMetaTextureCallback callback;
|
CoglMetaTextureCallback callback;
|
||||||
@ -287,6 +505,32 @@ cogl_meta_texture_foreach_in_region (CoglMetaTexture *meta_texture,
|
|||||||
float height = cogl_texture_get_height (texture);
|
float height = cogl_texture_get_height (texture);
|
||||||
NormalizeData normalize_data;
|
NormalizeData normalize_data;
|
||||||
|
|
||||||
|
if (wrap_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
|
||||||
|
wrap_s = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
|
||||||
|
if (wrap_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
|
||||||
|
wrap_t = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
|
||||||
|
|
||||||
|
if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE ||
|
||||||
|
wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
|
||||||
|
{
|
||||||
|
gboolean finished = foreach_clamped_region (meta_texture,
|
||||||
|
&tx_1, &ty_1, &tx_2, &ty_2,
|
||||||
|
wrap_s, wrap_t,
|
||||||
|
callback,
|
||||||
|
user_data);
|
||||||
|
if (finished)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Since clamping has been handled we now want to normalize our
|
||||||
|
* wrap modes we se can assume from this point on we don't
|
||||||
|
* need to consider CLAMP_TO_EDGE. (NB: The spans code will
|
||||||
|
* assert that CLAMP_TO_EDGE isn't requested) */
|
||||||
|
if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
|
||||||
|
wrap_s = COGL_PIPELINE_WRAP_MODE_REPEAT;
|
||||||
|
if (wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
|
||||||
|
wrap_t = COGL_PIPELINE_WRAP_MODE_REPEAT;
|
||||||
|
}
|
||||||
|
|
||||||
/* It makes things simpler to deal with non-normalized region
|
/* It makes things simpler to deal with non-normalized region
|
||||||
* coordinates beyond this point and only re-normalize just before
|
* coordinates beyond this point and only re-normalize just before
|
||||||
* calling the user's callback... */
|
* calling the user's callback... */
|
||||||
@ -389,3 +633,4 @@ cogl_meta_texture_foreach_in_region (CoglMetaTexture *meta_texture,
|
|||||||
user_data);
|
user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef SWAP
|
||||||
|
@ -129,10 +129,8 @@ typedef void (*CoglMetaTextureCallback) (CoglTexture *sub_texture,
|
|||||||
* @ty_1: The top-left y coordinate of the region to iterate
|
* @ty_1: The top-left y coordinate of the region to iterate
|
||||||
* @tx_2: The bottom-right x coordinate of the region to iterate
|
* @tx_2: The bottom-right x coordinate of the region to iterate
|
||||||
* @ty_2: The bottom-right y coordinate of the region to iterate
|
* @ty_2: The bottom-right y coordinate of the region to iterate
|
||||||
* @wrap_x: The wrap mode for the x-axis (Only
|
* @wrap_x: The wrap mode for the x-axis
|
||||||
* %COGL_PIPELINE_WRAP_MODE_REPEAT may be passed here.)
|
* @wrap_y: The wrap mode for the y-axis
|
||||||
* @wrap_y: The wrap mode for the y-axis (Only
|
|
||||||
* %COGL_PIPELINE_WRAP_MODE_REPEAT may be passed here.)
|
|
||||||
* @callback: A #CoglMetaTextureCallback pointer to be called
|
* @callback: A #CoglMetaTextureCallback pointer to be called
|
||||||
* for each low-level texture within the specified region.
|
* for each low-level texture within the specified region.
|
||||||
* @user_data: A private pointer that is passed to @callback.
|
* @user_data: A private pointer that is passed to @callback.
|
||||||
@ -164,13 +162,6 @@ typedef void (*CoglMetaTextureCallback) (CoglTexture *sub_texture,
|
|||||||
* of the @meta_texture, @callback is called specifying how the
|
* of the @meta_texture, @callback is called specifying how the
|
||||||
* low-level texture maps to the original region.
|
* low-level texture maps to the original region.
|
||||||
*
|
*
|
||||||
* <note>Currently this interface can only be used to iterate in terms
|
|
||||||
* of %COGL_PIPELINE_WRAP_MODE_REPEAT) which means if you want to
|
|
||||||
* support %COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE for a custom
|
|
||||||
* primitive then you need to do that manually by using this interface
|
|
||||||
* to find edge textures and then stretching the edge texels out using
|
|
||||||
* geometry.</note>
|
|
||||||
*
|
|
||||||
* Since: 1.10
|
* Since: 1.10
|
||||||
* Stability: unstable
|
* Stability: unstable
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user