diff --git a/cogl/Makefile.am b/cogl/Makefile.am index c6dba04fc..ac934394a 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -97,6 +97,7 @@ cogl_sources_c = \ $(srcdir)/cogl-bitmap-fallback.c \ $(srcdir)/cogl-primitives.h \ $(srcdir)/cogl-primitives.c \ + $(srcdir)/cogl-path-private.h \ $(srcdir)/cogl-path.h \ $(srcdir)/cogl-path.c \ $(srcdir)/cogl-bitmap-pixbuf.c \ diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c index 0a3d13351..427672592 100644 --- a/cogl/cogl-clip-stack.c +++ b/cogl/cogl-clip-stack.c @@ -38,13 +38,7 @@ #include "cogl-framebuffer-private.h" #include "cogl-journal-private.h" #include "cogl-util.h" - -void _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, - floatVec2 nodes_max, - unsigned int path_size, - CoglPathNode *path, - gboolean merge, - gboolean need_clear); +#include "cogl-path-private.h" typedef struct _CoglClipStack CoglClipStack; @@ -96,11 +90,7 @@ struct _CoglClipStackEntryPath /* The matrix that was current when the clip was set */ CoglMatrix matrix; - floatVec2 path_nodes_min; - floatVec2 path_nodes_max; - - unsigned int path_size; - CoglPathNode path[1]; + CoglHandle path; }; static void @@ -567,15 +557,10 @@ cogl_clip_push_from_path_preserve (void) stack = clip_state->stacks->data; - entry = g_malloc (sizeof (CoglClipStackEntryPath) - + sizeof (CoglPathNode) * (ctx->path_nodes->len - 1)); + entry = g_slice_new (CoglClipStackEntryPath); entry->type = COGL_CLIP_STACK_PATH; - entry->path_nodes_min = ctx->path_nodes_min; - entry->path_nodes_max = ctx->path_nodes_max; - entry->path_size = ctx->path_nodes->len; - memcpy (entry->path, ctx->path_nodes->data, - sizeof (CoglPathNode) * ctx->path_nodes->len); + entry->path = cogl_path_copy (cogl_path_get ()); cogl_get_modelview_matrix (&entry->matrix); @@ -617,7 +602,10 @@ _cogl_clip_pop_real (CoglClipStackState *clip_state) else if (type == COGL_CLIP_STACK_WINDOW_RECT) g_slice_free (CoglClipStackEntryWindowRect, entry); else - g_free (entry); + { + cogl_handle_unref (((CoglClipStackEntryPath *) entry)->path); + g_slice_free (CoglClipStackEntryPath, entry); + } stack->stack_top = g_list_delete_link (stack->stack_top, stack->stack_top); @@ -693,15 +681,12 @@ _cogl_flush_clip_state (CoglClipStackState *clip_state) if (type == COGL_CLIP_STACK_PATH) { - CoglClipStackEntryPath *path = (CoglClipStackEntryPath *) entry; + CoglClipStackEntryPath *path_entry = (CoglClipStackEntryPath *) entry; _cogl_matrix_stack_push (modelview_stack); - _cogl_matrix_stack_set (modelview_stack, &path->matrix); + _cogl_matrix_stack_set (modelview_stack, &path_entry->matrix); - _cogl_add_path_to_stencil_buffer (path->path_nodes_min, - path->path_nodes_max, - path->path_size, - path->path, + _cogl_add_path_to_stencil_buffer (path_entry->path, using_stencil_buffer, TRUE); diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 72601c758..cdbd99ec6 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -33,6 +33,7 @@ #include "cogl-texture-private.h" #include "cogl-material-private.h" #include "cogl-framebuffer-private.h" +#include "cogl-path-private.h" #include @@ -108,8 +109,7 @@ cogl_create_context (void) _context->dirty_bound_framebuffer = TRUE; _context->dirty_gl_viewport = TRUE; - _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); - _context->last_path = 0; + _context->current_path = _cogl_path_new (); _context->stencil_material = cogl_material_new (); _context->in_begin_gl_block = FALSE; @@ -168,8 +168,8 @@ _cogl_destroy_context () _cogl_free_framebuffer_stack (_context->framebuffer_stack); - if (_context->path_nodes) - g_array_free (_context->path_nodes, TRUE); + if (_context->current_path) + cogl_handle_unref (_context->current_path); if (_context->default_gl_texture_2d_tex) cogl_handle_unref (_context->default_gl_texture_2d_tex); diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h index c745daef8..a8b3e5ea9 100644 --- a/cogl/cogl-context.h +++ b/cogl/cogl-context.h @@ -99,12 +99,7 @@ typedef struct gboolean dirty_gl_viewport; /* Primitives */ - floatVec2 path_start; - floatVec2 path_pen; - GArray *path_nodes; - unsigned int last_path; - floatVec2 path_nodes_min; - floatVec2 path_nodes_max; + CoglHandle current_path; CoglHandle stencil_material; /* Pre-generated VBOs containing indices to generate GL_TRIANGLES diff --git a/cogl/cogl-internal.h b/cogl/cogl-internal.h index 3cf7c17b6..5783f0201 100644 --- a/cogl/cogl-internal.h +++ b/cogl/cogl-internal.h @@ -27,34 +27,6 @@ #include "cogl.h" #include "cogl-matrix-stack.h" -typedef struct _floatVec2 -{ - float x; - float y; -} floatVec2; - -typedef struct _CoglPathNode -{ - float x; - float y; - unsigned int path_size; -} CoglPathNode; - -typedef struct _CoglBezQuad -{ - floatVec2 p1; - floatVec2 p2; - floatVec2 p3; -} CoglBezQuad; - -typedef struct _CoglBezCubic -{ - floatVec2 p1; - floatVec2 p2; - floatVec2 p3; - floatVec2 p4; -} CoglBezCubic; - typedef enum { COGL_FRONT_WINDING_CLOCKWISE, diff --git a/cogl/cogl-path-private.h b/cogl/cogl-path-private.h new file mode 100644 index 000000000..a7c9d390f --- /dev/null +++ b/cogl/cogl-path-private.h @@ -0,0 +1,96 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#ifndef __COGL_PATH_PRIVATE_H +#define __COGL_PATH_PRIVATE_H + +#include "cogl-handle.h" + +#define COGL_PATH(tex) ((CoglPath *)(tex)) + +typedef struct _floatVec2 +{ + float x; + float y; +} floatVec2; + +typedef struct _CoglPathNode +{ + float x; + float y; + unsigned int path_size; +} CoglPathNode; + +typedef struct _CoglBezQuad +{ + floatVec2 p1; + floatVec2 p2; + floatVec2 p3; +} CoglBezQuad; + +typedef struct _CoglBezCubic +{ + floatVec2 p1; + floatVec2 p2; + floatVec2 p3; + floatVec2 p4; +} CoglBezCubic; + +typedef struct _CoglPath CoglPath; + +struct _CoglPath +{ + CoglHandleObject _parent; + + /* If this path was created with cogl_path_copy then parent_path + will point to the copied path. Otherwise it will be + COGL_INVALID_HANDLE to indicate that we own path_nodes. */ + CoglHandle parent_path; + /* Pointer to the path nodes array. This will point directly into + the parent path if this path is a copy */ + GArray *path_nodes; + /* Number of nodes to render from the data. This may be different + from path_nodes->len if this is a copied path and the parent path + was appended to. If that is the case then we need to be careful + to check that the size of a sub path doesn't extend past + path_size */ + unsigned int path_size; + + floatVec2 path_start; + floatVec2 path_pen; + unsigned int last_path; + floatVec2 path_nodes_min; + floatVec2 path_nodes_max; +}; + +/* This is an internal version of cogl_path_new that doesn't affect + the current path and just creates a new handle */ +CoglHandle +_cogl_path_new (void); + +void +_cogl_add_path_to_stencil_buffer (CoglHandle path, + gboolean merge, + gboolean need_clear); + +#endif /* __COGL_PATH_PRIVATE_H */ diff --git a/cogl/cogl-path.c b/cogl/cogl-path.c index 1255a18e5..1a7555859 100644 --- a/cogl/cogl-path.c +++ b/cogl/cogl-path.c @@ -31,6 +31,7 @@ #include "cogl-journal-private.h" #include "cogl-material-private.h" #include "cogl-framebuffer-private.h" +#include "cogl-path-private.h" #include #include @@ -41,37 +42,86 @@ #define glClientActiveTexture ctx->drv.pf_glClientActiveTexture #endif +static void _cogl_path_free (CoglPath *path); + +COGL_HANDLE_DEFINE (Path, path); + +static void +_cogl_path_modify (CoglPath *path) +{ + /* This needs to be called whenever the path is about to be modified + to implement copy-on-write semantics. Note that the current + mechanism assumes that a path will only ever be appended to (ie, + the path won't be cleared or have nodes in the middle + changed). This means that we don't need to keep track of how many + copies a node has because the copies can just keep track of the + number of nodes they should draw */ + + /* If this path is a copy then we need to actually copy the data so + we can modify it */ + if (path->parent_path) + { + CoglPath *old_path = COGL_PATH (path->parent_path); + CoglPathNode *old_nodes = &g_array_index (old_path->path_nodes, + CoglPathNode, 0); + CoglPathNode *new_nodes; + int i; + + path->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); + /* The parent path may have extra nodes added after the copy was + made so we need to truncate it */ + g_array_set_size (path->path_nodes, path->path_size); + memcpy (path->path_nodes->data, old_nodes, + sizeof (CoglPathNode) * path->path_size); + /* We need to make sure the last path size doesn't extend past + the total path size */ + new_nodes = &g_array_index (path->path_nodes, CoglPathNode, 0); + for (i = 0; i < path->path_size; i += new_nodes[i].path_size) + if (new_nodes[i].path_size >= path->path_size) + new_nodes[i].path_size = path->path_size - i; + + cogl_handle_unref (path->parent_path); + path->parent_path = COGL_INVALID_HANDLE; + } +} + static void _cogl_path_add_node (gboolean new_sub_path, float x, float y) { CoglPathNode new_node; + CoglPath *path; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + path = COGL_PATH (ctx->current_path); + + _cogl_path_modify (path); + new_node.x = x; new_node.y = y; new_node.path_size = 0; - if (new_sub_path || ctx->path_nodes->len == 0) - ctx->last_path = ctx->path_nodes->len; + if (new_sub_path || path->path_size == 0) + path->last_path = path->path_size; - g_array_append_val (ctx->path_nodes, new_node); + g_array_append_val (path->path_nodes, new_node); + path->path_size++; - g_array_index (ctx->path_nodes, CoglPathNode, ctx->last_path).path_size++; + g_array_index (path->path_nodes, CoglPathNode, path->last_path).path_size++; - if (ctx->path_nodes->len == 1) + if (path->path_size == 1) { - ctx->path_nodes_min.x = ctx->path_nodes_max.x = x; - ctx->path_nodes_min.y = ctx->path_nodes_max.y = y; + path->path_nodes_min.x = path->path_nodes_max.x = x; + path->path_nodes_min.y = path->path_nodes_max.y = y; } else { - if (x < ctx->path_nodes_min.x) ctx->path_nodes_min.x = x; - if (x > ctx->path_nodes_max.x) ctx->path_nodes_max.x = x; - if (y < ctx->path_nodes_min.y) ctx->path_nodes_min.y = y; - if (y > ctx->path_nodes_max.y) ctx->path_nodes_max.y = y; + if (x < path->path_nodes_min.x) path->path_nodes_min.x = x; + if (x > path->path_nodes_max.x) path->path_nodes_max.x = x; + if (y < path->path_nodes_min.y) path->path_nodes_min.y = y; + if (y > path->path_nodes_max.y) path->path_nodes_max.y = y; } } @@ -80,10 +130,13 @@ _cogl_path_stroke_nodes (void) { unsigned int path_start = 0; unsigned long enable_flags = COGL_ENABLE_VERTEX_ARRAY; + CoglPath *path; CoglMaterialFlushOptions options; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + path = COGL_PATH (ctx->current_path); + _cogl_journal_flush (); /* NB: _cogl_framebuffer_flush_state may disrupt various state (such @@ -100,17 +153,19 @@ _cogl_path_stroke_nodes (void) _cogl_material_flush_gl_state (ctx->source_material, &options); - while (path_start < ctx->path_nodes->len) + while (path_start < path->path_size) { - CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode, + CoglPathNode *node = &g_array_index (path->path_nodes, CoglPathNode, path_start); - GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), - (guint8 *) path - + G_STRUCT_OFFSET (CoglPathNode, x)) ); - GE( glDrawArrays (GL_LINE_STRIP, 0, path->path_size) ); + GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), &node->x) ); + /* We need to limit the size of the sub path to the size of our + path in case this path is a copy and the parent path has + grown */ + GE( glDrawArrays (GL_LINE_STRIP, 0, + MIN (node->path_size, path->path_size - path_start)) ); - path_start += path->path_size; + path_start += node->path_size; } } @@ -129,12 +184,9 @@ _cogl_path_get_bounds (floatVec2 nodes_min, } void -_cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, - floatVec2 nodes_max, - unsigned int path_size, - CoglPathNode *path, - gboolean merge, - gboolean need_clear) +_cogl_add_path_to_stencil_buffer (CoglHandle path_handle, + gboolean merge, + gboolean need_clear) { unsigned int path_start = 0; unsigned int sub_path_num = 0; @@ -150,10 +202,12 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, _cogl_framebuffer_get_modelview_stack (framebuffer); CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); - + CoglPath *path; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + path = COGL_PATH (path_handle); + /* We don't track changes to the stencil buffer in the journal * so we need to flush any batched geometry first */ _cogl_journal_flush (); @@ -173,7 +227,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, _cogl_material_get_cogl_enable_flags (ctx->source_material); _cogl_enable (enable_flags); - _cogl_path_get_bounds (nodes_min, nodes_max, + _cogl_path_get_bounds (path->path_nodes_min, path->path_nodes_max, &bounds_x, &bounds_y, &bounds_w, &bounds_h); GE( glEnable (GL_STENCIL_TEST) ); @@ -222,12 +276,17 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, } ctx->n_texcoord_arrays_enabled = 0; - while (path_start < path_size) + while (path_start < path->path_size) { - GE (glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), - (guint8 *) path - + G_STRUCT_OFFSET (CoglPathNode, x))); - GE (glDrawArrays (GL_TRIANGLE_FAN, 0, path->path_size)); + CoglPathNode *node = + &g_array_index (path->path_nodes, CoglPathNode, path_start); + + GE (glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), &node->x)); + /* We need to limit the size of the sub path to the size of our + path in case this path is a copy and the parent path has + grown */ + GE (glDrawArrays (GL_TRIANGLE_FAN, 0, + MIN (node->path_size, path->path_size - path_start))); if (sub_path_num > 0) { @@ -251,8 +310,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, GE (glStencilMask (merge ? 4 : 2)); - path_start += path->path_size; - path += path->path_size; + path_start += node->path_size; sub_path_num++; } @@ -488,6 +546,7 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path, static void _cogl_path_fill_nodes (void) { + CoglPath *path; float bounds_x; float bounds_y; float bounds_w; @@ -495,7 +554,9 @@ _cogl_path_fill_nodes (void) _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max, + path = COGL_PATH (ctx->current_path); + + _cogl_path_get_bounds (path->path_nodes_min, path->path_nodes_max, &bounds_x, &bounds_y, &bounds_w, &bounds_h); if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_FORCE_SCANLINE_PATHS)) && @@ -509,11 +570,7 @@ _cogl_path_fill_nodes (void) framebuffer = _cogl_get_framebuffer (); clip_state = _cogl_framebuffer_get_clip_state (framebuffer); - _cogl_add_path_to_stencil_buffer (ctx->path_nodes_min, - ctx->path_nodes_max, - ctx->path_nodes->len, - &g_array_index (ctx->path_nodes, - CoglPathNode, 0), + _cogl_add_path_to_stencil_buffer (ctx->current_path, clip_state->stencil_used, FALSE); @@ -535,17 +592,21 @@ _cogl_path_fill_nodes (void) { unsigned int path_start = 0; - while (path_start < ctx->path_nodes->len) + while (path_start < path->path_size) { - CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode, + CoglPathNode *node = &g_array_index (path->path_nodes, CoglPathNode, path_start); - _cogl_path_fill_nodes_scanlines (path, - path->path_size, + /* We need to limit the size of the sub path to the size of + our path in case this path is a copy and the parent path + has grown */ + _cogl_path_fill_nodes_scanlines (node, + MIN (node->path_size, + path->path_size - path_start), bounds_x, bounds_y, bounds_w, bounds_h); - path_start += path->path_size; + path_start += node->path_size; } } } @@ -563,7 +624,7 @@ cogl_path_fill_preserve (void) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (ctx->path_nodes->len == 0) + if (COGL_PATH (ctx->current_path)->path_size == 0) return; _cogl_path_fill_nodes (); @@ -582,7 +643,7 @@ cogl_path_stroke_preserve (void) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (ctx->path_nodes->len == 0) + if (COGL_PATH (ctx->current_path)->path_size == 0) return; _cogl_path_stroke_nodes (); @@ -592,57 +653,77 @@ void cogl_path_move_to (float x, float y) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + CoglPath *path; - /* FIXME: handle multiple contours maybe? */ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_path_add_node (TRUE, x, y); - ctx->path_start.x = x; - ctx->path_start.y = y; + path = COGL_PATH (ctx->current_path); - ctx->path_pen = ctx->path_start; + path->path_start.x = x; + path->path_start.y = y; + + path->path_pen = path->path_start; } void cogl_path_rel_move_to (float x, float y) { + CoglPath *path; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_path_move_to (ctx->path_pen.x + x, - ctx->path_pen.y + y); + path = COGL_PATH (ctx->current_path); + + cogl_path_move_to (path->path_pen.x + x, + path->path_pen.y + y); } void cogl_path_line_to (float x, float y) { + CoglPath *path; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_path_add_node (FALSE, x, y); - ctx->path_pen.x = x; - ctx->path_pen.y = y; + path = COGL_PATH (ctx->current_path); + + path->path_pen.x = x; + path->path_pen.y = y; } void cogl_path_rel_line_to (float x, float y) { + CoglPath *path; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_path_line_to (ctx->path_pen.x + x, - ctx->path_pen.y + y); + path = COGL_PATH (ctx->current_path); + + cogl_path_line_to (path->path_pen.x + x, + path->path_pen.y + y); } void cogl_path_close (void) { + CoglPath *path; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_path_add_node (FALSE, ctx->path_start.x, ctx->path_start.y); - ctx->path_pen = ctx->path_start; + path = COGL_PATH (ctx->current_path); + + _cogl_path_add_node (FALSE, path->path_start.x, + path->path_start.y); + + path->path_pen = path->path_start; } void @@ -650,7 +731,8 @@ cogl_path_new (void) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - g_array_set_size (ctx->path_nodes, 0); + cogl_handle_unref (ctx->current_path); + ctx->current_path = _cogl_path_new (); } void @@ -789,10 +871,14 @@ cogl_path_arc_rel (float center_x, float angle_2, float angle_step) { + CoglPath *path; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_path_arc (ctx->path_pen.x + center_x, - ctx->path_pen.y + center_y, + path = COGL_PATH (ctx->current_path); + + _cogl_path_arc (path->path_pen.x + center_x, + path->path_pen.y + center_y, radius_x, radius_y, angle_1, angle_2, angle_step, 0 /* no move */); @@ -825,11 +911,14 @@ cogl_path_round_rectangle (float x_1, float radius, float arc_step) { + CoglPath *path; float inner_width = x_2 - x_1 - radius * 2; float inner_height = y_2 - y_1 - radius * 2; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + path = COGL_PATH (ctx->current_path); + cogl_path_move_to (x_1, y_1 + radius); cogl_path_arc_rel (radius, 0, radius, radius, @@ -837,16 +926,16 @@ cogl_path_round_rectangle (float x_1, 270, arc_step); - cogl_path_line_to (ctx->path_pen.x + inner_width, - ctx->path_pen.y); + cogl_path_line_to (path->path_pen.x + inner_width, + path->path_pen.y); cogl_path_arc_rel (0, radius, radius, radius, -90, 0, arc_step); - cogl_path_line_to (ctx->path_pen.x, - ctx->path_pen.y + inner_height); + cogl_path_line_to (path->path_pen.x, + path->path_pen.y + inner_height); cogl_path_arc_rel (-radius, 0, radius, radius, @@ -854,8 +943,8 @@ cogl_path_round_rectangle (float x_1, 90, arc_step); - cogl_path_line_to (ctx->path_pen.x - inner_width, - ctx->path_pen.y); + cogl_path_line_to (path->path_pen.x - inner_width, + path->path_pen.y); cogl_path_arc_rel (0, -radius, radius, radius, 90, @@ -970,11 +1059,14 @@ cogl_path_curve_to (float x_1, float y_3) { CoglBezCubic cubic; + CoglPath *path; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + path = COGL_PATH (ctx->current_path); + /* Prepare cubic curve */ - cubic.p1 = ctx->path_pen; + cubic.p1 = path->path_pen; cubic.p2.x = x_1; cubic.p2.y = y_1; cubic.p3.x = x_2; @@ -987,7 +1079,7 @@ cogl_path_curve_to (float x_1, /* Add last point */ _cogl_path_add_node (FALSE, cubic.p4.x, cubic.p4.y); - ctx->path_pen = cubic.p4; + path->path_pen = cubic.p4; } void @@ -998,16 +1090,85 @@ cogl_path_rel_curve_to (float x_1, float x_3, float y_3) { + CoglPath *path; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_path_curve_to (ctx->path_pen.x + x_1, - ctx->path_pen.y + y_1, - ctx->path_pen.x + x_2, - ctx->path_pen.y + y_2, - ctx->path_pen.x + x_3, - ctx->path_pen.y + y_3); + path = COGL_PATH (ctx->current_path); + + cogl_path_curve_to (path->path_pen.x + x_1, + path->path_pen.y + y_1, + path->path_pen.x + x_2, + path->path_pen.y + y_2, + path->path_pen.x + x_3, + path->path_pen.y + y_3); } +CoglHandle +cogl_path_get (void) +{ + _COGL_GET_CONTEXT (ctx, FALSE); + + return ctx->current_path; +} + +void +cogl_path_set (CoglHandle handle) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!cogl_is_path (handle)) + return; + + /* Reference the new handle first in case it is the same as the old + handle */ + cogl_handle_ref (handle); + cogl_handle_unref (ctx->current_path); + ctx->current_path = handle; +} + +CoglHandle +_cogl_path_new (void) +{ + CoglPath *path; + + path = g_slice_new (CoglPath); + path->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); + path->last_path = 0; + path->parent_path = COGL_INVALID_HANDLE; + path->path_size = 0; + + return _cogl_path_handle_new (path); +} + +CoglHandle +cogl_path_copy (CoglHandle handle) +{ + CoglPath *old_path, *new_path; + + _COGL_GET_CONTEXT (ctx, FALSE); + + if (!cogl_is_path (handle)) + return COGL_INVALID_HANDLE; + + old_path = COGL_PATH (handle); + + new_path = g_slice_dup (CoglPath, old_path); + new_path->parent_path = cogl_handle_ref (handle); + + return _cogl_path_handle_new (new_path); +} + +static void +_cogl_path_free (CoglPath *path) +{ + if (path->parent_path) + cogl_handle_unref (path->parent_path); + else + g_array_free (path->path_nodes, TRUE); + + g_slice_free (CoglPath, path); +} /* If second order beziers were needed the following code could * be re-enabled: @@ -1086,9 +1247,12 @@ cogl_path_curve2_to (float x_1, float x_2, float y_2) { + CoglPath *path; + CoglBezQuad quad; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - CoglBezQuad quad; + path = COGL_PATH (ctx->current_path); /* Prepare quadratic curve */ quad.p1 = ctx->path_pen; @@ -1102,7 +1266,7 @@ cogl_path_curve2_to (float x_1, /* Add last point */ _cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y); - ctx->path_pen = quad.p3; + path->path_pen = quad.p3; } void @@ -1111,11 +1275,16 @@ cogl_rel_curve2_to (float x_1, float x_2, float y_2) { + CoglPath *path; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_path_curve2_to (ctx->path_pen.x + x_1, - ctx->path_pen.y + y_1, - ctx->path_pen.x + x_2, - ctx->path_pen.y + y_2); + path = COGL_PATH (ctx->current_path); + + cogl_path_curve2_to (path->path_pen.x + x_1, + path->path_pen.y + y_1, + path->path_pen.x + x_2, + path->path_pen.y + y_2); } + #endif diff --git a/cogl/cogl-path.h b/cogl/cogl-path.h index 5f8d2a102..4037cc374 100644 --- a/cogl/cogl-path.h +++ b/cogl/cogl-path.h @@ -341,6 +341,52 @@ cogl_path_round_rectangle (float x_1, float radius, float arc_step); +/** + * cogl_path_get: + * + * Gets a handle to the current path. The path can later be used again + * by calling cogl_path_set(). Note that the path isn't copied so if + * you later call any functions to add to the path it will affect the + * returned handle too. No reference is taken on the path so if you + * want to retain it you should take your own reference with + * cogl_handle_ref(). + * + * Return value: a handle to the current path. + * + * Since: 1.4 + */ +CoglHandle +cogl_path_get (void); + +/** + * cogl_path_set: + * @handle: A %CoglHandle to a path + * + * Replaces the current path with @handle. A reference is taken on the + * handle so if you no longer need the path you should unref with + * cogl_handle_unref(). + * + * Since: 1.4 + */ +void +cogl_path_set (CoglHandle handle); + +/** + * cogl_path_copy: + * @handle: A %CoglHandle to a path + * + * Returns a new copy of the path in @handle. The new path has a + * reference count of 1 so you should unref it with + * cogl_handle_unref() if you no longer need it. + * + * Internally the path will share the data until one of the paths is + * modified so copying paths should be relatively cheap. + * + * Return value: a copy of the path in @handle. + */ +CoglHandle +cogl_path_copy (CoglHandle handle); + G_END_DECLS #endif /* __COGL_PATH_H__ */ diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index cde92d53e..92c812ca6 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -155,6 +155,9 @@ cogl_polygon cogl_path_new +cogl_path_get +cogl_path_set +cogl_path_copy cogl_path_move_to cogl_path_close cogl_path_line_to