From 9da26fc1ca820d12d325df400e6e02d7cd25423a Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Wed, 16 Sep 2009 11:56:17 +0100 Subject: [PATCH] [cogl-texture] Seal CoglTexture internals from cogl-primitives.c cogl-primitives.c was previously digging right into CoglTextures so it could manually iterate the texture slices for texturing quads and polygons and because we were missing some state getters we were lazily just poking into the structures directly. This adds some extra state getter functions, and adds a higher level _cogl_texture_foreach_slice () API that hopefully simplifies the way in which sliced textures may be used to render primitives. This lets you specify a rectangle in "virtual" texture coords and it will call a given callback for each slice that intersects that rectangle giving the virtual coords of the current slice and corresponding "real" texture coordinates for the underlying gl texture. At the same time a noteable bug in how we previously iterated sliced textures was fixed, whereby we weren't correctly handling inverted texture coordinates. E.g. with the previous code if you supplied texture coords of tx1=100,ty1=0,tx2=0,ty2=100 (inverted along y axis) that would result in a back-facing quad, which could be discarded if using back-face culling. --- clutter/cogl/cogl/cogl-material.c | 9 +- clutter/cogl/cogl/cogl-primitives.c | 726 +++++++++++------------ clutter/cogl/cogl/cogl-texture-private.h | 47 +- clutter/cogl/cogl/cogl-texture.c | 239 +++++++- clutter/cogl/cogl/cogl-vertex-buffer.c | 6 +- clutter/cogl/cogl/driver/gl/cogl-fbo.c | 31 +- clutter/cogl/cogl/driver/gles/cogl-fbo.c | 31 +- 7 files changed, 637 insertions(+), 452 deletions(-) diff --git a/clutter/cogl/cogl/cogl-material.c b/clutter/cogl/cogl/cogl-material.c index cd55bf5a2..d47fad784 100644 --- a/clutter/cogl/cogl/cogl-material.c +++ b/clutter/cogl/cogl/cogl-material.c @@ -1365,14 +1365,6 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, cogl_texture_get_gl_texture (tex_handle, &gl_texture, NULL); } -#ifdef HAVE_COGL_GLES2 - { - CoglTexture *tex = - _cogl_texture_pointer_from_handle (tex_handle); - gl_internal_format = tex->gl_intformat; - } -#endif - GE (glActiveTexture (GL_TEXTURE0 + i)); _cogl_texture_set_filters (layer->texture, @@ -1390,6 +1382,7 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, texture should clear it from the cache in case a new texture is generated with the same number */ #ifdef HAVE_COGL_GLES2 + gl_internal_format = _cogl_texture_get_internal_gl_format (tex_handle); cogl_gles2_wrapper_bind_texture (gl_target, gl_texture, gl_internal_format); diff --git a/clutter/cogl/cogl/cogl-primitives.c b/clutter/cogl/cogl/cogl-primitives.c index 943657ec0..ca51f8a1d 100644 --- a/clutter/cogl/cogl/cogl-primitives.c +++ b/clutter/cogl/cogl/cogl-primitives.c @@ -104,6 +104,28 @@ typedef struct _CoglJournalFlushState #endif } CoglJournalFlushState; +typedef struct _TextureSlicedQuadState +{ + CoglHandle material; + float tex_virtual_origin_x; + float tex_virtual_origin_y; + float quad_origin_x; + float quad_origin_y; + float v_to_q_scale_x; + float v_to_q_scale_y; + float quad_len_x; + float quad_len_y; + gboolean flipped_x; + gboolean flipped_y; +} TextureSlicedQuadState; + +typedef struct _TextureSlicedPolygonState +{ + CoglTextureVertex *vertices; + int n_vertices; + int stride; +} TextureSlicedPolygonState; + /* these are defined in the particular backend */ void _cogl_path_add_node (gboolean new_sub_path, float x, @@ -750,189 +772,167 @@ _cogl_journal_log_quad (float x_1, } static void -_cogl_texture_sliced_quad (CoglTexture *tex, - CoglHandle material, - float x_1, - float y_1, - float x_2, - float y_2, - float tx_1, - float ty_1, - float tx_2, - float ty_2) +log_quad_sub_textures_cb (CoglHandle texture_handle, + GLuint gl_handle, + GLenum gl_target, + float *subtexture_coords, + float *virtual_coords, + void *user_data) { - CoglSpanIter iter_x , iter_y; - float tw , th; - float tqx , tqy; - float first_tx , first_ty; - float first_qx , first_qy; - float slice_tx1 , slice_ty1; - float slice_tx2 , slice_ty2; - float slice_qx1 , slice_qy1; - float slice_qx2 , slice_qy2; - GLuint gl_handle; + TextureSlicedQuadState *state = user_data; + float quad_coords[4]; + +#define TEX_VIRTUAL_TO_QUAD(V, Q, AXIS) \ + do { \ + Q = V - state->tex_virtual_origin_##AXIS; \ + Q *= state->v_to_q_scale_##AXIS; \ + if (state->flipped_##AXIS) \ + Q = state->quad_len_##AXIS - Q; \ + Q += state->quad_origin_##AXIS; \ + } while (0); + + TEX_VIRTUAL_TO_QUAD (virtual_coords[0], quad_coords[0], x); + TEX_VIRTUAL_TO_QUAD (virtual_coords[1], quad_coords[1], y); + + TEX_VIRTUAL_TO_QUAD (virtual_coords[2], quad_coords[2], x); + TEX_VIRTUAL_TO_QUAD (virtual_coords[3], quad_coords[3], y); + +#undef TEX_VIRTUAL_TO_QUAD + + COGL_NOTE (DRAW, + "~~~~~ slice\n" + "qx1: %f\t" + "qy1: %f\n" + "qx2: %f\t" + "qy2: %f\n" + "tx1: %f\t" + "ty1: %f\n" + "tx2: %f\t" + "ty2: %f\n", + quad_coords[0], quad_coords[1], + quad_coords[2], quad_coords[3], + subtexture_coords[0], subtexture_coords[1], + subtexture_coords[2], subtexture_coords[3]); + + /* FIXME: when the wrap mode becomes part of the material we need to + * be able to override the wrap mode when logging a quad. */ + _cogl_journal_log_quad (quad_coords[0], + quad_coords[1], + quad_coords[2], + quad_coords[3], + state->material, + 1, /* one layer */ + 0, /* don't need to use fallbacks */ + gl_handle, /* replace the layer0 texture */ + subtexture_coords, + 4); +} + +/* This path doesn't currently support multitexturing but is used for + * CoglTextures that don't support repeating using the GPU so we need to + * manually emit extra geometry to fake the repeating. This includes: + * + * - CoglTexture2DSliced: when made of > 1 slice or if the users given + * texture coordinates require repeating, + * - CoglTexture2DAtlas: if the users given texture coordinates require + * repeating, + * - CoglTextureRectangle: if the users given texture coordinates require + * repeating, + * - CoglTexturePixmap: if the users given texture coordinates require + * repeating + */ +/* TODO: support multitexturing */ +static void +_cogl_texture_quad_multiple_primitives (CoglHandle tex_handle, + CoglHandle material, + float x_1, + float y_1, + float x_2, + float y_2, + float tx_1, + float ty_1, + float tx_2, + float ty_2) +{ + TextureSlicedQuadState state; + gboolean tex_virtual_flipped_x; + gboolean tex_virtual_flipped_y; + gboolean quad_flipped_x; + gboolean quad_flipped_y; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - COGL_NOTE (DRAW, "Drawing Tex Quad (Sliced Mode)"); + COGL_NOTE (DRAW, "Drawing Tex Quad (Multi-Prim Mode)"); /* 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 */ - _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE); + /* FIXME: wrap modes should be part of the material! */ + _cogl_texture_set_wrap_mode_parameter (tex_handle, GL_CLAMP_TO_EDGE); - /* If the texture coordinates are backwards then swap both the - geometry and texture coordinates so that the texture will be - flipped but we can still use the same algorithm to iterate the - slices */ - if (tx_2 < tx_1) - { - float temp = x_1; - x_1 = x_2; - x_2 = temp; - temp = tx_1; - tx_1 = tx_2; - tx_2 = temp; - } - if (ty_2 < ty_1) - { - float temp = y_1; - y_1 = y_2; - y_2 = temp; - temp = ty_1; - ty_1 = ty_2; - ty_2 = temp; - } + state.material = material; - /* Scale ratio from texture to quad widths */ - tw = (float)(tex->bitmap.width); - th = (float)(tex->bitmap.height); + /* Get together the data we need to transform the virtual texture + * coordinates of each slice into quad coordinates... + * + * NB: We need to consider that the quad coordinates and the texture + * coordinates may be inverted along the x or y axis, and must preserve the + * inversions when we emit the final geometry. + */ - tqx = (x_2 - x_1) / (tw * (tx_2 - tx_1)); - tqy = (y_2 - y_1) / (th * (ty_2 - ty_1)); + tex_virtual_flipped_x = (tx_1 > tx_2) ? TRUE : FALSE; + tex_virtual_flipped_y = (ty_1 > ty_2) ? TRUE : FALSE; + state.tex_virtual_origin_x = tex_virtual_flipped_x ? tx_2 : tx_1; + state.tex_virtual_origin_y = tex_virtual_flipped_y ? ty_2 : ty_1; - /* Integral texture coordinate for first tile */ - first_tx = (float)(floorf (tx_1)); - first_ty = (float)(floorf (ty_1)); + quad_flipped_x = (x_1 > x_2) ? TRUE : FALSE; + quad_flipped_y = (y_1 > y_2) ? TRUE : FALSE; + state.quad_origin_x = quad_flipped_x ? x_2 : x_1; + state.quad_origin_y = quad_flipped_y ? y_2 : y_1; - /* Denormalize texture coordinates */ - first_tx = (first_tx * tw); - first_ty = (first_ty * th); - tx_1 = (tx_1 * tw); - ty_1 = (ty_1 * th); - tx_2 = (tx_2 * tw); - ty_2 = (ty_2 * th); + /* flatten the two forms of coordinate inversion into one... */ + state.flipped_x = tex_virtual_flipped_x ^ quad_flipped_x; + state.flipped_y = tex_virtual_flipped_y ^ quad_flipped_y; - /* Quad coordinate of the first tile */ - first_qx = x_1 - (tx_1 - first_tx) * tqx; - first_qy = y_1 - (ty_1 - first_ty) * tqy; + /* We use the _len_AXIS naming here instead of _width and _height because + * log_quad_slice_cb uses a macro with symbol concatenation to handle both + * axis, so this is more convenient... */ + state.quad_len_x = fabs (x_2 - x_1); + state.quad_len_y = fabs (y_2 - y_1); + 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)); - /* Iterate until whole quad height covered */ - for (_cogl_span_iter_begin (&iter_y, tex->slice_y_spans, - first_ty, ty_1, ty_2) ; - !_cogl_span_iter_end (&iter_y) ; - _cogl_span_iter_next (&iter_y) ) - { - float tex_coords[4]; - - /* Discard slices out of quad early */ - if (!iter_y.intersects) continue; - - /* Span-quad intersection in quad coordinates */ - slice_qy1 = first_qy + (iter_y.intersect_start - first_ty) * tqy; - - slice_qy2 = first_qy + (iter_y.intersect_end - first_ty) * tqy; - - /* Localize slice texture coordinates */ - slice_ty1 = iter_y.intersect_start - iter_y.pos; - slice_ty2 = iter_y.intersect_end - iter_y.pos; - - /* Normalize texture coordinates to current slice - (rectangle texture targets take denormalized) */ -#if HAVE_COGL_GL - if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB) -#endif - { - slice_ty1 /= iter_y.span->size; - slice_ty2 /= iter_y.span->size; - } - - /* Iterate until whole quad width covered */ - for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans, - first_tx, tx_1, tx_2) ; - !_cogl_span_iter_end (&iter_x) ; - _cogl_span_iter_next (&iter_x) ) - { - /* Discard slices out of quad early */ - if (!iter_x.intersects) continue; - - /* Span-quad intersection in quad coordinates */ - slice_qx1 = first_qx + (iter_x.intersect_start - first_tx) * tqx; - - slice_qx2 = first_qx + (iter_x.intersect_end - first_tx) * tqx; - - /* Localize slice texture coordinates */ - slice_tx1 = iter_x.intersect_start - iter_x.pos; - slice_tx2 = iter_x.intersect_end - iter_x.pos; - - /* Normalize texture coordinates to current slice - (rectangle texture targets take denormalized) */ -#if HAVE_COGL_GL - if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB) -#endif - { - slice_tx1 /= iter_x.span->size; - slice_tx2 /= iter_x.span->size; - } - - COGL_NOTE (DRAW, - "~~~~~ slice (%d, %d)\n" - "qx1: %f\t" - "qy1: %f\n" - "qx2: %f\t" - "qy2: %f\n" - "tx1: %f\t" - "ty1: %f\n" - "tx2: %f\t" - "ty2: %f\n", - iter_x.index, iter_y.index, - slice_qx1, slice_qy1, - slice_qx2, slice_qy2, - slice_tx1, slice_ty1, - slice_tx2, slice_ty2); - - /* Pick and bind opengl texture object */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - iter_y.index * iter_x.array->len + - iter_x.index); - - tex_coords[0] = slice_tx1; - tex_coords[1] = slice_ty1; - tex_coords[2] = slice_tx2; - tex_coords[3] = slice_ty2; - _cogl_journal_log_quad (slice_qx1, - slice_qy1, - slice_qx2, - slice_qy2, - material, - 1, /* one layer */ - 0, /* don't need to use fallbacks */ - gl_handle, /* replace the layer0 texture */ - tex_coords, - 4); - } - } + _cogl_texture_foreach_sub_texture_in_region (tex_handle, + tx_1, ty_1, tx_2, ty_2, + log_quad_sub_textures_cb, + &state); } +/* This path supports multitexturing but only when each of the layers is + * handled with a single GL texture. Also if repeating is necessary then + * _cogl_texture_can_hardware_repeat() must return TRUE. + * This includes layers made from: + * + * - CoglTexture2DSliced: if only comprised of a single slice with optional + * waste, assuming the users given texture coordinates don't require + * repeating. + * - CoglTexture{1D,2D,3D}: always. + * - CoglTexture2DAtlas: assuming the users given texture coordinates don't + * require repeating. + * - CoglTextureRectangle: assuming the users given texture coordinates don't + * require repeating. + * - CoglTexturePixmap: assuming the users given texture coordinates don't + * require repeating. + */ static gboolean -_cogl_multitexture_unsliced_quad (float x_1, - float y_1, - float x_2, - float y_2, - CoglHandle material, - guint32 fallback_layers, - const float *user_tex_coords, - gint user_tex_coords_len) +_cogl_multitexture_quad_single_primitive (float x_1, + float y_1, + float x_2, + float y_2, + CoglHandle material, + guint32 fallback_layers, + const float *user_tex_coords, + int user_tex_coords_len) { int n_layers = cogl_material_get_n_layers (material); float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers); @@ -950,11 +950,9 @@ _cogl_multitexture_unsliced_quad (float x_1, { CoglHandle layer = (CoglHandle)tmp->data; CoglHandle tex_handle; - CoglTexture *tex; const float *in_tex_coords; float *out_tex_coords; - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; + float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0}; tex_handle = cogl_material_layer_get_texture (layer); @@ -963,8 +961,6 @@ _cogl_multitexture_unsliced_quad (float x_1, if (tex_handle == COGL_INVALID_HANDLE) continue; - tex = _cogl_texture_pointer_from_handle (tex_handle); - in_tex_coords = &user_tex_coords[i * 4]; out_tex_coords = &final_tex_coords[i * 4]; @@ -973,21 +969,19 @@ _cogl_multitexture_unsliced_quad (float x_1, * can't handle texture repeating so we check that the texture * coords lie in the range [0,1]. * - * NB: We already know that no texture matrix is being used - * if the texture has waste since we validated that early on. - * TODO: check for a texture matrix in the GL_TEXTURE_RECT - * case. + * NB: We already know that the texture isn't sliced so we can assume + * that the default coords (0,0) and (1,1) would only reference a single + * GL texture. + * + * NB: We already know that no texture matrix is being used if the + * texture doesn't support hardware repeat. */ - if (( -#if HAVE_COGL_GL - tex->gl_target == GL_TEXTURE_RECTANGLE_ARB || -#endif - _cogl_texture_span_has_waste (tex, 0, 0)) - && i < user_tex_coords_len / 4 - && (in_tex_coords[0] < 0 || in_tex_coords[0] > 1.0 - || in_tex_coords[1] < 0 || in_tex_coords[1] > 1.0 - || in_tex_coords[2] < 0 || in_tex_coords[2] > 1.0 - || in_tex_coords[3] < 0 || in_tex_coords[3] > 1.0)) + if (!_cogl_texture_can_hardware_repeat (tex_handle) + && i < user_tex_coords_len / 4 + && (in_tex_coords[0] < 0 || in_tex_coords[0] > 1.0 + || in_tex_coords[1] < 0 || in_tex_coords[1] > 1.0 + || in_tex_coords[2] < 0 || in_tex_coords[2] > 1.0 + || in_tex_coords[3] < 0 || in_tex_coords[3] > 1.0)) { if (i == 0) { @@ -996,12 +990,11 @@ _cogl_multitexture_unsliced_quad (float x_1, static gboolean warning_seen = FALSE; if (!warning_seen) g_warning ("Skipping layers 1..n of your material since " - "the first layer has waste and you supplied " - "texture coordinates outside the range [0,1]. " - "We don't currently support any " - "multi-texturing using textures with waste " - "when repeating is necissary so we are " - "falling back to sliced textures assuming " + "the first layer doesn't support hardware " + "repeat (e.g. because of waste or use of " + "GL_TEXTURE_RECTANGLE_ARB) and you supplied " + "texture coordinates outside the range [0,1]." + "Falling back to software repeat assuming " "layer 0 is the most important one keep"); warning_seen = TRUE; } @@ -1012,10 +1005,12 @@ _cogl_multitexture_unsliced_quad (float x_1, static gboolean warning_seen = FALSE; if (!warning_seen) g_warning ("Skipping layer %d of your material " - "consisting of a texture with waste since " - "you have supplied texture coords outside " - "the range [0,1] (unsupported when " - "multi-texturing)", i); + "since you have supplied texture coords " + "outside the range [0,1] but the texture " + "doesn't support hardware repeat (e.g. " + "because of waste or use of " + "GL_TEXTURE_RECTANGLE_ARB). This isn't " + "supported with multi-texturing.", i); warning_seen = TRUE; /* NB: marking for fallback will replace the layer with @@ -1048,41 +1043,21 @@ _cogl_multitexture_unsliced_quad (float x_1, memcpy (out_tex_coords, in_tex_coords, sizeof (GLfloat) * 4); - _cogl_texture_set_wrap_mode_parameter (tex, wrap_mode); + _cogl_texture_set_wrap_mode_parameter (tex_handle, wrap_mode); } else { - out_tex_coords[0] = 0; /* tx_1 */ - out_tex_coords[1] = 0; /* ty_1 */ - out_tex_coords[2] = 1.0; /* tx_2 */ - out_tex_coords[3] = 1.0; /* ty_2 */ + memcpy (out_tex_coords, default_tex_coords, sizeof (GLfloat) * 4); - _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE); + _cogl_texture_set_wrap_mode_parameter (tex_handle, GL_CLAMP_TO_EDGE); } - /* Don't include the waste in the texture coordinates */ - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); - - out_tex_coords[0] = - out_tex_coords[0] * (x_span->size - x_span->waste) / x_span->size; - out_tex_coords[1] = - out_tex_coords[1] * (y_span->size - y_span->waste) / y_span->size; - out_tex_coords[2] = - out_tex_coords[2] * (x_span->size - x_span->waste) / x_span->size; - out_tex_coords[3] = - out_tex_coords[3] * (y_span->size - y_span->waste) / y_span->size; - -#if HAVE_COGL_GL - /* Denormalize texture coordinates for rectangle textures */ - if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB) - { - out_tex_coords[0] *= x_span->size; - out_tex_coords[1] *= y_span->size; - out_tex_coords[2] *= x_span->size; - out_tex_coords[3] *= y_span->size; - } -#endif + _cogl_texture_transform_coords_to_gl (tex_handle, + &out_tex_coords[0], + &out_tex_coords[1]); + _cogl_texture_transform_coords_to_gl (tex_handle, + &out_tex_coords[2], + &out_tex_coords[3]); } _cogl_journal_log_quad (x_1, @@ -1139,7 +1114,6 @@ _cogl_rectangles_with_multitexture_coords ( { CoglHandle layer = tmp->data; CoglHandle tex_handle; - CoglTexture *texture = NULL; gulong flags; if (cogl_material_layer_get_type (layer) @@ -1153,8 +1127,6 @@ _cogl_rectangles_with_multitexture_coords ( if (tex_handle == COGL_INVALID_HANDLE) continue; - texture = _cogl_texture_pointer_from_handle (tex_handle); - /* XXX: * For now, if the first layer is sliced then all other layers are * ignored since we currently don't support multi-texturing with @@ -1199,19 +1171,21 @@ _cogl_rectangles_with_multitexture_coords ( } } - /* We don't support multi texturing using textures with any waste if the - * user has supplied a custom texture matrix, since we don't know if - * the result will end up trying to texture from the waste area. */ + /* If the texture can't be repeated with the GPU (e.g. because it has + * waste or if using GL_TEXTURE_RECTANGLE_ARB) then we don't support + * multi texturing since we don't know if the result will end up trying + * to texture from the waste area. */ flags = _cogl_material_layer_get_flags (layer); if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX - && _cogl_texture_span_has_waste (texture, 0, 0)) + && !_cogl_texture_can_hardware_repeat (tex_handle)) { static gboolean warning_seen = FALSE; if (!warning_seen) - g_warning ("Skipping layer %d of your material consisting of a " - "texture with waste since you have supplied a custom " - "texture matrix and the result may try to sample from " - "the waste area of your texture.", i); + g_warning ("Skipping layer %d of your material since a custom " + "texture matrix was given for a texture that can't be " + "repeated using the GPU and the result may try to " + "sample beyond the bounds of the texture ", + i); warning_seen = TRUE; /* NB: marking for fallback will replace the layer with @@ -1227,36 +1201,49 @@ _cogl_rectangles_with_multitexture_coords ( for (i = 0; i < n_rects; i++) { - if (all_use_sliced_quad_fallback - || !_cogl_multitexture_unsliced_quad (rects[i].x_1, rects[i].y_1, - rects[i].x_2, rects[i].y_2, - material, - fallback_layers, - rects[i].tex_coords, - rects[i].tex_coords_len)) - { - CoglHandle first_layer, tex_handle; - CoglTexture *texture; + CoglHandle first_layer, tex_handle; + const float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0}; + const float *tex_coords; - first_layer = layers->data; - tex_handle = cogl_material_layer_get_texture (first_layer); - texture = _cogl_texture_pointer_from_handle (tex_handle); - if (rects[i].tex_coords) - _cogl_texture_sliced_quad (texture, - material, - rects[i].x_1, rects[i].y_1, - rects[i].x_2, rects[i].y_2, - rects[i].tex_coords[0], - rects[i].tex_coords[1], - rects[i].tex_coords[2], - rects[i].tex_coords[3]); - else - _cogl_texture_sliced_quad (texture, - material, - rects[i].x_1, rects[i].y_1, - rects[i].x_2, rects[i].y_2, - 0.0f, 0.0f, 1.0f, 1.0f); + if (!all_use_sliced_quad_fallback) + { + gboolean success = + _cogl_multitexture_quad_single_primitive (rects[i].x_1, + rects[i].y_1, + rects[i].x_2, + rects[i].y_2, + material, + fallback_layers, + rects[i].tex_coords, + rects[i].tex_coords_len); + + /* NB: If _cogl_multitexture_quad_single_primitive fails then it + * means the user tried to use texture repeat with a texture that + * can't be repeated by the GPU (e.g. due to waste or use of + * GL_TEXTURE_RECTANGLE_ARB) */ + if (success) + continue; } + + /* If multitexturing failed or we are drawing with a sliced texture + * then we only support a single layer so we pluck out the texture + * from the first material layer... */ + first_layer = layers->data; + tex_handle = cogl_material_layer_get_texture (first_layer); + + if (rects[i].tex_coords) + tex_coords = rects[i].tex_coords; + else + tex_coords = default_tex_coords; + + _cogl_texture_quad_multiple_primitives (tex_handle, + material, + rects[i].x_1, rects[i].y_1, + rects[i].x_2, rects[i].y_2, + tex_coords[0], + tex_coords[1], + tex_coords[2], + tex_coords[3]); } #if 0 @@ -1368,21 +1355,78 @@ cogl_rectangle (float x_1, NULL, 0); } -static void -_cogl_texture_sliced_polygon (CoglTextureVertex *vertices, - guint n_vertices, - guint stride, - gboolean use_color) +void +draw_polygon_sub_texture_cb (CoglHandle tex_handle, + GLuint gl_handle, + GLenum gl_target, + float *subtexture_coords, + float *virtual_coords, + void *user_data) { - const GList *layers; - CoglHandle layer0; - CoglHandle tex_handle; - CoglTexture *tex; - CoglTexSliceSpan *y_span, *x_span; - int x, y, tex_num, i; - GLuint gl_handle; - GLfloat *v; + TextureSlicedPolygonState *state = user_data; + GLfloat *v; + int i; CoglMaterialFlushOptions options; + float slice_origin_x; + float slice_origin_y; + float virtual_origin_x; + float virtual_origin_y; + float v_to_s_scale_x; + float v_to_s_scale_y; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + slice_origin_x = subtexture_coords[0]; + slice_origin_y = subtexture_coords[1]; + virtual_origin_x = virtual_coords[0]; + virtual_origin_y = virtual_coords[1]; + v_to_s_scale_x = ((virtual_coords[2] - virtual_coords[0]) / + (subtexture_coords[2] - subtexture_coords[0])); + v_to_s_scale_y = ((virtual_coords[3] - virtual_coords[1]) / + (subtexture_coords[3] - subtexture_coords[1])); + + /* Convert the vertices into an array of GLfloats ready to pass to + * OpenGL */ + v = (GLfloat *)ctx->logged_vertices->data; + for (i = 0; i < state->n_vertices; i++) + { + /* NB: layout = [X,Y,Z,TX,TY,R,G,B,A,...] */ + GLfloat *t = v + 3; + + t[0] = ((state->vertices[i].tx - virtual_origin_x) * v_to_s_scale_x + + slice_origin_x); + t[1] = ((state->vertices[i].ty - virtual_origin_y) * v_to_s_scale_y + + slice_origin_y); + + v += state->stride; + } + + options.flags = + COGL_MATERIAL_FLUSH_DISABLE_MASK | + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE; + /* disable all except the first layer */ + options.disable_layers = (guint32)~1; + options.layer0_override_texture = gl_handle; + + _cogl_material_flush_gl_state (ctx->source_material, &options); + _cogl_flush_matrix_stacks (); + + GE (glDrawArrays (GL_TRIANGLE_FAN, 0, state->n_vertices)); +} + +/* handles 2d-sliced textures with > 1 slice */ +static void +_cogl_texture_polygon_multiple_primitives (CoglTextureVertex *vertices, + unsigned int n_vertices, + unsigned int stride, + gboolean use_color) +{ + const GList *layers; + CoglHandle layer0; + CoglHandle tex_handle; + GLfloat *v; + int i; + TextureSlicedPolygonState state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -1391,7 +1435,6 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices, layers = cogl_material_get_layers (ctx->source_material); layer0 = (CoglHandle)layers->data; tex_handle = cogl_material_layer_get_texture (layer0); - tex = _cogl_texture_pointer_from_handle (tex_handle); v = (GLfloat *)ctx->logged_vertices->data; for (i = 0; i < n_vertices; i++) @@ -1415,88 +1458,33 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices, v += stride; } - /* Render all of the slices with the full geometry but use a - transparent border color so that any part of the texture not - covered by the slice will be ignored */ - tex_num = 0; - for (y = 0; y < tex->slice_y_spans->len; y++) - { - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); + state.stride = stride; + state.vertices = vertices; + state.n_vertices = n_vertices; - for (x = 0; x < tex->slice_x_spans->len; x++) - { - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); - - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, tex_num++); - - /* Convert the vertices into an array of GLfloats ready to pass to - OpenGL */ - v = (GLfloat *)ctx->logged_vertices->data; - for (i = 0; i < n_vertices; i++) - { - GLfloat *t; - float tx, ty; - - tx = ((vertices[i].tx - - ((float)(x_span->start) - / tex->bitmap.width)) - * tex->bitmap.width / x_span->size); - ty = ((vertices[i].ty - - ((float)(y_span->start) - / tex->bitmap.height)) - * tex->bitmap.height / y_span->size); - -#if HAVE_COGL_GL - /* Scale the coordinates up for rectangle textures */ - if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB) - { - tx *= x_span->size; - ty *= y_span->size; - } -#endif - - /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ - t = v + 3; - t[0] = tx; - t[1] = ty; - - v += stride; - } - - options.flags = - COGL_MATERIAL_FLUSH_DISABLE_MASK | - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE; - /* disable all except the first layer */ - options.disable_layers = (guint32)~1; - options.layer0_override_texture = gl_handle; - - _cogl_material_flush_gl_state (ctx->source_material, &options); - _cogl_flush_matrix_stacks (); - - GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); - } - } + _cogl_texture_foreach_sub_texture_in_region (tex_handle, + 0, 0, 1, 1, + draw_polygon_sub_texture_cb, + &state); } static void -_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, - guint n_vertices, - guint n_layers, - guint stride, - gboolean use_color, - guint32 fallback_layers) +_cogl_multitexture_polygon_single_primitive (CoglTextureVertex *vertices, + guint n_vertices, + guint n_layers, + guint stride, + gboolean use_color, + guint32 fallback_layers) { CoglHandle material; const GList *layers; int i; GList *tmp; - CoglTexSliceSpan *y_span, *x_span; GLfloat *v; CoglMaterialFlushOptions options; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - material = ctx->source_material; layers = cogl_material_get_layers (material); @@ -1518,7 +1506,6 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, { CoglHandle layer = (CoglHandle)tmp->data; CoglHandle tex_handle; - CoglTexture *tex; GLfloat *t; float tx, ty; @@ -1530,28 +1517,9 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, if (tex_handle == COGL_INVALID_HANDLE) continue; - tex = _cogl_texture_pointer_from_handle (tex_handle); - - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); - - tx = ((vertices[i].tx - - ((float)(x_span->start) - / tex->bitmap.width)) - * tex->bitmap.width / x_span->size); - ty = ((vertices[i].ty - - ((float)(y_span->start) - / tex->bitmap.height)) - * tex->bitmap.height / y_span->size); - -#if HAVE_COGL_GL - /* Scale the coordinates up for rectangle textures */ - if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB) - { - tx *= x_span->size; - ty *= y_span->size; - } -#endif + tx = vertices[i].tx; + ty = vertices[i].ty; + _cogl_texture_transform_coords_to_gl (tex_handle, &tx, &ty); /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ t = v + 3 + 2 * j; @@ -1659,12 +1627,12 @@ cogl_polygon (CoglTextureVertex *vertices, #ifdef HAVE_COGL_GL { - CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); /* Temporarily change the wrapping mode on all of the slices to use * a transparent border * XXX: it's doesn't look like we save/restore this, like * the comment implies? */ - _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER); + _cogl_texture_set_wrap_mode_parameter (tex_handle, + GL_CLAMP_TO_BORDER); } #endif break; @@ -1735,17 +1703,17 @@ cogl_polygon (CoglTextureVertex *vertices, } if (use_sliced_polygon_fallback) - _cogl_texture_sliced_polygon (vertices, - n_vertices, - stride, - use_color); + _cogl_texture_polygon_multiple_primitives (vertices, + n_vertices, + stride, + use_color); else - _cogl_multitexture_unsliced_polygon (vertices, - n_vertices, - n_layers, - stride, - use_color, - fallback_layers); + _cogl_multitexture_polygon_single_primitive (vertices, + n_vertices, + n_layers, + stride, + use_color, + fallback_layers); /* Reset the size of the logged vertex array because rendering rectangles expects it to start at 0 */ diff --git a/clutter/cogl/cogl/cogl-texture-private.h b/clutter/cogl/cogl/cogl-texture-private.h index bc610b671..e82bda9a7 100644 --- a/clutter/cogl/cogl/cogl-texture-private.h +++ b/clutter/cogl/cogl/cogl-texture-private.h @@ -55,6 +55,7 @@ struct _CoglSpanIter float intersect_start_local; float intersect_end_local; gboolean intersects; + gboolean flipped; }; /* This is used to store the first pixel of each slice. This is only @@ -109,11 +110,37 @@ typedef struct _CoglJournalEntry * later. */ } CoglJournalEntry; +typedef void (*CoglTextureSliceCallback) (CoglHandle handle, + GLuint gl_handle, + GLenum gl_target, + float *slice_coords, + float *virtual_coords, + void *user_data); + CoglTexture* _cogl_texture_pointer_from_handle (CoglHandle handle); void -_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, +_cogl_texture_foreach_sub_texture_in_region (CoglHandle handle, + 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 (CoglHandle handle); + +void +_cogl_texture_transform_coords_to_gl (CoglHandle handle, + float *s, + float *t); +GLenum +_cogl_texture_get_internal_gl_format (CoglHandle handle); + +void +_cogl_texture_set_wrap_mode_parameter (CoglHandle handle, GLenum wrap_mode); void @@ -124,24 +151,6 @@ _cogl_texture_set_filters (CoglHandle handle, void _cogl_texture_ensure_mipmaps (CoglHandle handle); -gboolean -_cogl_texture_span_has_waste (CoglTexture *tex, - gint x_span_index, - gint y_span_index); - -void -_cogl_span_iter_begin (CoglSpanIter *iter, - GArray *array, - float origin, - float cover_start, - float cover_end); - -gboolean -_cogl_span_iter_end (CoglSpanIter *iter); - -void -_cogl_span_iter_next (CoglSpanIter *iter); - void _cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride); diff --git a/clutter/cogl/cogl/cogl-texture.c b/clutter/cogl/cogl/cogl-texture.c index 440cf4565..796d1c234 100644 --- a/clutter/cogl/cogl/cogl-texture.c +++ b/clutter/cogl/cogl/cogl-texture.c @@ -108,17 +108,41 @@ _cogl_span_iter_update (CoglSpanIter *iter) } void -_cogl_span_iter_begin (CoglSpanIter *iter, - GArray *array, - float origin, - float cover_start, - float cover_end) +_cogl_span_iter_begin (CoglSpanIter *iter, + GArray *spans, + float normalize_factor, + float cover_start, + float cover_end) { - /* Copy info */ + float cover_start_normalized; + iter->index = 0; - iter->array = array; iter->span = NULL; - iter->origin = origin; + + iter->array = spans; + + /* We always iterate in a positive direction from the origin. If + * iter->flipped == TRUE that means whoever is using this API should + * interpreted the current span as extending in the opposite direction. I.e. + * it extends to the left if iterating the X axis, or up if the Y axis. */ + if (cover_start > cover_end) + { + float tmp = cover_start; + cover_start = cover_end; + cover_end = tmp; + iter->flipped = TRUE; + } + else + iter->flipped = FALSE; + + /* The texture spans cover the normalized texture coordinate space ranging + * from [0,1] but to help support repeating of sliced textures we allow + * iteration of any range so we need to relate the start of the range to the + * nearest point equivalent to 0. + */ + cover_start_normalized = cover_start / normalize_factor; + iter->origin = floorf (cover_start_normalized) * normalize_factor; + iter->cover_start = cover_start; iter->cover_end = cover_end; iter->pos = iter->origin; @@ -147,6 +171,143 @@ _cogl_span_iter_end (CoglSpanIter *iter) return iter->pos >= iter->cover_end; } +/* 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. + */ +/* 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 */ +void +_cogl_texture_foreach_sub_texture_in_region (CoglHandle handle, + float virtual_tx_1, + float virtual_ty_1, + float virtual_tx_2, + float virtual_ty_2, + CoglTextureSliceCallback callback, + void *user_data) +{ + CoglTexture *tex = _cogl_texture_pointer_from_handle (handle); + float width = tex->bitmap.width; + float height = tex->bitmap.height; + CoglSpanIter iter_x; + CoglSpanIter iter_y; + + g_assert (tex->gl_target == GL_TEXTURE_2D); + + /* 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. + */ + /* 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->slice_y_spans, + height, + virtual_ty_1, + virtual_ty_2); + !_cogl_span_iter_end (&iter_y); + _cogl_span_iter_next (&iter_y)) + { + float y_intersect_start = iter_y.intersect_start; + float y_intersect_end = iter_y.intersect_end; + float slice_ty1; + float slice_ty2; + + /* Discard slices out of rectangle early */ + if (!iter_y.intersects) + continue; + + if (iter_y.flipped) + { + y_intersect_start = iter_y.intersect_end; + y_intersect_end = iter_y.intersect_start; + } + + /* Localize slice texture coordinates */ + slice_ty1 = y_intersect_start - iter_y.pos; + slice_ty2 = y_intersect_end - iter_y.pos; + + /* Normalize slice texture coordinates */ + slice_ty1 /= iter_y.span->size; + slice_ty2 /= iter_y.span->size; + + /* Iterate the x axis of the virtual rectangle */ + for (_cogl_span_iter_begin (&iter_x, + tex->slice_x_spans, + width, + virtual_tx_1, + virtual_tx_2); + !_cogl_span_iter_end (&iter_x); + _cogl_span_iter_next (&iter_x)) + { + float slice_coords[4]; + float virtual_coords[4]; + float x_intersect_start = iter_x.intersect_start; + float x_intersect_end = iter_x.intersect_end; + float slice_tx1; + float slice_tx2; + GLuint gl_handle; + + /* Discard slices out of rectangle early */ + if (!iter_x.intersects) + continue; + + if (iter_x.flipped) + { + x_intersect_start = iter_x.intersect_end; + x_intersect_end = iter_x.intersect_start; + } + + /* Localize slice texture coordinates */ + slice_tx1 = x_intersect_start - iter_x.pos; + slice_tx2 = x_intersect_end - iter_x.pos; + + /* Normalize slice texture coordinates */ + slice_tx1 /= iter_x.span->size; + slice_tx2 /= iter_x.span->size; + + /* Pluck out opengl texture object for this slice */ + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, + iter_y.index * iter_x.array->len + + iter_x.index); + + slice_coords[0] = slice_tx1; + slice_coords[1] = slice_ty1; + slice_coords[2] = slice_tx2; + slice_coords[3] = slice_ty2; + + virtual_coords[0] = x_intersect_start / width; + virtual_coords[1] = y_intersect_start / height; + virtual_coords[2] = x_intersect_end / width; + virtual_coords[3] = y_intersect_end / height; + + callback (tex, + gl_handle, + tex->gl_target, + slice_coords, + virtual_coords, + user_data); + } + } +} + void _cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride) { @@ -361,7 +522,7 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, /* Iterate vertical spans */ for (source_y = src_y, _cogl_span_iter_begin (&y_iter, tex->slice_y_spans, - 0, (float)(dst_y), + tex->bitmap.height, (float)(dst_y), (float)(dst_y + height)); !_cogl_span_iter_end (&y_iter); @@ -382,7 +543,7 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, /* Iterate horizontal spans */ for (source_x = src_x, _cogl_span_iter_begin (&x_iter, tex->slice_x_spans, - 0, (float)(dst_x), + tex->bitmap.width, (float)(dst_x), (float)(dst_x + width)); !_cogl_span_iter_end (&x_iter); @@ -635,9 +796,11 @@ _cogl_pot_slices_for_size (gint size_to_fill, } void -_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, +_cogl_texture_set_wrap_mode_parameter (CoglHandle handle, GLenum wrap_mode) { + CoglTexture *tex = _cogl_texture_pointer_from_handle (handle); + /* Only set the wrap mode if it's different from the current value to avoid too many GL calls */ if (tex->wrap_mode != wrap_mode) @@ -1390,6 +1553,60 @@ cogl_texture_is_sliced (CoglHandle handle) return TRUE; } +gboolean +_cogl_texture_can_hardware_repeat (CoglHandle handle) +{ + CoglTexture *tex = _cogl_texture_pointer_from_handle (handle); + CoglTexSliceSpan *x_span; + CoglTexSliceSpan *y_span; + +#if HAVE_COGL_GL + if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB) + return FALSE; +#endif + + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); + + return (x_span->waste || y_span->waste) ? FALSE : TRUE; +} + +void +_cogl_texture_transform_coords_to_gl (CoglHandle handle, + float *s, + float *t) +{ + CoglTexture *tex = _cogl_texture_pointer_from_handle (handle); + CoglTexSliceSpan *x_span; + CoglTexSliceSpan *y_span; + + g_assert (!cogl_texture_is_sliced (tex)); + + /* Don't include the waste in the texture coordinates */ + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); + + *s *= tex->bitmap.width / (float)x_span->size; + *t *= tex->bitmap.height / (float)y_span->size; + +#if HAVE_COGL_GL + /* Denormalize texture coordinates for rectangle textures */ + if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB) + { + *s *= x_span->size; + *t *= y_span->size; + } +#endif +} + +GLenum +_cogl_texture_get_internal_gl_format (CoglHandle handle) +{ + CoglTexture *tex = _cogl_texture_pointer_from_handle (handle); + + return tex->gl_intformat; +} + gboolean cogl_texture_get_gl_texture (CoglHandle handle, GLuint *out_gl_handle, diff --git a/clutter/cogl/cogl/cogl-vertex-buffer.c b/clutter/cogl/cogl/cogl-vertex-buffer.c index a69798b14..c1aa172f4 100644 --- a/clutter/cogl/cogl/cogl-vertex-buffer.c +++ b/clutter/cogl/cogl/cogl-vertex-buffer.c @@ -1629,17 +1629,13 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer) { CoglHandle layer = (CoglHandle)tmp->data; CoglHandle tex_handle = cogl_material_layer_get_texture (layer); - CoglTexture *texture; /* invalid textures will be handled correctly in * _cogl_material_flush_layers_gl_state */ if (tex_handle == COGL_INVALID_HANDLE) continue; - texture = _cogl_texture_pointer_from_handle (tex_handle); - - if (cogl_texture_is_sliced (tex_handle) - || _cogl_texture_span_has_waste (texture, 0, 0)) + if (!_cogl_texture_can_hardware_repeat (tex_handle)) { g_warning ("Disabling layer %d of the current source material, " "because texturing with the vertex buffer API is not " diff --git a/clutter/cogl/cogl/driver/gl/cogl-fbo.c b/clutter/cogl/cogl/driver/gl/cogl-fbo.c index d77304e60..375a67363 100644 --- a/clutter/cogl/cogl/driver/gl/cogl-fbo.c +++ b/clutter/cogl/cogl/driver/gl/cogl-fbo.c @@ -61,11 +61,11 @@ COGL_HANDLE_DEFINE (Fbo, offscreen); CoglHandle cogl_offscreen_new_to_texture (CoglHandle texhandle) { - CoglTexture *tex; CoglFbo *fbo; - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; + int width; + int height; GLuint tex_gl_handle; + GLenum tex_gl_target; GLuint fbo_gl_handle; GLuint gl_stencil_handle; GLenum status; @@ -79,19 +79,20 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) if (!cogl_is_texture (texhandle)) return COGL_INVALID_HANDLE; - tex = _cogl_texture_pointer_from_handle (texhandle); - /* The texture must not be sliced */ - if (tex->slice_gl_handles == NULL) - return COGL_INVALID_HANDLE; - - if (tex->slice_gl_handles->len != 1) + if (cogl_texture_is_sliced (texhandle)) return COGL_INVALID_HANDLE; /* Pick the single texture slice width, height and GL id */ - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); - tex_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); + + width = cogl_texture_get_width (texhandle); + height = cogl_texture_get_height (texhandle); + + if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target)) + return COGL_INVALID_HANDLE; + + if (tex_gl_target != GL_TEXTURE_2D) + return COGL_INVALID_HANDLE; /* Create a renderbuffer for stenciling */ GE( glGenRenderbuffersEXT (1, &gl_stencil_handle) ); @@ -105,7 +106,7 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) glGenFramebuffersEXT (1, &fbo_gl_handle); GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo_gl_handle) ); GE( glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - tex->gl_target, tex_gl_handle, 0) ); + tex_gl_target, tex_gl_handle, 0) ); GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, gl_stencil_handle) ); @@ -152,8 +153,8 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) /* Allocate and init a CoglFbo object (store non-wasted size for subsequent blits and viewport setup) */ fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo)); - fbo->width = x_span->size - x_span->waste; - fbo->height = y_span->size - y_span->waste; + fbo->width = width; + fbo->height = height; fbo->gl_handle = fbo_gl_handle; fbo->gl_stencil_handle = gl_stencil_handle; diff --git a/clutter/cogl/cogl/driver/gles/cogl-fbo.c b/clutter/cogl/cogl/driver/gles/cogl-fbo.c index a1b419714..53604a10e 100644 --- a/clutter/cogl/cogl/driver/gles/cogl-fbo.c +++ b/clutter/cogl/cogl/driver/gles/cogl-fbo.c @@ -43,11 +43,11 @@ COGL_HANDLE_DEFINE (Fbo, offscreen); CoglHandle cogl_offscreen_new_to_texture (CoglHandle texhandle) { - CoglTexture *tex; CoglFbo *fbo; - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; + int width; + int height; GLuint tex_gl_handle; + GLenum tex_gl_target; GLuint fbo_gl_handle; GLuint gl_stencil_handle; GLenum status; @@ -61,19 +61,20 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) if (!cogl_is_texture (texhandle)) return COGL_INVALID_HANDLE; - tex = _cogl_texture_pointer_from_handle (texhandle); - /* The texture must not be sliced */ - if (tex->slice_gl_handles == NULL) - return COGL_INVALID_HANDLE; - - if (tex->slice_gl_handles->len != 1) + if (cogl_texture_is_sliced (texhandle)) return COGL_INVALID_HANDLE; /* Pick the single texture slice width, height and GL id */ - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); - tex_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); + + width = cogl_texture_get_width (texhandle); + height = cogl_texture_get_height (texhandle); + + if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target)) + return COGL_INVALID_HANDLE; + + if (tex_gl_target != GL_TEXTURE_2D) + return COGL_INVALID_HANDLE; /* Create a renderbuffer for stenciling */ GE( glGenRenderbuffers (1, &gl_stencil_handle) ); @@ -87,7 +88,7 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) glGenFramebuffers (1, &fbo_gl_handle); GE( glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle) ); GE( glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - tex->gl_target, tex_gl_handle, 0) ); + tex_gl_target, tex_gl_handle, 0) ); GE( glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_stencil_handle) ); @@ -122,8 +123,8 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) /* Allocate and init a CoglFbo object (store non-wasted size for subsequent blits and viewport setup) */ fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo)); - fbo->width = x_span->size - x_span->waste; - fbo->height = y_span->size - y_span->waste; + fbo->width = width; + fbo->height = height; fbo->gl_handle = fbo_gl_handle; fbo->gl_stencil_handle = gl_stencil_handle;