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-clip-stack.h"
32
#include "cogl-material-private.h"
38
#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
41
_cogl_path_add_node (gboolean new_sub_path,
45
CoglPathNode new_node;
47
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
51
new_node.path_size = 0;
53
if (new_sub_path || ctx->path_nodes->len == 0)
54
ctx->last_path = ctx->path_nodes->len;
56
g_array_append_val (ctx->path_nodes, new_node);
58
g_array_index (ctx->path_nodes, CoglPathNode, ctx->last_path).path_size++;
60
if (ctx->path_nodes->len == 1)
62
ctx->path_nodes_min.x = ctx->path_nodes_max.x = x;
63
ctx->path_nodes_min.y = ctx->path_nodes_max.y = y;
67
if (x < ctx->path_nodes_min.x) ctx->path_nodes_min.x = x;
68
if (x > ctx->path_nodes_max.x) ctx->path_nodes_max.x = x;
69
if (y < ctx->path_nodes_min.y) ctx->path_nodes_min.y = y;
70
if (y > ctx->path_nodes_max.y) ctx->path_nodes_max.y = y;
75
_cogl_path_stroke_nodes ()
78
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
79
CoglMaterialFlushOptions options;
81
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
83
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
84
cogl_enable (enable_flags);
86
options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK;
87
options.disable_layers = (guint32)~0;
88
_cogl_material_flush_gl_state (ctx->source_material,&options);
89
_cogl_flush_matrix_stacks();
91
while (path_start < ctx->path_nodes->len)
93
CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode,
96
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
98
+ G_STRUCT_OFFSET (CoglPathNode, x)) );
99
GE( glDrawArrays (GL_LINE_STRIP, 0, path->path_size) );
101
path_start += path->path_size;
106
_cogl_path_get_bounds (floatVec2 nodes_min,
113
*bounds_x = nodes_min.x;
114
*bounds_y = nodes_min.y;
115
*bounds_w = nodes_max.x - *bounds_x;
116
*bounds_h = nodes_max.y - *bounds_y;
119
static gint compare_ints (gconstpointer a,
122
return GPOINTER_TO_INT(a)-GPOINTER_TO_INT(b);
126
_cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
132
guint path_start = 0;
133
guint sub_path_num = 0;
138
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
140
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
142
/* Just setup a simple material that doesn't use texturing... */
143
_cogl_material_flush_gl_state (ctx->stencil_material, NULL);
146
_cogl_material_get_cogl_enable_flags (ctx->source_material);
147
cogl_enable (enable_flags);
149
_cogl_path_get_bounds (nodes_min, nodes_max,
150
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
154
GE( glStencilMask (2) );
155
GE( glStencilFunc (GL_LEQUAL, 0x2, 0x6) );
159
GE( glClear (GL_STENCIL_BUFFER_BIT) );
160
GE( glStencilMask (1) );
161
GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) );
164
GE( glEnable (GL_STENCIL_TEST) );
165
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
167
GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
168
GE( glDepthMask (FALSE) );
170
_cogl_current_matrix_state_flush ();
171
while (path_start < path_size)
173
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
175
+ G_STRUCT_OFFSET (CoglPathNode, x)) );
176
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, path->path_size) );
178
if (sub_path_num > 0)
180
/* Union the two stencil buffers bits into the least
182
GE( glStencilMask (merge ? 6 : 3) );
183
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
184
cogl_rectangle (bounds_x, bounds_y,
185
bounds_x + bounds_w, bounds_y + bounds_h);
187
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
190
GE( glStencilMask (merge ? 4 : 2) );
192
path_start += path->path_size;
193
path += path->path_size;
199
/* Now we have the new stencil buffer in bit 1 and the old
200
stencil buffer in bit 0 so we need to intersect them */
201
GE( glStencilMask (3) );
202
GE( glStencilFunc (GL_NEVER, 0x2, 0x3) );
203
GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
204
/* Decrement all of the bits twice so that only pixels where the
205
value is 3 will remain */
207
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
208
_cogl_current_matrix_push ();
209
_cogl_current_matrix_identity ();
211
/* Cogl generally assumes the modelview matrix is current, so since
212
* cogl_rectangle will be flushing GL state and emitting geometry
213
* to OpenGL it will be confused if we leave the projection matrix
215
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
216
_cogl_current_matrix_push ();
217
_cogl_current_matrix_identity ();
219
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
220
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
222
_cogl_current_matrix_pop ();
224
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
225
_cogl_current_matrix_pop ();
227
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
230
GE( glStencilMask (~(GLuint) 0) );
231
GE( glDepthMask (TRUE) );
232
GE( glColorMask (TRUE, TRUE, TRUE, TRUE) );
234
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
235
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
239
_cogl_path_fill_nodes_scanlines (CoglPathNode *path,
246
/* This is our edge list it stores intersections between our
247
* curve and scanlines, it should probably be implemented with a
248
* data structure that has smaller overhead for inserting the
249
* curve/scanline intersections.
251
GSList *scanlines[bounds_h];
258
gint lastdir=-2; /* last direction we vere moving */
259
gint lastline=-1; /* the previous scanline we added to */
261
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
263
/* clear scanline intersection lists */
264
for (i=0; i < bounds_h; i++)
267
first_x = prev_x = (path->x);
268
first_y = prev_y = (path->y);
270
/* create scanline intersection list */
271
for (i=1; i < path_size; i++)
273
gint dest_x = (path[i].x);
274
gint dest_y = (path[i].y);
281
dx = dest_x - prev_x;
282
dy = dest_y - prev_y;
291
/* do linear interpolation between vertexes */
292
for (y=prev_y; y!= dest_y; y += ydir)
295
/* only add a point if the scanline has changed and we're
298
if (y-bounds_y >= 0 &&
299
y-bounds_y < bounds_h &&
302
gint x = prev_x + (dx * (y-prev_y)) / dy;
304
scanlines[ y - bounds_y ]=
305
g_slist_insert_sorted (scanlines[ y - bounds_y],
309
if (ydir != lastdir && /* add a double entry when changing */
310
lastdir!=-2) /* vertical direction */
311
scanlines[ y - bounds_y ]=
312
g_slist_insert_sorted (scanlines[ y - bounds_y],
323
/* if we're on the last knot, fake the first vertex being a
325
if (path_size == i+1)
329
i++; /* to make the loop finally end */
339
/* count number of spans */
340
for (i=0; i < bounds_h; i++)
342
GSList *iter = scanlines[i];
345
GSList *next = iter->next;
350
/* draw the segments that should be visible */
355
coords = g_malloc0 (spans * sizeof (GLfloat) * 3 * 2 * 2);
358
/* build list of triangles */
359
for (i=0; i < bounds_h; i++)
361
GSList *iter = scanlines[i];
364
GSList *next = iter->next;
370
x_0 = GPOINTER_TO_INT (iter->data);
371
x_1 = GPOINTER_TO_INT (next->data);
373
y_1 = bounds_y + i + 1.0625f;
374
/* render scanlines 1.0625 high to avoid gaps when
377
coords[span_no * 12 + 0] = x_0;
378
coords[span_no * 12 + 1] = y_0;
379
coords[span_no * 12 + 2] = x_1;
380
coords[span_no * 12 + 3] = y_0;
381
coords[span_no * 12 + 4] = x_1;
382
coords[span_no * 12 + 5] = y_1;
383
coords[span_no * 12 + 6] = x_0;
384
coords[span_no * 12 + 7] = y_0;
385
coords[span_no * 12 + 8] = x_0;
386
coords[span_no * 12 + 9] = y_1;
387
coords[span_no * 12 + 10] = x_1;
388
coords[span_no * 12 + 11] = y_1;
393
for (i=0; i < bounds_h; i++)
395
g_slist_free (scanlines[i]);
398
/* render triangles */
399
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
400
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
401
GE ( glVertexPointer (2, GL_FLOAT, 0, coords ) );
402
GE ( glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3));
408
_cogl_path_fill_nodes ()
415
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
417
_cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max,
418
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
420
if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
422
_cogl_add_path_to_stencil_buffer (ctx->path_nodes_min,
424
ctx->path_nodes->len,
425
&g_array_index (ctx->path_nodes,
427
ctx->clip.stencil_used);
429
cogl_rectangle (bounds_x, bounds_y,
430
bounds_x + bounds_w, bounds_y + bounds_h);
432
/* The stencil buffer now contains garbage so the clip area needs to
434
ctx->clip.stack_dirty = TRUE;
438
guint path_start = 0;
440
while (path_start < ctx->path_nodes->len)
442
CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode,
445
_cogl_path_fill_nodes_scanlines (path,
450
path_start += path->path_size;