4
* An object oriented GL/GLES Abstraction/Utility Layer
6
* Copyright (C) 2007,2008,2009 Intel Corporation.
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the
20
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
* Boston, MA 02111-1307, USA.
29
#include "cogl-internal.h"
30
#include "cogl-context.h"
31
#include "cogl-texture-private.h"
32
#include "cogl-material-private.h"
33
#include "cogl-vertex-buffer-private.h"
39
#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
43
#define glGenBuffers ctx->pf_glGenBuffersARB
44
#define glBindBuffer ctx->pf_glBindBufferARB
45
#define glBufferData ctx->pf_glBufferDataARB
46
#define glBufferSubData ctx->pf_glBufferSubDataARB
47
#define glDeleteBuffers ctx->pf_glDeleteBuffersARB
48
#define glClientActiveTexture ctx->pf_glClientActiveTexture
50
#elif defined (HAVE_COGL_GLES2)
52
#include "../gles/cogl-gles2-wrapper.h"
58
* Our journal's vertex data is arranged as follows:
59
* 4 vertices per quad:
60
* 2 or 3 GLfloats per position (3 when doing software transforms)
62
* 2 GLfloats per tex coord * n_layers
64
* Where n_layers corresponds to the number of material layers enabled
66
* To avoid frequent changes in the stride of our vertex data we always pad
69
* When we are transforming quads in software we need to also track the z
70
* coordinate of transformed vertices.
72
* So for a given number of layers this gets the stride in 32bit words:
74
#define SW_TRANSFORM (!(cogl_debug_flags & \
75
COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
76
#define POS_STRIDE (SW_TRANSFORM ? 3 : 2) /* number of 32bit words */
77
#define N_POS_COMPONENTS POS_STRIDE
78
#define COLOR_STRIDE 1 /* number of 32bit words */
79
#define TEX_STRIDE 2 /* number of 32bit words */
80
#define MIN_LAYER_PADING 2
81
#define GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS(N_LAYERS) \
82
(POS_STRIDE + COLOR_STRIDE + \
83
TEX_STRIDE * (N_LAYERS < MIN_LAYER_PADING ? MIN_LAYER_PADING : N_LAYERS))
86
typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
89
typedef gboolean (*CoglJournalBatchTest) (CoglJournalEntry *entry0,
90
CoglJournalEntry *entry1);
91
typedef CoglVertexBufferIndices CoglJournalIndices;
93
typedef struct _CoglJournalFlushState
96
/* Note: this is a pointer to handle fallbacks. It normally holds a VBO
97
* offset, but when the driver doesn't support VBOs then this points into
98
* our GArray of logged vertices. */
100
GLuint vertex_offset;
102
CoglJournalIndices *indices;
103
size_t indices_type_size;
105
} CoglJournalFlushState;
107
/* these are defined in the particular backend */
108
void _cogl_path_add_node (gboolean new_sub_path,
111
void _cogl_path_fill_nodes ();
112
void _cogl_path_stroke_nodes ();
115
_cogl_journal_dump_quad_vertices (guint8 *data, int n_layers)
117
size_t stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
120
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
122
g_print ("n_layers = %d; stride = %d; pos stride = %d; color stride = %d; "
123
"tex stride = %d; stride in bytes = %d\n",
124
n_layers, (int)stride, POS_STRIDE, COLOR_STRIDE,
125
TEX_STRIDE, (int)stride * 4);
127
for (i = 0; i < 4; i++)
129
float *v = (float *)data + (i * stride);
130
guint8 *c = data + (POS_STRIDE * 4) + (i * stride * 4);
133
if (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)
134
g_print ("v%d: x = %f, y = %f, rgba=0x%02X%02X%02X%02X",
135
i, v[0], v[1], c[0], c[1], c[2], c[3]);
137
g_print ("v%d: x = %f, y = %f, z = %f, rgba=0x%02X%02X%02X%02X",
138
i, v[0], v[1], v[2], c[0], c[1], c[2], c[3]);
139
for (j = 0; j < n_layers; j++)
141
float *t = v + POS_STRIDE + COLOR_STRIDE + TEX_STRIDE * j;
142
g_print (", tx%d = %f, ty%d = %f", j, t[0], j, t[1]);
149
_cogl_journal_dump_quad_batch (guint8 *data, int n_layers, int n_quads)
151
size_t byte_stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4;
154
g_print ("_cogl_journal_dump_quad_batch: n_layers = %d, n_quads = %d\n",
156
for (i = 0; i < n_quads; i++)
157
_cogl_journal_dump_quad_vertices (data + byte_stride * 4 * i, n_layers);
161
batch_and_call (CoglJournalEntry *entries,
163
CoglJournalBatchTest can_batch_callback,
164
CoglJournalBatchCallback batch_callback,
169
CoglJournalEntry *batch_start = entries;
171
for (i = 1; i < n_entries; i++)
173
CoglJournalEntry *entry0 = &entries[i - 1];
174
CoglJournalEntry *entry1 = entry0 + 1;
176
if (can_batch_callback (entry0, entry1))
182
batch_callback (batch_start, batch_len, data);
184
batch_start = entry1;
188
/* The last batch... */
189
batch_callback (batch_start, batch_len, data);
193
_cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
197
CoglJournalFlushState *state = data;
199
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
200
g_print ("BATCHING: modelview batch len = %d\n", batch_len);
202
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
203
GE (glLoadMatrixf ((GLfloat *)&batch_start->model_view));
207
GE (glDrawArrays (GL_QUADS, state->vertex_offset, batch_len * 4));
209
#else /* HAVE_COGL_GL */
213
int indices_offset = (state->vertex_offset / 4) * 6;
214
GE (glDrawElements (GL_TRIANGLES,
216
state->indices->type,
217
(GLvoid*)(indices_offset * state->indices_type_size)));
221
GE (glDrawArrays (GL_TRIANGLE_FAN,
222
state->vertex_offset, /* first */
223
4)); /* n vertices */
227
/* DEBUGGING CODE XXX:
228
* This path will cause all rectangles to be drawn with a red, green
229
* or blue outline with no blending. This may e.g. help with debugging
230
* texture slicing issues or blending issues, plus it looks quite cool.
232
if (cogl_debug_flags & COGL_DEBUG_RECTANGLES)
234
static CoglHandle outline = COGL_INVALID_HANDLE;
235
static int color = 0;
237
if (outline == COGL_INVALID_HANDLE)
238
outline = cogl_material_new ();
240
cogl_enable (COGL_ENABLE_VERTEX_ARRAY);
241
for (i = 0; i < batch_len; i++, color = (color + 1) % 3)
243
cogl_material_set_color4ub (outline,
244
color == 0 ? 0xff : 0x00,
245
color == 1 ? 0xff : 0x00,
246
color == 2 ? 0xff : 0x00,
248
_cogl_material_flush_gl_state (outline, NULL);
249
GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) );
253
state->vertex_offset += (4 * batch_len);
257
compare_entry_modelviews (CoglJournalEntry *entry0,
258
CoglJournalEntry *entry1)
260
/* Batch together quads with the same model view matrix */
262
/* FIXME: this is nasty, there are much nicer ways to track this
263
* (at the add_quad_vertices level) without resorting to a memcmp!
265
* E.g. If the cogl-current-matrix code maintained an "age" for
266
* the modelview matrix we could simply check in add_quad_vertices
267
* if the age has increased, and if so record the change as a
268
* boolean in the journal.
271
if (memcmp (&entry0->model_view, &entry1->model_view,
272
sizeof (GLfloat) * 16) == 0)
278
/* At this point we have a run of quads that we know have compatible
279
* materials, but they may not all have the same modelview matrix */
281
_cogl_journal_flush_material_and_entries (CoglJournalEntry *batch_start,
285
gulong enable_flags = 0;
287
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
289
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
290
g_print ("BATCHING: material batch len = %d\n", batch_len);
292
_cogl_material_flush_gl_state (batch_start->material,
293
&batch_start->flush_options);
295
/* FIXME: This api is a bit yukky, ideally it will be removed if we
296
* re-work the cogl_enable mechanism */
297
enable_flags |= _cogl_material_get_cogl_enable_flags (batch_start->material);
299
if (ctx->enable_backface_culling)
300
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
302
enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
303
enable_flags |= COGL_ENABLE_COLOR_ARRAY;
304
cogl_enable (enable_flags);
306
/* If we haven't transformed the quads in software then we need to also break
307
* up batches according to changes in the modelview matrix... */
308
if (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)
310
batch_and_call (batch_start,
312
compare_entry_modelviews,
313
_cogl_journal_flush_modelview_and_entries,
317
_cogl_journal_flush_modelview_and_entries (batch_start, batch_len, data);
321
compare_entry_materials (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
323
/* batch rectangles using compatible materials */
325
/* XXX: _cogl_material_equal may give false negatives since it avoids
326
* deep comparisons as an optimization. It aims to compare enough so
327
* that we that we are able to batch the 90% common cases, but may not
328
* look at less common differences. */
329
if (_cogl_material_equal (entry0->material,
330
&entry0->flush_options,
332
&entry1->flush_options))
338
/* Since the stride may not reflect the number of texture layers in use
339
* (due to padding) we deal with texture coordinate offsets separately
340
* from vertex and color offsets... */
342
_cogl_journal_flush_texcoord_vbo_offsets_and_entries (
343
CoglJournalEntry *batch_start,
347
CoglJournalFlushState *state = data;
348
int prev_n_texcoord_arrays_enabled;
351
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
353
for (i = 0; i < batch_start->n_layers; i++)
355
GE (glClientActiveTexture (GL_TEXTURE0 + i));
356
GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
358
* Our journal's vertex data is arranged as follows:
359
* 4 vertices per quad:
360
* 2 or 3 GLfloats per position (3 when doing software transforms)
362
* 2 GLfloats per tex coord * n_layers
363
* (though n_layers may be padded; see definition of
364
* GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
366
GE (glTexCoordPointer (2, GL_FLOAT, state->stride,
367
(void *)(state->vbo_offset +
368
(POS_STRIDE + COLOR_STRIDE) * 4 +
369
TEX_STRIDE * 4 * i)));
371
prev_n_texcoord_arrays_enabled =
372
ctx->n_texcoord_arrays_enabled;
373
ctx->n_texcoord_arrays_enabled = batch_start->n_layers;
374
for (; i < prev_n_texcoord_arrays_enabled; i++)
376
GE (glClientActiveTexture (GL_TEXTURE0 + i));
377
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
380
batch_and_call (batch_start,
382
compare_entry_materials,
383
_cogl_journal_flush_material_and_entries,
388
compare_entry_n_layers (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
390
if (entry0->n_layers == entry1->n_layers)
396
/* At this point we know the stride has changed from the previous batch
397
* of journal entries */
399
_cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
403
CoglJournalFlushState *state = data;
406
int needed_indices = batch_len * 6;
407
CoglHandle indices_handle;
408
CoglVertexBufferIndices *indices;
411
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
413
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
414
g_print ("BATCHING: vbo offset batch len = %d\n", batch_len);
417
* Our journal's vertex data is arranged as follows:
418
* 4 vertices per quad:
419
* 2 or 3 GLfloats per position (3 when doing software transforms)
421
* 2 GLfloats per tex coord * n_layers
422
* (though n_layers may be padded; see definition of
423
* GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
425
stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers);
426
stride *= sizeof (GLfloat);
427
state->stride = stride;
429
GE (glVertexPointer (N_POS_COMPONENTS, GL_FLOAT, stride,
430
(void *)state->vbo_offset));
431
GE (glColorPointer (4, GL_UNSIGNED_BYTE, stride,
432
(void *)(state->vbo_offset + (POS_STRIDE * 4))));
435
indices_handle = cogl_vertex_buffer_indices_get_for_quads (needed_indices);
436
indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
437
state->indices = indices;
439
if (indices->type == GL_UNSIGNED_BYTE)
440
state->indices_type_size = 1;
441
else if (indices->type == GL_UNSIGNED_SHORT)
442
state->indices_type_size = 2;
444
g_critical ("unknown indices type %d", indices->type);
446
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
447
GPOINTER_TO_UINT (indices->vbo_name)));
450
/* We only call gl{Vertex,Color,Texture}Pointer when the stride within
451
* the VBO changes. (due to a change in the number of material layers)
452
* While the stride remains constant we walk forward through the above
453
* VBO using a vertex offset passed to glDraw{Arrays,Elements} */
454
state->vertex_offset = 0;
456
if (cogl_debug_flags & COGL_DEBUG_JOURNAL)
460
if (cogl_get_features () & COGL_FEATURE_VBOS)
461
verts = ((guint8 *)ctx->logged_vertices->data) +
462
(size_t)state->vbo_offset;
464
verts = (guint8 *)state->vbo_offset;
465
_cogl_journal_dump_quad_batch (verts,
466
batch_start->n_layers,
470
batch_and_call (batch_start,
472
compare_entry_n_layers,
473
_cogl_journal_flush_texcoord_vbo_offsets_and_entries,
476
/* progress forward through the VBO containing all our vertices */
477
state->vbo_offset += (stride * 4 * batch_len);
478
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
479
g_print ("new vbo offset = %lu\n", (gulong)state->vbo_offset);
483
compare_entry_strides (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
485
/* Currently the only thing that affects the stride for our vertex arrays
486
* is the number of material layers. We need to update our VBO offsets
487
* whenever the stride changes. */
488
/* TODO: We should be padding the n_layers == 1 case as if it were
489
* n_layers == 2 so we can reduce the need to split batches. */
490
if (entry0->n_layers == entry1->n_layers ||
491
(entry0->n_layers <= MIN_LAYER_PADING &&
492
entry1->n_layers <= MIN_LAYER_PADING))
499
upload_vertices_to_vbo (GArray *vertices, CoglJournalFlushState *state)
501
size_t needed_vbo_len;
504
_COGL_GET_CONTEXT (ctx, 0);
506
needed_vbo_len = vertices->len * sizeof (GLfloat);
508
g_assert (needed_vbo_len);
509
GE (glGenBuffers (1, &journal_vbo));
510
GE (glBindBuffer (GL_ARRAY_BUFFER, journal_vbo));
511
GE (glBufferData (GL_ARRAY_BUFFER,
516
/* As we flush the journal entries in batches we walk forward through the
517
* above VBO starting at offset 0... */
518
state->vbo_offset = 0;
523
/* XXX NB: When _cogl_journal_flush() returns all state relating
524
* to materials, all glEnable flags and current matrix state
528
_cogl_journal_flush (void)
530
CoglJournalFlushState state;
533
gboolean vbo_fallback =
534
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
536
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
538
if (ctx->journal->len == 0)
541
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
542
g_print ("BATCHING: journal len = %d\n", ctx->journal->len);
544
/* Load all the vertex data we have accumulated so far into a single VBO
545
* to minimize memory management costs within the GL driver. */
547
journal_vbo = upload_vertices_to_vbo (ctx->logged_vertices, &state);
549
state.vbo_offset = (char *)ctx->logged_vertices->data;
551
/* Since the journal deals with emitting the modelview matrices manually
552
* we need to dirty our client side modelview matrix stack cache... */
553
_cogl_current_matrix_state_dirty ();
555
/* And explicitly flush other matrix stacks... */
556
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
557
_cogl_current_matrix_state_flush ();
559
/* If we have transformed all our quads at log time then the whole journal
560
* then we ensure no further model transform is applied by loading the
561
* identity matrix here...*/
562
if (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
564
GE (glMatrixMode (GL_MODELVIEW));
568
/* batch_and_call() batches a list of journal entries according to some
569
* given criteria and calls a callback once for each determined batch.
571
* The process of flushing the journal is staggered to reduce the amount
572
* of driver/GPU state changes necessary:
573
* 1) We split the entries according to the stride of the vertices:
574
* Each time the stride of our vertex data changes we need to call
575
* gl{Vertex,Color}Pointer to inform GL of new VBO offsets.
576
* Currently the only thing that affects the stride of our vertex data
577
* is the number of material layers.
578
* 2) We split the entries explicitly by the number of material layers:
579
* We pad our vertex data when the number of layers is < 2 so that we
580
* can minimize changes in stride. Each time the number of layers
581
* changes we need to call glTexCoordPointer to inform GL of new VBO
583
* 3) We then split according to compatible Cogl materials:
584
* This is where we flush material state
585
* 4) Finally we split according to modelview matrix changes:
586
* This is when we finally tell GL to draw something.
587
* Note: Splitting by modelview changes is skipped when are doing the
588
* vertex transformation in software at log time.
590
batch_and_call ((CoglJournalEntry *)ctx->journal->data, /* first entry */
591
ctx->journal->len, /* max number of entries to consider */
592
compare_entry_strides,
593
_cogl_journal_flush_vbo_offsets_and_entries, /* callback */
596
for (i = 0; i < ctx->journal->len; i++)
598
CoglJournalEntry *entry =
599
&g_array_index (ctx->journal, CoglJournalEntry, i);
600
_cogl_material_journal_unref (entry->material);
604
GE (glDeleteBuffers (1, &journal_vbo));
606
g_array_set_size (ctx->journal, 0);
607
g_array_set_size (ctx->logged_vertices, 0);
611
_cogl_journal_log_quad (float x_1,
617
guint32 fallback_layers,
618
GLuint layer0_override_texture,
620
guint tex_coords_len)
630
guint32 disable_layers;
631
CoglJournalEntry *entry;
633
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
635
/* The vertex data is logged into a separate array in a layout that can be
636
* directly passed to OpenGL
639
/* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
640
* about how we pack our vertex data */
641
stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
642
/* NB: stride is in 32bit words */
643
byte_stride = stride * 4;
645
next_vert = ctx->logged_vertices->len;
646
g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride);
647
v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
648
c = (GLubyte *)(v + POS_STRIDE);
650
/* XXX: All the jumping around to fill in this strided buffer doesn't
653
/* XXX: we could defer expanding the vertex data for GL until we come
654
* to flushing the journal. */
656
/* FIXME: This is a hacky optimization, since it will break if we
657
* change the definition of CoglColor: */
658
_cogl_material_get_colorubv (material, c);
660
for (i = 0; i < 3; i++)
663
memcpy (c, src_c, 4);
666
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
668
v[0] = x_1; v[1] = y_1;
670
v[0] = x_1; v[1] = y_2;
672
v[0] = x_2; v[1] = y_2;
674
v[0] = x_2; v[1] = y_1;
681
cogl_get_modelview_matrix (&mv);
683
x = x_1, y = y_1, z = 0; w = 1;
684
cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
685
v[0] = x; v[1] = y; v[2] = z;
687
x = x_1, y = y_2, z = 0; w = 1;
688
cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
689
v[0] = x; v[1] = y; v[2] = z;
691
x = x_2, y = y_2, z = 0; w = 1;
692
cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
693
v[0] = x; v[1] = y; v[2] = z;
695
x = x_2, y = y_1, z = 0; w = 1;
696
cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
697
v[0] = x; v[1] = y; v[2] = z;
700
for (i = 0; i < n_layers; i++)
702
/* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
703
* about how we pack our vertex data */
704
GLfloat *t = &g_array_index (ctx->logged_vertices, GLfloat,
705
next_vert + POS_STRIDE +
706
COLOR_STRIDE + TEX_STRIDE * i);
708
t[0] = tex_coords[0]; t[1] = tex_coords[1];
710
t[0] = tex_coords[0]; t[1] = tex_coords[3];
712
t[0] = tex_coords[2]; t[1] = tex_coords[3];
714
t[0] = tex_coords[2]; t[1] = tex_coords[1];
717
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
719
g_print ("Logged new quad:\n");
720
v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
721
_cogl_journal_dump_quad_vertices ((guint8 *)v, n_layers);
724
next_entry = ctx->journal->len;
725
g_array_set_size (ctx->journal, next_entry + 1);
726
entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry);
728
disable_layers = (1 << n_layers) - 1;
729
disable_layers = ~disable_layers;
731
entry->material = _cogl_material_journal_ref (material);
732
entry->n_layers = n_layers;
733
entry->flush_options.flags =
734
COGL_MATERIAL_FLUSH_FALLBACK_MASK |
735
COGL_MATERIAL_FLUSH_DISABLE_MASK |
736
COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
737
entry->flush_options.fallback_layers = fallback_layers;
738
entry->flush_options.disable_layers = disable_layers;
739
if (layer0_override_texture)
741
entry->flush_options.flags |= COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE;
742
entry->flush_options.layer0_override_texture = layer0_override_texture;
744
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
745
cogl_get_modelview_matrix (&entry->model_view);
747
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING
748
|| cogl_debug_flags & COGL_DEBUG_RECTANGLES))
749
_cogl_journal_flush ();
753
_cogl_texture_sliced_quad (CoglTexture *tex,
764
CoglSpanIter iter_x , iter_y;
767
float first_tx , first_ty;
768
float first_qx , first_qy;
769
float slice_tx1 , slice_ty1;
770
float slice_tx2 , slice_ty2;
771
float slice_qx1 , slice_qy1;
772
float slice_qx2 , slice_qy2;
775
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
777
COGL_NOTE (DRAW, "Drawing Tex Quad (Sliced Mode)");
779
/* We can't use hardware repeat so we need to set clamp to edge
780
otherwise it might pull in edge pixels from the other side */
781
_cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE);
783
/* If the texture coordinates are backwards then swap both the
784
geometry and texture coordinates so that the texture will be
785
flipped but we can still use the same algorithm to iterate the
806
/* Scale ratio from texture to quad widths */
807
tw = (float)(tex->bitmap.width);
808
th = (float)(tex->bitmap.height);
810
tqx = (x_2 - x_1) / (tw * (tx_2 - tx_1));
811
tqy = (y_2 - y_1) / (th * (ty_2 - ty_1));
813
/* Integral texture coordinate for first tile */
814
first_tx = (float)(floorf (tx_1));
815
first_ty = (float)(floorf (ty_1));
817
/* Denormalize texture coordinates */
818
first_tx = (first_tx * tw);
819
first_ty = (first_ty * th);
825
/* Quad coordinate of the first tile */
826
first_qx = x_1 - (tx_1 - first_tx) * tqx;
827
first_qy = y_1 - (ty_1 - first_ty) * tqy;
830
/* Iterate until whole quad height covered */
831
for (_cogl_span_iter_begin (&iter_y, tex->slice_y_spans,
832
first_ty, ty_1, ty_2) ;
833
!_cogl_span_iter_end (&iter_y) ;
834
_cogl_span_iter_next (&iter_y) )
838
/* Discard slices out of quad early */
839
if (!iter_y.intersects) continue;
841
/* Span-quad intersection in quad coordinates */
842
slice_qy1 = first_qy + (iter_y.intersect_start - first_ty) * tqy;
844
slice_qy2 = first_qy + (iter_y.intersect_end - first_ty) * tqy;
846
/* Localize slice texture coordinates */
847
slice_ty1 = iter_y.intersect_start - iter_y.pos;
848
slice_ty2 = iter_y.intersect_end - iter_y.pos;
850
/* Normalize texture coordinates to current slice
851
(rectangle texture targets take denormalized) */
853
if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB)
856
slice_ty1 /= iter_y.span->size;
857
slice_ty2 /= iter_y.span->size;
860
/* Iterate until whole quad width covered */
861
for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans,
862
first_tx, tx_1, tx_2) ;
863
!_cogl_span_iter_end (&iter_x) ;
864
_cogl_span_iter_next (&iter_x) )
866
/* Discard slices out of quad early */
867
if (!iter_x.intersects) continue;
869
/* Span-quad intersection in quad coordinates */
870
slice_qx1 = first_qx + (iter_x.intersect_start - first_tx) * tqx;
872
slice_qx2 = first_qx + (iter_x.intersect_end - first_tx) * tqx;
874
/* Localize slice texture coordinates */
875
slice_tx1 = iter_x.intersect_start - iter_x.pos;
876
slice_tx2 = iter_x.intersect_end - iter_x.pos;
878
/* Normalize texture coordinates to current slice
879
(rectangle texture targets take denormalized) */
881
if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB)
884
slice_tx1 /= iter_x.span->size;
885
slice_tx2 /= iter_x.span->size;
889
"~~~~~ slice (%d, %d)\n"
898
iter_x.index, iter_y.index,
899
slice_qx1, slice_qy1,
900
slice_qx2, slice_qy2,
901
slice_tx1, slice_ty1,
902
slice_tx2, slice_ty2);
904
/* Pick and bind opengl texture object */
905
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
906
iter_y.index * iter_x.array->len +
909
tex_coords[0] = slice_tx1;
910
tex_coords[1] = slice_ty1;
911
tex_coords[2] = slice_tx2;
912
tex_coords[3] = slice_ty2;
913
_cogl_journal_log_quad (slice_qx1,
919
0, /* don't need to use fallbacks */
920
gl_handle, /* replace the layer0 texture */
928
_cogl_multitexture_unsliced_quad (float x_1,
933
guint32 fallback_layers,
934
const float *user_tex_coords,
935
gint user_tex_coords_len)
937
int n_layers = cogl_material_get_n_layers (material);
938
float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers);
943
_COGL_GET_CONTEXT (ctx, FALSE);
946
* Validate the texture coordinates for this rectangle.
948
layers = cogl_material_get_layers (material);
949
for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++)
951
CoglHandle layer = (CoglHandle)tmp->data;
952
CoglHandle tex_handle;
954
const float *in_tex_coords;
955
float *out_tex_coords;
956
CoglTexSliceSpan *x_span;
957
CoglTexSliceSpan *y_span;
959
tex_handle = cogl_material_layer_get_texture (layer);
961
/* COGL_INVALID_HANDLE textures are handled by
962
* _cogl_material_flush_gl_state */
963
if (tex_handle == COGL_INVALID_HANDLE)
966
tex = _cogl_texture_pointer_from_handle (tex_handle);
968
in_tex_coords = &user_tex_coords[i * 4];
969
out_tex_coords = &final_tex_coords[i * 4];
972
/* If the texture has waste or we are using GL_TEXTURE_RECT we
973
* can't handle texture repeating so we check that the texture
974
* coords lie in the range [0,1].
976
* NB: We already know that no texture matrix is being used
977
* if the texture has waste since we validated that early on.
978
* TODO: check for a texture matrix in the GL_TEXTURE_RECT
983
tex->gl_target == GL_TEXTURE_RECTANGLE_ARB ||
985
_cogl_texture_span_has_waste (tex, 0, 0))
986
&& i < user_tex_coords_len / 4
987
&& (in_tex_coords[0] < 0 || in_tex_coords[0] > 1.0
988
|| in_tex_coords[1] < 0 || in_tex_coords[1] > 1.0
989
|| in_tex_coords[2] < 0 || in_tex_coords[2] > 1.0
990
|| in_tex_coords[3] < 0 || in_tex_coords[3] > 1.0))
996
static gboolean warning_seen = FALSE;
998
g_warning ("Skipping layers 1..n of your material since "
999
"the first layer has waste and you supplied "
1000
"texture coordinates outside the range [0,1]. "
1001
"We don't currently support any "
1002
"multi-texturing using textures with waste "
1003
"when repeating is necissary so we are "
1004
"falling back to sliced textures assuming "
1005
"layer 0 is the most important one keep");
1006
warning_seen = TRUE;
1012
static gboolean warning_seen = FALSE;
1014
g_warning ("Skipping layer %d of your material "
1015
"consisting of a texture with waste since "
1016
"you have supplied texture coords outside "
1017
"the range [0,1] (unsupported when "
1018
"multi-texturing)", i);
1019
warning_seen = TRUE;
1021
/* NB: marking for fallback will replace the layer with
1022
* a default transparent texture */
1023
fallback_layers |= (1 << i);
1029
* Setup the texture unit...
1032
/* NB: The user might not have supplied texture coordinates for all
1034
if (i < (user_tex_coords_len / 4))
1038
/* If the texture coords are all in the range [0,1] then we want to
1039
clamp the coords to the edge otherwise it can pull in edge pixels
1040
from the wrong side when scaled */
1041
if (in_tex_coords[0] >= 0 && in_tex_coords[0] <= 1.0
1042
&& in_tex_coords[1] >= 0 && in_tex_coords[1] <= 1.0
1043
&& in_tex_coords[2] >= 0 && in_tex_coords[2] <= 1.0
1044
&& in_tex_coords[3] >= 0 && in_tex_coords[3] <= 1.0)
1045
wrap_mode = GL_CLAMP_TO_EDGE;
1047
wrap_mode = GL_REPEAT;
1049
memcpy (out_tex_coords, in_tex_coords, sizeof (GLfloat) * 4);
1051
_cogl_texture_set_wrap_mode_parameter (tex, wrap_mode);
1055
out_tex_coords[0] = 0; /* tx_1 */
1056
out_tex_coords[1] = 0; /* ty_1 */
1057
out_tex_coords[2] = 1.0; /* tx_2 */
1058
out_tex_coords[3] = 1.0; /* ty_2 */
1060
_cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE);
1063
/* Don't include the waste in the texture coordinates */
1064
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
1065
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
1068
out_tex_coords[0] * (x_span->size - x_span->waste) / x_span->size;
1070
out_tex_coords[1] * (y_span->size - y_span->waste) / y_span->size;
1072
out_tex_coords[2] * (x_span->size - x_span->waste) / x_span->size;
1074
out_tex_coords[3] * (y_span->size - y_span->waste) / y_span->size;
1077
/* Denormalize texture coordinates for rectangle textures */
1078
if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB)
1080
out_tex_coords[0] *= x_span->size;
1081
out_tex_coords[1] *= y_span->size;
1082
out_tex_coords[2] *= x_span->size;
1083
out_tex_coords[3] *= y_span->size;
1088
_cogl_journal_log_quad (x_1,
1095
0, /* don't replace the layer0 texture */
1102
struct _CoglMutiTexturedRect
1108
const float *tex_coords;
1109
gint tex_coords_len;
1113
_cogl_rectangles_with_multitexture_coords (
1114
struct _CoglMutiTexturedRect *rects,
1117
CoglHandle material;
1118
const GList *layers;
1121
guint32 fallback_layers = 0;
1122
gboolean all_use_sliced_quad_fallback = FALSE;
1125
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1127
cogl_clip_ensure ();
1129
material = ctx->source_material;
1131
layers = cogl_material_get_layers (material);
1132
n_layers = cogl_material_get_n_layers (material);
1135
* Validate all the layers of the current source material...
1138
for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++)
1140
CoglHandle layer = tmp->data;
1141
CoglHandle tex_handle;
1142
CoglTexture *texture = NULL;
1145
if (cogl_material_layer_get_type (layer)
1146
!= COGL_MATERIAL_LAYER_TYPE_TEXTURE)
1149
tex_handle = cogl_material_layer_get_texture (layer);
1151
/* COGL_INVALID_HANDLE textures are handled by
1152
* _cogl_material_flush_gl_state */
1153
if (tex_handle == COGL_INVALID_HANDLE)
1156
texture = _cogl_texture_pointer_from_handle (tex_handle);
1159
* For now, if the first layer is sliced then all other layers are
1160
* ignored since we currently don't support multi-texturing with
1161
* sliced textures. If the first layer is not sliced then any other
1162
* layers found to be sliced will be skipped. (with a warning)
1164
* TODO: Add support for multi-texturing rectangles with sliced
1165
* textures if no texture matrices are in use.
1167
if (cogl_texture_is_sliced (tex_handle))
1171
fallback_layers = ~1; /* fallback all except the first layer */
1172
all_use_sliced_quad_fallback = TRUE;
1175
static gboolean warning_seen = FALSE;
1177
g_warning ("Skipping layers 1..n of your material since "
1178
"the first layer is sliced. We don't currently "
1179
"support any multi-texturing with sliced "
1180
"textures but assume layer 0 is the most "
1181
"important to keep");
1182
warning_seen = TRUE;
1188
static gboolean warning_seen = FALSE;
1190
g_warning ("Skipping layer %d of your material consisting of "
1191
"a sliced texture (unsuported for multi texturing)",
1193
warning_seen = TRUE;
1195
/* NB: marking for fallback will replace the layer with
1196
* a default transparent texture */
1197
fallback_layers |= (1 << i);
1202
/* We don't support multi texturing using textures with any waste if the
1203
* user has supplied a custom texture matrix, since we don't know if
1204
* the result will end up trying to texture from the waste area. */
1205
flags = _cogl_material_layer_get_flags (layer);
1206
if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX
1207
&& _cogl_texture_span_has_waste (texture, 0, 0))
1209
static gboolean warning_seen = FALSE;
1211
g_warning ("Skipping layer %d of your material consisting of a "
1212
"texture with waste since you have supplied a custom "
1213
"texture matrix and the result may try to sample from "
1214
"the waste area of your texture.", i);
1215
warning_seen = TRUE;
1217
/* NB: marking for fallback will replace the layer with
1218
* a default transparent texture */
1219
fallback_layers |= (1 << i);
1225
* Emit geometry for each of the rectangles...
1228
for (i = 0; i < n_rects; i++)
1230
if (all_use_sliced_quad_fallback
1231
|| !_cogl_multitexture_unsliced_quad (rects[i].x_1, rects[i].y_1,
1232
rects[i].x_2, rects[i].y_2,
1235
rects[i].tex_coords,
1236
rects[i].tex_coords_len))
1238
CoglHandle first_layer, tex_handle;
1239
CoglTexture *texture;
1241
first_layer = layers->data;
1242
tex_handle = cogl_material_layer_get_texture (first_layer);
1243
texture = _cogl_texture_pointer_from_handle (tex_handle);
1244
if (rects[i].tex_coords)
1245
_cogl_texture_sliced_quad (texture,
1247
rects[i].x_1, rects[i].y_1,
1248
rects[i].x_2, rects[i].y_2,
1249
rects[i].tex_coords[0],
1250
rects[i].tex_coords[1],
1251
rects[i].tex_coords[2],
1252
rects[i].tex_coords[3]);
1254
_cogl_texture_sliced_quad (texture,
1256
rects[i].x_1, rects[i].y_1,
1257
rects[i].x_2, rects[i].y_2,
1258
0.0f, 0.0f, 1.0f, 1.0f);
1263
/* XXX: The current journal doesn't handle changes to the model view matrix
1264
* so for now we force a flush at the end of every primitive. */
1265
_cogl_journal_flush ();
1270
cogl_rectangles (const float *verts,
1273
struct _CoglMutiTexturedRect *rects;
1276
rects = g_alloca (n_rects * sizeof (struct _CoglMutiTexturedRect));
1278
for (i = 0; i < n_rects; i++)
1280
rects[i].x_1 = verts[i * 4];
1281
rects[i].y_1 = verts[i * 4 + 1];
1282
rects[i].x_2 = verts[i * 4 + 2];
1283
rects[i].y_2 = verts[i * 4 + 3];
1284
rects[i].tex_coords = NULL;
1285
rects[i].tex_coords_len = 0;
1288
_cogl_rectangles_with_multitexture_coords (rects, n_rects);
1292
cogl_rectangles_with_texture_coords (const float *verts,
1295
struct _CoglMutiTexturedRect *rects;
1298
rects = g_alloca (n_rects * sizeof (struct _CoglMutiTexturedRect));
1300
for (i = 0; i < n_rects; i++)
1302
rects[i].x_1 = verts[i * 8];
1303
rects[i].y_1 = verts[i * 8 + 1];
1304
rects[i].x_2 = verts[i * 8 + 2];
1305
rects[i].y_2 = verts[i * 8 + 3];
1306
/* FIXME: rect should be defined to have a const float *geom;
1307
* instead, to avoid this copy
1308
* rect[i].geom = &verts[n_rects * 8]; */
1309
rects[i].tex_coords = &verts[i * 8 + 4];
1310
rects[i].tex_coords_len = 4;
1313
_cogl_rectangles_with_multitexture_coords (rects, n_rects);
1317
cogl_rectangle_with_texture_coords (float x_1,
1337
cogl_rectangles_with_texture_coords (verts, 1);
1341
cogl_rectangle_with_multitexture_coords (float x_1,
1345
const float *user_tex_coords,
1346
gint user_tex_coords_len)
1348
struct _CoglMutiTexturedRect rect;
1354
rect.tex_coords = user_tex_coords;
1355
rect.tex_coords_len = user_tex_coords_len;
1357
_cogl_rectangles_with_multitexture_coords (&rect, 1);
1361
cogl_rectangle (float x_1,
1366
cogl_rectangle_with_multitexture_coords (x_1, y_1,
1372
_cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
1377
const GList *layers;
1379
CoglHandle tex_handle;
1381
CoglTexSliceSpan *y_span, *x_span;
1382
int x, y, tex_num, i;
1385
CoglMaterialFlushOptions options;
1387
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1389
/* We can assume in this case that we have at least one layer in the
1390
* material that corresponds to a sliced cogl texture */
1391
layers = cogl_material_get_layers (ctx->source_material);
1392
layer0 = (CoglHandle)layers->data;
1393
tex_handle = cogl_material_layer_get_texture (layer0);
1394
tex = _cogl_texture_pointer_from_handle (tex_handle);
1396
v = (GLfloat *)ctx->logged_vertices->data;
1397
for (i = 0; i < n_vertices; i++)
1401
v[0] = vertices[i].x;
1402
v[1] = vertices[i].y;
1403
v[2] = vertices[i].z;
1407
/* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */
1408
c = (guint8 *) (v + 5);
1409
c[0] = cogl_color_get_red_byte (&vertices[i].color);
1410
c[1] = cogl_color_get_green_byte (&vertices[i].color);
1411
c[2] = cogl_color_get_blue_byte (&vertices[i].color);
1412
c[3] = cogl_color_get_alpha_byte (&vertices[i].color);
1418
/* Render all of the slices with the full geometry but use a
1419
transparent border color so that any part of the texture not
1420
covered by the slice will be ignored */
1422
for (y = 0; y < tex->slice_y_spans->len; y++)
1424
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
1426
for (x = 0; x < tex->slice_x_spans->len; x++)
1428
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
1430
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, tex_num++);
1432
/* Convert the vertices into an array of GLfloats ready to pass to
1434
v = (GLfloat *)ctx->logged_vertices->data;
1435
for (i = 0; i < n_vertices; i++)
1440
tx = ((vertices[i].tx
1441
- ((float)(x_span->start)
1442
/ tex->bitmap.width))
1443
* tex->bitmap.width / x_span->size);
1444
ty = ((vertices[i].ty
1445
- ((float)(y_span->start)
1446
/ tex->bitmap.height))
1447
* tex->bitmap.height / y_span->size);
1450
/* Scale the coordinates up for rectangle textures */
1451
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
1458
/* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */
1467
COGL_MATERIAL_FLUSH_DISABLE_MASK |
1468
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE;
1469
/* disable all except the first layer */
1470
options.disable_layers = (guint32)~1;
1471
options.layer0_override_texture = gl_handle;
1473
_cogl_material_flush_gl_state (ctx->source_material, &options);
1474
_cogl_flush_matrix_stacks ();
1476
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) );
1482
_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
1487
guint32 fallback_layers)
1489
CoglHandle material;
1490
const GList *layers;
1493
CoglTexSliceSpan *y_span, *x_span;
1495
CoglMaterialFlushOptions options;
1497
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1500
material = ctx->source_material;
1501
layers = cogl_material_get_layers (material);
1503
/* Convert the vertices into an array of GLfloats ready to pass to
1505
for (v = (GLfloat *)ctx->logged_vertices->data, i = 0;
1512
/* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1513
v[0] = vertices[i].x;
1514
v[1] = vertices[i].y;
1515
v[2] = vertices[i].z;
1517
for (tmp = (GList *)layers, j = 0; tmp != NULL; tmp = tmp->next, j++)
1519
CoglHandle layer = (CoglHandle)tmp->data;
1520
CoglHandle tex_handle;
1525
tex_handle = cogl_material_layer_get_texture (layer);
1527
/* COGL_INVALID_HANDLE textures will be handled in
1528
* _cogl_material_flush_layers_gl_state but there is no need to worry
1529
* about scaling texture coordinates in this case */
1530
if (tex_handle == COGL_INVALID_HANDLE)
1533
tex = _cogl_texture_pointer_from_handle (tex_handle);
1535
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
1536
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
1538
tx = ((vertices[i].tx
1539
- ((float)(x_span->start)
1540
/ tex->bitmap.width))
1541
* tex->bitmap.width / x_span->size);
1542
ty = ((vertices[i].ty
1543
- ((float)(y_span->start)
1544
/ tex->bitmap.height))
1545
* tex->bitmap.height / y_span->size);
1548
/* Scale the coordinates up for rectangle textures */
1549
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
1556
/* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1564
/* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1565
c = (guint8 *) (v + 3 + 2 * n_layers);
1566
c[0] = cogl_color_get_red_byte (&vertices[i].color);
1567
c[1] = cogl_color_get_green_byte (&vertices[i].color);
1568
c[2] = cogl_color_get_blue_byte (&vertices[i].color);
1569
c[3] = cogl_color_get_alpha_byte (&vertices[i].color);
1573
options.flags = COGL_MATERIAL_FLUSH_FALLBACK_MASK;
1575
options.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
1576
options.fallback_layers = fallback_layers;
1577
_cogl_material_flush_gl_state (ctx->source_material, &options);
1578
_cogl_flush_matrix_stacks ();
1580
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
1584
cogl_polygon (CoglTextureVertex *vertices,
1588
CoglHandle material;
1589
const GList *layers;
1592
gboolean use_sliced_polygon_fallback = FALSE;
1593
guint32 fallback_layers = 0;
1595
gulong enable_flags;
1599
int prev_n_texcoord_arrays_enabled;
1601
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1603
_cogl_journal_flush ();
1604
cogl_clip_ensure ();
1606
material = ctx->source_material;
1607
layers = cogl_material_get_layers (ctx->source_material);
1608
n_layers = g_list_length ((GList *)layers);
1610
for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++)
1612
CoglHandle layer = (CoglHandle)tmp->data;
1613
CoglHandle tex_handle = cogl_material_layer_get_texture (layer);
1615
/* COGL_INVALID_HANDLE textures will be handled in
1616
* _cogl_material_flush_layers_gl_state */
1617
if (tex_handle == COGL_INVALID_HANDLE)
1620
if (i == 0 && cogl_texture_is_sliced (tex_handle))
1622
#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2)
1624
static gboolean warning_seen = FALSE;
1626
g_warning ("cogl_polygon does not work for sliced textures "
1628
warning_seen = TRUE;
1634
static gboolean warning_seen = FALSE;
1637
g_warning ("Disabling layers 1..n since multi-texturing with "
1638
"cogl_polygon isn't supported when using sliced "
1640
warning_seen = TRUE;
1643
use_sliced_polygon_fallback = TRUE;
1646
if (cogl_material_layer_get_min_filter (layer) != GL_NEAREST
1647
|| cogl_material_layer_get_mag_filter (layer) != GL_NEAREST)
1649
static gboolean warning_seen = FALSE;
1652
g_warning ("cogl_texture_polygon does not work for sliced textures "
1653
"when the minification and magnification filters are not "
1655
warning_seen = TRUE;
1662
CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle);
1663
/* Temporarily change the wrapping mode on all of the slices to use
1664
* a transparent border
1665
* XXX: it's doesn't look like we save/restore this, like
1666
* the comment implies? */
1667
_cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER);
1673
if (cogl_texture_is_sliced (tex_handle))
1675
static gboolean warning_seen = FALSE;
1677
g_warning ("Disabling layer %d of the current source material, "
1678
"because texturing with the vertex buffer API is not "
1679
"currently supported using sliced textures, or "
1680
"textures with waste\n", i);
1681
warning_seen = TRUE;
1683
fallback_layers |= (1 << i);
1688
/* Our data is arranged like:
1689
* [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */
1690
stride = 3 + (2 * n_layers) + (use_color ? 1 : 0);
1691
stride_bytes = stride * sizeof (GLfloat);
1693
/* Make sure there is enough space in the global vertex
1694
array. This is used so we can render the polygon with a single
1695
call to OpenGL but still support any number of vertices */
1696
g_array_set_size (ctx->logged_vertices, n_vertices * stride);
1697
v = (GLfloat *)ctx->logged_vertices->data;
1699
/* Prepare GL state */
1700
enable_flags = COGL_ENABLE_VERTEX_ARRAY;
1701
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
1703
if (ctx->enable_backface_culling)
1704
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
1708
enable_flags |= COGL_ENABLE_COLOR_ARRAY;
1709
GE( glColorPointer (4, GL_UNSIGNED_BYTE,
1711
/* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1712
v + 3 + 2 * n_layers) );
1715
cogl_enable (enable_flags);
1717
GE (glVertexPointer (3, GL_FLOAT, stride_bytes, v));
1719
for (i = 0; i < n_layers; i++)
1721
GE (glClientActiveTexture (GL_TEXTURE0 + i));
1722
GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
1723
GE (glTexCoordPointer (2, GL_FLOAT,
1725
/* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1728
prev_n_texcoord_arrays_enabled =
1729
ctx->n_texcoord_arrays_enabled;
1730
ctx->n_texcoord_arrays_enabled = n_layers;
1731
for (; i < prev_n_texcoord_arrays_enabled; i++)
1733
GE (glClientActiveTexture (GL_TEXTURE0 + i));
1734
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
1737
if (use_sliced_polygon_fallback)
1738
_cogl_texture_sliced_polygon (vertices,
1743
_cogl_multitexture_unsliced_polygon (vertices,
1750
/* Reset the size of the logged vertex array because rendering
1751
rectangles expects it to start at 0 */
1752
g_array_set_size (ctx->logged_vertices, 0);
1756
cogl_path_fill (void)
1758
cogl_path_fill_preserve ();
1764
cogl_path_fill_preserve (void)
1766
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1768
_cogl_journal_flush ();
1769
cogl_clip_ensure ();
1771
if (ctx->path_nodes->len == 0)
1774
_cogl_path_fill_nodes ();
1778
cogl_path_stroke (void)
1780
cogl_path_stroke_preserve ();
1786
cogl_path_stroke_preserve (void)
1788
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1790
if (ctx->path_nodes->len == 0)
1793
_cogl_journal_flush ();
1794
cogl_clip_ensure ();
1796
_cogl_path_stroke_nodes();
1800
cogl_path_move_to (float x,
1803
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1805
/* FIXME: handle multiple contours maybe? */
1807
_cogl_path_add_node (TRUE, x, y);
1809
ctx->path_start.x = x;
1810
ctx->path_start.y = y;
1812
ctx->path_pen = ctx->path_start;
1816
cogl_path_rel_move_to (float x,
1819
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1821
cogl_path_move_to (ctx->path_pen.x + x,
1822
ctx->path_pen.y + y);
1826
cogl_path_line_to (float x,
1829
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1831
_cogl_path_add_node (FALSE, x, y);
1833
ctx->path_pen.x = x;
1834
ctx->path_pen.y = y;
1838
cogl_path_rel_line_to (float x,
1841
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1843
cogl_path_line_to (ctx->path_pen.x + x,
1844
ctx->path_pen.y + y);
1848
cogl_path_close (void)
1850
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1852
_cogl_path_add_node (FALSE, ctx->path_start.x, ctx->path_start.y);
1853
ctx->path_pen = ctx->path_start;
1857
cogl_path_new (void)
1859
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
1861
g_array_set_size (ctx->path_nodes, 0);
1865
cogl_path_line (float x_1,
1870
cogl_path_move_to (x_1, y_1);
1871
cogl_path_line_to (x_2, y_2);
1875
cogl_path_polyline (float *coords,
1880
cogl_path_move_to (coords[0], coords[1]);
1882
for (c = 1; c < num_points; ++c)
1883
cogl_path_line_to (coords[2*c], coords[2*c+1]);
1887
cogl_path_polygon (float *coords,
1890
cogl_path_polyline (coords, num_points);
1895
cogl_path_rectangle (float x_1,
1900
cogl_path_move_to (x_1, y_1);
1901
cogl_path_line_to (x_2, y_1);
1902
cogl_path_line_to (x_2, y_2);
1903
cogl_path_line_to (x_1, y_2);
1908
_cogl_path_arc (float center_x,
1923
/* Fix invalid angles */
1925
if (angle_1 == angle_2 || angle_step == 0x0)
1928
if (angle_step < 0x0)
1929
angle_step = -angle_step;
1931
/* Walk the arc by given step */
1934
while (a != angle_2)
1936
cosa = cosf (a * (G_PI/180.0));
1937
sina = sinf (a * (G_PI/180.0));
1939
px = center_x + (cosa * radius_x);
1940
py = center_y + (sina * radius_y);
1942
if (a == angle_1 && move_first)
1943
cogl_path_move_to (px, py);
1945
cogl_path_line_to (px, py);
1947
if (G_LIKELY (angle_2 > angle_1))
1961
/* Make sure the final point is drawn */
1963
cosa = cosf (angle_2 * (G_PI/180.0));
1964
sina = sinf (angle_2 * (G_PI/180.0));
1966
px = center_x + (cosa * radius_x);
1967
py = center_y + (sina * radius_y);
1969
cogl_path_line_to (px, py);
1973
cogl_path_arc (float center_x,
1980
float angle_step = 10;
1981
/* it is documented that a move to is needed to create a freestanding
1984
_cogl_path_arc (center_x, center_y,
1987
angle_step, 0 /* no move */);
1992
cogl_path_arc_rel (float center_x,
2000
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
2002
_cogl_path_arc (ctx->path_pen.x + center_x,
2003
ctx->path_pen.y + center_y,
2006
angle_step, 0 /* no move */);
2010
cogl_path_ellipse (float center_x,
2015
float angle_step = 10;
2017
/* FIXME: if shows to be slow might be optimized
2018
* by mirroring just a quarter of it */
2020
_cogl_path_arc (center_x, center_y,
2023
angle_step, 1 /* move first */);
2029
cogl_path_round_rectangle (float x_1,
2036
float inner_width = x_2 - x_1 - radius * 2;
2037
float inner_height = y_2 - y_1 - radius * 2;
2039
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
2041
cogl_path_move_to (x_1, y_1 + radius);
2042
cogl_path_arc_rel (radius, 0,
2048
cogl_path_line_to (ctx->path_pen.x + inner_width,
2050
cogl_path_arc_rel (0, radius,
2056
cogl_path_line_to (ctx->path_pen.x,
2057
ctx->path_pen.y + inner_height);
2059
cogl_path_arc_rel (-radius, 0,
2065
cogl_path_line_to (ctx->path_pen.x - inner_width,
2067
cogl_path_arc_rel (0, -radius,
2078
_cogl_path_bezier3_sub (CoglBezCubic *cubic)
2080
CoglBezCubic cubics[_COGL_MAX_BEZ_RECURSE_DEPTH];
2081
CoglBezCubic *cleft;
2082
CoglBezCubic *cright;
2094
/* Put first curve on stack */
2100
c = &cubics[cindex];
2103
/* Calculate distance of control points from their
2104
* counterparts on the line between end points */
2105
dif1.x = (c->p2.x * 3) - (c->p1.x * 2) - c->p4.x;
2106
dif1.y = (c->p2.y * 3) - (c->p1.y * 2) - c->p4.y;
2107
dif2.x = (c->p3.x * 3) - (c->p4.x * 2) - c->p1.x;
2108
dif2.y = (c->p3.y * 3) - (c->p4.y * 2) - c->p1.y;
2120
/* Pick the greatest of two distances */
2121
if (dif1.x < dif2.x) dif1.x = dif2.x;
2122
if (dif1.y < dif2.y) dif1.y = dif2.y;
2124
/* Cancel if the curve is flat enough */
2125
if (dif1.x + dif1.y <= 1.0 ||
2126
cindex == _COGL_MAX_BEZ_RECURSE_DEPTH-1)
2128
/* Add subdivision point (skip last) */
2132
_cogl_path_add_node (FALSE, c->p4.x, c->p4.y);
2139
/* Left recursion goes on top of stack! */
2140
cright = c; cleft = &cubics[++cindex];
2142
/* Subdivide into 2 sub-curves */
2143
c1.x = ((c->p1.x + c->p2.x) / 2);
2144
c1.y = ((c->p1.y + c->p2.y) / 2);
2145
mm.x = ((c->p2.x + c->p3.x) / 2);
2146
mm.y = ((c->p2.y + c->p3.y) / 2);
2147
c5.x = ((c->p3.x + c->p4.x) / 2);
2148
c5.y = ((c->p3.y + c->p4.y) / 2);
2150
c2.x = ((c1.x + mm.x) / 2);
2151
c2.y = ((c1.y + mm.y) / 2);
2152
c4.x = ((mm.x + c5.x) / 2);
2153
c4.y = ((mm.y + c5.y) / 2);
2155
c3.x = ((c2.x + c4.x) / 2);
2156
c3.y = ((c2.y + c4.y) / 2);
2158
/* Add left recursion to stack */
2164
/* Add right recursion to stack */
2173
cogl_path_curve_to (float x_1,
2182
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
2184
/* Prepare cubic curve */
2185
cubic.p1 = ctx->path_pen;
2193
/* Run subdivision */
2194
_cogl_path_bezier3_sub (&cubic);
2196
/* Add last point */
2197
_cogl_path_add_node (FALSE, cubic.p4.x, cubic.p4.y);
2198
ctx->path_pen = cubic.p4;
2202
cogl_path_rel_curve_to (float x_1,
2209
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
2211
cogl_path_curve_to (ctx->path_pen.x + x_1,
2212
ctx->path_pen.y + y_1,
2213
ctx->path_pen.x + x_2,
2214
ctx->path_pen.y + y_2,
2215
ctx->path_pen.x + x_3,
2216
ctx->path_pen.y + y_3);
2220
/* If second order beziers were needed the following code could
2226
_cogl_path_bezier2_sub (CoglBezQuad *quad)
2228
CoglBezQuad quads[_COGL_MAX_BEZ_RECURSE_DEPTH];
2230
CoglBezQuad *qright;
2239
/* Put first curve on stack */
2243
/* While stack is not empty */
2249
/* Calculate distance of control point from its
2250
* counterpart on the line between end points */
2251
mid.x = ((q->p1.x + q->p3.x) / 2);
2252
mid.y = ((q->p1.y + q->p3.y) / 2);
2253
dif.x = (q->p2.x - mid.x);
2254
dif.y = (q->p2.y - mid.y);
2255
if (dif.x < 0) dif.x = -dif.x;
2256
if (dif.y < 0) dif.y = -dif.y;
2258
/* Cancel if the curve is flat enough */
2259
if (dif.x + dif.y <= 1.0 ||
2260
qindex == _COGL_MAX_BEZ_RECURSE_DEPTH - 1)
2262
/* Add subdivision point (skip last) */
2263
if (qindex == 0) return;
2264
_cogl_path_add_node (FALSE, q->p3.x, q->p3.y);
2268
/* Left recursion goes on top of stack! */
2269
qright = q; qleft = &quads[++qindex];
2271
/* Subdivide into 2 sub-curves */
2272
c1.x = ((q->p1.x + q->p2.x) / 2);
2273
c1.y = ((q->p1.y + q->p2.y) / 2);
2274
c3.x = ((q->p2.x + q->p3.x) / 2);
2275
c3.y = ((q->p2.y + q->p3.y) / 2);
2276
c2.x = ((c1.x + c3.x) / 2);
2277
c2.y = ((c1.y + c3.y) / 2);
2279
/* Add left recursion onto stack */
2284
/* Add right recursion onto stack */
2292
cogl_path_curve2_to (float x_1,
2297
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
2301
/* Prepare quadratic curve */
2302
quad.p1 = ctx->path_pen;
2308
/* Run subdivision */
2309
_cogl_path_bezier2_sub (&quad);
2311
/* Add last point */
2312
_cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y);
2313
ctx->path_pen = quad.p3;
2317
cogl_rel_curve2_to (float x_1,
2322
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
2324
cogl_path_curve2_to (ctx->path_pen.x + x_1,
2325
ctx->path_pen.y + y_1,
2326
ctx->path_pen.x + x_2,
2327
ctx->path_pen.y + y_2);