[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.
This commit is contained in:
Robert Bragg 2009-09-16 11:56:17 +01:00
parent 52cecd50ec
commit 9da26fc1ca
7 changed files with 637 additions and 452 deletions

View File

@ -1365,14 +1365,6 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
cogl_texture_get_gl_texture (tex_handle, &gl_texture, NULL); 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)); GE (glActiveTexture (GL_TEXTURE0 + i));
_cogl_texture_set_filters (layer->texture, _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 texture should clear it from the cache in case a new texture
is generated with the same number */ is generated with the same number */
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
gl_internal_format = _cogl_texture_get_internal_gl_format (tex_handle);
cogl_gles2_wrapper_bind_texture (gl_target, cogl_gles2_wrapper_bind_texture (gl_target,
gl_texture, gl_texture,
gl_internal_format); gl_internal_format);

View File

@ -104,6 +104,28 @@ typedef struct _CoglJournalFlushState
#endif #endif
} CoglJournalFlushState; } 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 */ /* these are defined in the particular backend */
void _cogl_path_add_node (gboolean new_sub_path, void _cogl_path_add_node (gboolean new_sub_path,
float x, float x,
@ -750,7 +772,78 @@ _cogl_journal_log_quad (float x_1,
} }
static void static void
_cogl_texture_sliced_quad (CoglTexture *tex, log_quad_sub_textures_cb (CoglHandle texture_handle,
GLuint gl_handle,
GLenum gl_target,
float *subtexture_coords,
float *virtual_coords,
void *user_data)
{
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, CoglHandle material,
float x_1, float x_1,
float y_1, float y_1,
@ -761,178 +854,85 @@ _cogl_texture_sliced_quad (CoglTexture *tex,
float tx_2, float tx_2,
float ty_2) float ty_2)
{ {
CoglSpanIter iter_x , iter_y; TextureSlicedQuadState state;
float tw , th; gboolean tex_virtual_flipped_x;
float tqx , tqy; gboolean tex_virtual_flipped_y;
float first_tx , first_ty; gboolean quad_flipped_x;
float first_qx , first_qy; gboolean quad_flipped_y;
float slice_tx1 , slice_ty1;
float slice_tx2 , slice_ty2;
float slice_qx1 , slice_qy1;
float slice_qx2 , slice_qy2;
GLuint gl_handle;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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 /* 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 */ 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 state.material = material;
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;
}
/* Scale ratio from texture to quad widths */ /* Get together the data we need to transform the virtual texture
tw = (float)(tex->bitmap.width); * coordinates of each slice into quad coordinates...
th = (float)(tex->bitmap.height); *
* 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)); tex_virtual_flipped_x = (tx_1 > tx_2) ? TRUE : FALSE;
tqy = (y_2 - y_1) / (th * (ty_2 - ty_1)); 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 */ quad_flipped_x = (x_1 > x_2) ? TRUE : FALSE;
first_tx = (float)(floorf (tx_1)); quad_flipped_y = (y_1 > y_2) ? TRUE : FALSE;
first_ty = (float)(floorf (ty_1)); 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 */ /* flatten the two forms of coordinate inversion into one... */
first_tx = (first_tx * tw); state.flipped_x = tex_virtual_flipped_x ^ quad_flipped_x;
first_ty = (first_ty * th); state.flipped_y = tex_virtual_flipped_y ^ quad_flipped_y;
tx_1 = (tx_1 * tw);
ty_1 = (ty_1 * th);
tx_2 = (tx_2 * tw);
ty_2 = (ty_2 * th);
/* Quad coordinate of the first tile */ /* We use the _len_AXIS naming here instead of _width and _height because
first_qx = x_1 - (tx_1 - first_tx) * tqx; * log_quad_slice_cb uses a macro with symbol concatenation to handle both
first_qy = y_1 - (ty_1 - first_ty) * tqy; * 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 */ _cogl_texture_foreach_sub_texture_in_region (tex_handle,
for (_cogl_span_iter_begin (&iter_y, tex->slice_y_spans, tx_1, ty_1, tx_2, ty_2,
first_ty, ty_1, ty_2) ; log_quad_sub_textures_cb,
!_cogl_span_iter_end (&iter_y) ; &state);
_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);
}
}
} }
/* 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 static gboolean
_cogl_multitexture_unsliced_quad (float x_1, _cogl_multitexture_quad_single_primitive (float x_1,
float y_1, float y_1,
float x_2, float x_2,
float y_2, float y_2,
CoglHandle material, CoglHandle material,
guint32 fallback_layers, guint32 fallback_layers,
const float *user_tex_coords, const float *user_tex_coords,
gint user_tex_coords_len) int user_tex_coords_len)
{ {
int n_layers = cogl_material_get_n_layers (material); int n_layers = cogl_material_get_n_layers (material);
float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers); 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 layer = (CoglHandle)tmp->data;
CoglHandle tex_handle; CoglHandle tex_handle;
CoglTexture *tex;
const float *in_tex_coords; const float *in_tex_coords;
float *out_tex_coords; float *out_tex_coords;
CoglTexSliceSpan *x_span; float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0};
CoglTexSliceSpan *y_span;
tex_handle = cogl_material_layer_get_texture (layer); 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) if (tex_handle == COGL_INVALID_HANDLE)
continue; continue;
tex = _cogl_texture_pointer_from_handle (tex_handle);
in_tex_coords = &user_tex_coords[i * 4]; in_tex_coords = &user_tex_coords[i * 4];
out_tex_coords = &final_tex_coords[i * 4]; out_tex_coords = &final_tex_coords[i * 4];
@ -973,16 +969,14 @@ _cogl_multitexture_unsliced_quad (float x_1,
* can't handle texture repeating so we check that the texture * can't handle texture repeating so we check that the texture
* coords lie in the range [0,1]. * coords lie in the range [0,1].
* *
* NB: We already know that no texture matrix is being used * NB: We already know that the texture isn't sliced so we can assume
* if the texture has waste since we validated that early on. * that the default coords (0,0) and (1,1) would only reference a single
* TODO: check for a texture matrix in the GL_TEXTURE_RECT * GL texture.
* case. *
* NB: We already know that no texture matrix is being used if the
* texture doesn't support hardware repeat.
*/ */
if (( if (!_cogl_texture_can_hardware_repeat (tex_handle)
#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 && i < user_tex_coords_len / 4
&& (in_tex_coords[0] < 0 || in_tex_coords[0] > 1.0 && (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[1] < 0 || in_tex_coords[1] > 1.0
@ -996,12 +990,11 @@ _cogl_multitexture_unsliced_quad (float x_1,
static gboolean warning_seen = FALSE; static gboolean warning_seen = FALSE;
if (!warning_seen) if (!warning_seen)
g_warning ("Skipping layers 1..n of your material since " g_warning ("Skipping layers 1..n of your material since "
"the first layer has waste and you supplied " "the first layer doesn't support hardware "
"texture coordinates outside the range [0,1]. " "repeat (e.g. because of waste or use of "
"We don't currently support any " "GL_TEXTURE_RECTANGLE_ARB) and you supplied "
"multi-texturing using textures with waste " "texture coordinates outside the range [0,1]."
"when repeating is necissary so we are " "Falling back to software repeat assuming "
"falling back to sliced textures assuming "
"layer 0 is the most important one keep"); "layer 0 is the most important one keep");
warning_seen = TRUE; warning_seen = TRUE;
} }
@ -1012,10 +1005,12 @@ _cogl_multitexture_unsliced_quad (float x_1,
static gboolean warning_seen = FALSE; static gboolean warning_seen = FALSE;
if (!warning_seen) if (!warning_seen)
g_warning ("Skipping layer %d of your material " g_warning ("Skipping layer %d of your material "
"consisting of a texture with waste since " "since you have supplied texture coords "
"you have supplied texture coords outside " "outside the range [0,1] but the texture "
"the range [0,1] (unsupported when " "doesn't support hardware repeat (e.g. "
"multi-texturing)", i); "because of waste or use of "
"GL_TEXTURE_RECTANGLE_ARB). This isn't "
"supported with multi-texturing.", i);
warning_seen = TRUE; warning_seen = TRUE;
/* NB: marking for fallback will replace the layer with /* 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); 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 else
{ {
out_tex_coords[0] = 0; /* tx_1 */ memcpy (out_tex_coords, default_tex_coords, sizeof (GLfloat) * 4);
out_tex_coords[1] = 0; /* ty_1 */
out_tex_coords[2] = 1.0; /* tx_2 */
out_tex_coords[3] = 1.0; /* ty_2 */
_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 */ _cogl_texture_transform_coords_to_gl (tex_handle,
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); &out_tex_coords[0],
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); &out_tex_coords[1]);
_cogl_texture_transform_coords_to_gl (tex_handle,
out_tex_coords[0] = &out_tex_coords[2],
out_tex_coords[0] * (x_span->size - x_span->waste) / x_span->size; &out_tex_coords[3]);
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_journal_log_quad (x_1, _cogl_journal_log_quad (x_1,
@ -1139,7 +1114,6 @@ _cogl_rectangles_with_multitexture_coords (
{ {
CoglHandle layer = tmp->data; CoglHandle layer = tmp->data;
CoglHandle tex_handle; CoglHandle tex_handle;
CoglTexture *texture = NULL;
gulong flags; gulong flags;
if (cogl_material_layer_get_type (layer) if (cogl_material_layer_get_type (layer)
@ -1153,8 +1127,6 @@ _cogl_rectangles_with_multitexture_coords (
if (tex_handle == COGL_INVALID_HANDLE) if (tex_handle == COGL_INVALID_HANDLE)
continue; continue;
texture = _cogl_texture_pointer_from_handle (tex_handle);
/* XXX: /* XXX:
* For now, if the first layer is sliced then all other layers are * For now, if the first layer is sliced then all other layers are
* ignored since we currently don't support multi-texturing with * 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 /* If the texture can't be repeated with the GPU (e.g. because it has
* user has supplied a custom texture matrix, since we don't know if * waste or if using GL_TEXTURE_RECTANGLE_ARB) then we don't support
* the result will end up trying to texture from the waste area. */ * 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); flags = _cogl_material_layer_get_flags (layer);
if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX 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; static gboolean warning_seen = FALSE;
if (!warning_seen) if (!warning_seen)
g_warning ("Skipping layer %d of your material consisting of a " g_warning ("Skipping layer %d of your material since a custom "
"texture with waste since you have supplied a custom " "texture matrix was given for a texture that can't be "
"texture matrix and the result may try to sample from " "repeated using the GPU and the result may try to "
"the waste area of your texture.", i); "sample beyond the bounds of the texture ",
i);
warning_seen = TRUE; warning_seen = TRUE;
/* NB: marking for fallback will replace the layer with /* 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++) for (i = 0; i < n_rects; i++)
{ {
if (all_use_sliced_quad_fallback CoglHandle first_layer, tex_handle;
|| !_cogl_multitexture_unsliced_quad (rects[i].x_1, rects[i].y_1, const float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0};
rects[i].x_2, rects[i].y_2, const float *tex_coords;
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, material,
fallback_layers, fallback_layers,
rects[i].tex_coords, rects[i].tex_coords,
rects[i].tex_coords_len)) rects[i].tex_coords_len);
{
CoglHandle first_layer, tex_handle;
CoglTexture *texture;
/* 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; first_layer = layers->data;
tex_handle = cogl_material_layer_get_texture (first_layer); tex_handle = cogl_material_layer_get_texture (first_layer);
texture = _cogl_texture_pointer_from_handle (tex_handle);
if (rects[i].tex_coords) if (rects[i].tex_coords)
_cogl_texture_sliced_quad (texture, tex_coords = rects[i].tex_coords;
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 else
_cogl_texture_sliced_quad (texture, tex_coords = default_tex_coords;
_cogl_texture_quad_multiple_primitives (tex_handle,
material, material,
rects[i].x_1, rects[i].y_1, rects[i].x_1, rects[i].y_1,
rects[i].x_2, rects[i].y_2, rects[i].x_2, rects[i].y_2,
0.0f, 0.0f, 1.0f, 1.0f); tex_coords[0],
} tex_coords[1],
tex_coords[2],
tex_coords[3]);
} }
#if 0 #if 0
@ -1368,21 +1355,78 @@ cogl_rectangle (float x_1,
NULL, 0); NULL, 0);
} }
void
draw_polygon_sub_texture_cb (CoglHandle tex_handle,
GLuint gl_handle,
GLenum gl_target,
float *subtexture_coords,
float *virtual_coords,
void *user_data)
{
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 static void
_cogl_texture_sliced_polygon (CoglTextureVertex *vertices, _cogl_texture_polygon_multiple_primitives (CoglTextureVertex *vertices,
guint n_vertices, unsigned int n_vertices,
guint stride, unsigned int stride,
gboolean use_color) gboolean use_color)
{ {
const GList *layers; const GList *layers;
CoglHandle layer0; CoglHandle layer0;
CoglHandle tex_handle; CoglHandle tex_handle;
CoglTexture *tex;
CoglTexSliceSpan *y_span, *x_span;
int x, y, tex_num, i;
GLuint gl_handle;
GLfloat *v; GLfloat *v;
CoglMaterialFlushOptions options; int i;
TextureSlicedPolygonState state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -1391,7 +1435,6 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
layers = cogl_material_get_layers (ctx->source_material); layers = cogl_material_get_layers (ctx->source_material);
layer0 = (CoglHandle)layers->data; layer0 = (CoglHandle)layers->data;
tex_handle = cogl_material_layer_get_texture (layer0); tex_handle = cogl_material_layer_get_texture (layer0);
tex = _cogl_texture_pointer_from_handle (tex_handle);
v = (GLfloat *)ctx->logged_vertices->data; v = (GLfloat *)ctx->logged_vertices->data;
for (i = 0; i < n_vertices; i++) for (i = 0; i < n_vertices; i++)
@ -1415,71 +1458,18 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
v += stride; v += stride;
} }
/* Render all of the slices with the full geometry but use a state.stride = stride;
transparent border color so that any part of the texture not state.vertices = vertices;
covered by the slice will be ignored */ state.n_vertices = n_vertices;
tex_num = 0;
for (y = 0; y < tex->slice_y_spans->len; y++)
{
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
for (x = 0; x < tex->slice_x_spans->len; x++) _cogl_texture_foreach_sub_texture_in_region (tex_handle,
{ 0, 0, 1, 1,
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); draw_polygon_sub_texture_cb,
&state);
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) );
}
}
} }
static void static void
_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, _cogl_multitexture_polygon_single_primitive (CoglTextureVertex *vertices,
guint n_vertices, guint n_vertices,
guint n_layers, guint n_layers,
guint stride, guint stride,
@ -1490,13 +1480,11 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
const GList *layers; const GList *layers;
int i; int i;
GList *tmp; GList *tmp;
CoglTexSliceSpan *y_span, *x_span;
GLfloat *v; GLfloat *v;
CoglMaterialFlushOptions options; CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
material = ctx->source_material; material = ctx->source_material;
layers = cogl_material_get_layers (material); layers = cogl_material_get_layers (material);
@ -1518,7 +1506,6 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
{ {
CoglHandle layer = (CoglHandle)tmp->data; CoglHandle layer = (CoglHandle)tmp->data;
CoglHandle tex_handle; CoglHandle tex_handle;
CoglTexture *tex;
GLfloat *t; GLfloat *t;
float tx, ty; float tx, ty;
@ -1530,28 +1517,9 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
if (tex_handle == COGL_INVALID_HANDLE) if (tex_handle == COGL_INVALID_HANDLE)
continue; continue;
tex = _cogl_texture_pointer_from_handle (tex_handle); tx = vertices[i].tx;
ty = vertices[i].ty;
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); _cogl_texture_transform_coords_to_gl (tex_handle, &tx, &ty);
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
/* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
t = v + 3 + 2 * j; t = v + 3 + 2 * j;
@ -1659,12 +1627,12 @@ cogl_polygon (CoglTextureVertex *vertices,
#ifdef HAVE_COGL_GL #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 /* Temporarily change the wrapping mode on all of the slices to use
* a transparent border * a transparent border
* XXX: it's doesn't look like we save/restore this, like * XXX: it's doesn't look like we save/restore this, like
* the comment implies? */ * 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 #endif
break; break;
@ -1735,12 +1703,12 @@ cogl_polygon (CoglTextureVertex *vertices,
} }
if (use_sliced_polygon_fallback) if (use_sliced_polygon_fallback)
_cogl_texture_sliced_polygon (vertices, _cogl_texture_polygon_multiple_primitives (vertices,
n_vertices, n_vertices,
stride, stride,
use_color); use_color);
else else
_cogl_multitexture_unsliced_polygon (vertices, _cogl_multitexture_polygon_single_primitive (vertices,
n_vertices, n_vertices,
n_layers, n_layers,
stride, stride,

View File

@ -55,6 +55,7 @@ struct _CoglSpanIter
float intersect_start_local; float intersect_start_local;
float intersect_end_local; float intersect_end_local;
gboolean intersects; gboolean intersects;
gboolean flipped;
}; };
/* This is used to store the first pixel of each slice. This is only /* This is used to store the first pixel of each slice. This is only
@ -109,11 +110,37 @@ typedef struct _CoglJournalEntry
* later. */ * later. */
} CoglJournalEntry; } CoglJournalEntry;
typedef void (*CoglTextureSliceCallback) (CoglHandle handle,
GLuint gl_handle,
GLenum gl_target,
float *slice_coords,
float *virtual_coords,
void *user_data);
CoglTexture* CoglTexture*
_cogl_texture_pointer_from_handle (CoglHandle handle); _cogl_texture_pointer_from_handle (CoglHandle handle);
void 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); GLenum wrap_mode);
void void
@ -124,24 +151,6 @@ _cogl_texture_set_filters (CoglHandle handle,
void void
_cogl_texture_ensure_mipmaps (CoglHandle handle); _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 void
_cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride); _cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride);

View File

@ -109,16 +109,40 @@ _cogl_span_iter_update (CoglSpanIter *iter)
void void
_cogl_span_iter_begin (CoglSpanIter *iter, _cogl_span_iter_begin (CoglSpanIter *iter,
GArray *array, GArray *spans,
float origin, float normalize_factor,
float cover_start, float cover_start,
float cover_end) float cover_end)
{ {
/* Copy info */ float cover_start_normalized;
iter->index = 0; iter->index = 0;
iter->array = array;
iter->span = NULL; 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_start = cover_start;
iter->cover_end = cover_end; iter->cover_end = cover_end;
iter->pos = iter->origin; iter->pos = iter->origin;
@ -147,6 +171,143 @@ _cogl_span_iter_end (CoglSpanIter *iter)
return iter->pos >= iter->cover_end; 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 void
_cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride) _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 */ /* Iterate vertical spans */
for (source_y = src_y, for (source_y = src_y,
_cogl_span_iter_begin (&y_iter, tex->slice_y_spans, _cogl_span_iter_begin (&y_iter, tex->slice_y_spans,
0, (float)(dst_y), tex->bitmap.height, (float)(dst_y),
(float)(dst_y + height)); (float)(dst_y + height));
!_cogl_span_iter_end (&y_iter); !_cogl_span_iter_end (&y_iter);
@ -382,7 +543,7 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
/* Iterate horizontal spans */ /* Iterate horizontal spans */
for (source_x = src_x, for (source_x = src_x,
_cogl_span_iter_begin (&x_iter, tex->slice_x_spans, _cogl_span_iter_begin (&x_iter, tex->slice_x_spans,
0, (float)(dst_x), tex->bitmap.width, (float)(dst_x),
(float)(dst_x + width)); (float)(dst_x + width));
!_cogl_span_iter_end (&x_iter); !_cogl_span_iter_end (&x_iter);
@ -635,9 +796,11 @@ _cogl_pot_slices_for_size (gint size_to_fill,
} }
void void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, _cogl_texture_set_wrap_mode_parameter (CoglHandle handle,
GLenum wrap_mode) GLenum wrap_mode)
{ {
CoglTexture *tex = _cogl_texture_pointer_from_handle (handle);
/* Only set the wrap mode if it's different from the current /* Only set the wrap mode if it's different from the current
value to avoid too many GL calls */ value to avoid too many GL calls */
if (tex->wrap_mode != wrap_mode) if (tex->wrap_mode != wrap_mode)
@ -1390,6 +1553,60 @@ cogl_texture_is_sliced (CoglHandle handle)
return TRUE; 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 gboolean
cogl_texture_get_gl_texture (CoglHandle handle, cogl_texture_get_gl_texture (CoglHandle handle,
GLuint *out_gl_handle, GLuint *out_gl_handle,

View File

@ -1629,17 +1629,13 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
{ {
CoglHandle layer = (CoglHandle)tmp->data; CoglHandle layer = (CoglHandle)tmp->data;
CoglHandle tex_handle = cogl_material_layer_get_texture (layer); CoglHandle tex_handle = cogl_material_layer_get_texture (layer);
CoglTexture *texture;
/* invalid textures will be handled correctly in /* invalid textures will be handled correctly in
* _cogl_material_flush_layers_gl_state */ * _cogl_material_flush_layers_gl_state */
if (tex_handle == COGL_INVALID_HANDLE) if (tex_handle == COGL_INVALID_HANDLE)
continue; continue;
texture = _cogl_texture_pointer_from_handle (tex_handle); if (!_cogl_texture_can_hardware_repeat (tex_handle))
if (cogl_texture_is_sliced (tex_handle)
|| _cogl_texture_span_has_waste (texture, 0, 0))
{ {
g_warning ("Disabling layer %d of the current source material, " g_warning ("Disabling layer %d of the current source material, "
"because texturing with the vertex buffer API is not " "because texturing with the vertex buffer API is not "

View File

@ -61,11 +61,11 @@ COGL_HANDLE_DEFINE (Fbo, offscreen);
CoglHandle CoglHandle
cogl_offscreen_new_to_texture (CoglHandle texhandle) cogl_offscreen_new_to_texture (CoglHandle texhandle)
{ {
CoglTexture *tex;
CoglFbo *fbo; CoglFbo *fbo;
CoglTexSliceSpan *x_span; int width;
CoglTexSliceSpan *y_span; int height;
GLuint tex_gl_handle; GLuint tex_gl_handle;
GLenum tex_gl_target;
GLuint fbo_gl_handle; GLuint fbo_gl_handle;
GLuint gl_stencil_handle; GLuint gl_stencil_handle;
GLenum status; GLenum status;
@ -79,19 +79,20 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
if (!cogl_is_texture (texhandle)) if (!cogl_is_texture (texhandle))
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
tex = _cogl_texture_pointer_from_handle (texhandle);
/* The texture must not be sliced */ /* The texture must not be sliced */
if (tex->slice_gl_handles == NULL) if (cogl_texture_is_sliced (texhandle))
return COGL_INVALID_HANDLE;
if (tex->slice_gl_handles->len != 1)
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
/* Pick the single texture slice width, height and GL id */ /* 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); width = cogl_texture_get_width (texhandle);
tex_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); 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 */ /* Create a renderbuffer for stenciling */
GE( glGenRenderbuffersEXT (1, &gl_stencil_handle) ); GE( glGenRenderbuffersEXT (1, &gl_stencil_handle) );
@ -105,7 +106,7 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
glGenFramebuffersEXT (1, &fbo_gl_handle); glGenFramebuffersEXT (1, &fbo_gl_handle);
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo_gl_handle) ); GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo_gl_handle) );
GE( glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 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, GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
GL_STENCIL_ATTACHMENT_EXT, GL_STENCIL_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, gl_stencil_handle) ); 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 /* Allocate and init a CoglFbo object (store non-wasted size
for subsequent blits and viewport setup) */ for subsequent blits and viewport setup) */
fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo)); fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo));
fbo->width = x_span->size - x_span->waste; fbo->width = width;
fbo->height = y_span->size - y_span->waste; fbo->height = height;
fbo->gl_handle = fbo_gl_handle; fbo->gl_handle = fbo_gl_handle;
fbo->gl_stencil_handle = gl_stencil_handle; fbo->gl_stencil_handle = gl_stencil_handle;

View File

@ -43,11 +43,11 @@ COGL_HANDLE_DEFINE (Fbo, offscreen);
CoglHandle CoglHandle
cogl_offscreen_new_to_texture (CoglHandle texhandle) cogl_offscreen_new_to_texture (CoglHandle texhandle)
{ {
CoglTexture *tex;
CoglFbo *fbo; CoglFbo *fbo;
CoglTexSliceSpan *x_span; int width;
CoglTexSliceSpan *y_span; int height;
GLuint tex_gl_handle; GLuint tex_gl_handle;
GLenum tex_gl_target;
GLuint fbo_gl_handle; GLuint fbo_gl_handle;
GLuint gl_stencil_handle; GLuint gl_stencil_handle;
GLenum status; GLenum status;
@ -61,19 +61,20 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
if (!cogl_is_texture (texhandle)) if (!cogl_is_texture (texhandle))
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
tex = _cogl_texture_pointer_from_handle (texhandle);
/* The texture must not be sliced */ /* The texture must not be sliced */
if (tex->slice_gl_handles == NULL) if (cogl_texture_is_sliced (texhandle))
return COGL_INVALID_HANDLE;
if (tex->slice_gl_handles->len != 1)
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
/* Pick the single texture slice width, height and GL id */ /* 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); width = cogl_texture_get_width (texhandle);
tex_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); 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 */ /* Create a renderbuffer for stenciling */
GE( glGenRenderbuffers (1, &gl_stencil_handle) ); GE( glGenRenderbuffers (1, &gl_stencil_handle) );
@ -87,7 +88,7 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
glGenFramebuffers (1, &fbo_gl_handle); glGenFramebuffers (1, &fbo_gl_handle);
GE( glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle) ); GE( glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle) );
GE( glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 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, GE( glFramebufferRenderbuffer (GL_FRAMEBUFFER,
GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, gl_stencil_handle) ); 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 /* Allocate and init a CoglFbo object (store non-wasted size
for subsequent blits and viewport setup) */ for subsequent blits and viewport setup) */
fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo)); fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo));
fbo->width = x_span->size - x_span->waste; fbo->width = width;
fbo->height = y_span->size - y_span->waste; fbo->height = height;
fbo->gl_handle = fbo_gl_handle; fbo->gl_handle = fbo_gl_handle;
fbo->gl_stencil_handle = gl_stencil_handle; fbo->gl_stencil_handle = gl_stencil_handle;