app/vectors/gimpvectors.[ch] app/vectors/gimpstroke.[ch] Implement

2008-05-12  Simon Budig  <simon@gimp.org>

	* app/vectors/gimpvectors.[ch]
	* app/vectors/gimpstroke.[ch]
	* app/vectors/gimpbezierstroke.c: Implement functionality to
	get a bezier description a la moveto/curveto/closepath.

	* app/vectors/vectors-types.h: implement an evil hack to avoid
	the inclusion of cairo.h in most C files...

	* app/vectors/Makefile.am: link against cairo

	* app/widgets/gimpviewrenderervectors.c: use the new functionality
	for preview rendering.


svn path=/trunk/; revision=25645
This commit is contained in:
Simon Budig 2008-05-12 21:47:07 +00:00 committed by Simon Budig
parent 7f2d708819
commit 80039486aa
9 changed files with 176 additions and 60 deletions

View File

@ -1,3 +1,18 @@
2008-05-12 Simon Budig <simon@gimp.org>
* app/vectors/gimpvectors.[ch]
* app/vectors/gimpstroke.[ch]
* app/vectors/gimpbezierstroke.c: Implement functionality to
get a bezier description a la moveto/curveto/closepath.
* app/vectors/vectors-types.h: implement an evil hack to avoid
the inclusion of cairo.h in most C files...
* app/vectors/Makefile.am: link against cairo
* app/widgets/gimpviewrenderervectors.c: use the new functionality
for preview rendering.
2008-05-11 Sven Neumann <sven@gimp.org> 2008-05-11 Sven Neumann <sven@gimp.org>
* app/core/Makefile.am * app/core/Makefile.am

View File

@ -9,7 +9,7 @@ INCLUDES = \
-I$(top_builddir)/app \ -I$(top_builddir)/app \
-I$(top_srcdir)/app \ -I$(top_srcdir)/app \
$(GDK_PIXBUF_CFLAGS) \ $(GDK_PIXBUF_CFLAGS) \
$(LIBART_CFLAGS) \ $(CAIRO_CFLAGS) \
$(GLIB_CFLAGS) \ $(GLIB_CFLAGS) \
-I$(includedir) -I$(includedir)

View File

@ -22,6 +22,7 @@
#include "config.h" #include "config.h"
#include <glib-object.h> #include <glib-object.h>
#include <cairo/cairo.h>
#include "libgimpmath/gimpmath.h" #include "libgimpmath/gimpmath.h"
@ -130,6 +131,8 @@ static GArray *
gimp_bezier_stroke_interpolate (const GimpStroke *stroke, gimp_bezier_stroke_interpolate (const GimpStroke *stroke,
const gdouble precision, const gdouble precision,
gboolean *closed); gboolean *closed);
static GimpBezierDesc *
gimp_bezier_stroke_make_bezier (const GimpStroke *stroke);
static void gimp_bezier_stroke_finalize (GObject *object); static void gimp_bezier_stroke_finalize (GObject *object);
@ -185,6 +188,7 @@ gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass)
stroke_class->extend = gimp_bezier_stroke_extend; stroke_class->extend = gimp_bezier_stroke_extend;
stroke_class->connect_stroke = gimp_bezier_stroke_connect_stroke; stroke_class->connect_stroke = gimp_bezier_stroke_connect_stroke;
stroke_class->interpolate = gimp_bezier_stroke_interpolate; stroke_class->interpolate = gimp_bezier_stroke_interpolate;
stroke_class->make_bezier = gimp_bezier_stroke_make_bezier;
} }
static void static void
@ -1438,6 +1442,94 @@ gimp_bezier_stroke_anchor_convert (GimpStroke *stroke,
} }
} }
static GimpBezierDesc *
gimp_bezier_stroke_make_bezier (const GimpStroke *stroke)
{
GArray *points, *cmd_array;
GimpBezierDesc *bezdesc;
cairo_path_data_t pathdata;
gint num_cmds, i;
points = gimp_stroke_control_points_get (stroke, NULL);
g_return_val_if_fail (points && points->len % 3 == 0, NULL);
if (points->len < 3)
return NULL;
/* Moveto + (n-1) * curveto + (if closed) curveto + closepath */
num_cmds = 2 + (points->len / 3 - 1) * 4;
if (stroke->closed)
num_cmds += 1 + 4;
cmd_array = g_array_sized_new (FALSE, FALSE,
sizeof (cairo_path_data_t),
num_cmds);
pathdata.header.type = CAIRO_PATH_MOVE_TO;
pathdata.header.length = 2;
g_array_append_val (cmd_array, pathdata);
pathdata.point.x = g_array_index (points, GimpAnchor, 1).position.x;
pathdata.point.y = g_array_index (points, GimpAnchor, 1).position.y;
g_array_append_val (cmd_array, pathdata);
for (i = 2; i+2 < points->len; i += 3)
{
pathdata.header.type = CAIRO_PATH_CURVE_TO;
pathdata.header.length = 4;
g_array_append_val (cmd_array, pathdata);
pathdata.point.x = g_array_index (points, GimpAnchor, i).position.x;
pathdata.point.y = g_array_index (points, GimpAnchor, i).position.y;
g_array_append_val (cmd_array, pathdata);
pathdata.point.x = g_array_index (points, GimpAnchor, i+1).position.x;
pathdata.point.y = g_array_index (points, GimpAnchor, i+1).position.y;
g_array_append_val (cmd_array, pathdata);
pathdata.point.x = g_array_index (points, GimpAnchor, i+2).position.x;
pathdata.point.y = g_array_index (points, GimpAnchor, i+2).position.y;
g_array_append_val (cmd_array, pathdata);
}
if (stroke->closed)
{
pathdata.header.type = CAIRO_PATH_CURVE_TO;
pathdata.header.length = 4;
g_array_append_val (cmd_array, pathdata);
pathdata.point.x = g_array_index (points, GimpAnchor, i).position.x;
pathdata.point.y = g_array_index (points, GimpAnchor, i).position.y;
g_array_append_val (cmd_array, pathdata);
pathdata.point.x = g_array_index (points, GimpAnchor, 0).position.x;
pathdata.point.y = g_array_index (points, GimpAnchor, 0).position.y;
g_array_append_val (cmd_array, pathdata);
pathdata.point.x = g_array_index (points, GimpAnchor, 1).position.x;
pathdata.point.y = g_array_index (points, GimpAnchor, 1).position.y;
g_array_append_val (cmd_array, pathdata);
pathdata.header.type = CAIRO_PATH_CLOSE_PATH;
pathdata.header.length = 1;
g_array_append_val (cmd_array, pathdata);
}
if (cmd_array->len != num_cmds)
g_printerr ("miscalculated path cmd length! (%d vs. %d)\n",
cmd_array->len, num_cmds);
bezdesc = g_new (GimpBezierDesc, 1);
bezdesc->status = CAIRO_STATUS_SUCCESS;
bezdesc->data = (cairo_path_data_t *) cmd_array->data;
bezdesc->num_data = cmd_array->len;
g_array_free (points, TRUE);
g_array_free (cmd_array, FALSE);
return bezdesc;
}
static GArray * static GArray *
gimp_bezier_stroke_interpolate (const GimpStroke *stroke, gimp_bezier_stroke_interpolate (const GimpStroke *stroke,
gdouble precision, gdouble precision,

View File

@ -129,7 +129,7 @@ static GArray * gimp_stroke_real_interpolate (const GimpStroke *stroke,
gdouble precision, gdouble precision,
gboolean *closed); gboolean *closed);
static GimpStroke * gimp_stroke_real_duplicate (const GimpStroke *stroke); static GimpStroke * gimp_stroke_real_duplicate (const GimpStroke *stroke);
static GimpStroke * gimp_stroke_real_make_bezier (const GimpStroke *stroke); static GimpBezierDesc * gimp_stroke_real_make_bezier (const GimpStroke *stroke);
static void gimp_stroke_real_translate (GimpStroke *stroke, static void gimp_stroke_real_translate (GimpStroke *stroke,
gdouble offset_x, gdouble offset_x,
@ -1006,7 +1006,7 @@ gimp_stroke_real_duplicate (const GimpStroke *stroke)
} }
GimpStroke * GimpBezierDesc *
gimp_stroke_make_bezier (const GimpStroke *stroke) gimp_stroke_make_bezier (const GimpStroke *stroke)
{ {
g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL); g_return_val_if_fail (GIMP_IS_STROKE (stroke), NULL);
@ -1014,7 +1014,7 @@ gimp_stroke_make_bezier (const GimpStroke *stroke)
return GIMP_STROKE_GET_CLASS (stroke)->make_bezier (stroke); return GIMP_STROKE_GET_CLASS (stroke)->make_bezier (stroke);
} }
static GimpStroke * static GimpBezierDesc *
gimp_stroke_real_make_bezier (const GimpStroke *stroke) gimp_stroke_real_make_bezier (const GimpStroke *stroke)
{ {
g_printerr ("gimp_stroke_make_bezier: default implementation\n"); g_printerr ("gimp_stroke_make_bezier: default implementation\n");

View File

@ -149,7 +149,7 @@ struct _GimpStrokeClass
GimpStroke * (* duplicate) (const GimpStroke *stroke); GimpStroke * (* duplicate) (const GimpStroke *stroke);
GimpStroke * (* make_bezier) (const GimpStroke *stroke); GimpBezierDesc * (* make_bezier) (const GimpStroke *stroke);
void (* translate) (GimpStroke *stroke, void (* translate) (GimpStroke *stroke,
gdouble offset_x, gdouble offset_x,
@ -177,8 +177,6 @@ struct _GimpStrokeClass
GArray * (* get_draw_lines) (const GimpStroke *stroke); GArray * (* get_draw_lines) (const GimpStroke *stroke);
GArray * (* control_points_get) (const GimpStroke *stroke, GArray * (* control_points_get) (const GimpStroke *stroke,
gboolean *ret_closed); gboolean *ret_closed);
void (* art_stroke) (const GimpStroke *stroke);
}; };
@ -312,7 +310,7 @@ GArray * gimp_stroke_interpolate (const GimpStroke *stroke,
GimpStroke * gimp_stroke_duplicate (const GimpStroke *stroke); GimpStroke * gimp_stroke_duplicate (const GimpStroke *stroke);
/* creates a bezier approximation. */ /* creates a bezier approximation. */
GimpStroke * gimp_stroke_make_bezier (const GimpStroke *stroke); GimpBezierDesc * gimp_stroke_make_bezier (const GimpStroke *stroke);
void gimp_stroke_translate (GimpStroke *stroke, void gimp_stroke_translate (GimpStroke *stroke,
gdouble offset_x, gdouble offset_x,

View File

@ -22,6 +22,7 @@
#include "config.h" #include "config.h"
#include <glib-object.h> #include <glib-object.h>
#include <cairo/cairo.h>
#include "libgimpcolor/gimpcolor.h" #include "libgimpcolor/gimpcolor.h"
#include "libgimpmath/gimpmath.h" #include "libgimpmath/gimpmath.h"
@ -135,7 +136,7 @@ static gint gimp_vectors_real_interpolate (const GimpVectors *vectors,
gdouble precision, gdouble precision,
gint max_points, gint max_points,
GimpCoords *ret_coords); GimpCoords *ret_coords);
static GimpVectors * gimp_vectors_real_make_bezier (const GimpVectors *vectors); static GimpBezierDesc * gimp_vectors_real_make_bezier (const GimpVectors *vectors);
G_DEFINE_TYPE (GimpVectors, gimp_vectors, GIMP_TYPE_ITEM) G_DEFINE_TYPE (GimpVectors, gimp_vectors, GIMP_TYPE_ITEM)
@ -1013,7 +1014,7 @@ gimp_vectors_real_interpolate (const GimpVectors *vectors,
} }
GimpVectors * GimpBezierDesc *
gimp_vectors_make_bezier (const GimpVectors *vectors) gimp_vectors_make_bezier (const GimpVectors *vectors)
{ {
g_return_val_if_fail (GIMP_IS_VECTORS (vectors), NULL); g_return_val_if_fail (GIMP_IS_VECTORS (vectors), NULL);
@ -1021,11 +1022,38 @@ gimp_vectors_make_bezier (const GimpVectors *vectors)
return GIMP_VECTORS_GET_CLASS (vectors)->make_bezier (vectors); return GIMP_VECTORS_GET_CLASS (vectors)->make_bezier (vectors);
} }
static GimpVectors * static GimpBezierDesc *
gimp_vectors_real_make_bezier (const GimpVectors *vectors) gimp_vectors_real_make_bezier (const GimpVectors *vectors)
{ {
g_printerr ("gimp_vectors_make_bezier: default implementation\n"); GimpStroke *cur_stroke;
GArray *cmd_array;
GimpBezierDesc *bezdesc;
GimpBezierDesc *ret_bezdesc = NULL;
return NULL; cmd_array = g_array_new (FALSE, FALSE, sizeof (cairo_path_data_t));
for (cur_stroke = gimp_vectors_stroke_get_next (vectors, NULL);
cur_stroke;
cur_stroke = gimp_vectors_stroke_get_next (vectors, cur_stroke))
{
bezdesc = gimp_stroke_make_bezier (cur_stroke);
if (bezdesc)
{
cmd_array = g_array_append_vals (cmd_array, bezdesc->data,
bezdesc->num_data);
g_free (bezdesc->data);
g_free (bezdesc);
}
}
if (cmd_array->len > 0)
{
ret_bezdesc = g_new (GimpBezierDesc, 1);
ret_bezdesc->num_data = cmd_array->len;
ret_bezdesc->data = (cairo_path_data_t *) cmd_array->data;
g_array_free (cmd_array, FALSE);
}
return ret_bezdesc;
} }

View File

@ -24,7 +24,6 @@
#include "core/gimpitem.h" #include "core/gimpitem.h"
#define GIMP_TYPE_VECTORS (gimp_vectors_get_type ()) #define GIMP_TYPE_VECTORS (gimp_vectors_get_type ())
#define GIMP_VECTORS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VECTORS, GimpVectors)) #define GIMP_VECTORS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VECTORS, GimpVectors))
#define GIMP_VECTORS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_VECTORS, GimpVectorsClass)) #define GIMP_VECTORS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_VECTORS, GimpVectorsClass))
@ -79,7 +78,7 @@ struct _GimpVectorsClass
gdouble precision, gdouble precision,
gint max_points, gint max_points,
GimpCoords *ret_coords); GimpCoords *ret_coords);
GimpVectors * (* make_bezier) (const GimpVectors *vectors); GimpBezierDesc * (* make_bezier) (const GimpVectors *vectors);
}; };
@ -173,8 +172,8 @@ gint gimp_vectors_interpolate (const GimpVectors *vectors,
/* usually overloaded */ /* usually overloaded */
/* creates a bezier approximation. */ /* creates a bezier representation. */
GimpVectors * gimp_vectors_make_bezier (const GimpVectors *vectors); GimpBezierDesc * gimp_vectors_make_bezier (const GimpVectors *vectors);
#endif /* __GIMP_VECTORS_H__ */ #endif /* __GIMP_VECTORS_H__ */

View File

@ -35,5 +35,10 @@ typedef struct _GimpVectorsPropUndo GimpVectorsPropUndo;
typedef struct _GimpStroke GimpStroke; typedef struct _GimpStroke GimpStroke;
typedef struct _GimpBezierStroke GimpBezierStroke; typedef struct _GimpBezierStroke GimpBezierStroke;
#ifdef CAIRO_VERSION
typedef cairo_path_t GimpBezierDesc;
#else
typedef void * GimpBezierDesc;
#endif
#endif /* __VECTORS_TYPES_H__ */ #endif /* __VECTORS_TYPES_H__ */

View File

@ -70,7 +70,7 @@ gimp_view_renderer_vectors_draw (GimpViewRenderer *renderer,
const GdkRectangle *area) const GdkRectangle *area)
{ {
GimpVectors *vectors = GIMP_VECTORS (renderer->viewable); GimpVectors *vectors = GIMP_VECTORS (renderer->viewable);
GimpStroke *stroke; GimpBezierDesc *bezdesc;
gdouble xscale; gdouble xscale;
gdouble yscale; gdouble yscale;
gint x, y; gint x, y;
@ -80,50 +80,29 @@ gimp_view_renderer_vectors_draw (GimpViewRenderer *renderer,
x = area->x + (area->width - renderer->width) / 2; x = area->x + (area->width - renderer->width) / 2;
y = area->y + (area->height - renderer->height) / 2; y = area->y + (area->height - renderer->height) / 2;
cairo_rectangle (cr, x, y, renderer->width, renderer->height); cairo_translate (cr, x, y);
cairo_rectangle (cr, 0, 0, renderer->width, renderer->height);
cairo_clip_preserve (cr); cairo_clip_preserve (cr);
cairo_fill (cr); cairo_fill (cr);
cairo_set_line_width (cr, 1.0); xscale = (gdouble) renderer->width / (gdouble) gimp_item_width (GIMP_ITEM (vectors));
yscale = (gdouble) renderer->height / (gdouble) gimp_item_height (GIMP_ITEM (vectors));
cairo_scale (cr, xscale, yscale);
/* determine line width */
xscale = yscale = 0.5;
cairo_device_to_user_distance (cr, &xscale, &yscale);
cairo_set_line_width (cr, MAX (xscale, yscale));
gdk_cairo_set_source_color (cr, &widget->style->black); gdk_cairo_set_source_color (cr, &widget->style->black);
xscale = (gdouble) gimp_item_width (GIMP_ITEM (vectors)) / (gdouble) renderer->width; bezdesc = gimp_vectors_make_bezier (vectors);
yscale = (gdouble) gimp_item_height (GIMP_ITEM (vectors)) / (gdouble) renderer->height;
for (stroke = gimp_vectors_stroke_get_next (vectors, NULL); if (bezdesc)
stroke != NULL;
stroke = gimp_vectors_stroke_get_next (vectors, stroke))
{ {
GArray *coordinates; cairo_append_path (cr, (cairo_path_t *) bezdesc);
coordinates = gimp_stroke_interpolate (stroke,
MIN (xscale, yscale) / 2,
NULL);
if (! coordinates)
continue;
if (coordinates->len > 0)
{
GimpCoords *coords = &(g_array_index (coordinates, GimpCoords, 0));
gdouble cx = x + ROUND (coords->x / xscale);
gdouble cy = y + ROUND (coords->y / yscale);
gint i;
cairo_move_to (cr, cx, cy);
for (i = 1; i < coordinates->len; i++)
{
coords = &(g_array_index (coordinates, GimpCoords, i));
cx = x + ROUND (coords->x / xscale) + 0.5;
cy = y + ROUND (coords->y / yscale) + 0.5;
cairo_line_to (cr, cx, cy);
}
cairo_stroke (cr); cairo_stroke (cr);
} g_free (bezdesc->data);
g_free (bezdesc);
g_array_free (coordinates, TRUE);
} }
} }