meta-texture: This publicly exposes CoglMetaTexture

CoglMetaTexture is an interface for dealing with high level textures
that may be comprised of one or more low-level textures internally. The
interface allows the development of primitive drawing APIs that can draw
with high-level textures (such as atlas textures) even though the
GPU doesn't natively understand these texture types.

There is currently just one function that's part of this interface:
cogl_meta_texture_foreach_in_region() which allows an application to
resolve the internal, low-level textures of a high-level texture.
cogl_rectangle() uses this API for example so that it can easily emulate
the _REPEAT wrap mode for textures that the hardware can't natively
handle repeating of.

Reviewed-by: Neil Roberts <neil@linux.intel.com>
This commit is contained in:
Robert Bragg 2011-10-08 14:13:03 +01:00
parent c11036cd13
commit 1d8fd64e1c
18 changed files with 1069 additions and 691 deletions

View File

@ -140,13 +140,15 @@ cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv,
the neighbouring glyphs are coming from the same atlas and bundle
them together into a single VBO */
_cogl_texture_foreach_sub_texture_in_region (cache_value->texture,
cache_value->tx1,
cache_value->ty1,
cache_value->tx2,
cache_value->ty2,
cogl_pango_renderer_slice_cb,
&data);
cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (cache_value->texture),
cache_value->tx1,
cache_value->ty1,
cache_value->tx2,
cache_value->ty2,
COGL_PIPELINE_WRAP_MODE_REPEAT,
COGL_PIPELINE_WRAP_MODE_REPEAT,
cogl_pango_renderer_slice_cb,
&data);
}
static void cogl_pango_renderer_finalize (GObject *object);

View File

@ -78,6 +78,7 @@ cogl_public_h = \
$(srcdir)/cogl-texture-3d.h \
$(srcdir)/cogl-texture-2d.h \
$(srcdir)/cogl-texture-2d-sliced.h \
$(srcdir)/cogl-meta-texture.h \
$(srcdir)/cogl-types.h \
$(srcdir)/cogl-vertex-buffer.h \
$(srcdir)/cogl-index-buffer.h \
@ -295,6 +296,7 @@ cogl_sources_c = \
$(srcdir)/cogl-atlas.c \
$(srcdir)/cogl-atlas-texture-private.h \
$(srcdir)/cogl-atlas-texture.c \
$(srcdir)/cogl-meta-texture.c \
$(srcdir)/cogl-blit.h \
$(srcdir)/cogl-blit.c \
$(srcdir)/cogl-spans.h \

View File

@ -225,19 +225,21 @@ _cogl_atlas_texture_foreach_sub_texture_in_region (
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
CoglMetaTextureCallback callback,
void *user_data)
{
CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
/* Forward on to the sub texture */
_cogl_texture_foreach_sub_texture_in_region (atlas_tex->sub_texture,
virtual_tx_1,
virtual_ty_1,
virtual_tx_2,
virtual_ty_2,
callback,
user_data);
cogl_meta_texture_foreach_in_region (atlas_tex->sub_texture,
virtual_tx_1,
virtual_ty_1,
virtual_tx_2,
virtual_ty_2,
COGL_PIPELINE_WRAP_MODE_REPEAT,
COGL_PIPELINE_WRAP_MODE_REPEAT,
callback,
user_data);
}
static void

391
cogl/cogl-meta-texture.c Normal file
View File

@ -0,0 +1,391 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
* Authors:
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cogl-texture.h"
#include "cogl-matrix.h"
#include "cogl-spans.h"
#include "cogl-meta-texture.h"
#include "cogl-texture-rectangle-private.h"
#include <string.h>
#include <math.h>
typedef struct _ForeachData
{
float meta_region_coords[4];
CoglPipelineWrapMode wrap_s;
CoglPipelineWrapMode wrap_t;
CoglMetaTextureCallback callback;
void *user_data;
int width;
int height;
CoglTexture *padded_textures[9];
const float *grid_slice_texture_coords;
float slice_offset_s;
float slice_offset_t;
float slice_range_s;
float slice_range_t;
} ForeachData;
static void
padded_grid_repeat_cb (CoglTexture *slice_texture,
const float *slice_texture_coords,
const float *meta_coords,
void *user_data)
{
ForeachData *data;
float mapped_coords[4];
/* Ignore padding slices for the current grid */
if (!slice_texture)
return;
data = user_data;
/* NB: the slice_texture_coords[] we get here will always be
* normalized.
*
* We now need to map the normalized slice_texture_coords[] we have
* here back to the real slice coordinates we saved in the previous
* stage...
*/
mapped_coords[0] =
slice_texture_coords[0] * data->slice_range_s + data->slice_offset_s;
mapped_coords[1] =
slice_texture_coords[1] * data->slice_range_t + data->slice_offset_t;
mapped_coords[2] =
slice_texture_coords[2] * data->slice_range_s + data->slice_offset_s;
mapped_coords[3] =
slice_texture_coords[3] * data->slice_range_t + data->slice_offset_t;
data->callback (slice_texture,
mapped_coords, meta_coords, data->user_data);
}
static int
setup_padded_spans (CoglSpan *spans,
float start,
float end,
float range,
int *real_index)
{
int span_index = 0;
if (start > 0)
{
spans[0].start = 0;
spans[0].size = start;
spans[0].waste = 0;
span_index++;
spans[1].start = spans[0].size;
}
else
spans[span_index].start = 0;
spans[span_index].size = end - start;
spans[span_index].waste = 0;
*real_index = span_index;
span_index++;
if (end < range)
{
spans[span_index].start =
spans[span_index - 1].start + spans[span_index - 1].size;
spans[span_index].size = range - end;
spans[span_index].waste = 0;
span_index++;
}
return span_index;
}
/* This handles each sub-texture within the range [0,1] of our
* original meta texture and repeats each one separately across the
* users requested virtual texture coordinates.
*
* A notable advantage of this approach is that we will batch
* together callbacks corresponding to the same underlying slice
* together.
*/
void
create_grid_and_repeat_cb (CoglTexture *slice_texture,
const float *slice_texture_coords,
const float *meta_coords,
void *user_data)
{
ForeachData *data = user_data;
CoglSpan x_spans[3];
int n_x_spans;
int x_real_index;
CoglSpan y_spans[3];
int n_y_spans;
int y_real_index;
/* NB: This callback is called for each slice of the meta-texture
* in the range [0,1].
*
* We define a "padded grid" for each slice of the meta-texture in
* the range [0,1]. The x axis and y axis grid lines are defined
* using CoglSpans.
*
* The padded grid maps over the meta-texture coordinates in the
* range [0,1] but only contains one valid cell that corresponds to
* current slice being iterated and all the surrounding cells just
* provide padding.
*
* Once we've defined our padded grid we then repeat that across
* the user's original region, calling their callback whenever
* we see our current slice - ignoring padding.
*
* NB: we can assume meta_coords[] are normalized at this point
* since TextureRectangles aren't iterated with this code-path.
*
* NB: spans are always defined using non-normalized coordinates
*/
n_x_spans = setup_padded_spans (x_spans,
meta_coords[0] * data->width,
meta_coords[2] * data->width,
data->width,
&x_real_index);
n_y_spans = setup_padded_spans (y_spans,
meta_coords[1] * data->height,
meta_coords[3] * data->height,
data->height,
&y_real_index);
data->padded_textures[n_y_spans * y_real_index + x_real_index] =
slice_texture;
/* Our callback is going to be passed normalized slice texture
* coordinates, and we will need to map the range [0,1] to the real
* slice_texture_coords we have here... */
data->grid_slice_texture_coords = slice_texture_coords;
data->slice_range_s = fabs (data->grid_slice_texture_coords[2] -
data->grid_slice_texture_coords[0]);
data->slice_range_t = fabs (data->grid_slice_texture_coords[3] -
data->grid_slice_texture_coords[1]);
data->slice_offset_s = MIN (data->grid_slice_texture_coords[0],
data->grid_slice_texture_coords[2]);
data->slice_offset_t = MIN (data->grid_slice_texture_coords[1],
data->grid_slice_texture_coords[3]);
/* Now actually iterate the region the user originally requested
* using the current padded grid */
_cogl_texture_spans_foreach_in_region (x_spans,
n_x_spans,
y_spans,
n_y_spans,
data->padded_textures,
data->meta_region_coords,
data->width,
data->height,
data->wrap_s,
data->wrap_t,
padded_grid_repeat_cb,
data);
/* Clear the padded_textures ready for the next iteration */
data->padded_textures[n_y_spans * y_real_index + x_real_index] = NULL;
}
typedef struct _NormalizeData
{
CoglMetaTextureCallback callback;
void *user_data;
float s_normalize_factor;
float t_normalize_factor;
} NormalizeData;
static void
normalize_meta_coords_cb (CoglTexture *slice_texture,
const float *slice_coords,
const float *meta_coords,
void *user_data)
{
NormalizeData *data = user_data;
float normalized_meta_coords[4] = {
meta_coords[0] * data->s_normalize_factor,
meta_coords[1] * data->t_normalize_factor,
meta_coords[2] * data->s_normalize_factor,
meta_coords[3] * data->t_normalize_factor
};
data->callback (slice_texture,
slice_coords, normalized_meta_coords,
data->user_data);
}
typedef struct _UnNormalizeData
{
CoglMetaTextureCallback callback;
void *user_data;
float width;
float height;
} UnNormalizeData;
static void
un_normalize_slice_coords_cb (CoglTexture *slice_texture,
const float *slice_coords,
const float *meta_coords,
void *user_data)
{
UnNormalizeData *data = user_data;
float un_normalized_slice_coords[4] = {
slice_coords[0] * data->width,
slice_coords[1] * data->height,
slice_coords[2] * data->width,
slice_coords[3] * data->height
};
data->callback (slice_texture,
un_normalized_slice_coords, meta_coords,
data->user_data);
}
void
cogl_meta_texture_foreach_in_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)
{
CoglTexture *texture = COGL_TEXTURE (meta_texture);
float width = cogl_texture_get_width (texture);
float height = cogl_texture_get_height (texture);
NormalizeData normalize_data;
/* It makes things simpler to deal with non-normalized region
* coordinates beyond this point and only re-normalize just before
* calling the user's callback... */
if (!_cogl_is_texture_rectangle (COGL_TEXTURE (meta_texture)))
{
normalize_data.callback = callback;
normalize_data.user_data = user_data;
normalize_data.s_normalize_factor = 1.0f / width;
normalize_data.t_normalize_factor = 1.0f / height;
callback = normalize_meta_coords_cb;
user_data = &normalize_data;
tx_1 *= width;
ty_1 *= height;
tx_2 *= width;
ty_2 *= height;
}
/* XXX: at some point this wont be routed through the CoglTexture
* vtable, instead there will be a separate CoglMetaTexture
* interface vtable. */
if (texture->vtable->foreach_sub_texture_in_region)
{
ForeachData data;
data.meta_region_coords[0] = tx_1;
data.meta_region_coords[1] = ty_1;
data.meta_region_coords[2] = tx_2;
data.meta_region_coords[3] = ty_2;
data.wrap_s = wrap_s;
data.wrap_t = wrap_t;
data.callback = callback;
data.user_data = user_data;
data.width = width;
data.height = height;
memset (data.padded_textures, 0, sizeof (data.padded_textures));
/*
* 1) We iterate all the slices of the meta-texture only within
* the range [0,1].
*
* 2) We define a "padded grid" for each slice of the
* meta-texture in the range [0,1].
*
* The padded grid maps over the meta-texture coordinates in
* the range [0,1] but only contains one valid cell that
* corresponds to current slice being iterated and all the
* surrounding cells just provide padding.
*
* 3) Once we've defined our padded grid we then repeat that
* across the user's original region, calling their callback
* whenever we see our current slice - ignoring padding.
*
* A notable benefit of this design is that repeating a texture
* made of multiple slices will result in us repeating each
* slice in-turn so the user gets repeat callbacks for the same
* texture batched together. For manual emulation of texture
* repeats done by drawing geometry this makes it more likely
* that we can batch geometry.
*/
texture->vtable->foreach_sub_texture_in_region (texture,
0, 0, 1, 1,
create_grid_and_repeat_cb,
&data);
}
else
{
CoglSpan x_span = { 0, width, 0 };
CoglSpan y_span = { 0, height, 0 };
float meta_region_coords[4] = { tx_1, ty_1, tx_2, ty_2 };
UnNormalizeData un_normalize_data;
/* If we are dealing with a CoglTextureRectangle then we need a shim
* callback that un_normalizes the slice coordinates we get from
* _cogl_texture_spans_foreach_in_region before passing them to
* the user's callback. */
if (_cogl_is_texture_rectangle (meta_texture))
{
un_normalize_data.callback = callback;
un_normalize_data.user_data = user_data;
un_normalize_data.width = width;
un_normalize_data.height = height;
callback = un_normalize_slice_coords_cb;
user_data = &un_normalize_data;
}
_cogl_texture_spans_foreach_in_region (&x_span, 1,
&y_span, 1,
&texture,
meta_region_coords,
width,
height,
wrap_s,
wrap_t,
callback,
user_data);
}
}

190
cogl/cogl-meta-texture.h Normal file
View File

@ -0,0 +1,190 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
*/
#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <cogl/cogl.h> can be included directly."
#endif
#ifndef __COGL_META_TEXTURE_H__
#define __COGL_META_TEXTURE_H__
#include <cogl/cogl-pipeline-layer-state.h>
#include <glib.h>
G_BEGIN_DECLS
/**
* SECTION:cogl-meta-texture
* @short_description: Interface for high-level textures built from
* low-level textures like #CoglTexture2D and
* #CoglTexture3D.
*
* Cogl helps to make it easy to deal with high level textures such
* as #CoglAtlasTexture<!-- -->s, #CoglSubTexture<!-- -->s,
* #CoglTexturePixmapX11 textures and #CoglTexture2DSliced textures
* consistently.
*
* A #CoglMetaTexture is a texture that might internally be
* represented by one or more low-level #CoglTexture<!-- -->s
* such as #CoglTexture2D or #CoglTexture3D. These low-level textures
* are the only ones that a GPU really understands but because
* applications often want more high-level texture abstractions
* (such as storing multiple textures inside one larger "atlas"
* texture) it's desirable to be able to deal with these
* using a common interface.
*
* For example the GPU is not able to automatically handle repeating a
* texture that is part of a larger atlas texture but if you use
* %COGL_PIPELINE_WRAP_MODE_REPEAT with an atlas texture when drawing
* with cogl_rectangle() you should see that it "Just Works™" - at
* least if you don't use multi-texturing. The reason this works is
* because cogl_rectangle() internally understands the #CoglMetaTexture
* interface and is able to manually resolve the low-level textures
* using this interface and by making multiple draw calls it can
* emulate the texture repeat modes.
*
* Cogl doesn't aim to pretend that meta-textures are just like real
* textures because it would get extremely complex to try and emulate
* low-level GPU semantics transparently for these textures. The low
* level drawing APIs of Cogl, such as cogl_draw_attributes() don't
* actually know anything about the #CoglMetaTexture interface and its
* the developer's responsibility to resolve all textures referenced by
* a #CoglPipeline to low-level textures before drawing.
*
* If you want to develop custom primitive APIs like cogl_rectangle()
* and you want to support drawing with #CoglAtlasTexture<!-- -->s
* or #CoglSubTexture<!-- -->s for example, then you will need to use
* this #CoglMetaTexture interface to be able to resolve high-level
* textures into low-level textures before drawing with Cogl's
* low-level drawing APIs such as cogl_draw_attributes().
*
* <note>Most developers won't need to use this interface directly
* but still it is worth understanding the distinction between
* low-level and meta textures because you may find other references
* in the documentation that detail limitations of using
* meta-textures.</note>
*/
typedef struct _CoglMetaTexture CoglMetaTexture;
#define COGL_META_TEXTURE(X) ((CoglMetaTexture *)X)
/**
* CoglMetaTextureCallback:
* @sub_texture: A low-level #CoglTexture making up part of a
* #CoglMetaTexture.
* @sub_texture_coords: A float 4-tuple ordered like
* (tx1,ty1,tx2,ty2) defining what region of the
* current @sub_texture maps to a sub-region of a
* #CoglMetaTexture. (tx1,ty1) is the top-left
* sub-region coordinate and (tx2,ty2) is the
* bottom-right. These are low-level texture
* coordinates.
* @meta_coords: A float 4-tuple ordered like (tx1,ty1,tx2,ty2)
* defining what sub-region of a #CoglMetaTexture this
* low-level @sub_texture maps too. (tx1,ty1) is
* the top-left sub-region coordinate and (tx2,ty2) is
* the bottom-right. These are high-level meta-texture
* coordinates.
* @user_data: A private pointer passed to
* cogl_meta_texture_foreach_in_region().
*
* A callback used with cogl_meta_texture_foreach_in_region() to
* retrieve details of all the low-level #CoglTexture<!-- -->s that
* make up a given #CoglMetaTexture.
*
* Since: 1.10
* Stability: unstable
*/
typedef void (*CoglMetaTextureCallback) (CoglTexture *sub_texture,
const float *sub_texture_coords,
const float *meta_coords,
void *user_data);
/**
* cogl_meta_texture_foreach_in_region:
* @meta_texture: An object implementing the #CoglMetaTexture
* interface.
* @tx_1: The top-left x 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
* @ty_2: The bottom-right y coordinate of the region to iterate
* @wrap_x: The wrap mode for the x-axis (Only
* %COGL_PIPELINE_WRAP_MODE_REPEAT may be passed here.)
* @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
* for each low-level texture within the specified region.
* @user_data: A private pointer that is passed to @callback.
*
* Allows you to manually iterate the low-level textures that define a
* given region of a high-level #CoglMetaTexture.
*
* For example cogl_texture_2d_sliced_new_with_size() can be used to
* create a meta texture that may slice a large image into multiple,
* smaller power-of-two sized textures. These high level textures are
* not directly understood by a GPU and so this API must be used to
* manually resolve the underlying textures for drawing.
*
* All high level textures (#CoglAtlasTexture, #CoglSubTexture,
* #CoglTexturePixmapX11, and #CoglTexture2DSliced) can be handled
* consistently using this interface which greately simplifies
* implementing primitives that support all texture types.
*
* For example if you use the cogl_rectangle() API then Cogl will
* internally use this API to resolve the low level textures of any
* meta textures you have associated with CoglPipeline layers.
*
* <note>The low level drawing APIs such as cogl_draw_attributes()
* don't understand the #CoglMetaTexture interface and so it is your
* responsibility to use this API to resolve all CoglPipeline
* textures into low-level textures before drawing.</note>
*
* For each low-level texture that makes up part of the given region
* of the @meta_texture, @callback is called specifying how the
* 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
* Stability: unstable
*/
void
cogl_meta_texture_foreach_in_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);
G_END_DECLS
#endif /* __COGL_META_TEXTURE_H__ */

View File

@ -37,6 +37,7 @@
#include "cogl-framebuffer-private.h"
#include "cogl-attribute-private.h"
#include "cogl-private.h"
#include "cogl-meta-texture.h"
#include <string.h>
#include <math.h>
@ -139,6 +140,8 @@ validate_first_layer_cb (CoglPipeline *pipeline,
ValidateFirstLayerState *state = user_data;
CoglPipelineWrapMode clamp_to_edge =
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
CoglPipelineWrapMode wrap_s;
CoglPipelineWrapMode wrap_t;
/* We can't use hardware repeat so we need to set clamp to edge
* otherwise it might pull in edge pixels from the other side. By
@ -184,15 +187,16 @@ validate_first_layer_cb (CoglPipeline *pipeline,
*/
/* TODO: support multitexturing */
static void
_cogl_texture_quad_multiple_primitives (CoglTexture *texture,
_cogl_texture_quad_multiple_primitives (CoglTexture *texture,
CoglPipeline *pipeline,
gboolean clamp_s,
gboolean clamp_t,
const float *position,
float tx_1,
float ty_1,
float tx_2,
float ty_2)
int layer_index,
gboolean check_clamp_s,
gboolean check_clamp_t,
const float *position,
float tx_1,
float ty_1,
float tx_2,
float ty_2)
{
TextureSlicedQuadState state;
gboolean tex_virtual_flipped_x;
@ -200,12 +204,17 @@ _cogl_texture_quad_multiple_primitives (CoglTexture *texture,
gboolean quad_flipped_x;
gboolean quad_flipped_y;
ValidateFirstLayerState validate_first_layer_state;
CoglPipelineWrapMode wrap_s, wrap_t;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
wrap_s = cogl_pipeline_get_layer_wrap_mode_s (pipeline, layer_index);
wrap_t = cogl_pipeline_get_layer_wrap_mode_t (pipeline, layer_index);
/* If the wrap mode is clamp to edge then we'll recursively draw the
stretched part and replace the coordinates */
if (clamp_s && tx_1 != tx_2)
if (check_clamp_s &&
wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE && tx_1 != tx_2)
{
float *replacement_position = g_newa (float, 4);
float old_tx_1 = tx_1, old_tx_2 = tx_2;
@ -225,7 +234,8 @@ _cogl_texture_quad_multiple_primitives (CoglTexture *texture,
(tx_1 - old_tx_1) / (old_tx_2 - old_tx_1)),
position[3] };
_cogl_texture_quad_multiple_primitives (texture, pipeline,
FALSE, clamp_t,
layer_index,
FALSE, TRUE,
tmp_position,
tx_1, ty_1, tx_1, ty_2);
replacement_position[0] = tmp_position[2];
@ -240,7 +250,8 @@ _cogl_texture_quad_multiple_primitives (CoglTexture *texture,
(tx_2 - old_tx_1) / (old_tx_2 - old_tx_1)),
position[1], position[2], position[3] };
_cogl_texture_quad_multiple_primitives (texture, pipeline,
FALSE, clamp_t,
layer_index,
FALSE, TRUE,
tmp_position,
tx_2, ty_1, tx_2, ty_2);
replacement_position[2] = tmp_position[0];
@ -253,7 +264,8 @@ _cogl_texture_quad_multiple_primitives (CoglTexture *texture,
position = replacement_position;
}
if (clamp_t && ty_1 != ty_2)
if (check_clamp_t &&
wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE && ty_1 != ty_2)
{
float *replacement_position = g_newa (float, 4);
float old_ty_1 = ty_1, old_ty_2 = ty_2;
@ -272,7 +284,8 @@ _cogl_texture_quad_multiple_primitives (CoglTexture *texture,
(position[3] - position[1]) *
(ty_1 - old_ty_1) / (old_ty_2 - old_ty_1)) };
_cogl_texture_quad_multiple_primitives (texture, pipeline,
clamp_s, FALSE,
layer_index,
TRUE, FALSE,
tmp_position,
tx_1, ty_1, tx_2, ty_1);
replacement_position[1] = tmp_position[3];
@ -288,7 +301,8 @@ _cogl_texture_quad_multiple_primitives (CoglTexture *texture,
(ty_2 - old_ty_1) / (old_ty_2 - old_ty_1)),
position[2], position[3] };
_cogl_texture_quad_multiple_primitives (texture, pipeline,
clamp_s, FALSE,
layer_index,
TRUE, FALSE,
tmp_position,
tx_1, ty_2, tx_2, ty_2);
replacement_position[3] = tmp_position[1];
@ -354,10 +368,23 @@ _cogl_texture_quad_multiple_primitives (CoglTexture *texture,
state.v_to_q_scale_x = fabs (state.quad_len_x / (tx_2 - tx_1));
state.v_to_q_scale_y = fabs (state.quad_len_y / (ty_2 - ty_1));
_cogl_texture_foreach_sub_texture_in_region (texture,
tx_1, ty_1, tx_2, ty_2,
log_quad_sub_textures_cb,
&state);
/* cogl_meta_texture_foreach_in_region only allows WRAP_MODE_REPEAT.
* If CLAMP_TO_EDGE is in use then we have already dealt with
* emulation for that and we can just pass WRAP_MODE_REPEAT here...
*/
if (wrap_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC ||
wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
wrap_s = COGL_PIPELINE_WRAP_MODE_REPEAT;
if (wrap_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC ||
wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
wrap_t = COGL_PIPELINE_WRAP_MODE_REPEAT;
cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (texture),
tx_1, ty_1, tx_2, ty_2,
wrap_s,
wrap_t,
log_quad_sub_textures_cb,
&state);
if (validate_first_layer_state.override_pipeline)
cogl_object_unref (validate_first_layer_state.override_pipeline);
@ -760,7 +787,6 @@ _cogl_rectangles_with_multitexture_coords (
CoglTexture *texture;
const float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0};
const float *tex_coords;
gboolean clamp_s, clamp_t;
if (!state.all_use_sliced_quad_fallback)
{
@ -788,18 +814,12 @@ _cogl_rectangles_with_multitexture_coords (
else
tex_coords = default_tex_coords;
clamp_s = (cogl_pipeline_get_layer_wrap_mode_s (pipeline,
state.first_layer) ==
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
clamp_t = (cogl_pipeline_get_layer_wrap_mode_t (pipeline,
state.first_layer) ==
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
COGL_NOTE (DRAW, "Drawing Tex Quad (Multi-Prim Mode)");
_cogl_texture_quad_multiple_primitives (texture,
pipeline,
clamp_s, clamp_t,
state.first_layer,
TRUE, TRUE,
rects[i].position,
tex_coords[0],
tex_coords[1],

View File

@ -35,7 +35,7 @@ void
_cogl_span_iter_update (CoglSpanIter *iter)
{
/* Pick current span */
iter->span = &g_array_index (iter->array, CoglSpan, iter->index);
iter->span = &iter->spans[iter->index];
/* Offset next position by span size */
iter->next_pos = iter->pos + iter->span->size - iter->span->waste;
@ -66,17 +66,24 @@ _cogl_span_iter_update (CoglSpanIter *iter)
void
_cogl_span_iter_begin (CoglSpanIter *iter,
GArray *spans,
float normalize_factor,
float cover_start,
float cover_end)
const CoglSpan *spans,
int n_spans,
float normalize_factor,
float cover_start,
float cover_end,
CoglPipelineWrapMode wrap_mode)
{
float cover_start_normalized;
/* XXX: If CLAMP_TO_EDGE needs to be emulated then it needs to be
* done at a higher level than here... */
g_return_if_fail (wrap_mode == COGL_PIPELINE_WRAP_MODE_REPEAT);
iter->index = 0;
iter->span = NULL;
iter->array = spans;
iter->spans = spans;
iter->n_spans = n_spans;
/* We always iterate in a positive direction from the origin. If
* iter->flipped == TRUE that means whoever is using this API should
@ -100,6 +107,8 @@ _cogl_span_iter_begin (CoglSpanIter *iter,
cover_start_normalized = cover_start / normalize_factor;
iter->origin = floorf (cover_start_normalized) * normalize_factor;
iter->wrap_mode = wrap_mode;
iter->cover_start = cover_start;
iter->cover_end = cover_end;
iter->pos = iter->origin;
@ -117,8 +126,7 @@ _cogl_span_iter_next (CoglSpanIter *iter)
/* Move current position */
iter->pos = iter->next_pos;
/* Pick next slice (wrap when last reached) */
iter->index = (iter->index + 1) % iter->array->len;
iter->index = (iter->index + 1) % iter->n_spans;
/* Update intersection */
_cogl_span_iter_update (iter);

View File

@ -25,6 +25,7 @@
#define __COGL_SPANS_PRIVATE_H
#include "cogl-handle.h"
#include "cogl-pipeline-layer-state.h"
typedef struct _CoglSpan
{
@ -35,18 +36,20 @@ typedef struct _CoglSpan
typedef struct _CoglSpanIter
{
int index;
GArray *array;
CoglSpan *span;
float pos;
float next_pos;
float origin;
float cover_start;
float cover_end;
float intersect_start;
float intersect_end;
gboolean intersects;
gboolean flipped;
int index;
const CoglSpan *spans;
int n_spans;
const CoglSpan *span;
float pos;
float next_pos;
float origin;
float cover_start;
float cover_end;
float intersect_start;
float intersect_end;
gboolean intersects;
gboolean flipped;
CoglPipelineWrapMode wrap_mode;
} CoglSpanIter;
void
@ -54,10 +57,12 @@ _cogl_span_iter_update (CoglSpanIter *iter);
void
_cogl_span_iter_begin (CoglSpanIter *iter,
GArray *spans,
float normalize_factor,
float cover_start,
float cover_end);
const CoglSpan *spans,
int n_spans,
float normalize_factor,
float cover_start,
float cover_end,
CoglPipelineWrapMode wrap_mode);
void
_cogl_span_iter_next (CoglSpanIter *iter);

View File

@ -36,6 +36,7 @@
#include "cogl-context-private.h"
#include "cogl-handle.h"
#include "cogl-texture-driver.h"
#include "cogl-texture-rectangle-private.h"
#include <string.h>
#include <math.h>
@ -47,157 +48,90 @@ COGL_TEXTURE_INTERNAL_DEFINE (SubTexture, sub_texture);
static const CoglTextureVtable cogl_sub_texture_vtable;
static void
_cogl_sub_texture_map_range (float *t1, float *t2,
int sub_offset,
int sub_size,
int full_size)
_cogl_sub_texture_unmap_quad (CoglSubTexture *sub_tex,
float *coords)
{
float 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)
/* NB: coords[] come in as non-normalized if sub_tex->full_texture
* is a CoglTextureRectangle otherwhise they are normalized. The
* coordinates we write out though must always be normalized.
*
* NB: sub_tex->sub_x/y/width/height are in non-normalized
* coordinates.
*/
if (_cogl_is_texture_rectangle (sub_tex->full_texture))
{
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;
}
coords[0] = (coords[0] - sub_tex->sub_x) / sub_tex->sub_width;
coords[1] = (coords[1] - sub_tex->sub_y) / sub_tex->sub_height;
coords[2] = (coords[2] - sub_tex->sub_x) / sub_tex->sub_width;
coords[3] = (coords[3] - sub_tex->sub_y) / sub_tex->sub_height;
}
else
{
if (t1_frac == 0.0f)
{
t1_frac = 1.0f;
t1_int -= 1.0f;
}
float width = cogl_texture_get_width (sub_tex->full_texture);
float height = cogl_texture_get_height (sub_tex->full_texture);
coords[0] = (coords[0] * width - sub_tex->sub_x) / sub_tex->sub_width;
coords[1] = (coords[1] * height - sub_tex->sub_y) / sub_tex->sub_height;
coords[2] = (coords[2] * width - sub_tex->sub_x) / sub_tex->sub_width;
coords[3] = (coords[3] * height - sub_tex->sub_y) / sub_tex->sub_height;
}
/* 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_quad (CoglSubTexture *sub_tex,
float *coords)
{
unsigned int full_width = cogl_texture_get_width (sub_tex->full_texture);
unsigned int full_height = cogl_texture_get_height (sub_tex->full_texture);
/* NB: coords[] always come in as normalized coordinates but may go
* out as non-normalized if sub_tex->full_texture is a
* CoglTextureRectangle.
*
* NB: sub_tex->sub_x/y/width/height are in non-normalized
* coordinates.
*/
_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 float
_cogl_sub_texture_unmap_coord (float t,
int sub_offset,
int sub_size,
int full_size)
{
float frac_part, int_part;
/* Convert the fractional part leaving the integer part in tact */
frac_part = modff (t, &int_part);
if (cogl_util_float_signbit (frac_part))
frac_part = ((1.0f + frac_part) * full_size -
sub_offset - sub_size) / sub_size;
if (_cogl_is_texture_rectangle (sub_tex->full_texture))
{
coords[0] = coords[0] * sub_tex->sub_width + sub_tex->sub_x;
coords[1] = coords[1] * sub_tex->sub_height + sub_tex->sub_y;
coords[2] = coords[2] * sub_tex->sub_width + sub_tex->sub_x;
coords[3] = coords[3] * sub_tex->sub_height + sub_tex->sub_y;
}
else
frac_part = (frac_part * full_size - sub_offset) / sub_size;
return frac_part + int_part;
}
static void
_cogl_sub_texture_unmap_coords (CoglSubTexture *sub_tex,
float *s,
float *t)
{
unsigned int full_width = cogl_texture_get_width (sub_tex->full_texture);
unsigned int full_height = cogl_texture_get_height (sub_tex->full_texture);
*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);
{
float width = cogl_texture_get_width (sub_tex->full_texture);
float height = cogl_texture_get_height (sub_tex->full_texture);
coords[0] = (coords[0] * sub_tex->sub_width + sub_tex->sub_x) / width;
coords[1] = (coords[1] * sub_tex->sub_height + sub_tex->sub_y) / height;
coords[2] = (coords[2] * sub_tex->sub_width + sub_tex->sub_x) / width;
coords[3] = (coords[3] * sub_tex->sub_height + sub_tex->sub_y) / height;
}
}
typedef struct _CoglSubTextureForeachData
{
CoglSubTexture *sub_tex;
CoglTextureSliceCallback callback;
CoglMetaTextureCallback callback;
void *user_data;
} CoglSubTextureForeachData;
static void
_cogl_sub_texture_foreach_cb (CoglTexture *texture,
const float *slice_coords,
const float *full_virtual_coords,
void *user_data)
unmap_coords_cb (CoglTexture *slice_texture,
const float *slice_texture_coords,
const float *meta_coords,
void *user_data)
{
CoglSubTextureForeachData *data = user_data;
float virtual_coords[4];
float unmapped_coords[4];
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_coords (data->sub_tex,
&virtual_coords[0],
&virtual_coords[1]);
_cogl_sub_texture_unmap_coords (data->sub_tex,
&virtual_coords[2],
&virtual_coords[3]);
memcpy (unmapped_coords, meta_coords, sizeof (unmapped_coords));
data->callback (texture,
slice_coords, virtual_coords,
_cogl_sub_texture_unmap_quad (data->sub_tex, unmapped_coords);
data->callback (slice_texture,
slice_texture_coords,
unmapped_coords,
data->user_data);
}
static void
_cogl_sub_texture_manual_repeat_cb (const float *coords,
void *user_data)
{
CoglSubTextureForeachData *data = user_data;
float mapped_coords[4];
memcpy (mapped_coords, coords, sizeof (mapped_coords));
_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],
mapped_coords[1],
mapped_coords[2],
mapped_coords[3],
_cogl_sub_texture_foreach_cb,
user_data);
}
static void
_cogl_sub_texture_foreach_sub_texture_in_region (
CoglTexture *tex,
@ -205,20 +139,46 @@ _cogl_sub_texture_foreach_sub_texture_in_region (
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
CoglMetaTextureCallback callback,
void *user_data)
{
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
CoglSubTextureForeachData data;
CoglTexture *full_texture = sub_tex->full_texture;
float mapped_coords[4] =
{ virtual_tx_1, virtual_ty_1, virtual_tx_2, virtual_ty_2};
float virtual_coords[4] =
{ virtual_tx_1, virtual_ty_1, virtual_tx_2, virtual_ty_2};
data.sub_tex = sub_tex;
data.callback = callback;
data.user_data = user_data;
/* map the virtual coordinates to ->full_texture coordinates */
_cogl_sub_texture_map_quad (sub_tex, mapped_coords);
_cogl_texture_iterate_manual_repeats (_cogl_sub_texture_manual_repeat_cb,
virtual_tx_1, virtual_ty_1,
virtual_tx_2, virtual_ty_2,
&data);
/* TODO: Add something like cogl_is_low_level_texture() */
if (cogl_is_texture_2d (full_texture) ||
_cogl_is_texture_rectangle (full_texture))
{
callback (sub_tex->full_texture,
mapped_coords,
virtual_coords,
user_data);
}
else
{
CoglSubTextureForeachData data;
data.sub_tex = sub_tex;
data.callback = callback;
data.user_data = user_data;
cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (full_texture),
mapped_coords[0],
mapped_coords[1],
mapped_coords[2],
mapped_coords[3],
COGL_PIPELINE_WRAP_MODE_REPEAT,
COGL_PIPELINE_WRAP_MODE_REPEAT,
unmap_coords_cb,
&data);
}
}
static void

View File

@ -56,14 +56,33 @@ COGL_TEXTURE_DEFINE (Texture2DSliced, texture_2d_sliced);
static const CoglTextureVtable cogl_texture_2d_sliced_vtable;
/* To differentiate between texture coordinates of a specific, real, slice
* texture and the texture coordinates of the composite, sliced texture, the
* coordinates of the sliced texture are called "virtual" coordinates and the
* coordinates of slices are called "slice" coordinates. */
/* This function lets you iterate all the slices that lie within the given
* virtual coordinates of the parent sliced texture. */
/* Note: no guarantee is given about the order in which the slices will be
* visited */
typedef struct _ForeachData
{
CoglMetaTextureCallback callback;
void *user_data;
float x_normalize_factor;
float y_normalize_factor;
} ForeachData;
static void
re_normalize_sub_texture_coords_cb (CoglTexture *sub_texture,
const float *sub_texture_coords,
const float *meta_coords,
void *user_data)
{
ForeachData *data = user_data;
float re_normalized_coords[4] =
{
sub_texture_coords[0] * data->x_normalize_factor,
sub_texture_coords[1] * data->y_normalize_factor,
sub_texture_coords[2] * data->x_normalize_factor,
sub_texture_coords[3] * data->y_normalize_factor
};
data->callback (sub_texture, re_normalized_coords, meta_coords,
data->user_data);
}
static void
_cogl_texture_2d_sliced_foreach_sub_texture_in_region (
CoglTexture *tex,
@ -71,103 +90,44 @@ _cogl_texture_2d_sliced_foreach_sub_texture_in_region (
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
CoglMetaTextureCallback callback,
void *user_data)
{
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
float width = tex_2ds->width;
float height = tex_2ds->height;
CoglSpanIter iter_x;
CoglSpanIter iter_y;
float slice_coords[4];
CoglSpan *x_spans = (CoglSpan *)tex_2ds->slice_x_spans->data;
CoglSpan *y_spans = (CoglSpan *)tex_2ds->slice_y_spans->data;
CoglTexture **textures = (CoglTexture **)tex_2ds->slice_textures->data;
float un_normalized_coords[4];
ForeachData data;
/* Slice spans are stored in denormalized coordinates, and this is what
* the _cogl_span_iter_* funcs expect to be given, so we scale the given
* virtual coordinates by the texture size to denormalize.
/* NB: its convenient for us to store non-normalized coordinates in
* our CoglSpans but that means we need to un-normalize the incoming
* virtual coordinates and make sure we re-normalize the coordinates
* before calling the given callback.
*/
/* XXX: I wonder if it's worth changing how we store spans so we can avoid
* the need to denormalize here */
virtual_tx_1 *= width;
virtual_ty_1 *= height;
virtual_tx_2 *= width;
virtual_ty_2 *= height;
/* Iterate the y axis of the virtual rectangle */
for (_cogl_span_iter_begin (&iter_y,
tex_2ds->slice_y_spans,
height,
virtual_ty_1,
virtual_ty_2);
!_cogl_span_iter_end (&iter_y);
_cogl_span_iter_next (&iter_y))
{
if (iter_y.flipped)
{
slice_coords[1] = iter_y.intersect_end;
slice_coords[3] = iter_y.intersect_start;
}
else
{
slice_coords[1] = iter_y.intersect_start;
slice_coords[3] = iter_y.intersect_end;
}
data.callback = callback;
data.user_data = user_data;
data.x_normalize_factor = 1.0f / tex_2ds->width;
data.y_normalize_factor = 1.0f / tex_2ds->height;
/* Localize slice texture coordinates */
slice_coords[1] -= iter_y.pos;
slice_coords[3] -= iter_y.pos;
un_normalized_coords[0] = virtual_tx_1 * data.x_normalize_factor;
un_normalized_coords[1] = virtual_ty_1 * data.y_normalize_factor;
un_normalized_coords[2] = virtual_tx_2 * data.x_normalize_factor;
un_normalized_coords[3] = virtual_ty_2 * data.y_normalize_factor;
/* Normalize slice texture coordinates */
slice_coords[1] /= iter_y.span->size;
slice_coords[3] /= iter_y.span->size;
/* Iterate the x axis of the virtual rectangle */
for (_cogl_span_iter_begin (&iter_x,
tex_2ds->slice_x_spans,
width,
virtual_tx_1,
virtual_tx_2);
!_cogl_span_iter_end (&iter_x);
_cogl_span_iter_next (&iter_x))
{
CoglTexture2D *slice_tex;
float normalized_virtual_coords[4];
if (iter_x.flipped)
{
slice_coords[0] = iter_x.intersect_end;
slice_coords[2] = iter_x.intersect_start;
}
else
{
slice_coords[0] = iter_x.intersect_start;
slice_coords[2] = iter_x.intersect_end;
}
/* Localize slice texture coordinates */
slice_coords[0] -= iter_x.pos;
slice_coords[2] -= iter_x.pos;
/* Normalize slice texture coordinates */
slice_coords[0] /= iter_x.span->size;
slice_coords[2] /= iter_x.span->size;
/* Pluck out the cogl texture for this slice */
slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *,
iter_y.index *
tex_2ds->slice_x_spans->len +
iter_x.index);
normalized_virtual_coords[0] = iter_x.intersect_start / width;
normalized_virtual_coords[1] = iter_y.intersect_start / height;
normalized_virtual_coords[2] = iter_x.intersect_end / width;
normalized_virtual_coords[3] = iter_y.intersect_end / height;
callback (COGL_TEXTURE (slice_tex),
slice_coords,
normalized_virtual_coords,
user_data);
}
}
_cogl_texture_spans_foreach_in_region (x_spans,
tex_2ds->slice_x_spans->len,
y_spans,
tex_2ds->slice_y_spans->len,
textures,
un_normalized_coords,
1, /* x_normalize_factor */
1, /* y_normalize_factor */
COGL_PIPELINE_WRAP_MODE_REPEAT,
COGL_PIPELINE_WRAP_MODE_REPEAT,
re_normalize_sub_texture_coords_cb,
&data);
}
static guint8 *
@ -455,10 +415,12 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
/* Iterate vertical spans */
for (source_y = src_y,
_cogl_span_iter_begin (&y_iter,
tex_2ds->slice_y_spans,
(CoglSpan *)tex_2ds->slice_y_spans->data,
tex_2ds->slice_y_spans->len,
tex_2ds->height,
dst_y,
dst_y + height);
dst_y + height,
COGL_PIPELINE_WRAP_MODE_REPEAT);
!_cogl_span_iter_end (&y_iter);
@ -471,10 +433,12 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
/* Iterate horizontal spans */
for (source_x = src_x,
_cogl_span_iter_begin (&x_iter,
tex_2ds->slice_x_spans,
(CoglSpan *)tex_2ds->slice_x_spans->data,
tex_2ds->slice_x_spans->len,
tex_2ds->width,
dst_x,
dst_x + width);
dst_x + width,
COGL_PIPELINE_WRAP_MODE_REPEAT);
!_cogl_span_iter_end (&x_iter);

View File

@ -57,77 +57,10 @@ static const CoglTextureVtable cogl_texture_2d_vtable;
typedef struct _CoglTexture2DManualRepeatData
{
CoglTexture2D *tex_2d;
CoglTextureSliceCallback callback;
CoglMetaTextureCallback callback;
void *user_data;
} CoglTexture2DManualRepeatData;
static void
_cogl_texture_2d_wrap_coords (float t_1, float t_2,
float *out_t_1, float *out_t_2)
{
float int_part;
/* Wrap t_1 and t_2 to the range [0,1] */
modff (t_1 < t_2 ? t_1 : t_2, &int_part);
t_1 -= int_part;
t_2 -= int_part;
if (cogl_util_float_signbit (int_part))
{
*out_t_1 = 1.0f + t_1;
*out_t_2 = 1.0f + t_2;
}
else
{
*out_t_1 = t_1;
*out_t_2 = t_2;
}
}
static void
_cogl_texture_2d_manual_repeat_cb (const float *coords,
void *user_data)
{
CoglTexture2DManualRepeatData *data = user_data;
float slice_coords[4];
_cogl_texture_2d_wrap_coords (coords[0], coords[2],
slice_coords + 0, slice_coords + 2);
_cogl_texture_2d_wrap_coords (coords[1], coords[3],
slice_coords + 1, slice_coords + 3);
data->callback (COGL_TEXTURE (data->tex_2d),
slice_coords,
coords,
data->user_data);
}
static void
_cogl_texture_2d_foreach_sub_texture_in_region (
CoglTexture *tex,
float virtual_tx_1,
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
void *user_data)
{
CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
CoglTexture2DManualRepeatData data;
data.tex_2d = tex_2d;
data.callback = callback;
data.user_data = user_data;
/* We need to implement manual repeating because if Cogl is calling
this function then it will set the wrap mode to GL_CLAMP_TO_EDGE
and hardware repeating can't be done */
_cogl_texture_iterate_manual_repeats (_cogl_texture_2d_manual_repeat_cb,
virtual_tx_1, virtual_ty_1,
virtual_tx_2, virtual_ty_2,
&data);
}
static void
_cogl_texture_2d_set_wrap_mode_parameters (CoglTexture *tex,
GLenum wrap_mode_s,
@ -923,7 +856,7 @@ cogl_texture_2d_vtable =
{
_cogl_texture_2d_set_region,
_cogl_texture_2d_get_data,
_cogl_texture_2d_foreach_sub_texture_in_region,
NULL, /* foreach_sub_texture_in_region */
_cogl_texture_2d_get_max_waste,
_cogl_texture_2d_is_sliced,
_cogl_texture_2d_can_hardware_repeat,

View File

@ -55,80 +55,6 @@ COGL_TEXTURE_DEFINE (Texture3D, texture_3d);
static const CoglTextureVtable cogl_texture_3d_vtable;
typedef struct _CoglTexture3DManualRepeatData
{
CoglTexture3D *tex_3d;
CoglTextureSliceCallback callback;
void *user_data;
} CoglTexture3DManualRepeatData;
static void
_cogl_texture_3d_wrap_coords (float t_1, float t_2,
float *out_t_1, float *out_t_2)
{
float int_part;
/* Wrap t_1 and t_2 to the range [0,1] */
modff (t_1 < t_2 ? t_1 : t_2, &int_part);
t_1 -= int_part;
t_2 -= int_part;
if (cogl_util_float_signbit (int_part))
{
*out_t_1 = 1.0f + t_1;
*out_t_2 = 1.0f + t_2;
}
else
{
*out_t_1 = t_1;
*out_t_2 = t_2;
}
}
static void
_cogl_texture_3d_manual_repeat_cb (const float *coords,
void *user_data)
{
CoglTexture3DManualRepeatData *data = user_data;
float slice_coords[4];
_cogl_texture_3d_wrap_coords (coords[0], coords[2],
slice_coords + 0, slice_coords + 2);
_cogl_texture_3d_wrap_coords (coords[1], coords[3],
slice_coords + 1, slice_coords + 3);
data->callback (COGL_TEXTURE (data->tex_3d),
slice_coords,
coords,
data->user_data);
}
static void
_cogl_texture_3d_foreach_sub_texture_in_region (
CoglTexture *tex,
float virtual_tx_1,
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
void *user_data)
{
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
CoglTexture3DManualRepeatData data;
data.tex_3d = tex_3d;
data.callback = callback;
data.user_data = user_data;
/* We need to implement manual repeating because if Cogl is calling
this function then it will set the wrap mode to GL_CLAMP_TO_EDGE
and hardware repeating can't be done */
_cogl_texture_iterate_manual_repeats (_cogl_texture_3d_manual_repeat_cb,
virtual_tx_1, virtual_ty_1,
virtual_tx_2, virtual_ty_2,
&data);
}
static void
_cogl_texture_3d_set_wrap_mode_parameters (CoglTexture *tex,
GLenum wrap_mode_s,
@ -671,7 +597,7 @@ cogl_texture_3d_vtable =
{
_cogl_texture_3d_set_region,
_cogl_texture_3d_get_data,
_cogl_texture_3d_foreach_sub_texture_in_region,
NULL, /* foreach_sub_texture_in_region */
_cogl_texture_3d_get_max_waste,
_cogl_texture_3d_is_sliced,
_cogl_texture_3d_can_hardware_repeat,

View File

@ -27,17 +27,10 @@
#include "cogl-bitmap-private.h"
#include "cogl-handle.h"
#include "cogl-pipeline-private.h"
#include "cogl-spans.h"
typedef struct _CoglTextureVtable CoglTextureVtable;
typedef void (*CoglTextureSliceCallback) (CoglTexture *texture,
const float *slice_coords,
const float *virtual_coords,
void *user_data);
typedef void (* CoglTextureManualRepeatCallback) (const float *coords,
void *user_data);
/* Encodes three possibiloities result of transforming a quad */
typedef enum {
/* quad doesn't cross the boundaries of a texture */
@ -92,7 +85,7 @@ struct _CoglTextureVtable
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
CoglMetaTextureCallback callback,
void *user_data);
int (* get_max_waste) (CoglTexture *tex);
@ -189,15 +182,6 @@ _cogl_texture_register_texture_type (GQuark type);
_cogl_texture_register_texture_type (_cogl_handle_ \
## type_name ## _get_type ()))
void
_cogl_texture_foreach_sub_texture_in_region (CoglTexture *texture,
float virtual_tx_1,
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
void *user_data);
gboolean
_cogl_texture_can_hardware_repeat (CoglTexture *texture);
@ -256,17 +240,6 @@ _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 */
@ -289,4 +262,18 @@ _cogl_texture_get_associated_framebuffers (CoglTexture *texture);
void
_cogl_texture_flush_journal_rendering (CoglTexture *texture);
void
_cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
int n_x_spans,
CoglSpan *y_spans,
int n_y_spans,
CoglTexture **textures,
float *virtual_coords,
float x_normalize_factor,
float y_normalize_factor,
CoglPipelineWrapMode wrap_x,
CoglPipelineWrapMode wrap_y,
CoglMetaTextureCallback callback,
void *user_data);
#endif /* __COGL_TEXTURE_PRIVATE_H */

View File

@ -52,6 +52,9 @@ struct _CoglTextureRectangle
gboolean is_foreign;
};
gboolean
_cogl_is_texture_rectangle (void *object);
GQuark
_cogl_handle_texture_rectangle_get_type (void);

View File

@ -59,85 +59,6 @@ COGL_TEXTURE_INTERNAL_DEFINE (TextureRectangle, texture_rectangle);
static const CoglTextureVtable cogl_texture_rectangle_vtable;
typedef struct _CoglTextureRectangleManualRepeatData
{
CoglTextureRectangle *tex_rect;
CoglTextureSliceCallback callback;
void *user_data;
} CoglTextureRectangleManualRepeatData;
static void
_cogl_texture_rectangle_wrap_coords (float t_1, float t_2,
float *out_t_1, float *out_t_2)
{
float int_part;
/* Wrap t_1 and t_2 to the range [0,1] */
modff (t_1 < t_2 ? t_1 : t_2, &int_part);
t_1 -= int_part;
t_2 -= int_part;
if (cogl_util_float_signbit (int_part))
{
*out_t_1 = 1.0f + t_1;
*out_t_2 = 1.0f + t_2;
}
else
{
*out_t_1 = t_1;
*out_t_2 = t_2;
}
}
static void
_cogl_texture_rectangle_manual_repeat_cb (const float *coords,
void *user_data)
{
CoglTextureRectangleManualRepeatData *data = user_data;
float slice_coords[4];
_cogl_texture_rectangle_wrap_coords (coords[0], coords[2],
slice_coords + 0, slice_coords + 2);
_cogl_texture_rectangle_wrap_coords (coords[1], coords[3],
slice_coords + 1, slice_coords + 3);
slice_coords[0] *= data->tex_rect->width;
slice_coords[1] *= data->tex_rect->height;
slice_coords[2] *= data->tex_rect->width;
slice_coords[3] *= data->tex_rect->height;
data->callback (COGL_TEXTURE (data->tex_rect),
slice_coords,
coords,
data->user_data);
}
static void
_cogl_texture_rectangle_foreach_sub_texture_in_region (
CoglTexture *tex,
float virtual_tx_1,
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
void *user_data)
{
CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
CoglTextureRectangleManualRepeatData data;
data.tex_rect = tex_rect;
data.callback = callback;
data.user_data = user_data;
/* We need to implement manual repeating because if Cogl is calling
this function then it will set the wrap mode to GL_CLAMP_TO_EDGE
and hardware repeating can't be done */
_cogl_texture_iterate_manual_repeats
(_cogl_texture_rectangle_manual_repeat_cb,
virtual_tx_1, virtual_ty_1, virtual_tx_2, virtual_ty_2,
&data);
}
static gboolean
can_use_wrap_mode (GLenum wrap_mode)
{
@ -653,7 +574,7 @@ cogl_texture_rectangle_vtable =
{
_cogl_texture_rectangle_set_region,
_cogl_texture_rectangle_get_data,
_cogl_texture_rectangle_foreach_sub_texture_in_region,
NULL, /* foreach_sub_texture_in_region */
_cogl_texture_rectangle_get_max_waste,
_cogl_texture_rectangle_is_sliced,
_cogl_texture_rectangle_can_hardware_repeat,

View File

@ -292,101 +292,6 @@ _cogl_texture_set_wrap_mode_parameters (CoglTexture *texture,
wrap_mode_p);
}
/* 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
{
float pos, end, next_pos;
gboolean flipped;
float t_1, t_2;
} CoglTextureIter;
static void
_cogl_texture_iter_update (CoglTextureIter *iter)
{
float t_2;
float frac_part;
frac_part = 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 || frac_part == 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,
float t_1, float 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);
}
}
CoglTexture *
cogl_texture_new_with_size (unsigned int width,
unsigned int height,
@ -527,6 +432,11 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
#if HAVE_COGL_GL
if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
{
CoglTextureRectangle *texture_rectangle;
CoglSubTexture *sub_texture;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
if (x_pot_waste != 0 || y_pot_waste != 0)
{
/* It shouldn't be necessary to have waste in this case since
@ -536,10 +446,17 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
return COGL_INVALID_HANDLE;
}
return _cogl_texture_rectangle_new_from_foreign (gl_handle,
width,
height,
format);
texture_rectangle = _cogl_texture_rectangle_new_from_foreign (gl_handle,
width,
height,
format);
/* CoglTextureRectangle textures work with non-normalized
* coordinates, but the semantics for this function that people
* depend on are that all returned texture works with normalized
* coordinates so we wrap with a CoglSubTexture... */
sub_texture = _cogl_sub_texture_new (COGL_TEXTURE (texture_rectangle),
0, 0, width, height);
return COGL_TEXTURE (sub_texture);
}
#endif
@ -681,33 +598,6 @@ cogl_texture_is_sliced (CoglTexture *texture)
return texture->vtable->is_sliced (texture);
}
/* Some CoglTextures, notably sliced textures or atlas textures when repeating
* is used, will need to divide the coordinate space into multiple GL textures
* (or rather; in the case of atlases duplicate a single texture in multiple
* positions to handle repeating)
*
* This function helps you implement primitives using such textures by
* invoking a callback once for each sub texture that intersects a given
* region specified in texture coordinates.
*/
void
_cogl_texture_foreach_sub_texture_in_region (CoglTexture *texture,
float virtual_tx_1,
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
void *user_data)
{
texture->vtable->foreach_sub_texture_in_region (texture,
virtual_tx_1,
virtual_ty_1,
virtual_tx_2,
virtual_ty_2,
callback,
user_data);
}
/* If this returns FALSE, that implies _foreach_sub_texture_in_region
* will be needed to iterate over multiple sub textures for regions whos
* texture coordinates extend out of the range [0,1]
@ -1353,10 +1243,12 @@ cogl_texture_get_data (CoglTexture *texture,
* the data for a sliced texture, and allows us to do the
* read-from-framebuffer logic here in a simple fashion rather than
* passing offsets down through the code. */
_cogl_texture_foreach_sub_texture_in_region (texture,
0, 0, 1, 1,
texture_get_cb,
&tg_data);
cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (texture),
0, 0, 1, 1,
COGL_PIPELINE_WRAP_MODE_REPEAT,
COGL_PIPELINE_WRAP_MODE_REPEAT,
texture_get_cb,
&tg_data);
_cogl_bitmap_unmap (target_bmp);
@ -1457,3 +1349,115 @@ _cogl_texture_flush_journal_rendering (CoglTexture *texture)
for (l = texture->framebuffers; l; l = l->next)
_cogl_framebuffer_flush_journal (l->data);
}
/* This function lets you define a meta texture as a grid of textures
* whereby the x and y grid-lines are defined by an array of
* CoglSpans. With that grid based description this function can then
* iterate all the cells of the grid that lye within a region
* specified as virtual, meta-texture, coordinates. This function can
* also cope with regions that extend beyond the original meta-texture
* grid by iterating cells repeatedly according to the wrap_x/y
* arguments.
*
* To differentiate between texture coordinates of a specific, real,
* slice texture and the texture coordinates of a composite, meta
* texture, the coordinates of the meta texture are called "virtual"
* coordinates and the coordinates of spans are called "slice"
* coordinates.
*
* Note: no guarantee is given about the order in which the slices
* will be visited.
*
* Note: The slice coordinates passed to @callback are always
* normalized coordinates even if the span coordinates aren't
* normalized.
*/
void
_cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
int n_x_spans,
CoglSpan *y_spans,
int n_y_spans,
CoglTexture **textures,
float *virtual_coords,
float x_normalize_factor,
float y_normalize_factor,
CoglPipelineWrapMode wrap_x,
CoglPipelineWrapMode wrap_y,
CoglMetaTextureCallback callback,
void *user_data)
{
CoglSpanIter iter_x;
CoglSpanIter iter_y;
float slice_coords[4];
/* Iterate the y axis of the virtual rectangle */
for (_cogl_span_iter_begin (&iter_y,
y_spans,
n_y_spans,
y_normalize_factor,
virtual_coords[1],
virtual_coords[3],
wrap_y);
!_cogl_span_iter_end (&iter_y);
_cogl_span_iter_next (&iter_y))
{
if (iter_y.flipped)
{
slice_coords[1] = iter_y.intersect_end;
slice_coords[3] = iter_y.intersect_start;
}
else
{
slice_coords[1] = iter_y.intersect_start;
slice_coords[3] = iter_y.intersect_end;
}
/* Map the current intersection to normalized slice coordinates */
slice_coords[1] = (slice_coords[1] - iter_y.pos) / iter_y.span->size;
slice_coords[3] = (slice_coords[3] - iter_y.pos) / iter_y.span->size;
/* Iterate the x axis of the virtual rectangle */
for (_cogl_span_iter_begin (&iter_x,
x_spans,
n_x_spans,
x_normalize_factor,
virtual_coords[0],
virtual_coords[2],
wrap_x);
!_cogl_span_iter_end (&iter_x);
_cogl_span_iter_next (&iter_x))
{
CoglTexture *span_tex;
float span_virtual_coords[4];
if (iter_x.flipped)
{
slice_coords[0] = iter_x.intersect_end;
slice_coords[2] = iter_x.intersect_start;
}
else
{
slice_coords[0] = iter_x.intersect_start;
slice_coords[2] = iter_x.intersect_end;
}
/* Map the current intersection to normalized slice coordinates */
slice_coords[0] = (slice_coords[0] - iter_x.pos) / iter_x.span->size;
slice_coords[2] = (slice_coords[2] - iter_x.pos) / iter_x.span->size;
/* Pluck out the cogl texture for this span */
span_tex = textures[iter_y.index * n_y_spans + iter_x.index];
span_virtual_coords[0] = iter_x.intersect_start;
span_virtual_coords[1] = iter_y.intersect_start;
span_virtual_coords[2] = iter_x.intersect_end;
span_virtual_coords[3] = iter_y.intersect_end;
callback (COGL_TEXTURE (span_tex),
slice_coords,
span_virtual_coords,
user_data);
}
}
}

View File

@ -82,6 +82,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
#include <cogl/cogl-texture-2d.h>
#include <cogl/cogl-texture-3d.h>
#include <cogl/cogl-texture-2d-sliced.h>
#include <cogl/cogl-meta-texture.h>
#include <cogl/cogl-index-buffer.h>
#include <cogl/cogl-attribute-buffer.h>
#include <cogl/cogl-indices.h>

View File

@ -739,6 +739,33 @@ _cogl_texture_pixmap_x11_get_data (CoglTexture *tex,
return cogl_texture_get_data (child_tex, format, rowstride, data);
}
typedef struct _NormalizeCoordsWrapperData
{
int width;
int height;
CoglMetaTextureCallback callback;
void *user_data;
} NormalizeCoordsWrapperData;
static void
normalize_coords_wrapper_cb (CoglTexture *child_texture,
const float *child_texture_coords,
const float *meta_coords,
void *user_data)
{
NormalizeCoordsWrapperData *data = user_data;
float normalized_coords[4];
normalized_coords[0] = meta_coords[0] / data->width;
normalized_coords[1] = meta_coords[1] / data->height;
normalized_coords[2] = meta_coords[2] / data->width;
normalized_coords[3] = meta_coords[3] / data->height;
data->callback (child_texture,
child_texture_coords, normalized_coords,
data->user_data);
}
static void
_cogl_texture_pixmap_x11_foreach_sub_texture_in_region
(CoglTexture *tex,
@ -746,22 +773,54 @@ _cogl_texture_pixmap_x11_foreach_sub_texture_in_region
float virtual_ty_1,
float virtual_tx_2,
float virtual_ty_2,
CoglTextureSliceCallback callback,
CoglMetaTextureCallback callback,
void *user_data)
{
CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex);
CoglHandle child_tex;
child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap);
CoglHandle child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap);
/* Forward on to the child texture */
_cogl_texture_foreach_sub_texture_in_region (child_tex,
virtual_tx_1,
virtual_ty_1,
virtual_tx_2,
virtual_ty_2,
callback,
user_data);
/* tfp textures may be implemented in terms of a
* CoglTextureRectangle texture which uses un-normalized texture
* coordinates but we want to consistently deal with normalized
* texture coordinates with CoglTexturePixmapX11... */
if (_cogl_is_texture_rectangle (child_tex))
{
NormalizeCoordsWrapperData data;
int width = tex_pixmap->width;
int height = tex_pixmap->height;
virtual_tx_1 *= width;
virtual_ty_1 *= height;
virtual_tx_2 *= width;
virtual_ty_2 *= height;
data.width = width;
data.height = height;
data.callback = callback;
data.user_data = user_data;
cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex),
virtual_tx_1,
virtual_ty_1,
virtual_tx_2,
virtual_ty_2,
COGL_PIPELINE_WRAP_MODE_REPEAT,
COGL_PIPELINE_WRAP_MODE_REPEAT,
normalize_coords_wrapper_cb,
&data);
}
else
cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex),
virtual_tx_1,
virtual_ty_1,
virtual_tx_2,
virtual_ty_2,
COGL_PIPELINE_WRAP_MODE_REPEAT,
COGL_PIPELINE_WRAP_MODE_REPEAT,
callback,
user_data);
}
static int