From 1d8fd64e1cd74a44cb60689bd5ee2c8c8f518b20 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 8 Oct 2011 14:13:03 +0100 Subject: [PATCH] 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 --- cogl-pango/cogl-pango-render.c | 16 +- cogl/Makefile.am | 2 + cogl/cogl-atlas-texture.c | 18 +- cogl/cogl-meta-texture.c | 391 ++++++++++++++++++++++++++ cogl/cogl-meta-texture.h | 190 +++++++++++++ cogl/cogl-primitives.c | 74 +++-- cogl/cogl-spans.c | 24 +- cogl/cogl-spans.h | 37 +-- cogl/cogl-sub-texture.c | 220 ++++++--------- cogl/cogl-texture-2d-sliced.c | 166 +++++------ cogl/cogl-texture-2d.c | 71 +---- cogl/cogl-texture-3d.c | 76 +---- cogl/cogl-texture-private.h | 45 ++- cogl/cogl-texture-rectangle-private.h | 3 + cogl/cogl-texture-rectangle.c | 81 +----- cogl/cogl-texture.c | 264 ++++++++--------- cogl/cogl.h | 1 + cogl/winsys/cogl-texture-pixmap-x11.c | 81 +++++- 18 files changed, 1069 insertions(+), 691 deletions(-) create mode 100644 cogl/cogl-meta-texture.c create mode 100644 cogl/cogl-meta-texture.h diff --git a/cogl-pango/cogl-pango-render.c b/cogl-pango/cogl-pango-render.c index ff974d69c..3f87b5278 100644 --- a/cogl-pango/cogl-pango-render.c +++ b/cogl-pango/cogl-pango-render.c @@ -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); diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 3135afdc5..7e3e943f7 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -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 \ diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c index 3fc459b7e..5b6b2ff6d 100644 --- a/cogl/cogl-atlas-texture.c +++ b/cogl/cogl-atlas-texture.c @@ -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 diff --git a/cogl/cogl-meta-texture.c b/cogl/cogl-meta-texture.c new file mode 100644 index 000000000..811ded65d --- /dev/null +++ b/cogl/cogl-meta-texture.c @@ -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 + * . + * + * + * Authors: + * Robert Bragg + */ + +#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 +#include + +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); + } +} diff --git a/cogl/cogl-meta-texture.h b/cogl/cogl-meta-texture.h new file mode 100644 index 000000000..f78f1b3bb --- /dev/null +++ b/cogl/cogl-meta-texture.h @@ -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 + * . + * + * + */ + +#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __COGL_META_TEXTURE_H__ +#define __COGL_META_TEXTURE_H__ + +#include +#include + +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 #CoglAtlasTextures, #CoglSubTextures, + * #CoglTexturePixmapX11 textures and #CoglTexture2DSliced textures + * consistently. + * + * A #CoglMetaTexture is a texture that might internally be + * represented by one or more low-level #CoglTextures + * 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 #CoglAtlasTextures + * or #CoglSubTextures 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(). + * + * 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. + */ + +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 #CoglTextures 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. + * + * 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. + * + * 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. + * + * 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. + * + * 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__ */ diff --git a/cogl/cogl-primitives.c b/cogl/cogl-primitives.c index 92813066d..27707bb32 100644 --- a/cogl/cogl-primitives.c +++ b/cogl/cogl-primitives.c @@ -37,6 +37,7 @@ #include "cogl-framebuffer-private.h" #include "cogl-attribute-private.h" #include "cogl-private.h" +#include "cogl-meta-texture.h" #include #include @@ -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], diff --git a/cogl/cogl-spans.c b/cogl/cogl-spans.c index d627930e4..3d9d3e516 100644 --- a/cogl/cogl-spans.c +++ b/cogl/cogl-spans.c @@ -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); diff --git a/cogl/cogl-spans.h b/cogl/cogl-spans.h index c3b77c052..e328b72ac 100644 --- a/cogl/cogl-spans.h +++ b/cogl/cogl-spans.h @@ -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); diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c index 331eecc43..44a8543bc 100644 --- a/cogl/cogl-sub-texture.c +++ b/cogl/cogl-sub-texture.c @@ -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 #include @@ -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 diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c index 150f05d4b..ec8db2fbd 100644 --- a/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl-texture-2d-sliced.c @@ -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); diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index 4697917d5..c64b14e43 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -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, diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c index 58adee602..584bbbd2a 100644 --- a/cogl/cogl-texture-3d.c +++ b/cogl/cogl-texture-3d.c @@ -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, diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h index 0ca0a45be..1ca056105 100644 --- a/cogl/cogl-texture-private.h +++ b/cogl/cogl-texture-private.h @@ -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 */ diff --git a/cogl/cogl-texture-rectangle-private.h b/cogl/cogl-texture-rectangle-private.h index 9a0dca225..07eca5e80 100644 --- a/cogl/cogl-texture-rectangle-private.h +++ b/cogl/cogl-texture-rectangle-private.h @@ -52,6 +52,9 @@ struct _CoglTextureRectangle gboolean is_foreign; }; +gboolean +_cogl_is_texture_rectangle (void *object); + GQuark _cogl_handle_texture_rectangle_get_type (void); diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c index 558def692..a2011536b 100644 --- a/cogl/cogl-texture-rectangle.c +++ b/cogl/cogl-texture-rectangle.c @@ -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, diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index b2e0a409f..fa3857dc0 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -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); + } + } +} + diff --git a/cogl/cogl.h b/cogl/cogl.h index 1f738a7c2..3925a0b98 100644 --- a/cogl/cogl.h +++ b/cogl/cogl.h @@ -82,6 +82,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer; #include #include #include +#include #include #include #include diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c index 44ac4cdb0..76ad7feb0 100644 --- a/cogl/winsys/cogl-texture-pixmap-x11.c +++ b/cogl/winsys/cogl-texture-pixmap-x11.c @@ -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