4
* A Low Level GPU Graphics and Utilities API
6
* Copyright (C) 2007,2008,2009,2010,2013 Intel Corporation.
8
* Permission is hereby granted, free of charge, to any person
9
* obtaining a copy of this software and associated documentation
10
* files (the "Software"), to deal in the Software without
11
* restriction, including without limitation the rights to use, copy,
12
* modify, merge, publish, distribute, sublicense, and/or sell copies
13
* of the Software, and to permit persons to whom the Software is
14
* furnished to do so, subject to the following conditions:
16
* The above copyright notice and this permission notice shall be
17
* included in all copies or substantial portions of the Software.
19
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
* Ivan Leben <ivan@openedhand.com>
30
* Øyvind Kolås <pippin@linux.intel.com>
31
* Neil Roberts <neil@linux.intel.com>
32
* Robert Bragg <robert@linux.intel.com>
35
#include "cogl-config.h"
37
#include "cogl-util.h"
38
#include "cogl-object.h"
39
#include "cogl-context-private.h"
40
#include "cogl-journal-private.h"
41
#include "cogl-pipeline-private.h"
42
#include "cogl-framebuffer-private.h"
43
#include "cogl-primitive-private.h"
44
#include "cogl-texture-private.h"
45
#include "cogl-primitives-private.h"
46
#include "cogl-private.h"
47
#include "cogl-attribute-private.h"
48
#include "cogl1-context.h"
49
#include "tesselator/tesselator.h"
51
#include "cogl-path/cogl-path.h"
52
#include "cogl-path-private.h"
53
#include "cogl-gtype-private.h"
58
#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
60
static void _cogl_path_free (CoglPath *path);
62
static void _cogl_path_build_fill_attribute_buffer (CoglPath *path);
63
static CoglPrimitive *_cogl_path_get_fill_primitive (CoglPath *path);
64
static void _cogl_path_build_stroke_attribute_buffer (CoglPath *path);
66
COGL_OBJECT_DEFINE (Path, path);
67
COGL_GTYPE_DEFINE_CLASS (Path, path);
70
_cogl_path_data_clear_vbos (CoglPathData *data)
74
if (data->fill_attribute_buffer)
76
cogl_object_unref (data->fill_attribute_buffer);
77
cogl_object_unref (data->fill_vbo_indices);
79
for (i = 0; i < COGL_PATH_N_ATTRIBUTES; i++)
80
cogl_object_unref (data->fill_attributes[i]);
82
data->fill_attribute_buffer = NULL;
85
if (data->fill_primitive)
87
cogl_object_unref (data->fill_primitive);
88
data->fill_primitive = NULL;
91
if (data->stroke_attribute_buffer)
93
cogl_object_unref (data->stroke_attribute_buffer);
95
for (i = 0; i < data->stroke_n_attributes; i++)
96
cogl_object_unref (data->stroke_attributes[i]);
98
g_free (data->stroke_attributes);
100
data->stroke_attribute_buffer = NULL;
105
_cogl_path_data_unref (CoglPathData *data)
107
if (--data->ref_count <= 0)
109
_cogl_path_data_clear_vbos (data);
111
g_array_free (data->path_nodes, TRUE);
113
g_slice_free (CoglPathData, data);
118
_cogl_path_modify (CoglPath *path)
120
/* This needs to be called whenever the path is about to be modified
121
to implement copy-on-write semantics */
123
/* If there is more than one path using the data then we need to
124
copy the data instead */
125
if (path->data->ref_count != 1)
127
CoglPathData *old_data = path->data;
129
path->data = g_slice_dup (CoglPathData, old_data);
130
path->data->path_nodes = g_array_new (FALSE, FALSE,
131
sizeof (CoglPathNode));
132
g_array_append_vals (path->data->path_nodes,
133
old_data->path_nodes->data,
134
old_data->path_nodes->len);
136
path->data->fill_attribute_buffer = NULL;
137
path->data->fill_primitive = NULL;
138
path->data->stroke_attribute_buffer = NULL;
139
path->data->ref_count = 1;
141
_cogl_path_data_unref (old_data);
144
/* The path is altered so the vbos will now be invalid */
145
_cogl_path_data_clear_vbos (path->data);
149
cogl2_path_set_fill_rule (CoglPath *path,
150
CoglPathFillRule fill_rule)
152
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
154
if (path->data->fill_rule != fill_rule)
156
_cogl_path_modify (path);
158
path->data->fill_rule = fill_rule;
163
cogl2_path_get_fill_rule (CoglPath *path)
165
_COGL_RETURN_VAL_IF_FAIL (cogl_is_path (path), COGL_PATH_FILL_RULE_NON_ZERO);
167
return path->data->fill_rule;
171
_cogl_path_add_node (CoglPath *path,
172
CoglBool new_sub_path,
176
CoglPathNode new_node;
179
_cogl_path_modify (path);
185
new_node.path_size = 0;
187
if (new_sub_path || data->path_nodes->len == 0)
188
data->last_path = data->path_nodes->len;
190
g_array_append_val (data->path_nodes, new_node);
192
g_array_index (data->path_nodes, CoglPathNode, data->last_path).path_size++;
194
if (data->path_nodes->len == 1)
196
data->path_nodes_min.x = data->path_nodes_max.x = x;
197
data->path_nodes_min.y = data->path_nodes_max.y = y;
201
if (x < data->path_nodes_min.x)
202
data->path_nodes_min.x = x;
203
if (x > data->path_nodes_max.x)
204
data->path_nodes_max.x = x;
205
if (y < data->path_nodes_min.y)
206
data->path_nodes_min.y = y;
207
if (y > data->path_nodes_max.y)
208
data->path_nodes_max.y = y;
211
/* Once the path nodes have been modified then we'll assume it's no
212
longer a rectangle. cogl2_path_rectangle will set this back to
213
TRUE if this has been called from there */
214
data->is_rectangle = FALSE;
218
_cogl_path_stroke_nodes (CoglPath *path,
219
CoglFramebuffer *framebuffer,
220
CoglPipeline *pipeline)
223
CoglPipeline *copy = NULL;
224
unsigned int path_start;
228
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
229
_COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
230
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
234
if (data->path_nodes->len == 0)
237
if (cogl_pipeline_get_n_layers (pipeline) != 0)
239
copy = cogl_pipeline_copy (pipeline);
240
_cogl_pipeline_prune_to_n_layers (copy, 0);
244
_cogl_path_build_stroke_attribute_buffer (path);
247
path_start < data->path_nodes->len;
248
path_start += node->path_size)
250
CoglPrimitive *primitive;
252
node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
255
cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_LINE_STRIP,
257
&data->stroke_attributes[path_num],
259
cogl_primitive_draw (primitive, framebuffer, pipeline);
260
cogl_object_unref (primitive);
266
cogl_object_unref (copy);
270
_cogl_path_get_bounds (CoglPath *path,
276
CoglPathData *data = path->data;
278
if (data->path_nodes->len == 0)
287
*min_x = data->path_nodes_min.x;
288
*min_y = data->path_nodes_min.y;
289
*max_x = data->path_nodes_max.x;
290
*max_y = data->path_nodes_max.y;
295
_cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path,
296
CoglFramebuffer *framebuffer,
297
CoglPipeline *pipeline)
299
/* We need at least three stencil bits to combine clips */
300
if (_cogl_framebuffer_get_stencil_bits (framebuffer) >= 3)
302
static CoglBool seen_warning = FALSE;
306
g_warning ("Paths can not be filled using materials with "
307
"sliced textures unless there is a stencil "
313
cogl_framebuffer_push_path_clip (framebuffer, path);
314
cogl_framebuffer_draw_rectangle (framebuffer,
316
path->data->path_nodes_min.x,
317
path->data->path_nodes_min.y,
318
path->data->path_nodes_max.x,
319
path->data->path_nodes_max.y);
320
cogl_framebuffer_pop_clip (framebuffer);
324
validate_layer_cb (CoglPipelineLayer *layer, void *user_data)
326
CoglBool *needs_fallback = user_data;
327
CoglTexture *texture = _cogl_pipeline_layer_get_texture (layer);
329
/* If any of the layers of the current pipeline contain sliced
330
* textures or textures with waste then it won't work to draw the
331
* path directly. Instead we fallback to pushing the path as a clip
332
* on the clip-stack and drawing the path's bounding rectangle
336
if (texture != NULL && (cogl_texture_is_sliced (texture) ||
337
!_cogl_texture_can_hardware_repeat (texture)))
338
*needs_fallback = TRUE;
340
return !*needs_fallback;
344
_cogl_path_fill_nodes (CoglPath *path,
345
CoglFramebuffer *framebuffer,
346
CoglPipeline *pipeline,
349
if (path->data->path_nodes->len == 0)
352
/* If the path is a simple rectangle then we can divert to using
353
cogl_framebuffer_draw_rectangle which should be faster because it
354
can go through the journal instead of uploading the geometry just
356
if (path->data->is_rectangle && flags == 0)
358
float x_1, y_1, x_2, y_2;
360
_cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
361
cogl_framebuffer_draw_rectangle (framebuffer,
368
CoglBool needs_fallback = FALSE;
369
CoglPrimitive *primitive;
371
_cogl_pipeline_foreach_layer_internal (pipeline,
376
_cogl_path_fill_nodes_with_clipped_rectangle (path,
382
primitive = _cogl_path_get_fill_primitive (path);
384
_cogl_primitive_draw (primitive, framebuffer, pipeline, flags);
388
/* TODO: Update to the protoype used in the Cogl master branch.
389
* This is experimental API but not in sync with the cogl_path_fill()
390
* api in Cogl master which takes explicit framebuffer and pipeline
393
cogl2_path_fill (CoglPath *path)
395
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
397
_cogl_path_fill_nodes (path,
398
cogl_get_draw_framebuffer (),
403
/* TODO: Update to the protoype used in the Cogl master branch.
404
* This is experimental API but not in sync with the cogl_path_fill()
405
* api in Cogl master which takes explicit framebuffer and pipeline
408
cogl2_path_stroke (CoglPath *path)
410
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
412
if (path->data->path_nodes->len == 0)
415
_cogl_path_stroke_nodes (path,
416
cogl_get_draw_framebuffer (),
421
cogl2_path_move_to (CoglPath *path,
427
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
429
_cogl_path_add_node (path, TRUE, x, y);
433
data->path_start.x = x;
434
data->path_start.y = y;
436
data->path_pen = data->path_start;
440
cogl2_path_rel_move_to (CoglPath *path,
446
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
450
cogl2_path_move_to (path,
451
data->path_pen.x + x,
452
data->path_pen.y + y);
456
cogl2_path_line_to (CoglPath *path,
462
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
464
_cogl_path_add_node (path, FALSE, x, y);
468
data->path_pen.x = x;
469
data->path_pen.y = y;
473
cogl2_path_rel_line_to (CoglPath *path,
479
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
483
cogl2_path_line_to (path,
484
data->path_pen.x + x,
485
data->path_pen.y + y);
489
cogl2_path_close (CoglPath *path)
491
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
493
_cogl_path_add_node (path, FALSE, path->data->path_start.x,
494
path->data->path_start.y);
496
path->data->path_pen = path->data->path_start;
500
cogl2_path_line (CoglPath *path,
506
cogl2_path_move_to (path, x_1, y_1);
507
cogl2_path_line_to (path, x_2, y_2);
511
cogl2_path_polyline (CoglPath *path,
517
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
519
cogl2_path_move_to (path, coords[0], coords[1]);
521
for (c = 1; c < num_points; ++c)
522
cogl2_path_line_to (path, coords[2*c], coords[2*c+1]);
526
cogl2_path_polygon (CoglPath *path,
530
cogl2_path_polyline (path, coords, num_points);
531
cogl2_path_close (path);
535
cogl2_path_rectangle (CoglPath *path,
541
CoglBool is_rectangle;
543
/* If the path was previously empty and the rectangle isn't mirrored
544
then we'll record that this is a simple rectangle path so that we
546
is_rectangle = (path->data->path_nodes->len == 0 &&
550
cogl2_path_move_to (path, x_1, y_1);
551
cogl2_path_line_to (path, x_2, y_1);
552
cogl2_path_line_to (path, x_2, y_2);
553
cogl2_path_line_to (path, x_1, y_2);
554
cogl2_path_close (path);
556
path->data->is_rectangle = is_rectangle;
560
_cogl_path_is_rectangle (CoglPath *path)
562
return path->data->is_rectangle;
566
_cogl_path_arc (CoglPath *path,
574
unsigned int move_first)
582
/* Fix invalid angles */
584
if (angle_1 == angle_2 || angle_step == 0x0)
587
if (angle_step < 0x0)
588
angle_step = -angle_step;
590
/* Walk the arc by given step */
595
cosa = cosf (a * (G_PI/180.0));
596
sina = sinf (a * (G_PI/180.0));
598
px = center_x + (cosa * radius_x);
599
py = center_y + (sina * radius_y);
601
if (a == angle_1 && move_first)
602
cogl2_path_move_to (path, px, py);
604
cogl2_path_line_to (path, px, py);
606
if (G_LIKELY (angle_2 > angle_1))
620
/* Make sure the final point is drawn */
622
cosa = cosf (angle_2 * (G_PI/180.0));
623
sina = sinf (angle_2 * (G_PI/180.0));
625
px = center_x + (cosa * radius_x);
626
py = center_y + (sina * radius_y);
628
cogl2_path_line_to (path, px, py);
632
cogl2_path_arc (CoglPath *path,
640
float angle_step = 10;
642
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
644
/* it is documented that a move to is needed to create a freestanding
647
_cogl_path_arc (path,
651
angle_step, 0 /* no move */);
656
_cogl_path_rel_arc (CoglPath *path,
669
_cogl_path_arc (path,
670
data->path_pen.x + center_x,
671
data->path_pen.y + center_y,
674
angle_step, 0 /* no move */);
678
cogl2_path_ellipse (CoglPath *path,
684
float angle_step = 10;
686
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
688
/* FIXME: if shows to be slow might be optimized
689
* by mirroring just a quarter of it */
691
_cogl_path_arc (path,
695
angle_step, 1 /* move first */);
697
cogl2_path_close (path);
701
cogl2_path_round_rectangle (CoglPath *path,
709
float inner_width = x_2 - x_1 - radius * 2;
710
float inner_height = y_2 - y_1 - radius * 2;
712
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
714
cogl2_path_move_to (path, x_1, y_1 + radius);
715
_cogl_path_rel_arc (path,
722
cogl2_path_line_to (path,
723
path->data->path_pen.x + inner_width,
724
path->data->path_pen.y);
725
_cogl_path_rel_arc (path,
732
cogl2_path_line_to (path,
733
path->data->path_pen.x,
734
path->data->path_pen.y + inner_height);
736
_cogl_path_rel_arc (path,
743
cogl2_path_line_to (path,
744
path->data->path_pen.x - inner_width,
745
path->data->path_pen.y);
746
_cogl_path_rel_arc (path,
753
cogl2_path_close (path);
757
_cogl_path_bezier3_sub (CoglPath *path,
760
CoglBezCubic cubics[_COGL_MAX_BEZ_RECURSE_DEPTH];
762
CoglBezCubic *cright;
774
/* Put first curve on stack */
783
/* Calculate distance of control points from their
784
* counterparts on the line between end points */
785
dif1.x = (c->p2.x * 3) - (c->p1.x * 2) - c->p4.x;
786
dif1.y = (c->p2.y * 3) - (c->p1.y * 2) - c->p4.y;
787
dif2.x = (c->p3.x * 3) - (c->p4.x * 2) - c->p1.x;
788
dif2.y = (c->p3.y * 3) - (c->p4.y * 2) - c->p1.y;
800
/* Pick the greatest of two distances */
801
if (dif1.x < dif2.x) dif1.x = dif2.x;
802
if (dif1.y < dif2.y) dif1.y = dif2.y;
804
/* Cancel if the curve is flat enough */
805
if (dif1.x + dif1.y <= 1.0 ||
806
cindex == _COGL_MAX_BEZ_RECURSE_DEPTH-1)
808
/* Add subdivision point (skip last) */
812
_cogl_path_add_node (path, FALSE, c->p4.x, c->p4.y);
819
/* Left recursion goes on top of stack! */
820
cright = c; cleft = &cubics[++cindex];
822
/* Subdivide into 2 sub-curves */
823
c1.x = ((c->p1.x + c->p2.x) / 2);
824
c1.y = ((c->p1.y + c->p2.y) / 2);
825
mm.x = ((c->p2.x + c->p3.x) / 2);
826
mm.y = ((c->p2.y + c->p3.y) / 2);
827
c5.x = ((c->p3.x + c->p4.x) / 2);
828
c5.y = ((c->p3.y + c->p4.y) / 2);
830
c2.x = ((c1.x + mm.x) / 2);
831
c2.y = ((c1.y + mm.y) / 2);
832
c4.x = ((mm.x + c5.x) / 2);
833
c4.y = ((mm.y + c5.y) / 2);
835
c3.x = ((c2.x + c4.x) / 2);
836
c3.y = ((c2.y + c4.y) / 2);
838
/* Add left recursion to stack */
844
/* Add right recursion to stack */
853
cogl2_path_curve_to (CoglPath *path,
863
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
865
/* Prepare cubic curve */
866
cubic.p1 = path->data->path_pen;
874
/* Run subdivision */
875
_cogl_path_bezier3_sub (path, &cubic);
878
_cogl_path_add_node (path, FALSE, cubic.p4.x, cubic.p4.y);
879
path->data->path_pen = cubic.p4;
883
cogl2_path_rel_curve_to (CoglPath *path,
893
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
897
cogl2_path_curve_to (path,
898
data->path_pen.x + x_1,
899
data->path_pen.y + y_1,
900
data->path_pen.x + x_2,
901
data->path_pen.y + y_2,
902
data->path_pen.x + x_3,
903
data->path_pen.y + y_3);
907
cogl2_path_new (void)
912
_COGL_GET_CONTEXT (ctx, NULL);
914
path = g_slice_new (CoglPath);
915
data = path->data = g_slice_new (CoglPathData);
919
data->fill_rule = COGL_PATH_FILL_RULE_EVEN_ODD;
920
data->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
922
data->fill_attribute_buffer = NULL;
923
data->stroke_attribute_buffer = NULL;
924
data->fill_primitive = NULL;
925
data->is_rectangle = FALSE;
927
return _cogl_path_object_new (path);
931
cogl_path_copy (CoglPath *old_path)
935
_COGL_RETURN_VAL_IF_FAIL (cogl_is_path (old_path), NULL);
937
new_path = g_slice_new (CoglPath);
938
new_path->data = old_path->data;
939
new_path->data->ref_count++;
941
return _cogl_path_object_new (new_path);
945
_cogl_path_free (CoglPath *path)
947
_cogl_path_data_unref (path->data);
948
g_slice_free (CoglPath, path);
951
/* If second order beziers were needed the following code could
957
_cogl_path_bezier2_sub (CoglPath *path,
960
CoglBezQuad quads[_COGL_MAX_BEZ_RECURSE_DEPTH];
971
/* Put first curve on stack */
975
/* While stack is not empty */
981
/* Calculate distance of control point from its
982
* counterpart on the line between end points */
983
mid.x = ((q->p1.x + q->p3.x) / 2);
984
mid.y = ((q->p1.y + q->p3.y) / 2);
985
dif.x = (q->p2.x - mid.x);
986
dif.y = (q->p2.y - mid.y);
987
if (dif.x < 0) dif.x = -dif.x;
988
if (dif.y < 0) dif.y = -dif.y;
990
/* Cancel if the curve is flat enough */
991
if (dif.x + dif.y <= 1.0 ||
992
qindex == _COGL_MAX_BEZ_RECURSE_DEPTH - 1)
994
/* Add subdivision point (skip last) */
995
if (qindex == 0) return;
996
_cogl_path_add_node (path, FALSE, q->p3.x, q->p3.y);
1000
/* Left recursion goes on top of stack! */
1001
qright = q; qleft = &quads[++qindex];
1003
/* Subdivide into 2 sub-curves */
1004
c1.x = ((q->p1.x + q->p2.x) / 2);
1005
c1.y = ((q->p1.y + q->p2.y) / 2);
1006
c3.x = ((q->p2.x + q->p3.x) / 2);
1007
c3.y = ((q->p2.y + q->p3.y) / 2);
1008
c2.x = ((c1.x + c3.x) / 2);
1009
c2.y = ((c1.y + c3.y) / 2);
1011
/* Add left recursion onto stack */
1016
/* Add right recursion onto stack */
1024
cogl_path_curve2_to (CoglPath *path,
1032
/* Prepare quadratic curve */
1033
quad.p1 = path->data->path_pen;
1039
/* Run subdivision */
1040
_cogl_path_bezier2_sub (&quad);
1042
/* Add last point */
1043
_cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y);
1044
path->data->path_pen = quad.p3;
1048
cogl_rel_curve2_to (CoglPath *path,
1056
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
1060
cogl_path_curve2_to (data->path_pen.x + x_1,
1061
data->path_pen.y + y_1,
1062
data->path_pen.x + x_2,
1063
data->path_pen.y + y_2);
1068
typedef struct _CoglPathTesselator CoglPathTesselator;
1069
typedef struct _CoglPathTesselatorVertex CoglPathTesselatorVertex;
1071
struct _CoglPathTesselator
1073
GLUtesselator *glu_tess;
1074
GLenum primitive_type;
1076
/* Array of CoglPathTesselatorVertex. This needs to grow when the
1077
combine callback is called */
1079
/* Array of integers for the indices into the vertices array. Each
1080
element will either be uint8_t, uint16_t or uint32_t depending on
1081
the number of vertices */
1083
CoglIndicesType indices_type;
1084
/* Indices used to split fans and strips */
1085
int index_a, index_b;
1088
struct _CoglPathTesselatorVertex
1094
_cogl_path_tesselator_begin (GLenum type,
1095
CoglPathTesselator *tess)
1097
g_assert (type == GL_TRIANGLES ||
1098
type == GL_TRIANGLE_FAN ||
1099
type == GL_TRIANGLE_STRIP);
1101
tess->primitive_type = type;
1102
tess->vertex_number = 0;
1105
static CoglIndicesType
1106
_cogl_path_tesselator_get_indices_type_for_size (int n_vertices)
1108
if (n_vertices <= 256)
1109
return COGL_INDICES_TYPE_UNSIGNED_BYTE;
1110
else if (n_vertices <= 65536)
1111
return COGL_INDICES_TYPE_UNSIGNED_SHORT;
1113
return COGL_INDICES_TYPE_UNSIGNED_INT;
1117
_cogl_path_tesselator_allocate_indices_array (CoglPathTesselator *tess)
1119
switch (tess->indices_type)
1121
case COGL_INDICES_TYPE_UNSIGNED_BYTE:
1122
tess->indices = g_array_new (FALSE, FALSE, sizeof (uint8_t));
1125
case COGL_INDICES_TYPE_UNSIGNED_SHORT:
1126
tess->indices = g_array_new (FALSE, FALSE, sizeof (uint16_t));
1129
case COGL_INDICES_TYPE_UNSIGNED_INT:
1130
tess->indices = g_array_new (FALSE, FALSE, sizeof (uint32_t));
1136
_cogl_path_tesselator_add_index (CoglPathTesselator *tess, int vertex_index)
1138
switch (tess->indices_type)
1140
case COGL_INDICES_TYPE_UNSIGNED_BYTE:
1142
uint8_t val = vertex_index;
1143
g_array_append_val (tess->indices, val);
1147
case COGL_INDICES_TYPE_UNSIGNED_SHORT:
1149
uint16_t val = vertex_index;
1150
g_array_append_val (tess->indices, val);
1154
case COGL_INDICES_TYPE_UNSIGNED_INT:
1156
uint32_t val = vertex_index;
1157
g_array_append_val (tess->indices, val);
1164
_cogl_path_tesselator_vertex (void *vertex_data,
1165
CoglPathTesselator *tess)
1169
vertex_index = GPOINTER_TO_INT (vertex_data);
1171
/* This tries to convert all of the primitives into GL_TRIANGLES
1172
with indices to share vertices */
1173
switch (tess->primitive_type)
1176
/* Directly use the vertex */
1177
_cogl_path_tesselator_add_index (tess, vertex_index);
1180
case GL_TRIANGLE_FAN:
1181
if (tess->vertex_number == 0)
1182
tess->index_a = vertex_index;
1183
else if (tess->vertex_number == 1)
1184
tess->index_b = vertex_index;
1187
/* Create a triangle with the first vertex, the previous
1188
vertex and this vertex */
1189
_cogl_path_tesselator_add_index (tess, tess->index_a);
1190
_cogl_path_tesselator_add_index (tess, tess->index_b);
1191
_cogl_path_tesselator_add_index (tess, vertex_index);
1192
/* Next time we will use this vertex as the previous
1194
tess->index_b = vertex_index;
1198
case GL_TRIANGLE_STRIP:
1199
if (tess->vertex_number == 0)
1200
tess->index_a = vertex_index;
1201
else if (tess->vertex_number == 1)
1202
tess->index_b = vertex_index;
1205
_cogl_path_tesselator_add_index (tess, tess->index_a);
1206
_cogl_path_tesselator_add_index (tess, tess->index_b);
1207
_cogl_path_tesselator_add_index (tess, vertex_index);
1208
if (tess->vertex_number & 1)
1209
tess->index_b = vertex_index;
1211
tess->index_a = vertex_index;
1216
g_assert_not_reached ();
1219
tess->vertex_number++;
1223
_cogl_path_tesselator_end (CoglPathTesselator *tess)
1225
tess->primitive_type = GL_FALSE;
1229
_cogl_path_tesselator_combine (double coords[3],
1230
void *vertex_data[4],
1233
CoglPathTesselator *tess)
1235
CoglPathTesselatorVertex *vertex;
1236
CoglIndicesType new_indices_type;
1239
/* Add a new vertex to the array */
1240
g_array_set_size (tess->vertices, tess->vertices->len + 1);
1241
vertex = &g_array_index (tess->vertices,
1242
CoglPathTesselatorVertex,
1243
tess->vertices->len - 1);
1244
/* The data is just the index to the vertex */
1245
*out_data = GINT_TO_POINTER (tess->vertices->len - 1);
1246
/* Set the coordinates of the new vertex */
1247
vertex->x = coords[0];
1248
vertex->y = coords[1];
1249
/* Generate the texture coordinates as the weighted average of the
1250
four incoming coordinates */
1253
for (i = 0; i < 4; i++)
1255
CoglPathTesselatorVertex *old_vertex =
1256
&g_array_index (tess->vertices, CoglPathTesselatorVertex,
1257
GPOINTER_TO_INT (vertex_data[i]));
1258
vertex->s += old_vertex->s * weight[i];
1259
vertex->t += old_vertex->t * weight[i];
1262
/* Check if we've reached the limit for the data type of our indices */
1264
_cogl_path_tesselator_get_indices_type_for_size (tess->vertices->len);
1265
if (new_indices_type != tess->indices_type)
1267
CoglIndicesType old_indices_type = new_indices_type;
1268
GArray *old_vertices = tess->indices;
1270
/* Copy the indices to an array of the new type */
1271
tess->indices_type = new_indices_type;
1272
_cogl_path_tesselator_allocate_indices_array (tess);
1274
switch (old_indices_type)
1276
case COGL_INDICES_TYPE_UNSIGNED_BYTE:
1277
for (i = 0; i < old_vertices->len; i++)
1278
_cogl_path_tesselator_add_index (tess,
1279
g_array_index (old_vertices,
1283
case COGL_INDICES_TYPE_UNSIGNED_SHORT:
1284
for (i = 0; i < old_vertices->len; i++)
1285
_cogl_path_tesselator_add_index (tess,
1286
g_array_index (old_vertices,
1290
case COGL_INDICES_TYPE_UNSIGNED_INT:
1291
for (i = 0; i < old_vertices->len; i++)
1292
_cogl_path_tesselator_add_index (tess,
1293
g_array_index (old_vertices,
1298
g_array_free (old_vertices, TRUE);
1303
_cogl_path_build_fill_attribute_buffer (CoglPath *path)
1305
CoglPathTesselator tess;
1306
unsigned int path_start = 0;
1307
CoglPathData *data = path->data;
1310
/* If we've already got a vbo then we don't need to do anything */
1311
if (data->fill_attribute_buffer)
1314
tess.primitive_type = FALSE;
1316
/* Generate a vertex for each point on the path */
1317
tess.vertices = g_array_new (FALSE, FALSE, sizeof (CoglPathTesselatorVertex));
1318
g_array_set_size (tess.vertices, data->path_nodes->len);
1319
for (i = 0; i < data->path_nodes->len; i++)
1321
CoglPathNode *node =
1322
&g_array_index (data->path_nodes, CoglPathNode, i);
1323
CoglPathTesselatorVertex *vertex =
1324
&g_array_index (tess.vertices, CoglPathTesselatorVertex, i);
1326
vertex->x = node->x;
1327
vertex->y = node->y;
1329
/* Add texture coordinates so that a texture would be drawn to
1330
fit the bounding box of the path and then cropped by the
1332
if (data->path_nodes_min.x == data->path_nodes_max.x)
1335
vertex->s = ((node->x - data->path_nodes_min.x)
1336
/ (data->path_nodes_max.x - data->path_nodes_min.x));
1337
if (data->path_nodes_min.y == data->path_nodes_max.y)
1340
vertex->t = ((node->y - data->path_nodes_min.y)
1341
/ (data->path_nodes_max.y - data->path_nodes_min.y));
1345
_cogl_path_tesselator_get_indices_type_for_size (data->path_nodes->len);
1346
_cogl_path_tesselator_allocate_indices_array (&tess);
1348
tess.glu_tess = gluNewTess ();
1350
if (data->fill_rule == COGL_PATH_FILL_RULE_EVEN_ODD)
1351
gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE,
1352
GLU_TESS_WINDING_ODD);
1354
gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE,
1355
GLU_TESS_WINDING_NONZERO);
1357
/* All vertices are on the xy-plane */
1358
gluTessNormal (tess.glu_tess, 0.0, 0.0, 1.0);
1360
gluTessCallback (tess.glu_tess, GLU_TESS_BEGIN_DATA,
1361
_cogl_path_tesselator_begin);
1362
gluTessCallback (tess.glu_tess, GLU_TESS_VERTEX_DATA,
1363
_cogl_path_tesselator_vertex);
1364
gluTessCallback (tess.glu_tess, GLU_TESS_END_DATA,
1365
_cogl_path_tesselator_end);
1366
gluTessCallback (tess.glu_tess, GLU_TESS_COMBINE_DATA,
1367
_cogl_path_tesselator_combine);
1369
gluTessBeginPolygon (tess.glu_tess, &tess);
1371
while (path_start < data->path_nodes->len)
1373
CoglPathNode *node =
1374
&g_array_index (data->path_nodes, CoglPathNode, path_start);
1376
gluTessBeginContour (tess.glu_tess);
1378
for (i = 0; i < node->path_size; i++)
1380
double vertex[3] = { node[i].x, node[i].y, 0.0 };
1381
gluTessVertex (tess.glu_tess, vertex,
1382
GINT_TO_POINTER (i + path_start));
1385
gluTessEndContour (tess.glu_tess);
1387
path_start += node->path_size;
1390
gluTessEndPolygon (tess.glu_tess);
1392
gluDeleteTess (tess.glu_tess);
1394
data->fill_attribute_buffer =
1395
cogl_attribute_buffer_new (data->context,
1396
sizeof (CoglPathTesselatorVertex) *
1398
tess.vertices->data);
1399
g_array_free (tess.vertices, TRUE);
1401
data->fill_attributes[0] =
1402
cogl_attribute_new (data->fill_attribute_buffer,
1404
sizeof (CoglPathTesselatorVertex),
1405
G_STRUCT_OFFSET (CoglPathTesselatorVertex, x),
1406
2, /* n_components */
1407
COGL_ATTRIBUTE_TYPE_FLOAT);
1408
data->fill_attributes[1] =
1409
cogl_attribute_new (data->fill_attribute_buffer,
1410
"cogl_tex_coord0_in",
1411
sizeof (CoglPathTesselatorVertex),
1412
G_STRUCT_OFFSET (CoglPathTesselatorVertex, s),
1413
2, /* n_components */
1414
COGL_ATTRIBUTE_TYPE_FLOAT);
1416
data->fill_vbo_indices = cogl_indices_new (data->context,
1420
data->fill_vbo_n_indices = tess.indices->len;
1421
g_array_free (tess.indices, TRUE);
1424
static CoglPrimitive *
1425
_cogl_path_get_fill_primitive (CoglPath *path)
1427
if (path->data->fill_primitive)
1428
return path->data->fill_primitive;
1430
_cogl_path_build_fill_attribute_buffer (path);
1432
path->data->fill_primitive =
1433
cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
1434
path->data->fill_vbo_n_indices,
1435
path->data->fill_attributes,
1436
COGL_PATH_N_ATTRIBUTES);
1437
cogl_primitive_set_indices (path->data->fill_primitive,
1438
path->data->fill_vbo_indices,
1439
path->data->fill_vbo_n_indices);
1441
return path->data->fill_primitive;
1444
static CoglClipStack *
1445
_cogl_clip_stack_push_from_path (CoglClipStack *stack,
1447
CoglMatrixEntry *modelview_entry,
1448
CoglMatrixEntry *projection_entry,
1449
const float *viewport)
1451
float x_1, y_1, x_2, y_2;
1453
_cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
1455
/* If the path is a simple rectangle then we can divert to pushing a
1456
rectangle clip instead which usually won't involve the stencil
1458
if (_cogl_path_is_rectangle (path))
1459
return _cogl_clip_stack_push_rectangle (stack,
1467
CoglPrimitive *primitive = _cogl_path_get_fill_primitive (path);
1469
return _cogl_clip_stack_push_primitive (stack,
1479
cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
1482
CoglMatrixEntry *modelview_entry =
1483
_cogl_framebuffer_get_modelview_entry (framebuffer);
1484
CoglMatrixEntry *projection_entry =
1485
_cogl_framebuffer_get_projection_entry (framebuffer);
1486
/* XXX: It would be nicer if we stored the private viewport as a
1487
* vec4 so we could avoid this redundant copy. */
1488
float viewport[] = {
1489
framebuffer->viewport_x,
1490
framebuffer->viewport_y,
1491
framebuffer->viewport_width,
1492
framebuffer->viewport_height
1495
framebuffer->clip_stack =
1496
_cogl_clip_stack_push_from_path (framebuffer->clip_stack,
1502
if (framebuffer->context->current_draw_buffer == framebuffer)
1503
framebuffer->context->current_draw_buffer_changes |=
1504
COGL_FRAMEBUFFER_STATE_CLIP;
1507
/* XXX: deprecated */
1509
cogl_clip_push_from_path (CoglPath *path)
1511
cogl_framebuffer_push_path_clip (cogl_get_draw_framebuffer (), path);
1515
_cogl_path_build_stroke_attribute_buffer (CoglPath *path)
1517
CoglPathData *data = path->data;
1519
unsigned int n_attributes = 0;
1520
unsigned int path_start;
1522
floatVec2 *buffer_p;
1525
/* If we've already got a cached vbo then we don't need to do anything */
1526
if (data->stroke_attribute_buffer)
1529
data->stroke_attribute_buffer =
1530
cogl_attribute_buffer_new_with_size (data->context,
1531
data->path_nodes->len *
1532
sizeof (floatVec2));
1534
buffer = COGL_BUFFER (data->stroke_attribute_buffer);
1535
buffer_p = _cogl_buffer_map_for_fill_or_fallback (buffer);
1537
/* Copy the vertices in and count the number of sub paths. Each sub
1538
path will form a separate attribute so we can paint the disjoint
1540
for (path_start = 0;
1541
path_start < data->path_nodes->len;
1542
path_start += node->path_size)
1544
node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
1546
for (i = 0; i < node->path_size; i++)
1548
buffer_p[path_start + i].x = node[i].x;
1549
buffer_p[path_start + i].y = node[i].y;
1555
_cogl_buffer_unmap_for_fill_or_fallback (buffer);
1557
data->stroke_attributes = g_new (CoglAttribute *, n_attributes);
1559
/* Now we can loop the sub paths again to create the attributes */
1560
for (i = 0, path_start = 0;
1561
path_start < data->path_nodes->len;
1562
i++, path_start += node->path_size)
1564
node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
1566
data->stroke_attributes[i] =
1567
cogl_attribute_new (data->stroke_attribute_buffer,
1570
path_start * sizeof (floatVec2),
1571
2, /* n_components */
1572
COGL_ATTRIBUTE_TYPE_FLOAT);
1575
data->stroke_n_attributes = n_attributes;
1578
/* XXX: deprecated */
1580
cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
1581
CoglPipeline *pipeline,
1584
_COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
1585
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1586
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
1588
_cogl_path_fill_nodes (path, framebuffer, pipeline, 0 /* flags */);
1591
/* XXX: deprecated */
1593
cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
1594
CoglPipeline *pipeline,
1597
_COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
1598
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1599
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
1601
_cogl_path_stroke_nodes (path, framebuffer, pipeline);