Cleaned up XrPathInterpret. Prepare for splines

This commit is contained in:
Carl Worth 2002-08-15 17:29:26 +00:00
parent 20f631ce22
commit c1c7ee62bc
15 changed files with 772 additions and 348 deletions

View file

@ -24,9 +24,11 @@ INCLUDES = -I$(XLIBSRE)
SRCS = xr.c \
xrcolor.c \
xrfiller.c \
xrgstate.c \
xrpath.c \
xrpolygon.c \
xrspline.c \
xrstate.c \
xrstroker.c \
xrsurface.c \
@ -35,9 +37,11 @@ SRCS = xr.c \
OBJS = xr.o \
xrcolor.o \
xrfiller.o \
xrgstate.o \
xrpath.o \
xrpolygon.o \
xrspline.o \
xrstate.o \
xrstroker.o \
xrsurface.o \

94
src/xrfiller.c Normal file
View file

@ -0,0 +1,94 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. 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
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH 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 "xrint.h"
void
XrFillerInit(XrFiller *filler, XrGState *gstate, XrTraps *traps)
{
filler->gstate = gstate;
filler->traps = traps;
XrPolygonInit(&filler->polygon);
}
void
XrFillerDeinit(XrFiller *filler)
{
XrPolygonDeinit(&filler->polygon);
}
XrError
XrFillerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
return XrPolygonAddEdge(polygon, p1, p2);
}
XrError
XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
int i;
XrError err = XrErrorSuccess;
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
XrGState *gstate = filler->gstate;
XrSpline spline;
XrSplineInit(&spline, a, b, c, d);
XrSplineDecompose(&spline, gstate->tolerance);
if (err)
goto CLEANUP_SPLINE;
for (i = 0; i < spline.num_pts; i++) {
err = XrPolygonAddEdge(polygon,
&spline.pt[i],
i < spline.num_pts ? &spline.pt[i+1] : &spline.pt[0]);
if (err)
goto CLEANUP_SPLINE;
}
CLEANUP_SPLINE:
XrSplineDeinit(&spline);
return err;
}
XrError
XrFillerDoneSubPath (void *closure, XrSubPathDone done)
{
return XrErrorSuccess;
}
XrError
XrFillerDonePath (void *closure)
{
XrFiller *filler = closure;
return XrTrapsTessellatePolygon(filler->traps, &filler->polygon, filler->gstate->winding);
}

View file

@ -49,6 +49,8 @@ XrGStateInit(XrGState *gstate, Display *dpy)
gstate->operator = XR_GSTATE_OPERATOR_DEFAULT;
gstate->tolerance = XR_GSTATE_TOLERANCE_DEFAULT;
gstate->winding = XR_GSTATE_WINDING_DEFAULT;
gstate->line_width = XR_GSTATE_LINE_WIDTH_DEFAULT;
@ -198,8 +200,6 @@ XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join)
XrError
XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset)
{
double *ndashes;
if (gstate->dashes) {
free (gstate->dashes);
}
@ -273,18 +273,20 @@ XrGStateAddPathOp(XrGState *gstate, XrPathOp op, XPointDouble *pt, int num_pts)
switch (op) {
case XrPathOpMoveTo:
case XrPathOpLineTo:
case XrPathOpCurveTo:
for (i=0; i < num_pts; i++) {
XrTransformPoint(&gstate->ctm, &pt[i]);
}
break;
case XrPathOpRelMoveTo:
case XrPathOpRelLineTo:
case XrPathOpRelCurveTo:
for (i=0; i < num_pts; i++) {
XrTransformPointWithoutTranslate(&gstate->ctm, &pt[i]);
}
break;
default:
return XrErrorSuccess;
case XrPathOpClosePath:
break;
}
pt_fixed = malloc(num_pts * sizeof(XPointFixed));
@ -326,54 +328,22 @@ XrGStateStroke(XrGState *gstate)
{
XrError err;
static XrPathCallbacks cb = { XrStrokerAddEdge, XrStrokerDoneSubPath };
static XrPathCallbacks cb = {
XrStrokerAddEdge,
XrStrokerAddSpline,
XrStrokerDoneSubPath,
XrStrokerDonePath
};
XrStroker stroker;
XrTraps traps;
XrStrokerInit(&stroker, gstate, &traps);
XrTrapsInit(&traps);
XrStrokerInit(&stroker, gstate, &traps);
err = XrPathInterpret(&gstate->path, XrPathDirectionForward, &cb, &stroker);
if (err)
return err;
XcCompositeTrapezoids(gstate->dpy, gstate->operator,
gstate->src.xcsurface, gstate->surface.xcsurface,
gstate->alphaFormat,
0, 0,
traps.xtraps,
traps.num_xtraps);
XrTrapsDeinit(&traps);
XrStrokerDeinit(&stroker);
XrGStateNewPath(gstate);
return XrErrorSuccess;
}
XrError
XrGStateFill(XrGState *gstate)
{
XrError err;
static XrPathCallbacks cb = { XrPolygonAddEdge, XrPolygonDoneSubPath };
XrPolygon polygon;
XrTraps traps;
XrPolygonInit(&polygon);
err = XrPathInterpret(&gstate->path, XrPathDirectionForward, &cb, &polygon);
if (err) {
XrPolygonDeinit(&polygon);
return err;
}
XrTrapsInit(&traps);
err = XrTrapsTessellatePolygon(&traps, &polygon, gstate->winding);
if (err) {
XrStrokerDeinit(&stroker);
XrTrapsDeinit(&traps);
return err;
}
@ -385,8 +355,47 @@ XrGStateFill(XrGState *gstate)
traps.xtraps,
traps.num_xtraps);
XrStrokerDeinit(&stroker);
XrTrapsDeinit(&traps);
XrGStateNewPath(gstate);
return XrErrorSuccess;
}
XrError
XrGStateFill(XrGState *gstate)
{
XrError err;
static XrPathCallbacks cb = {
XrFillerAddEdge,
XrFillerAddSpline,
XrFillerDoneSubPath,
XrFillerDonePath
};
XrFiller filler;
XrTraps traps;
XrTrapsInit(&traps);
XrFillerInit(&filler, gstate, &traps);
err = XrPathInterpret(&gstate->path, XrPathDirectionForward, &cb, &filler);
if (err) {
XrFillerDeinit(&filler);
XrTrapsDeinit(&traps);
return err;
}
XcCompositeTrapezoids(gstate->dpy, gstate->operator,
gstate->src.xcsurface, gstate->surface.xcsurface,
gstate->alphaFormat,
0, 0,
traps.xtraps,
traps.num_xtraps);
XrFillerDeinit(&filler);
XrTrapsDeinit(&traps);
XrPolygonDeinit(&polygon);
XrGStateNewPath(gstate);

View file

@ -48,13 +48,13 @@ typedef enum _XrError {
} XrError;
typedef enum _XrPathOp {
XrPathOpMoveTo,
XrPathOpLineTo,
XrPathOpCurveTo,
XrPathOpRelMoveTo,
XrPathOpRelLineTo,
XrPathOpRelCurveTo,
XrPathOpClosePath
XrPathOpMoveTo = 0,
XrPathOpLineTo = 1,
XrPathOpCurveTo = 2,
XrPathOpRelMoveTo = 3,
XrPathOpRelLineTo = 4,
XrPathOpRelCurveTo = 5,
XrPathOpClosePath = 6
} __attribute__ ((packed)) XrPathOp; /* Don't want 32 bits if we can avoid it. */
typedef enum _XrPathDirection {
@ -69,7 +69,9 @@ typedef enum _XrSubPathDone {
typedef struct _XrPathCallbacks {
XrError (*AddEdge)(void *closure, XPointFixed *p1, XPointFixed *p2);
XrError (*AddSpline)(void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError (*DoneSubPath) (void *closure, XrSubPathDone done);
XrError (*DonePath) (void *closure);
} XrPathCallbacks;
#define XR_PATH_BUF_SZ 64
@ -113,6 +115,31 @@ typedef struct _XrPolygon {
XrEdge *edges;
} XrPolygon;
typedef struct _XrSpline {
XPointFixed a, b, c, d;
XPointFixed *pt;
int num_pts;
} XrSpline;
typedef enum _XrPenVertexStart {
XrPenVertexNone,
XrPenVertexForward,
XrPenVertexRevers
} XrPenVertexStart;
typedef struct _XrPenVertex {
XPointFixed pt;
double theta;
XPointFixed slope_ccw;
XPointFixed slope_cw;
XrPenVertexStart start;
} XrPenVertex;
typedef struct _XrPen {
int num_vertices;
XrPenVertex *vertex;
} XrPen;
typedef struct _XrSurface {
Display *dpy;
@ -148,6 +175,7 @@ typedef struct _XrTraps {
} XrTraps;
#define XR_GSTATE_OPERATOR_DEFAULT XrOperatorOver
#define XR_GSTATE_TOLERANCE_DEFAULT 0.1
#define XR_GSTATE_WINDING_DEFAULT 1
#define XR_GSTATE_LINE_WIDTH_DEFAULT 2.0
#define XR_GSTATE_LINE_CAP_DEFAULT XrLineCapButt
@ -157,6 +185,8 @@ typedef struct _XrTraps {
typedef struct _XrGState {
Display *dpy;
double tolerance;
/* stroke style */
double line_width;
XrLineCap line_cap;
@ -183,6 +213,8 @@ typedef struct _XrGState {
XrPath path;
XrPen pen_regular;
struct _XrGState *next;
} XrGState;
@ -207,6 +239,13 @@ typedef struct _XrStroker {
XrStrokeFace first;
} XrStroker;
typedef struct _XrFiller {
XrGState *gstate;
XrTraps *traps;
XrPolygon polygon;
} XrFiller;
/* xrstate.c */
#define CURRENT_GSTATE(xrs) (xrs->stack)
@ -356,20 +395,43 @@ XrSurfaceSetVisual(XrSurface *surface, Visual *visual);
void
XrSurfaceSetFormat(XrSurface *surface, XrFormat format);
/* xrpen.c */
XrError
XrPenInit(XrPen *pen, double radius);
XrError
XrPenInitCopy(XrPen *pen, XrPen *other);
void
XrPenDeinit(XrPen *pen);
void
XrPenAddPointsForSlopes(XrPen *pen, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError
XrPenStrokePoints(XrPen *pen, XPointFixed *pt, int num_pts, XrPolygon *polygon);
/* xrpolygon.c */
void
XrPolygonInit(XrPolygon *poly);
XrPolygonInit(XrPolygon *polygon);
void
XrPolygonDeinit(XrPolygon *poly);
XrPolygonDeinit(XrPolygon *polygon);
XrError
XrPolygonAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
XrPolygonAddEdge(XrPolygon *polygon, XPointFixed *p1, XPointFixed *p2);
/* xrspline.c */
void
XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError
XrPolygonDoneSubPath (void *closure, XrSubPathDone done);
/* xrstroke.c */
XrSplineDecompose(XrSpline *spline, double tolerance);
void
XrSplineDeinit(XrSpline *spline);
/* xrstroker.c */
void
XrStrokerInit(XrStroker *stroker, XrGState *gstate, XrTraps *traps);
@ -379,9 +441,34 @@ XrStrokerDeinit(XrStroker *stroker);
XrError
XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
XrError
XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError
XrStrokerDoneSubPath (void *closure, XrSubPathDone done);
XrError
XrStrokerDonePath (void *closure);
/* xrfiller.c */
void
XrFillerInit(XrFiller *filler, XrGState *gstate, XrTraps *traps);
void
XrFillerDeinit(XrFiller *filler);
XrError
XrFillerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
XrError
XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError
XrFillerDoneSubPath (void *closure, XrSubPathDone done);
XrError
XrFillerDonePath (void *closure);
/* xrtransform.c */
void
XrTransformInit(XrTransform *transform);

View file

@ -270,46 +270,29 @@ _TranslatePointFixed(XPointFixed *pt, XPointFixed *offset)
pt->y += offset->y;
}
#define START_ARGS(n) \
{ \
if (dir != XrPathDirectionForward) \
{ \
if (arg_i == 0) { \
arg_buf = arg_buf->prev; \
arg_i = arg_buf->num_pts; \
} \
arg_i -= n; \
} \
}
#define XR_PATH_OP_MAX_ARGS 3
#define NEXT_ARG(pt) \
{ \
(pt) = arg_buf->pt[arg_i]; \
arg_i++; \
if (arg_i >= arg_buf->num_pts) { \
arg_buf = arg_buf->next; \
arg_i = 0; \
} \
}
#define END_ARGS(n) \
{ \
if (dir != XrPathDirectionForward) \
{ \
arg_i -= n; \
} \
}
static int num_args[] =
{
1, /* XrPathMoveTo */
1, /* XrPathOpLineTo */
3, /* XrPathOpCurveTo */
1, /* XrPathOpRelMoveTo */
1, /* XrPathOpRelLineTo */
3, /* XrPathOpRelCurveTo */
0, /* XrPathOpClosePath */
};
XrError
XrPathInterpret(XrPath *path, XrPathDirection dir, XrPathCallbacks *cb, void *closure)
{
XrError err;
int i;
int i, arg;
XrPathOpBuf *op_buf;
XrPathOp op;
XrPathArgBuf *arg_buf = path->arg_head;
int arg_i = 0;
XPointFixed pt;
int buf_i = 0;
XPointFixed pt[XR_PATH_OP_MAX_ARGS];
XPointFixed current = {0, 0};
XPointFixed first = {0, 0};
int has_current = 0;
@ -334,67 +317,76 @@ XrPathInterpret(XrPath *path, XrPathDirection dir, XrPathCallbacks *cb, void *cl
{
op = op_buf->op[i];
if (dir == XrPathDirectionReverse) {
if (buf_i == 0) {
arg_buf = arg_buf->prev;
buf_i = arg_buf->num_pts;
}
buf_i -= num_args[op];
}
for (arg = 0; arg < num_args[op]; arg++) {
pt[arg] = arg_buf->pt[buf_i];
buf_i++;
if (buf_i >= arg_buf->num_pts) {
arg_buf = arg_buf->next;
buf_i = 0;
}
}
if (dir == XrPathDirectionReverse) {
buf_i -= num_args[op];
}
switch (op) {
case XrPathOpRelMoveTo:
_TranslatePointFixed(&pt[0], &current);
/* fall-through */
case XrPathOpMoveTo:
if (has_edge) {
err = (*cb->DoneSubPath) (closure, XrSubPathDoneCap);
if (err)
return err;
}
START_ARGS(1);
NEXT_ARG(pt);
END_ARGS(1);
first = pt;
current = pt;
has_current = 1;
has_edge = 0;
break;
case XrPathOpLineTo:
START_ARGS(1);
NEXT_ARG(pt);
END_ARGS(1);
if (has_current) {
err = (*cb->AddEdge)(closure, &current, &pt);
if (err)
return err;
current = pt;
has_edge = 1;
} else {
first = pt;
current = pt;
has_current = 1;
}
break;
case XrPathOpRelMoveTo:
if (has_edge) {
err = (*cb->DoneSubPath) (closure, XrSubPathDoneCap);
if (err)
return err;
}
START_ARGS(1);
NEXT_ARG(pt);
END_ARGS(1);
_TranslatePointFixed(&pt, &current);
first = pt;
current = pt;
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
break;
case XrPathOpRelLineTo:
START_ARGS(1);
NEXT_ARG(pt);
END_ARGS(1);
_TranslatePointFixed(&pt, &current);
_TranslatePointFixed(&pt[0], &current);
/* fall-through */
case XrPathOpLineTo:
if (has_current) {
err = (*cb->AddEdge)(closure, &current, &pt);
err = (*cb->AddEdge)(closure, &current, &pt[0]);
if (err)
return err;
current = pt;
current = pt[0];
has_edge = 1;
} else {
first = pt;
current = pt;
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
}
break;
case XrPathOpRelCurveTo:
for (arg = 0; arg < num_args[op]; arg++) {
_TranslatePointFixed(&pt[arg], &current);
}
/* fall-through */
case XrPathOpCurveTo:
if (has_current) {
err = (*cb->AddSpline)(closure, &current, &pt[0], &pt[1], &pt[2]);
if (err)
return err;
current = pt[2];
has_edge = 1;
} else {
first = pt[2];
current = pt[2];
has_current = 1;
has_edge = 0;
}
break;
case XrPathOpClosePath:
@ -415,5 +407,5 @@ XrPathInterpret(XrPath *path, XrPathDirection dir, XrPathCallbacks *cb, void *cl
if (has_edge)
(*cb->DoneSubPath) (closure, XrSubPathDoneCap);
return XrErrorSuccess;
return (*cb->DonePath)(closure);
}

View file

@ -31,71 +31,70 @@
/* private functions */
static XrError
_XrPolygonGrowBy(XrPolygon *poly, int additional);
_XrPolygonGrowBy(XrPolygon *polygon, int additional);
void
XrPolygonInit(XrPolygon *poly)
XrPolygonInit(XrPolygon *polygon)
{
poly->num_edges = 0;
polygon->num_edges = 0;
poly->edges_size = 0;
poly->edges = NULL;
polygon->edges_size = 0;
polygon->edges = NULL;
}
void
XrPolygonDeinit(XrPolygon *poly)
XrPolygonDeinit(XrPolygon *polygon)
{
if (poly->edges_size) {
free(poly->edges);
poly->edges_size = 0;
poly->num_edges = 0;
if (polygon->edges_size) {
free(polygon->edges);
polygon->edges_size = 0;
polygon->num_edges = 0;
}
}
static XrError
_XrPolygonGrowBy(XrPolygon *poly, int additional)
_XrPolygonGrowBy(XrPolygon *polygon, int additional)
{
XrEdge *new_edges;
int old_size = poly->edges_size;
int new_size = poly->num_edges + additional;
int old_size = polygon->edges_size;
int new_size = polygon->num_edges + additional;
if (new_size <= poly->edges_size) {
if (new_size <= polygon->edges_size) {
return XrErrorSuccess;
}
poly->edges_size = new_size;
new_edges = realloc(poly->edges, poly->edges_size * sizeof(XrEdge));
polygon->edges_size = new_size;
new_edges = realloc(polygon->edges, polygon->edges_size * sizeof(XrEdge));
if (new_edges == NULL) {
poly->edges_size = old_size;
polygon->edges_size = old_size;
return XrErrorNoMemory;
}
poly->edges = new_edges;
polygon->edges = new_edges;
return XrErrorSuccess;
}
XrError
XrPolygonAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
XrPolygonAddEdge(XrPolygon *polygon, XPointFixed *p1, XPointFixed *p2)
{
XrError err;
XrEdge *edge;
XrPolygon *poly = closure;
/* drop horizontal edges */
if (p1->y == p2->y) {
return XrErrorSuccess;
}
if (poly->num_edges >= poly->edges_size) {
err = _XrPolygonGrowBy(poly, XR_POLYGON_GROWTH_INC);
if (polygon->num_edges >= polygon->edges_size) {
err = _XrPolygonGrowBy(polygon, XR_POLYGON_GROWTH_INC);
if (err) {
return err;
}
}
edge = &poly->edges[poly->num_edges];
edge = &polygon->edges[polygon->num_edges];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
@ -106,14 +105,7 @@ XrPolygonAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
edge->clockWise = False;
}
poly->num_edges++;
polygon->num_edges++;
return XrErrorSuccess;
}
XrError
XrPolygonDoneSubPath (void *closure, XrSubPathDone done)
{
return XrErrorSuccess;
}

View file

@ -166,7 +166,7 @@ _XrStrokerCap(XrStroker *stroker, XrStrokeFace *f)
case XrLineCapSquare: {
XPointDouble vector = f->vector;
XPointFixed fvector;
XPointFixed outer, occw, ocw;
XPointFixed occw, ocw;
vector.x *= gstate->line_width / 2.0;
vector.y *= gstate->line_width / 2.0;
XrTransformPointWithoutTranslate(&gstate->ctm, &vector);
@ -269,6 +269,44 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
return XrTrapsTessellateRectangle(traps, quad);
}
XrError
XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
XrError err = XrErrorSuccess;
XrStroker *stroker = closure;
XrSpline spline;
XrPolygon polygon;
XrPen pen;
XrSplineInit(&spline, a, b, c, d);
err = XrSplineDecompose(&spline, stroker->gstate->tolerance);
if (err)
goto CLEANUP_SPLINE;
XrPolygonInit(&polygon);
err = XrPenInitCopy(&pen, &stroker->gstate->pen_regular);
if (err)
goto CLEANUP_POLYGON;
XrPenAddPointsForSlopes(&pen, a, b, c, d);
err = XrPenStrokePoints(&pen, spline.pt, spline.num_pts, &polygon);
if (err)
goto CLEANUP_PEN;
err = XrTrapsTessellatePolygon(stroker->traps, &polygon, 1);
CLEANUP_PEN:
XrPenDeinit(&pen);
CLEANUP_POLYGON:
XrPolygonDeinit(&polygon);
CLEANUP_SPLINE:
XrSplineDeinit(&spline);
return err;
}
XrError
XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
{
@ -289,3 +327,9 @@ XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
return XrErrorSuccess;
}
XrError
XrStrokerDonePath (void *closure)
{
return XrErrorSuccess;
}

View file

@ -36,14 +36,6 @@ static XrTransform XR_TRANSFORM_DEFAULT = {
}
};
static XrTransform XR_TRANSFORM_ZERO = {
{
{0, 0},
{0, 0},
{0, 0}
}
};
void
XrTransformInit(XrTransform *transform)
{

94
xrfiller.c Normal file
View file

@ -0,0 +1,94 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. 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
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH 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 "xrint.h"
void
XrFillerInit(XrFiller *filler, XrGState *gstate, XrTraps *traps)
{
filler->gstate = gstate;
filler->traps = traps;
XrPolygonInit(&filler->polygon);
}
void
XrFillerDeinit(XrFiller *filler)
{
XrPolygonDeinit(&filler->polygon);
}
XrError
XrFillerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
return XrPolygonAddEdge(polygon, p1, p2);
}
XrError
XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
int i;
XrError err = XrErrorSuccess;
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
XrGState *gstate = filler->gstate;
XrSpline spline;
XrSplineInit(&spline, a, b, c, d);
XrSplineDecompose(&spline, gstate->tolerance);
if (err)
goto CLEANUP_SPLINE;
for (i = 0; i < spline.num_pts; i++) {
err = XrPolygonAddEdge(polygon,
&spline.pt[i],
i < spline.num_pts ? &spline.pt[i+1] : &spline.pt[0]);
if (err)
goto CLEANUP_SPLINE;
}
CLEANUP_SPLINE:
XrSplineDeinit(&spline);
return err;
}
XrError
XrFillerDoneSubPath (void *closure, XrSubPathDone done)
{
return XrErrorSuccess;
}
XrError
XrFillerDonePath (void *closure)
{
XrFiller *filler = closure;
return XrTrapsTessellatePolygon(filler->traps, &filler->polygon, filler->gstate->winding);
}

View file

@ -49,6 +49,8 @@ XrGStateInit(XrGState *gstate, Display *dpy)
gstate->operator = XR_GSTATE_OPERATOR_DEFAULT;
gstate->tolerance = XR_GSTATE_TOLERANCE_DEFAULT;
gstate->winding = XR_GSTATE_WINDING_DEFAULT;
gstate->line_width = XR_GSTATE_LINE_WIDTH_DEFAULT;
@ -198,8 +200,6 @@ XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join)
XrError
XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset)
{
double *ndashes;
if (gstate->dashes) {
free (gstate->dashes);
}
@ -273,18 +273,20 @@ XrGStateAddPathOp(XrGState *gstate, XrPathOp op, XPointDouble *pt, int num_pts)
switch (op) {
case XrPathOpMoveTo:
case XrPathOpLineTo:
case XrPathOpCurveTo:
for (i=0; i < num_pts; i++) {
XrTransformPoint(&gstate->ctm, &pt[i]);
}
break;
case XrPathOpRelMoveTo:
case XrPathOpRelLineTo:
case XrPathOpRelCurveTo:
for (i=0; i < num_pts; i++) {
XrTransformPointWithoutTranslate(&gstate->ctm, &pt[i]);
}
break;
default:
return XrErrorSuccess;
case XrPathOpClosePath:
break;
}
pt_fixed = malloc(num_pts * sizeof(XPointFixed));
@ -326,54 +328,22 @@ XrGStateStroke(XrGState *gstate)
{
XrError err;
static XrPathCallbacks cb = { XrStrokerAddEdge, XrStrokerDoneSubPath };
static XrPathCallbacks cb = {
XrStrokerAddEdge,
XrStrokerAddSpline,
XrStrokerDoneSubPath,
XrStrokerDonePath
};
XrStroker stroker;
XrTraps traps;
XrStrokerInit(&stroker, gstate, &traps);
XrTrapsInit(&traps);
XrStrokerInit(&stroker, gstate, &traps);
err = XrPathInterpret(&gstate->path, XrPathDirectionForward, &cb, &stroker);
if (err)
return err;
XcCompositeTrapezoids(gstate->dpy, gstate->operator,
gstate->src.xcsurface, gstate->surface.xcsurface,
gstate->alphaFormat,
0, 0,
traps.xtraps,
traps.num_xtraps);
XrTrapsDeinit(&traps);
XrStrokerDeinit(&stroker);
XrGStateNewPath(gstate);
return XrErrorSuccess;
}
XrError
XrGStateFill(XrGState *gstate)
{
XrError err;
static XrPathCallbacks cb = { XrPolygonAddEdge, XrPolygonDoneSubPath };
XrPolygon polygon;
XrTraps traps;
XrPolygonInit(&polygon);
err = XrPathInterpret(&gstate->path, XrPathDirectionForward, &cb, &polygon);
if (err) {
XrPolygonDeinit(&polygon);
return err;
}
XrTrapsInit(&traps);
err = XrTrapsTessellatePolygon(&traps, &polygon, gstate->winding);
if (err) {
XrStrokerDeinit(&stroker);
XrTrapsDeinit(&traps);
return err;
}
@ -385,8 +355,47 @@ XrGStateFill(XrGState *gstate)
traps.xtraps,
traps.num_xtraps);
XrStrokerDeinit(&stroker);
XrTrapsDeinit(&traps);
XrGStateNewPath(gstate);
return XrErrorSuccess;
}
XrError
XrGStateFill(XrGState *gstate)
{
XrError err;
static XrPathCallbacks cb = {
XrFillerAddEdge,
XrFillerAddSpline,
XrFillerDoneSubPath,
XrFillerDonePath
};
XrFiller filler;
XrTraps traps;
XrTrapsInit(&traps);
XrFillerInit(&filler, gstate, &traps);
err = XrPathInterpret(&gstate->path, XrPathDirectionForward, &cb, &filler);
if (err) {
XrFillerDeinit(&filler);
XrTrapsDeinit(&traps);
return err;
}
XcCompositeTrapezoids(gstate->dpy, gstate->operator,
gstate->src.xcsurface, gstate->surface.xcsurface,
gstate->alphaFormat,
0, 0,
traps.xtraps,
traps.num_xtraps);
XrFillerDeinit(&filler);
XrTrapsDeinit(&traps);
XrPolygonDeinit(&polygon);
XrGStateNewPath(gstate);

113
xrint.h
View file

@ -48,13 +48,13 @@ typedef enum _XrError {
} XrError;
typedef enum _XrPathOp {
XrPathOpMoveTo,
XrPathOpLineTo,
XrPathOpCurveTo,
XrPathOpRelMoveTo,
XrPathOpRelLineTo,
XrPathOpRelCurveTo,
XrPathOpClosePath
XrPathOpMoveTo = 0,
XrPathOpLineTo = 1,
XrPathOpCurveTo = 2,
XrPathOpRelMoveTo = 3,
XrPathOpRelLineTo = 4,
XrPathOpRelCurveTo = 5,
XrPathOpClosePath = 6
} __attribute__ ((packed)) XrPathOp; /* Don't want 32 bits if we can avoid it. */
typedef enum _XrPathDirection {
@ -69,7 +69,9 @@ typedef enum _XrSubPathDone {
typedef struct _XrPathCallbacks {
XrError (*AddEdge)(void *closure, XPointFixed *p1, XPointFixed *p2);
XrError (*AddSpline)(void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError (*DoneSubPath) (void *closure, XrSubPathDone done);
XrError (*DonePath) (void *closure);
} XrPathCallbacks;
#define XR_PATH_BUF_SZ 64
@ -113,6 +115,31 @@ typedef struct _XrPolygon {
XrEdge *edges;
} XrPolygon;
typedef struct _XrSpline {
XPointFixed a, b, c, d;
XPointFixed *pt;
int num_pts;
} XrSpline;
typedef enum _XrPenVertexStart {
XrPenVertexNone,
XrPenVertexForward,
XrPenVertexRevers
} XrPenVertexStart;
typedef struct _XrPenVertex {
XPointFixed pt;
double theta;
XPointFixed slope_ccw;
XPointFixed slope_cw;
XrPenVertexStart start;
} XrPenVertex;
typedef struct _XrPen {
int num_vertices;
XrPenVertex *vertex;
} XrPen;
typedef struct _XrSurface {
Display *dpy;
@ -148,6 +175,7 @@ typedef struct _XrTraps {
} XrTraps;
#define XR_GSTATE_OPERATOR_DEFAULT XrOperatorOver
#define XR_GSTATE_TOLERANCE_DEFAULT 0.1
#define XR_GSTATE_WINDING_DEFAULT 1
#define XR_GSTATE_LINE_WIDTH_DEFAULT 2.0
#define XR_GSTATE_LINE_CAP_DEFAULT XrLineCapButt
@ -157,6 +185,8 @@ typedef struct _XrTraps {
typedef struct _XrGState {
Display *dpy;
double tolerance;
/* stroke style */
double line_width;
XrLineCap line_cap;
@ -183,6 +213,8 @@ typedef struct _XrGState {
XrPath path;
XrPen pen_regular;
struct _XrGState *next;
} XrGState;
@ -207,6 +239,13 @@ typedef struct _XrStroker {
XrStrokeFace first;
} XrStroker;
typedef struct _XrFiller {
XrGState *gstate;
XrTraps *traps;
XrPolygon polygon;
} XrFiller;
/* xrstate.c */
#define CURRENT_GSTATE(xrs) (xrs->stack)
@ -356,20 +395,43 @@ XrSurfaceSetVisual(XrSurface *surface, Visual *visual);
void
XrSurfaceSetFormat(XrSurface *surface, XrFormat format);
/* xrpen.c */
XrError
XrPenInit(XrPen *pen, double radius);
XrError
XrPenInitCopy(XrPen *pen, XrPen *other);
void
XrPenDeinit(XrPen *pen);
void
XrPenAddPointsForSlopes(XrPen *pen, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError
XrPenStrokePoints(XrPen *pen, XPointFixed *pt, int num_pts, XrPolygon *polygon);
/* xrpolygon.c */
void
XrPolygonInit(XrPolygon *poly);
XrPolygonInit(XrPolygon *polygon);
void
XrPolygonDeinit(XrPolygon *poly);
XrPolygonDeinit(XrPolygon *polygon);
XrError
XrPolygonAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
XrPolygonAddEdge(XrPolygon *polygon, XPointFixed *p1, XPointFixed *p2);
/* xrspline.c */
void
XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError
XrPolygonDoneSubPath (void *closure, XrSubPathDone done);
/* xrstroke.c */
XrSplineDecompose(XrSpline *spline, double tolerance);
void
XrSplineDeinit(XrSpline *spline);
/* xrstroker.c */
void
XrStrokerInit(XrStroker *stroker, XrGState *gstate, XrTraps *traps);
@ -379,9 +441,34 @@ XrStrokerDeinit(XrStroker *stroker);
XrError
XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
XrError
XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError
XrStrokerDoneSubPath (void *closure, XrSubPathDone done);
XrError
XrStrokerDonePath (void *closure);
/* xrfiller.c */
void
XrFillerInit(XrFiller *filler, XrGState *gstate, XrTraps *traps);
void
XrFillerDeinit(XrFiller *filler);
XrError
XrFillerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
XrError
XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrError
XrFillerDoneSubPath (void *closure, XrSubPathDone done);
XrError
XrFillerDonePath (void *closure);
/* xrtransform.c */
void
XrTransformInit(XrTransform *transform);

144
xrpath.c
View file

@ -270,46 +270,29 @@ _TranslatePointFixed(XPointFixed *pt, XPointFixed *offset)
pt->y += offset->y;
}
#define START_ARGS(n) \
{ \
if (dir != XrPathDirectionForward) \
{ \
if (arg_i == 0) { \
arg_buf = arg_buf->prev; \
arg_i = arg_buf->num_pts; \
} \
arg_i -= n; \
} \
}
#define XR_PATH_OP_MAX_ARGS 3
#define NEXT_ARG(pt) \
{ \
(pt) = arg_buf->pt[arg_i]; \
arg_i++; \
if (arg_i >= arg_buf->num_pts) { \
arg_buf = arg_buf->next; \
arg_i = 0; \
} \
}
#define END_ARGS(n) \
{ \
if (dir != XrPathDirectionForward) \
{ \
arg_i -= n; \
} \
}
static int num_args[] =
{
1, /* XrPathMoveTo */
1, /* XrPathOpLineTo */
3, /* XrPathOpCurveTo */
1, /* XrPathOpRelMoveTo */
1, /* XrPathOpRelLineTo */
3, /* XrPathOpRelCurveTo */
0, /* XrPathOpClosePath */
};
XrError
XrPathInterpret(XrPath *path, XrPathDirection dir, XrPathCallbacks *cb, void *closure)
{
XrError err;
int i;
int i, arg;
XrPathOpBuf *op_buf;
XrPathOp op;
XrPathArgBuf *arg_buf = path->arg_head;
int arg_i = 0;
XPointFixed pt;
int buf_i = 0;
XPointFixed pt[XR_PATH_OP_MAX_ARGS];
XPointFixed current = {0, 0};
XPointFixed first = {0, 0};
int has_current = 0;
@ -334,67 +317,76 @@ XrPathInterpret(XrPath *path, XrPathDirection dir, XrPathCallbacks *cb, void *cl
{
op = op_buf->op[i];
if (dir == XrPathDirectionReverse) {
if (buf_i == 0) {
arg_buf = arg_buf->prev;
buf_i = arg_buf->num_pts;
}
buf_i -= num_args[op];
}
for (arg = 0; arg < num_args[op]; arg++) {
pt[arg] = arg_buf->pt[buf_i];
buf_i++;
if (buf_i >= arg_buf->num_pts) {
arg_buf = arg_buf->next;
buf_i = 0;
}
}
if (dir == XrPathDirectionReverse) {
buf_i -= num_args[op];
}
switch (op) {
case XrPathOpRelMoveTo:
_TranslatePointFixed(&pt[0], &current);
/* fall-through */
case XrPathOpMoveTo:
if (has_edge) {
err = (*cb->DoneSubPath) (closure, XrSubPathDoneCap);
if (err)
return err;
}
START_ARGS(1);
NEXT_ARG(pt);
END_ARGS(1);
first = pt;
current = pt;
has_current = 1;
has_edge = 0;
break;
case XrPathOpLineTo:
START_ARGS(1);
NEXT_ARG(pt);
END_ARGS(1);
if (has_current) {
err = (*cb->AddEdge)(closure, &current, &pt);
if (err)
return err;
current = pt;
has_edge = 1;
} else {
first = pt;
current = pt;
has_current = 1;
}
break;
case XrPathOpRelMoveTo:
if (has_edge) {
err = (*cb->DoneSubPath) (closure, XrSubPathDoneCap);
if (err)
return err;
}
START_ARGS(1);
NEXT_ARG(pt);
END_ARGS(1);
_TranslatePointFixed(&pt, &current);
first = pt;
current = pt;
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
break;
case XrPathOpRelLineTo:
START_ARGS(1);
NEXT_ARG(pt);
END_ARGS(1);
_TranslatePointFixed(&pt, &current);
_TranslatePointFixed(&pt[0], &current);
/* fall-through */
case XrPathOpLineTo:
if (has_current) {
err = (*cb->AddEdge)(closure, &current, &pt);
err = (*cb->AddEdge)(closure, &current, &pt[0]);
if (err)
return err;
current = pt;
current = pt[0];
has_edge = 1;
} else {
first = pt;
current = pt;
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
}
break;
case XrPathOpRelCurveTo:
for (arg = 0; arg < num_args[op]; arg++) {
_TranslatePointFixed(&pt[arg], &current);
}
/* fall-through */
case XrPathOpCurveTo:
if (has_current) {
err = (*cb->AddSpline)(closure, &current, &pt[0], &pt[1], &pt[2]);
if (err)
return err;
current = pt[2];
has_edge = 1;
} else {
first = pt[2];
current = pt[2];
has_current = 1;
has_edge = 0;
}
break;
case XrPathOpClosePath:
@ -415,5 +407,5 @@ XrPathInterpret(XrPath *path, XrPathDirection dir, XrPathCallbacks *cb, void *cl
if (has_edge)
(*cb->DoneSubPath) (closure, XrSubPathDoneCap);
return XrErrorSuccess;
return (*cb->DonePath)(closure);
}

View file

@ -31,71 +31,70 @@
/* private functions */
static XrError
_XrPolygonGrowBy(XrPolygon *poly, int additional);
_XrPolygonGrowBy(XrPolygon *polygon, int additional);
void
XrPolygonInit(XrPolygon *poly)
XrPolygonInit(XrPolygon *polygon)
{
poly->num_edges = 0;
polygon->num_edges = 0;
poly->edges_size = 0;
poly->edges = NULL;
polygon->edges_size = 0;
polygon->edges = NULL;
}
void
XrPolygonDeinit(XrPolygon *poly)
XrPolygonDeinit(XrPolygon *polygon)
{
if (poly->edges_size) {
free(poly->edges);
poly->edges_size = 0;
poly->num_edges = 0;
if (polygon->edges_size) {
free(polygon->edges);
polygon->edges_size = 0;
polygon->num_edges = 0;
}
}
static XrError
_XrPolygonGrowBy(XrPolygon *poly, int additional)
_XrPolygonGrowBy(XrPolygon *polygon, int additional)
{
XrEdge *new_edges;
int old_size = poly->edges_size;
int new_size = poly->num_edges + additional;
int old_size = polygon->edges_size;
int new_size = polygon->num_edges + additional;
if (new_size <= poly->edges_size) {
if (new_size <= polygon->edges_size) {
return XrErrorSuccess;
}
poly->edges_size = new_size;
new_edges = realloc(poly->edges, poly->edges_size * sizeof(XrEdge));
polygon->edges_size = new_size;
new_edges = realloc(polygon->edges, polygon->edges_size * sizeof(XrEdge));
if (new_edges == NULL) {
poly->edges_size = old_size;
polygon->edges_size = old_size;
return XrErrorNoMemory;
}
poly->edges = new_edges;
polygon->edges = new_edges;
return XrErrorSuccess;
}
XrError
XrPolygonAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
XrPolygonAddEdge(XrPolygon *polygon, XPointFixed *p1, XPointFixed *p2)
{
XrError err;
XrEdge *edge;
XrPolygon *poly = closure;
/* drop horizontal edges */
if (p1->y == p2->y) {
return XrErrorSuccess;
}
if (poly->num_edges >= poly->edges_size) {
err = _XrPolygonGrowBy(poly, XR_POLYGON_GROWTH_INC);
if (polygon->num_edges >= polygon->edges_size) {
err = _XrPolygonGrowBy(polygon, XR_POLYGON_GROWTH_INC);
if (err) {
return err;
}
}
edge = &poly->edges[poly->num_edges];
edge = &polygon->edges[polygon->num_edges];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
@ -106,14 +105,7 @@ XrPolygonAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
edge->clockWise = False;
}
poly->num_edges++;
polygon->num_edges++;
return XrErrorSuccess;
}
XrError
XrPolygonDoneSubPath (void *closure, XrSubPathDone done)
{
return XrErrorSuccess;
}

View file

@ -166,7 +166,7 @@ _XrStrokerCap(XrStroker *stroker, XrStrokeFace *f)
case XrLineCapSquare: {
XPointDouble vector = f->vector;
XPointFixed fvector;
XPointFixed outer, occw, ocw;
XPointFixed occw, ocw;
vector.x *= gstate->line_width / 2.0;
vector.y *= gstate->line_width / 2.0;
XrTransformPointWithoutTranslate(&gstate->ctm, &vector);
@ -269,6 +269,44 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
return XrTrapsTessellateRectangle(traps, quad);
}
XrError
XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
XrError err = XrErrorSuccess;
XrStroker *stroker = closure;
XrSpline spline;
XrPolygon polygon;
XrPen pen;
XrSplineInit(&spline, a, b, c, d);
err = XrSplineDecompose(&spline, stroker->gstate->tolerance);
if (err)
goto CLEANUP_SPLINE;
XrPolygonInit(&polygon);
err = XrPenInitCopy(&pen, &stroker->gstate->pen_regular);
if (err)
goto CLEANUP_POLYGON;
XrPenAddPointsForSlopes(&pen, a, b, c, d);
err = XrPenStrokePoints(&pen, spline.pt, spline.num_pts, &polygon);
if (err)
goto CLEANUP_PEN;
err = XrTrapsTessellatePolygon(stroker->traps, &polygon, 1);
CLEANUP_PEN:
XrPenDeinit(&pen);
CLEANUP_POLYGON:
XrPolygonDeinit(&polygon);
CLEANUP_SPLINE:
XrSplineDeinit(&spline);
return err;
}
XrError
XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
{
@ -289,3 +327,9 @@ XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
return XrErrorSuccess;
}
XrError
XrStrokerDonePath (void *closure)
{
return XrErrorSuccess;
}

View file

@ -36,14 +36,6 @@ static XrTransform XR_TRANSFORM_DEFAULT = {
}
};
static XrTransform XR_TRANSFORM_ZERO = {
{
{0, 0},
{0, 0},
{0, 0}
}
};
void
XrTransformInit(XrTransform *transform)
{