mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-21 12:10:12 +01:00
Added round caps/joins. Fixed initial cap. Fixed disabling of dashing.
This commit is contained in:
parent
1507f1c795
commit
a4b439eb69
11 changed files with 626 additions and 276 deletions
22
ChangeLog
22
ChangeLog
|
|
@ -1,3 +1,25 @@
|
||||||
|
2003-01-28 Carl Worth <cworth@isi.edu>
|
||||||
|
|
||||||
|
* xrtraps.c (_XrTrapsTessellateTriangle): Fixed to not re-order
|
||||||
|
the array provided as an argument. (Note: the rectangle and
|
||||||
|
polyghon tessellators still perform reordering).
|
||||||
|
|
||||||
|
* xrstroker.c (_XrStrokerJoin):
|
||||||
|
(_XrStrokerCap): Implemented round caps and joins.
|
||||||
|
(_XrStrokerDoneSubPath): Fixed initial cap, (was always being
|
||||||
|
drawn on the inside previously).
|
||||||
|
|
||||||
|
* xrpen.c (_XrPenInit): Fixed to keep pen vertex theta values all
|
||||||
|
in device space.
|
||||||
|
(_XrPenAddPoints): Removed the silly flags from the pen vertices,
|
||||||
|
(in favor of just using the FindActiveVertex functions)
|
||||||
|
(_XrPenFindActiveCWVertexIndex):
|
||||||
|
(_XrPenFindActiveCCWVertexIndex): Added functions needed for round
|
||||||
|
caps/joins.
|
||||||
|
|
||||||
|
* xrgstate.c (_XrGStateSetDash): Fixed to accept a NULL dash array
|
||||||
|
to revert to no dashing.
|
||||||
|
|
||||||
2003-01-28 Carl Worth <cworth@east.isi.edu>
|
2003-01-28 Carl Worth <cworth@east.isi.edu>
|
||||||
|
|
||||||
* xrtraps.c (_XrTrapsTessellateTriangle): Restored triangle
|
* xrtraps.c (_XrTrapsTessellateTriangle): Restored triangle
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ _XrGStateInit(XrGState *gstate, Display *dpy)
|
||||||
|
|
||||||
gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT;
|
gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT;
|
||||||
|
|
||||||
gstate->dashes = 0;
|
gstate->dash = NULL;
|
||||||
gstate->ndashes = 0;
|
gstate->num_dashes = 0;
|
||||||
gstate->dash_offset = 0.0;
|
gstate->dash_offset = 0.0;
|
||||||
|
|
||||||
gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8);
|
gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8);
|
||||||
|
|
@ -98,11 +98,11 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
||||||
XrStatus status;
|
XrStatus status;
|
||||||
|
|
||||||
*gstate = *other;
|
*gstate = *other;
|
||||||
if (other->dashes) {
|
if (other->dash) {
|
||||||
gstate->dashes = malloc (other->ndashes * sizeof (double));
|
gstate->dash = malloc (other->num_dashes * sizeof (double));
|
||||||
if (gstate->dashes == NULL)
|
if (gstate->dash == NULL)
|
||||||
return XrStatusNoMemory;
|
return XrStatusNoMemory;
|
||||||
memcpy(gstate->dashes, other->dashes, other->ndashes * sizeof (double));
|
memcpy(gstate->dash, other->dash, other->num_dashes * sizeof (double));
|
||||||
}
|
}
|
||||||
|
|
||||||
status = _XrFontInitCopy(&gstate->font, &other->font);
|
status = _XrFontInitCopy(&gstate->font, &other->font);
|
||||||
|
|
@ -130,8 +130,8 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
||||||
CLEANUP_FONT:
|
CLEANUP_FONT:
|
||||||
_XrFontDeinit(&gstate->font);
|
_XrFontDeinit(&gstate->font);
|
||||||
CLEANUP_DASHES:
|
CLEANUP_DASHES:
|
||||||
free (gstate->dashes);
|
free (gstate->dash);
|
||||||
gstate->dashes = NULL;
|
gstate->dash = NULL;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
@ -158,9 +158,9 @@ _XrGStateDeinit(XrGState *gstate)
|
||||||
|
|
||||||
_XrPenDeinit(&gstate->pen_regular);
|
_XrPenDeinit(&gstate->pen_regular);
|
||||||
|
|
||||||
if (gstate->dashes) {
|
if (gstate->dash) {
|
||||||
free (gstate->dashes);
|
free (gstate->dash);
|
||||||
gstate->dashes = NULL;
|
gstate->dash = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -363,19 +363,23 @@ _XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join)
|
||||||
}
|
}
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset)
|
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset)
|
||||||
{
|
{
|
||||||
if (gstate->dashes) {
|
if (gstate->dash) {
|
||||||
free (gstate->dashes);
|
free (gstate->dash);
|
||||||
|
gstate->dash = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gstate->dashes = malloc (ndash * sizeof (double));
|
gstate->num_dashes = num_dashes;
|
||||||
if (!gstate->dashes) {
|
if (gstate->num_dashes) {
|
||||||
gstate->ndashes = 0;
|
gstate->dash = malloc (gstate->num_dashes * sizeof (double));
|
||||||
|
if (gstate->dash == NULL) {
|
||||||
|
gstate->num_dashes = 0;
|
||||||
return XrStatusNoMemory;
|
return XrStatusNoMemory;
|
||||||
}
|
}
|
||||||
gstate->ndashes = ndash;
|
}
|
||||||
memcpy (gstate->dashes, dashes, ndash * sizeof (double));
|
|
||||||
|
memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double));
|
||||||
gstate->dash_offset = offset;
|
gstate->dash_offset = offset;
|
||||||
|
|
||||||
return XrStatusSuccess;
|
return XrStatusSuccess;
|
||||||
|
|
@ -639,7 +643,7 @@ _XrGStateStroke(XrGState *gstate)
|
||||||
_XrStrokerDoneSubPath,
|
_XrStrokerDoneSubPath,
|
||||||
_XrStrokerDonePath
|
_XrStrokerDonePath
|
||||||
};
|
};
|
||||||
XrPathCallbacks *cbs = gstate->dashes ? &cb_dash : &cb;
|
XrPathCallbacks *cbs = gstate->dash ? &cb_dash : &cb;
|
||||||
|
|
||||||
XrStroker stroker;
|
XrStroker stroker;
|
||||||
XrTraps traps;
|
XrTraps traps;
|
||||||
|
|
|
||||||
33
src/xrint.h
33
src/xrint.h
|
|
@ -137,20 +137,14 @@ typedef struct _XrSpline {
|
||||||
XPointFixed *pts;
|
XPointFixed *pts;
|
||||||
} XrSpline;
|
} XrSpline;
|
||||||
|
|
||||||
typedef enum _XrPenVertexFlag {
|
/* XXX: This can go away once incremental spline tessellation is working */
|
||||||
XrPenVertexFlagNone = 0,
|
typedef enum _XrPenStrokeDirection {
|
||||||
XrPenVertexFlagForward = 1,
|
XrPenStrokeDirectionForward,
|
||||||
XrPenVertexFlagReverse = 2
|
XrPenStrokeDirectionReverse
|
||||||
} XrPenVertexFlag;
|
} XrPenStrokeDirection;
|
||||||
|
|
||||||
typedef struct _XrPenFlaggedPoint {
|
|
||||||
XPointFixed pt;
|
|
||||||
XrPenVertexFlag flag;
|
|
||||||
} XrPenFlaggedPoint;
|
|
||||||
|
|
||||||
typedef struct _XrPenVertex {
|
typedef struct _XrPenVertex {
|
||||||
XPointFixed pt;
|
XPointFixed pt;
|
||||||
XrPenVertexFlag flag;
|
|
||||||
|
|
||||||
double theta;
|
double theta;
|
||||||
XrSlopeFixed slope_ccw;
|
XrSlopeFixed slope_ccw;
|
||||||
|
|
@ -244,8 +238,8 @@ typedef struct _XrGState {
|
||||||
|
|
||||||
XrFillRule fill_rule;
|
XrFillRule fill_rule;
|
||||||
|
|
||||||
double *dashes;
|
double *dash;
|
||||||
int ndashes;
|
int num_dashes;
|
||||||
double dash_offset;
|
double dash_offset;
|
||||||
|
|
||||||
XcFormat *alphaFormat;
|
XcFormat *alphaFormat;
|
||||||
|
|
@ -284,7 +278,8 @@ typedef struct _XrStrokeFace {
|
||||||
XPointFixed ccw;
|
XPointFixed ccw;
|
||||||
XPointFixed pt;
|
XPointFixed pt;
|
||||||
XPointFixed cw;
|
XPointFixed cw;
|
||||||
XPointDouble vector;
|
XrSlopeFixed dev_vector;
|
||||||
|
XPointDouble usr_vector;
|
||||||
} XrStrokeFace;
|
} XrStrokeFace;
|
||||||
|
|
||||||
typedef struct _XrStroker {
|
typedef struct _XrStroker {
|
||||||
|
|
@ -387,7 +382,7 @@ XrStatus
|
||||||
_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join);
|
_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset);
|
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrGStateSetMiterLimit(XrGState *gstate, double limit);
|
_XrGStateSetMiterLimit(XrGState *gstate, double limit);
|
||||||
|
|
@ -640,11 +635,17 @@ void
|
||||||
_XrPenDeinit(XrPen *pen);
|
_XrPenDeinit(XrPen *pen);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts);
|
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenAddPointsForSlopes(XrPen *pen, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
_XrPenAddPointsForSlopes(XrPen *pen, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||||
|
|
||||||
|
XrStatus
|
||||||
|
_XrPenFindActiveCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active);
|
||||||
|
|
||||||
|
XrStatus
|
||||||
|
_XrPenFindActiveCCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenStrokeSpline(XrPen *pen, XrSpline *spline, double tolerance, XrTraps *traps);
|
_XrPenStrokeSpline(XrPen *pen, XrSpline *spline, double tolerance, XrTraps *traps);
|
||||||
|
|
||||||
|
|
|
||||||
96
src/xrpen.c
96
src/xrpen.c
|
|
@ -41,8 +41,7 @@ static int
|
||||||
_XrPenVertexCompareByTheta(const void *a, const void *b);
|
_XrPenVertexCompareByTheta(const void *a, const void *b);
|
||||||
|
|
||||||
static XrStatus
|
static XrStatus
|
||||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline,
|
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon);
|
||||||
XrPenVertexFlag dir, XrPolygon *polygon);
|
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenInitEmpty(XrPen *pen)
|
_XrPenInitEmpty(XrPen *pen)
|
||||||
|
|
@ -93,7 +92,10 @@ _XrPenInit(XrPen *pen, double radius, XrGState *gstate)
|
||||||
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
||||||
v->pt.x = XDoubleToFixed(dx);
|
v->pt.x = XDoubleToFixed(dx);
|
||||||
v->pt.y = XDoubleToFixed(dy);
|
v->pt.y = XDoubleToFixed(dy);
|
||||||
v->flag = XrPenVertexFlagNone;
|
/* Recompute theta in device space */
|
||||||
|
v->theta = atan2(v->pt.y, v->pt.x);
|
||||||
|
if (v->theta < 0)
|
||||||
|
v->theta += 2 * M_PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
_XrPenComputeSlopes(pen);
|
_XrPenComputeSlopes(pen);
|
||||||
|
|
@ -141,7 +143,7 @@ _XrPenVertexCompareByTheta(const void *a, const void *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
XrPenVertex *v, *v_next, *new_vertex;
|
XrPenVertex *v, *v_next, *new_vertex;
|
||||||
|
|
@ -157,8 +159,7 @@ _XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
||||||
/* initialize new vertices */
|
/* initialize new vertices */
|
||||||
for (i=0; i < num_pts; i++) {
|
for (i=0; i < num_pts; i++) {
|
||||||
v = &pen->vertex[pen->num_vertices-(i+1)];
|
v = &pen->vertex[pen->num_vertices-(i+1)];
|
||||||
v->pt = pt[i].pt;
|
v->pt = pt[i];
|
||||||
v->flag = pt[i].flag;
|
|
||||||
v->theta = atan2(v->pt.y, v->pt.x);
|
v->theta = atan2(v->pt.y, v->pt.x);
|
||||||
if (v->theta < 0)
|
if (v->theta < 0)
|
||||||
v->theta += 2 * M_PI;
|
v->theta += 2 * M_PI;
|
||||||
|
|
@ -171,7 +172,6 @@ _XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
||||||
v = &pen->vertex[i];
|
v = &pen->vertex[i];
|
||||||
v_next = &pen->vertex[i+1];
|
v_next = &pen->vertex[i+1];
|
||||||
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
|
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
|
||||||
v->flag |= v_next->flag;
|
|
||||||
for (j=i+1; j < pen->num_vertices - 1; j++)
|
for (j=i+1; j < pen->num_vertices - 1; j++)
|
||||||
pen->vertex[j] = pen->vertex[j+1];
|
pen->vertex[j] = pen->vertex[j+1];
|
||||||
pen->num_vertices--;
|
pen->num_vertices--;
|
||||||
|
|
@ -223,6 +223,12 @@ _XrPenComputeSlopes(XrPen *pen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is a clockwise of b?
|
||||||
|
*
|
||||||
|
* NOTE: The strict equality here is not significant in and of itself,
|
||||||
|
* but there are functions up above that are sensitive to it,
|
||||||
|
* (cf. _XrPenFindActiveCWVertexIndex).
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
||||||
{
|
{
|
||||||
|
|
@ -240,40 +246,90 @@ _SlopeCounterClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
||||||
return ! _SlopeClockwise(a, b);
|
return ! _SlopeClockwise(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find active pen vertex for clockwise edge of stroke at the given slope.
|
||||||
|
*
|
||||||
|
* NOTE: The behavior of this function is sensitive to the sense of
|
||||||
|
* the inequality within _SlopeClockwise/_SlopeCounterClockwise.
|
||||||
|
*
|
||||||
|
* The issue is that the slope_ccw member of one pen vertex will be
|
||||||
|
* equivalent to the slope_cw member of the next pen vertex in a
|
||||||
|
* counterclockwise order. However, for this function, we care
|
||||||
|
* strongly about which vertex is returned.
|
||||||
|
*/
|
||||||
|
XrStatus
|
||||||
|
_XrPenFindActiveCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i < pen->num_vertices; i++) {
|
||||||
|
if (_SlopeClockwise(slope, &pen->vertex[i].slope_ccw)
|
||||||
|
&& _SlopeCounterClockwise(slope, &pen->vertex[i].slope_cw))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*active = i;
|
||||||
|
|
||||||
|
return XrStatusSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
|
||||||
|
*
|
||||||
|
* NOTE: The behavior of this function is sensitive to the sense of
|
||||||
|
* the inequality within _SlopeClockwise/_SlopeCounterClockwise.
|
||||||
|
*/
|
||||||
|
XrStatus
|
||||||
|
_XrPenFindActiveCCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
XrSlopeFixed slope_reverse;
|
||||||
|
|
||||||
|
slope_reverse = *slope;
|
||||||
|
slope_reverse.dx = -slope_reverse.dx;
|
||||||
|
slope_reverse.dy = -slope_reverse.dy;
|
||||||
|
|
||||||
|
for (i=pen->num_vertices-1; i >= 0; i--) {
|
||||||
|
if (_SlopeCounterClockwise(&pen->vertex[i].slope_ccw, &slope_reverse)
|
||||||
|
&& _SlopeClockwise(&pen->vertex[i].slope_cw, &slope_reverse))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*active = i;
|
||||||
|
|
||||||
|
return XrStatusSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
static XrStatus
|
static XrStatus
|
||||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline,
|
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon)
|
||||||
XrPenVertexFlag dir, XrPolygon *polygon)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
XrStatus status;
|
XrStatus status;
|
||||||
int start, stop, step;
|
int start, stop, step;
|
||||||
int active = 0;
|
int active = 0;
|
||||||
XPointFixed hull_pt;
|
XPointFixed hull_pt;
|
||||||
XrSlopeFixed slope, final_slope;
|
XrSlopeFixed slope, initial_slope, final_slope;
|
||||||
XPointFixed *pt = spline->pts;
|
XPointFixed *pt = spline->pts;
|
||||||
int num_pts = spline->num_pts;
|
int num_pts = spline->num_pts;
|
||||||
|
|
||||||
for (i=0; i < pen->num_vertices; i++) {
|
if (dir == XrPenStrokeDirectionForward) {
|
||||||
if (pen->vertex[i].flag & dir) {
|
|
||||||
active = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dir == XrPenVertexFlagForward) {
|
|
||||||
start = 0;
|
start = 0;
|
||||||
stop = num_pts;
|
stop = num_pts;
|
||||||
step = 1;
|
step = 1;
|
||||||
|
initial_slope = spline->initial_slope;
|
||||||
final_slope = spline->final_slope;
|
final_slope = spline->final_slope;
|
||||||
} else {
|
} else {
|
||||||
start = num_pts - 1;
|
start = num_pts - 1;
|
||||||
stop = -1;
|
stop = -1;
|
||||||
step = -1;
|
step = -1;
|
||||||
|
initial_slope = spline->final_slope;
|
||||||
|
initial_slope.dx = -initial_slope.dx;
|
||||||
|
initial_slope.dy = -initial_slope.dy;
|
||||||
final_slope = spline->initial_slope;
|
final_slope = spline->initial_slope;
|
||||||
final_slope.dx = -final_slope.dx;
|
final_slope.dx = -final_slope.dx;
|
||||||
final_slope.dy = -final_slope.dy;
|
final_slope.dy = -final_slope.dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &initial_slope, &active);
|
||||||
|
|
||||||
i = start;
|
i = start;
|
||||||
while (i != stop) {
|
while (i != stop) {
|
||||||
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
|
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
|
||||||
|
|
@ -318,11 +374,11 @@ _XrPenStrokeSpline(XrPen *pen,
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenVertexFlagForward, &polygon);
|
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionForward, &polygon);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenVertexFlagReverse, &polygon);
|
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionReverse, &polygon);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
|
|
||||||
199
src/xrstroker.c
199
src/xrstroker.c
|
|
@ -44,15 +44,15 @@ _XrStrokerStartDash (XrStroker *stroker)
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
offset = gstate->dash_offset;
|
offset = gstate->dash_offset;
|
||||||
while (offset >= gstate->dashes[i]) {
|
while (offset >= gstate->dash[i]) {
|
||||||
offset -= gstate->dashes[i];
|
offset -= gstate->dash[i];
|
||||||
on = 1-on;
|
on = 1-on;
|
||||||
if (++i == gstate->ndashes)
|
if (++i == gstate->num_dashes)
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
stroker->dash_index = i;
|
stroker->dash_index = i;
|
||||||
stroker->dash_on = on;
|
stroker->dash_on = on;
|
||||||
stroker->dash_remain = gstate->dashes[i] - offset;
|
stroker->dash_remain = gstate->dash[i] - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -62,10 +62,10 @@ _XrStrokerStepDash (XrStroker *stroker, double step)
|
||||||
stroker->dash_remain -= step;
|
stroker->dash_remain -= step;
|
||||||
if (stroker->dash_remain <= 0) {
|
if (stroker->dash_remain <= 0) {
|
||||||
stroker->dash_index++;
|
stroker->dash_index++;
|
||||||
if (stroker->dash_index == gstate->ndashes)
|
if (stroker->dash_index == gstate->num_dashes)
|
||||||
stroker->dash_index = 0;
|
stroker->dash_index = 0;
|
||||||
stroker->dash_on = 1-stroker->dash_on;
|
stroker->dash_on = 1-stroker->dash_on;
|
||||||
stroker->dash_remain = gstate->dashes[stroker->dash_index];
|
stroker->dash_remain = gstate->dash[stroker->dash_index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ _XrStrokerInit(XrStroker *stroker, XrGState *gstate, XrTraps *traps)
|
||||||
stroker->have_prev = 0;
|
stroker->have_prev = 0;
|
||||||
stroker->have_first = 0;
|
stroker->have_first = 0;
|
||||||
stroker->is_first = 1;
|
stroker->is_first = 1;
|
||||||
if (gstate->dashes)
|
if (gstate->dash)
|
||||||
_XrStrokerStartDash (stroker);
|
_XrStrokerStartDash (stroker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,12 +112,9 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
{
|
{
|
||||||
XrStatus status;
|
XrStatus status;
|
||||||
XrGState *gstate = stroker->gstate;
|
XrGState *gstate = stroker->gstate;
|
||||||
int clockwise = _XrStrokerFaceClockwise (in, out);
|
int clockwise = _XrStrokerFaceClockwise (out, in);
|
||||||
XPointFixed *inpt, *outpt;
|
XPointFixed *inpt, *outpt;
|
||||||
|
|
||||||
/* XXX: There might be a more natural place to check for the
|
|
||||||
degenerate join later in the code, (such as right before
|
|
||||||
dividing by zero) */
|
|
||||||
if (in->cw.x == out->cw.x
|
if (in->cw.x == out->cw.x
|
||||||
&& in->cw.y == out->cw.y
|
&& in->cw.y == out->cw.y
|
||||||
&& in->ccw.x == out->ccw.x
|
&& in->ccw.x == out->ccw.x
|
||||||
|
|
@ -126,20 +123,57 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clockwise) {
|
if (clockwise) {
|
||||||
inpt = &in->cw;
|
|
||||||
outpt = &out->cw;
|
|
||||||
} else {
|
|
||||||
inpt = &in->ccw;
|
inpt = &in->ccw;
|
||||||
outpt = &out->ccw;
|
outpt = &out->ccw;
|
||||||
|
} else {
|
||||||
|
inpt = &in->cw;
|
||||||
|
outpt = &out->cw;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (gstate->line_join) {
|
switch (gstate->line_join) {
|
||||||
case XrLineJoinRound:
|
case XrLineJoinRound: {
|
||||||
status = XrStatusSuccess;
|
int i;
|
||||||
break;
|
int start, step, stop;
|
||||||
case XrLineJoinMiter: {
|
XPointFixed tri[3], initial, final;
|
||||||
|
XrPen *pen = &gstate->pen_regular;
|
||||||
|
|
||||||
|
tri[0] = in->pt;
|
||||||
|
if (clockwise) {
|
||||||
|
initial = in->ccw;
|
||||||
|
_XrPenFindActiveCCWVertexIndex(pen, &in->dev_vector, &start);
|
||||||
|
step = -1;
|
||||||
|
_XrPenFindActiveCCWVertexIndex(pen, &out->dev_vector, &stop);
|
||||||
|
final = out->ccw;
|
||||||
|
} else {
|
||||||
|
initial = in->cw;
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &in->dev_vector, &start);
|
||||||
|
step = +1;
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &out->dev_vector, &stop);
|
||||||
|
final = out->cw;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = start;
|
||||||
|
tri[1] = initial;
|
||||||
|
while (i != stop) {
|
||||||
|
tri[2] = in->pt;
|
||||||
|
_TranslatePoint(&tri[2], &pen->vertex[i].pt);
|
||||||
|
_XrTrapsTessellateTriangle(stroker->traps, tri);
|
||||||
|
tri[1] = tri[2];
|
||||||
|
i += step;
|
||||||
|
if (i < 0)
|
||||||
|
i = pen->num_vertices - 1;
|
||||||
|
if (i >= pen->num_vertices)
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tri[2] = final;
|
||||||
|
|
||||||
|
return _XrTrapsTessellateTriangle(stroker->traps, tri);
|
||||||
|
}
|
||||||
|
case XrLineJoinMiter:
|
||||||
|
default: {
|
||||||
XrPolygon polygon;
|
XrPolygon polygon;
|
||||||
XDouble c = (-in->vector.x * out->vector.x)+(-in->vector.y * out->vector.y);
|
XDouble c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
|
||||||
XDouble ml = gstate->miter_limit;
|
XDouble ml = gstate->miter_limit;
|
||||||
|
|
||||||
_XrPolygonInit (&polygon);
|
_XrPolygonInit (&polygon);
|
||||||
|
|
@ -152,14 +186,14 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
|
|
||||||
x1 = XFixedToDouble(inpt->x);
|
x1 = XFixedToDouble(inpt->x);
|
||||||
y1 = XFixedToDouble(inpt->y);
|
y1 = XFixedToDouble(inpt->y);
|
||||||
dx1 = in->vector.x;
|
dx1 = in->usr_vector.x;
|
||||||
dy1 = in->vector.y;
|
dy1 = in->usr_vector.y;
|
||||||
_XrTransformDistance(&gstate->ctm, &dx1, &dy1);
|
_XrTransformDistance(&gstate->ctm, &dx1, &dy1);
|
||||||
|
|
||||||
x2 = XFixedToDouble(outpt->x);
|
x2 = XFixedToDouble(outpt->x);
|
||||||
y2 = XFixedToDouble(outpt->y);
|
y2 = XFixedToDouble(outpt->y);
|
||||||
dx2 = out->vector.x;
|
dx2 = out->usr_vector.x;
|
||||||
dy2 = out->vector.y;
|
dy2 = out->usr_vector.y;
|
||||||
_XrTransformDistance(&gstate->ctm, &dx2, &dy2);
|
_XrTransformDistance(&gstate->ctm, &dx2, &dy2);
|
||||||
|
|
||||||
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
||||||
|
|
@ -179,7 +213,8 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
&polygon,
|
&polygon,
|
||||||
XrFillRuleWinding);
|
XrFillRuleWinding);
|
||||||
_XrPolygonDeinit (&polygon);
|
_XrPolygonDeinit (&polygon);
|
||||||
break;
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
/* fall through ... */
|
/* fall through ... */
|
||||||
}
|
}
|
||||||
|
|
@ -188,12 +223,10 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
tri[0] = in->pt;
|
tri[0] = in->pt;
|
||||||
tri[1] = *inpt;
|
tri[1] = *inpt;
|
||||||
tri[2] = *outpt;
|
tri[2] = *outpt;
|
||||||
status = _XrTrapsTessellateTriangle (stroker->traps, tri);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return _XrTrapsTessellateTriangle (stroker->traps, tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static XrStatus
|
static XrStatus
|
||||||
|
|
@ -201,45 +234,70 @@ _XrStrokerCap(XrStroker *stroker, XrStrokeFace *f)
|
||||||
{
|
{
|
||||||
XrStatus status;
|
XrStatus status;
|
||||||
XrGState *gstate = stroker->gstate;
|
XrGState *gstate = stroker->gstate;
|
||||||
XrPolygon polygon;
|
|
||||||
|
|
||||||
if (gstate->line_cap == XrLineCapButt)
|
if (gstate->line_cap == XrLineCapButt)
|
||||||
return XrStatusSuccess;
|
return XrStatusSuccess;
|
||||||
|
|
||||||
_XrPolygonInit (&polygon);
|
|
||||||
switch (gstate->line_cap) {
|
switch (gstate->line_cap) {
|
||||||
case XrLineCapRound:
|
case XrLineCapRound: {
|
||||||
break;
|
int i;
|
||||||
|
int start, stop;
|
||||||
|
XrSlopeFixed slope;
|
||||||
|
XPointFixed tri[3];
|
||||||
|
XrPen *pen = &gstate->pen_regular;
|
||||||
|
|
||||||
|
slope = f->dev_vector;
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &slope, &start);
|
||||||
|
slope.dx = -slope.dx;
|
||||||
|
slope.dy = -slope.dy;
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &slope, &stop);
|
||||||
|
|
||||||
|
tri[0] = f->pt;
|
||||||
|
tri[1] = f->cw;
|
||||||
|
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
|
||||||
|
tri[2] = f->pt;
|
||||||
|
_TranslatePoint(&tri[2], &pen->vertex[i].pt);
|
||||||
|
_XrTrapsTessellateTriangle(stroker->traps, tri);
|
||||||
|
tri[1] = tri[2];
|
||||||
|
}
|
||||||
|
tri[2] = f->ccw;
|
||||||
|
|
||||||
|
return _XrTrapsTessellateTriangle(stroker->traps, tri);
|
||||||
|
}
|
||||||
case XrLineCapSquare: {
|
case XrLineCapSquare: {
|
||||||
double dx, dy;
|
double dx, dy;
|
||||||
XPointFixed fvector;
|
XrSlopeFixed fvector;
|
||||||
XPointFixed occw, ocw;
|
XPointFixed occw, ocw;
|
||||||
dx = f->vector.x;
|
XrPolygon polygon;
|
||||||
dy = f->vector.y;
|
|
||||||
|
_XrPolygonInit (&polygon);
|
||||||
|
|
||||||
|
dx = f->usr_vector.x;
|
||||||
|
dy = f->usr_vector.y;
|
||||||
dx *= gstate->line_width / 2.0;
|
dx *= gstate->line_width / 2.0;
|
||||||
dy *= gstate->line_width / 2.0;
|
dy *= gstate->line_width / 2.0;
|
||||||
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
||||||
fvector.x = XDoubleToFixed(dx);
|
fvector.dx = XDoubleToFixed(dx);
|
||||||
fvector.y = XDoubleToFixed(dy);
|
fvector.dy = XDoubleToFixed(dy);
|
||||||
occw.x = f->ccw.x + fvector.x;
|
occw.x = f->ccw.x + fvector.dx;
|
||||||
occw.y = f->ccw.y + fvector.y;
|
occw.y = f->ccw.y + fvector.dy;
|
||||||
ocw.x = f->cw.x + fvector.x;
|
ocw.x = f->cw.x + fvector.dx;
|
||||||
ocw.y = f->cw.y + fvector.y;
|
ocw.y = f->cw.y + fvector.dy;
|
||||||
|
|
||||||
_XrPolygonAddEdge (&polygon, &f->cw, &ocw);
|
_XrPolygonAddEdge (&polygon, &f->cw, &ocw);
|
||||||
_XrPolygonAddEdge (&polygon, &ocw, &occw);
|
_XrPolygonAddEdge (&polygon, &ocw, &occw);
|
||||||
_XrPolygonAddEdge (&polygon, &occw, &f->ccw);
|
_XrPolygonAddEdge (&polygon, &occw, &f->ccw);
|
||||||
_XrPolygonAddEdge (&polygon, &f->ccw, &f->cw);
|
_XrPolygonAddEdge (&polygon, &f->ccw, &f->cw);
|
||||||
break;
|
|
||||||
}
|
|
||||||
case XrLineCapButt:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = _XrTrapsTessellatePolygon (stroker->traps, &polygon, XrFillRuleWinding);
|
status = _XrTrapsTessellatePolygon (stroker->traps, &polygon, XrFillRuleWinding);
|
||||||
_XrPolygonDeinit (&polygon);
|
_XrPolygonDeinit (&polygon);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
}
|
||||||
|
case XrLineCapButt:
|
||||||
|
default:
|
||||||
|
return XrStatusSuccess;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -247,7 +305,7 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
||||||
{
|
{
|
||||||
double mag, tmp;
|
double mag, tmp;
|
||||||
double dx, dy;
|
double dx, dy;
|
||||||
XPointDouble user_vector;
|
XPointDouble usr_vector;
|
||||||
XPointFixed offset_ccw, offset_cw;
|
XPointFixed offset_ccw, offset_cw;
|
||||||
|
|
||||||
dx = XFixedToDouble(slope->dx);
|
dx = XFixedToDouble(slope->dx);
|
||||||
|
|
@ -264,8 +322,8 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
||||||
dx /= mag;
|
dx /= mag;
|
||||||
dy /= mag;
|
dy /= mag;
|
||||||
|
|
||||||
user_vector.x = dx;
|
usr_vector.x = dx;
|
||||||
user_vector.y = dy;
|
usr_vector.y = dy;
|
||||||
|
|
||||||
tmp = dx;
|
tmp = dx;
|
||||||
dx = - dy * (gstate->line_width / 2.0);
|
dx = - dy * (gstate->line_width / 2.0);
|
||||||
|
|
@ -286,8 +344,10 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
||||||
face->cw = *pt;
|
face->cw = *pt;
|
||||||
_TranslatePoint(&face->cw, &offset_cw);
|
_TranslatePoint(&face->cw, &offset_cw);
|
||||||
|
|
||||||
face->vector.x = user_vector.x;
|
face->usr_vector.x = usr_vector.x;
|
||||||
face->vector.y = user_vector.y;
|
face->usr_vector.y = usr_vector.y;
|
||||||
|
|
||||||
|
face->dev_vector = *slope;
|
||||||
}
|
}
|
||||||
|
|
||||||
static XrStatus
|
static XrStatus
|
||||||
|
|
@ -475,7 +535,7 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed
|
||||||
XrSpline spline;
|
XrSpline spline;
|
||||||
XrPen pen;
|
XrPen pen;
|
||||||
XrStrokeFace start, end;
|
XrStrokeFace start, end;
|
||||||
XrPenFlaggedPoint extra_points[4];
|
XPointFixed extra_points[4];
|
||||||
|
|
||||||
status = _XrSplineInit(&spline, a, b, c, d);
|
status = _XrSplineInit(&spline, a, b, c, d);
|
||||||
if (status == XrIntStatusDegenerate)
|
if (status == XrIntStatusDegenerate)
|
||||||
|
|
@ -502,18 +562,18 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed
|
||||||
stroker->prev = end;
|
stroker->prev = end;
|
||||||
stroker->is_first = 0;
|
stroker->is_first = 0;
|
||||||
|
|
||||||
extra_points[0].pt = start.cw; extra_points[0].flag = XrPenVertexFlagForward;
|
extra_points[0] = start.cw;
|
||||||
extra_points[0].pt.x -= start.pt.x;
|
extra_points[0].x -= start.pt.x;
|
||||||
extra_points[0].pt.y -= start.pt.y;
|
extra_points[0].y -= start.pt.y;
|
||||||
extra_points[1].pt = start.ccw; extra_points[1].flag = XrPenVertexFlagNone;
|
extra_points[1] = start.ccw;
|
||||||
extra_points[1].pt.x -= start.pt.x;
|
extra_points[1].x -= start.pt.x;
|
||||||
extra_points[1].pt.y -= start.pt.y;
|
extra_points[1].y -= start.pt.y;
|
||||||
extra_points[2].pt = end.cw; extra_points[2].flag = XrPenVertexFlagNone;
|
extra_points[2] = end.cw;
|
||||||
extra_points[2].pt.x -= end.pt.x;
|
extra_points[2].x -= end.pt.x;
|
||||||
extra_points[2].pt.y -= end.pt.y;
|
extra_points[2].y -= end.pt.y;
|
||||||
extra_points[3].pt = end.ccw; extra_points[3].flag = XrPenVertexFlagReverse;
|
extra_points[3] = end.ccw;
|
||||||
extra_points[3].pt.x -= end.pt.x;
|
extra_points[3].x -= end.pt.x;
|
||||||
extra_points[3].pt.y -= end.pt.y;
|
extra_points[3].y -= end.pt.y;
|
||||||
|
|
||||||
status = _XrPenAddPoints(&pen, extra_points, 4);
|
status = _XrPenAddPoints(&pen, extra_points, 4);
|
||||||
if (status)
|
if (status)
|
||||||
|
|
@ -548,6 +608,15 @@ _XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
|
||||||
/* fall through... */
|
/* fall through... */
|
||||||
case XrSubPathDoneCap:
|
case XrSubPathDoneCap:
|
||||||
if (stroker->have_first) {
|
if (stroker->have_first) {
|
||||||
|
XPointFixed t;
|
||||||
|
/* The initial cap needs an outward facing vector. Reverse everything */
|
||||||
|
stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
|
||||||
|
stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
|
||||||
|
stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
|
||||||
|
stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
|
||||||
|
t = stroker->first.cw;
|
||||||
|
stroker->first.cw = stroker->first.ccw;
|
||||||
|
stroker->first.ccw = t;
|
||||||
status = _XrStrokerCap (stroker, &stroker->first);
|
status = _XrStrokerCap (stroker, &stroker->first);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
|
||||||
|
|
@ -164,34 +164,66 @@ _ComparePointFixedByY (const void *av, const void *bv)
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
||||||
{
|
{
|
||||||
|
XrStatus status;
|
||||||
XLineFixed line;
|
XLineFixed line;
|
||||||
double intersect;
|
double intersect;
|
||||||
|
XPointFixed tsort[3];
|
||||||
|
|
||||||
qsort(t, 3, sizeof(XPointFixed), _ComparePointFixedByY);
|
memcpy(tsort, t, 3 * sizeof(XPointFixed));
|
||||||
|
qsort(tsort, 3, sizeof(XPointFixed), _ComparePointFixedByY);
|
||||||
|
|
||||||
/* horizontal top edge requires special handling */
|
/* horizontal top edge requires special handling */
|
||||||
if (t[0].y == t[1].y) {
|
if (tsort[0].y == tsort[1].y) {
|
||||||
if (t[0].x < t[1].x)
|
if (tsort[0].x < tsort[1].x)
|
||||||
_XrTrapsAddTrapFromPoints (traps, t[1].y, t[2].y, t[0], t[2], t[1], t[2]);
|
status = _XrTrapsAddTrapFromPoints (traps,
|
||||||
|
tsort[1].y, tsort[2].y,
|
||||||
|
tsort[0], tsort[2],
|
||||||
|
tsort[1], tsort[2]);
|
||||||
else
|
else
|
||||||
_XrTrapsAddTrapFromPoints (traps, t[1].y, t[2].y, t[1], t[2], t[0], t[2]);
|
status = _XrTrapsAddTrapFromPoints (traps,
|
||||||
return;
|
tsort[1].y, tsort[2].y,
|
||||||
|
tsort[1], tsort[2],
|
||||||
|
tsort[0], tsort[2]);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
line.p1 = t[0];
|
line.p1 = tsort[0];
|
||||||
line.p2 = t[1];
|
line.p2 = tsort[1];
|
||||||
|
|
||||||
intersect = _ComputeX (&line, t[2].y);
|
intersect = _ComputeX (&line, tsort[2].y);
|
||||||
|
|
||||||
if (intersect < t[2].x) {
|
if (intersect < tsort[2].x) {
|
||||||
_XrTrapsAddTrapFromPoints(traps, t[0].y, t[1].y, t[0], t[1], t[0], t[2]);
|
status = _XrTrapsAddTrapFromPoints(traps,
|
||||||
_XrTrapsAddTrapFromPoints(traps, t[1].y, t[2].y, t[1], t[2], t[0], t[2]);
|
tsort[0].y, tsort[1].y,
|
||||||
|
tsort[0], tsort[1],
|
||||||
|
tsort[0], tsort[2]);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
status = _XrTrapsAddTrapFromPoints(traps,
|
||||||
|
tsort[1].y, tsort[2].y,
|
||||||
|
tsort[1], tsort[2],
|
||||||
|
tsort[0], tsort[2]);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
} else {
|
} else {
|
||||||
_XrTrapsAddTrapFromPoints(traps, t[0].y, t[1].y, t[0], t[2], t[0], t[1]);
|
status = _XrTrapsAddTrapFromPoints(traps,
|
||||||
_XrTrapsAddTrapFromPoints(traps, t[1].y, t[2].y, t[0], t[2], t[1], t[2]);
|
tsort[0].y, tsort[1].y,
|
||||||
|
tsort[0], tsort[2],
|
||||||
|
tsort[0], tsort[1]);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
status = _XrTrapsAddTrapFromPoints(traps,
|
||||||
|
tsort[1].y, tsort[2].y,
|
||||||
|
tsort[0], tsort[2],
|
||||||
|
tsort[1], tsort[2]);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return XrStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Warning: This function reorderd the elements of the array provided. */
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
||||||
{
|
{
|
||||||
|
|
@ -432,6 +464,8 @@ _SortEdgeList(XrEdge **active)
|
||||||
active edges, forming a trapezoid between each adjacent pair. Then,
|
active edges, forming a trapezoid between each adjacent pair. Then,
|
||||||
either the even-odd or winding rule is used to determine whether to
|
either the even-odd or winding rule is used to determine whether to
|
||||||
emit each of these trapezoids.
|
emit each of these trapezoids.
|
||||||
|
|
||||||
|
Warning: This function reorders the edges of the polygon provided.
|
||||||
*/
|
*/
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrTrapsTessellatePolygon (XrTraps *traps,
|
_XrTrapsTessellatePolygon (XrTraps *traps,
|
||||||
|
|
|
||||||
44
xrgstate.c
44
xrgstate.c
|
|
@ -63,8 +63,8 @@ _XrGStateInit(XrGState *gstate, Display *dpy)
|
||||||
|
|
||||||
gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT;
|
gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT;
|
||||||
|
|
||||||
gstate->dashes = 0;
|
gstate->dash = NULL;
|
||||||
gstate->ndashes = 0;
|
gstate->num_dashes = 0;
|
||||||
gstate->dash_offset = 0.0;
|
gstate->dash_offset = 0.0;
|
||||||
|
|
||||||
gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8);
|
gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8);
|
||||||
|
|
@ -98,11 +98,11 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
||||||
XrStatus status;
|
XrStatus status;
|
||||||
|
|
||||||
*gstate = *other;
|
*gstate = *other;
|
||||||
if (other->dashes) {
|
if (other->dash) {
|
||||||
gstate->dashes = malloc (other->ndashes * sizeof (double));
|
gstate->dash = malloc (other->num_dashes * sizeof (double));
|
||||||
if (gstate->dashes == NULL)
|
if (gstate->dash == NULL)
|
||||||
return XrStatusNoMemory;
|
return XrStatusNoMemory;
|
||||||
memcpy(gstate->dashes, other->dashes, other->ndashes * sizeof (double));
|
memcpy(gstate->dash, other->dash, other->num_dashes * sizeof (double));
|
||||||
}
|
}
|
||||||
|
|
||||||
status = _XrFontInitCopy(&gstate->font, &other->font);
|
status = _XrFontInitCopy(&gstate->font, &other->font);
|
||||||
|
|
@ -130,8 +130,8 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
||||||
CLEANUP_FONT:
|
CLEANUP_FONT:
|
||||||
_XrFontDeinit(&gstate->font);
|
_XrFontDeinit(&gstate->font);
|
||||||
CLEANUP_DASHES:
|
CLEANUP_DASHES:
|
||||||
free (gstate->dashes);
|
free (gstate->dash);
|
||||||
gstate->dashes = NULL;
|
gstate->dash = NULL;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
@ -158,9 +158,9 @@ _XrGStateDeinit(XrGState *gstate)
|
||||||
|
|
||||||
_XrPenDeinit(&gstate->pen_regular);
|
_XrPenDeinit(&gstate->pen_regular);
|
||||||
|
|
||||||
if (gstate->dashes) {
|
if (gstate->dash) {
|
||||||
free (gstate->dashes);
|
free (gstate->dash);
|
||||||
gstate->dashes = NULL;
|
gstate->dash = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -363,19 +363,23 @@ _XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join)
|
||||||
}
|
}
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset)
|
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset)
|
||||||
{
|
{
|
||||||
if (gstate->dashes) {
|
if (gstate->dash) {
|
||||||
free (gstate->dashes);
|
free (gstate->dash);
|
||||||
|
gstate->dash = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gstate->dashes = malloc (ndash * sizeof (double));
|
gstate->num_dashes = num_dashes;
|
||||||
if (!gstate->dashes) {
|
if (gstate->num_dashes) {
|
||||||
gstate->ndashes = 0;
|
gstate->dash = malloc (gstate->num_dashes * sizeof (double));
|
||||||
|
if (gstate->dash == NULL) {
|
||||||
|
gstate->num_dashes = 0;
|
||||||
return XrStatusNoMemory;
|
return XrStatusNoMemory;
|
||||||
}
|
}
|
||||||
gstate->ndashes = ndash;
|
}
|
||||||
memcpy (gstate->dashes, dashes, ndash * sizeof (double));
|
|
||||||
|
memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double));
|
||||||
gstate->dash_offset = offset;
|
gstate->dash_offset = offset;
|
||||||
|
|
||||||
return XrStatusSuccess;
|
return XrStatusSuccess;
|
||||||
|
|
@ -639,7 +643,7 @@ _XrGStateStroke(XrGState *gstate)
|
||||||
_XrStrokerDoneSubPath,
|
_XrStrokerDoneSubPath,
|
||||||
_XrStrokerDonePath
|
_XrStrokerDonePath
|
||||||
};
|
};
|
||||||
XrPathCallbacks *cbs = gstate->dashes ? &cb_dash : &cb;
|
XrPathCallbacks *cbs = gstate->dash ? &cb_dash : &cb;
|
||||||
|
|
||||||
XrStroker stroker;
|
XrStroker stroker;
|
||||||
XrTraps traps;
|
XrTraps traps;
|
||||||
|
|
|
||||||
33
xrint.h
33
xrint.h
|
|
@ -137,20 +137,14 @@ typedef struct _XrSpline {
|
||||||
XPointFixed *pts;
|
XPointFixed *pts;
|
||||||
} XrSpline;
|
} XrSpline;
|
||||||
|
|
||||||
typedef enum _XrPenVertexFlag {
|
/* XXX: This can go away once incremental spline tessellation is working */
|
||||||
XrPenVertexFlagNone = 0,
|
typedef enum _XrPenStrokeDirection {
|
||||||
XrPenVertexFlagForward = 1,
|
XrPenStrokeDirectionForward,
|
||||||
XrPenVertexFlagReverse = 2
|
XrPenStrokeDirectionReverse
|
||||||
} XrPenVertexFlag;
|
} XrPenStrokeDirection;
|
||||||
|
|
||||||
typedef struct _XrPenFlaggedPoint {
|
|
||||||
XPointFixed pt;
|
|
||||||
XrPenVertexFlag flag;
|
|
||||||
} XrPenFlaggedPoint;
|
|
||||||
|
|
||||||
typedef struct _XrPenVertex {
|
typedef struct _XrPenVertex {
|
||||||
XPointFixed pt;
|
XPointFixed pt;
|
||||||
XrPenVertexFlag flag;
|
|
||||||
|
|
||||||
double theta;
|
double theta;
|
||||||
XrSlopeFixed slope_ccw;
|
XrSlopeFixed slope_ccw;
|
||||||
|
|
@ -244,8 +238,8 @@ typedef struct _XrGState {
|
||||||
|
|
||||||
XrFillRule fill_rule;
|
XrFillRule fill_rule;
|
||||||
|
|
||||||
double *dashes;
|
double *dash;
|
||||||
int ndashes;
|
int num_dashes;
|
||||||
double dash_offset;
|
double dash_offset;
|
||||||
|
|
||||||
XcFormat *alphaFormat;
|
XcFormat *alphaFormat;
|
||||||
|
|
@ -284,7 +278,8 @@ typedef struct _XrStrokeFace {
|
||||||
XPointFixed ccw;
|
XPointFixed ccw;
|
||||||
XPointFixed pt;
|
XPointFixed pt;
|
||||||
XPointFixed cw;
|
XPointFixed cw;
|
||||||
XPointDouble vector;
|
XrSlopeFixed dev_vector;
|
||||||
|
XPointDouble usr_vector;
|
||||||
} XrStrokeFace;
|
} XrStrokeFace;
|
||||||
|
|
||||||
typedef struct _XrStroker {
|
typedef struct _XrStroker {
|
||||||
|
|
@ -387,7 +382,7 @@ XrStatus
|
||||||
_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join);
|
_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset);
|
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrGStateSetMiterLimit(XrGState *gstate, double limit);
|
_XrGStateSetMiterLimit(XrGState *gstate, double limit);
|
||||||
|
|
@ -640,11 +635,17 @@ void
|
||||||
_XrPenDeinit(XrPen *pen);
|
_XrPenDeinit(XrPen *pen);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts);
|
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenAddPointsForSlopes(XrPen *pen, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
_XrPenAddPointsForSlopes(XrPen *pen, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||||
|
|
||||||
|
XrStatus
|
||||||
|
_XrPenFindActiveCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active);
|
||||||
|
|
||||||
|
XrStatus
|
||||||
|
_XrPenFindActiveCCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active);
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenStrokeSpline(XrPen *pen, XrSpline *spline, double tolerance, XrTraps *traps);
|
_XrPenStrokeSpline(XrPen *pen, XrSpline *spline, double tolerance, XrTraps *traps);
|
||||||
|
|
||||||
|
|
|
||||||
96
xrpen.c
96
xrpen.c
|
|
@ -41,8 +41,7 @@ static int
|
||||||
_XrPenVertexCompareByTheta(const void *a, const void *b);
|
_XrPenVertexCompareByTheta(const void *a, const void *b);
|
||||||
|
|
||||||
static XrStatus
|
static XrStatus
|
||||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline,
|
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon);
|
||||||
XrPenVertexFlag dir, XrPolygon *polygon);
|
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenInitEmpty(XrPen *pen)
|
_XrPenInitEmpty(XrPen *pen)
|
||||||
|
|
@ -93,7 +92,10 @@ _XrPenInit(XrPen *pen, double radius, XrGState *gstate)
|
||||||
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
||||||
v->pt.x = XDoubleToFixed(dx);
|
v->pt.x = XDoubleToFixed(dx);
|
||||||
v->pt.y = XDoubleToFixed(dy);
|
v->pt.y = XDoubleToFixed(dy);
|
||||||
v->flag = XrPenVertexFlagNone;
|
/* Recompute theta in device space */
|
||||||
|
v->theta = atan2(v->pt.y, v->pt.x);
|
||||||
|
if (v->theta < 0)
|
||||||
|
v->theta += 2 * M_PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
_XrPenComputeSlopes(pen);
|
_XrPenComputeSlopes(pen);
|
||||||
|
|
@ -141,7 +143,7 @@ _XrPenVertexCompareByTheta(const void *a, const void *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
XrPenVertex *v, *v_next, *new_vertex;
|
XrPenVertex *v, *v_next, *new_vertex;
|
||||||
|
|
@ -157,8 +159,7 @@ _XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
||||||
/* initialize new vertices */
|
/* initialize new vertices */
|
||||||
for (i=0; i < num_pts; i++) {
|
for (i=0; i < num_pts; i++) {
|
||||||
v = &pen->vertex[pen->num_vertices-(i+1)];
|
v = &pen->vertex[pen->num_vertices-(i+1)];
|
||||||
v->pt = pt[i].pt;
|
v->pt = pt[i];
|
||||||
v->flag = pt[i].flag;
|
|
||||||
v->theta = atan2(v->pt.y, v->pt.x);
|
v->theta = atan2(v->pt.y, v->pt.x);
|
||||||
if (v->theta < 0)
|
if (v->theta < 0)
|
||||||
v->theta += 2 * M_PI;
|
v->theta += 2 * M_PI;
|
||||||
|
|
@ -171,7 +172,6 @@ _XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
||||||
v = &pen->vertex[i];
|
v = &pen->vertex[i];
|
||||||
v_next = &pen->vertex[i+1];
|
v_next = &pen->vertex[i+1];
|
||||||
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
|
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
|
||||||
v->flag |= v_next->flag;
|
|
||||||
for (j=i+1; j < pen->num_vertices - 1; j++)
|
for (j=i+1; j < pen->num_vertices - 1; j++)
|
||||||
pen->vertex[j] = pen->vertex[j+1];
|
pen->vertex[j] = pen->vertex[j+1];
|
||||||
pen->num_vertices--;
|
pen->num_vertices--;
|
||||||
|
|
@ -223,6 +223,12 @@ _XrPenComputeSlopes(XrPen *pen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is a clockwise of b?
|
||||||
|
*
|
||||||
|
* NOTE: The strict equality here is not significant in and of itself,
|
||||||
|
* but there are functions up above that are sensitive to it,
|
||||||
|
* (cf. _XrPenFindActiveCWVertexIndex).
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
||||||
{
|
{
|
||||||
|
|
@ -240,40 +246,90 @@ _SlopeCounterClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
||||||
return ! _SlopeClockwise(a, b);
|
return ! _SlopeClockwise(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find active pen vertex for clockwise edge of stroke at the given slope.
|
||||||
|
*
|
||||||
|
* NOTE: The behavior of this function is sensitive to the sense of
|
||||||
|
* the inequality within _SlopeClockwise/_SlopeCounterClockwise.
|
||||||
|
*
|
||||||
|
* The issue is that the slope_ccw member of one pen vertex will be
|
||||||
|
* equivalent to the slope_cw member of the next pen vertex in a
|
||||||
|
* counterclockwise order. However, for this function, we care
|
||||||
|
* strongly about which vertex is returned.
|
||||||
|
*/
|
||||||
|
XrStatus
|
||||||
|
_XrPenFindActiveCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i < pen->num_vertices; i++) {
|
||||||
|
if (_SlopeClockwise(slope, &pen->vertex[i].slope_ccw)
|
||||||
|
&& _SlopeCounterClockwise(slope, &pen->vertex[i].slope_cw))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*active = i;
|
||||||
|
|
||||||
|
return XrStatusSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
|
||||||
|
*
|
||||||
|
* NOTE: The behavior of this function is sensitive to the sense of
|
||||||
|
* the inequality within _SlopeClockwise/_SlopeCounterClockwise.
|
||||||
|
*/
|
||||||
|
XrStatus
|
||||||
|
_XrPenFindActiveCCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
XrSlopeFixed slope_reverse;
|
||||||
|
|
||||||
|
slope_reverse = *slope;
|
||||||
|
slope_reverse.dx = -slope_reverse.dx;
|
||||||
|
slope_reverse.dy = -slope_reverse.dy;
|
||||||
|
|
||||||
|
for (i=pen->num_vertices-1; i >= 0; i--) {
|
||||||
|
if (_SlopeCounterClockwise(&pen->vertex[i].slope_ccw, &slope_reverse)
|
||||||
|
&& _SlopeClockwise(&pen->vertex[i].slope_cw, &slope_reverse))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*active = i;
|
||||||
|
|
||||||
|
return XrStatusSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
static XrStatus
|
static XrStatus
|
||||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline,
|
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon)
|
||||||
XrPenVertexFlag dir, XrPolygon *polygon)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
XrStatus status;
|
XrStatus status;
|
||||||
int start, stop, step;
|
int start, stop, step;
|
||||||
int active = 0;
|
int active = 0;
|
||||||
XPointFixed hull_pt;
|
XPointFixed hull_pt;
|
||||||
XrSlopeFixed slope, final_slope;
|
XrSlopeFixed slope, initial_slope, final_slope;
|
||||||
XPointFixed *pt = spline->pts;
|
XPointFixed *pt = spline->pts;
|
||||||
int num_pts = spline->num_pts;
|
int num_pts = spline->num_pts;
|
||||||
|
|
||||||
for (i=0; i < pen->num_vertices; i++) {
|
if (dir == XrPenStrokeDirectionForward) {
|
||||||
if (pen->vertex[i].flag & dir) {
|
|
||||||
active = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dir == XrPenVertexFlagForward) {
|
|
||||||
start = 0;
|
start = 0;
|
||||||
stop = num_pts;
|
stop = num_pts;
|
||||||
step = 1;
|
step = 1;
|
||||||
|
initial_slope = spline->initial_slope;
|
||||||
final_slope = spline->final_slope;
|
final_slope = spline->final_slope;
|
||||||
} else {
|
} else {
|
||||||
start = num_pts - 1;
|
start = num_pts - 1;
|
||||||
stop = -1;
|
stop = -1;
|
||||||
step = -1;
|
step = -1;
|
||||||
|
initial_slope = spline->final_slope;
|
||||||
|
initial_slope.dx = -initial_slope.dx;
|
||||||
|
initial_slope.dy = -initial_slope.dy;
|
||||||
final_slope = spline->initial_slope;
|
final_slope = spline->initial_slope;
|
||||||
final_slope.dx = -final_slope.dx;
|
final_slope.dx = -final_slope.dx;
|
||||||
final_slope.dy = -final_slope.dy;
|
final_slope.dy = -final_slope.dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &initial_slope, &active);
|
||||||
|
|
||||||
i = start;
|
i = start;
|
||||||
while (i != stop) {
|
while (i != stop) {
|
||||||
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
|
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
|
||||||
|
|
@ -318,11 +374,11 @@ _XrPenStrokeSpline(XrPen *pen,
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenVertexFlagForward, &polygon);
|
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionForward, &polygon);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenVertexFlagReverse, &polygon);
|
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionReverse, &polygon);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
|
|
||||||
199
xrstroker.c
199
xrstroker.c
|
|
@ -44,15 +44,15 @@ _XrStrokerStartDash (XrStroker *stroker)
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
offset = gstate->dash_offset;
|
offset = gstate->dash_offset;
|
||||||
while (offset >= gstate->dashes[i]) {
|
while (offset >= gstate->dash[i]) {
|
||||||
offset -= gstate->dashes[i];
|
offset -= gstate->dash[i];
|
||||||
on = 1-on;
|
on = 1-on;
|
||||||
if (++i == gstate->ndashes)
|
if (++i == gstate->num_dashes)
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
stroker->dash_index = i;
|
stroker->dash_index = i;
|
||||||
stroker->dash_on = on;
|
stroker->dash_on = on;
|
||||||
stroker->dash_remain = gstate->dashes[i] - offset;
|
stroker->dash_remain = gstate->dash[i] - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -62,10 +62,10 @@ _XrStrokerStepDash (XrStroker *stroker, double step)
|
||||||
stroker->dash_remain -= step;
|
stroker->dash_remain -= step;
|
||||||
if (stroker->dash_remain <= 0) {
|
if (stroker->dash_remain <= 0) {
|
||||||
stroker->dash_index++;
|
stroker->dash_index++;
|
||||||
if (stroker->dash_index == gstate->ndashes)
|
if (stroker->dash_index == gstate->num_dashes)
|
||||||
stroker->dash_index = 0;
|
stroker->dash_index = 0;
|
||||||
stroker->dash_on = 1-stroker->dash_on;
|
stroker->dash_on = 1-stroker->dash_on;
|
||||||
stroker->dash_remain = gstate->dashes[stroker->dash_index];
|
stroker->dash_remain = gstate->dash[stroker->dash_index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ _XrStrokerInit(XrStroker *stroker, XrGState *gstate, XrTraps *traps)
|
||||||
stroker->have_prev = 0;
|
stroker->have_prev = 0;
|
||||||
stroker->have_first = 0;
|
stroker->have_first = 0;
|
||||||
stroker->is_first = 1;
|
stroker->is_first = 1;
|
||||||
if (gstate->dashes)
|
if (gstate->dash)
|
||||||
_XrStrokerStartDash (stroker);
|
_XrStrokerStartDash (stroker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,12 +112,9 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
{
|
{
|
||||||
XrStatus status;
|
XrStatus status;
|
||||||
XrGState *gstate = stroker->gstate;
|
XrGState *gstate = stroker->gstate;
|
||||||
int clockwise = _XrStrokerFaceClockwise (in, out);
|
int clockwise = _XrStrokerFaceClockwise (out, in);
|
||||||
XPointFixed *inpt, *outpt;
|
XPointFixed *inpt, *outpt;
|
||||||
|
|
||||||
/* XXX: There might be a more natural place to check for the
|
|
||||||
degenerate join later in the code, (such as right before
|
|
||||||
dividing by zero) */
|
|
||||||
if (in->cw.x == out->cw.x
|
if (in->cw.x == out->cw.x
|
||||||
&& in->cw.y == out->cw.y
|
&& in->cw.y == out->cw.y
|
||||||
&& in->ccw.x == out->ccw.x
|
&& in->ccw.x == out->ccw.x
|
||||||
|
|
@ -126,20 +123,57 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clockwise) {
|
if (clockwise) {
|
||||||
inpt = &in->cw;
|
|
||||||
outpt = &out->cw;
|
|
||||||
} else {
|
|
||||||
inpt = &in->ccw;
|
inpt = &in->ccw;
|
||||||
outpt = &out->ccw;
|
outpt = &out->ccw;
|
||||||
|
} else {
|
||||||
|
inpt = &in->cw;
|
||||||
|
outpt = &out->cw;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (gstate->line_join) {
|
switch (gstate->line_join) {
|
||||||
case XrLineJoinRound:
|
case XrLineJoinRound: {
|
||||||
status = XrStatusSuccess;
|
int i;
|
||||||
break;
|
int start, step, stop;
|
||||||
case XrLineJoinMiter: {
|
XPointFixed tri[3], initial, final;
|
||||||
|
XrPen *pen = &gstate->pen_regular;
|
||||||
|
|
||||||
|
tri[0] = in->pt;
|
||||||
|
if (clockwise) {
|
||||||
|
initial = in->ccw;
|
||||||
|
_XrPenFindActiveCCWVertexIndex(pen, &in->dev_vector, &start);
|
||||||
|
step = -1;
|
||||||
|
_XrPenFindActiveCCWVertexIndex(pen, &out->dev_vector, &stop);
|
||||||
|
final = out->ccw;
|
||||||
|
} else {
|
||||||
|
initial = in->cw;
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &in->dev_vector, &start);
|
||||||
|
step = +1;
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &out->dev_vector, &stop);
|
||||||
|
final = out->cw;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = start;
|
||||||
|
tri[1] = initial;
|
||||||
|
while (i != stop) {
|
||||||
|
tri[2] = in->pt;
|
||||||
|
_TranslatePoint(&tri[2], &pen->vertex[i].pt);
|
||||||
|
_XrTrapsTessellateTriangle(stroker->traps, tri);
|
||||||
|
tri[1] = tri[2];
|
||||||
|
i += step;
|
||||||
|
if (i < 0)
|
||||||
|
i = pen->num_vertices - 1;
|
||||||
|
if (i >= pen->num_vertices)
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tri[2] = final;
|
||||||
|
|
||||||
|
return _XrTrapsTessellateTriangle(stroker->traps, tri);
|
||||||
|
}
|
||||||
|
case XrLineJoinMiter:
|
||||||
|
default: {
|
||||||
XrPolygon polygon;
|
XrPolygon polygon;
|
||||||
XDouble c = (-in->vector.x * out->vector.x)+(-in->vector.y * out->vector.y);
|
XDouble c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
|
||||||
XDouble ml = gstate->miter_limit;
|
XDouble ml = gstate->miter_limit;
|
||||||
|
|
||||||
_XrPolygonInit (&polygon);
|
_XrPolygonInit (&polygon);
|
||||||
|
|
@ -152,14 +186,14 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
|
|
||||||
x1 = XFixedToDouble(inpt->x);
|
x1 = XFixedToDouble(inpt->x);
|
||||||
y1 = XFixedToDouble(inpt->y);
|
y1 = XFixedToDouble(inpt->y);
|
||||||
dx1 = in->vector.x;
|
dx1 = in->usr_vector.x;
|
||||||
dy1 = in->vector.y;
|
dy1 = in->usr_vector.y;
|
||||||
_XrTransformDistance(&gstate->ctm, &dx1, &dy1);
|
_XrTransformDistance(&gstate->ctm, &dx1, &dy1);
|
||||||
|
|
||||||
x2 = XFixedToDouble(outpt->x);
|
x2 = XFixedToDouble(outpt->x);
|
||||||
y2 = XFixedToDouble(outpt->y);
|
y2 = XFixedToDouble(outpt->y);
|
||||||
dx2 = out->vector.x;
|
dx2 = out->usr_vector.x;
|
||||||
dy2 = out->vector.y;
|
dy2 = out->usr_vector.y;
|
||||||
_XrTransformDistance(&gstate->ctm, &dx2, &dy2);
|
_XrTransformDistance(&gstate->ctm, &dx2, &dy2);
|
||||||
|
|
||||||
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
||||||
|
|
@ -179,7 +213,8 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
&polygon,
|
&polygon,
|
||||||
XrFillRuleWinding);
|
XrFillRuleWinding);
|
||||||
_XrPolygonDeinit (&polygon);
|
_XrPolygonDeinit (&polygon);
|
||||||
break;
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
/* fall through ... */
|
/* fall through ... */
|
||||||
}
|
}
|
||||||
|
|
@ -188,12 +223,10 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
||||||
tri[0] = in->pt;
|
tri[0] = in->pt;
|
||||||
tri[1] = *inpt;
|
tri[1] = *inpt;
|
||||||
tri[2] = *outpt;
|
tri[2] = *outpt;
|
||||||
status = _XrTrapsTessellateTriangle (stroker->traps, tri);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return _XrTrapsTessellateTriangle (stroker->traps, tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static XrStatus
|
static XrStatus
|
||||||
|
|
@ -201,45 +234,70 @@ _XrStrokerCap(XrStroker *stroker, XrStrokeFace *f)
|
||||||
{
|
{
|
||||||
XrStatus status;
|
XrStatus status;
|
||||||
XrGState *gstate = stroker->gstate;
|
XrGState *gstate = stroker->gstate;
|
||||||
XrPolygon polygon;
|
|
||||||
|
|
||||||
if (gstate->line_cap == XrLineCapButt)
|
if (gstate->line_cap == XrLineCapButt)
|
||||||
return XrStatusSuccess;
|
return XrStatusSuccess;
|
||||||
|
|
||||||
_XrPolygonInit (&polygon);
|
|
||||||
switch (gstate->line_cap) {
|
switch (gstate->line_cap) {
|
||||||
case XrLineCapRound:
|
case XrLineCapRound: {
|
||||||
break;
|
int i;
|
||||||
|
int start, stop;
|
||||||
|
XrSlopeFixed slope;
|
||||||
|
XPointFixed tri[3];
|
||||||
|
XrPen *pen = &gstate->pen_regular;
|
||||||
|
|
||||||
|
slope = f->dev_vector;
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &slope, &start);
|
||||||
|
slope.dx = -slope.dx;
|
||||||
|
slope.dy = -slope.dy;
|
||||||
|
_XrPenFindActiveCWVertexIndex(pen, &slope, &stop);
|
||||||
|
|
||||||
|
tri[0] = f->pt;
|
||||||
|
tri[1] = f->cw;
|
||||||
|
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
|
||||||
|
tri[2] = f->pt;
|
||||||
|
_TranslatePoint(&tri[2], &pen->vertex[i].pt);
|
||||||
|
_XrTrapsTessellateTriangle(stroker->traps, tri);
|
||||||
|
tri[1] = tri[2];
|
||||||
|
}
|
||||||
|
tri[2] = f->ccw;
|
||||||
|
|
||||||
|
return _XrTrapsTessellateTriangle(stroker->traps, tri);
|
||||||
|
}
|
||||||
case XrLineCapSquare: {
|
case XrLineCapSquare: {
|
||||||
double dx, dy;
|
double dx, dy;
|
||||||
XPointFixed fvector;
|
XrSlopeFixed fvector;
|
||||||
XPointFixed occw, ocw;
|
XPointFixed occw, ocw;
|
||||||
dx = f->vector.x;
|
XrPolygon polygon;
|
||||||
dy = f->vector.y;
|
|
||||||
|
_XrPolygonInit (&polygon);
|
||||||
|
|
||||||
|
dx = f->usr_vector.x;
|
||||||
|
dy = f->usr_vector.y;
|
||||||
dx *= gstate->line_width / 2.0;
|
dx *= gstate->line_width / 2.0;
|
||||||
dy *= gstate->line_width / 2.0;
|
dy *= gstate->line_width / 2.0;
|
||||||
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
||||||
fvector.x = XDoubleToFixed(dx);
|
fvector.dx = XDoubleToFixed(dx);
|
||||||
fvector.y = XDoubleToFixed(dy);
|
fvector.dy = XDoubleToFixed(dy);
|
||||||
occw.x = f->ccw.x + fvector.x;
|
occw.x = f->ccw.x + fvector.dx;
|
||||||
occw.y = f->ccw.y + fvector.y;
|
occw.y = f->ccw.y + fvector.dy;
|
||||||
ocw.x = f->cw.x + fvector.x;
|
ocw.x = f->cw.x + fvector.dx;
|
||||||
ocw.y = f->cw.y + fvector.y;
|
ocw.y = f->cw.y + fvector.dy;
|
||||||
|
|
||||||
_XrPolygonAddEdge (&polygon, &f->cw, &ocw);
|
_XrPolygonAddEdge (&polygon, &f->cw, &ocw);
|
||||||
_XrPolygonAddEdge (&polygon, &ocw, &occw);
|
_XrPolygonAddEdge (&polygon, &ocw, &occw);
|
||||||
_XrPolygonAddEdge (&polygon, &occw, &f->ccw);
|
_XrPolygonAddEdge (&polygon, &occw, &f->ccw);
|
||||||
_XrPolygonAddEdge (&polygon, &f->ccw, &f->cw);
|
_XrPolygonAddEdge (&polygon, &f->ccw, &f->cw);
|
||||||
break;
|
|
||||||
}
|
|
||||||
case XrLineCapButt:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = _XrTrapsTessellatePolygon (stroker->traps, &polygon, XrFillRuleWinding);
|
status = _XrTrapsTessellatePolygon (stroker->traps, &polygon, XrFillRuleWinding);
|
||||||
_XrPolygonDeinit (&polygon);
|
_XrPolygonDeinit (&polygon);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
}
|
||||||
|
case XrLineCapButt:
|
||||||
|
default:
|
||||||
|
return XrStatusSuccess;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -247,7 +305,7 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
||||||
{
|
{
|
||||||
double mag, tmp;
|
double mag, tmp;
|
||||||
double dx, dy;
|
double dx, dy;
|
||||||
XPointDouble user_vector;
|
XPointDouble usr_vector;
|
||||||
XPointFixed offset_ccw, offset_cw;
|
XPointFixed offset_ccw, offset_cw;
|
||||||
|
|
||||||
dx = XFixedToDouble(slope->dx);
|
dx = XFixedToDouble(slope->dx);
|
||||||
|
|
@ -264,8 +322,8 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
||||||
dx /= mag;
|
dx /= mag;
|
||||||
dy /= mag;
|
dy /= mag;
|
||||||
|
|
||||||
user_vector.x = dx;
|
usr_vector.x = dx;
|
||||||
user_vector.y = dy;
|
usr_vector.y = dy;
|
||||||
|
|
||||||
tmp = dx;
|
tmp = dx;
|
||||||
dx = - dy * (gstate->line_width / 2.0);
|
dx = - dy * (gstate->line_width / 2.0);
|
||||||
|
|
@ -286,8 +344,10 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
||||||
face->cw = *pt;
|
face->cw = *pt;
|
||||||
_TranslatePoint(&face->cw, &offset_cw);
|
_TranslatePoint(&face->cw, &offset_cw);
|
||||||
|
|
||||||
face->vector.x = user_vector.x;
|
face->usr_vector.x = usr_vector.x;
|
||||||
face->vector.y = user_vector.y;
|
face->usr_vector.y = usr_vector.y;
|
||||||
|
|
||||||
|
face->dev_vector = *slope;
|
||||||
}
|
}
|
||||||
|
|
||||||
static XrStatus
|
static XrStatus
|
||||||
|
|
@ -475,7 +535,7 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed
|
||||||
XrSpline spline;
|
XrSpline spline;
|
||||||
XrPen pen;
|
XrPen pen;
|
||||||
XrStrokeFace start, end;
|
XrStrokeFace start, end;
|
||||||
XrPenFlaggedPoint extra_points[4];
|
XPointFixed extra_points[4];
|
||||||
|
|
||||||
status = _XrSplineInit(&spline, a, b, c, d);
|
status = _XrSplineInit(&spline, a, b, c, d);
|
||||||
if (status == XrIntStatusDegenerate)
|
if (status == XrIntStatusDegenerate)
|
||||||
|
|
@ -502,18 +562,18 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed
|
||||||
stroker->prev = end;
|
stroker->prev = end;
|
||||||
stroker->is_first = 0;
|
stroker->is_first = 0;
|
||||||
|
|
||||||
extra_points[0].pt = start.cw; extra_points[0].flag = XrPenVertexFlagForward;
|
extra_points[0] = start.cw;
|
||||||
extra_points[0].pt.x -= start.pt.x;
|
extra_points[0].x -= start.pt.x;
|
||||||
extra_points[0].pt.y -= start.pt.y;
|
extra_points[0].y -= start.pt.y;
|
||||||
extra_points[1].pt = start.ccw; extra_points[1].flag = XrPenVertexFlagNone;
|
extra_points[1] = start.ccw;
|
||||||
extra_points[1].pt.x -= start.pt.x;
|
extra_points[1].x -= start.pt.x;
|
||||||
extra_points[1].pt.y -= start.pt.y;
|
extra_points[1].y -= start.pt.y;
|
||||||
extra_points[2].pt = end.cw; extra_points[2].flag = XrPenVertexFlagNone;
|
extra_points[2] = end.cw;
|
||||||
extra_points[2].pt.x -= end.pt.x;
|
extra_points[2].x -= end.pt.x;
|
||||||
extra_points[2].pt.y -= end.pt.y;
|
extra_points[2].y -= end.pt.y;
|
||||||
extra_points[3].pt = end.ccw; extra_points[3].flag = XrPenVertexFlagReverse;
|
extra_points[3] = end.ccw;
|
||||||
extra_points[3].pt.x -= end.pt.x;
|
extra_points[3].x -= end.pt.x;
|
||||||
extra_points[3].pt.y -= end.pt.y;
|
extra_points[3].y -= end.pt.y;
|
||||||
|
|
||||||
status = _XrPenAddPoints(&pen, extra_points, 4);
|
status = _XrPenAddPoints(&pen, extra_points, 4);
|
||||||
if (status)
|
if (status)
|
||||||
|
|
@ -548,6 +608,15 @@ _XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
|
||||||
/* fall through... */
|
/* fall through... */
|
||||||
case XrSubPathDoneCap:
|
case XrSubPathDoneCap:
|
||||||
if (stroker->have_first) {
|
if (stroker->have_first) {
|
||||||
|
XPointFixed t;
|
||||||
|
/* The initial cap needs an outward facing vector. Reverse everything */
|
||||||
|
stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
|
||||||
|
stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
|
||||||
|
stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
|
||||||
|
stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
|
||||||
|
t = stroker->first.cw;
|
||||||
|
stroker->first.cw = stroker->first.ccw;
|
||||||
|
stroker->first.ccw = t;
|
||||||
status = _XrStrokerCap (stroker, &stroker->first);
|
status = _XrStrokerCap (stroker, &stroker->first);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
|
||||||
62
xrtraps.c
62
xrtraps.c
|
|
@ -164,34 +164,66 @@ _ComparePointFixedByY (const void *av, const void *bv)
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
||||||
{
|
{
|
||||||
|
XrStatus status;
|
||||||
XLineFixed line;
|
XLineFixed line;
|
||||||
double intersect;
|
double intersect;
|
||||||
|
XPointFixed tsort[3];
|
||||||
|
|
||||||
qsort(t, 3, sizeof(XPointFixed), _ComparePointFixedByY);
|
memcpy(tsort, t, 3 * sizeof(XPointFixed));
|
||||||
|
qsort(tsort, 3, sizeof(XPointFixed), _ComparePointFixedByY);
|
||||||
|
|
||||||
/* horizontal top edge requires special handling */
|
/* horizontal top edge requires special handling */
|
||||||
if (t[0].y == t[1].y) {
|
if (tsort[0].y == tsort[1].y) {
|
||||||
if (t[0].x < t[1].x)
|
if (tsort[0].x < tsort[1].x)
|
||||||
_XrTrapsAddTrapFromPoints (traps, t[1].y, t[2].y, t[0], t[2], t[1], t[2]);
|
status = _XrTrapsAddTrapFromPoints (traps,
|
||||||
|
tsort[1].y, tsort[2].y,
|
||||||
|
tsort[0], tsort[2],
|
||||||
|
tsort[1], tsort[2]);
|
||||||
else
|
else
|
||||||
_XrTrapsAddTrapFromPoints (traps, t[1].y, t[2].y, t[1], t[2], t[0], t[2]);
|
status = _XrTrapsAddTrapFromPoints (traps,
|
||||||
return;
|
tsort[1].y, tsort[2].y,
|
||||||
|
tsort[1], tsort[2],
|
||||||
|
tsort[0], tsort[2]);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
line.p1 = t[0];
|
line.p1 = tsort[0];
|
||||||
line.p2 = t[1];
|
line.p2 = tsort[1];
|
||||||
|
|
||||||
intersect = _ComputeX (&line, t[2].y);
|
intersect = _ComputeX (&line, tsort[2].y);
|
||||||
|
|
||||||
if (intersect < t[2].x) {
|
if (intersect < tsort[2].x) {
|
||||||
_XrTrapsAddTrapFromPoints(traps, t[0].y, t[1].y, t[0], t[1], t[0], t[2]);
|
status = _XrTrapsAddTrapFromPoints(traps,
|
||||||
_XrTrapsAddTrapFromPoints(traps, t[1].y, t[2].y, t[1], t[2], t[0], t[2]);
|
tsort[0].y, tsort[1].y,
|
||||||
|
tsort[0], tsort[1],
|
||||||
|
tsort[0], tsort[2]);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
status = _XrTrapsAddTrapFromPoints(traps,
|
||||||
|
tsort[1].y, tsort[2].y,
|
||||||
|
tsort[1], tsort[2],
|
||||||
|
tsort[0], tsort[2]);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
} else {
|
} else {
|
||||||
_XrTrapsAddTrapFromPoints(traps, t[0].y, t[1].y, t[0], t[2], t[0], t[1]);
|
status = _XrTrapsAddTrapFromPoints(traps,
|
||||||
_XrTrapsAddTrapFromPoints(traps, t[1].y, t[2].y, t[0], t[2], t[1], t[2]);
|
tsort[0].y, tsort[1].y,
|
||||||
|
tsort[0], tsort[2],
|
||||||
|
tsort[0], tsort[1]);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
status = _XrTrapsAddTrapFromPoints(traps,
|
||||||
|
tsort[1].y, tsort[2].y,
|
||||||
|
tsort[0], tsort[2],
|
||||||
|
tsort[1], tsort[2]);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return XrStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Warning: This function reorderd the elements of the array provided. */
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
||||||
{
|
{
|
||||||
|
|
@ -432,6 +464,8 @@ _SortEdgeList(XrEdge **active)
|
||||||
active edges, forming a trapezoid between each adjacent pair. Then,
|
active edges, forming a trapezoid between each adjacent pair. Then,
|
||||||
either the even-odd or winding rule is used to determine whether to
|
either the even-odd or winding rule is used to determine whether to
|
||||||
emit each of these trapezoids.
|
emit each of these trapezoids.
|
||||||
|
|
||||||
|
Warning: This function reorders the edges of the polygon provided.
|
||||||
*/
|
*/
|
||||||
XrStatus
|
XrStatus
|
||||||
_XrTrapsTessellatePolygon (XrTraps *traps,
|
_XrTrapsTessellatePolygon (XrTraps *traps,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue