configure.in app/Makefile.am We depend on Libart now.

2002-03-06  Simon Budig  <simon@gimp.org>

        * configure.in
        * app/Makefile.am
        * app/core/Makefile.am: We depend on Libart now.

        * app/core/gimpscanconvert.c: Converted the Scan-Conversion to
        use libart. *Way* better results.
This commit is contained in:
Simon Budig 2002-03-06 20:25:31 +00:00 committed by Simon Budig
parent 5940d5795f
commit 68f03aa0af
5 changed files with 92 additions and 205 deletions

View File

@ -1,3 +1,12 @@
2002-03-06 Simon Budig <simon@gimp.org>
* configure.in
* app/Makefile.am
* app/core/Makefile.am: We depend on Libart now.
* app/core/gimpscanconvert.c: Converted the Scan-Conversion to
use libart. *Way* better results.
2002-03-06 Sven Neumann <sven@gimp.org>
* app/core/gimpbrushpipe.c

View File

@ -135,6 +135,7 @@ gimp_1_3_LDADD = @STRIP_BEGIN@ \
$(top_builddir)/libgimpwidgets/libgimpwidgets-$(LT_RELEASE).la \
$(GTK_LIBS) \
$(PANGOFT2_LIBS) \
$(LIBART_LIBS) \
$(GIMP_THREAD_LIBS) \
$(GIMP_MP_LIBS) \
$(INTLLIBS) \

View File

@ -11,6 +11,7 @@ INCLUDES = @STRIP_BEGIN@ \
-I$(top_srcdir) \
-I$(top_srcdir)/app \
$(GTK_CFLAGS) \
$(LIBART_CFLAGS) \
-I$(includedir) \
@STRIP_END@

View File

@ -22,6 +22,14 @@
#include <glib-object.h>
#include <libart_lgpl/art_gray_svp.h>
#include <libart_lgpl/art_misc.h>
#include <libart_lgpl/art_pathcode.h>
#include <libart_lgpl/art_svp.h>
#include <libart_lgpl/art_svp_vpath.h>
#include <libart_lgpl/art_svp_wind.h>
#include <libart_lgpl/art_vpath.h>
#include "libgimpmath/gimpmath.h"
#include "core-types.h"
@ -33,113 +41,25 @@
#include "gimpscanconvert.h"
#ifdef DEBUG
#define TRC(x) printf x
#else
#define TRC(x)
#endif
struct _GimpScanConvert
{
guint width;
guint height;
GSList **scanlines; /* array of height*antialias scanlines */
guint antialias; /* how much to oversample by */
/* currently only used as boolean value */
/* record the first and last points so we can close the curve */
gboolean got_first;
GimpVector2 first;
gboolean got_last;
GimpVector2 last;
guint num_nodes;
ArtVpath *vpath;
};
/* Local helper routines to scan convert the polygon */
static GSList *
insert_into_sorted_list (GSList *list,
gint x)
{
GSList *orig = list;
GSList *next;
if (!list)
return g_slist_prepend (list, GINT_TO_POINTER (x));
while (list)
{
next = g_slist_next (list);
if (x < GPOINTER_TO_INT (list->data))
{
next = g_slist_prepend (next, list->data);
list->next = next;
list->data = GINT_TO_POINTER (x);
return orig;
}
else if (!next)
{
g_slist_append (list, GINT_TO_POINTER (x));
return orig;
}
list = g_slist_next (list);
}
return orig;
}
static void
convert_segment (GimpScanConvert *sc,
gint x1,
gint y1,
gint x2,
gint y2)
{
gint ydiff, y;
gint width;
gint height;
GSList **scanlines;
gfloat xinc, x;
/* pre-calculate invariant commonly used values */
width = sc->width * sc->antialias;
height = sc->height * sc->antialias;
scanlines = sc->scanlines;
ydiff = y2 - y1;
if (ydiff)
{
if (ydiff < 0)
{
gint tmp;
tmp = y2; y2 = y1; y1 = tmp;
tmp = x2; x2 = x1; x1 = tmp;
ydiff = - ydiff;
}
/* FIXME: using Bresenham here would probably be more appropriate */
xinc = (float) (x2 - x1) / (float) ydiff;
x = x1 + 0.5 * xinc;
for (y = y1 ; y < y2; y++)
{
if (y >= 0 && y < height)
scanlines[y] = insert_into_sorted_list (scanlines[y],
CLAMP (ROUND (x),
0, width));
x += xinc;
}
}
}
/* public functions */
GimpScanConvert *
@ -158,7 +78,9 @@ gimp_scan_convert_new (guint width,
sc->antialias = antialias;
sc->width = width;
sc->height = height;
sc->scanlines = g_new0 (GSList *, height * antialias);
sc->num_nodes = 0;
sc->vpath = NULL;
return sc;
}
@ -166,12 +88,7 @@ gimp_scan_convert_new (guint width,
void
gimp_scan_convert_free (GimpScanConvert *sc)
{
gint i;
for (i = 0; i < sc->height * sc->antialias; i++)
g_slist_free (sc->scanlines[i]);
g_free (sc->scanlines);
art_free (sc->vpath);
g_free (sc);
}
@ -197,31 +114,16 @@ gimp_scan_convert_add_points (GimpScanConvert *sc,
sc->first = points[0];
}
/* link from previous point */
if (sc->got_last && n_points > 0)
{
TRC (("|| %g,%g -> %g,%g\n",
sc->last.x, sc->last.y,
points[0].x, points[0].y));
convert_segment (sc,
(gint) sc->last.x * antialias,
(gint) sc->last.y * antialias,
(gint) points[0].x * antialias,
(gint) points[0].y * antialias);
}
/* We need up to two extra nodes later to close and finish the path */
sc->vpath = art_renew (sc->vpath, ArtVpath, sc->num_nodes + n_points + 2);
for (i = 0; i < (n_points - 1); i++)
for (i = 0; i < n_points; i++)
{
convert_segment (sc,
(gint) points[i].x * antialias,
(gint) points[i].y * antialias,
(gint) points[i + 1].x * antialias,
(gint) points[i + 1].y * antialias);
sc->vpath[sc->num_nodes + i].code = (sc->num_nodes + i) ? ART_LINETO : ART_MOVETO;
sc->vpath[sc->num_nodes + i].x = points[i].x;
sc->vpath[sc->num_nodes + i].y = points[i].y;
}
TRC (("[] %g,%g -> %g,%g\n",
points[0].x, points[0].y,
points[n_points-1].x, points[n_points-1].y));
sc->num_nodes += n_points;
if (n_points > 0)
{
@ -242,112 +144,82 @@ gimp_scan_convert_to_channel (GimpScanConvert *sc,
GimpImage *gimage)
{
GimpChannel *mask;
GSList *list;
PixelRegion maskPR;
guint widtha;
guint heighta;
guint antialias;
guint antialias2;
guchar *buf;
guchar *b;
gint *vals;
gint val;
gint x, w;
gint i, j;
antialias = sc->antialias;
antialias2 = antialias * antialias;
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))
{
convert_segment (sc,
(gint) sc->last.x * antialias,
(gint) sc->last.y * antialias,
(gint) sc->first.x * antialias,
(gint) sc->first.y * antialias);
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);
buf = g_new0 (guchar, sc->width);
widtha = sc->width * antialias;
heighta = sc->height * antialias;
/* allocate value array */
vals = g_new (gint, widtha);
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++;
/* dump scanlines */
for (i = 0; i < heighta; i++)
{
list = sc->scanlines[i];
TRC (("%03d: ", i));
while (list)
{
TRC (("%3d ", GPOINTER_TO_INT (list->data)));
list = g_slist_next (list);
}
TRC (("\n"));
}
/*
* 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);
svp2 = art_svp_uncross (svp);
svp3 = art_svp_rewind_uncrossed (svp2, ART_WIND_RULE_ODDEVEN);
pixel_region_init (&maskPR, gimp_drawable_data (GIMP_DRAWABLE (mask)), 0, 0,
gimp_drawable_width (GIMP_DRAWABLE (mask)),
gimp_drawable_height (GIMP_DRAWABLE (mask)), TRUE);
for (i = 0; i < heighta; i++)
g_return_val_if_fail (maskPR.bytes == 1, NULL);
for (pr = pixel_regions_register (1, &maskPR);
pr != NULL;
pr = pixel_regions_process (pr))
{
list = sc->scanlines[i];
art_gray_svp_aa (svp3, maskPR.x, maskPR.y,
maskPR.x + maskPR.w, maskPR.y + maskPR.h,
maskPR.data, maskPR.rowstride);
if (!sc->antialias)
{
/*
* Ok, the user didn't want to have antialiasing, so just
* remove the results from lots of CPU-Power...
*/
dest = maskPR.data;
/* zero the vals array */
if (!(i % antialias))
memset (vals, 0, widtha * sizeof (int));
while (list)
{
x = GPOINTER_TO_INT (list->data);
list = g_slist_next (list);
if (!list)
{
g_message ("Cannot properly scanline convert polygon!\n");
}
else
{
w = GPOINTER_TO_INT (list->data) - x;
if (w > 0)
{
if (antialias == 1)
{
gimp_channel_add_segment (mask, x, i, w, 255);
}
else
{
for (j = 0; j < w; j++)
vals[j + x] += 255;
}
}
list = g_slist_next (list);
}
}
if (antialias != 1 && !((i+1) % antialias))
{
b = buf;
for (j = 0; j < widtha; j += antialias)
{
val = 0;
for (x = 0; x < antialias; x++)
val += vals[j + x];
*b++ = (guchar) (val / antialias2);
}
pixel_region_set_row (&maskPR, 0, (i / antialias), sc->width, buf);
}
for (j = 0; j < maskPR.h; j++)
{
d = dest;
for (i = 0; i < maskPR.w; i++)
{
d[0] = (d[0] >= 127) ? 255 : 0;
d += maskPR.bytes;
}
dest += maskPR.rowstride;
}
}
}
g_free (vals);
g_free (buf);
art_free (svp3);
art_free (svp2);
art_free (svp);
art_free (pert_vpath);
return mask;
}

View File

@ -136,6 +136,7 @@ AM_PATH_GTK_2_0($GTK_REQUIRED_VERSION,,
PKG_CHECK_MODULES(PANGOFT2, pangoft2 >= $PANGOFT2_REQUIRED_VERSION)
PKG_CHECK_MODULES(LIBART, libart-2.0)
if eval "test x$GCC = xyes"; then
case " $CFLAGS " in
@ -793,6 +794,9 @@ AC_SUBST(X_LIBS)
AC_SUBST(PANGOFT2_CFLAGS)
AC_SUBST(PANGOFT2_LIBS)
AC_SUBST(LIBART_CFLAGS)
AC_SUBST(LIBART_LIBS)
AC_SUBST(PKG_CONFIG)
AC_SUBST(HAVE_GLIBC_REGEX)