#include "cogl.h"
#include "cogl-internal.h"
#include "cogl-context.h"
+#include "cogl-texture-private.h"
+#include "cogl-material.h"
#include <string.h>
#include <gmodule.h>
#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,
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)
{
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;
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 */
#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)
{
iter->intersect_end = iter->next_pos;
}
-static void
+void
_cogl_span_iter_begin (CoglSpanIter *iter,
GArray *array,
float origin,
_cogl_span_iter_update (iter);
}
-static gboolean
+gboolean
_cogl_span_iter_end (CoglSpanIter *iter)
{
/* End reached when whole area covered */
}
}
-static void
+void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
GLenum wrap_mode)
{
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);
-}
-
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;
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 */
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)
{
iter->intersect_end = iter->next_pos;
}
-static void
+void
_cogl_span_iter_begin (CoglSpanIter *iter,
GArray *array,
float origin,
_cogl_span_iter_update (iter);
}
-static gboolean
+gboolean
_cogl_span_iter_end (CoglSpanIter *iter)
{
/* End reached when whole area covered */
return TRUE;
}
-static void
+void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
GLenum wrap_mode)
{
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);
-}
-