diff --git a/common/cogl-primitives.c b/common/cogl-primitives.c index e549a89a8..881e6cef4 100644 --- a/common/cogl-primitives.c +++ b/common/cogl-primitives.c @@ -30,6 +30,8 @@ #include "cogl.h" #include "cogl-internal.h" #include "cogl-context.h" +#include "cogl-texture-private.h" +#include "cogl-material.h" #include #include @@ -37,13 +39,907 @@ #define _COGL_MAX_BEZ_RECURSE_DEPTH 16 -/* these are defined in the particular backend(float in gl vs fixed in gles)*/ +#ifdef HAVE_COGL_GL + +#define glDrawRangeElements ctx->pf_glDrawRangeElements +#define glClientActiveTexture ctx->pf_glClientActiveTexture + +#else + +/* GLES doesn't have glDrawRangeElements, so we simply pretend it does + * but that it makes no use of the start, end constraints: */ +#define glDrawRangeElements(mode, start, end, count, type, indices) \ + glDrawElements (mode, count, type, indices) + +#endif + +/* these are defined in the particular backend */ void _cogl_path_add_node (gboolean new_sub_path, float x, float y); void _cogl_path_fill_nodes (); void _cogl_path_stroke_nodes (); +static void +_cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, + gint batch_len, + GLfloat *vertex_pointer) +{ + int needed_indices; + gsize stride; + int i; + gulong enable_flags = 0; + guint32 disable_mask; + int prev_n_texcoord_arrays_enabled; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* The indices are always the same sequence regardless of the vertices so we + * only need to change it if there are more vertices than ever before. */ + needed_indices = batch_len * 6; + if (needed_indices > ctx->static_indices->len) + { + int old_len = ctx->static_indices->len; + int vert_num = old_len / 6 * 4; + GLushort *q; + + /* Add two triangles for each quad to the list of + indices. That makes six new indices but two of the + vertices in the triangles are shared. */ + g_array_set_size (ctx->static_indices, needed_indices); + q = &g_array_index (ctx->static_indices, GLushort, old_len); + + for (i = old_len; + i < ctx->static_indices->len; + i += 6, vert_num += 4) + { + *(q++) = vert_num + 0; + *(q++) = vert_num + 1; + *(q++) = vert_num + 3; + + *(q++) = vert_num + 1; + *(q++) = vert_num + 2; + *(q++) = vert_num + 3; + } + } + + /* XXX NB: + * Our vertex data is arranged as follows: + * 4 vertices per quad: 2 GLfloats per position, + * 2 GLfloats per tex coord * n_layers + */ + stride = 2 + 2 * batch_start->n_layers; + stride *= sizeof (GLfloat); + + disable_mask = (1 << batch_start->n_layers) - 1; + disable_mask = ~disable_mask; + + cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + batch_start->fallback_mask, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + disable_mask, + /* Redundant when dealing with unsliced + * textures but does no harm... */ + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, + batch_start->layer0_override_texture, + NULL); + + for (i = 0; i < batch_start->n_layers; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); + GE (glTexCoordPointer (2, GL_FLOAT, stride, vertex_pointer + 2 + 2 * i)); + } + prev_n_texcoord_arrays_enabled = + ctx->n_texcoord_arrays_enabled; + ctx->n_texcoord_arrays_enabled = batch_start->n_layers; + for (; i < prev_n_texcoord_arrays_enabled; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); + } + + /* FIXME: This api is a bit yukky, ideally it will be removed if we + * re-work the cogl_enable mechanism */ + enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + + if (ctx->enable_backface_culling) + enable_flags |= COGL_ENABLE_BACKFACE_CULLING; + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + cogl_enable (enable_flags); + + GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); + _cogl_current_matrix_state_flush (); + GE (glDrawRangeElements (GL_TRIANGLES, + 0, ctx->static_indices->len - 1, + 6 * batch_len, + GL_UNSIGNED_SHORT, + ctx->static_indices->data)); + + + /* DEBUGGING CODE XXX: + * Uncommenting this will cause all rectangles to be drawn with a red, green + * or blue outline with no blending. This may e.g. help with debugging + * texture slicing issues or blending issues, plus it looks quite cool. + */ +#if 0 + { + static CoglHandle outline = COGL_INVALID_HANDLE; + static int color = 0; + if (outline == COGL_INVALID_HANDLE) + outline = cogl_material_new (); + + cogl_enable (COGL_ENABLE_VERTEX_ARRAY); + for (i = 0; i < batch_len; i++, color = (++color) % 3) + { + cogl_material_set_color4ub (outline, + color == 0 ? 0xff : 0x00, + color == 1 ? 0xff : 0x00, + color == 2 ? 0xff : 0x00, + 0xff); + cogl_material_flush_gl_state (outline, NULL); + _cogl_current_matrix_state_flush (); + GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) ); + } + } +#endif +} + +void +_cogl_journal_flush (void) +{ + GLfloat *current_vertex_pointer; + GLfloat *batch_vertex_pointer; + CoglJournalEntry *batch_start; + guint batch_len; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (ctx->journal->len == 0) + return; + + /* Current non-variables / constraints: + * + * - We don't have to worry about much GL state changing between journal + * entries since currently the journal never out lasts a single call to + * _cogl_multitexture_multiple_rectangles. So the user doesn't get the + * chance to fiddle with anything. (XXX: later this will be extended at + * which point we can start logging certain state changes) + * + * - Implied from above: all entries will refer to the same material. + * + * - Although _cogl_multitexture_multiple_rectangles can cause the wrap mode + * of textures to be modified, the journal is flushed if a wrap mode is + * changed so we don't currently have to log wrap mode changes. + * + * - XXX - others? + */ + + /* TODO: "compile" the journal to find ways of batching draw calls and vertex + * data. + * + * Simple E.g. given current constraints... + * pass 0 - load all data into a single CoglVertexBuffer + * pass 1 - batch gl draw calls according to entries that use the same + * textures. + * + * We will be able to do cooler stuff here when we extend the life of + * journals beyond _cogl_multitexture_multiple_rectangles. + */ + + batch_vertex_pointer = (GLfloat *)ctx->logged_vertices->data; + batch_start = (CoglJournalEntry *)ctx->journal->data; + batch_len = 1; + + current_vertex_pointer = batch_vertex_pointer; + + for (i = 1; i < ctx->journal->len; i++) + { + CoglJournalEntry *prev_entry = + &g_array_index (ctx->journal, CoglJournalEntry, i - 1); + CoglJournalEntry *current_entry = prev_entry + 1; + gsize stride; + + /* Progress the vertex pointer to the next quad */ + stride = 2 + current_entry->n_layers * 2; + current_vertex_pointer += stride * 4; + + /* batch rectangles using the same textures */ + if (current_entry->material == prev_entry->material && + current_entry->n_layers == prev_entry->n_layers && + current_entry->fallback_mask == prev_entry->fallback_mask && + current_entry->layer0_override_texture + == prev_entry->layer0_override_texture) + { + batch_len++; + continue; + } + + _cogl_journal_flush_quad_batch (batch_start, + batch_len, + batch_vertex_pointer); + + batch_start = current_entry; + batch_len = 1; + batch_vertex_pointer = current_vertex_pointer; + } + + /* The last batch... */ + _cogl_journal_flush_quad_batch (batch_start, + batch_len, + batch_vertex_pointer); + + + g_array_set_size (ctx->journal, 0); + g_array_set_size (ctx->logged_vertices, 0); +} + +static void +_cogl_journal_log_quad (float x_1, + float y_1, + float x_2, + float y_2, + CoglHandle material, + gint n_layers, + guint32 fallback_mask, + GLuint layer0_override_texture, + float *tex_coords, + guint tex_coords_len) +{ + int stride; + int next_vert; + GLfloat *v; + int i; + int next_entry; + CoglJournalEntry *entry; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* The vertex data is logged into a seperate array in a layout that can be + * directly passed to OpenGL + */ + + /* We pack the vertex data as 2 (x,y) GLfloats folowed by 2 (tx,ty) GLfloats + * for each texture being used, E.g.: + * [X, Y, TX0, TY0, TX1, TY1, X, Y, TX0, TY0, X, Y, ...] + */ + stride = 2 + n_layers * 2; + + next_vert = ctx->logged_vertices->len; + g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride); + v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert); + + /* XXX: All the jumping around to fill in this strided buffer doesn't + * seem ideal. */ + + /* XXX: we could defer expanding the vertex data for GL until we come + * to flushing the journal. */ + + v[0] = x_1; v[1] = y_1; + v += stride; + v[0] = x_1; v[1] = y_2; + v += stride; + v[0] = x_2; v[1] = y_2; + v += stride; + v[0] = x_2; v[1] = y_1; + + for (i = 0; i < n_layers; i++) + { + GLfloat *t = + &g_array_index (ctx->logged_vertices, GLfloat, next_vert + 2 + 2 * i); + + t[0] = tex_coords[0]; t[1] = tex_coords[1]; + t += stride; + t[0] = tex_coords[0]; t[1] = tex_coords[3]; + t += stride; + t[0] = tex_coords[2]; t[1] = tex_coords[3]; + t += stride; + t[0] = tex_coords[2]; t[1] = tex_coords[1]; + } + + next_entry = ctx->journal->len; + g_array_set_size (ctx->journal, next_entry + 1); + entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry); + + entry->material = material; + entry->n_layers = n_layers; + entry->fallback_mask = fallback_mask; + entry->layer0_override_texture = layer0_override_texture; +} + +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) +{ + 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; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + +#if COGL_DEBUG + printf("=== Drawing Tex Quad (Sliced Mode) ===\n"); +#endif + + /* 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); + + /* 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; + } + + /* Scale ratio from texture to quad widths */ + tw = (float)(tex->bitmap.width); + th = (float)(tex->bitmap.height); + + tqx = (x_2 - x_1) / (tw * (tx_2 - tx_1)); + tqy = (y_2 - y_1) / (th * (ty_2 - ty_1)); + + /* Integral texture coordinate for first tile */ + first_tx = (float)(floorf (tx_1)); + first_ty = (float)(floorf (ty_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); + + /* Quad coordinate of the first tile */ + first_qx = x_1 - (tx_1 - first_tx) * tqx; + first_qy = y_1 - (ty_1 - first_ty) * tqy; + + + /* 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; + } + +#if COGL_DEBUG + printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index); + printf("qx1: %f\n", (slice_qx1)); + printf("qy1: %f\n", (slice_qy1)); + printf("qx2: %f\n", (slice_qx2)); + printf("qy2: %f\n", (slice_qy2)); + printf("tx1: %f\n", (slice_tx1)); + printf("ty1: %f\n", (slice_ty1)); + printf("tx2: %f\n", (slice_tx2)); + printf("ty2: %f\n", (slice_ty2)); +#endif + + /* 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); + } + } +} + +static gboolean +_cogl_multitexture_unsliced_quad (float x_1, + float y_1, + float x_2, + float y_2, + CoglHandle material, + gint n_layers, + guint32 fallback_mask, + const float *user_tex_coords, + gint user_tex_coords_len) +{ + float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers); + const GList *layers; + GList *tmp; + int i; + + _COGL_GET_CONTEXT (ctx, FALSE); + + /* + * Validate the texture coordinates for this rectangle. + */ + layers = cogl_material_get_layers (material); + for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) + { + CoglHandle layer = (CoglHandle)tmp->data; + /* CoglLayerInfo *layer_info; */ + CoglHandle tex_handle; + CoglTexture *tex; + const float *in_tex_coords; + float *out_tex_coords; + CoglTexSliceSpan *x_span; + CoglTexSliceSpan *y_span; + + /* layer_info = &layers[i]; */ + + /* FIXME - we shouldn't be checking this stuff if layer_info->gl_texture + * already == 0 */ + + tex_handle = cogl_material_layer_get_texture (layer); + tex = _cogl_texture_pointer_from_handle (tex_handle); + + in_tex_coords = &user_tex_coords[i * 4]; + out_tex_coords = &final_tex_coords[i * 4]; + + + /* If the texture has waste or we are using GL_TEXTURE_RECT we + * 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. + */ + 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 (i == 0) + { + if (n_layers > 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 " + "layer 0 is the most important one keep"); + warning_seen = TRUE; + } + return FALSE; + } + else + { + 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); + warning_seen = TRUE; + + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + } + } + + + /* + * Setup the texture unit... + */ + + /* NB: The user might not have supplied texture coordinates for all + * layers... */ + if (i < (user_tex_coords_len / 4)) + { + GLenum wrap_mode; + + /* If the texture coords are all in the range [0,1] then we want to + clamp the coords to the edge otherwise it can pull in edge pixels + from the wrong side when scaled */ + if (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) + wrap_mode = GL_CLAMP_TO_EDGE; + else + wrap_mode = GL_REPEAT; + + memcpy (out_tex_coords, in_tex_coords, sizeof (GLfloat) * 4); + + _cogl_texture_set_wrap_mode_parameter (tex, 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 */ + + _cogl_texture_set_wrap_mode_parameter (tex, 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_journal_log_quad (x_1, + y_1, + x_2, + y_2, + material, + n_layers, + fallback_mask, + 0, /* don't replace the layer0 texture */ + final_tex_coords, + n_layers * 4); + + return TRUE; +} + +struct _CoglMutiTexturedRect +{ + float x_1; + float y_1; + float x_2; + float y_2; + const float *tex_coords; + gint tex_coords_len; +}; + +static void +_cogl_rectangles_with_multitexture_coords ( + struct _CoglMutiTexturedRect *rects, + gint n_rects) +{ + CoglHandle material; + const GList *layers; + int n_layers; + const GList *tmp; + guint32 fallback_mask = 0; + gboolean all_use_sliced_quad_fallback = FALSE; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + cogl_clip_ensure (); + + material = ctx->source_material; + + layers = cogl_material_get_layers (material); + n_layers = g_list_length ((GList *)layers); + + /* + * Validate all the layers of the current source material... + */ + + for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++) + { + CoglHandle layer = tmp->data; + CoglHandle tex_handle = cogl_material_layer_get_texture (layer); + CoglTexture *texture = _cogl_texture_pointer_from_handle (tex_handle); + gulong flags; + + if (cogl_material_layer_get_type (layer) + != COGL_MATERIAL_LAYER_TYPE_TEXTURE) + continue; + + /* XXX: + * For now, if the first layer is sliced then all other layers are + * ignored since we currently don't support multi-texturing with + * sliced textures. If the first layer is not sliced then any other + * layers found to be sliced will be skipped. (with a warning) + * + * TODO: Add support for multi-texturing rectangles with sliced + * textures if no texture matrices are in use. + */ + if (cogl_texture_is_sliced (tex_handle)) + { + if (i == 0) + { + fallback_mask = ~1; /* fallback all except the first layer */ + all_use_sliced_quad_fallback = TRUE; + if (tmp->next) + { + static gboolean warning_seen = FALSE; + if (!warning_seen) + g_warning ("Skipping layers 1..n of your material since " + "the first layer is sliced. We don't currently " + "support any multi-texturing with sliced " + "textures but assume layer 0 is the most " + "important to keep"); + warning_seen = TRUE; + } + break; + } + else + { + static gboolean warning_seen = FALSE; + if (!warning_seen) + g_warning ("Skipping layer %d of your material consisting of " + "a sliced texture (unsuported for multi texturing)", + i); + warning_seen = TRUE; + + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + continue; + } + } + + /* 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. */ + flags = cogl_material_layer_get_flags (layer); + if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX + && _cogl_texture_span_has_waste (texture, 0, 0)) + { + 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); + warning_seen = TRUE; + + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + continue; + } + } + + /* + * Emit geometry for each of the rectangles... + */ + + 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, + n_layers, + fallback_mask, + rects[i].tex_coords, + rects[i].tex_coords_len)) + { + CoglHandle first_layer, tex_handle; + CoglTexture *texture; + + 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); + } + } + + _cogl_journal_flush (); +} + +void +cogl_rectangles (const float *verts, + guint n_rects) +{ + struct _CoglMutiTexturedRect rects[n_rects]; + int i; + + for (i = 0; i < n_rects; i++) + { + rects[i].x_1 = verts[i * 4]; + rects[i].y_1 = verts[i * 4 + 1]; + rects[i].x_2 = verts[i * 4 + 2]; + rects[i].y_2 = verts[i * 4 + 3]; + rects[i].tex_coords = NULL; + rects[i].tex_coords_len = 0; + } + + _cogl_rectangles_with_multitexture_coords (rects, n_rects); +} + +void +cogl_rectangles_with_texture_coords (const float *verts, + guint n_rects) +{ + struct _CoglMutiTexturedRect rects[n_rects]; + int i; + + for (i = 0; i < n_rects; i++) + { + rects[i].x_1 = verts[i * 8]; + rects[i].y_1 = verts[i * 8 + 1]; + rects[i].x_2 = verts[i * 8 + 2]; + rects[i].y_2 = verts[i * 8 + 3]; + /* FIXME: rect should be defined to have a const float *geom; + * instead, to avoid this copy + * rect[i].geom = &verts[n_rects * 8]; */ + rects[i].tex_coords = &verts[i * 8 + 4]; + rects[i].tex_coords_len = 4; + } + + _cogl_rectangles_with_multitexture_coords (rects, n_rects); +} + +void +cogl_rectangle_with_texture_coords (float x_1, + float y_1, + float x_2, + float y_2, + float tx_1, + float ty_1, + float tx_2, + float ty_2) +{ + float verts[8]; + + verts[0] = x_1; + verts[1] = y_1; + verts[2] = x_2; + verts[3] = y_2; + verts[4] = tx_1; + verts[5] = ty_1; + verts[6] = tx_2; + verts[7] = ty_2; + + cogl_rectangles_with_texture_coords (verts, 1); +} + +void +cogl_rectangle_with_multitexture_coords (float x_1, + float y_1, + float x_2, + float y_2, + const float *user_tex_coords, + gint user_tex_coords_len) +{ + struct _CoglMutiTexturedRect rect; + + rect.x_1 = x_1; + rect.y_1 = y_1; + rect.x_2 = x_2; + rect.y_2 = y_2; + rect.tex_coords = user_tex_coords; + rect.tex_coords_len = user_tex_coords_len; + + _cogl_rectangles_with_multitexture_coords (&rect, 1); +} + void cogl_rectangle (float x_1, float y_1, @@ -55,6 +951,364 @@ cogl_rectangle (float x_1, NULL, 0); } +static void +_cogl_texture_sliced_polygon (CoglTextureVertex *vertices, + guint n_vertices, + guint stride, + gboolean use_color) +{ + 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; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* We can assume in this case that we have at least one layer in the + * material that corresponds to a sliced cogl texture */ + 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++) + { + GLfloat *c; + + v[0] = vertices[i].x; + v[1] = vertices[i].y; + v[2] = vertices[i].z; + + /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ + c = v + 5; + c[0] = cogl_color_get_red_byte (&vertices[i].color); + c[1] = cogl_color_get_green_byte (&vertices[i].color); + c[2] = cogl_color_get_blue_byte (&vertices[i].color); + c[3] = cogl_color_get_alpha_byte (&vertices[i].color); + + 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); + + 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; + } + + cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + (guint32)~1, /* disable all except the + first layer */ + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, + gl_handle, + NULL); + _cogl_current_matrix_state_flush (); + + GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); + } + } +} + +static void +_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, + guint n_vertices, + guint n_layers, + guint stride, + gboolean use_color, + guint32 fallback_mask) +{ + CoglHandle material; + const GList *layers; + int i; + GList *tmp; + CoglTexSliceSpan *y_span, *x_span; + GLfloat *v; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + + material = ctx->source_material; + layers = cogl_material_get_layers (material); + + /* Convert the vertices into an array of GLfloats ready to pass to + OpenGL */ + for (v = (GLfloat *)ctx->logged_vertices->data, i = 0; + i < n_vertices; + v += stride, i++) + { + GLfloat *c; + int j; + + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v[0] = vertices[i].x; + v[1] = vertices[i].y; + v[2] = vertices[i].z; + + for (tmp = (GList *)layers, j = 0; tmp != NULL; tmp = tmp->next, j++) + { + CoglHandle layer = (CoglHandle)tmp->data; + CoglHandle tex_handle; + CoglTexture *tex; + GLfloat *t; + float tx, ty; + + tex_handle = cogl_material_layer_get_texture (layer); + 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 + + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + t = v + 3 + 2 * j; + t[0] = tx; + t[1] = ty; + } + + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + c = v + 3 + 2 * n_layers; + c[0] = cogl_color_get_red_float (&vertices[i].color); + c[1] = cogl_color_get_green_float (&vertices[i].color); + c[2] = cogl_color_get_blue_float (&vertices[i].color); + c[3] = cogl_color_get_alpha_float (&vertices[i].color); + } + + cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + fallback_mask, + NULL); + _cogl_current_matrix_state_flush (); + + GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); +} + +void +cogl_polygon (CoglTextureVertex *vertices, + guint n_vertices, + gboolean use_color) +{ + CoglHandle material; + const GList *layers; + int n_layers; + GList *tmp; + gboolean use_sliced_polygon_fallback = FALSE; + guint32 fallback_mask = 0; + int i; + gulong enable_flags; + guint stride; + gsize stride_bytes; + GLfloat *v; + int prev_n_texcoord_arrays_enabled; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + cogl_clip_ensure (); + + material = ctx->source_material; + layers = cogl_material_get_layers (ctx->source_material); + n_layers = g_list_length ((GList *)layers); + + for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) + { + CoglHandle layer = (CoglHandle)tmp->data; + CoglHandle tex_handle = cogl_material_layer_get_texture (layer); + CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); + + if (i == 0 && cogl_texture_is_sliced (tex_handle)) + { +#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) + { + static gboolean warning_seen = FALSE; + if (!warning_seen) + g_warning ("cogl_polygon does not work for sliced textures " + "on GL ES"); + warning_seen = TRUE; + return; + } +#endif + if (n_layers > 1) + { + static gboolean warning_seen = FALSE; + if (!warning_seen) + { + g_warning ("Disabling layers 1..n since multi-texturing with " + "cogl_polygon isn't supported when using sliced " + "textures\n"); + warning_seen = TRUE; + } + } + use_sliced_polygon_fallback = TRUE; + n_layers = 1; + + if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST) + { + static gboolean warning_seen = FALSE; + if (!warning_seen) + { + g_warning ("cogl_texture_polygon does not work for sliced textures " + "when the minification and magnification filters are not " + "CGL_NEAREST"); + warning_seen = TRUE; + } + return; + } + +#ifdef HAVE_COGL_GL + /* 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); +#endif + break; + } + + if (cogl_texture_is_sliced (tex_handle)) + { + static gboolean warning_seen = FALSE; + if (!warning_seen) + g_warning ("Disabling layer %d of the current source material, " + "because texturing with the vertex buffer API is not " + "currently supported using sliced textures, or " + "textures with waste\n", i); + warning_seen = TRUE; + + fallback_mask |= (1 << i); + continue; + } + } + + /* Our data is arranged like: + * [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */ + stride = 3 + (2 * n_layers) + (use_color ? 4 : 0); + stride_bytes = stride * sizeof (GLfloat); + + /* Make sure there is enough space in the global vertex + array. This is used so we can render the polygon with a single + call to OpenGL but still support any number of vertices */ + g_array_set_size (ctx->logged_vertices, n_vertices * stride); + v = (GLfloat *)ctx->logged_vertices->data; + + /* Prepare GL state */ + enable_flags = COGL_ENABLE_VERTEX_ARRAY; + enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + + if (ctx->enable_backface_culling) + enable_flags |= COGL_ENABLE_BACKFACE_CULLING; + + if (use_color) + { + enable_flags |= COGL_ENABLE_COLOR_ARRAY; + GE( glColorPointer (4, GL_FLOAT, + stride_bytes, + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v + 3 + 2 * n_layers) ); + } + + cogl_enable (enable_flags); + + GE (glVertexPointer (3, GL_FLOAT, stride_bytes, v)); + + for (i = 0; i < n_layers; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); + GE (glTexCoordPointer (2, GL_FLOAT, + stride_bytes, + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v + 3 + 2 * i)); + } + prev_n_texcoord_arrays_enabled = + ctx->n_texcoord_arrays_enabled; + ctx->n_texcoord_arrays_enabled = n_layers; + for (; i < prev_n_texcoord_arrays_enabled; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); + } + + if (use_sliced_polygon_fallback) + _cogl_texture_sliced_polygon (vertices, + n_vertices, + stride, + use_color); + else + _cogl_multitexture_unsliced_polygon (vertices, + n_vertices, + n_layers, + stride, + use_color, + fallback_mask); + + /* Reset the size of the logged vertex array because rendering + rectangles expects it to start at 0 */ + g_array_set_size (ctx->logged_vertices, 0); +} + void cogl_path_fill (void) { diff --git a/gl/cogl-texture-private.h b/gl/cogl-texture-private.h index 59bcad108..d4e4f2437 100644 --- a/gl/cogl-texture-private.h +++ b/gl/cogl-texture-private.h @@ -39,6 +39,23 @@ struct _CoglTexSliceSpan gint waste; }; +struct _CoglSpanIter +{ + gint index; + GArray *array; + CoglTexSliceSpan *span; + float pos; + float next_pos; + float origin; + float cover_start; + float cover_end; + float intersect_start; + float intersect_end; + float intersect_start_local; + float intersect_end_local; + gboolean intersects; +}; + struct _CoglTexture { guint ref_count; @@ -73,9 +90,26 @@ typedef struct _CoglJournalEntry CoglTexture* _cogl_texture_pointer_from_handle (CoglHandle handle); +void +_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, + GLenum wrap_mode); + 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); + #endif /* __COGL_TEXTURE_H */ diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 0c6a2a370..9758e9491 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -66,29 +66,12 @@ #endif -static void _cogl_journal_flush (void); +extern void _cogl_journal_flush (void); static void _cogl_texture_free (CoglTexture *tex); COGL_HANDLE_DEFINE (Texture, texture, texture_handles); -struct _CoglSpanIter -{ - gint index; - GArray *array; - CoglTexSliceSpan *span; - float pos; - float next_pos; - float origin; - float cover_start; - float cover_end; - float intersect_start; - float intersect_end; - float intersect_start_local; - float intersect_end_local; - gboolean intersects; -}; - static void _cogl_texture_bitmap_free (CoglTexture *tex) { @@ -146,7 +129,7 @@ _cogl_span_iter_update (CoglSpanIter *iter) iter->intersect_end = iter->next_pos; } -static void +void _cogl_span_iter_begin (CoglSpanIter *iter, GArray *array, float origin, @@ -179,7 +162,7 @@ _cogl_span_iter_next (CoglSpanIter *iter) _cogl_span_iter_update (iter); } -static gboolean +gboolean _cogl_span_iter_end (CoglSpanIter *iter) { /* End reached when whole area covered */ @@ -781,7 +764,7 @@ _cogl_texture_size_supported (GLenum gl_target, } } -static void +void _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode) { @@ -1955,1239 +1938,3 @@ cogl_texture_get_data (CoglHandle handle, return byte_size; } - -/****************************************************************************** - * XXX: Here ends the code that strictly implements "CoglTextures". - * - * The following consists of code for rendering rectangles and polygons. It - * might be neater to move this code somewhere else. I think everything below - * here should be implementable without access to CoglTexture internals, but - * that will at least mean exposing the cogl_span_iter_* funcs. - */ - -static void -_cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, - gint batch_len, - GLfloat *vertex_pointer) -{ - int needed_indices; - gsize stride; - int i; - gulong enable_flags = 0; - guint32 disable_mask; - int prev_n_texcoord_arrays_enabled; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* The indices are always the same sequence regardless of the vertices so we - * only need to change it if there are more vertices than ever before. */ - needed_indices = batch_len * 6; - if (needed_indices > ctx->static_indices->len) - { - int old_len = ctx->static_indices->len; - int vert_num = old_len / 6 * 4; - GLushort *q; - - /* Add two triangles for each quad to the list of - indices. That makes six new indices but two of the - vertices in the triangles are shared. */ - g_array_set_size (ctx->static_indices, needed_indices); - q = &g_array_index (ctx->static_indices, GLushort, old_len); - - for (i = old_len; - i < ctx->static_indices->len; - i += 6, vert_num += 4) - { - *(q++) = vert_num + 0; - *(q++) = vert_num + 1; - *(q++) = vert_num + 3; - - *(q++) = vert_num + 1; - *(q++) = vert_num + 2; - *(q++) = vert_num + 3; - } - } - - /* XXX NB: - * Our vertex data is arranged as follows: - * 4 vertices per quad: 2 GLfloats per position, - * 2 GLfloats per tex coord * n_layers - */ - stride = 2 + 2 * batch_start->n_layers; - stride *= sizeof (GLfloat); - - disable_mask = (1 << batch_start->n_layers) - 1; - disable_mask = ~disable_mask; - - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - batch_start->fallback_mask, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - disable_mask, - /* Redundant when dealing with unsliced - * textures but does no harm... */ - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, - batch_start->layer0_override_texture, - NULL); - - for (i = 0; i < batch_start->n_layers; i++) - { - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); - GE (glTexCoordPointer (2, GL_FLOAT, stride, vertex_pointer + 2 + 2 * i)); - } - prev_n_texcoord_arrays_enabled = - ctx->n_texcoord_arrays_enabled; - ctx->n_texcoord_arrays_enabled = i + 1; - for (; i < prev_n_texcoord_arrays_enabled; i++) - { - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); - } - - /* FIXME: This api is a bit yukky, ideally it will be removed if we - * re-work the cogl_enable mechanism */ - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); - - if (ctx->enable_backface_culling) - enable_flags |= COGL_ENABLE_BACKFACE_CULLING; - - enable_flags |= COGL_ENABLE_VERTEX_ARRAY; - cogl_enable (enable_flags); - - GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); - _cogl_current_matrix_state_flush (); - GE (glDrawRangeElements (GL_TRIANGLES, - 0, ctx->static_indices->len - 1, - 6 * batch_len, - GL_UNSIGNED_SHORT, - ctx->static_indices->data)); - - - /* DEBUGGING CODE XXX: - * Uncommenting this will cause all rectangles to be drawn with a red, green - * or blue outline with no blending. This may e.g. help with debugging - * texture slicing issues or blending issues, plus it looks quite cool. - */ -#if 0 - { - static CoglHandle outline = COGL_INVALID_HANDLE; - static int color = 0; - if (outline == COGL_INVALID_HANDLE) - outline = cogl_material_new (); - - cogl_enable (COGL_ENABLE_VERTEX_ARRAY); - for (i = 0; i < batch_len; i++, color = (++color) % 3) - { - cogl_material_set_color4ub (outline, - color == 0 ? 0xff : 0x00, - color == 1 ? 0xff : 0x00, - color == 2 ? 0xff : 0x00, - 0xff); - cogl_material_flush_gl_state (outline, NULL); - _cogl_current_matrix_state_flush (); - GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) ); - } - } -#endif -} - -static void -_cogl_journal_flush (void) -{ - GLfloat *current_vertex_pointer; - GLfloat *batch_vertex_pointer; - CoglJournalEntry *batch_start; - guint batch_len; - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (ctx->journal->len == 0) - return; - - /* Current non-variables / constraints: - * - * - We don't have to worry about much GL state changing between journal - * entries since currently the journal never out lasts a single call to - * _cogl_multitexture_multiple_rectangles. So the user doesn't get the - * chance to fiddle with anything. (XXX: later this will be extended at - * which point we can start logging certain state changes) - * - * - Implied from above: all entries will refer to the same material. - * - * - Although _cogl_multitexture_multiple_rectangles can cause the wrap mode - * of textures to be modified, the journal is flushed if a wrap mode is - * changed so we don't currently have to log wrap mode changes. - * - * - XXX - others? - */ - - /* TODO: "compile" the journal to find ways of batching draw calls and vertex - * data. - * - * Simple E.g. given current constraints... - * pass 0 - load all data into a single CoglVertexBuffer - * pass 1 - batch gl draw calls according to entries that use the same - * textures. - * - * We will be able to do cooler stuff here when we extend the life of - * journals beyond _cogl_multitexture_multiple_rectangles. - */ - - batch_vertex_pointer = (GLfloat *)ctx->logged_vertices->data; - batch_start = (CoglJournalEntry *)ctx->journal->data; - batch_len = 1; - - current_vertex_pointer = batch_vertex_pointer; - - for (i = 1; i < ctx->journal->len; i++) - { - CoglJournalEntry *prev_entry = - &g_array_index (ctx->journal, CoglJournalEntry, i - 1); - CoglJournalEntry *current_entry = prev_entry + 1; - gsize stride; - - /* Progress the vertex pointer to the next quad */ - stride = 2 + current_entry->n_layers * 2; - current_vertex_pointer += stride * 4; - - /* batch rectangles using the same textures */ - if (current_entry->material == prev_entry->material && - current_entry->n_layers == prev_entry->n_layers && - current_entry->fallback_mask == prev_entry->fallback_mask && - current_entry->layer0_override_texture - == prev_entry->layer0_override_texture) - { - batch_len++; - continue; - } - - _cogl_journal_flush_quad_batch (batch_start, - batch_len, - batch_vertex_pointer); - - batch_start = current_entry; - batch_len = 1; - batch_vertex_pointer = current_vertex_pointer; - } - - /* The last batch... */ - _cogl_journal_flush_quad_batch (batch_start, - batch_len, - batch_vertex_pointer); - - - g_array_set_size (ctx->journal, 0); - g_array_set_size (ctx->logged_vertices, 0); -} - -static void -_cogl_journal_log_quad (float x_1, - float y_1, - float x_2, - float y_2, - CoglHandle material, - gint n_layers, - guint32 fallback_mask, - GLuint layer0_override_texture, - float *tex_coords, - guint tex_coords_len) -{ - int stride; - int next_vert; - GLfloat *v; - int i; - int next_entry; - CoglJournalEntry *entry; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* The vertex data is logged into a seperate array in a layout that can be - * directly passed to OpenGL - */ - - /* We pack the vertex data as 2 (x,y) GLfloats folowed by 2 (tx,ty) GLfloats - * for each texture being used, E.g.: - * [X, Y, TX0, TY0, TX1, TY1, X, Y, TX0, TY0, X, Y, ...] - */ - stride = 2 + n_layers * 2; - - next_vert = ctx->logged_vertices->len; - g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride); - v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert); - - /* XXX: All the jumping around to fill in this strided buffer doesn't - * seem ideal. */ - - /* XXX: we could defer expanding the vertex data for GL until we come - * to flushing the journal. */ - - v[0] = x_1; v[1] = y_1; - v += stride; - v[0] = x_1; v[1] = y_2; - v += stride; - v[0] = x_2; v[1] = y_2; - v += stride; - v[0] = x_2; v[1] = y_1; - - for (i = 0; i < n_layers; i++) - { - GLfloat *t = - &g_array_index (ctx->logged_vertices, GLfloat, next_vert + 2 + 2 * i); - - t[0] = tex_coords[0]; t[1] = tex_coords[1]; - t += stride; - t[0] = tex_coords[0]; t[1] = tex_coords[3]; - t += stride; - t[0] = tex_coords[2]; t[1] = tex_coords[3]; - t += stride; - t[0] = tex_coords[2]; t[1] = tex_coords[1]; - } - - next_entry = ctx->journal->len; - g_array_set_size (ctx->journal, next_entry + 1); - entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry); - - entry->material = material; - entry->n_layers = n_layers; - entry->fallback_mask = fallback_mask; - entry->layer0_override_texture = layer0_override_texture; -} - -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) -{ - 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; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - -#if COGL_DEBUG - printf("=== Drawing Tex Quad (Sliced Mode) ===\n"); -#endif - - /* 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); - - /* 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; - } - - /* Scale ratio from texture to quad widths */ - tw = (float)(tex->bitmap.width); - th = (float)(tex->bitmap.height); - - tqx = (x_2 - x_1) / (tw * (tx_2 - tx_1)); - tqy = (y_2 - y_1) / (th * (ty_2 - ty_1)); - - /* Integral texture coordinate for first tile */ - first_tx = (float)(floorf (tx_1)); - first_ty = (float)(floorf (ty_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); - - /* Quad coordinate of the first tile */ - first_qx = x_1 - (tx_1 - first_tx) * tqx; - first_qy = y_1 - (ty_1 - first_ty) * tqy; - - - /* 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 (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB) - { - 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 (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB) - { - slice_tx1 /= iter_x.span->size; - slice_tx2 /= iter_x.span->size; - } - -#if COGL_DEBUG - printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index); - printf("qx1: %f\n", (slice_qx1)); - printf("qy1: %f\n", (slice_qy1)); - printf("qx2: %f\n", (slice_qx2)); - printf("qy2: %f\n", (slice_qy2)); - printf("tx1: %f\n", (slice_tx1)); - printf("ty1: %f\n", (slice_ty1)); - printf("tx2: %f\n", (slice_tx2)); - printf("ty2: %f\n", (slice_ty2)); -#endif - - /* 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); - } - } -} - -static gboolean -_cogl_multitexture_unsliced_quad (float x_1, - float y_1, - float x_2, - float y_2, - CoglHandle material, - gint n_layers, - guint32 fallback_mask, - const float *user_tex_coords, - gint user_tex_coords_len) -{ - float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers); - const GList *layers; - GList *tmp; - int i; - - _COGL_GET_CONTEXT (ctx, FALSE); - - /* - * Validate the texture coordinates for this rectangle. - */ - layers = cogl_material_get_layers (material); - for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) - { - CoglHandle layer = (CoglHandle)tmp->data; - /* CoglLayerInfo *layer_info; */ - CoglHandle tex_handle; - CoglTexture *tex; - const float *in_tex_coords; - float *out_tex_coords; - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; - - /* layer_info = &layers[i]; */ - - /* FIXME - we shouldn't be checking this stuff if layer_info->gl_texture - * already == 0 */ - - tex_handle = cogl_material_layer_get_texture (layer); - tex = _cogl_texture_pointer_from_handle (tex_handle); - - in_tex_coords = &user_tex_coords[i * 4]; - out_tex_coords = &final_tex_coords[i * 4]; - - - /* If the texture has waste or we are using GL_TEXTURE_RECT we - * 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. - */ - if ((tex->gl_target == GL_TEXTURE_RECTANGLE_ARB - || _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 (i == 0) - { - if (n_layers > 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 " - "layer 0 is the most important one keep"); - warning_seen = TRUE; - } - return FALSE; - } - else - { - 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); - warning_seen = TRUE; - - /* NB: marking for fallback will replace the layer with - * a default transparent texture */ - fallback_mask |= (1 << i); - } - } - - - /* - * Setup the texture unit... - */ - - /* NB: The user might not have supplied texture coordinates for all - * layers... */ - if (i < (user_tex_coords_len / 4)) - { - GLenum wrap_mode; - - /* If the texture coords are all in the range [0,1] then we want to - clamp the coords to the edge otherwise it can pull in edge pixels - from the wrong side when scaled */ - if (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) - wrap_mode = GL_CLAMP_TO_EDGE; - else - wrap_mode = GL_REPEAT; - - memcpy (out_tex_coords, in_tex_coords, sizeof (GLfloat) * 4); - - _cogl_texture_set_wrap_mode_parameter (tex, 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 */ - - _cogl_texture_set_wrap_mode_parameter (tex, 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; - - /* 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; - } - } - - _cogl_journal_log_quad (x_1, - y_1, - x_2, - y_2, - material, - n_layers, - fallback_mask, - 0, /* don't replace the layer0 texture */ - final_tex_coords, - n_layers * 4); - - return TRUE; -} - -struct _CoglMutiTexturedRect -{ - float x_1; - float y_1; - float x_2; - float y_2; - const float *tex_coords; - gint tex_coords_len; -}; - -static void -_cogl_rectangles_with_multitexture_coords ( - struct _CoglMutiTexturedRect *rects, - gint n_rects) -{ - CoglHandle material; - const GList *layers; - int n_layers; - const GList *tmp; - guint32 fallback_mask = 0; - gboolean all_use_sliced_quad_fallback = FALSE; - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - cogl_clip_ensure (); - - material = ctx->source_material; - - layers = cogl_material_get_layers (material); - n_layers = g_list_length ((GList *)layers); - - /* - * Validate all the layers of the current source material... - */ - - for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++) - { - CoglHandle layer = tmp->data; - CoglHandle tex_handle = cogl_material_layer_get_texture (layer); - CoglTexture *texture = _cogl_texture_pointer_from_handle (tex_handle); - gulong flags; - - if (cogl_material_layer_get_type (layer) - != COGL_MATERIAL_LAYER_TYPE_TEXTURE) - continue; - - /* XXX: - * For now, if the first layer is sliced then all other layers are - * ignored since we currently don't support multi-texturing with - * sliced textures. If the first layer is not sliced then any other - * layers found to be sliced will be skipped. (with a warning) - * - * TODO: Add support for multi-texturing rectangles with sliced - * textures if no texture matrices are in use. - */ - if (cogl_texture_is_sliced (tex_handle)) - { - if (i == 0) - { - fallback_mask = ~1; /* fallback all except the first layer */ - all_use_sliced_quad_fallback = TRUE; - if (tmp->next) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - g_warning ("Skipping layers 1..n of your material since " - "the first layer is sliced. We don't currently " - "support any multi-texturing with sliced " - "textures but assume layer 0 is the most " - "important to keep"); - warning_seen = TRUE; - } - break; - } - else - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - g_warning ("Skipping layer %d of your material consisting of " - "a sliced texture (unsuported for multi texturing)", - i); - warning_seen = TRUE; - - /* NB: marking for fallback will replace the layer with - * a default transparent texture */ - fallback_mask |= (1 << i); - continue; - } - } - - /* 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. */ - flags = cogl_material_layer_get_flags (layer); - if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX - && _cogl_texture_span_has_waste (texture, 0, 0)) - { - 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); - warning_seen = TRUE; - - /* NB: marking for fallback will replace the layer with - * a default transparent texture */ - fallback_mask |= (1 << i); - continue; - } - } - - /* - * Emit geometry for each of the rectangles... - */ - - 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, - n_layers, - fallback_mask, - rects[i].tex_coords, - rects[i].tex_coords_len)) - { - CoglHandle first_layer, tex_handle; - CoglTexture *texture; - - 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); - } - } - - _cogl_journal_flush (); -} - -void -cogl_rectangles (const float *verts, - guint n_rects) -{ - struct _CoglMutiTexturedRect rects[n_rects]; - int i; - - for (i = 0; i < n_rects; i++) - { - rects[i].x_1 = verts[i * 4]; - rects[i].y_1 = verts[i * 4 + 1]; - rects[i].x_2 = verts[i * 4 + 2]; - rects[i].y_2 = verts[i * 4 + 3]; - rects[i].tex_coords = NULL; - rects[i].tex_coords_len = 0; - } - - _cogl_rectangles_with_multitexture_coords (rects, n_rects); -} - -void -cogl_rectangles_with_texture_coords (const float *verts, - guint n_rects) -{ - struct _CoglMutiTexturedRect rects[n_rects]; - int i; - - for (i = 0; i < n_rects; i++) - { - rects[i].x_1 = verts[i * 8]; - rects[i].y_1 = verts[i * 8 + 1]; - rects[i].x_2 = verts[i * 8 + 2]; - rects[i].y_2 = verts[i * 8 + 3]; - /* FIXME: rect should be defined to have a const float *geom; - * instead, to avoid this copy - * rect[i].geom = &verts[n_rects * 8]; */ - rects[i].tex_coords = &verts[i * 8 + 4]; - rects[i].tex_coords_len = 4; - } - - _cogl_rectangles_with_multitexture_coords (rects, n_rects); -} - -void -cogl_rectangle_with_texture_coords (float x_1, - float y_1, - float x_2, - float y_2, - float tx_1, - float ty_1, - float tx_2, - float ty_2) -{ - float verts[8]; - - verts[0] = x_1; - verts[1] = y_1; - verts[2] = x_2; - verts[3] = y_2; - verts[4] = tx_1; - verts[5] = ty_1; - verts[6] = tx_2; - verts[7] = ty_2; - - cogl_rectangles_with_texture_coords (verts, 1); -} - -void -cogl_rectangle_with_multitexture_coords (float x_1, - float y_1, - float x_2, - float y_2, - const float *user_tex_coords, - gint user_tex_coords_len) -{ - struct _CoglMutiTexturedRect rect; - - rect.x_1 = x_1; - rect.y_1 = y_1; - rect.x_2 = x_2; - rect.y_2 = y_2; - rect.tex_coords = user_tex_coords; - rect.tex_coords_len = user_tex_coords_len; - - _cogl_rectangles_with_multitexture_coords (&rect, 1); -} - -static void -_cogl_texture_sliced_polygon (CoglTextureVertex *vertices, - guint n_vertices, - guint stride, - gboolean use_color) -{ - 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; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* We can assume in this case that we have at least one layer in the - * material that corresponds to a sliced cogl texture */ - 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++) - { - GLfloat *c; - - v[0] = vertices[i].x; - v[1] = vertices[i].y; - v[2] = vertices[i].z; - - /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ - c = v + 5; - c[0] = cogl_color_get_red_byte (&vertices[i].color); - c[1] = cogl_color_get_green_byte (&vertices[i].color); - c[2] = cogl_color_get_blue_byte (&vertices[i].color); - c[3] = cogl_color_get_alpha_byte (&vertices[i].color); - - 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); - - 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); - - /* Scale the coordinates up for rectangle textures */ - if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB) - { - tx *= x_span->size; - ty *= y_span->size; - } - - /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ - t = v + 3; - t[0] = tx; - t[1] = ty; - - v += stride; - } - - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - (guint32)~1, /* disable all except the - first layer */ - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, - gl_handle, - NULL); - _cogl_current_matrix_state_flush (); - - GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); - } - } -} - - -static void -_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, - guint n_vertices, - guint n_layers, - guint stride, - gboolean use_color, - guint32 fallback_mask) -{ - CoglHandle material; - const GList *layers; - int i; - GList *tmp; - CoglTexSliceSpan *y_span, *x_span; - GLfloat *v; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - - material = ctx->source_material; - layers = cogl_material_get_layers (material); - - /* Convert the vertices into an array of GLfloats ready to pass to - OpenGL */ - for (v = (GLfloat *)ctx->logged_vertices->data, i = 0; - i < n_vertices; - v += stride, i++) - { - GLfloat *c; - int j; - - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - v[0] = vertices[i].x; - v[1] = vertices[i].y; - v[2] = vertices[i].z; - - for (tmp = (GList *)layers, j = 0; tmp != NULL; tmp = tmp->next, j++) - { - CoglHandle layer = (CoglHandle)tmp->data; - CoglHandle tex_handle; - CoglTexture *tex; - GLfloat *t; - float tx, ty; - - tex_handle = cogl_material_layer_get_texture (layer); - 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); - - /* Scale the coordinates up for rectangle textures */ - if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB) - { - tx *= x_span->size; - ty *= y_span->size; - } - - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - t = v + 3 + 2 * j; - t[0] = tx; - t[1] = ty; - } - - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - c = v + 3 + 2 * n_layers; - c[0] = cogl_color_get_red_float (&vertices[i].color); - c[1] = cogl_color_get_green_float (&vertices[i].color); - c[2] = cogl_color_get_blue_float (&vertices[i].color); - c[3] = cogl_color_get_alpha_float (&vertices[i].color); - } - - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - fallback_mask, - NULL); - _cogl_current_matrix_state_flush (); - - GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); -} - -void -cogl_polygon (CoglTextureVertex *vertices, - guint n_vertices, - gboolean use_color) -{ - CoglHandle material; - const GList *layers; - int n_layers; - GList *tmp; - gboolean use_sliced_polygon_fallback = FALSE; - guint32 fallback_mask = 0; - int i; - gulong enable_flags; - guint stride; - gsize stride_bytes; - GLfloat *v; - int prev_n_texcoord_arrays_enabled; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - cogl_clip_ensure (); - - material = ctx->source_material; - layers = cogl_material_get_layers (ctx->source_material); - n_layers = g_list_length ((GList *)layers); - - for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) - { - CoglHandle layer = (CoglHandle)tmp->data; - CoglHandle tex_handle = cogl_material_layer_get_texture (layer); - CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); - - if (i == 0 && cogl_texture_is_sliced (tex_handle)) - { -#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - g_warning ("cogl_polygon does not work for sliced textures " - "on GL ES"); - warning_seen = TRUE; - return; - } -#endif - if (n_layers > 1) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - { - g_warning ("Disabling layers 1..n since multi-texturing with " - "cogl_polygon isn't supported when using sliced " - "textures\n"); - warning_seen = TRUE; - } - } - use_sliced_polygon_fallback = TRUE; - n_layers = 1; - - if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - { - g_warning ("cogl_texture_polygon does not work for sliced textures " - "when the minification and magnification filters are not " - "CGL_NEAREST"); - warning_seen = TRUE; - } - return; - } - -#ifdef HAVE_COGL_GL - /* 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); -#endif - break; - } - - if (cogl_texture_is_sliced (tex_handle)) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - g_warning ("Disabling layer %d of the current source material, " - "because texturing with the vertex buffer API is not " - "currently supported using sliced textures, or " - "textures with waste\n", i); - warning_seen = TRUE; - - fallback_mask |= (1 << i); - continue; - } - } - - /* Our data is arranged like: - * [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */ - stride = 3 + (2 * n_layers) + (use_color ? 4 : 0); - stride_bytes = stride * sizeof (GLfloat); - - /* Make sure there is enough space in the global vertex - array. This is used so we can render the polygon with a single - call to OpenGL but still support any number of vertices */ - g_array_set_size (ctx->logged_vertices, n_vertices * stride); - v = (GLfloat *)ctx->logged_vertices->data; - - /* Prepare GL state */ - enable_flags = COGL_ENABLE_VERTEX_ARRAY; - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); - - if (ctx->enable_backface_culling) - enable_flags |= COGL_ENABLE_BACKFACE_CULLING; - - if (use_color) - { - enable_flags |= COGL_ENABLE_COLOR_ARRAY; - GE( glColorPointer (4, GL_FLOAT, - stride_bytes, - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - v + 3 + 2 * n_layers) ); - } - - cogl_enable (enable_flags); - - GE (glVertexPointer (3, GL_FLOAT, stride_bytes, v)); - - for (i = 0; i < n_layers; i++) - { - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); - GE (glTexCoordPointer (2, GL_FLOAT, - stride_bytes, - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - v + 3 + 2 * i)); - } - prev_n_texcoord_arrays_enabled = - ctx->n_texcoord_arrays_enabled; - ctx->n_texcoord_arrays_enabled = i + 1; - for (; i < prev_n_texcoord_arrays_enabled; i++) - { - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); - } - - if (use_sliced_polygon_fallback) - _cogl_texture_sliced_polygon (vertices, - n_vertices, - stride, - use_color); - else - _cogl_multitexture_unsliced_polygon (vertices, - n_vertices, - n_layers, - stride, - use_color, - fallback_mask); - - /* Reset the size of the logged vertex array because rendering - rectangles expects it to start at 0 */ - g_array_set_size (ctx->logged_vertices, 0); -} - diff --git a/gles/cogl-texture-private.h b/gles/cogl-texture-private.h index 59bcad108..d4e4f2437 100644 --- a/gles/cogl-texture-private.h +++ b/gles/cogl-texture-private.h @@ -39,6 +39,23 @@ struct _CoglTexSliceSpan gint waste; }; +struct _CoglSpanIter +{ + gint index; + GArray *array; + CoglTexSliceSpan *span; + float pos; + float next_pos; + float origin; + float cover_start; + float cover_end; + float intersect_start; + float intersect_end; + float intersect_start_local; + float intersect_end_local; + gboolean intersects; +}; + struct _CoglTexture { guint ref_count; @@ -73,9 +90,26 @@ typedef struct _CoglJournalEntry CoglTexture* _cogl_texture_pointer_from_handle (CoglHandle handle); +void +_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, + GLenum wrap_mode); + 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); + #endif /* __COGL_TEXTURE_H */ diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index 575829336..204948ce5 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -53,44 +53,12 @@ printf("err: 0x%x\n", err); \ } */ -#ifdef HAVE_COGL_GL - -#define glDrawRangeElements ctx->pf_glDrawRangeElements -#define glActiveTexture ctx->pf_glActiveTexture -#define glClientActiveTexture ctx->pf_glClientActiveTexture - -#else - -/* GLES doesn't have glDrawRangeElements, so we simply pretend it does - * but that it makes no use of the start, end constraints: */ -#define glDrawRangeElements(mode, start, end, count, type, indices) \ - glDrawElements (mode, count, type, indices) - -#endif - -static void _cogl_journal_flush (void); +extern void _cogl_journal_flush (void); static void _cogl_texture_free (CoglTexture *tex); COGL_HANDLE_DEFINE (Texture, texture, texture_handles); -struct _CoglSpanIter -{ - gint index; - GArray *array; - CoglTexSliceSpan *span; - float pos; - float next_pos; - float origin; - float cover_start; - float cover_end; - float intersect_start; - float intersect_end; - float intersect_start_local; - float intersect_end_local; - gboolean intersects; -}; - static void _cogl_texture_bitmap_free (CoglTexture *tex) { @@ -148,7 +116,7 @@ _cogl_span_iter_update (CoglSpanIter *iter) iter->intersect_end = iter->next_pos; } -static void +void _cogl_span_iter_begin (CoglSpanIter *iter, GArray *array, float origin, @@ -181,7 +149,7 @@ _cogl_span_iter_next (CoglSpanIter *iter) _cogl_span_iter_update (iter); } -static gboolean +gboolean _cogl_span_iter_end (CoglSpanIter *iter) { /* End reached when whole area covered */ @@ -953,7 +921,7 @@ _cogl_texture_size_supported (GLenum gl_target, return TRUE; } -static void +void _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode) { @@ -2068,1207 +2036,3 @@ cogl_texture_get_data (CoglHandle handle, return byte_size; } - -/****************************************************************************** - * XXX: Here ends the code that strictly implements "CoglTextures". - * - * The following consists of code for rendering rectangles and polygons. It - * might be neater to move this code somewhere else. I think everything below - * here should be implementable without access to CoglTexture internals, but - * that will at least mean exposing the cogl_span_iter_* funcs. - */ - -static void -_cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, - gint batch_len, - GLfloat *vertex_pointer) -{ - int needed_indices; - gsize stride; - int i; - gulong enable_flags = 0; - guint32 disable_mask; - int prev_n_texcoord_arrays_enabled; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* The indices are always the same sequence regardless of the vertices so we - * only need to change it if there are more vertices than ever before. */ - needed_indices = batch_len * 6; - if (needed_indices > ctx->static_indices->len) - { - int old_len = ctx->static_indices->len; - int vert_num = old_len / 6 * 4; - GLushort *q; - - /* Add two triangles for each quad to the list of - indices. That makes six new indices but two of the - vertices in the triangles are shared. */ - g_array_set_size (ctx->static_indices, needed_indices); - q = &g_array_index (ctx->static_indices, GLushort, old_len); - - for (i = old_len; - i < ctx->static_indices->len; - i += 6, vert_num += 4) - { - *(q++) = vert_num + 0; - *(q++) = vert_num + 1; - *(q++) = vert_num + 3; - - *(q++) = vert_num + 1; - *(q++) = vert_num + 2; - *(q++) = vert_num + 3; - } - } - - /* XXX NB: - * Our vertex data is arranged as follows: - * 4 vertices per quad: 2 GLfloats per position, - * 2 GLfloats per tex coord * n_layers - */ - stride = 2 + 2 * batch_start->n_layers; - stride *= sizeof (GLfloat); - - disable_mask = (1 << batch_start->n_layers) - 1; - disable_mask = ~disable_mask; - - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - batch_start->fallback_mask, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - disable_mask, - /* Redundant when dealing with unsliced - * textures but does no harm... */ - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, - batch_start->layer0_override_texture, - NULL); - - for (i = 0; i < batch_start->n_layers; i++) - { - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); - GE (glTexCoordPointer (2, GL_FLOAT, stride, vertex_pointer + 2 + 2 * i)); - } - prev_n_texcoord_arrays_enabled = - ctx->n_texcoord_arrays_enabled; - ctx->n_texcoord_arrays_enabled = i; - for (; i < prev_n_texcoord_arrays_enabled; i++) - { - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); - } - - /* FIXME: This api is a bit yukky, ideally it will be removed if we - * re-work the cogl_enable mechanism */ - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); - - if (ctx->enable_backface_culling) - enable_flags |= COGL_ENABLE_BACKFACE_CULLING; - - enable_flags |= COGL_ENABLE_VERTEX_ARRAY; - cogl_enable (enable_flags); - - GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); - _cogl_current_matrix_state_flush (); - GE (glDrawRangeElements (GL_TRIANGLES, - 0, ctx->static_indices->len - 1, - 6 * batch_len, - GL_UNSIGNED_SHORT, - ctx->static_indices->data)); - - - /* DEBUGGING CODE XXX: - * Uncommenting this will cause all rectangles to be drawn with a red, green - * or blue outline with no blending. This may e.g. help with debugging - * texture slicing issues or blending issues, plus it looks quite cool. - */ -#if 0 - { - static CoglHandle outline = COGL_INVALID_HANDLE; - static int color = 0; - if (outline == COGL_INVALID_HANDLE) - outline = cogl_material_new (); - - cogl_enable (COGL_ENABLE_VERTEX_ARRAY); - for (i = 0; i < batch_len; i++, color = (++color) % 3) - { - cogl_material_set_color4ub (outline, - color == 0 ? 0xff : 0x00, - color == 1 ? 0xff : 0x00, - color == 2 ? 0xff : 0x00, - 0xff); - cogl_material_flush_gl_state (outline, NULL); - _cogl_current_matrix_state_flush (); - GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) ); - } - } -#endif -} - -static void -_cogl_journal_flush (void) -{ - GLfloat *current_vertex_pointer; - GLfloat *batch_vertex_pointer; - CoglJournalEntry *batch_start; - guint batch_len; - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (ctx->journal->len == 0) - return; - - /* Current non-variables / constraints: - * - * - We don't have to worry about much GL state changing between journal - * entries since currently the journal never out lasts a single call to - * _cogl_multitexture_multiple_rectangles. So the user doesn't get the - * chance to fiddle with anything. (XXX: later this will be extended at - * which point we can start logging certain state changes) - * - * - Implied from above: all entries will refer to the same material. - * - * - Although _cogl_multitexture_multiple_rectangles can cause the wrap mode - * of textures to be modified, the journal is flushed if a wrap mode is - * changed so we don't currently have to log wrap mode changes. - * - * - XXX - others? - */ - - /* TODO: "compile" the journal to find ways of batching draw calls and vertex - * data. - * - * Simple E.g. given current constraints... - * pass 0 - load all data into a single CoglVertexBuffer - * pass 1 - batch gl draw calls according to entries that use the same - * textures. - * - * We will be able to do cooler stuff here when we extend the life of - * journals beyond _cogl_multitexture_multiple_rectangles. - */ - - batch_vertex_pointer = (GLfloat *)ctx->logged_vertices->data; - batch_start = (CoglJournalEntry *)ctx->journal->data; - batch_len = 1; - - current_vertex_pointer = batch_vertex_pointer; - - for (i = 1; i < ctx->journal->len; i++) - { - CoglJournalEntry *prev_entry = - &g_array_index (ctx->journal, CoglJournalEntry, i - 1); - CoglJournalEntry *current_entry = prev_entry + 1; - gsize stride; - - /* Progress the vertex pointer to the next quad */ - stride = 2 + current_entry->n_layers * 2; - current_vertex_pointer += stride * 4; - - /* batch rectangles using the same textures */ - if (current_entry->material == prev_entry->material && - current_entry->n_layers == prev_entry->n_layers && - current_entry->fallback_mask == prev_entry->fallback_mask && - current_entry->layer0_override_texture - == prev_entry->layer0_override_texture) - { - batch_len++; - continue; - } - - _cogl_journal_flush_quad_batch (batch_start, - batch_len, - batch_vertex_pointer); - - batch_start = current_entry; - batch_len = 1; - batch_vertex_pointer = current_vertex_pointer; - } - - /* The last batch... */ - _cogl_journal_flush_quad_batch (batch_start, - batch_len, - batch_vertex_pointer); - - - g_array_set_size (ctx->journal, 0); - g_array_set_size (ctx->logged_vertices, 0); -} - -static void -_cogl_journal_log_quad (float x_1, - float y_1, - float x_2, - float y_2, - CoglHandle material, - gint n_layers, - guint32 fallback_mask, - GLuint layer0_override_texture, - float *tex_coords, - guint tex_coords_len) -{ - int stride; - int next_vert; - GLfloat *v; - int i; - int next_entry; - CoglJournalEntry *entry; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* The vertex data is logged into a seperate array in a layout that can be - * directly passed to OpenGL - */ - - /* We pack the vertex data as 2 (x,y) GLfloats folowed by 2 (tx,ty) GLfloats - * for each texture being used, E.g.: - * [X, Y, TX0, TY0, TX1, TY1, X, Y, TX0, TY0, X, Y, ...] - */ - stride = 2 + n_layers * 2; - - next_vert = ctx->logged_vertices->len; - g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride); - v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert); - - /* XXX: All the jumping around to fill in this strided buffer doesn't - * seem ideal. */ - - /* XXX: we could defer expanding the vertex data for GL until we come - * to flushing the journal. */ - - v[0] = x_1; v[1] = y_1; - v += stride; - v[0] = x_1; v[1] = y_2; - v += stride; - v[0] = x_2; v[1] = y_2; - v += stride; - v[0] = x_2; v[1] = y_1; - - for (i = 0; i < n_layers; i++) - { - GLfloat *t = - &g_array_index (ctx->logged_vertices, GLfloat, next_vert + 2 + 2 * i); - - t[0] = tex_coords[0]; t[1] = tex_coords[1]; - t += stride; - t[0] = tex_coords[0]; t[1] = tex_coords[3]; - t += stride; - t[0] = tex_coords[2]; t[1] = tex_coords[3]; - t += stride; - t[0] = tex_coords[2]; t[1] = tex_coords[1]; - } - - next_entry = ctx->journal->len; - g_array_set_size (ctx->journal, next_entry + 1); - entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry); - - entry->material = material; - entry->n_layers = n_layers; - entry->fallback_mask = fallback_mask; - entry->layer0_override_texture = layer0_override_texture; -} - -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) -{ - 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; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - -#if COGL_DEBUG - printf("=== Drawing Tex Quad (Sliced Mode) ===\n"); -#endif - - /* 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); - - /* 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; - } - - /* Scale ratio from texture to quad widths */ - tw = (float)(tex->bitmap.width); - th = (float)(tex->bitmap.height); - - tqx = (x_2 - x_1) / (tw * (tx_2 - tx_1)); - tqy = (y_2 - y_1) / (th * (ty_2 - ty_1)); - - /* Integral texture coordinate for first tile */ - first_tx = (float)(floorf (tx_1)); - first_ty = (float)(floorf (ty_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); - - /* Quad coordinate of the first tile */ - first_qx = x_1 - (tx_1 - first_tx) * tqx; - first_qy = y_1 - (ty_1 - first_ty) * tqy; - - - /* 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; - - 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) */ - slice_tx1 /= iter_x.span->size; - slice_tx2 /= iter_x.span->size; - -#if COGL_DEBUG - printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index); - printf("qx1: %f\n", (slice_qx1)); - printf("qy1: %f\n", (slice_qy1)); - printf("qx2: %f\n", (slice_qx2)); - printf("qy2: %f\n", (slice_qy2)); - printf("tx1: %f\n", (slice_tx1)); - printf("ty1: %f\n", (slice_ty1)); - printf("tx2: %f\n", (slice_tx2)); - printf("ty2: %f\n", (slice_ty2)); -#endif - - /* 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); - } - } -} - -static gboolean -_cogl_multitexture_unsliced_quad (float x_1, - float y_1, - float x_2, - float y_2, - CoglHandle material, - gint n_layers, - guint32 fallback_mask, - const float *user_tex_coords, - gint user_tex_coords_len) -{ - float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers); - const GList *layers; - GList *tmp; - int i; - - _COGL_GET_CONTEXT (ctx, FALSE); - - /* - * Validate the texture coordinates for this rectangle. - */ - layers = cogl_material_get_layers (material); - for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) - { - CoglHandle layer = (CoglHandle)tmp->data; - /* CoglLayerInfo *layer_info; */ - CoglHandle tex_handle; - CoglTexture *tex; - const float *in_tex_coords; - float *out_tex_coords; - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; - - /* layer_info = &layers[i]; */ - - /* FIXME - we shouldn't be checking this stuff if layer_info->gl_texture - * already == 0 */ - - tex_handle = cogl_material_layer_get_texture (layer); - tex = _cogl_texture_pointer_from_handle (tex_handle); - - in_tex_coords = &user_tex_coords[i * 4]; - out_tex_coords = &final_tex_coords[i * 4]; - - - /* If the texture has waste or we are using GL_TEXTURE_RECT we - * 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. - */ - if (_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 (i == 0) - { - if (n_layers > 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 " - "layer 0 is the most important one keep"); - warning_seen = TRUE; - } - return FALSE; - } - else - { - 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); - warning_seen = TRUE; - - /* NB: marking for fallback will replace the layer with - * a default transparent texture */ - fallback_mask |= (1 << i); - } - } - - - /* - * Setup the texture unit... - */ - - /* NB: The user might not have supplied texture coordinates for all - * layers... */ - if (i < (user_tex_coords_len / 4)) - { - GLenum wrap_mode; - - /* If the texture coords are all in the range [0,1] then we want to - clamp the coords to the edge otherwise it can pull in edge pixels - from the wrong side when scaled */ - if (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) - wrap_mode = GL_CLAMP_TO_EDGE; - else - wrap_mode = GL_REPEAT; - - memcpy (out_tex_coords, in_tex_coords, sizeof (GLfloat) * 4); - - _cogl_texture_set_wrap_mode_parameter (tex, 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 */ - - _cogl_texture_set_wrap_mode_parameter (tex, 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; - } - - _cogl_journal_log_quad (x_1, - y_1, - x_2, - y_2, - material, - n_layers, - fallback_mask, - 0, /* don't replace the layer0 texture */ - final_tex_coords, - n_layers * 4); - - return TRUE; -} - -struct _CoglMutiTexturedRect -{ - float x_1; - float y_1; - float x_2; - float y_2; - const float *tex_coords; - gint tex_coords_len; -}; - -static void -_cogl_rectangles_with_multitexture_coords ( - struct _CoglMutiTexturedRect *rects, - gint n_rects) -{ - CoglHandle material; - const GList *layers; - int n_layers; - const GList *tmp; - guint32 fallback_mask = 0; - gboolean all_use_sliced_quad_fallback = FALSE; - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - cogl_clip_ensure (); - - material = ctx->source_material; - - layers = cogl_material_get_layers (material); - n_layers = g_list_length ((GList *)layers); - - /* - * Validate all the layers of the current source material... - */ - - for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++) - { - CoglHandle layer = tmp->data; - CoglHandle tex_handle = cogl_material_layer_get_texture (layer); - CoglTexture *texture = _cogl_texture_pointer_from_handle (tex_handle); - gulong flags; - - if (cogl_material_layer_get_type (layer) - != COGL_MATERIAL_LAYER_TYPE_TEXTURE) - continue; - - /* XXX: - * For now, if the first layer is sliced then all other layers are - * ignored since we currently don't support multi-texturing with - * sliced textures. If the first layer is not sliced then any other - * layers found to be sliced will be skipped. (with a warning) - * - * TODO: Add support for multi-texturing rectangles with sliced - * textures if no texture matrices are in use. - */ - if (cogl_texture_is_sliced (tex_handle)) - { - if (i == 0) - { - fallback_mask = ~1; /* fallback all except the first layer */ - all_use_sliced_quad_fallback = TRUE; - if (tmp->next) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - g_warning ("Skipping layers 1..n of your material since " - "the first layer is sliced. We don't currently " - "support any multi-texturing with sliced " - "textures but assume layer 0 is the most " - "important to keep"); - warning_seen = TRUE; - } - break; - } - else - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - g_warning ("Skipping layer %d of your material consisting of " - "a sliced texture (unsuported for multi texturing)", - i); - warning_seen = TRUE; - - /* NB: marking for fallback will replace the layer with - * a default transparent texture */ - fallback_mask |= (1 << i); - continue; - } - } - - /* 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. */ - flags = cogl_material_layer_get_flags (layer); - if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX - && _cogl_texture_span_has_waste (texture, 0, 0)) - { - 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); - warning_seen = TRUE; - - /* NB: marking for fallback will replace the layer with - * a default transparent texture */ - fallback_mask |= (1 << i); - continue; - } - } - - /* - * Emit geometry for each of the rectangles... - */ - - 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, - n_layers, - fallback_mask, - rects[i].tex_coords, - rects[i].tex_coords_len)) - { - CoglHandle first_layer, tex_handle; - CoglTexture *texture; - - 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); - } - } - - _cogl_journal_flush (); -} - -void -cogl_rectangles (const float *verts, - guint n_rects) -{ - struct _CoglMutiTexturedRect rects[n_rects]; - int i; - - for (i = 0; i < n_rects; i++) - { - rects[i].x_1 = verts[i * 4]; - rects[i].y_1 = verts[i * 4 + 1]; - rects[i].x_2 = verts[i * 4 + 2]; - rects[i].y_2 = verts[i * 4 + 3]; - rects[i].tex_coords = NULL; - rects[i].tex_coords_len = 0; - } - - _cogl_rectangles_with_multitexture_coords (rects, n_rects); -} - -void -cogl_rectangles_with_texture_coords (const float *verts, - guint n_rects) -{ - struct _CoglMutiTexturedRect rects[n_rects]; - int i; - - for (i = 0; i < n_rects; i++) - { - rects[i].x_1 = verts[i * 8]; - rects[i].y_1 = verts[i * 8 + 1]; - rects[i].x_2 = verts[i * 8 + 2]; - rects[i].y_2 = verts[i * 8 + 3]; - /* FIXME: rect should be defined to have a const float *geom; - * instead, to avoid this copy - * rect[i].geom = &verts[n_rects * 8]; */ - rects[i].tex_coords = &verts[i * 8 + 4]; - rects[i].tex_coords_len = 4; - } - - _cogl_rectangles_with_multitexture_coords (rects, n_rects); -} - -void -cogl_rectangle_with_texture_coords (float x_1, - float y_1, - float x_2, - float y_2, - float tx_1, - float ty_1, - float tx_2, - float ty_2) -{ - float verts[8]; - - verts[0] = x_1; - verts[1] = y_1; - verts[2] = x_2; - verts[3] = y_2; - verts[4] = tx_1; - verts[5] = ty_1; - verts[6] = tx_2; - verts[7] = ty_2; - - cogl_rectangles_with_texture_coords (verts, 1); -} - -void -cogl_rectangle_with_multitexture_coords (float x_1, - float y_1, - float x_2, - float y_2, - const float *user_tex_coords, - gint user_tex_coords_len) -{ - struct _CoglMutiTexturedRect rect; - - rect.x_1 = x_1; - rect.y_1 = y_1; - rect.x_2 = x_2; - rect.y_2 = y_2; - rect.tex_coords = user_tex_coords; - rect.tex_coords_len = user_tex_coords_len; - - _cogl_rectangles_with_multitexture_coords (&rect, 1); -} - -static void -_cogl_texture_sliced_polygon (CoglTextureVertex *vertices, - guint n_vertices, - guint stride, - gboolean use_color) -{ - 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; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* We can assume in this case that we have at least one layer in the - * material that corresponds to a sliced cogl texture */ - 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++) - { - GLfloat *c; - - v[0] = vertices[i].x; - v[1] = vertices[i].y; - v[2] = vertices[i].z; - - /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ - c = v + 5; - c[0] = cogl_color_get_red_byte (&vertices[i].color); - c[1] = cogl_color_get_green_byte (&vertices[i].color); - c[2] = cogl_color_get_blue_byte (&vertices[i].color); - c[3] = cogl_color_get_alpha_byte (&vertices[i].color); - - 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); - - 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); - - /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ - t = v + 3; - t[0] = tx; - t[1] = ty; - - v += stride; - } - - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - (guint32)~1, /* disable all except the - first layer */ - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, - gl_handle, - NULL); - _cogl_current_matrix_state_flush (); - - GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); - } - } -} - - -static void -_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, - guint n_vertices, - guint n_layers, - guint stride, - gboolean use_color, - guint32 fallback_mask) -{ - CoglHandle material; - const GList *layers; - int i; - GList *tmp; - CoglTexSliceSpan *y_span, *x_span; - GLfloat *v; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - - material = ctx->source_material; - layers = cogl_material_get_layers (material); - - /* Convert the vertices into an array of GLfloats ready to pass to - OpenGL */ - for (v = (GLfloat *)ctx->logged_vertices->data, i = 0; - i < n_vertices; - v += stride, i++) - { - GLfloat *c; - int j; - - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - v[0] = vertices[i].x; - v[1] = vertices[i].y; - v[2] = vertices[i].z; - - for (tmp = (GList *)layers, j = 0; tmp != NULL; tmp = tmp->next, j++) - { - CoglHandle layer = (CoglHandle)tmp->data; - CoglHandle tex_handle; - CoglTexture *tex; - GLfloat *t; - float tx, ty; - - tex_handle = cogl_material_layer_get_texture (layer); - 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); - - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - t = v + 3 + 2 * j; - t[0] = tx; - t[1] = ty; - } - - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - c = v + 3 + 2 * n_layers; - c[0] = cogl_color_get_red_float (&vertices[i].color); - c[1] = cogl_color_get_green_float (&vertices[i].color); - c[2] = cogl_color_get_blue_float (&vertices[i].color); - c[3] = cogl_color_get_alpha_float (&vertices[i].color); - } - - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - fallback_mask, - NULL); - _cogl_current_matrix_state_flush (); - - GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); -} - -void -cogl_polygon (CoglTextureVertex *vertices, - guint n_vertices, - gboolean use_color) -{ - CoglHandle material; - const GList *layers; - int n_layers; - GList *tmp; - gboolean use_sliced_polygon_fallback = FALSE; - guint32 fallback_mask = 0; - int i; - gulong enable_flags; - guint stride; - gsize stride_bytes; - GLfloat *v; - int prev_n_texcoord_arrays_enabled; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - cogl_clip_ensure (); - - material = ctx->source_material; - layers = cogl_material_get_layers (ctx->source_material); - n_layers = g_list_length ((GList *)layers); - - for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) - { - CoglHandle layer = (CoglHandle)tmp->data; - CoglHandle tex_handle = cogl_material_layer_get_texture (layer); - CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); - - if (i == 0 && cogl_texture_is_sliced (tex_handle)) - { -#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - g_warning ("cogl_polygon does not work for sliced textures " - "on GL ES"); - warning_seen = TRUE; - return; - } -#endif - if (n_layers > 1) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - { - g_warning ("Disabling layers 1..n since multi-texturing with " - "cogl_polygon isn't supported when using sliced " - "textures\n"); - warning_seen = TRUE; - } - } - use_sliced_polygon_fallback = TRUE; - n_layers = 1; - - if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - { - g_warning ("cogl_texture_polygon does not work for sliced textures " - "when the minification and magnification filters are not " - "CGL_NEAREST"); - warning_seen = TRUE; - } - return; - } - -#ifdef HAVE_COGL_GL - /* 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); -#endif - break; - } - - if (cogl_texture_is_sliced (tex_handle)) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - g_warning ("Disabling layer %d of the current source material, " - "because texturing with the vertex buffer API is not " - "currently supported using sliced textures, or " - "textures with waste\n", i); - warning_seen = TRUE; - - fallback_mask |= (1 << i); - continue; - } - } - - /* Our data is arranged like: - * [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */ - stride = 3 + (2 * n_layers) + (use_color ? 4 : 0); - stride_bytes = stride * sizeof (GLfloat); - - /* Make sure there is enough space in the global vertex - array. This is used so we can render the polygon with a single - call to OpenGL but still support any number of vertices */ - g_array_set_size (ctx->logged_vertices, n_vertices * stride); - v = (GLfloat *)ctx->logged_vertices->data; - - /* Prepare GL state */ - enable_flags = COGL_ENABLE_VERTEX_ARRAY; - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); - - if (ctx->enable_backface_culling) - enable_flags |= COGL_ENABLE_BACKFACE_CULLING; - - if (use_color) - { - enable_flags |= COGL_ENABLE_COLOR_ARRAY; - GE( glColorPointer (4, GL_FLOAT, - stride_bytes, - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - v + 3 + 2 * n_layers) ); - } - - cogl_enable (enable_flags); - - GE (glVertexPointer (3, GL_FLOAT, stride_bytes, v)); - - for (i = 0; i < n_layers; i++) - { - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); - GE (glTexCoordPointer (2, GL_FLOAT, - stride_bytes, - /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ - v + 3 + 2 * i)); - } - prev_n_texcoord_arrays_enabled = - ctx->n_texcoord_arrays_enabled; - ctx->n_texcoord_arrays_enabled = i + 1; - for (; i < prev_n_texcoord_arrays_enabled; i++) - { - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); - } - - if (use_sliced_polygon_fallback) - _cogl_texture_sliced_polygon (vertices, - n_vertices, - stride, - use_color); - else - _cogl_multitexture_unsliced_polygon (vertices, - n_vertices, - n_layers, - stride, - use_color, - fallback_mask); - - /* Reset the size of the logged vertex array because rendering - rectangles expects it to start at 0 */ - g_array_set_size (ctx->logged_vertices, 0); -} -