summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2004-09-25 01:10:01 +0000
committerKeith Packard <keithp@keithp.com>2004-09-25 01:10:01 +0000
commit5655b42ba2abd6321a9319f6751df187eebb1d3a (patch)
tree448d542f303d576d314f5e4ecd423a18562edc8e
parent04304578ca34a7e1da5582f231a44515226f7d38 (diff)
Add convex hull algorithm from cairo sources. Used to constrain pens to
convex shapes so that the convolution algorithm works correctly. Reduce default tolerance to 1/16 of a pixel Use convex hull of pen. Snap horizontal and vertical elements of glyphs to pixel boundaries. Snap stem widths to integer amounts. Add slanting and emboldening Add space and box Avoid using __inline as it increases size dramatically Use <= tolerance_squared as that may be zero Swizzle code to show off recent changes
-rw-r--r--ChangeLog37
-rw-r--r--Makefile.am1
-rw-r--r--twin.h27
-rw-r--r--twin_convolve.c8
-rw-r--r--twin_font.c194
-rw-r--r--twin_glyphs.c31
-rw-r--r--twin_hull.c244
-rw-r--r--twin_primitive.c2
-rw-r--r--twin_spline.c2
-rw-r--r--xtwin.c63
10 files changed, 534 insertions, 75 deletions
diff --git a/ChangeLog b/ChangeLog
index d1b1c0e..603bae1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2004-09-24 Keith Packard <keithp@keithp.com>
+
+ * Makefile.am:
+ * twin_hull.c: (_twin_slope_init), (_twin_hull_create),
+ (_twin_slope_compare), (_twin_hull_vertex_compare),
+ (_twin_hull_prev_valid), (_twin_hull_next_valid),
+ (_twin_hull_eliminate_concave), (_twin_hull_to_path),
+ (twin_path_convex_hull):
+ Add convex hull algorithm from cairo sources. Used to
+ constrain pens to convex shapes so that the convolution
+ algorithm works correctly.
+
+ * twin.h:
+ Reduce default tolerance to 1/16 of a pixel
+
+ * twin_convolve.c: (_angle), (_twin_subpath_convolve),
+ (twin_path_convolve):
+ Use convex hull of pen.
+
+ * twin_font.c: (compare_snap), (_snap), (_add_snap),
+ (twin_path_glyph), (twin_glyph_width), (twin_path_string):
+ Snap horizontal and vertical elements of glyphs to
+ pixel boundaries. Snap stem widths to integer amounts.
+ Add slanting and emboldening
+
+ * twin_glyphs.c:
+ Add space and box
+
+ * twin_primitive.c:
+ Avoid using __inline as it increases size dramatically
+
+ * twin_spline.c: (_twin_spline_decompose):
+ Use <= tolerance_squared as that may be zero
+
+ * xtwin.c: (main):
+ Swizzle code to show off recent changes
+
2004-09-23 Keith Packard <keithp@keithp.com>
* Makefile.am:
diff --git a/Makefile.am b/Makefile.am
index e0afcab..f1b6c60 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,6 +20,7 @@ xtwin_SOURCES = \
twin_convolve.c \
twin_draw.c \
twin_glyphs.c \
+ twin_hull.c \
twin_font.c \
twin_geom.c \
twin_path.c \
diff --git a/twin.h b/twin.h
index aa4fff8..1eea7ca 100644
--- a/twin.h
+++ b/twin.h
@@ -47,7 +47,7 @@ typedef int32_t twin_dfixed_t;
#define TWIN_FIXED_ONE (0x10)
#define TWIN_FIXED_HALF (0x08)
-#define TWIN_FIXED_TOLERANCE (TWIN_FIXED_HALF)
+#define TWIN_FIXED_TOLERANCE (1)
#define TWIN_FALSE 0
#define TWIN_TRUE 1
@@ -213,13 +213,25 @@ twin_bool_t
twin_has_glyph (int glyph);
void
-twin_path_glyph (twin_path_t *path, int glyph);
+twin_path_glyph (twin_path_t *path,
+ twin_fixed_t scale_x,
+ twin_fixed_t scale_y,
+ int style,
+ int glyph);
int
-twin_glyph_width (int glyph);
+twin_glyph_width (int glyph, twin_fixed_t scale_x);
+
+#define TWIN_TEXT_ROMAN 0
+#define TWIN_TEXT_BOLD 1
+#define TWIN_TEXT_OBLIQUE 2
void
-twin_path_string (twin_path_t *path, unsigned char *string);
+twin_path_string (twin_path_t *path,
+ twin_fixed_t scale_x,
+ twin_fixed_t scale_y,
+ int style,
+ unsigned char *string);
void
twin_path_ucs4 (twin_path_t *path, twin_fixed_t scale_x,
@@ -230,6 +242,13 @@ twin_path_utf8 (twin_path_t *path, twin_fixed_t scale_x, twin_fixed_t scale_y,
const char *string);
/*
+ * twin_hull.c
+ */
+
+twin_path_t *
+twin_path_convex_hull (twin_path_t *path);
+
+/*
* twin_path.c
*/
diff --git a/twin_convolve.c b/twin_convolve.c
index 0010a22..cbddb9f 100644
--- a/twin_convolve.c
+++ b/twin_convolve.c
@@ -110,7 +110,6 @@ _around_order (twin_point_t *a1,
#define F(x) twin_fixed_to_double(x)
#define DBGOUT(x...) printf(x)
-#if 0
static double
_angle (twin_point_t *a, twin_point_t *b)
{
@@ -121,7 +120,6 @@ _angle (twin_point_t *a, twin_point_t *b)
rad = atan2 ((double) dy, (double) dx);
return rad * 180 / M_PI;
}
-#endif
#else
#define DBGOUT(x...)
#endif
@@ -190,12 +188,10 @@ _twin_subpath_convolve (twin_path_t *path,
* step along pen (forwards or backwards) or stroke as appropriate
*/
-#if 0
DBGOUT ("\tangles: stroke %9.4f +pen %9.4f -pen %9.4f\n",
_angle (&sp[s], &sp[sn]),
_angle (&pp[p], &pp[pn]),
_angle (&pp[pm], &pp[p]));
-#endif
if (_around_order (&sp[s],&sp[sn],&pp[p],&pp[pn]) > 0)
{
DBGOUT ("+pen: ");
@@ -261,6 +257,7 @@ twin_path_convolve (twin_path_t *path,
{
int p;
int s;
+ twin_path_t *hull = twin_path_convex_hull (pen);
p = 0;
for (s = 0; s <= stroke->nsublen; s++)
@@ -281,8 +278,9 @@ twin_path_convolve (twin_path_t *path,
subpath.npoints = npoints;
subpath.sublen = 0;
subpath.nsublen = 0;
- _twin_subpath_convolve (path, &subpath, pen);
+ _twin_subpath_convolve (path, &subpath, hull);
p = sublen;
}
}
+ twin_path_destroy (hull);
}
diff --git a/twin_font.c b/twin_font.c
index bb90dcf..b7e9424 100644
--- a/twin_font.c
+++ b/twin_font.c
@@ -28,7 +28,9 @@
#define F(x) twin_fixed_to_double(x)
-#define S(x) (twin_int_to_fixed (x) / 2)
+#define S(f,s) ((twin_fixed_t) ((((twin_dfixed_t) (f) * (s)) >> 5)))
+#define SX(x) (((x) * scale_x) >> 5)
+#define SY(y) (((y) * scale_y) >> 5)
twin_bool_t
twin_has_glyph (int glyph)
@@ -36,52 +38,216 @@ twin_has_glyph (int glyph)
return _twin_font[glyph] != NULL;
}
+static int
+compare_snap (const void *av, const void *bv)
+{
+ const twin_gfixed_t *a = av;
+ const twin_gfixed_t *b = bv;
+
+ return (int) (*a - *b);
+}
+
+#define SNAPI(p) (((p) + 0x7) & ~0xf)
+#define SNAPH(p) (((p) + 0x3) & ~0x7)
+
+static twin_fixed_t
+_snap (twin_gfixed_t g, twin_fixed_t scale, twin_gfixed_t *snap, int nsnap)
+{
+ int s;
+ twin_fixed_t v;
+
+ v = S(g, scale);
+ for (s = 0; s < nsnap - 1; s++)
+ {
+ if (snap[s] <= g && g <= snap[s+1])
+ {
+ twin_fixed_t before = S(snap[s],scale);
+ twin_fixed_t after = S(snap[s+1],scale);
+ twin_fixed_t dist = after - before;
+ twin_fixed_t snap_before = SNAPI(before);
+ twin_fixed_t snap_after = SNAPI(after);
+ twin_fixed_t move_before = snap_before - before;
+ twin_fixed_t move_after = snap_after - after;
+ twin_fixed_t dist_before = v - before;
+ twin_fixed_t dist_after = after - v;
+ twin_fixed_t move = ((twin_dfixed_t) dist_before * move_after +
+ (twin_dfixed_t) dist_after * move_before) / dist;
+#if 0
+ printf ("%d <= %d <= %d\n", snap[s], g, snap[s+1]);
+ printf ("%9.4f <= %9.4f <= %9.4f\n", F(before), F(v), F(after));
+ printf ("before: %9.4f -> %9.4f\n", F(before), F(snap_before));
+ printf ("after: %9.4f -> %9.4f\n", F(after), F(snap_after));
+ printf ("v: %9.4f -> %9.4f\n", F(v), F(v+move));
+#endif
+ v += move;
+ break;
+ }
+ }
+#if 0
+ printf ("_snap: %d => %9.4f\n", g, F(v));
+#endif
+ return v;
+}
+
+#define SNAPX(p) _snap (p, scale_x, snap_x, nsnap_x)
+#define SNAPY(p) _snap (p, scale_y, snap_y, nsnap_y)
+
+static int
+_add_snap (twin_gfixed_t *snaps, int nsnap, twin_fixed_t snap)
+{
+ int s;
+
+ for (s = 0; s < nsnap; s++)
+ if (snaps[s] == snap)
+ return nsnap;
+ snaps[nsnap++] = snap;
+ return nsnap;
+}
+
void
-twin_path_glyph (twin_path_t *path, int glyph)
+twin_path_glyph (twin_path_t *path,
+ twin_fixed_t scale_x,
+ twin_fixed_t scale_y,
+ int style,
+ int glyph)
{
const twin_gpoint_t *p = _twin_font[glyph];
int i;
twin_fixed_t xo, yo;
twin_fixed_t xc, yc;
+ twin_path_t *stroke;
+ twin_path_t *pen;
+ twin_fixed_t pen_size;
+ twin_fixed_t pen_adjust;
+ twin_gfixed_t *snap_x, *snap_y;
+ int nsnap_x, nsnap_y;
+ int npoints;
if (!p)
return;
twin_path_cur_point (path, &xo, &yo);
- twin_path_close (path);
- xc = xo - S (p[0].x);
- yc = yo - S (16);
+ for (i = 1; p[i].y != -64; i++)
+ ;
+
+ npoints = i - 1 + 3;
+
+ snap_x = malloc ((npoints * 2) * sizeof (twin_gfixed_t));
+ snap_y = snap_x + npoints;
+
+ nsnap_x = 0;
+ nsnap_y = 0;
+
+ /* snap left and right boundaries */
+
+ nsnap_x = _add_snap (snap_x, nsnap_x, p[0].x);
+ nsnap_x = _add_snap (snap_x, nsnap_x, p[0].y);
+
+ /* snap baseline, x height and cap height */
+ nsnap_y = _add_snap (snap_y, nsnap_y, 9);
+ nsnap_y = _add_snap (snap_y, nsnap_y, -5);
+ nsnap_y = _add_snap (snap_y, nsnap_y, -12);
+
+ /*
+ * Locate horizontal and vertical segments
+ */
+ for (i = 1; p[i].y != -64 && p[i+1].y != -64; i++)
+ {
+ if (p[i].x == -64 || p[i+1].x == -64)
+ continue;
+ if (p[i].x == p[i+1].x)
+ nsnap_x = _add_snap (snap_x, nsnap_x, p[i].x);
+ if (p[i].y == p[i+1].y)
+ nsnap_y = _add_snap (snap_y, nsnap_y, p[i].y);
+ }
+
+ qsort (snap_x, nsnap_x, sizeof (twin_gfixed_t), compare_snap);
+ qsort (snap_y, nsnap_y, sizeof (twin_gfixed_t), compare_snap);
+
+#if 0
+ printf ("snap_x:");
+ for (i = 0; i < nsnap_x; i++)
+ printf (" %d", snap_x[i]);
+ printf ("\n");
+
+ printf ("snap_y:");
+ for (i = 0; i < nsnap_y; i++)
+ printf (" %d", snap_y[i]);
+ printf ("\n");
+#endif
+
+ stroke = twin_path_create ();
+
+ /* snap pen size to half integer value */
+ if (style & TWIN_TEXT_BOLD)
+ pen_size = SNAPH(scale_y / 12);
+ else
+ pen_size = SNAPH(scale_y / 24);
+
+ if (pen_size < TWIN_FIXED_HALF)
+ pen_size = TWIN_FIXED_HALF;
+
+ pen_adjust = pen_size & TWIN_FIXED_HALF;
+
+ pen = twin_path_create ();
+ twin_path_circle (pen, pen_size);
+
+ xc = SNAPI(xo - SX (p[0].x)) + pen_adjust;
+ yc = SNAPI(yo - SY (16)) + pen_adjust;
for (i = 1; p[i].y != -64; i++)
if (p[i].x == -64)
- twin_path_close (path);
+ twin_path_close (stroke);
else
- twin_path_draw (path,
- xc + S (p[i].x),
- yc + S (p[i].y));
+ {
+ twin_fixed_t x = SNAPX(p[i].x);
+ twin_fixed_t y = SNAPY(p[i].y);
+
+ if (style & TWIN_TEXT_OBLIQUE)
+ x -= y / 4;
+ twin_path_draw (stroke, x + xc, y + yc);
+ }
+
+ twin_path_convolve (path, stroke, pen);
+ twin_path_destroy (stroke);
+ twin_path_destroy (pen);
+
+ free (snap_x);
- xo = xo + twin_glyph_width (glyph);
+ xo = xo + twin_glyph_width (glyph, scale_x);
twin_path_move (path, xo, yo);
}
int
-twin_glyph_width (int glyph)
+twin_glyph_width (int glyph, twin_fixed_t scale_x)
{
const twin_gpoint_t *p = _twin_font[glyph];
if (!p)
return 0;
- return twin_fixed_ceil (S (p[0].y) - S (p[0].x));
+ return twin_fixed_ceil (SX (p[0].y) - SX (p[0].x));
}
extern const uint16_t _twin_unicode[];
void
-twin_path_string (twin_path_t *path, unsigned char *string)
+twin_path_string (twin_path_t *path,
+ twin_fixed_t scale_x,
+ twin_fixed_t scale_y,
+ int style,
+ unsigned char *string)
{
-
+ unsigned char c;
+
+ while ((c = *string++))
+ {
+ uint16_t g = _twin_unicode[c];
+
+ if (g)
+ twin_path_glyph (path, scale_x, scale_y, style, g);
+ }
}
extern twin_font_t twin_Bitstream_Vera_Sans_Roman;
diff --git a/twin_glyphs.c b/twin_glyphs.c
index 632371f..d3fdd03 100644
--- a/twin_glyphs.c
+++ b/twin_glyphs.c
@@ -57166,8 +57166,23 @@ static const twin_gpoint_t g2268[] = {
{ -64, -64 },
};
+static const twin_gpoint_t g0000[] = {
+ { -9, 9 },
+ { -9, 9 },
+ { -9, 12 },
+ { 9, -12 },
+ { 9, 9 },
+ { -9, 9 },
+ { -64, -64 },
+};
+
+static const twin_gpoint_t g0500[] = {
+ { -4, 4 },
+ { -64, -64 },
+};
+
const twin_gpoint_t *_twin_font[] = {
- 0, g0001, g0002, g0003, g0004, g0005, g0006, g0007,
+g0000, g0001, g0002, g0003, g0004, g0005, g0006, g0007,
g0008, g0009, g0010, g0011, g0012, g0013, g0014, g0015,
g0016, g0017, g0018, g0019, g0020, g0021, g0022, g0023,
g0024, g0025, g0026, g0027, g0028, g0029, g0030, g0031,
@@ -57229,7 +57244,7 @@ g0232, g0233, g0234, g0235, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, g0501, g0502, g0503,
+ 0, 0, 0, 0, g0500, g0501, g0502, g0503,
g0504, g0505, g0506, g0507, g0508, g0509, g0510, g0511,
g0512, g0513, g0514, g0515, g0516, g0517, g0518, g0519,
g0520, g0521, g0522, g0523, g0524, g0525, g0526, g0527,
@@ -57709,16 +57724,6 @@ g4304, g4305, g4306, g4307, g4308, g4309, g4310, g4311,
g4312, g4313, g4314, g4315, g4316, g4317, g4318, g4319,
g4320, g4321, g4322, g4323, g4324, g4325, g4326, };
-static const twin_gpoint_t g0000[] = {
- { -9, 9 },
- { -9, 9 },
- { -9, 12 },
- { 9, -12 },
- { 9, 9 },
- { -9, 9 },
- { -64, -64 },
-};
-
const uint16_t _twin_unicode[] = {
000, 000, 000, 000, 000, 000, 000, 000, /* 0x0000 */
000, 000, 000, 000, 000, 000, 000, 000,
@@ -57726,7 +57731,7 @@ const uint16_t _twin_unicode[] = {
000, 000, 000, 000, 000, 000, 000, 000, /* 0x0010 */
000, 000, 000, 000, 000, 000, 000, 000,
- 000, 000, 000, 000, 000, 000, 000, 000, /* 0x0020 */
+ 500, 000, 000, 000, 000, 000, 000, 000, /* 0x0020 */
000, 000, 000, 000, 000, 000, 000, 000,
700, 701, 702, 703, 704, 705, 706, 707, /* 0x0030 */
diff --git a/twin_hull.c b/twin_hull.c
new file mode 100644
index 0000000..0774821
--- /dev/null
+++ b/twin_hull.c
@@ -0,0 +1,244 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2003 Carl Worth
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Carl Worth not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Carl Worth makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * CARL WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "twinint.h"
+
+typedef struct twin_slope {
+ twin_fixed_t dx;
+ twin_fixed_t dy;
+} twin_slope_t, twin_distance_t;
+
+typedef struct _twin_hull {
+ twin_point_t point;
+ twin_slope_t slope;
+ int discard;
+} twin_hull_t;
+
+static void
+_twin_slope_init (twin_slope_t *slope, twin_point_t *a, twin_point_t *b)
+{
+ slope->dx = b->x - a->x;
+ slope->dy = b->y - a->y;
+}
+
+static twin_hull_t *
+_twin_hull_create (twin_path_t *path, int *nhull)
+{
+ int i, j;
+ int n = path->npoints;
+ twin_point_t *p = path->points;
+ twin_hull_t *hull;
+ int e;
+
+ e = 0;
+ for (i = 1; i < n; i++)
+ if (p[i].y < p[e].y || (p[i].y == p[e].y && p[i].x < p[e].x))
+ e = i;
+
+ hull = malloc (n * sizeof (twin_hull_t));
+ if (hull == NULL)
+ return NULL;
+ *nhull = n;
+
+ for (i = 0; i < n; i++)
+ {
+ /* place extremum first in array */
+ if (i == 0) j = e;
+ else if (i == e) j = 0;
+ else j = i;
+
+ hull[i].point = p[j];
+ _twin_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
+
+ /* Discard all points coincident with the extremal point */
+ if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
+ hull[i].discard = 1;
+ else
+ hull[i].discard = 0;
+ }
+
+ return hull;
+}
+
+/* Compare two slopes. Slope angles begin at 0 in the direction of the
+ positive X axis and increase in the direction of the positive Y
+ axis.
+
+ WARNING: This function only gives correct results if the angular
+ difference between a and b is less than PI.
+
+ < 0 => a less positive than b
+ == 0 => a equal to be
+ > 0 => a more positive than b
+*/
+static int
+_twin_slope_compare (twin_slope_t *a, twin_slope_t *b)
+{
+ twin_dfixed_t diff;
+
+ diff = ((twin_dfixed_t) a->dy * (twin_dfixed_t) b->dx -
+ (twin_dfixed_t) b->dy * (twin_dfixed_t) a->dx);
+
+ if (diff > 0)
+ return 1;
+ if (diff < 0)
+ return -1;
+
+ if (a->dx == 0 && a->dy == 0)
+ return 1;
+ if (b->dx == 0 && b->dy ==0)
+ return -1;
+
+ return 0;
+}
+
+static int
+_twin_hull_vertex_compare (const void *av, const void *bv)
+{
+ twin_hull_t *a = (twin_hull_t *) av;
+ twin_hull_t *b = (twin_hull_t *) bv;
+ int ret;
+
+ ret = _twin_slope_compare (&a->slope, &b->slope);
+
+ /* In the case of two vertices with identical slope from the
+ extremal point discard the nearer point. */
+
+ if (ret == 0)
+ {
+ twin_dfixed_t a_dist, b_dist;
+ a_dist = ((twin_dfixed_t) a->slope.dx * a->slope.dx +
+ (twin_dfixed_t) a->slope.dy * a->slope.dy);
+ b_dist = ((twin_dfixed_t) b->slope.dx * b->slope.dx +
+ (twin_dfixed_t) b->slope.dy * b->slope.dy);
+ if (a_dist < b_dist)
+ a->discard = 1;
+ else
+ b->discard = 1;
+ }
+
+ return ret;
+}
+
+static int
+_twin_hull_prev_valid (twin_hull_t *hull, int num_hull, int index)
+{
+ do {
+ /* hull[0] is always valid, so don't test and wraparound */
+ index--;
+ } while (hull[index].discard);
+
+ return index;
+}
+
+static int
+_twin_hull_next_valid (twin_hull_t *hull, int num_hull, int index)
+{
+ do {
+ index = (index + 1) % num_hull;
+ } while (hull[index].discard);
+
+ return index;
+}
+
+/*
+ * Graham scan to compute convex hull
+ */
+
+static void
+_twin_hull_eliminate_concave (twin_hull_t *hull, int num_hull)
+{
+ int i, j, k;
+ twin_slope_t slope_ij, slope_jk;
+
+ i = 0;
+ j = _twin_hull_next_valid (hull, num_hull, i);
+ k = _twin_hull_next_valid (hull, num_hull, j);
+
+ do {
+ _twin_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
+ _twin_slope_init (&slope_jk, &hull[j].point, &hull[k].point);
+
+ /* Is the angle formed by ij and jk concave? */
+ if (_twin_slope_compare (&slope_ij, &slope_jk) >= 0) {
+ if (i == k)
+ break;
+ hull[j].discard = 1;
+ j = i;
+ i = _twin_hull_prev_valid (hull, num_hull, j);
+ } else {
+ i = j;
+ j = k;
+ k = _twin_hull_next_valid (hull, num_hull, j);
+ }
+ } while (j != 0);
+}
+
+/*
+ * Convert the hull structure back to a simple path
+ */
+static twin_path_t *
+_twin_hull_to_path (twin_hull_t *hull, int num_hull)
+{
+ twin_path_t *path = twin_path_create ();
+ int i;
+
+ for (i = 0; i < num_hull; i++)
+ {
+ if (hull[i].discard)
+ continue;
+ twin_path_draw (path, hull[i].point.x, hull[i].point.y);
+ }
+
+ return path;
+}
+
+/*
+ * Given a path, return the convex hull using the Graham scan algorithm.
+ */
+
+twin_path_t *
+twin_path_convex_hull (twin_path_t *path)
+{
+ twin_hull_t *hull;
+ int num_hull;
+ twin_path_t *convex_path;
+
+ hull = _twin_hull_create (path, &num_hull);
+
+ if (hull == NULL)
+ return 0;
+
+ qsort (hull + 1, num_hull - 1, sizeof (twin_hull_t),
+ _twin_hull_vertex_compare);
+
+ _twin_hull_eliminate_concave (hull, num_hull);
+
+ convex_path = _twin_hull_to_path (hull, num_hull);
+
+ free (hull);
+
+ return convex_path;
+}
diff --git a/twin_primitive.c b/twin_primitive.c
index 2f69938..5c94784 100644
--- a/twin_primitive.c
+++ b/twin_primitive.c
@@ -24,6 +24,8 @@
#include "twinint.h"
+#define __inline
+
static twin_argb32_t __inline
in_over (twin_argb32_t dst,
twin_argb32_t src,
diff --git a/twin_spline.c b/twin_spline.c
index ee92216..426db64 100644
--- a/twin_spline.c
+++ b/twin_spline.c
@@ -89,7 +89,7 @@ _twin_spline_decompose (twin_path_t *path,
twin_spline_t *spline,
twin_dfixed_t tolerance_squared)
{
- if (_twin_spline_error_squared (spline) < tolerance_squared)
+ if (_twin_spline_error_squared (spline) <= tolerance_squared)
{
twin_path_draw (path, spline->a.x, spline->a.y);
}
diff --git a/xtwin.c b/xtwin.c
index 88930df..323856e 100644
--- a/xtwin.c
+++ b/xtwin.c
@@ -29,6 +29,13 @@
#define D(x) twin_double_to_fixed(x)
+static int styles[] = {
+ TWIN_TEXT_ROMAN,
+ TWIN_TEXT_OBLIQUE,
+ TWIN_TEXT_BOLD,
+ TWIN_TEXT_BOLD|TWIN_TEXT_OBLIQUE
+};
+
int
main (int argc, char **argv)
{
@@ -46,55 +53,35 @@ main (int argc, char **argv)
int x, y;
twin_fixed_t fx, fy;
int g;
+ int s;
pen = twin_path_create ();
twin_path_circle (pen, D (0.5));
-#define OFF TWIN_FIXED_HALF
-#if 0
- twin_path_move (pen, D(-1), D(-1));
- twin_path_draw (pen, D(1), D(-1));
- twin_path_draw (pen, D(1), D(1));
- twin_path_draw (pen, D(-1), D(1));
-#endif
twin_fill (red, 0x00000000, TWIN_SOURCE, 0, 0, 512, 512);
twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, 512, 512);
path = twin_path_create ();
-#if 0
- stroke = twin_path_create();
-
-#define HEIGHT twin_int_to_fixed(16)
-#define LEFT (twin_int_to_fixed (3) + OFF)
-
- fx = LEFT;
- fy = HEIGHT + OFF;
-
- twin_path_move (stroke, fx, fy);
-
- for (g = 0; g < 4000; g++)
-/* for (g = 1000; g < 2000; g++) */
-/* for (g = 2000; g < 2500; g++) */
-/* for (g = 2500; g < 3000; g++) */
-/* for (g = 3000; g < 4000; g++) */
- /* really chunky looking */
-/* for (g = 4000; g < 4327; g++) */
-/* #define WIDTH twin_int_to_fixed(60)
- #define HEIGHT twin_int_to_fixed(80)
- */
+#if 1
+ fx = D(3);
+ fy = D(8);
+ for (g = 10; g < 20; g++)
{
- if (twin_has_glyph (g))
+#if 1
+ for (s = 0; s < 4; s++)
{
- if (fx + twin_glyph_width (g) > twin_int_to_fixed (500))
- twin_path_move (stroke, fx = LEFT, fy += HEIGHT);
- twin_path_glyph (stroke, g);
- fx += twin_glyph_width (g);
+ twin_path_move (path, fx, fy);
+ twin_path_string (path, D(g), D(g), styles[s],
+ "the quick brown fox jumps over the lazy dog.");
+ twin_path_string (path, D(g), D(g), styles[s],
+ "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.");
+ fy += D(g);
}
+#else
+ twin_path_string (path, D(g), D(g), "t");
+ fy += D(g);
+#endif
}
-
- twin_path_convolve (path, stroke, pen);
-
- twin_path_destroy (stroke);
#else
fx = D(3);
fy = D(8);
@@ -157,7 +144,7 @@ main (int argc, char **argv)
twin_pixmap_move (red, 0, 0);
twin_pixmap_move (blue, 100, 100);
twin_pixmap_show (red, x11->screen, 0);
- twin_pixmap_show (blue, x11->screen, 0);
+/* twin_pixmap_show (blue, x11->screen, 0); */
had_motion = TWIN_FALSE;
for (;;)
{