[Cogl] [PATCH 1/2] Remove the legacy CoglPath API
Neil Roberts
neil at linux.intel.com
Mon Apr 16 05:21:14 PDT 2012
This removes the legacy path API which operates on an implicit global
CoglPath object and works in terms of integers. The newer API which
takes a CoglPath* pointer can be used instead.
---
cogl/Makefile.am | 7 +-
cogl/cogl-clip-stack.h | 2 +-
cogl/cogl-clip-state.c | 20 -
cogl/cogl-clip-state.h | 13 -
cogl/cogl-context-private.h | 1 -
cogl/cogl-context.c | 6 +-
cogl/cogl-framebuffer.h | 5 -
cogl/cogl-path-functions.h | 430 -------------
cogl/cogl-path.c | 1393 +++++++++++++++++++++++++++++++++++++----
cogl/cogl-path.h | 386 ++++++++++++-
cogl/cogl.h | 9 +-
cogl/cogl.symbols | 67 +--
cogl/cogl1-context.h | 13 -
cogl/cogl2-path.c | 1449 -------------------------------------------
cogl/cogl2-path.h | 506 ---------------
15 files changed, 1675 insertions(+), 2632 deletions(-)
delete mode 100644 cogl/cogl-path-functions.h
delete mode 100644 cogl/cogl2-path.c
delete mode 100644 cogl/cogl2-path.h
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 16e7005..88b05bb 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -54,8 +54,6 @@ cogl_1_public_h = \
$(srcdir)/cogl-matrix.h \
$(srcdir)/cogl-offscreen.h \
$(srcdir)/cogl-primitives.h \
- $(srcdir)/cogl-path.h \
- $(srcdir)/cogl-path-functions.h \
$(srcdir)/cogl-shader.h \
$(srcdir)/cogl-texture.h \
$(srcdir)/cogl-types.h \
@@ -76,7 +74,7 @@ cogl_experimental_h = \
$(srcdir)/cogl-pipeline-state.h \
$(srcdir)/cogl-pipeline-layer-state.h \
$(srcdir)/cogl-snippet.h \
- $(srcdir)/cogl2-path.h \
+ $(srcdir)/cogl-path.h \
$(srcdir)/cogl-index-buffer.h \
$(srcdir)/cogl-attribute-buffer.h \
$(srcdir)/cogl-indices.h \
@@ -199,10 +197,7 @@ cogl_sources_c = \
$(srcdir)/cogl-primitives.h \
$(srcdir)/cogl-primitives.c \
$(srcdir)/cogl-path-private.h \
- $(srcdir)/cogl-path.h \
$(srcdir)/cogl-path.c \
- $(srcdir)/cogl2-path.h \
- $(srcdir)/cogl2-path.c \
$(srcdir)/cogl-bitmap-pixbuf.c \
$(srcdir)/cogl-clip-stack.h \
$(srcdir)/cogl-clip-stack.c \
diff --git a/cogl/cogl-clip-stack.h b/cogl/cogl-clip-stack.h
index c263caa..ec7b52f 100644
--- a/cogl/cogl-clip-stack.h
+++ b/cogl/cogl-clip-stack.h
@@ -24,7 +24,7 @@
#ifndef __COGL_CLIP_STACK_H
#define __COGL_CLIP_STACK_H
-#include "cogl2-path.h"
+#include "cogl-path.h"
#include "cogl-matrix.h"
#include "cogl-primitive.h"
#include "cogl-framebuffer.h"
diff --git a/cogl/cogl-clip-state.c b/cogl/cogl-clip-state.c
index ca34d78..97f8ce6 100644
--- a/cogl/cogl-clip-state.c
+++ b/cogl/cogl-clip-state.c
@@ -85,26 +85,6 @@ cogl_clip_push (float x_offset,
}
void
-cogl_clip_push_from_path_preserve (void)
-{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
- cogl_framebuffer_push_path_clip (cogl_get_draw_framebuffer (),
- ctx->current_path);
-}
-
-#undef cogl_clip_push_from_path
-void
-cogl_clip_push_from_path (void)
-{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- cogl_clip_push_from_path_preserve ();
-
- cogl_object_unref (ctx->current_path);
- ctx->current_path = cogl2_path_new ();
-}
-
-void
cogl_clip_push_primitive (CoglPrimitive *primitive,
float bounds_x1,
float bounds_y1,
diff --git a/cogl/cogl-clip-state.h b/cogl/cogl-clip-state.h
index b51943f..4865ae5 100644
--- a/cogl/cogl-clip-state.h
+++ b/cogl/cogl-clip-state.h
@@ -32,19 +32,6 @@
G_BEGIN_DECLS
-/**
- * cogl_clip_push_from_path:
- *
- * Sets a new clipping area using the current path. The current path
- * is then cleared. The clipping area is intersected with the previous
- * clipping area. To restore the previous clipping area, call
- * cogl_clip_pop().
- *
- * Since: 1.0
- */
-void
-cogl_clip_push_from_path (void);
-
G_END_DECLS
#endif /* __COGL_CLIP_STATE_H */
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 333235b..3adadc5 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -177,7 +177,6 @@ struct _CoglContext
CoglFramebuffer *current_read_buffer;
/* Primitives */
- CoglPath *current_path;
CoglPipeline *stencil_pipeline;
/* Pre-generated VBOs containing indices to generate GL_TRIANGLES
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 94ce2f1..6a01fcc 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -44,7 +44,7 @@
#include "cogl-pipeline-opengl-private.h"
#include "cogl-framebuffer-private.h"
#include "cogl-onscreen-private.h"
-#include "cogl2-path.h"
+#include "cogl-path.h"
#include "cogl-attribute-private.h"
#include "cogl1-context.h"
#include "cogl-gpu-info-private.h"
@@ -370,7 +370,6 @@ cogl_context_new (CoglDisplay *display,
cogl_object_unref (COGL_FRAMEBUFFER (window));
}
- context->current_path = cogl2_path_new ();
context->stencil_pipeline = cogl_pipeline_new (context);
context->in_begin_gl_block = FALSE;
@@ -462,9 +461,6 @@ _cogl_context_free (CoglContext *context)
_cogl_free_framebuffer_stack (context->framebuffer_stack);
- if (context->current_path)
- cogl_handle_unref (context->current_path);
-
if (context->default_gl_texture_2d_tex)
cogl_object_unref (context->default_gl_texture_2d_tex);
if (context->default_gl_texture_3d_tex)
diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h
index 07886db..1769975 100644
--- a/cogl/cogl-framebuffer.h
+++ b/cogl/cogl-framebuffer.h
@@ -34,12 +34,7 @@
#include <windows.h>
#endif /* COGL_HAS_WIN32_SUPPORT */
-#ifdef COGL_ENABLE_EXPERIMENTAL_2_0_API
-#include <cogl/cogl2-path.h>
-#else
#include <cogl/cogl-path.h>
-#endif
-
#include <cogl/cogl-pipeline.h>
#include <cogl/cogl-indices.h>
#include <cogl/cogl-bitmap.h>
diff --git a/cogl/cogl-path-functions.h b/cogl/cogl-path-functions.h
deleted file mode 100644
index 2566fe1..0000000
--- a/cogl/cogl-path-functions.h
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Cogl
- *
- * An object oriented GL/GLES Abstraction/Utility Layer
- *
- * Copyright (C) 2008,2009,2012 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 <http://www.gnu.org/licenses/>.
- *
- *
- */
-
-#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
-#error "Only <cogl/cogl.h> can be included directly."
-#endif
-
-#ifndef __COGL_PATH_FUNCTIONS_H__
-#define __COGL_PATH_FUNCTIONS_H__
-
-/* The functions are declared separately because cogl-path.c needs to
- get the function declarations from the old 1.0 API without
- colliding with the enum declarations from the 2.0 API */
-
-#include <cogl/cogl-types.h>
-
-G_BEGIN_DECLS
-
-/**
- * cogl_is_path:
- * @handle: A CoglHandle
- *
- * Gets whether the given handle references an existing path object.
- *
- * Return value: %TRUE if the handle references a #CoglPath,
- * %FALSE otherwise
- */
-gboolean
-cogl_is_path (CoglHandle handle);
-
-/**
- * cogl_path_set_fill_rule:
- * @fill_rule: The new fill rule.
- *
- * Sets the fill rule of the current path to @fill_rule. This will
- * affect how the path is filled when cogl_path_fill() is later
- * called. Note that the fill rule state is attached to the path so
- * calling cogl_get_path() will preserve the fill rule and calling
- * cogl_path_new() will reset the fill rule back to the default.
- *
- * Since: 1.4
- */
-void
-cogl_path_set_fill_rule (CoglPathFillRule fill_rule);
-
-/**
- * cogl_path_get_fill_rule:
- *
- * Retrieves the fill rule set using cogl_path_set_fill_rule().
- *
- * Return value: the fill rule that is used for the current path.
- *
- * Since: 1.4
- */
-CoglPathFillRule
-cogl_path_get_fill_rule (void);
-
-/**
- * cogl_path_fill:
- *
- * Fills the interior of the constructed shape using the current
- * drawing color. The current path is then cleared. To use the path
- * again, call cogl_path_fill_preserve() instead.
- *
- * The interior of the shape is determined using the fill rule of the
- * path. See %CoglPathFillRule for details.
- **/
-void
-cogl_path_fill (void);
-
-/**
- * cogl_path_fill_preserve:
- *
- * Fills the interior of the constructed shape using the current
- * drawing color and preserves the path to be used again. See
- * cogl_path_fill() for a description what is considered the interior
- * of the shape.
- *
- * Since: 1.0
- **/
-void
-cogl_path_fill_preserve (void);
-
-/**
- * cogl_path_stroke:
- *
- * Strokes the constructed shape using the current drawing color and a
- * width of 1 pixel (regardless of the current transformation
- * matrix). To current path is then cleared. To use the path again,
- * call cogl_path_stroke_preserve() instead.
- **/
-void
-cogl_path_stroke (void);
-
-/**
- * cogl_path_stroke_preserve:
- *
- * Strokes the constructed shape using the current drawing color and
- * preserves the path to be used again.
- *
- * Since: 1.0
- **/
-void
-cogl_path_stroke_preserve (void);
-
-/**
- * cogl_path_new:
- *
- * Clears the current path and starts a new one. Creating a new path
- * also resets the fill rule to the default which is
- * %COGL_PATH_FILL_RULE_EVEN_ODD.
- *
- * Since: 1.0
- */
-void
-cogl_path_new (void);
-
-/**
- * cogl_path_move_to:
- * @x: X coordinate of the pen location to move to.
- * @y: Y coordinate of the pen location to move to.
- *
- * Moves the pen to the given location. If there is an existing path
- * this will start a new disjoint subpath.
- **/
-void
-cogl_path_move_to (float x,
- float y);
-
-
-/**
- * cogl_path_rel_move_to:
- * @x: X offset from the current pen location to move the pen to.
- * @y: Y offset from the current pen location to move the pen to.
- *
- * Moves the pen to the given offset relative to the current pen
- * location. If there is an existing path this will start a new
- * disjoint subpath.
- **/
-void
-cogl_path_rel_move_to (float x,
- float y);
-
-/**
- * cogl_path_line_to:
- * @x: X coordinate of the end line vertex
- * @y: Y coordinate of the end line vertex
- *
- * Adds a straight line segment to the current path that ends at the
- * given coordinates.
- **/
-void
-cogl_path_line_to (float x,
- float y);
-
-/**
- * cogl_path_rel_line_to:
- * @x: X offset from the current pen location of the end line vertex
- * @y: Y offset from the current pen location of the end line vertex
- *
- * Adds a straight line segment to the current path that ends at the
- * given coordinates relative to the current pen location.
- **/
-void
-cogl_path_rel_line_to (float x,
- float y);
-
-
-/**
- * cogl_path_arc:
- * @center_x: X coordinate of the elliptical arc center
- * @center_y: Y coordinate of the elliptical arc center
- * @radius_x: X radius of the elliptical arc
- * @radius_y: Y radius of the elliptical arc
- * @angle_1: Angle in degrees at which the arc begin
- * @angle_2: Angle in degrees at which the arc ends
- *
- * Adds an elliptical arc segment to the current path. A straight line
- * segment will link the current pen location with the first vertex
- * of the arc. If you perform a move_to to the arcs start just before
- * drawing it you create a free standing arc.
- *
- * The angles are measured in degrees where 0° is in the direction of
- * the positive X axis and 90° is in the direction of the positive Y
- * axis. The angle of the arc begins at @angle_1 and heads towards
- * @angle_2 (so if @angle_2 is less than @angle_1 it will decrease,
- * otherwise it will increase).
- **/
-void
-cogl_path_arc (float center_x,
- float center_y,
- float radius_x,
- float radius_y,
- float angle_1,
- float angle_2);
-
-/**
- * cogl_path_curve_to:
- * @x_1: X coordinate of the second bezier control point
- * @y_1: Y coordinate of the second bezier control point
- * @x_2: X coordinate of the third bezier control point
- * @y_2: Y coordinate of the third bezier control point
- * @x_3: X coordinate of the fourth bezier control point
- * @y_3: Y coordinate of the fourth bezier control point
- *
- * Adds a cubic bezier curve segment to the current path with the given
- * second, third and fourth control points and using current pen location
- * as the first control point.
- **/
-void
-cogl_path_curve_to (float x_1,
- float y_1,
- float x_2,
- float y_2,
- float x_3,
- float y_3);
-
-/**
- * cogl_path_rel_curve_to:
- * @x_1: X coordinate of the second bezier control point
- * @y_1: Y coordinate of the second bezier control point
- * @x_2: X coordinate of the third bezier control point
- * @y_2: Y coordinate of the third bezier control point
- * @x_3: X coordinate of the fourth bezier control point
- * @y_3: Y coordinate of the fourth bezier control point
- *
- * Adds a cubic bezier curve segment to the current path with the given
- * second, third and fourth control points and using current pen location
- * as the first control point. The given coordinates are relative to the
- * current pen location.
- */
-void
-cogl_path_rel_curve_to (float x_1,
- float y_1,
- float x_2,
- float y_2,
- float x_3,
- float y_3);
-
-/**
- * cogl_path_close:
- *
- * Closes the path being constructed by adding a straight line segment
- * to it that ends at the first vertex of the path.
- **/
-void
-cogl_path_close (void);
-
-/**
- * cogl_path_line:
- * @x_1: X coordinate of the start line vertex
- * @y_1: Y coordinate of the start line vertex
- * @x_2: X coordinate of the end line vertex
- * @y_2: Y coordinate of the end line vertex
- *
- * Constructs a straight line shape starting and ending at the given
- * coordinates. If there is an existing path this will start a new
- * disjoint sub-path.
- **/
-void
-cogl_path_line (float x_1,
- float y_1,
- float x_2,
- float y_2);
-
-/**
- * cogl_path_polyline:
- * @coords: (in) (array) (transfer none): A pointer to the first element of an
- * array of fixed-point values that specify the vertex coordinates.
- * @num_points: The total number of vertices.
- *
- * Constructs a series of straight line segments, starting from the
- * first given vertex coordinate. If there is an existing path this
- * will start a new disjoint sub-path. Each subsequent segment starts
- * where the previous one ended and ends at the next given vertex
- * coordinate.
- *
- * The coords array must contain 2 * num_points values. The first value
- * represents the X coordinate of the first vertex, the second value
- * represents the Y coordinate of the first vertex, continuing in the same
- * fashion for the rest of the vertices. (num_points - 1) segments will
- * be constructed.
- **/
-void
-cogl_path_polyline (const float *coords,
- int num_points);
-
-
-/**
- * cogl_path_polygon:
- * @coords: (in) (array) (transfer none): A pointer to the first element of
- * an array of fixed-point values that specify the vertex coordinates.
- * @num_points: The total number of vertices.
- *
- * Constructs a polygonal shape of the given number of vertices. If
- * there is an existing path this will start a new disjoint sub-path.
- *
- * The coords array must contain 2 * num_points values. The first value
- * represents the X coordinate of the first vertex, the second value
- * represents the Y coordinate of the first vertex, continuing in the same
- * fashion for the rest of the vertices.
- **/
-void
-cogl_path_polygon (const float *coords,
- int num_points);
-
-
-/**
- * cogl_path_rectangle:
- * @x_1: X coordinate of the top-left corner.
- * @y_1: Y coordinate of the top-left corner.
- * @x_2: X coordinate of the bottom-right corner.
- * @y_2: Y coordinate of the bottom-right corner.
- *
- * Constructs a rectangular shape at the given coordinates. If there
- * is an existing path this will start a new disjoint sub-path.
- **/
-void
-cogl_path_rectangle (float x_1,
- float y_1,
- float x_2,
- float y_2);
-
-/**
- * cogl_path_ellipse:
- * @center_x: X coordinate of the ellipse center
- * @center_y: Y coordinate of the ellipse center
- * @radius_x: X radius of the ellipse
- * @radius_y: Y radius of the ellipse
- *
- * Constructs an ellipse shape. If there is an existing path this will
- * start a new disjoint sub-path.
- **/
-void
-cogl_path_ellipse (float center_x,
- float center_y,
- float radius_x,
- float radius_y);
-
-/**
- * cogl_path_round_rectangle:
- * @x_1: X coordinate of the top-left corner.
- * @y_1: Y coordinate of the top-left corner.
- * @x_2: X coordinate of the bottom-right corner.
- * @y_2: Y coordinate of the bottom-right corner.
- * @radius: Radius of the corner arcs.
- * @arc_step: Angle increment resolution for subdivision of
- * the corner arcs.
- *
- * Constructs a rectangular shape with rounded corners. If there is an
- * existing path this will start a new disjoint sub-path.
- **/
-void
-cogl_path_round_rectangle (float x_1,
- float y_1,
- float x_2,
- float y_2,
- float radius,
- float arc_step);
-
-/**
- * cogl_get_path: (skip)
- *
- * Gets a pointer 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 object too. No reference is taken on the path
- * so if you want to retain it you should take your own reference with
- * cogl_object_ref().
- *
- * Return value: a pointer to the current path.
- *
- * Since: 1.4
- */
-CoglPath *
-cogl_get_path (void);
-
-/**
- * cogl_set_path: (skip)
- * @path: A #CoglPath object
- *
- * Replaces the current path with @path. A reference is taken on the
- * object so if you no longer need the path you should unref with
- * cogl_object_unref().
- *
- * Since: 1.4
- */
-void
-cogl_set_path (CoglPath *path);
-
-/**
- * cogl_path_copy: (skip)
- * @path: A #CoglPath object
- *
- * Returns a new copy of the path in @path. The new path has a
- * reference count of 1 so you should unref it with
- * cogl_object_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: (transfer full): a copy of the path in @path.
- */
-CoglPath *
-cogl_path_copy (CoglPath *path);
-
-G_END_DECLS
-
-#endif /* __COGL_PATH_FUNCTIONS_H__ */
-
diff --git a/cogl/cogl-path.c b/cogl/cogl-path.c
index aab3dfb..571114b 100644
--- a/cogl/cogl-path.c
+++ b/cogl/cogl-path.c
@@ -3,7 +3,7 @@
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
- * Copyright (C) 2010 Intel Corporation.
+ * Copyright (C) 2007,2008,2009,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
@@ -20,7 +20,10 @@
* <http://www.gnu.org/licenses/>.
*
* Authors:
- * Robert Bragg <robert at linux.intel.com>
+ * Ivan Leben <ivan at openedhand.com>
+ * Øyvind Kolås <pippin at linux.intel.com>
+ * Neil Roberts <neil at linux.intel.com>
+ * Robert Bragg <robert at linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
@@ -28,279 +31,1419 @@
#endif
#include "cogl-util.h"
+#include "cogl-object.h"
#include "cogl-internal.h"
#include "cogl-context-private.h"
-#include "cogl2-path.h"
+#include "cogl-journal-private.h"
+#include "cogl-pipeline-private.h"
+#include "cogl-pipeline-opengl-private.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-path-private.h"
+#include "cogl-texture-private.h"
+#include "cogl-primitives-private.h"
+#include "cogl-private.h"
+#include "cogl-attribute-private.h"
+#include "cogl1-context.h"
+#include "tesselator/tesselator.h"
#include <string.h>
#include <math.h>
-#undef cogl_path_set_fill_rule
-#undef cogl_path_get_fill_rule
-#undef cogl_path_fill
-#undef cogl_path_fill_preserve
-#undef cogl_path_stroke
-#undef cogl_path_stroke_preserve
-#undef cogl_path_move_to
-#undef cogl_path_rel_move_to
-#undef cogl_path_line_to
-#undef cogl_path_rel_line_to
-#undef cogl_path_close
-#undef cogl_path_new
-#undef cogl_path_line
-#undef cogl_path_polyline
-#undef cogl_path_polygon
-#undef cogl_path_rectangle
-#undef cogl_path_arc
-#undef cogl_path_ellipse
-#undef cogl_path_round_rectangle
-#undef cogl_path_curve_to
-#undef cogl_path_rel_curve_to
-
-#include "cogl-path-functions.h"
+#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
+
+static void _cogl_path_free (CoglPath *path);
+
+static void _cogl_path_build_fill_attribute_buffer (CoglPath *path);
+static void _cogl_path_build_stroke_attribute_buffer (CoglPath *path);
+
+COGL_OBJECT_DEFINE (Path, path);
+
+static void
+_cogl_path_data_clear_vbos (CoglPathData *data)
+{
+ int i;
+
+ if (data->fill_attribute_buffer)
+ {
+ cogl_object_unref (data->fill_attribute_buffer);
+ cogl_object_unref (data->fill_vbo_indices);
+
+ for (i = 0; i < COGL_PATH_N_ATTRIBUTES; i++)
+ cogl_object_unref (data->fill_attributes[i]);
+
+ data->fill_attribute_buffer = NULL;
+ }
+
+ if (data->stroke_attribute_buffer)
+ {
+ cogl_object_unref (data->stroke_attribute_buffer);
+
+ for (i = 0; i < data->stroke_n_attributes; i++)
+ cogl_object_unref (data->stroke_attributes[i]);
+
+ g_free (data->stroke_attributes);
+
+ data->stroke_attribute_buffer = NULL;
+ }
+}
+
+static void
+_cogl_path_data_unref (CoglPathData *data)
+{
+ if (--data->ref_count <= 0)
+ {
+ _cogl_path_data_clear_vbos (data);
+
+ g_array_free (data->path_nodes, TRUE);
+
+ g_slice_free (CoglPathData, data);
+ }
+}
+
+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 */
+
+ /* If there is more than one path using the data then we need to
+ copy the data instead */
+ if (path->data->ref_count != 1)
+ {
+ CoglPathData *old_data = path->data;
+
+ path->data = g_slice_dup (CoglPathData, old_data);
+ path->data->path_nodes = g_array_new (FALSE, FALSE,
+ sizeof (CoglPathNode));
+ g_array_append_vals (path->data->path_nodes,
+ old_data->path_nodes->data,
+ old_data->path_nodes->len);
+
+ path->data->fill_attribute_buffer = NULL;
+ path->data->stroke_attribute_buffer = NULL;
+ path->data->ref_count = 1;
+
+ _cogl_path_data_unref (old_data);
+ }
+ else
+ /* The path is altered so the vbos will now be invalid */
+ _cogl_path_data_clear_vbos (path->data);
+}
void
-cogl_path_set_fill_rule (CoglPathFillRule fill_rule)
+cogl_path_set_fill_rule (CoglPath *path,
+ CoglPathFillRule fill_rule)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ if (path->data->fill_rule != fill_rule)
+ {
+ _cogl_path_modify (path);
- cogl2_path_set_fill_rule (ctx->current_path, fill_rule);
+ path->data->fill_rule = fill_rule;
+ }
}
CoglPathFillRule
-cogl_path_get_fill_rule (void)
+cogl_path_get_fill_rule (CoglPath *path)
{
- _COGL_GET_CONTEXT (ctx, COGL_PATH_FILL_RULE_EVEN_ODD);
+ _COGL_RETURN_VAL_IF_FAIL (cogl_is_path (path), COGL_PATH_FILL_RULE_NON_ZERO);
- return cogl2_path_get_fill_rule (ctx->current_path);
+ return path->data->fill_rule;
}
-void
-cogl_path_fill (void)
+static void
+_cogl_path_add_node (CoglPath *path,
+ gboolean new_sub_path,
+ float x,
+ float y)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglPathNode new_node;
+ CoglPathData *data;
- cogl2_path_fill (ctx->current_path);
+ _cogl_path_modify (path);
- cogl_object_unref (ctx->current_path);
- ctx->current_path = cogl2_path_new ();
+ data = path->data;
+
+ new_node.x = x;
+ new_node.y = y;
+ new_node.path_size = 0;
+
+ if (new_sub_path || data->path_nodes->len == 0)
+ data->last_path = data->path_nodes->len;
+
+ g_array_append_val (data->path_nodes, new_node);
+
+ g_array_index (data->path_nodes, CoglPathNode, data->last_path).path_size++;
+
+ if (data->path_nodes->len == 1)
+ {
+ data->path_nodes_min.x = data->path_nodes_max.x = x;
+ data->path_nodes_min.y = data->path_nodes_max.y = y;
+ }
+ else
+ {
+ if (x < data->path_nodes_min.x)
+ data->path_nodes_min.x = x;
+ if (x > data->path_nodes_max.x)
+ data->path_nodes_max.x = x;
+ if (y < data->path_nodes_min.y)
+ data->path_nodes_min.y = y;
+ if (y > data->path_nodes_max.y)
+ data->path_nodes_max.y = y;
+ }
+
+ /* Once the path nodes have been modified then we'll assume it's no
+ longer a rectangle. cogl_path_rectangle will set this back to
+ TRUE if this has been called from there */
+ data->is_rectangle = FALSE;
}
-void
-cogl_path_fill_preserve (void)
+static void
+_cogl_path_stroke_nodes (CoglPath *path)
{
+ CoglPathData *data = path->data;
+ CoglPipeline *copy = NULL;
+ CoglPipeline *source;
+ unsigned int path_start;
+ int path_num = 0;
+ CoglPathNode *node;
+
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
- cogl2_path_fill (ctx->current_path);
+ source = cogl_get_source ();
+
+ if (cogl_pipeline_get_n_layers (source) != 0)
+ {
+ copy = cogl_pipeline_copy (source);
+ _cogl_pipeline_prune_to_n_layers (copy, 0);
+ source = copy;
+ }
+
+ _cogl_path_build_stroke_attribute_buffer (path);
+
+ cogl_push_source (source);
+
+ for (path_start = 0;
+ path_start < data->path_nodes->len;
+ path_start += node->path_size)
+ {
+ node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
+
+ cogl_framebuffer_vdraw_attributes (cogl_get_draw_framebuffer (),
+ source,
+ COGL_VERTICES_MODE_LINE_STRIP,
+ 0, node->path_size,
+ data->stroke_attributes[path_num],
+ NULL);
+
+ path_num++;
+ }
+
+ cogl_pop_source ();
+
+ if (copy)
+ cogl_object_unref (copy);
}
void
-cogl_path_stroke (void)
+_cogl_path_get_bounds (CoglPath *path,
+ float *min_x,
+ float *min_y,
+ float *max_x,
+ float *max_y)
{
+ CoglPathData *data = path->data;
+
+ if (data->path_nodes->len == 0)
+ {
+ *min_x = 0.0f;
+ *min_y = 0.0f;
+ *max_x = 0.0f;
+ *max_y = 0.0f;
+ }
+ else
+ {
+ *min_x = data->path_nodes_min.x;
+ *min_y = data->path_nodes_min.y;
+ *max_x = data->path_nodes_max.x;
+ *max_y = data->path_nodes_max.y;
+ }
+}
+
+static void
+_cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path)
+{
+ CoglFramebuffer *fb;
+
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
- cogl2_path_stroke (ctx->current_path);
+ if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_STENCIL_BUFFER))
+ {
+ static gboolean seen_warning = FALSE;
+
+ if (!seen_warning)
+ {
+ g_warning ("Paths can not be filled using materials with "
+ "sliced textures unless there is a stencil "
+ "buffer");
+ seen_warning = TRUE;
+ }
+ }
+
+ fb = cogl_get_draw_framebuffer ();
+ cogl_framebuffer_push_path_clip (fb, path);
+ cogl_rectangle (path->data->path_nodes_min.x,
+ path->data->path_nodes_min.y,
+ path->data->path_nodes_max.x,
+ path->data->path_nodes_max.y);
+ cogl_framebuffer_pop_clip (fb);
+}
+
+static gboolean
+validate_layer_cb (CoglPipelineLayer *layer, void *user_data)
+{
+ gboolean *needs_fallback = user_data;
+ CoglTexture *texture = _cogl_pipeline_layer_get_texture (layer);
+
+ /* If any of the layers of the current pipeline contain sliced
+ * textures or textures with waste then it won't work to draw the
+ * path directly. Instead we fallback to pushing the path as a clip
+ * on the clip-stack and drawing the path's bounding rectangle
+ * instead.
+ */
+
+ if (texture != NULL && (cogl_texture_is_sliced (texture) ||
+ !_cogl_texture_can_hardware_repeat (texture)))
+ *needs_fallback = TRUE;
- cogl_object_unref (ctx->current_path);
- ctx->current_path = cogl2_path_new ();
+ return !*needs_fallback;
}
void
-cogl_path_stroke_preserve (void)
+_cogl_path_fill_nodes (CoglPath *path, CoglDrawFlags flags)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ gboolean needs_fallback = FALSE;
+ CoglPipeline *pipeline = cogl_get_source ();
+
+ _cogl_pipeline_foreach_layer_internal (pipeline,
+ validate_layer_cb, &needs_fallback);
+ if (needs_fallback)
+ {
+ _cogl_path_fill_nodes_with_clipped_rectangle (path);
+ return;
+ }
+
+ _cogl_path_build_fill_attribute_buffer (path);
- cogl2_path_stroke (ctx->current_path);
+ _cogl_framebuffer_draw_indexed_attributes (cogl_get_draw_framebuffer (),
+ pipeline,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 0, /* first_vertex */
+ path->data->fill_vbo_n_indices,
+ path->data->fill_vbo_indices,
+ path->data->fill_attributes,
+ COGL_PATH_N_ATTRIBUTES,
+ flags);
}
void
-cogl_path_move_to (float x,
- float y)
+cogl_path_fill (CoglPath *path)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ if (path->data->path_nodes->len == 0)
+ return;
+
+ /* If the path is a simple rectangle then we can divert to using
+ cogl_rectangle which should be faster because it can go through
+ the journal instead of uploading the geometry just for two
+ triangles */
+ if (path->data->is_rectangle)
+ {
+ float x_1, y_1, x_2, y_2;
- cogl2_path_move_to (ctx->current_path, x, y);
+ _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
+ cogl_rectangle (x_1, y_1, x_2, y_2);
+ }
+ else
+ _cogl_path_fill_nodes (path, 0);
}
void
-cogl_path_rel_move_to (float x,
- float y)
+cogl_path_stroke (CoglPath *path)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ if (path->data->path_nodes->len == 0)
+ return;
- cogl2_path_rel_move_to (ctx->current_path, x, y);
+ _cogl_path_stroke_nodes (path);
}
void
-cogl_path_line_to (float x,
+cogl_path_move_to (CoglPath *path,
+ float x,
float y)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
- cogl2_path_line_to (ctx->current_path, x, y);
+ _cogl_path_add_node (path, TRUE, x, y);
+
+ data = path->data;
+
+ data->path_start.x = x;
+ data->path_start.y = y;
+
+ data->path_pen = data->path_start;
}
void
-cogl_path_rel_line_to (float x,
+cogl_path_rel_move_to (CoglPath *path,
+ float x,
float y)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglPathData *data;
- cogl2_path_rel_line_to (ctx->current_path, x, y);
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ data = path->data;
+
+ cogl_path_move_to (path,
+ data->path_pen.x + x,
+ data->path_pen.y + y);
}
void
-cogl_path_close (void)
+cogl_path_line_to (CoglPath *path,
+ float x,
+ float y)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglPathData *data;
- cogl2_path_close (ctx->current_path);
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ _cogl_path_add_node (path, FALSE, x, y);
+
+ data = path->data;
+
+ data->path_pen.x = x;
+ data->path_pen.y = y;
}
void
-cogl_path_new (void)
+cogl_path_rel_line_to (CoglPath *path,
+ float x,
+ float y)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ data = path->data;
- cogl_object_unref (ctx->current_path);
- ctx->current_path = cogl2_path_new ();
+ cogl_path_line_to (path,
+ data->path_pen.x + x,
+ data->path_pen.y + y);
}
void
-cogl_path_line (float x_1,
- float y_1,
- float x_2,
- float y_2)
+cogl_path_close (CoglPath *path)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
- cogl2_path_line (ctx->current_path, x_1, y_1, x_2, y_2);
+ _cogl_path_add_node (path, FALSE, path->data->path_start.x,
+ path->data->path_start.y);
+
+ path->data->path_pen = path->data->path_start;
}
void
-cogl_path_polyline (const float *coords,
- int num_points)
+cogl_path_line (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- cogl2_path_polyline (ctx->current_path, coords, num_points);
+ cogl_path_move_to (path, x_1, y_1);
+ cogl_path_line_to (path, x_2, y_2);
}
void
-cogl_path_polygon (const float *coords,
- int num_points)
+cogl_path_polyline (CoglPath *path,
+ const float *coords,
+ int num_points)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ int c = 0;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ cogl_path_move_to (path, coords[0], coords[1]);
- cogl2_path_polygon (ctx->current_path, coords, num_points);
+ for (c = 1; c < num_points; ++c)
+ cogl_path_line_to (path, coords[2*c], coords[2*c+1]);
}
void
-cogl_path_rectangle (float x_1,
+cogl_path_polygon (CoglPath *path,
+ const float *coords,
+ int num_points)
+{
+ cogl_path_polyline (path, coords, num_points);
+ cogl_path_close (path);
+}
+
+void
+cogl_path_rectangle (CoglPath *path,
+ float x_1,
float y_1,
float x_2,
float y_2)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ gboolean is_rectangle;
+
+ /* If the path was previously empty and the rectangle isn't mirrored
+ then we'll record that this is a simple rectangle path so that we
+ can optimise it */
+ is_rectangle = (path->data->path_nodes->len == 0 &&
+ x_2 >= x_1 &&
+ y_2 >= y_1);
+
+ cogl_path_move_to (path, x_1, y_1);
+ cogl_path_line_to (path, x_2, y_1);
+ cogl_path_line_to (path, x_2, y_2);
+ cogl_path_line_to (path, x_1, y_2);
+ cogl_path_close (path);
+
+ path->data->is_rectangle = is_rectangle;
+}
+
+gboolean
+_cogl_path_is_rectangle (CoglPath *path)
+{
+ return path->data->is_rectangle;
+}
+
+static void
+_cogl_path_arc (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2,
+ float angle_step,
+ unsigned int move_first)
+{
+ float a = 0x0;
+ float cosa = 0x0;
+ float sina = 0x0;
+ float px = 0x0;
+ float py = 0x0;
- cogl2_path_rectangle (ctx->current_path, x_1, y_1, x_2, y_2);
+ /* Fix invalid angles */
+
+ if (angle_1 == angle_2 || angle_step == 0x0)
+ return;
+
+ if (angle_step < 0x0)
+ angle_step = -angle_step;
+
+ /* Walk the arc by given step */
+
+ a = angle_1;
+ while (a != angle_2)
+ {
+ cosa = cosf (a * (G_PI/180.0));
+ sina = sinf (a * (G_PI/180.0));
+
+ px = center_x + (cosa * radius_x);
+ py = center_y + (sina * radius_y);
+
+ if (a == angle_1 && move_first)
+ cogl_path_move_to (path, px, py);
+ else
+ cogl_path_line_to (path, px, py);
+
+ if (G_LIKELY (angle_2 > angle_1))
+ {
+ a += angle_step;
+ if (a > angle_2)
+ a = angle_2;
+ }
+ else
+ {
+ a -= angle_step;
+ if (a < angle_2)
+ a = angle_2;
+ }
+ }
+
+ /* Make sure the final point is drawn */
+
+ cosa = cosf (angle_2 * (G_PI/180.0));
+ sina = sinf (angle_2 * (G_PI/180.0));
+
+ px = center_x + (cosa * radius_x);
+ py = center_y + (sina * radius_y);
+
+ cogl_path_line_to (path, px, py);
}
void
-cogl_path_arc (float center_x,
+cogl_path_arc (CoglPath *path,
+ float center_x,
float center_y,
float radius_x,
float radius_y,
float angle_1,
float angle_2)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ float angle_step = 10;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ /* it is documented that a move to is needed to create a freestanding
+ * arc
+ */
+ _cogl_path_arc (path,
+ center_x, center_y,
+ radius_x, radius_y,
+ angle_1, angle_2,
+ angle_step, 0 /* no move */);
+}
+
+
+static void
+_cogl_path_rel_arc (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2,
+ float angle_step)
+{
+ CoglPathData *data;
- cogl2_path_arc (ctx->current_path,
- center_x,
- center_y,
- radius_x,
- radius_y,
- angle_1,
- angle_2);
+ data = path->data;
+
+ _cogl_path_arc (path,
+ data->path_pen.x + center_x,
+ data->path_pen.y + center_y,
+ radius_x, radius_y,
+ angle_1, angle_2,
+ angle_step, 0 /* no move */);
}
void
-cogl_path_ellipse (float center_x,
+cogl_path_ellipse (CoglPath *path,
+ float center_x,
float center_y,
float radius_x,
float radius_y)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ float angle_step = 10;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ /* FIXME: if shows to be slow might be optimized
+ * by mirroring just a quarter of it */
- cogl2_path_ellipse (ctx->current_path,
- center_x,
- center_y,
- radius_x,
- radius_y);
+ _cogl_path_arc (path,
+ center_x, center_y,
+ radius_x, radius_y,
+ 0, 360,
+ angle_step, 1 /* move first */);
+
+ cogl_path_close (path);
}
void
-cogl_path_round_rectangle (float x_1,
+cogl_path_round_rectangle (CoglPath *path,
+ float x_1,
float y_1,
float x_2,
float y_2,
float radius,
float arc_step)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ float inner_width = x_2 - x_1 - radius * 2;
+ float inner_height = y_2 - y_1 - radius * 2;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ cogl_path_move_to (path, x_1, y_1 + radius);
+ _cogl_path_rel_arc (path,
+ radius, 0,
+ radius, radius,
+ 180,
+ 270,
+ arc_step);
- cogl2_path_round_rectangle (ctx->current_path,
- x_1, y_1, x_2, y_2, radius, arc_step);
+ cogl_path_line_to (path,
+ path->data->path_pen.x + inner_width,
+ path->data->path_pen.y);
+ _cogl_path_rel_arc (path,
+ 0, radius,
+ radius, radius,
+ -90,
+ 0,
+ arc_step);
+
+ cogl_path_line_to (path,
+ path->data->path_pen.x,
+ path->data->path_pen.y + inner_height);
+
+ _cogl_path_rel_arc (path,
+ -radius, 0,
+ radius, radius,
+ 0,
+ 90,
+ arc_step);
+
+ cogl_path_line_to (path,
+ path->data->path_pen.x - inner_width,
+ path->data->path_pen.y);
+ _cogl_path_rel_arc (path,
+ 0, -radius,
+ radius, radius,
+ 90,
+ 180,
+ arc_step);
+
+ cogl_path_close (path);
+}
+
+static void
+_cogl_path_bezier3_sub (CoglPath *path,
+ CoglBezCubic *cubic)
+{
+ CoglBezCubic cubics[_COGL_MAX_BEZ_RECURSE_DEPTH];
+ CoglBezCubic *cleft;
+ CoglBezCubic *cright;
+ CoglBezCubic *c;
+ floatVec2 dif1;
+ floatVec2 dif2;
+ floatVec2 mm;
+ floatVec2 c1;
+ floatVec2 c2;
+ floatVec2 c3;
+ floatVec2 c4;
+ floatVec2 c5;
+ int cindex;
+
+ /* Put first curve on stack */
+ cubics[0] = *cubic;
+ cindex = 0;
+
+ while (cindex >= 0)
+ {
+ c = &cubics[cindex];
+
+
+ /* Calculate distance of control points from their
+ * counterparts on the line between end points */
+ dif1.x = (c->p2.x * 3) - (c->p1.x * 2) - c->p4.x;
+ dif1.y = (c->p2.y * 3) - (c->p1.y * 2) - c->p4.y;
+ dif2.x = (c->p3.x * 3) - (c->p4.x * 2) - c->p1.x;
+ dif2.y = (c->p3.y * 3) - (c->p4.y * 2) - c->p1.y;
+
+ if (dif1.x < 0)
+ dif1.x = -dif1.x;
+ if (dif1.y < 0)
+ dif1.y = -dif1.y;
+ if (dif2.x < 0)
+ dif2.x = -dif2.x;
+ if (dif2.y < 0)
+ dif2.y = -dif2.y;
+
+
+ /* Pick the greatest of two distances */
+ if (dif1.x < dif2.x) dif1.x = dif2.x;
+ if (dif1.y < dif2.y) dif1.y = dif2.y;
+
+ /* Cancel if the curve is flat enough */
+ if (dif1.x + dif1.y <= 1.0 ||
+ cindex == _COGL_MAX_BEZ_RECURSE_DEPTH-1)
+ {
+ /* Add subdivision point (skip last) */
+ if (cindex == 0)
+ return;
+
+ _cogl_path_add_node (path, FALSE, c->p4.x, c->p4.y);
+
+ --cindex;
+
+ continue;
+ }
+
+ /* Left recursion goes on top of stack! */
+ cright = c; cleft = &cubics[++cindex];
+
+ /* Subdivide into 2 sub-curves */
+ c1.x = ((c->p1.x + c->p2.x) / 2);
+ c1.y = ((c->p1.y + c->p2.y) / 2);
+ mm.x = ((c->p2.x + c->p3.x) / 2);
+ mm.y = ((c->p2.y + c->p3.y) / 2);
+ c5.x = ((c->p3.x + c->p4.x) / 2);
+ c5.y = ((c->p3.y + c->p4.y) / 2);
+
+ c2.x = ((c1.x + mm.x) / 2);
+ c2.y = ((c1.y + mm.y) / 2);
+ c4.x = ((mm.x + c5.x) / 2);
+ c4.y = ((mm.y + c5.y) / 2);
+
+ c3.x = ((c2.x + c4.x) / 2);
+ c3.y = ((c2.y + c4.y) / 2);
+
+ /* Add left recursion to stack */
+ cleft->p1 = c->p1;
+ cleft->p2 = c1;
+ cleft->p3 = c2;
+ cleft->p4 = c3;
+
+ /* Add right recursion to stack */
+ cright->p1 = c3;
+ cright->p2 = c4;
+ cright->p3 = c5;
+ cright->p4 = c->p4;
+ }
}
void
-cogl_path_curve_to (float x_1,
+cogl_path_curve_to (CoglPath *path,
+ float x_1,
float y_1,
float x_2,
float y_2,
float x_3,
float y_3)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglBezCubic cubic;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ /* Prepare cubic curve */
+ cubic.p1 = path->data->path_pen;
+ cubic.p2.x = x_1;
+ cubic.p2.y = y_1;
+ cubic.p3.x = x_2;
+ cubic.p3.y = y_2;
+ cubic.p4.x = x_3;
+ cubic.p4.y = y_3;
- cogl2_path_curve_to (ctx->current_path,
- x_1, y_1, x_2, y_2, x_3, y_3);
+ /* Run subdivision */
+ _cogl_path_bezier3_sub (path, &cubic);
+
+ /* Add last point */
+ _cogl_path_add_node (path, FALSE, cubic.p4.x, cubic.p4.y);
+ path->data->path_pen = cubic.p4;
}
void
-cogl_path_rel_curve_to (float x_1,
+cogl_path_rel_curve_to (CoglPath *path,
+ float x_1,
float y_1,
float x_2,
float y_2,
float x_3,
float y_3)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ data = path->data;
- cogl2_path_rel_curve_to (ctx->current_path,
- x_1, y_1, x_2, y_2, x_3, y_3);
+ cogl_path_curve_to (path,
+ data->path_pen.x + x_1,
+ data->path_pen.y + y_1,
+ data->path_pen.x + x_2,
+ data->path_pen.y + y_2,
+ data->path_pen.x + x_3,
+ data->path_pen.y + y_3);
}
CoglPath *
-cogl_get_path (void)
+cogl_path_new (void)
+{
+ CoglPath *path;
+ CoglPathData *data;
+
+ path = g_slice_new (CoglPath);
+ data = path->data = g_slice_new (CoglPathData);
+
+ data->ref_count = 1;
+ data->fill_rule = COGL_PATH_FILL_RULE_EVEN_ODD;
+ data->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
+ data->last_path = 0;
+ data->fill_attribute_buffer = NULL;
+ data->stroke_attribute_buffer = NULL;
+ data->is_rectangle = FALSE;
+
+ return _cogl_path_object_new (path);
+}
+
+CoglPath *
+cogl_path_copy (CoglPath *old_path)
+{
+ CoglPath *new_path;
+
+ _COGL_RETURN_VAL_IF_FAIL (cogl_is_path (old_path), NULL);
+
+ new_path = g_slice_new (CoglPath);
+ new_path->data = old_path->data;
+ new_path->data->ref_count++;
+
+ return _cogl_path_object_new (new_path);
+}
+
+static void
+_cogl_path_free (CoglPath *path)
{
- _COGL_GET_CONTEXT (ctx, NULL);
+ _cogl_path_data_unref (path->data);
+ g_slice_free (CoglPath, path);
+}
+
+/* If second order beziers were needed the following code could
+ * be re-enabled:
+ */
+#if 0
+
+static void
+_cogl_path_bezier2_sub (CoglPath *path,
+ CoglBezQuad *quad)
+{
+ CoglBezQuad quads[_COGL_MAX_BEZ_RECURSE_DEPTH];
+ CoglBezQuad *qleft;
+ CoglBezQuad *qright;
+ CoglBezQuad *q;
+ floatVec2 mid;
+ floatVec2 dif;
+ floatVec2 c1;
+ floatVec2 c2;
+ floatVec2 c3;
+ int qindex;
+
+ /* Put first curve on stack */
+ quads[0] = *quad;
+ qindex = 0;
+
+ /* While stack is not empty */
+ while (qindex >= 0)
+ {
+
+ q = &quads[qindex];
+
+ /* Calculate distance of control point from its
+ * counterpart on the line between end points */
+ mid.x = ((q->p1.x + q->p3.x) / 2);
+ mid.y = ((q->p1.y + q->p3.y) / 2);
+ dif.x = (q->p2.x - mid.x);
+ dif.y = (q->p2.y - mid.y);
+ if (dif.x < 0) dif.x = -dif.x;
+ if (dif.y < 0) dif.y = -dif.y;
+
+ /* Cancel if the curve is flat enough */
+ if (dif.x + dif.y <= 1.0 ||
+ qindex == _COGL_MAX_BEZ_RECURSE_DEPTH - 1)
+ {
+ /* Add subdivision point (skip last) */
+ if (qindex == 0) return;
+ _cogl_path_add_node (path, FALSE, q->p3.x, q->p3.y);
+ --qindex; continue;
+ }
- return ctx->current_path;
+ /* Left recursion goes on top of stack! */
+ qright = q; qleft = &quads[++qindex];
+
+ /* Subdivide into 2 sub-curves */
+ c1.x = ((q->p1.x + q->p2.x) / 2);
+ c1.y = ((q->p1.y + q->p2.y) / 2);
+ c3.x = ((q->p2.x + q->p3.x) / 2);
+ c3.y = ((q->p2.y + q->p3.y) / 2);
+ c2.x = ((c1.x + c3.x) / 2);
+ c2.y = ((c1.y + c3.y) / 2);
+
+ /* Add left recursion onto stack */
+ qleft->p1 = q->p1;
+ qleft->p2 = c1;
+ qleft->p3 = c2;
+
+ /* Add right recursion onto stack */
+ qright->p1 = c2;
+ qright->p2 = c3;
+ qright->p3 = q->p3;
+ }
}
void
-cogl_set_path (CoglPath *path)
+cogl_path_curve2_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglBezQuad quad;
+
+ /* Prepare quadratic curve */
+ quad.p1 = path->data->path_pen;
+ quad.p2.x = x_1;
+ quad.p2.y = y_1;
+ quad.p3.x = x_2;
+ quad.p3.y = y_2;
+
+ /* Run subdivision */
+ _cogl_path_bezier2_sub (&quad);
+
+ /* Add last point */
+ _cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y);
+ path->data->path_pen = quad.p3;
+}
+
+void
+cogl_rel_curve2_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
+{
+ CoglPathData *data;
_COGL_RETURN_IF_FAIL (cogl_is_path (path));
- /* Reference the new object first in case it is the same as the old
- object */
- cogl_object_ref (path);
- cogl_object_unref (ctx->current_path);
- ctx->current_path = path;
+ data = path->data;
+
+ cogl_path_curve2_to (data->path_pen.x + x_1,
+ data->path_pen.y + y_1,
+ data->path_pen.x + x_2,
+ data->path_pen.y + y_2);
+}
+
+#endif
+
+typedef struct _CoglPathTesselator CoglPathTesselator;
+typedef struct _CoglPathTesselatorVertex CoglPathTesselatorVertex;
+
+struct _CoglPathTesselator
+{
+ GLUtesselator *glu_tess;
+ GLenum primitive_type;
+ int vertex_number;
+ /* Array of CoglPathTesselatorVertex. This needs to grow when the
+ combine callback is called */
+ GArray *vertices;
+ /* Array of integers for the indices into the vertices array. Each
+ element will either be guint8, guint16 or guint32 depending on
+ the number of vertices */
+ GArray *indices;
+ CoglIndicesType indices_type;
+ /* Indices used to split fans and strips */
+ int index_a, index_b;
+};
+
+struct _CoglPathTesselatorVertex
+{
+ float x, y, s, t;
+};
+
+static void
+_cogl_path_tesselator_begin (GLenum type,
+ CoglPathTesselator *tess)
+{
+ g_assert (type == GL_TRIANGLES ||
+ type == GL_TRIANGLE_FAN ||
+ type == GL_TRIANGLE_STRIP);
+
+ tess->primitive_type = type;
+ tess->vertex_number = 0;
}
+static CoglIndicesType
+_cogl_path_tesselator_get_indices_type_for_size (int n_vertices)
+{
+ if (n_vertices <= 256)
+ return COGL_INDICES_TYPE_UNSIGNED_BYTE;
+ else if (n_vertices <= 65536)
+ return COGL_INDICES_TYPE_UNSIGNED_SHORT;
+ else
+ return COGL_INDICES_TYPE_UNSIGNED_INT;
+}
+
+static void
+_cogl_path_tesselator_allocate_indices_array (CoglPathTesselator *tess)
+{
+ switch (tess->indices_type)
+ {
+ case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+ tess->indices = g_array_new (FALSE, FALSE, sizeof (guint8));
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+ tess->indices = g_array_new (FALSE, FALSE, sizeof (guint16));
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_INT:
+ tess->indices = g_array_new (FALSE, FALSE, sizeof (guint32));
+ break;
+ }
+}
+
+static void
+_cogl_path_tesselator_add_index (CoglPathTesselator *tess, int vertex_index)
+{
+ switch (tess->indices_type)
+ {
+ case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+ {
+ guint8 val = vertex_index;
+ g_array_append_val (tess->indices, val);
+ }
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+ {
+ guint16 val = vertex_index;
+ g_array_append_val (tess->indices, val);
+ }
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_INT:
+ {
+ guint32 val = vertex_index;
+ g_array_append_val (tess->indices, val);
+ }
+ break;
+ }
+}
+
+static void
+_cogl_path_tesselator_vertex (void *vertex_data,
+ CoglPathTesselator *tess)
+{
+ int vertex_index;
+
+ vertex_index = GPOINTER_TO_INT (vertex_data);
+
+ /* This tries to convert all of the primitives into GL_TRIANGLES
+ with indices to share vertices */
+ switch (tess->primitive_type)
+ {
+ case GL_TRIANGLES:
+ /* Directly use the vertex */
+ _cogl_path_tesselator_add_index (tess, vertex_index);
+ break;
+
+ case GL_TRIANGLE_FAN:
+ if (tess->vertex_number == 0)
+ tess->index_a = vertex_index;
+ else if (tess->vertex_number == 1)
+ tess->index_b = vertex_index;
+ else
+ {
+ /* Create a triangle with the first vertex, the previous
+ vertex and this vertex */
+ _cogl_path_tesselator_add_index (tess, tess->index_a);
+ _cogl_path_tesselator_add_index (tess, tess->index_b);
+ _cogl_path_tesselator_add_index (tess, vertex_index);
+ /* Next time we will use this vertex as the previous
+ vertex */
+ tess->index_b = vertex_index;
+ }
+ break;
+
+ case GL_TRIANGLE_STRIP:
+ if (tess->vertex_number == 0)
+ tess->index_a = vertex_index;
+ else if (tess->vertex_number == 1)
+ tess->index_b = vertex_index;
+ else
+ {
+ _cogl_path_tesselator_add_index (tess, tess->index_a);
+ _cogl_path_tesselator_add_index (tess, tess->index_b);
+ _cogl_path_tesselator_add_index (tess, vertex_index);
+ if (tess->vertex_number & 1)
+ tess->index_b = vertex_index;
+ else
+ tess->index_a = vertex_index;
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ tess->vertex_number++;
+}
+
+static void
+_cogl_path_tesselator_end (CoglPathTesselator *tess)
+{
+ tess->primitive_type = GL_FALSE;
+}
+
+static void
+_cogl_path_tesselator_combine (double coords[3],
+ void *vertex_data[4],
+ float weight[4],
+ void **out_data,
+ CoglPathTesselator *tess)
+{
+ CoglPathTesselatorVertex *vertex;
+ CoglIndicesType new_indices_type;
+ int i;
+
+ /* Add a new vertex to the array */
+ g_array_set_size (tess->vertices, tess->vertices->len + 1);
+ vertex = &g_array_index (tess->vertices,
+ CoglPathTesselatorVertex,
+ tess->vertices->len - 1);
+ /* The data is just the index to the vertex */
+ *out_data = GINT_TO_POINTER (tess->vertices->len - 1);
+ /* Set the coordinates of the new vertex */
+ vertex->x = coords[0];
+ vertex->y = coords[1];
+ /* Generate the texture coordinates as the weighted average of the
+ four incoming coordinates */
+ vertex->s = 0.0f;
+ vertex->t = 0.0f;
+ for (i = 0; i < 4; i++)
+ {
+ CoglPathTesselatorVertex *old_vertex =
+ &g_array_index (tess->vertices, CoglPathTesselatorVertex,
+ GPOINTER_TO_INT (vertex_data[i]));
+ vertex->s += old_vertex->s * weight[i];
+ vertex->t += old_vertex->t * weight[i];
+ }
+
+ /* Check if we've reached the limit for the data type of our indices */
+ new_indices_type =
+ _cogl_path_tesselator_get_indices_type_for_size (tess->vertices->len);
+ if (new_indices_type != tess->indices_type)
+ {
+ CoglIndicesType old_indices_type = new_indices_type;
+ GArray *old_vertices = tess->indices;
+
+ /* Copy the indices to an array of the new type */
+ tess->indices_type = new_indices_type;
+ _cogl_path_tesselator_allocate_indices_array (tess);
+
+ switch (old_indices_type)
+ {
+ case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+ for (i = 0; i < old_vertices->len; i++)
+ _cogl_path_tesselator_add_index (tess,
+ g_array_index (old_vertices,
+ guint8, i));
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+ for (i = 0; i < old_vertices->len; i++)
+ _cogl_path_tesselator_add_index (tess,
+ g_array_index (old_vertices,
+ guint16, i));
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_INT:
+ for (i = 0; i < old_vertices->len; i++)
+ _cogl_path_tesselator_add_index (tess,
+ g_array_index (old_vertices,
+ guint32, i));
+ break;
+ }
+
+ g_array_free (old_vertices, TRUE);
+ }
+}
+
+static void
+_cogl_path_build_fill_attribute_buffer (CoglPath *path)
+{
+ CoglPathTesselator tess;
+ unsigned int path_start = 0;
+ CoglPathData *data = path->data;
+ int i;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ /* If we've already got a vbo then we don't need to do anything */
+ if (data->fill_attribute_buffer)
+ return;
+
+ tess.primitive_type = FALSE;
+
+ /* Generate a vertex for each point on the path */
+ tess.vertices = g_array_new (FALSE, FALSE, sizeof (CoglPathTesselatorVertex));
+ g_array_set_size (tess.vertices, data->path_nodes->len);
+ for (i = 0; i < data->path_nodes->len; i++)
+ {
+ CoglPathNode *node =
+ &g_array_index (data->path_nodes, CoglPathNode, i);
+ CoglPathTesselatorVertex *vertex =
+ &g_array_index (tess.vertices, CoglPathTesselatorVertex, i);
+
+ vertex->x = node->x;
+ vertex->y = node->y;
+
+ /* Add texture coordinates so that a texture would be drawn to
+ fit the bounding box of the path and then cropped by the
+ path */
+ if (data->path_nodes_min.x == data->path_nodes_max.x)
+ vertex->s = 0.0f;
+ else
+ vertex->s = ((node->x - data->path_nodes_min.x)
+ / (data->path_nodes_max.x - data->path_nodes_min.x));
+ if (data->path_nodes_min.y == data->path_nodes_max.y)
+ vertex->t = 0.0f;
+ else
+ vertex->t = ((node->y - data->path_nodes_min.y)
+ / (data->path_nodes_max.y - data->path_nodes_min.y));
+ }
+
+ tess.indices_type =
+ _cogl_path_tesselator_get_indices_type_for_size (data->path_nodes->len);
+ _cogl_path_tesselator_allocate_indices_array (&tess);
+
+ tess.glu_tess = gluNewTess ();
+
+ if (data->fill_rule == COGL_PATH_FILL_RULE_EVEN_ODD)
+ gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE,
+ GLU_TESS_WINDING_ODD);
+ else
+ gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE,
+ GLU_TESS_WINDING_NONZERO);
+
+ /* All vertices are on the xy-plane */
+ gluTessNormal (tess.glu_tess, 0.0, 0.0, 1.0);
+
+ gluTessCallback (tess.glu_tess, GLU_TESS_BEGIN_DATA,
+ _cogl_path_tesselator_begin);
+ gluTessCallback (tess.glu_tess, GLU_TESS_VERTEX_DATA,
+ _cogl_path_tesselator_vertex);
+ gluTessCallback (tess.glu_tess, GLU_TESS_END_DATA,
+ _cogl_path_tesselator_end);
+ gluTessCallback (tess.glu_tess, GLU_TESS_COMBINE_DATA,
+ _cogl_path_tesselator_combine);
+
+ gluTessBeginPolygon (tess.glu_tess, &tess);
+
+ while (path_start < data->path_nodes->len)
+ {
+ CoglPathNode *node =
+ &g_array_index (data->path_nodes, CoglPathNode, path_start);
+
+ gluTessBeginContour (tess.glu_tess);
+
+ for (i = 0; i < node->path_size; i++)
+ {
+ double vertex[3] = { node[i].x, node[i].y, 0.0 };
+ gluTessVertex (tess.glu_tess, vertex,
+ GINT_TO_POINTER (i + path_start));
+ }
+
+ gluTessEndContour (tess.glu_tess);
+
+ path_start += node->path_size;
+ }
+
+ gluTessEndPolygon (tess.glu_tess);
+
+ gluDeleteTess (tess.glu_tess);
+
+ data->fill_attribute_buffer =
+ cogl_attribute_buffer_new (ctx,
+ sizeof (CoglPathTesselatorVertex) *
+ tess.vertices->len,
+ tess.vertices->data);
+ g_array_free (tess.vertices, TRUE);
+
+ data->fill_attributes[0] =
+ cogl_attribute_new (data->fill_attribute_buffer,
+ "cogl_position_in",
+ sizeof (CoglPathTesselatorVertex),
+ G_STRUCT_OFFSET (CoglPathTesselatorVertex, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ data->fill_attributes[1] =
+ cogl_attribute_new (data->fill_attribute_buffer,
+ "cogl_tex_coord0_in",
+ sizeof (CoglPathTesselatorVertex),
+ G_STRUCT_OFFSET (CoglPathTesselatorVertex, s),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+
+ data->fill_vbo_indices = cogl_indices_new (ctx,
+ tess.indices_type,
+ tess.indices->data,
+ tess.indices->len);
+ data->fill_vbo_n_indices = tess.indices->len;
+ g_array_free (tess.indices, TRUE);
+}
+
+static void
+_cogl_path_build_stroke_attribute_buffer (CoglPath *path)
+{
+ CoglPathData *data = path->data;
+ CoglBuffer *buffer;
+ unsigned int n_attributes = 0;
+ unsigned int path_start;
+ CoglPathNode *node;
+ floatVec2 *buffer_p;
+ unsigned int i;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ /* If we've already got a cached vbo then we don't need to do anything */
+ if (data->stroke_attribute_buffer)
+ return;
+
+ data->stroke_attribute_buffer =
+ cogl_attribute_buffer_new (ctx, data->path_nodes->len * sizeof (floatVec2),
+ NULL);
+
+ buffer = COGL_BUFFER (data->stroke_attribute_buffer);
+ buffer_p = _cogl_buffer_map_for_fill_or_fallback (buffer);
+
+ /* Copy the vertices in and count the number of sub paths. Each sub
+ path will form a separate attribute so we can paint the disjoint
+ line strips */
+ for (path_start = 0;
+ path_start < data->path_nodes->len;
+ path_start += node->path_size)
+ {
+ node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
+
+ for (i = 0; i < node->path_size; i++)
+ {
+ buffer_p[path_start + i].x = node[i].x;
+ buffer_p[path_start + i].y = node[i].y;
+ }
+
+ n_attributes++;
+ }
+
+ _cogl_buffer_unmap_for_fill_or_fallback (buffer);
+
+ data->stroke_attributes = g_new (CoglAttribute *, n_attributes);
+
+ /* Now we can loop the sub paths again to create the attributes */
+ for (i = 0, path_start = 0;
+ path_start < data->path_nodes->len;
+ i++, path_start += node->path_size)
+ {
+ node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
+
+ data->stroke_attributes[i] =
+ cogl_attribute_new (data->stroke_attribute_buffer,
+ "cogl_position_in",
+ sizeof (floatVec2),
+ path_start * sizeof (floatVec2),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ }
+
+ data->stroke_n_attributes = n_attributes;
+}
diff --git a/cogl/cogl-path.h b/cogl/cogl-path.h
index c3d0d45..5ab976f 100644
--- a/cogl/cogl-path.h
+++ b/cogl/cogl-path.h
@@ -56,6 +56,332 @@ typedef struct _CoglPath CoglPath;
#define COGL_PATH(obj) ((CoglPath *)(obj))
/**
+ * cogl_path_new:
+ *
+ * Creates a new, empty path object. The default fill rule is
+ * %COGL_PATH_FILL_RULE_EVEN_ODD.
+ *
+ * Return value: A pointer to a newly allocated #CoglPath, which can
+ * be freed using cogl_object_unref().
+ *
+ * Since: 2.0
+ */
+CoglPath *
+cogl_path_new (void);
+
+/**
+ * cogl_path_copy:
+ * @path: A #CoglPath object
+ *
+ * Returns a new copy of the path in @path. The new path has a
+ * reference count of 1 so you should unref it with
+ * cogl_object_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 @path.
+ *
+ * Since: 2.0
+ */
+CoglPath *
+cogl_path_copy (CoglPath *path);
+
+/**
+ * cogl_is_path:
+ * @object: A #CoglObject
+ *
+ * Gets whether the given object references an existing path object.
+ *
+ * Return value: %TRUE if the object references a #CoglPath,
+ * %FALSE otherwise.
+ *
+ * Since: 2.0
+ */
+gboolean
+cogl_is_path (void *object);
+
+/**
+ * cogl_path_move_to:
+ * @x: X coordinate of the pen location to move to.
+ * @y: Y coordinate of the pen location to move to.
+ *
+ * Moves the pen to the given location. If there is an existing path
+ * this will start a new disjoint subpath.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_move_to (CoglPath *path,
+ float x,
+ float y);
+
+/**
+ * cogl_path_rel_move_to:
+ * @x: X offset from the current pen location to move the pen to.
+ * @y: Y offset from the current pen location to move the pen to.
+ *
+ * Moves the pen to the given offset relative to the current pen
+ * location. If there is an existing path this will start a new
+ * disjoint subpath.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_rel_move_to (CoglPath *path,
+ float x,
+ float y);
+
+/**
+ * cogl_path_line_to:
+ * @x: X coordinate of the end line vertex
+ * @y: Y coordinate of the end line vertex
+ *
+ * Adds a straight line segment to the current path that ends at the
+ * given coordinates.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_line_to (CoglPath *path,
+ float x,
+ float y);
+
+/**
+ * cogl_path_rel_line_to:
+ * @x: X offset from the current pen location of the end line vertex
+ * @y: Y offset from the current pen location of the end line vertex
+ *
+ * Adds a straight line segment to the current path that ends at the
+ * given coordinates relative to the current pen location.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_rel_line_to (CoglPath *path,
+ float x,
+ float y);
+
+/**
+ * cogl_path_arc:
+ * @center_x: X coordinate of the elliptical arc center
+ * @center_y: Y coordinate of the elliptical arc center
+ * @radius_x: X radius of the elliptical arc
+ * @radius_y: Y radius of the elliptical arc
+ * @angle_1: Angle in degrees at which the arc begin
+ * @angle_2: Angle in degrees at which the arc ends
+ *
+ * Adds an elliptical arc segment to the current path. A straight line
+ * segment will link the current pen location with the first vertex
+ * of the arc. If you perform a move_to to the arcs start just before
+ * drawing it you create a free standing arc.
+ *
+ * The angles are measured in degrees where 0° is in the direction of
+ * the positive X axis and 90° is in the direction of the positive Y
+ * axis. The angle of the arc begins at @angle_1 and heads towards
+ * @angle_2 (so if @angle_2 is less than @angle_1 it will decrease,
+ * otherwise it will increase).
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_arc (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2);
+
+/**
+ * cogl_path_curve_to:
+ * @x_1: X coordinate of the second bezier control point
+ * @y_1: Y coordinate of the second bezier control point
+ * @x_2: X coordinate of the third bezier control point
+ * @y_2: Y coordinate of the third bezier control point
+ * @x_3: X coordinate of the fourth bezier control point
+ * @y_3: Y coordinate of the fourth bezier control point
+ *
+ * Adds a cubic bezier curve segment to the current path with the given
+ * second, third and fourth control points and using current pen location
+ * as the first control point.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_curve_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3);
+
+/**
+ * cogl_path_rel_curve_to:
+ * @x_1: X coordinate of the second bezier control point
+ * @y_1: Y coordinate of the second bezier control point
+ * @x_2: X coordinate of the third bezier control point
+ * @y_2: Y coordinate of the third bezier control point
+ * @x_3: X coordinate of the fourth bezier control point
+ * @y_3: Y coordinate of the fourth bezier control point
+ *
+ * Adds a cubic bezier curve segment to the current path with the given
+ * second, third and fourth control points and using current pen location
+ * as the first control point. The given coordinates are relative to the
+ * current pen location.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_rel_curve_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3);
+
+/**
+ * cogl_path_close:
+ *
+ * Closes the path being constructed by adding a straight line segment
+ * to it that ends at the first vertex of the path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_close (CoglPath *path);
+
+/**
+ * cogl_path_line:
+ * @x_1: X coordinate of the start line vertex
+ * @y_1: Y coordinate of the start line vertex
+ * @x_2: X coordinate of the end line vertex
+ * @y_2: Y coordinate of the end line vertex
+ *
+ * Constructs a straight line shape starting and ending at the given
+ * coordinates. If there is an existing path this will start a new
+ * disjoint sub-path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_line (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2);
+
+/**
+ * cogl_path_polyline:
+ * @coords: (in) (array) (transfer none): A pointer to the first element of an
+ * array of fixed-point values that specify the vertex coordinates.
+ * @num_points: The total number of vertices.
+ *
+ * Constructs a series of straight line segments, starting from the
+ * first given vertex coordinate. If there is an existing path this
+ * will start a new disjoint sub-path. Each subsequent segment starts
+ * where the previous one ended and ends at the next given vertex
+ * coordinate.
+ *
+ * The coords array must contain 2 * num_points values. The first value
+ * represents the X coordinate of the first vertex, the second value
+ * represents the Y coordinate of the first vertex, continuing in the same
+ * fashion for the rest of the vertices. (num_points - 1) segments will
+ * be constructed.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_polyline (CoglPath *path,
+ const float *coords,
+ int num_points);
+
+/**
+ * cogl_path_polygon:
+ * @coords: (in) (array) (transfer none): A pointer to the first element of
+ * an array of fixed-point values that specify the vertex coordinates.
+ * @num_points: The total number of vertices.
+ *
+ * Constructs a polygonal shape of the given number of vertices. If
+ * there is an existing path this will start a new disjoint sub-path.
+ *
+ * The coords array must contain 2 * num_points values. The first value
+ * represents the X coordinate of the first vertex, the second value
+ * represents the Y coordinate of the first vertex, continuing in the same
+ * fashion for the rest of the vertices.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_polygon (CoglPath *path,
+ const float *coords,
+ int num_points);
+
+/**
+ * cogl_path_rectangle:
+ * @x_1: X coordinate of the top-left corner.
+ * @y_1: Y coordinate of the top-left corner.
+ * @x_2: X coordinate of the bottom-right corner.
+ * @y_2: Y coordinate of the bottom-right corner.
+ *
+ * Constructs a rectangular shape at the given coordinates. If there
+ * is an existing path this will start a new disjoint sub-path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_rectangle (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2);
+
+/**
+ * cogl_path_ellipse:
+ * @center_x: X coordinate of the ellipse center
+ * @center_y: Y coordinate of the ellipse center
+ * @radius_x: X radius of the ellipse
+ * @radius_y: Y radius of the ellipse
+ *
+ * Constructs an ellipse shape. If there is an existing path this will
+ * start a new disjoint sub-path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_ellipse (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y);
+
+/**
+ * cogl_path_round_rectangle:
+ * @x_1: X coordinate of the top-left corner.
+ * @y_1: Y coordinate of the top-left corner.
+ * @x_2: X coordinate of the bottom-right corner.
+ * @y_2: Y coordinate of the bottom-right corner.
+ * @radius: Radius of the corner arcs.
+ * @arc_step: Angle increment resolution for subdivision of
+ * the corner arcs.
+ *
+ * Constructs a rectangular shape with rounded corners. If there is an
+ * existing path this will start a new disjoint sub-path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_round_rectangle (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float radius,
+ float arc_step);
+
+/**
* CoglPathFillRule:
* @COGL_PATH_FILL_RULE_NON_ZERO: Each time the line crosses an edge of
* the path from left to right one is added to a counter and each time
@@ -97,9 +423,65 @@ typedef enum {
COGL_PATH_FILL_RULE_EVEN_ODD
} CoglPathFillRule;
-G_END_DECLS
+/**
+ * cogl_path_set_fill_rule:
+ * @fill_rule: The new fill rule.
+ *
+ * Sets the fill rule of the current path to @fill_rule. This will
+ * affect how the path is filled when cogl_path_fill() is later
+ * called. Note that the fill rule state is attached to the path so
+ * calling cogl_get_path() will preserve the fill rule and calling
+ * cogl_path_new() will reset the fill rule back to the default.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_set_fill_rule (CoglPath *path, CoglPathFillRule fill_rule);
-#include "cogl-path-functions.h"
+/**
+ * cogl_path_get_fill_rule:
+ *
+ * Retrieves the fill rule set using cogl_path_set_fill_rule().
+ *
+ * Return value: the fill rule that is used for the current path.
+ *
+ * Since: 2.0
+ */
+CoglPathFillRule
+cogl_path_get_fill_rule (CoglPath *path);
+
+/**
+ * cogl_path_fill:
+ *
+ * Fills the interior of the constructed shape using the current
+ * drawing color.
+ *
+ * The interior of the shape is determined using the fill rule of the
+ * path. See %CoglPathFillRule for details.
+ *
+ * <note>The result of referencing sliced textures in your current
+ * pipeline when filling a path are undefined. You should pass
+ * the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will
+ * use while filling a path.</note>
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_fill (CoglPath *path);
+
+/**
+ * cogl_path_stroke:
+ *
+ * Strokes the constructed shape using the current drawing color and a
+ * width of 1 pixel (regardless of the current transformation
+ * matrix).
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_stroke (CoglPath *path);
+
+G_END_DECLS
#endif /* __COGL_PATH_H__ */
diff --git a/cogl/cogl.h b/cogl/cogl.h
index baacd8a..6f2a5d1 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -60,12 +60,12 @@
#include <cogl/cogl-primitives.h>
#include <cogl/cogl-texture.h>
#include <cogl/cogl-types.h>
+#include <cogl/cogl-path.h>
/*
* 1.x only api...
*/
#ifndef COGL_ENABLE_EXPERIMENTAL_2_0_API
-#include <cogl/cogl-path.h>
#include <cogl/cogl-clip-state.h>
#include <cogl/cogl-enum-types.h>
#include <cogl/cogl-shader.h>
@@ -123,13 +123,6 @@
#endif
/*
- * 2.0 only api...
- */
-#ifdef COGL_ENABLE_EXPERIMENTAL_2_0_API
-#include <cogl/cogl2-path.h>
-#endif
-
-/*
* API deprecations
*/
#include <cogl/cogl-deprecated.h>
diff --git a/cogl/cogl.symbols b/cogl/cogl.symbols
index d0627b7..47ee24c 100644
--- a/cogl/cogl.symbols
+++ b/cogl/cogl.symbols
@@ -4,28 +4,25 @@
/* (this may be subject to change!) */
#endif
-/* cogl2_clip_push_from_path is only for 1.10.x*/
-cogl2_clip_push_from_path
-
-cogl2_path_arc
-cogl2_path_close
-cogl2_path_curve_to
-cogl2_path_ellipse
-cogl2_path_fill
-cogl2_path_get_fill_rule
-cogl2_path_line
-cogl2_path_line_to
-cogl2_path_move_to
-cogl2_path_new
-cogl2_path_polygon
-cogl2_path_polyline
-cogl2_path_rectangle
-cogl2_path_rel_curve_to
-cogl2_path_rel_line_to
-cogl2_path_rel_move_to
-cogl2_path_round_rectangle
-cogl2_path_set_fill_rule
-cogl2_path_stroke
+cogl_path_arc
+cogl_path_close
+cogl_path_curve_to
+cogl_path_ellipse
+cogl_path_fill
+cogl_path_get_fill_rule
+cogl_path_line
+cogl_path_line_to
+cogl_path_move_to
+cogl_path_new
+cogl_path_polygon
+cogl_path_polyline
+cogl_path_rectangle
+cogl_path_rel_curve_to
+cogl_path_rel_line_to
+cogl_path_rel_move_to
+cogl_path_round_rectangle
+cogl_path_set_fill_rule
+cogl_path_stroke
#ifdef COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT
cogl_android_set_native_window_EXP
@@ -93,8 +90,6 @@ cogl_clip_pop
cogl_clip_push
#endif
-cogl_clip_push_from_path
-cogl_clip_push_from_path_preserve
cogl_clip_push_rectangle
cogl_clip_push_window_rect
@@ -404,30 +399,6 @@ cogl_onscreen_template_set_swap_throttled
cogl_ortho
-cogl_path_arc
-cogl_path_close
-cogl_path_copy
-cogl_path_curve_to
-cogl_path_ellipse
-cogl_path_fill
-cogl_path_fill_preserve /* this is COGL 1.0 API */
-cogl_path_fill_rule_get_type
-cogl_path_get_fill_rule
-cogl_path_line
-cogl_path_line_to
-cogl_path_move_to
-cogl_path_new
-cogl_path_polygon
-cogl_path_polyline
-cogl_path_rectangle
-cogl_path_rel_curve_to
-cogl_path_rel_line_to
-cogl_path_rel_move_to
-cogl_path_round_rectangle
-cogl_path_set_fill_rule
-cogl_path_stroke
-cogl_path_stroke_preserve /* this is COGL 1.0 API */
-
cogl_perspective
cogl_pipeline_add_layer_snippet
diff --git a/cogl/cogl1-context.h b/cogl/cogl1-context.h
index c59bd69..519b8b0 100644
--- a/cogl/cogl1-context.h
+++ b/cogl/cogl1-context.h
@@ -750,19 +750,6 @@ cogl_clip_push_rectangle (float x0,
float x1,
float y1);
-/**
- * cogl_clip_push_from_path_preserve:
- *
- * Sets a new clipping area using the current path. The current path
- * is then cleared. The clipping area is intersected with the previous
- * clipping area. To restore the previous clipping area, call
- * cogl_clip_pop().
- *
- * Since: 1.0
- */
-void
-cogl_clip_push_from_path_preserve (void);
-
#ifdef COGL_ENABLE_EXPERIMENTAL_2_0_API
/**
* cogl_clip_push_primitive:
diff --git a/cogl/cogl2-path.c b/cogl/cogl2-path.c
deleted file mode 100644
index d9426ae..0000000
--- a/cogl/cogl2-path.c
+++ /dev/null
@@ -1,1449 +0,0 @@
-/*
- * Cogl
- *
- * An object oriented GL/GLES Abstraction/Utility Layer
- *
- * Copyright (C) 2007,2008,2009,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
- * <http://www.gnu.org/licenses/>.
- *
- * Authors:
- * Ivan Leben <ivan at openedhand.com>
- * Øyvind Kolås <pippin at linux.intel.com>
- * Neil Roberts <neil at linux.intel.com>
- * Robert Bragg <robert at linux.intel.com>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "cogl-util.h"
-#include "cogl-object.h"
-#include "cogl-internal.h"
-#include "cogl-context-private.h"
-#include "cogl-journal-private.h"
-#include "cogl-pipeline-private.h"
-#include "cogl-pipeline-opengl-private.h"
-#include "cogl-framebuffer-private.h"
-#include "cogl-path-private.h"
-#include "cogl-texture-private.h"
-#include "cogl-primitives-private.h"
-#include "cogl-private.h"
-#include "cogl-attribute-private.h"
-#include "cogl1-context.h"
-#include "tesselator/tesselator.h"
-
-#include <string.h>
-#include <math.h>
-
-#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
-
-static void _cogl_path_free (CoglPath *path);
-
-static void _cogl_path_build_fill_attribute_buffer (CoglPath *path);
-static void _cogl_path_build_stroke_attribute_buffer (CoglPath *path);
-
-COGL_OBJECT_DEFINE (Path, path);
-
-static void
-_cogl_path_data_clear_vbos (CoglPathData *data)
-{
- int i;
-
- if (data->fill_attribute_buffer)
- {
- cogl_object_unref (data->fill_attribute_buffer);
- cogl_object_unref (data->fill_vbo_indices);
-
- for (i = 0; i < COGL_PATH_N_ATTRIBUTES; i++)
- cogl_object_unref (data->fill_attributes[i]);
-
- data->fill_attribute_buffer = NULL;
- }
-
- if (data->stroke_attribute_buffer)
- {
- cogl_object_unref (data->stroke_attribute_buffer);
-
- for (i = 0; i < data->stroke_n_attributes; i++)
- cogl_object_unref (data->stroke_attributes[i]);
-
- g_free (data->stroke_attributes);
-
- data->stroke_attribute_buffer = NULL;
- }
-}
-
-static void
-_cogl_path_data_unref (CoglPathData *data)
-{
- if (--data->ref_count <= 0)
- {
- _cogl_path_data_clear_vbos (data);
-
- g_array_free (data->path_nodes, TRUE);
-
- g_slice_free (CoglPathData, data);
- }
-}
-
-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 */
-
- /* If there is more than one path using the data then we need to
- copy the data instead */
- if (path->data->ref_count != 1)
- {
- CoglPathData *old_data = path->data;
-
- path->data = g_slice_dup (CoglPathData, old_data);
- path->data->path_nodes = g_array_new (FALSE, FALSE,
- sizeof (CoglPathNode));
- g_array_append_vals (path->data->path_nodes,
- old_data->path_nodes->data,
- old_data->path_nodes->len);
-
- path->data->fill_attribute_buffer = NULL;
- path->data->stroke_attribute_buffer = NULL;
- path->data->ref_count = 1;
-
- _cogl_path_data_unref (old_data);
- }
- else
- /* The path is altered so the vbos will now be invalid */
- _cogl_path_data_clear_vbos (path->data);
-}
-
-void
-cogl2_path_set_fill_rule (CoglPath *path,
- CoglPathFillRule fill_rule)
-{
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- if (path->data->fill_rule != fill_rule)
- {
- _cogl_path_modify (path);
-
- path->data->fill_rule = fill_rule;
- }
-}
-
-CoglPathFillRule
-cogl2_path_get_fill_rule (CoglPath *path)
-{
- _COGL_RETURN_VAL_IF_FAIL (cogl_is_path (path), COGL_PATH_FILL_RULE_NON_ZERO);
-
- return path->data->fill_rule;
-}
-
-static void
-_cogl_path_add_node (CoglPath *path,
- gboolean new_sub_path,
- float x,
- float y)
-{
- CoglPathNode new_node;
- CoglPathData *data;
-
- _cogl_path_modify (path);
-
- data = path->data;
-
- new_node.x = x;
- new_node.y = y;
- new_node.path_size = 0;
-
- if (new_sub_path || data->path_nodes->len == 0)
- data->last_path = data->path_nodes->len;
-
- g_array_append_val (data->path_nodes, new_node);
-
- g_array_index (data->path_nodes, CoglPathNode, data->last_path).path_size++;
-
- if (data->path_nodes->len == 1)
- {
- data->path_nodes_min.x = data->path_nodes_max.x = x;
- data->path_nodes_min.y = data->path_nodes_max.y = y;
- }
- else
- {
- if (x < data->path_nodes_min.x)
- data->path_nodes_min.x = x;
- if (x > data->path_nodes_max.x)
- data->path_nodes_max.x = x;
- if (y < data->path_nodes_min.y)
- data->path_nodes_min.y = y;
- if (y > data->path_nodes_max.y)
- data->path_nodes_max.y = y;
- }
-
- /* Once the path nodes have been modified then we'll assume it's no
- longer a rectangle. cogl2_path_rectangle will set this back to
- TRUE if this has been called from there */
- data->is_rectangle = FALSE;
-}
-
-static void
-_cogl_path_stroke_nodes (CoglPath *path)
-{
- CoglPathData *data = path->data;
- CoglPipeline *copy = NULL;
- CoglPipeline *source;
- unsigned int path_start;
- int path_num = 0;
- CoglPathNode *node;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- source = cogl_get_source ();
-
- if (cogl_pipeline_get_n_layers (source) != 0)
- {
- copy = cogl_pipeline_copy (source);
- _cogl_pipeline_prune_to_n_layers (copy, 0);
- source = copy;
- }
-
- _cogl_path_build_stroke_attribute_buffer (path);
-
- cogl_push_source (source);
-
- for (path_start = 0;
- path_start < data->path_nodes->len;
- path_start += node->path_size)
- {
- node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
-
- cogl_framebuffer_vdraw_attributes (cogl_get_draw_framebuffer (),
- source,
- COGL_VERTICES_MODE_LINE_STRIP,
- 0, node->path_size,
- data->stroke_attributes[path_num],
- NULL);
-
- path_num++;
- }
-
- cogl_pop_source ();
-
- if (copy)
- cogl_object_unref (copy);
-}
-
-void
-_cogl_path_get_bounds (CoglPath *path,
- float *min_x,
- float *min_y,
- float *max_x,
- float *max_y)
-{
- CoglPathData *data = path->data;
-
- if (data->path_nodes->len == 0)
- {
- *min_x = 0.0f;
- *min_y = 0.0f;
- *max_x = 0.0f;
- *max_y = 0.0f;
- }
- else
- {
- *min_x = data->path_nodes_min.x;
- *min_y = data->path_nodes_min.y;
- *max_x = data->path_nodes_max.x;
- *max_y = data->path_nodes_max.y;
- }
-}
-
-static void
-_cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path)
-{
- CoglFramebuffer *fb;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_STENCIL_BUFFER))
- {
- static gboolean seen_warning = FALSE;
-
- if (!seen_warning)
- {
- g_warning ("Paths can not be filled using materials with "
- "sliced textures unless there is a stencil "
- "buffer");
- seen_warning = TRUE;
- }
- }
-
- fb = cogl_get_draw_framebuffer ();
- cogl_framebuffer_push_path_clip (fb, path);
- cogl_rectangle (path->data->path_nodes_min.x,
- path->data->path_nodes_min.y,
- path->data->path_nodes_max.x,
- path->data->path_nodes_max.y);
- cogl_framebuffer_pop_clip (fb);
-}
-
-static gboolean
-validate_layer_cb (CoglPipelineLayer *layer, void *user_data)
-{
- gboolean *needs_fallback = user_data;
- CoglTexture *texture = _cogl_pipeline_layer_get_texture (layer);
-
- /* If any of the layers of the current pipeline contain sliced
- * textures or textures with waste then it won't work to draw the
- * path directly. Instead we fallback to pushing the path as a clip
- * on the clip-stack and drawing the path's bounding rectangle
- * instead.
- */
-
- if (texture != NULL && (cogl_texture_is_sliced (texture) ||
- !_cogl_texture_can_hardware_repeat (texture)))
- *needs_fallback = TRUE;
-
- return !*needs_fallback;
-}
-
-void
-_cogl_path_fill_nodes (CoglPath *path, CoglDrawFlags flags)
-{
- gboolean needs_fallback = FALSE;
- CoglPipeline *pipeline = cogl_get_source ();
-
- _cogl_pipeline_foreach_layer_internal (pipeline,
- validate_layer_cb, &needs_fallback);
- if (needs_fallback)
- {
- _cogl_path_fill_nodes_with_clipped_rectangle (path);
- return;
- }
-
- _cogl_path_build_fill_attribute_buffer (path);
-
- _cogl_framebuffer_draw_indexed_attributes (cogl_get_draw_framebuffer (),
- pipeline,
- COGL_VERTICES_MODE_TRIANGLES,
- 0, /* first_vertex */
- path->data->fill_vbo_n_indices,
- path->data->fill_vbo_indices,
- path->data->fill_attributes,
- COGL_PATH_N_ATTRIBUTES,
- flags);
-}
-
-void
-cogl2_path_fill (CoglPath *path)
-{
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- if (path->data->path_nodes->len == 0)
- return;
-
- /* If the path is a simple rectangle then we can divert to using
- cogl_rectangle which should be faster because it can go through
- the journal instead of uploading the geometry just for two
- triangles */
- if (path->data->is_rectangle)
- {
- float x_1, y_1, x_2, y_2;
-
- _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
- cogl_rectangle (x_1, y_1, x_2, y_2);
- }
- else
- _cogl_path_fill_nodes (path, 0);
-}
-
-void
-cogl2_path_stroke (CoglPath *path)
-{
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- if (path->data->path_nodes->len == 0)
- return;
-
- _cogl_path_stroke_nodes (path);
-}
-
-void
-cogl2_path_move_to (CoglPath *path,
- float x,
- float y)
-{
- CoglPathData *data;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- _cogl_path_add_node (path, TRUE, x, y);
-
- data = path->data;
-
- data->path_start.x = x;
- data->path_start.y = y;
-
- data->path_pen = data->path_start;
-}
-
-void
-cogl2_path_rel_move_to (CoglPath *path,
- float x,
- float y)
-{
- CoglPathData *data;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- data = path->data;
-
- cogl2_path_move_to (path,
- data->path_pen.x + x,
- data->path_pen.y + y);
-}
-
-void
-cogl2_path_line_to (CoglPath *path,
- float x,
- float y)
-{
- CoglPathData *data;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- _cogl_path_add_node (path, FALSE, x, y);
-
- data = path->data;
-
- data->path_pen.x = x;
- data->path_pen.y = y;
-}
-
-void
-cogl2_path_rel_line_to (CoglPath *path,
- float x,
- float y)
-{
- CoglPathData *data;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- data = path->data;
-
- cogl2_path_line_to (path,
- data->path_pen.x + x,
- data->path_pen.y + y);
-}
-
-void
-cogl2_path_close (CoglPath *path)
-{
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- _cogl_path_add_node (path, FALSE, path->data->path_start.x,
- path->data->path_start.y);
-
- path->data->path_pen = path->data->path_start;
-}
-
-void
-cogl2_path_line (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2)
-{
- cogl2_path_move_to (path, x_1, y_1);
- cogl2_path_line_to (path, x_2, y_2);
-}
-
-void
-cogl2_path_polyline (CoglPath *path,
- const float *coords,
- int num_points)
-{
- int c = 0;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- cogl2_path_move_to (path, coords[0], coords[1]);
-
- for (c = 1; c < num_points; ++c)
- cogl2_path_line_to (path, coords[2*c], coords[2*c+1]);
-}
-
-void
-cogl2_path_polygon (CoglPath *path,
- const float *coords,
- int num_points)
-{
- cogl2_path_polyline (path, coords, num_points);
- cogl2_path_close (path);
-}
-
-void
-cogl2_path_rectangle (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2)
-{
- gboolean is_rectangle;
-
- /* If the path was previously empty and the rectangle isn't mirrored
- then we'll record that this is a simple rectangle path so that we
- can optimise it */
- is_rectangle = (path->data->path_nodes->len == 0 &&
- x_2 >= x_1 &&
- y_2 >= y_1);
-
- cogl2_path_move_to (path, x_1, y_1);
- cogl2_path_line_to (path, x_2, y_1);
- cogl2_path_line_to (path, x_2, y_2);
- cogl2_path_line_to (path, x_1, y_2);
- cogl2_path_close (path);
-
- path->data->is_rectangle = is_rectangle;
-}
-
-gboolean
-_cogl_path_is_rectangle (CoglPath *path)
-{
- return path->data->is_rectangle;
-}
-
-static void
-_cogl_path_arc (CoglPath *path,
- float center_x,
- float center_y,
- float radius_x,
- float radius_y,
- float angle_1,
- float angle_2,
- float angle_step,
- unsigned int move_first)
-{
- float a = 0x0;
- float cosa = 0x0;
- float sina = 0x0;
- float px = 0x0;
- float py = 0x0;
-
- /* Fix invalid angles */
-
- if (angle_1 == angle_2 || angle_step == 0x0)
- return;
-
- if (angle_step < 0x0)
- angle_step = -angle_step;
-
- /* Walk the arc by given step */
-
- a = angle_1;
- while (a != angle_2)
- {
- cosa = cosf (a * (G_PI/180.0));
- sina = sinf (a * (G_PI/180.0));
-
- px = center_x + (cosa * radius_x);
- py = center_y + (sina * radius_y);
-
- if (a == angle_1 && move_first)
- cogl2_path_move_to (path, px, py);
- else
- cogl2_path_line_to (path, px, py);
-
- if (G_LIKELY (angle_2 > angle_1))
- {
- a += angle_step;
- if (a > angle_2)
- a = angle_2;
- }
- else
- {
- a -= angle_step;
- if (a < angle_2)
- a = angle_2;
- }
- }
-
- /* Make sure the final point is drawn */
-
- cosa = cosf (angle_2 * (G_PI/180.0));
- sina = sinf (angle_2 * (G_PI/180.0));
-
- px = center_x + (cosa * radius_x);
- py = center_y + (sina * radius_y);
-
- cogl2_path_line_to (path, px, py);
-}
-
-void
-cogl2_path_arc (CoglPath *path,
- float center_x,
- float center_y,
- float radius_x,
- float radius_y,
- float angle_1,
- float angle_2)
-{
- float angle_step = 10;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- /* it is documented that a move to is needed to create a freestanding
- * arc
- */
- _cogl_path_arc (path,
- center_x, center_y,
- radius_x, radius_y,
- angle_1, angle_2,
- angle_step, 0 /* no move */);
-}
-
-
-static void
-_cogl_path_rel_arc (CoglPath *path,
- float center_x,
- float center_y,
- float radius_x,
- float radius_y,
- float angle_1,
- float angle_2,
- float angle_step)
-{
- CoglPathData *data;
-
- data = path->data;
-
- _cogl_path_arc (path,
- data->path_pen.x + center_x,
- data->path_pen.y + center_y,
- radius_x, radius_y,
- angle_1, angle_2,
- angle_step, 0 /* no move */);
-}
-
-void
-cogl2_path_ellipse (CoglPath *path,
- float center_x,
- float center_y,
- float radius_x,
- float radius_y)
-{
- float angle_step = 10;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- /* FIXME: if shows to be slow might be optimized
- * by mirroring just a quarter of it */
-
- _cogl_path_arc (path,
- center_x, center_y,
- radius_x, radius_y,
- 0, 360,
- angle_step, 1 /* move first */);
-
- cogl2_path_close (path);
-}
-
-void
-cogl2_path_round_rectangle (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2,
- float radius,
- float arc_step)
-{
- float inner_width = x_2 - x_1 - radius * 2;
- float inner_height = y_2 - y_1 - radius * 2;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- cogl2_path_move_to (path, x_1, y_1 + radius);
- _cogl_path_rel_arc (path,
- radius, 0,
- radius, radius,
- 180,
- 270,
- arc_step);
-
- cogl2_path_line_to (path,
- path->data->path_pen.x + inner_width,
- path->data->path_pen.y);
- _cogl_path_rel_arc (path,
- 0, radius,
- radius, radius,
- -90,
- 0,
- arc_step);
-
- cogl2_path_line_to (path,
- path->data->path_pen.x,
- path->data->path_pen.y + inner_height);
-
- _cogl_path_rel_arc (path,
- -radius, 0,
- radius, radius,
- 0,
- 90,
- arc_step);
-
- cogl2_path_line_to (path,
- path->data->path_pen.x - inner_width,
- path->data->path_pen.y);
- _cogl_path_rel_arc (path,
- 0, -radius,
- radius, radius,
- 90,
- 180,
- arc_step);
-
- cogl2_path_close (path);
-}
-
-static void
-_cogl_path_bezier3_sub (CoglPath *path,
- CoglBezCubic *cubic)
-{
- CoglBezCubic cubics[_COGL_MAX_BEZ_RECURSE_DEPTH];
- CoglBezCubic *cleft;
- CoglBezCubic *cright;
- CoglBezCubic *c;
- floatVec2 dif1;
- floatVec2 dif2;
- floatVec2 mm;
- floatVec2 c1;
- floatVec2 c2;
- floatVec2 c3;
- floatVec2 c4;
- floatVec2 c5;
- int cindex;
-
- /* Put first curve on stack */
- cubics[0] = *cubic;
- cindex = 0;
-
- while (cindex >= 0)
- {
- c = &cubics[cindex];
-
-
- /* Calculate distance of control points from their
- * counterparts on the line between end points */
- dif1.x = (c->p2.x * 3) - (c->p1.x * 2) - c->p4.x;
- dif1.y = (c->p2.y * 3) - (c->p1.y * 2) - c->p4.y;
- dif2.x = (c->p3.x * 3) - (c->p4.x * 2) - c->p1.x;
- dif2.y = (c->p3.y * 3) - (c->p4.y * 2) - c->p1.y;
-
- if (dif1.x < 0)
- dif1.x = -dif1.x;
- if (dif1.y < 0)
- dif1.y = -dif1.y;
- if (dif2.x < 0)
- dif2.x = -dif2.x;
- if (dif2.y < 0)
- dif2.y = -dif2.y;
-
-
- /* Pick the greatest of two distances */
- if (dif1.x < dif2.x) dif1.x = dif2.x;
- if (dif1.y < dif2.y) dif1.y = dif2.y;
-
- /* Cancel if the curve is flat enough */
- if (dif1.x + dif1.y <= 1.0 ||
- cindex == _COGL_MAX_BEZ_RECURSE_DEPTH-1)
- {
- /* Add subdivision point (skip last) */
- if (cindex == 0)
- return;
-
- _cogl_path_add_node (path, FALSE, c->p4.x, c->p4.y);
-
- --cindex;
-
- continue;
- }
-
- /* Left recursion goes on top of stack! */
- cright = c; cleft = &cubics[++cindex];
-
- /* Subdivide into 2 sub-curves */
- c1.x = ((c->p1.x + c->p2.x) / 2);
- c1.y = ((c->p1.y + c->p2.y) / 2);
- mm.x = ((c->p2.x + c->p3.x) / 2);
- mm.y = ((c->p2.y + c->p3.y) / 2);
- c5.x = ((c->p3.x + c->p4.x) / 2);
- c5.y = ((c->p3.y + c->p4.y) / 2);
-
- c2.x = ((c1.x + mm.x) / 2);
- c2.y = ((c1.y + mm.y) / 2);
- c4.x = ((mm.x + c5.x) / 2);
- c4.y = ((mm.y + c5.y) / 2);
-
- c3.x = ((c2.x + c4.x) / 2);
- c3.y = ((c2.y + c4.y) / 2);
-
- /* Add left recursion to stack */
- cleft->p1 = c->p1;
- cleft->p2 = c1;
- cleft->p3 = c2;
- cleft->p4 = c3;
-
- /* Add right recursion to stack */
- cright->p1 = c3;
- cright->p2 = c4;
- cright->p3 = c5;
- cright->p4 = c->p4;
- }
-}
-
-void
-cogl2_path_curve_to (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2,
- float x_3,
- float y_3)
-{
- CoglBezCubic cubic;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- /* Prepare cubic curve */
- cubic.p1 = path->data->path_pen;
- cubic.p2.x = x_1;
- cubic.p2.y = y_1;
- cubic.p3.x = x_2;
- cubic.p3.y = y_2;
- cubic.p4.x = x_3;
- cubic.p4.y = y_3;
-
- /* Run subdivision */
- _cogl_path_bezier3_sub (path, &cubic);
-
- /* Add last point */
- _cogl_path_add_node (path, FALSE, cubic.p4.x, cubic.p4.y);
- path->data->path_pen = cubic.p4;
-}
-
-void
-cogl2_path_rel_curve_to (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2,
- float x_3,
- float y_3)
-{
- CoglPathData *data;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- data = path->data;
-
- cogl2_path_curve_to (path,
- data->path_pen.x + x_1,
- data->path_pen.y + y_1,
- data->path_pen.x + x_2,
- data->path_pen.y + y_2,
- data->path_pen.x + x_3,
- data->path_pen.y + y_3);
-}
-
-CoglPath *
-cogl2_path_new (void)
-{
- CoglPath *path;
- CoglPathData *data;
-
- path = g_slice_new (CoglPath);
- data = path->data = g_slice_new (CoglPathData);
-
- data->ref_count = 1;
- data->fill_rule = COGL_PATH_FILL_RULE_EVEN_ODD;
- data->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
- data->last_path = 0;
- data->fill_attribute_buffer = NULL;
- data->stroke_attribute_buffer = NULL;
- data->is_rectangle = FALSE;
-
- return _cogl_path_object_new (path);
-}
-
-CoglPath *
-cogl_path_copy (CoglPath *old_path)
-{
- CoglPath *new_path;
-
- _COGL_RETURN_VAL_IF_FAIL (cogl_is_path (old_path), NULL);
-
- new_path = g_slice_new (CoglPath);
- new_path->data = old_path->data;
- new_path->data->ref_count++;
-
- return _cogl_path_object_new (new_path);
-}
-
-static void
-_cogl_path_free (CoglPath *path)
-{
- _cogl_path_data_unref (path->data);
- g_slice_free (CoglPath, path);
-}
-
-/* If second order beziers were needed the following code could
- * be re-enabled:
- */
-#if 0
-
-static void
-_cogl_path_bezier2_sub (CoglPath *path,
- CoglBezQuad *quad)
-{
- CoglBezQuad quads[_COGL_MAX_BEZ_RECURSE_DEPTH];
- CoglBezQuad *qleft;
- CoglBezQuad *qright;
- CoglBezQuad *q;
- floatVec2 mid;
- floatVec2 dif;
- floatVec2 c1;
- floatVec2 c2;
- floatVec2 c3;
- int qindex;
-
- /* Put first curve on stack */
- quads[0] = *quad;
- qindex = 0;
-
- /* While stack is not empty */
- while (qindex >= 0)
- {
-
- q = &quads[qindex];
-
- /* Calculate distance of control point from its
- * counterpart on the line between end points */
- mid.x = ((q->p1.x + q->p3.x) / 2);
- mid.y = ((q->p1.y + q->p3.y) / 2);
- dif.x = (q->p2.x - mid.x);
- dif.y = (q->p2.y - mid.y);
- if (dif.x < 0) dif.x = -dif.x;
- if (dif.y < 0) dif.y = -dif.y;
-
- /* Cancel if the curve is flat enough */
- if (dif.x + dif.y <= 1.0 ||
- qindex == _COGL_MAX_BEZ_RECURSE_DEPTH - 1)
- {
- /* Add subdivision point (skip last) */
- if (qindex == 0) return;
- _cogl_path_add_node (path, FALSE, q->p3.x, q->p3.y);
- --qindex; continue;
- }
-
- /* Left recursion goes on top of stack! */
- qright = q; qleft = &quads[++qindex];
-
- /* Subdivide into 2 sub-curves */
- c1.x = ((q->p1.x + q->p2.x) / 2);
- c1.y = ((q->p1.y + q->p2.y) / 2);
- c3.x = ((q->p2.x + q->p3.x) / 2);
- c3.y = ((q->p2.y + q->p3.y) / 2);
- c2.x = ((c1.x + c3.x) / 2);
- c2.y = ((c1.y + c3.y) / 2);
-
- /* Add left recursion onto stack */
- qleft->p1 = q->p1;
- qleft->p2 = c1;
- qleft->p3 = c2;
-
- /* Add right recursion onto stack */
- qright->p1 = c2;
- qright->p2 = c3;
- qright->p3 = q->p3;
- }
-}
-
-void
-cogl_path_curve2_to (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2)
-{
- CoglBezQuad quad;
-
- /* Prepare quadratic curve */
- quad.p1 = path->data->path_pen;
- quad.p2.x = x_1;
- quad.p2.y = y_1;
- quad.p3.x = x_2;
- quad.p3.y = y_2;
-
- /* Run subdivision */
- _cogl_path_bezier2_sub (&quad);
-
- /* Add last point */
- _cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y);
- path->data->path_pen = quad.p3;
-}
-
-void
-cogl_rel_curve2_to (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2)
-{
- CoglPathData *data;
-
- _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
- data = path->data;
-
- cogl_path_curve2_to (data->path_pen.x + x_1,
- data->path_pen.y + y_1,
- data->path_pen.x + x_2,
- data->path_pen.y + y_2);
-}
-
-#endif
-
-typedef struct _CoglPathTesselator CoglPathTesselator;
-typedef struct _CoglPathTesselatorVertex CoglPathTesselatorVertex;
-
-struct _CoglPathTesselator
-{
- GLUtesselator *glu_tess;
- GLenum primitive_type;
- int vertex_number;
- /* Array of CoglPathTesselatorVertex. This needs to grow when the
- combine callback is called */
- GArray *vertices;
- /* Array of integers for the indices into the vertices array. Each
- element will either be guint8, guint16 or guint32 depending on
- the number of vertices */
- GArray *indices;
- CoglIndicesType indices_type;
- /* Indices used to split fans and strips */
- int index_a, index_b;
-};
-
-struct _CoglPathTesselatorVertex
-{
- float x, y, s, t;
-};
-
-static void
-_cogl_path_tesselator_begin (GLenum type,
- CoglPathTesselator *tess)
-{
- g_assert (type == GL_TRIANGLES ||
- type == GL_TRIANGLE_FAN ||
- type == GL_TRIANGLE_STRIP);
-
- tess->primitive_type = type;
- tess->vertex_number = 0;
-}
-
-static CoglIndicesType
-_cogl_path_tesselator_get_indices_type_for_size (int n_vertices)
-{
- if (n_vertices <= 256)
- return COGL_INDICES_TYPE_UNSIGNED_BYTE;
- else if (n_vertices <= 65536)
- return COGL_INDICES_TYPE_UNSIGNED_SHORT;
- else
- return COGL_INDICES_TYPE_UNSIGNED_INT;
-}
-
-static void
-_cogl_path_tesselator_allocate_indices_array (CoglPathTesselator *tess)
-{
- switch (tess->indices_type)
- {
- case COGL_INDICES_TYPE_UNSIGNED_BYTE:
- tess->indices = g_array_new (FALSE, FALSE, sizeof (guint8));
- break;
-
- case COGL_INDICES_TYPE_UNSIGNED_SHORT:
- tess->indices = g_array_new (FALSE, FALSE, sizeof (guint16));
- break;
-
- case COGL_INDICES_TYPE_UNSIGNED_INT:
- tess->indices = g_array_new (FALSE, FALSE, sizeof (guint32));
- break;
- }
-}
-
-static void
-_cogl_path_tesselator_add_index (CoglPathTesselator *tess, int vertex_index)
-{
- switch (tess->indices_type)
- {
- case COGL_INDICES_TYPE_UNSIGNED_BYTE:
- {
- guint8 val = vertex_index;
- g_array_append_val (tess->indices, val);
- }
- break;
-
- case COGL_INDICES_TYPE_UNSIGNED_SHORT:
- {
- guint16 val = vertex_index;
- g_array_append_val (tess->indices, val);
- }
- break;
-
- case COGL_INDICES_TYPE_UNSIGNED_INT:
- {
- guint32 val = vertex_index;
- g_array_append_val (tess->indices, val);
- }
- break;
- }
-}
-
-static void
-_cogl_path_tesselator_vertex (void *vertex_data,
- CoglPathTesselator *tess)
-{
- int vertex_index;
-
- vertex_index = GPOINTER_TO_INT (vertex_data);
-
- /* This tries to convert all of the primitives into GL_TRIANGLES
- with indices to share vertices */
- switch (tess->primitive_type)
- {
- case GL_TRIANGLES:
- /* Directly use the vertex */
- _cogl_path_tesselator_add_index (tess, vertex_index);
- break;
-
- case GL_TRIANGLE_FAN:
- if (tess->vertex_number == 0)
- tess->index_a = vertex_index;
- else if (tess->vertex_number == 1)
- tess->index_b = vertex_index;
- else
- {
- /* Create a triangle with the first vertex, the previous
- vertex and this vertex */
- _cogl_path_tesselator_add_index (tess, tess->index_a);
- _cogl_path_tesselator_add_index (tess, tess->index_b);
- _cogl_path_tesselator_add_index (tess, vertex_index);
- /* Next time we will use this vertex as the previous
- vertex */
- tess->index_b = vertex_index;
- }
- break;
-
- case GL_TRIANGLE_STRIP:
- if (tess->vertex_number == 0)
- tess->index_a = vertex_index;
- else if (tess->vertex_number == 1)
- tess->index_b = vertex_index;
- else
- {
- _cogl_path_tesselator_add_index (tess, tess->index_a);
- _cogl_path_tesselator_add_index (tess, tess->index_b);
- _cogl_path_tesselator_add_index (tess, vertex_index);
- if (tess->vertex_number & 1)
- tess->index_b = vertex_index;
- else
- tess->index_a = vertex_index;
- }
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- tess->vertex_number++;
-}
-
-static void
-_cogl_path_tesselator_end (CoglPathTesselator *tess)
-{
- tess->primitive_type = GL_FALSE;
-}
-
-static void
-_cogl_path_tesselator_combine (double coords[3],
- void *vertex_data[4],
- float weight[4],
- void **out_data,
- CoglPathTesselator *tess)
-{
- CoglPathTesselatorVertex *vertex;
- CoglIndicesType new_indices_type;
- int i;
-
- /* Add a new vertex to the array */
- g_array_set_size (tess->vertices, tess->vertices->len + 1);
- vertex = &g_array_index (tess->vertices,
- CoglPathTesselatorVertex,
- tess->vertices->len - 1);
- /* The data is just the index to the vertex */
- *out_data = GINT_TO_POINTER (tess->vertices->len - 1);
- /* Set the coordinates of the new vertex */
- vertex->x = coords[0];
- vertex->y = coords[1];
- /* Generate the texture coordinates as the weighted average of the
- four incoming coordinates */
- vertex->s = 0.0f;
- vertex->t = 0.0f;
- for (i = 0; i < 4; i++)
- {
- CoglPathTesselatorVertex *old_vertex =
- &g_array_index (tess->vertices, CoglPathTesselatorVertex,
- GPOINTER_TO_INT (vertex_data[i]));
- vertex->s += old_vertex->s * weight[i];
- vertex->t += old_vertex->t * weight[i];
- }
-
- /* Check if we've reached the limit for the data type of our indices */
- new_indices_type =
- _cogl_path_tesselator_get_indices_type_for_size (tess->vertices->len);
- if (new_indices_type != tess->indices_type)
- {
- CoglIndicesType old_indices_type = new_indices_type;
- GArray *old_vertices = tess->indices;
-
- /* Copy the indices to an array of the new type */
- tess->indices_type = new_indices_type;
- _cogl_path_tesselator_allocate_indices_array (tess);
-
- switch (old_indices_type)
- {
- case COGL_INDICES_TYPE_UNSIGNED_BYTE:
- for (i = 0; i < old_vertices->len; i++)
- _cogl_path_tesselator_add_index (tess,
- g_array_index (old_vertices,
- guint8, i));
- break;
-
- case COGL_INDICES_TYPE_UNSIGNED_SHORT:
- for (i = 0; i < old_vertices->len; i++)
- _cogl_path_tesselator_add_index (tess,
- g_array_index (old_vertices,
- guint16, i));
- break;
-
- case COGL_INDICES_TYPE_UNSIGNED_INT:
- for (i = 0; i < old_vertices->len; i++)
- _cogl_path_tesselator_add_index (tess,
- g_array_index (old_vertices,
- guint32, i));
- break;
- }
-
- g_array_free (old_vertices, TRUE);
- }
-}
-
-static void
-_cogl_path_build_fill_attribute_buffer (CoglPath *path)
-{
- CoglPathTesselator tess;
- unsigned int path_start = 0;
- CoglPathData *data = path->data;
- int i;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- /* If we've already got a vbo then we don't need to do anything */
- if (data->fill_attribute_buffer)
- return;
-
- tess.primitive_type = FALSE;
-
- /* Generate a vertex for each point on the path */
- tess.vertices = g_array_new (FALSE, FALSE, sizeof (CoglPathTesselatorVertex));
- g_array_set_size (tess.vertices, data->path_nodes->len);
- for (i = 0; i < data->path_nodes->len; i++)
- {
- CoglPathNode *node =
- &g_array_index (data->path_nodes, CoglPathNode, i);
- CoglPathTesselatorVertex *vertex =
- &g_array_index (tess.vertices, CoglPathTesselatorVertex, i);
-
- vertex->x = node->x;
- vertex->y = node->y;
-
- /* Add texture coordinates so that a texture would be drawn to
- fit the bounding box of the path and then cropped by the
- path */
- if (data->path_nodes_min.x == data->path_nodes_max.x)
- vertex->s = 0.0f;
- else
- vertex->s = ((node->x - data->path_nodes_min.x)
- / (data->path_nodes_max.x - data->path_nodes_min.x));
- if (data->path_nodes_min.y == data->path_nodes_max.y)
- vertex->t = 0.0f;
- else
- vertex->t = ((node->y - data->path_nodes_min.y)
- / (data->path_nodes_max.y - data->path_nodes_min.y));
- }
-
- tess.indices_type =
- _cogl_path_tesselator_get_indices_type_for_size (data->path_nodes->len);
- _cogl_path_tesselator_allocate_indices_array (&tess);
-
- tess.glu_tess = gluNewTess ();
-
- if (data->fill_rule == COGL_PATH_FILL_RULE_EVEN_ODD)
- gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE,
- GLU_TESS_WINDING_ODD);
- else
- gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE,
- GLU_TESS_WINDING_NONZERO);
-
- /* All vertices are on the xy-plane */
- gluTessNormal (tess.glu_tess, 0.0, 0.0, 1.0);
-
- gluTessCallback (tess.glu_tess, GLU_TESS_BEGIN_DATA,
- _cogl_path_tesselator_begin);
- gluTessCallback (tess.glu_tess, GLU_TESS_VERTEX_DATA,
- _cogl_path_tesselator_vertex);
- gluTessCallback (tess.glu_tess, GLU_TESS_END_DATA,
- _cogl_path_tesselator_end);
- gluTessCallback (tess.glu_tess, GLU_TESS_COMBINE_DATA,
- _cogl_path_tesselator_combine);
-
- gluTessBeginPolygon (tess.glu_tess, &tess);
-
- while (path_start < data->path_nodes->len)
- {
- CoglPathNode *node =
- &g_array_index (data->path_nodes, CoglPathNode, path_start);
-
- gluTessBeginContour (tess.glu_tess);
-
- for (i = 0; i < node->path_size; i++)
- {
- double vertex[3] = { node[i].x, node[i].y, 0.0 };
- gluTessVertex (tess.glu_tess, vertex,
- GINT_TO_POINTER (i + path_start));
- }
-
- gluTessEndContour (tess.glu_tess);
-
- path_start += node->path_size;
- }
-
- gluTessEndPolygon (tess.glu_tess);
-
- gluDeleteTess (tess.glu_tess);
-
- data->fill_attribute_buffer =
- cogl_attribute_buffer_new (ctx,
- sizeof (CoglPathTesselatorVertex) *
- tess.vertices->len,
- tess.vertices->data);
- g_array_free (tess.vertices, TRUE);
-
- data->fill_attributes[0] =
- cogl_attribute_new (data->fill_attribute_buffer,
- "cogl_position_in",
- sizeof (CoglPathTesselatorVertex),
- G_STRUCT_OFFSET (CoglPathTesselatorVertex, x),
- 2, /* n_components */
- COGL_ATTRIBUTE_TYPE_FLOAT);
- data->fill_attributes[1] =
- cogl_attribute_new (data->fill_attribute_buffer,
- "cogl_tex_coord0_in",
- sizeof (CoglPathTesselatorVertex),
- G_STRUCT_OFFSET (CoglPathTesselatorVertex, s),
- 2, /* n_components */
- COGL_ATTRIBUTE_TYPE_FLOAT);
-
- data->fill_vbo_indices = cogl_indices_new (ctx,
- tess.indices_type,
- tess.indices->data,
- tess.indices->len);
- data->fill_vbo_n_indices = tess.indices->len;
- g_array_free (tess.indices, TRUE);
-}
-
-static void
-_cogl_path_build_stroke_attribute_buffer (CoglPath *path)
-{
- CoglPathData *data = path->data;
- CoglBuffer *buffer;
- unsigned int n_attributes = 0;
- unsigned int path_start;
- CoglPathNode *node;
- floatVec2 *buffer_p;
- unsigned int i;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- /* If we've already got a cached vbo then we don't need to do anything */
- if (data->stroke_attribute_buffer)
- return;
-
- data->stroke_attribute_buffer =
- cogl_attribute_buffer_new (ctx, data->path_nodes->len * sizeof (floatVec2),
- NULL);
-
- buffer = COGL_BUFFER (data->stroke_attribute_buffer);
- buffer_p = _cogl_buffer_map_for_fill_or_fallback (buffer);
-
- /* Copy the vertices in and count the number of sub paths. Each sub
- path will form a separate attribute so we can paint the disjoint
- line strips */
- for (path_start = 0;
- path_start < data->path_nodes->len;
- path_start += node->path_size)
- {
- node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
-
- for (i = 0; i < node->path_size; i++)
- {
- buffer_p[path_start + i].x = node[i].x;
- buffer_p[path_start + i].y = node[i].y;
- }
-
- n_attributes++;
- }
-
- _cogl_buffer_unmap_for_fill_or_fallback (buffer);
-
- data->stroke_attributes = g_new (CoglAttribute *, n_attributes);
-
- /* Now we can loop the sub paths again to create the attributes */
- for (i = 0, path_start = 0;
- path_start < data->path_nodes->len;
- i++, path_start += node->path_size)
- {
- node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
-
- data->stroke_attributes[i] =
- cogl_attribute_new (data->stroke_attribute_buffer,
- "cogl_position_in",
- sizeof (floatVec2),
- path_start * sizeof (floatVec2),
- 2, /* n_components */
- COGL_ATTRIBUTE_TYPE_FLOAT);
- }
-
- data->stroke_n_attributes = n_attributes;
-}
diff --git a/cogl/cogl2-path.h b/cogl/cogl2-path.h
deleted file mode 100644
index f702c4a..0000000
--- a/cogl/cogl2-path.h
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * Cogl
- *
- * An object oriented GL/GLES Abstraction/Utility Layer
- *
- * Copyright (C) 2008,2009 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 <http://www.gnu.org/licenses/>.
- *
- *
- */
-
-#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
-#error "Only <cogl/cogl.h> can be included directly."
-#endif
-
-#ifndef __COGL2_PATH_H__
-#define __COGL2_PATH_H__
-
-#include <cogl/cogl-types.h>
-
-G_BEGIN_DECLS
-
-/**
- * SECTION:cogl-paths
- * @short_description: Functions for constructing and drawing 2D paths.
- *
- * There are two levels on which drawing with cogl-paths can be used.
- * The highest level functions construct various simple primitive
- * shapes to be either filled or stroked. Using a lower-level set of
- * functions more complex and arbitrary paths can be constructed by
- * concatenating straight line, bezier curve and arc segments.
- *
- * When constructing arbitrary paths, the current pen location is
- * initialized using the move_to command. The subsequent path segments
- * implicitly use the last pen location as their first vertex and move
- * the pen location to the last vertex they produce at the end. Also
- * there are special versions of functions that allow specifying the
- * vertices of the path segments relative to the last pen location
- * rather then in the absolute coordinates.
- */
-
-typedef struct _CoglPath CoglPath;
-
-#define COGL_PATH(obj) ((CoglPath *)(obj))
-
-#define cogl_path_new cogl2_path_new
-/**
- * cogl_path_new:
- *
- * Creates a new, empty path object. The default fill rule is
- * %COGL_PATH_FILL_RULE_EVEN_ODD.
- *
- * Return value: A pointer to a newly allocated #CoglPath, which can
- * be freed using cogl_object_unref().
- *
- * Since: 2.0
- */
-CoglPath *
-cogl_path_new (void);
-
-/**
- * cogl_path_copy:
- * @path: A #CoglPath object
- *
- * Returns a new copy of the path in @path. The new path has a
- * reference count of 1 so you should unref it with
- * cogl_object_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 @path.
- *
- * Since: 2.0
- */
-CoglPath *
-cogl_path_copy (CoglPath *path);
-
-/**
- * cogl_is_path:
- * @object: A #CoglObject
- *
- * Gets whether the given object references an existing path object.
- *
- * Return value: %TRUE if the object references a #CoglPath,
- * %FALSE otherwise.
- *
- * Since: 2.0
- */
-gboolean
-cogl_is_path (void *object);
-
-#define cogl_path_move_to cogl2_path_move_to
-/**
- * cogl_path_move_to:
- * @x: X coordinate of the pen location to move to.
- * @y: Y coordinate of the pen location to move to.
- *
- * Moves the pen to the given location. If there is an existing path
- * this will start a new disjoint subpath.
- *
- * Since: 2.0
- */
-void
-cogl_path_move_to (CoglPath *path,
- float x,
- float y);
-
-#define cogl_path_rel_move_to cogl2_path_rel_move_to
-/**
- * cogl_path_rel_move_to:
- * @x: X offset from the current pen location to move the pen to.
- * @y: Y offset from the current pen location to move the pen to.
- *
- * Moves the pen to the given offset relative to the current pen
- * location. If there is an existing path this will start a new
- * disjoint subpath.
- *
- * Since: 2.0
- */
-void
-cogl_path_rel_move_to (CoglPath *path,
- float x,
- float y);
-
-#define cogl_path_line_to cogl2_path_line_to
-/**
- * cogl_path_line_to:
- * @x: X coordinate of the end line vertex
- * @y: Y coordinate of the end line vertex
- *
- * Adds a straight line segment to the current path that ends at the
- * given coordinates.
- *
- * Since: 2.0
- */
-void
-cogl_path_line_to (CoglPath *path,
- float x,
- float y);
-
-#define cogl_path_rel_line_to cogl2_path_rel_line_to
-/**
- * cogl_path_rel_line_to:
- * @x: X offset from the current pen location of the end line vertex
- * @y: Y offset from the current pen location of the end line vertex
- *
- * Adds a straight line segment to the current path that ends at the
- * given coordinates relative to the current pen location.
- *
- * Since: 2.0
- */
-void
-cogl_path_rel_line_to (CoglPath *path,
- float x,
- float y);
-
-#define cogl_path_arc cogl2_path_arc
-/**
- * cogl_path_arc:
- * @center_x: X coordinate of the elliptical arc center
- * @center_y: Y coordinate of the elliptical arc center
- * @radius_x: X radius of the elliptical arc
- * @radius_y: Y radius of the elliptical arc
- * @angle_1: Angle in degrees at which the arc begin
- * @angle_2: Angle in degrees at which the arc ends
- *
- * Adds an elliptical arc segment to the current path. A straight line
- * segment will link the current pen location with the first vertex
- * of the arc. If you perform a move_to to the arcs start just before
- * drawing it you create a free standing arc.
- *
- * The angles are measured in degrees where 0° is in the direction of
- * the positive X axis and 90° is in the direction of the positive Y
- * axis. The angle of the arc begins at @angle_1 and heads towards
- * @angle_2 (so if @angle_2 is less than @angle_1 it will decrease,
- * otherwise it will increase).
- *
- * Since: 2.0
- */
-void
-cogl_path_arc (CoglPath *path,
- float center_x,
- float center_y,
- float radius_x,
- float radius_y,
- float angle_1,
- float angle_2);
-
-#define cogl_path_curve_to cogl2_path_curve_to
-/**
- * cogl_path_curve_to:
- * @x_1: X coordinate of the second bezier control point
- * @y_1: Y coordinate of the second bezier control point
- * @x_2: X coordinate of the third bezier control point
- * @y_2: Y coordinate of the third bezier control point
- * @x_3: X coordinate of the fourth bezier control point
- * @y_3: Y coordinate of the fourth bezier control point
- *
- * Adds a cubic bezier curve segment to the current path with the given
- * second, third and fourth control points and using current pen location
- * as the first control point.
- *
- * Since: 2.0
- */
-void
-cogl_path_curve_to (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2,
- float x_3,
- float y_3);
-
-#define cogl_path_rel_curve_to cogl2_path_rel_curve_to
-/**
- * cogl_path_rel_curve_to:
- * @x_1: X coordinate of the second bezier control point
- * @y_1: Y coordinate of the second bezier control point
- * @x_2: X coordinate of the third bezier control point
- * @y_2: Y coordinate of the third bezier control point
- * @x_3: X coordinate of the fourth bezier control point
- * @y_3: Y coordinate of the fourth bezier control point
- *
- * Adds a cubic bezier curve segment to the current path with the given
- * second, third and fourth control points and using current pen location
- * as the first control point. The given coordinates are relative to the
- * current pen location.
- *
- * Since: 2.0
- */
-void
-cogl_path_rel_curve_to (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2,
- float x_3,
- float y_3);
-
-#define cogl_path_close cogl2_path_close
-/**
- * cogl_path_close:
- *
- * Closes the path being constructed by adding a straight line segment
- * to it that ends at the first vertex of the path.
- *
- * Since: 2.0
- */
-void
-cogl_path_close (CoglPath *path);
-
-#define cogl_path_line cogl2_path_line
-/**
- * cogl_path_line:
- * @x_1: X coordinate of the start line vertex
- * @y_1: Y coordinate of the start line vertex
- * @x_2: X coordinate of the end line vertex
- * @y_2: Y coordinate of the end line vertex
- *
- * Constructs a straight line shape starting and ending at the given
- * coordinates. If there is an existing path this will start a new
- * disjoint sub-path.
- *
- * Since: 2.0
- */
-void
-cogl_path_line (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2);
-
-#define cogl_path_polyline cogl2_path_polyline
-/**
- * cogl_path_polyline:
- * @coords: (in) (array) (transfer none): A pointer to the first element of an
- * array of fixed-point values that specify the vertex coordinates.
- * @num_points: The total number of vertices.
- *
- * Constructs a series of straight line segments, starting from the
- * first given vertex coordinate. If there is an existing path this
- * will start a new disjoint sub-path. Each subsequent segment starts
- * where the previous one ended and ends at the next given vertex
- * coordinate.
- *
- * The coords array must contain 2 * num_points values. The first value
- * represents the X coordinate of the first vertex, the second value
- * represents the Y coordinate of the first vertex, continuing in the same
- * fashion for the rest of the vertices. (num_points - 1) segments will
- * be constructed.
- *
- * Since: 2.0
- */
-void
-cogl_path_polyline (CoglPath *path,
- const float *coords,
- int num_points);
-
-#define cogl_path_polygon cogl2_path_polygon
-/**
- * cogl_path_polygon:
- * @coords: (in) (array) (transfer none): A pointer to the first element of
- * an array of fixed-point values that specify the vertex coordinates.
- * @num_points: The total number of vertices.
- *
- * Constructs a polygonal shape of the given number of vertices. If
- * there is an existing path this will start a new disjoint sub-path.
- *
- * The coords array must contain 2 * num_points values. The first value
- * represents the X coordinate of the first vertex, the second value
- * represents the Y coordinate of the first vertex, continuing in the same
- * fashion for the rest of the vertices.
- *
- * Since: 2.0
- */
-void
-cogl_path_polygon (CoglPath *path,
- const float *coords,
- int num_points);
-
-#define cogl_path_rectangle cogl2_path_rectangle
-/**
- * cogl_path_rectangle:
- * @x_1: X coordinate of the top-left corner.
- * @y_1: Y coordinate of the top-left corner.
- * @x_2: X coordinate of the bottom-right corner.
- * @y_2: Y coordinate of the bottom-right corner.
- *
- * Constructs a rectangular shape at the given coordinates. If there
- * is an existing path this will start a new disjoint sub-path.
- *
- * Since: 2.0
- */
-void
-cogl_path_rectangle (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2);
-
-#define cogl_path_ellipse cogl2_path_ellipse
-/**
- * cogl_path_ellipse:
- * @center_x: X coordinate of the ellipse center
- * @center_y: Y coordinate of the ellipse center
- * @radius_x: X radius of the ellipse
- * @radius_y: Y radius of the ellipse
- *
- * Constructs an ellipse shape. If there is an existing path this will
- * start a new disjoint sub-path.
- *
- * Since: 2.0
- */
-void
-cogl_path_ellipse (CoglPath *path,
- float center_x,
- float center_y,
- float radius_x,
- float radius_y);
-
-#define cogl_path_round_rectangle cogl2_path_round_rectangle
-/**
- * cogl_path_round_rectangle:
- * @x_1: X coordinate of the top-left corner.
- * @y_1: Y coordinate of the top-left corner.
- * @x_2: X coordinate of the bottom-right corner.
- * @y_2: Y coordinate of the bottom-right corner.
- * @radius: Radius of the corner arcs.
- * @arc_step: Angle increment resolution for subdivision of
- * the corner arcs.
- *
- * Constructs a rectangular shape with rounded corners. If there is an
- * existing path this will start a new disjoint sub-path.
- *
- * Since: 2.0
- */
-void
-cogl_path_round_rectangle (CoglPath *path,
- float x_1,
- float y_1,
- float x_2,
- float y_2,
- float radius,
- float arc_step);
-
-/**
- * CoglPathFillRule:
- * @COGL_PATH_FILL_RULE_NON_ZERO: Each time the line crosses an edge of
- * the path from left to right one is added to a counter and each time
- * it crosses from right to left the counter is decremented. If the
- * counter is non-zero then the point will be filled. See <xref
- * linkend="fill-rule-non-zero"/>.
- * @COGL_PATH_FILL_RULE_EVEN_ODD: If the line crosses an edge of the
- * path an odd number of times then the point will filled, otherwise
- * it won't. See <xref linkend="fill-rule-even-odd"/>.
- *
- * #CoglPathFillRule is used to determine how a path is filled. There
- * are two options - 'non-zero' and 'even-odd'. To work out whether any
- * point will be filled imagine drawing an infinetely long line in any
- * direction from that point. The number of times and the direction
- * that the edges of the path crosses this line determines whether the
- * line is filled as described below. Any open sub paths are treated
- * as if there was an extra line joining the first point and the last
- * point.
- *
- * The default fill rule is %COGL_PATH_FILL_RULE_EVEN_ODD. The fill
- * rule is attached to the current path so preserving a path with
- * cogl_get_path() also preserves the fill rule. Calling
- * cogl_path_new() resets the current fill rule to the default.
- *
- * <figure id="fill-rule-non-zero">
- * <title>Example of filling various paths using the non-zero rule</title>
- * <graphic fileref="fill-rule-non-zero.png" format="PNG"/>
- * </figure>
- *
- * <figure id="fill-rule-even-odd">
- * <title>Example of filling various paths using the even-odd rule</title>
- * <graphic fileref="fill-rule-even-odd.png" format="PNG"/>
- * </figure>
- *
- * Since: 1.4
- */
-typedef enum {
- COGL_PATH_FILL_RULE_NON_ZERO,
- COGL_PATH_FILL_RULE_EVEN_ODD
-} CoglPathFillRule;
-
-#define cogl_path_set_fill_rule cogl2_path_set_fill_rule
-/**
- * cogl_path_set_fill_rule:
- * @fill_rule: The new fill rule.
- *
- * Sets the fill rule of the current path to @fill_rule. This will
- * affect how the path is filled when cogl_path_fill() is later
- * called. Note that the fill rule state is attached to the path so
- * calling cogl_get_path() will preserve the fill rule and calling
- * cogl_path_new() will reset the fill rule back to the default.
- *
- * Since: 2.0
- */
-void
-cogl_path_set_fill_rule (CoglPath *path, CoglPathFillRule fill_rule);
-
-#define cogl_path_get_fill_rule cogl2_path_get_fill_rule
-/**
- * cogl_path_get_fill_rule:
- *
- * Retrieves the fill rule set using cogl_path_set_fill_rule().
- *
- * Return value: the fill rule that is used for the current path.
- *
- * Since: 2.0
- */
-CoglPathFillRule
-cogl_path_get_fill_rule (CoglPath *path);
-
-#define cogl_path_fill cogl2_path_fill
-/**
- * cogl_path_fill:
- *
- * Fills the interior of the constructed shape using the current
- * drawing color.
- *
- * The interior of the shape is determined using the fill rule of the
- * path. See %CoglPathFillRule for details.
- *
- * <note>The result of referencing sliced textures in your current
- * pipeline when filling a path are undefined. You should pass
- * the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will
- * use while filling a path.</note>
- *
- * Since: 2.0
- */
-void
-cogl_path_fill (CoglPath *path);
-
-#define cogl_path_stroke cogl2_path_stroke
-/**
- * cogl_path_stroke:
- *
- * Strokes the constructed shape using the current drawing color and a
- * width of 1 pixel (regardless of the current transformation
- * matrix).
- *
- * Since: 2.0
- */
-void
-cogl_path_stroke (CoglPath *path);
-
-G_END_DECLS
-
-#endif /* __COGL2_PATH_H__ */
-
--
1.7.3.16.g9464b
More information about the Cogl
mailing list