mirror of https://github.com/GNOME/gimp.git
Dave Neary <bolsh@gimp.org>
2003-09-20 Simon Budig <simon@gimp.org> Dave Neary <bolsh@gimp.org> First steps towards Libart stroking. Right now the code crashes and thus is disabled by default. If you want to test it, change the #define LIBART_STROKE in app/vectors/gimpvectors.c. Then a click on the stroke button in the paths dialog invokes the new code. The crash is in gimpdrawable-stroke.c - apparently I did not yet get the TileManager stuff correctly. * app/core/gimpscanconvert.[ch]: Rewritten to be more clear and have an easier API. Now can handle open Paths and libart-stroke the (open/closed) polygons defined earlier. * app/core/core-enums.h: Added Enums for LineJoin-Type and EndCap-Type for stroking. * app/core/core-enums.c: regenerated. * app/core/gimpimage-mask-select.c: Use the new API of GimpScanConvert where appropriate. * app/vectors/gimpvectors.c: Added #define to enable the libart stroking. Disabled by default because of the crash mentioned above... * app/vectors/gimpbezierstroke.c * app/vectors/gimpstroke.c * app/vectors/gimpvectors.[ch]: Removed Libart stuff here. Libart usage now lives exclusively in GimpScanConvert. * app/core/gimpdrawable-stroke.[ch]: New files for the libart stroking (right now just vector objects). * app/core/Makefile.am: changed accordingly. * app/Makefile.am: Needed to tweak linking. :-/
This commit is contained in:
parent
09837f7add
commit
ca07f5ddb2
38
ChangeLog
38
ChangeLog
|
@ -1,3 +1,41 @@
|
|||
2003-09-20 Simon Budig <simon@gimp.org>
|
||||
Dave Neary <bolsh@gimp.org>
|
||||
|
||||
First steps towards Libart stroking. Right now the code
|
||||
crashes and thus is disabled by default. If you want to
|
||||
test it, change the #define LIBART_STROKE in
|
||||
app/vectors/gimpvectors.c. Then a click on the stroke button
|
||||
in the paths dialog invokes the new code.
|
||||
The crash is in gimpdrawable-stroke.c - apparently I did not
|
||||
yet get the TileManager stuff correctly.
|
||||
|
||||
* app/core/gimpscanconvert.[ch]: Rewritten to be more clear
|
||||
and have an easier API. Now can handle open Paths and
|
||||
libart-stroke the (open/closed) polygons defined earlier.
|
||||
|
||||
* app/core/core-enums.h: Added Enums for LineJoin-Type and
|
||||
EndCap-Type for stroking.
|
||||
|
||||
* app/core/core-enums.c: regenerated.
|
||||
|
||||
* app/core/gimpimage-mask-select.c: Use the new API of
|
||||
GimpScanConvert where appropriate.
|
||||
|
||||
* app/vectors/gimpvectors.c: Added #define to enable the libart
|
||||
stroking. Disabled by default because of the crash mentioned
|
||||
above...
|
||||
|
||||
* app/vectors/gimpbezierstroke.c
|
||||
* app/vectors/gimpstroke.c
|
||||
* app/vectors/gimpvectors.[ch]: Removed Libart stuff here.
|
||||
Libart usage now lives exclusively in GimpScanConvert.
|
||||
|
||||
* app/core/gimpdrawable-stroke.[ch]: New files for the libart
|
||||
stroking (right now just vector objects).
|
||||
* app/core/Makefile.am: changed accordingly.
|
||||
|
||||
* app/Makefile.am: Needed to tweak linking. :-/
|
||||
|
||||
2003-09-20 Henrik Brix Andersen <brix@gimp.org>
|
||||
|
||||
* app/config/gimpconfig-dump.c (dump_gimprc): removed reference to
|
||||
|
|
|
@ -57,7 +57,8 @@ endif
|
|||
gimp_1_3_LDFLAGS = \
|
||||
$(mwindows) \
|
||||
-u $(symprefix)gimp_container_filter \
|
||||
-u $(symprefix)gimp_xml_parser_new
|
||||
-u $(symprefix)gimp_xml_parser_new \
|
||||
-u $(symprefix)gimp_drawable_stroke_vectors
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DG_LOG_DOMAIN=\"Gimp\" \
|
||||
|
|
|
@ -85,6 +85,8 @@ libappcore_a_sources = \
|
|||
gimpdrawable-offset.h \
|
||||
gimpdrawable-preview.c \
|
||||
gimpdrawable-preview.h \
|
||||
gimpdrawable-stroke.c \
|
||||
gimpdrawable-stroke.h \
|
||||
gimpdrawable-transform.c \
|
||||
gimpdrawable-transform.h \
|
||||
gimpenvirontable.h \
|
||||
|
|
|
@ -254,6 +254,46 @@ gimp_grid_type_get_type (void)
|
|||
}
|
||||
|
||||
|
||||
static const GEnumValue gimp_join_type_enum_values[] =
|
||||
{
|
||||
{ GIMP_JOIN_MITER, N_("Miter"), "miter" },
|
||||
{ GIMP_JOIN_ROUND, N_("Round"), "round" },
|
||||
{ GIMP_JOIN_BEVEL, N_("Bevel"), "bevel" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
GType
|
||||
gimp_join_type_get_type (void)
|
||||
{
|
||||
static GType enum_type = 0;
|
||||
|
||||
if (!enum_type)
|
||||
enum_type = g_enum_register_static ("GimpJoinType", gimp_join_type_enum_values);
|
||||
|
||||
return enum_type;
|
||||
}
|
||||
|
||||
|
||||
static const GEnumValue gimp_cap_type_enum_values[] =
|
||||
{
|
||||
{ GIMP_CAP_BUTT, N_("Butt"), "butt" },
|
||||
{ GIMP_CAP_ROUND, N_("Round"), "round" },
|
||||
{ GIMP_CAP_SQUARE, N_("Square"), "square" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
GType
|
||||
gimp_cap_type_get_type (void)
|
||||
{
|
||||
static GType enum_type = 0;
|
||||
|
||||
if (!enum_type)
|
||||
enum_type = g_enum_register_static ("GimpCapType", gimp_cap_type_enum_values);
|
||||
|
||||
return enum_type;
|
||||
}
|
||||
|
||||
|
||||
static const GEnumValue gimp_image_base_type_enum_values[] =
|
||||
{
|
||||
{ GIMP_RGB, N_("RGB"), "rgb" },
|
||||
|
|
|
@ -195,6 +195,30 @@ typedef enum /*< pdb-skip >*/
|
|||
} GimpGridType;
|
||||
|
||||
|
||||
#define GIMP_TYPE_JOIN_TYPE (gimp_join_type_get_type ())
|
||||
|
||||
GType gimp_join_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
GIMP_JOIN_MITER, /*< desc="Miter" >*/
|
||||
GIMP_JOIN_ROUND, /*< desc="Round" >*/
|
||||
GIMP_JOIN_BEVEL /*< desc="Bevel" >*/
|
||||
} GimpJoinType;
|
||||
|
||||
|
||||
#define GIMP_TYPE_CAP_TYPE (gimp_cap_type_get_type ())
|
||||
|
||||
GType gimp_cap_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
GIMP_CAP_BUTT, /*< desc="Butt" >*/
|
||||
GIMP_CAP_ROUND, /*< desc="Round" >*/
|
||||
GIMP_CAP_SQUARE /*< desc="Square" >*/
|
||||
} GimpCapType;
|
||||
|
||||
|
||||
#define GIMP_TYPE_IMAGE_BASE_TYPE (gimp_image_base_type_get_type ())
|
||||
|
||||
GType gimp_image_base_type_get_type (void) G_GNUC_CONST;
|
||||
|
|
|
@ -172,7 +172,8 @@ gimp_image_mask_select_polygon (GimpImage *gimage,
|
|||
scan_convert = gimp_scan_convert_new (gimage->width,
|
||||
gimage->height,
|
||||
antialias ? SUPERSAMPLE : 1);
|
||||
gimp_scan_convert_add_points (scan_convert, n_points, points, FALSE);
|
||||
|
||||
gimp_scan_convert_add_polyline (scan_convert, n_points, points, TRUE);
|
||||
|
||||
mask = gimp_scan_convert_to_channel (scan_convert, gimage);
|
||||
|
||||
|
@ -253,8 +254,8 @@ gimp_image_mask_select_vectors (GimpImage *gimage,
|
|||
num_coords++;
|
||||
}
|
||||
|
||||
gimp_scan_convert_add_points (scan_convert, coords->len,
|
||||
points, TRUE);
|
||||
gimp_scan_convert_add_polyline (scan_convert, coords->len,
|
||||
points, TRUE);
|
||||
|
||||
g_free (points);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* gimpdrawable-stroke.c
|
||||
* Copyright (C) 2003 Simon Budig <simon@gimp.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "libgimpcolor/gimpcolor.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "base/pixel-region.h"
|
||||
#include "base/temp-buf.h"
|
||||
#include "base/tile-manager.h"
|
||||
|
||||
#include "core/gimpitem.h"
|
||||
#include "core/gimpscanconvert.h"
|
||||
|
||||
#include "vectors/gimpstroke.h"
|
||||
#include "vectors/gimpvectors.h"
|
||||
|
||||
#include "paint-funcs/paint-funcs.h"
|
||||
|
||||
#include "gimp.h"
|
||||
#include "gimpdrawable.h"
|
||||
#include "gimpdrawable-stroke.h"
|
||||
#include "gimpimage.h"
|
||||
|
||||
#include "gimp-intl.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
void
|
||||
gimp_drawable_stroke_vectors (GimpDrawable *drawable,
|
||||
GimpVectors *vectors,
|
||||
gdouble opacity,
|
||||
GimpRGB *color,
|
||||
GimpLayerModeEffects paint_mode,
|
||||
gdouble width,
|
||||
GimpJoinType jointype,
|
||||
GimpCapType captype,
|
||||
gboolean antialias)
|
||||
{
|
||||
GimpScanConvert *scan_convert;
|
||||
gint num_coords = 0;
|
||||
GimpStroke *stroke;
|
||||
TileManager *base;
|
||||
TileManager *mask;
|
||||
gint x1, x2, y1, y2, bytes;
|
||||
guchar ucolor[4] = { 0, 0, 0, 255 };
|
||||
PixelRegion maskPR, basePR;
|
||||
|
||||
gimp_drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
||||
|
||||
scan_convert = gimp_scan_convert_new (x2 - x1, y2 - y1, antialias ? 1 : 0);
|
||||
|
||||
/* For each Stroke in the vector, interpolate it, and add it to the
|
||||
* ScanConvert */
|
||||
for (stroke = gimp_vectors_stroke_get_next (vectors, NULL);
|
||||
stroke;
|
||||
stroke = gimp_vectors_stroke_get_next (vectors, stroke))
|
||||
{
|
||||
GimpVector2 *points;
|
||||
gboolean closed;
|
||||
GArray *coords;
|
||||
gint i;
|
||||
|
||||
/* Get the interpolated version of this stroke, and add it to our
|
||||
* scanconvert. */
|
||||
coords = gimp_stroke_interpolate (stroke, 1, &closed);
|
||||
|
||||
if (coords && coords->len)
|
||||
{
|
||||
points = g_new0 (GimpVector2, coords->len);
|
||||
|
||||
for (i = 0; i < coords->len; i++)
|
||||
{
|
||||
points[i].x = g_array_index (coords, GimpCoords, i).x;
|
||||
points[i].y = g_array_index (coords, GimpCoords, i).y;
|
||||
num_coords++;
|
||||
}
|
||||
|
||||
gimp_scan_convert_add_polyline (scan_convert, coords->len,
|
||||
points, closed);
|
||||
|
||||
g_free (points);
|
||||
}
|
||||
}
|
||||
|
||||
if (num_coords == 0)
|
||||
{
|
||||
gimp_scan_convert_free (scan_convert);
|
||||
return;
|
||||
}
|
||||
|
||||
gimp_scan_convert_stroke (scan_convert, jointype, captype, width);
|
||||
|
||||
mask = tile_manager_new (x2 - x1, y2 - y1, 1);
|
||||
tile_manager_set_offsets (mask, x1, y1);
|
||||
|
||||
pixel_region_init (&maskPR, mask, x1, y1, x2 - x1, y2 - y1, TRUE);
|
||||
color_region (&maskPR, ucolor);
|
||||
|
||||
gimp_scan_convert_render (scan_convert, mask);
|
||||
|
||||
gimp_scan_convert_free (scan_convert);
|
||||
|
||||
|
||||
bytes = drawable->bytes;
|
||||
if (!gimp_drawable_has_alpha (drawable))
|
||||
bytes++;
|
||||
|
||||
base = tile_manager_new (x2 - x1, y2 - y1, bytes);
|
||||
tile_manager_set_offsets (base, x1, y1);
|
||||
|
||||
gimp_rgb_get_uchar (color, &(ucolor[0]), &(ucolor[1]), &(ucolor[2]));
|
||||
pixel_region_init (&basePR, base, x1, y1, x2 - x1, y2 - y1, TRUE);
|
||||
color_region (&basePR, ucolor);
|
||||
|
||||
apply_mask_to_region (&basePR, &maskPR, OPAQUE_OPACITY);
|
||||
|
||||
gimp_image_apply_image (gimp_item_get_image (GIMP_ITEM (drawable)),
|
||||
drawable, &basePR,
|
||||
TRUE, _("Render Vectors"), opacity, paint_mode,
|
||||
base, x1, y1);
|
||||
|
||||
tile_manager_unref (mask);
|
||||
tile_manager_unref (base);
|
||||
|
||||
gimp_drawable_update (drawable, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* gimpdrawable-stroke.h
|
||||
* Copyright (C) 2003 Simon Budig <simon@gimp.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_DRAWABLE_STROKE_H__
|
||||
#define __GIMP_DRAWABLE_STROKE_H__
|
||||
|
||||
|
||||
void gimp_drawable_stroke_vectors (GimpDrawable *drawable,
|
||||
GimpVectors *vectors,
|
||||
gdouble opacity,
|
||||
GimpRGB *color,
|
||||
GimpLayerModeEffects paint_mode,
|
||||
gdouble width,
|
||||
GimpJoinType jointype,
|
||||
GimpCapType captype,
|
||||
gboolean antialias);
|
||||
|
||||
#endif /* __GIMP_DRAWABLE_STROKE_H__ */
|
|
@ -172,7 +172,8 @@ gimp_image_mask_select_polygon (GimpImage *gimage,
|
|||
scan_convert = gimp_scan_convert_new (gimage->width,
|
||||
gimage->height,
|
||||
antialias ? SUPERSAMPLE : 1);
|
||||
gimp_scan_convert_add_points (scan_convert, n_points, points, FALSE);
|
||||
|
||||
gimp_scan_convert_add_polyline (scan_convert, n_points, points, TRUE);
|
||||
|
||||
mask = gimp_scan_convert_to_channel (scan_convert, gimage);
|
||||
|
||||
|
@ -253,8 +254,8 @@ gimp_image_mask_select_vectors (GimpImage *gimage,
|
|||
num_coords++;
|
||||
}
|
||||
|
||||
gimp_scan_convert_add_points (scan_convert, coords->len,
|
||||
points, TRUE);
|
||||
gimp_scan_convert_add_polyline (scan_convert, coords->len,
|
||||
points, TRUE);
|
||||
|
||||
g_free (points);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "core-types.h"
|
||||
|
||||
#include "base/pixel-region.h"
|
||||
#include "base/tile-manager.h"
|
||||
|
||||
#include "gimpchannel.h"
|
||||
#include "gimpimage.h"
|
||||
|
@ -40,23 +41,23 @@ struct _GimpScanConvert
|
|||
guint width;
|
||||
guint height;
|
||||
|
||||
guint antialias; /* how much to oversample by */
|
||||
/* currently only used as boolean value */
|
||||
gboolean antialias; /* do we want antialiasing? */
|
||||
|
||||
/* record the first and last points so we can close the current polygon. */
|
||||
gboolean got_first;
|
||||
GimpVector2 first;
|
||||
GimpVector2 prev;
|
||||
gboolean got_last;
|
||||
GimpVector2 last;
|
||||
gboolean have_open;
|
||||
|
||||
guint num_nodes;
|
||||
ArtVpath *vpath;
|
||||
|
||||
ArtSVP *svp; /* Sorted vector path
|
||||
(extension no longer possible) */
|
||||
};
|
||||
|
||||
/* Private functions */
|
||||
static void gimp_scan_convert_finish (GimpScanConvert *sc);
|
||||
|
||||
/* public functions */
|
||||
|
||||
GimpScanConvert *
|
||||
gimp_scan_convert_new (guint width,
|
||||
guint height,
|
||||
|
@ -70,12 +71,16 @@ gimp_scan_convert_new (guint width,
|
|||
|
||||
sc = g_new0 (GimpScanConvert, 1);
|
||||
|
||||
sc->antialias = antialias;
|
||||
sc->antialias = (antialias != 0 ? TRUE : FALSE);
|
||||
sc->width = width;
|
||||
sc->height = height;
|
||||
|
||||
sc->got_first = FALSE;
|
||||
sc->have_open = FALSE;
|
||||
|
||||
sc->num_nodes = 0;
|
||||
sc->vpath = NULL;
|
||||
sc->svp = NULL;
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
@ -84,11 +89,12 @@ void
|
|||
gimp_scan_convert_free (GimpScanConvert *sc)
|
||||
{
|
||||
art_free (sc->vpath);
|
||||
art_free (sc->svp);
|
||||
g_free (sc);
|
||||
}
|
||||
|
||||
/* Add "n_points" from "points" to the polygon currently being
|
||||
* described by "scan_converter".
|
||||
* described by "scan_converter". DEPRECATED.
|
||||
*/
|
||||
void
|
||||
gimp_scan_convert_add_points (GimpScanConvert *sc,
|
||||
|
@ -96,140 +102,215 @@ gimp_scan_convert_add_points (GimpScanConvert *sc,
|
|||
GimpVector2 *points,
|
||||
gboolean new_polygon)
|
||||
{
|
||||
GimpVector2 prev;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (sc != NULL);
|
||||
g_return_if_fail (points != NULL);
|
||||
g_return_if_fail (n_points > 0);
|
||||
g_return_if_fail (sc->svp == NULL);
|
||||
|
||||
/* We need up to three extra nodes later to close and finish the path */
|
||||
sc->vpath = art_renew (sc->vpath, ArtVpath, sc->num_nodes + n_points + 3);
|
||||
/* We need an extra nodes to end the path */
|
||||
sc->vpath = art_renew (sc->vpath, ArtVpath, sc->num_nodes + n_points + 2);
|
||||
|
||||
/* if we need to start a new polygon check, if we need to close the
|
||||
* previous.
|
||||
*/
|
||||
if (new_polygon)
|
||||
{
|
||||
/* close the last polygon if necessary */
|
||||
if (sc->got_first && sc->got_last &&
|
||||
(sc->first.x != sc->last.x || sc->first.y != sc->last.y))
|
||||
{
|
||||
sc->vpath[sc->num_nodes].code = ART_LINETO;
|
||||
sc->vpath[sc->num_nodes].x = sc->first.x;
|
||||
sc->vpath[sc->num_nodes].y = sc->first.y;
|
||||
sc->num_nodes++;
|
||||
}
|
||||
sc->got_first = FALSE;
|
||||
sc->got_last = FALSE;
|
||||
}
|
||||
|
||||
if (!sc->got_first && n_points > 0)
|
||||
{
|
||||
sc->got_first = TRUE;
|
||||
sc->first = points[0];
|
||||
sc->vpath[sc->num_nodes].code =
|
||||
(sc->num_nodes == 0 || new_polygon) ?
|
||||
ART_MOVETO : ART_LINETO;
|
||||
sc->vpath[sc->num_nodes].x = points[0].x;
|
||||
sc->vpath[sc->num_nodes].y = points[0].y;
|
||||
sc->num_nodes++;
|
||||
sc->prev = points[0];
|
||||
}
|
||||
sc->vpath[sc->num_nodes].code = ((! sc->got_first) || new_polygon) ?
|
||||
ART_MOVETO : ART_LINETO;
|
||||
sc->vpath[sc->num_nodes].x = points[0].x;
|
||||
sc->vpath[sc->num_nodes].y = points[0].y;
|
||||
sc->num_nodes++;
|
||||
sc->got_first = TRUE;
|
||||
prev = points[0];
|
||||
|
||||
for (i = 1; i < n_points; i++)
|
||||
{
|
||||
if (sc->prev.x != points[i].x || sc->prev.y != points[i].y)
|
||||
if (prev.x != points[i].x || prev.y != points[i].y)
|
||||
{
|
||||
sc->vpath[sc->num_nodes].code = ART_LINETO;
|
||||
sc->vpath[sc->num_nodes].x = points[i].x;
|
||||
sc->vpath[sc->num_nodes].y = points[i].y;
|
||||
sc->num_nodes++;
|
||||
sc->prev = points[i];
|
||||
prev = points[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (n_points > 0)
|
||||
{
|
||||
sc->got_last = TRUE;
|
||||
sc->last = points[n_points - 1];
|
||||
}
|
||||
/* for some reason we need to duplicate the last node?? */
|
||||
|
||||
sc->vpath[sc->num_nodes] = sc->vpath[sc->num_nodes - 1];
|
||||
sc->num_nodes++;
|
||||
sc->vpath[sc->num_nodes].code = ART_END;
|
||||
}
|
||||
|
||||
|
||||
/* Scan convert the polygon described by the list of points passed to
|
||||
* scan_convert_add_points, and return a channel with a bits set if
|
||||
* they fall within the polygon defined. The polygon is filled
|
||||
* according to the even-odd rule. The polygon is closed by
|
||||
* joining the final point to the initial point.
|
||||
/* Add a polygon with "npoints" "points" that may be open or closed.
|
||||
* It is not recommended to mix gimp_scan_convert_add_polyline with
|
||||
* gimp_scan_convert_add_points.
|
||||
*
|
||||
* Please note that if you should use gimp_scan_convert_stroke() if you
|
||||
* specify open polygons.
|
||||
*/
|
||||
|
||||
void
|
||||
gimp_scan_convert_add_polyline (GimpScanConvert *sc,
|
||||
guint n_points,
|
||||
GimpVector2 *points,
|
||||
gboolean closed)
|
||||
{
|
||||
GimpVector2 prev;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (sc != NULL);
|
||||
g_return_if_fail (points != NULL);
|
||||
g_return_if_fail (n_points > 0);
|
||||
g_return_if_fail (sc->svp == NULL);
|
||||
|
||||
if (!closed)
|
||||
sc->have_open = TRUE;
|
||||
|
||||
/* We need two extra nodes later to close the path. */
|
||||
sc->vpath = art_renew (sc->vpath, ArtVpath,
|
||||
sc->num_nodes + n_points + 2);
|
||||
|
||||
for (i = 0; i < n_points; i++)
|
||||
{
|
||||
/* compress multiple identical coordinates */
|
||||
if (i == 0 ||
|
||||
prev.x != points[i].x ||
|
||||
prev.y != points[i].y)
|
||||
{
|
||||
sc->vpath[sc->num_nodes].code = (i == 0 ? (closed ?
|
||||
ART_MOVETO :
|
||||
ART_MOVETO_OPEN) :
|
||||
ART_LINETO);
|
||||
sc->vpath[sc->num_nodes].x = points[i].x;
|
||||
sc->vpath[sc->num_nodes].y = points[i].y;
|
||||
sc->num_nodes++;
|
||||
prev = points[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* for some reason we need to duplicate the last node?? */
|
||||
|
||||
sc->vpath[sc->num_nodes] = sc->vpath[sc->num_nodes - 1];
|
||||
sc->num_nodes++;
|
||||
sc->vpath[sc->num_nodes].code = ART_END;
|
||||
|
||||
/* If someone wants to mix this function with _add_points ()
|
||||
* try to do something reasonable...
|
||||
*/
|
||||
|
||||
sc->got_first = FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Stroke the content of a GimpScanConvert. The next
|
||||
* gimp_scan_convert_to_channel will result in the outline of the polygon
|
||||
* defined with the commands above.
|
||||
*
|
||||
* You cannot add additional polygons after this command.
|
||||
*/
|
||||
void
|
||||
gimp_scan_convert_stroke (GimpScanConvert *sc,
|
||||
GimpJoinType join,
|
||||
GimpCapType cap,
|
||||
gdouble width)
|
||||
{
|
||||
ArtSVP *stroke;
|
||||
ArtPathStrokeJoinType artjoin;
|
||||
ArtPathStrokeCapType artcap;
|
||||
|
||||
g_return_if_fail (sc->svp == NULL);
|
||||
|
||||
switch (join)
|
||||
{
|
||||
case GIMP_JOIN_MITER:
|
||||
artjoin = ART_PATH_STROKE_JOIN_MITER;
|
||||
break;
|
||||
case GIMP_JOIN_ROUND:
|
||||
artjoin = ART_PATH_STROKE_JOIN_ROUND;
|
||||
break;
|
||||
case GIMP_JOIN_BEVEL:
|
||||
artjoin = ART_PATH_STROKE_JOIN_BEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cap)
|
||||
{
|
||||
case GIMP_CAP_BUTT:
|
||||
artcap = ART_PATH_STROKE_CAP_BUTT;
|
||||
break;
|
||||
case GIMP_CAP_ROUND:
|
||||
artcap = ART_PATH_STROKE_CAP_ROUND;
|
||||
break;
|
||||
case GIMP_CAP_SQUARE:
|
||||
artcap = ART_PATH_STROKE_CAP_SQUARE;
|
||||
break;
|
||||
}
|
||||
|
||||
stroke = art_svp_vpath_stroke (sc->vpath, artjoin, artcap,
|
||||
width, 10.0, 1.0);
|
||||
|
||||
sc->svp = stroke;
|
||||
}
|
||||
|
||||
/* Return a new Channel according to the polygonal shapes defined with
|
||||
* the commands above.
|
||||
*
|
||||
* You cannot add additional polygons after this command.
|
||||
*/
|
||||
GimpChannel *
|
||||
gimp_scan_convert_to_channel (GimpScanConvert *sc,
|
||||
GimpImage *gimage)
|
||||
{
|
||||
GimpChannel *mask;
|
||||
PixelRegion maskPR;
|
||||
gint i, j;
|
||||
|
||||
gpointer pr;
|
||||
ArtVpath *pert_vpath;
|
||||
ArtSVP *svp, *svp2, *svp3;
|
||||
guchar *dest, *d;
|
||||
|
||||
/* do we need to close the polygon? */
|
||||
if (sc->got_first && sc->got_last &&
|
||||
(sc->first.x != sc->last.x || sc->first.y != sc->last.y))
|
||||
{
|
||||
sc->vpath[sc->num_nodes].code = ART_LINETO;
|
||||
sc->vpath[sc->num_nodes].x = sc->first.x;
|
||||
sc->vpath[sc->num_nodes].y = sc->first.y;
|
||||
sc->num_nodes++;
|
||||
}
|
||||
|
||||
mask = gimp_channel_new_mask (gimage, sc->width, sc->height);
|
||||
|
||||
sc->vpath[sc->num_nodes].code = ART_END;
|
||||
sc->vpath[sc->num_nodes].x = sc->first.x;
|
||||
sc->vpath[sc->num_nodes].y = sc->first.y;
|
||||
sc->num_nodes++;
|
||||
gimp_scan_convert_render (sc, gimp_drawable_data (GIMP_DRAWABLE (mask)));
|
||||
|
||||
/*
|
||||
* Current Libart (2.3.8) recommends a slight random distorsion
|
||||
* of the path, because art_svp_uncross and art_svp_rewind_uncrossed
|
||||
* are not yet numerically stable. It is actually possible to construct
|
||||
* worst case scenarios. The slight perturbation should not have any
|
||||
* visible effect.
|
||||
*/
|
||||
mask->bounds_known = FALSE;
|
||||
|
||||
/* Debug output of libart path
|
||||
for (i=0; i < sc->num_nodes ; i++)
|
||||
{
|
||||
g_printerr ("X: %f, Y: %f, Type: %d\n", sc->vpath[i].x, sc->vpath[i].y,
|
||||
sc->vpath[i].code );
|
||||
}
|
||||
*/
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
/* This is a more low level version. Expects a tile manager of depth 1.
|
||||
*
|
||||
* You cannot add additional polygons after this command.
|
||||
*/
|
||||
void
|
||||
gimp_scan_convert_render (GimpScanConvert *sc,
|
||||
TileManager *tile_manager)
|
||||
{
|
||||
PixelRegion maskPR;
|
||||
gpointer pr;
|
||||
|
||||
gint i, j, x0, y0;
|
||||
guchar *dest, *d;
|
||||
|
||||
pert_vpath = art_vpath_perturb (sc->vpath);
|
||||
g_return_if_fail (sc != NULL);
|
||||
g_return_if_fail (tile_manager != NULL);
|
||||
|
||||
gimp_scan_convert_finish (sc);
|
||||
|
||||
svp = art_svp_from_vpath (pert_vpath);
|
||||
svp2 = art_svp_uncross (svp);
|
||||
svp3 = art_svp_rewind_uncrossed (svp2, ART_WIND_RULE_ODDEVEN);
|
||||
tile_manager_get_offsets (tile_manager, &x0, &y0);
|
||||
|
||||
pixel_region_init (&maskPR, gimp_drawable_data (GIMP_DRAWABLE (mask)),
|
||||
0, 0,
|
||||
gimp_item_width (GIMP_ITEM (mask)),
|
||||
gimp_item_height (GIMP_ITEM (mask)),
|
||||
pixel_region_init (&maskPR, tile_manager,
|
||||
x0, y0,
|
||||
tile_manager_width (tile_manager),
|
||||
tile_manager_height (tile_manager),
|
||||
TRUE);
|
||||
|
||||
g_return_val_if_fail (maskPR.bytes == 1, NULL);
|
||||
g_return_if_fail (maskPR.bytes == 1);
|
||||
|
||||
for (pr = pixel_regions_register (1, &maskPR);
|
||||
pr != NULL;
|
||||
pr = pixel_regions_process (pr))
|
||||
{
|
||||
art_gray_svp_aa (svp3, maskPR.x, maskPR.y,
|
||||
art_gray_svp_aa (sc->svp, maskPR.x, maskPR.y,
|
||||
maskPR.x + maskPR.w, maskPR.y + maskPR.h,
|
||||
maskPR.data, maskPR.rowstride);
|
||||
if (!sc->antialias)
|
||||
if (sc->antialias == FALSE)
|
||||
{
|
||||
/*
|
||||
* Ok, the user didn't want to have antialiasing, so just
|
||||
|
@ -249,13 +330,68 @@ gimp_scan_convert_to_channel (GimpScanConvert *sc,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
art_free (svp3);
|
||||
art_free (svp2);
|
||||
art_free (svp);
|
||||
|
||||
/* private function to convert the vpath to a svp when not using
|
||||
* gimp_scan_convert_stroke
|
||||
*/
|
||||
static void
|
||||
gimp_scan_convert_finish (GimpScanConvert *sc)
|
||||
{
|
||||
ArtVpath *pert_vpath;
|
||||
ArtSVP *svp, *svp2;
|
||||
|
||||
g_return_if_fail (sc->vpath != NULL);
|
||||
|
||||
/* gimp_scan_convert_stroke (sc, GIMP_JOIN_MITER, GIMP_CAP_BUTT, 15.0);
|
||||
*/
|
||||
|
||||
if (sc->svp)
|
||||
return; /* We already have a valid SVP */
|
||||
|
||||
/* Debug output of libart path */
|
||||
/* {
|
||||
* gint i;
|
||||
* for (i=0; i < sc->num_nodes + 1; i++)
|
||||
* {
|
||||
* g_printerr ("X: %f, Y: %f, Type: %d\n", sc->vpath[i].x,
|
||||
* sc->vpath[i].y,
|
||||
* sc->vpath[i].code );
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
if (sc->have_open)
|
||||
{
|
||||
gint i;
|
||||
for (i = 0; i < sc->num_nodes; i++)
|
||||
if (sc->vpath[i].code == ART_MOVETO_OPEN)
|
||||
{
|
||||
g_printerr ("Fixing ART_MOVETO_OPEN - result might be incorrect\n");
|
||||
sc->vpath[i].code = ART_MOVETO;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Current Libart (2.3.8) recommends a slight random distorsion
|
||||
* of the path, because art_svp_uncross and art_svp_rewind_uncrossed
|
||||
* are not yet numerically stable. It is actually possible to construct
|
||||
* worst case scenarios. The slight perturbation should not have any
|
||||
* visible effect.
|
||||
*/
|
||||
|
||||
pert_vpath = art_vpath_perturb (sc->vpath);
|
||||
|
||||
svp = art_svp_from_vpath (pert_vpath);
|
||||
art_free (pert_vpath);
|
||||
|
||||
mask->bounds_known = FALSE;
|
||||
svp2 = art_svp_uncross (svp);
|
||||
art_free (svp);
|
||||
|
||||
svp = art_svp_rewind_uncrossed (svp2, ART_WIND_RULE_ODDEVEN);
|
||||
art_free (svp2);
|
||||
|
||||
return mask;
|
||||
sc->svp = svp;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,22 +33,51 @@ GimpScanConvert * gimp_scan_convert_new (guint width,
|
|||
void gimp_scan_convert_free (GimpScanConvert *scan_converter);
|
||||
|
||||
/* Add "npoints" from "pointlist" to the polygon currently being
|
||||
* described by "scan_converter".
|
||||
* described by "scan_converter". DEPRECATED.
|
||||
*/
|
||||
void gimp_scan_convert_add_points (GimpScanConvert *scan_converter,
|
||||
guint n_points,
|
||||
GimpVector2 *points,
|
||||
gboolean new_polygon);
|
||||
|
||||
/* Add a polygon with "npoints" "points" that may be open or closed.
|
||||
* It is not recommended to mix gimp_scan_convert_add_polyline with
|
||||
* gimp_scan_convert_add_points.
|
||||
*
|
||||
* Please note that if you should use gimp_scan_convert_stroke() if you
|
||||
* specify open polygons.
|
||||
*/
|
||||
void gimp_scan_convert_add_polyline (GimpScanConvert *sc,
|
||||
guint n_points,
|
||||
GimpVector2 *points,
|
||||
gboolean closed);
|
||||
|
||||
/* Scan convert the polygon described by the list of points passed to
|
||||
* scan_convert_add_points, and return a channel with a bits set if
|
||||
* they fall within the polygon defined. The polygon is filled
|
||||
* according to the even-odd rule. The polygon is closed by
|
||||
* joining the final point to the initial point.
|
||||
/* Stroke the content of a GimpScanConvert. The next
|
||||
* gimp_scan_convert_to_channel will result in the outline of the polygon
|
||||
* defined with the commands above.
|
||||
*
|
||||
* You cannot add additional polygons after this command.
|
||||
*/
|
||||
|
||||
void gimp_scan_convert_stroke (GimpScanConvert *sc,
|
||||
GimpJoinType join,
|
||||
GimpCapType cap,
|
||||
gdouble width);
|
||||
|
||||
/* Return a new Channel according to the polygonal shapes defined with
|
||||
* the commands above.
|
||||
*
|
||||
* You cannot add additional polygons after this command.
|
||||
*/
|
||||
GimpChannel * gimp_scan_convert_to_channel (GimpScanConvert *scan_converter,
|
||||
GimpImage *gimage);
|
||||
|
||||
|
||||
/* This is a more low level version. Expects a tile manager of depth 1.
|
||||
*
|
||||
* You cannot add additional polygons after this command.
|
||||
*/
|
||||
|
||||
void gimp_scan_convert_render (GimpScanConvert *scan_converter,
|
||||
TileManager *tile_manager);
|
||||
#endif /* __GIMP_SCAN_CONVERT_H__ */
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <libart_lgpl/libart.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "libgimpmath/gimpmath.h"
|
||||
|
@ -120,8 +118,6 @@ static void gimp_bezier_coords_subdivide2 (const GimpCoords *beziercoords,
|
|||
static gboolean gimp_bezier_coords_is_straight (const GimpCoords *beziercoords,
|
||||
const gdouble precision);
|
||||
|
||||
static void gimp_bezier_stroke_art_stroke (const GimpStroke *stroke);
|
||||
|
||||
|
||||
/* private variables */
|
||||
|
||||
|
@ -185,7 +181,6 @@ gimp_bezier_stroke_class_init (GimpBezierStrokeClass *klass)
|
|||
stroke_class->extend = gimp_bezier_stroke_extend;
|
||||
stroke_class->connect_stroke = gimp_bezier_stroke_connect_stroke;
|
||||
stroke_class->interpolate = gimp_bezier_stroke_interpolate;
|
||||
stroke_class->art_stroke = gimp_bezier_stroke_art_stroke;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1919,10 +1914,3 @@ gimp_bezier_coords_subdivide2 (const GimpCoords *beziercoords,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_bezier_stroke_art_stroke (const GimpStroke *stroke)
|
||||
{
|
||||
g_printerr ("gimp_bezier_stroke_art_stroke: implement me!\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <libart_lgpl/libart.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "vectors-types.h"
|
||||
|
@ -150,8 +148,6 @@ static GArray * gimp_stroke_real_get_draw_lines (const GimpStroke *stroke);
|
|||
static GArray * gimp_stroke_real_control_points_get (const GimpStroke *stroke,
|
||||
gboolean *ret_closed);
|
||||
|
||||
static void gimp_stroke_art_stroke (const GimpStroke *stroke);
|
||||
|
||||
/* private variables */
|
||||
|
||||
static GimpObjectClass *parent_class = NULL;
|
||||
|
@ -246,8 +242,6 @@ gimp_stroke_class_init (GimpStrokeClass *klass)
|
|||
klass->get_draw_lines = gimp_stroke_real_get_draw_lines;
|
||||
klass->control_points_get = gimp_stroke_real_control_points_get;
|
||||
|
||||
klass->art_stroke = gimp_stroke_art_stroke;
|
||||
|
||||
anchor_param_spec = g_param_spec_boxed ("gimp-anchor",
|
||||
"Gimp Anchor",
|
||||
"The control points of a Stroke",
|
||||
|
@ -1202,13 +1196,3 @@ gimp_stroke_real_control_points_get (const GimpStroke *stroke,
|
|||
return ret_array;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gimp_stroke_art_stroke (const GimpStroke *stroke)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_STROKE (stroke));
|
||||
|
||||
GIMP_STROKE_GET_CLASS (stroke)->art_stroke (stroke);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <libart_lgpl/libart.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "vectors-types.h"
|
||||
|
@ -33,7 +31,14 @@
|
|||
#include "core/gimpmarshal.h"
|
||||
#include "core/gimppaintinfo.h"
|
||||
|
||||
#include "paint/gimppaintcore-stroke.h"
|
||||
#undef LIBART_STROKE
|
||||
|
||||
#ifdef LIBART_STROKE
|
||||
# include "libgimpcolor/gimpcolor.h"
|
||||
# include "core/gimpdrawable-stroke.h"
|
||||
#else
|
||||
# include "paint/gimppaintcore-stroke.h"
|
||||
#endif
|
||||
|
||||
#include "gimpanchor.h"
|
||||
#include "gimpstroke.h"
|
||||
|
@ -540,6 +545,7 @@ gimp_vectors_stroke (GimpItem *item,
|
|||
GimpVectors *vectors;
|
||||
GimpPaintCore *core;
|
||||
gboolean retval;
|
||||
GimpRGB color;
|
||||
|
||||
vectors = GIMP_VECTORS (item);
|
||||
|
||||
|
@ -549,6 +555,14 @@ gimp_vectors_stroke (GimpItem *item,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef LIBART_STROKE
|
||||
gimp_rgba_set (&color, 0.0, 0.7, 0.5, 1.0);
|
||||
|
||||
gimp_drawable_stroke_vectors (drawable, vectors, 0.5, &color,
|
||||
GIMP_NORMAL_MODE, 15, GIMP_JOIN_MITER,
|
||||
GIMP_CAP_SQUARE, TRUE);
|
||||
retval = TRUE;
|
||||
#else
|
||||
core = g_object_new (paint_info->paint_type, NULL);
|
||||
|
||||
retval = gimp_paint_core_stroke_vectors (core, drawable,
|
||||
|
@ -556,6 +570,7 @@ gimp_vectors_stroke (GimpItem *item,
|
|||
vectors);
|
||||
|
||||
g_object_unref (core);
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -1000,30 +1015,3 @@ gimp_vectors_real_make_bezier (const GimpVectors *vectors)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* gimp_vectors_art_stroke: Stroke a GimpVectors object using libart.
|
||||
* @vectors: The source path
|
||||
*
|
||||
* Traverses the stroke list of a GimpVector object, calling art_stroke
|
||||
* on each stroke as we go. Will eventually take cap type, join type
|
||||
* and width as arguments.
|
||||
*/
|
||||
void
|
||||
gimp_vectors_art_stroke (const GimpVectors *vectors)
|
||||
{
|
||||
GimpStroke *cur_stroke;
|
||||
|
||||
/* For each Stroke in the vector, stroke it */
|
||||
|
||||
for (cur_stroke = gimp_vectors_stroke_get_next (vectors, NULL);
|
||||
cur_stroke;
|
||||
cur_stroke = gimp_vectors_stroke_get_next (vectors, cur_stroke))
|
||||
{
|
||||
/* Add this stroke to the art_vpath */
|
||||
GIMP_STROKE_GET_CLASS(cur_stroke)->art_stroke (cur_stroke);
|
||||
}
|
||||
|
||||
/* That's it - nothing else to see here */
|
||||
return;
|
||||
|
||||
}
|
||||
|
|
|
@ -170,7 +170,4 @@ gint gimp_vectors_interpolate (const GimpVectors *vectors,
|
|||
|
||||
GimpVectors * gimp_vectors_make_bezier (const GimpVectors *vectors);
|
||||
|
||||
/* Stroke a vector with libart (needs a better name) */
|
||||
void gimp_vectors_art_stroke(const GimpVectors * vectors);
|
||||
|
||||
#endif /* __GIMP_VECTORS_H__ */
|
||||
|
|
Loading…
Reference in New Issue