mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-21 09:50:10 +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>
|
||||
|
||||
* xrtraps.c (_XrTrapsTessellateTriangle): Restored triangle
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ _XrGStateInit(XrGState *gstate, Display *dpy)
|
|||
|
||||
gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT;
|
||||
|
||||
gstate->dashes = 0;
|
||||
gstate->ndashes = 0;
|
||||
gstate->dash = NULL;
|
||||
gstate->num_dashes = 0;
|
||||
gstate->dash_offset = 0.0;
|
||||
|
||||
gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8);
|
||||
|
|
@ -98,11 +98,11 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
|||
XrStatus status;
|
||||
|
||||
*gstate = *other;
|
||||
if (other->dashes) {
|
||||
gstate->dashes = malloc (other->ndashes * sizeof (double));
|
||||
if (gstate->dashes == NULL)
|
||||
if (other->dash) {
|
||||
gstate->dash = malloc (other->num_dashes * sizeof (double));
|
||||
if (gstate->dash == NULL)
|
||||
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);
|
||||
|
|
@ -130,8 +130,8 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
|||
CLEANUP_FONT:
|
||||
_XrFontDeinit(&gstate->font);
|
||||
CLEANUP_DASHES:
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = NULL;
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -158,9 +158,9 @@ _XrGStateDeinit(XrGState *gstate)
|
|||
|
||||
_XrPenDeinit(&gstate->pen_regular);
|
||||
|
||||
if (gstate->dashes) {
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = NULL;
|
||||
if (gstate->dash) {
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,19 +363,23 @@ _XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join)
|
|||
}
|
||||
|
||||
XrStatus
|
||||
_XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset)
|
||||
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset)
|
||||
{
|
||||
if (gstate->dashes) {
|
||||
free (gstate->dashes);
|
||||
if (gstate->dash) {
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
}
|
||||
|
||||
gstate->dashes = malloc (ndash * sizeof (double));
|
||||
if (!gstate->dashes) {
|
||||
gstate->ndashes = 0;
|
||||
gstate->num_dashes = num_dashes;
|
||||
if (gstate->num_dashes) {
|
||||
gstate->dash = malloc (gstate->num_dashes * sizeof (double));
|
||||
if (gstate->dash == NULL) {
|
||||
gstate->num_dashes = 0;
|
||||
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;
|
||||
|
||||
return XrStatusSuccess;
|
||||
|
|
@ -639,7 +643,7 @@ _XrGStateStroke(XrGState *gstate)
|
|||
_XrStrokerDoneSubPath,
|
||||
_XrStrokerDonePath
|
||||
};
|
||||
XrPathCallbacks *cbs = gstate->dashes ? &cb_dash : &cb;
|
||||
XrPathCallbacks *cbs = gstate->dash ? &cb_dash : &cb;
|
||||
|
||||
XrStroker stroker;
|
||||
XrTraps traps;
|
||||
|
|
|
|||
33
src/xrint.h
33
src/xrint.h
|
|
@ -137,20 +137,14 @@ typedef struct _XrSpline {
|
|||
XPointFixed *pts;
|
||||
} XrSpline;
|
||||
|
||||
typedef enum _XrPenVertexFlag {
|
||||
XrPenVertexFlagNone = 0,
|
||||
XrPenVertexFlagForward = 1,
|
||||
XrPenVertexFlagReverse = 2
|
||||
} XrPenVertexFlag;
|
||||
|
||||
typedef struct _XrPenFlaggedPoint {
|
||||
XPointFixed pt;
|
||||
XrPenVertexFlag flag;
|
||||
} XrPenFlaggedPoint;
|
||||
/* XXX: This can go away once incremental spline tessellation is working */
|
||||
typedef enum _XrPenStrokeDirection {
|
||||
XrPenStrokeDirectionForward,
|
||||
XrPenStrokeDirectionReverse
|
||||
} XrPenStrokeDirection;
|
||||
|
||||
typedef struct _XrPenVertex {
|
||||
XPointFixed pt;
|
||||
XrPenVertexFlag flag;
|
||||
|
||||
double theta;
|
||||
XrSlopeFixed slope_ccw;
|
||||
|
|
@ -244,8 +238,8 @@ typedef struct _XrGState {
|
|||
|
||||
XrFillRule fill_rule;
|
||||
|
||||
double *dashes;
|
||||
int ndashes;
|
||||
double *dash;
|
||||
int num_dashes;
|
||||
double dash_offset;
|
||||
|
||||
XcFormat *alphaFormat;
|
||||
|
|
@ -284,7 +278,8 @@ typedef struct _XrStrokeFace {
|
|||
XPointFixed ccw;
|
||||
XPointFixed pt;
|
||||
XPointFixed cw;
|
||||
XPointDouble vector;
|
||||
XrSlopeFixed dev_vector;
|
||||
XPointDouble usr_vector;
|
||||
} XrStrokeFace;
|
||||
|
||||
typedef struct _XrStroker {
|
||||
|
|
@ -387,7 +382,7 @@ XrStatus
|
|||
_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join);
|
||||
|
||||
XrStatus
|
||||
_XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset);
|
||||
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset);
|
||||
|
||||
XrStatus
|
||||
_XrGStateSetMiterLimit(XrGState *gstate, double limit);
|
||||
|
|
@ -640,11 +635,17 @@ void
|
|||
_XrPenDeinit(XrPen *pen);
|
||||
|
||||
XrStatus
|
||||
_XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts);
|
||||
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts);
|
||||
|
||||
XrStatus
|
||||
_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
|
||||
_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);
|
||||
|
||||
static XrStatus
|
||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline,
|
||||
XrPenVertexFlag dir, XrPolygon *polygon);
|
||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon);
|
||||
|
||||
XrStatus
|
||||
_XrPenInitEmpty(XrPen *pen)
|
||||
|
|
@ -93,7 +92,10 @@ _XrPenInit(XrPen *pen, double radius, XrGState *gstate)
|
|||
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
||||
v->pt.x = XDoubleToFixed(dx);
|
||||
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);
|
||||
|
|
@ -141,7 +143,7 @@ _XrPenVertexCompareByTheta(const void *a, const void *b)
|
|||
}
|
||||
|
||||
XrStatus
|
||||
_XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
||||
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts)
|
||||
{
|
||||
int i, j;
|
||||
XrPenVertex *v, *v_next, *new_vertex;
|
||||
|
|
@ -157,8 +159,7 @@ _XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
|||
/* initialize new vertices */
|
||||
for (i=0; i < num_pts; i++) {
|
||||
v = &pen->vertex[pen->num_vertices-(i+1)];
|
||||
v->pt = pt[i].pt;
|
||||
v->flag = pt[i].flag;
|
||||
v->pt = pt[i];
|
||||
v->theta = atan2(v->pt.y, v->pt.x);
|
||||
if (v->theta < 0)
|
||||
v->theta += 2 * M_PI;
|
||||
|
|
@ -171,7 +172,6 @@ _XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
|||
v = &pen->vertex[i];
|
||||
v_next = &pen->vertex[i+1];
|
||||
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++)
|
||||
pen->vertex[j] = pen->vertex[j+1];
|
||||
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
|
||||
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
||||
{
|
||||
|
|
@ -240,40 +246,90 @@ _SlopeCounterClockwise(XrSlopeFixed *a, XrSlopeFixed *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
|
||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline,
|
||||
XrPenVertexFlag dir, XrPolygon *polygon)
|
||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon)
|
||||
{
|
||||
int i;
|
||||
XrStatus status;
|
||||
int start, stop, step;
|
||||
int active = 0;
|
||||
XPointFixed hull_pt;
|
||||
XrSlopeFixed slope, final_slope;
|
||||
XrSlopeFixed slope, initial_slope, final_slope;
|
||||
XPointFixed *pt = spline->pts;
|
||||
int num_pts = spline->num_pts;
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
if (pen->vertex[i].flag & dir) {
|
||||
active = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == XrPenVertexFlagForward) {
|
||||
if (dir == XrPenStrokeDirectionForward) {
|
||||
start = 0;
|
||||
stop = num_pts;
|
||||
step = 1;
|
||||
initial_slope = spline->initial_slope;
|
||||
final_slope = spline->final_slope;
|
||||
} else {
|
||||
start = num_pts - 1;
|
||||
stop = -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.dx = -final_slope.dx;
|
||||
final_slope.dy = -final_slope.dy;
|
||||
}
|
||||
|
||||
_XrPenFindActiveCWVertexIndex(pen, &initial_slope, &active);
|
||||
|
||||
i = start;
|
||||
while (i != stop) {
|
||||
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
|
||||
|
|
@ -318,11 +374,11 @@ _XrPenStrokeSpline(XrPen *pen,
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenVertexFlagForward, &polygon);
|
||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionForward, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenVertexFlagReverse, &polygon);
|
||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionReverse, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
|
|
|
|||
199
src/xrstroker.c
199
src/xrstroker.c
|
|
@ -44,15 +44,15 @@ _XrStrokerStartDash (XrStroker *stroker)
|
|||
int i = 0;
|
||||
|
||||
offset = gstate->dash_offset;
|
||||
while (offset >= gstate->dashes[i]) {
|
||||
offset -= gstate->dashes[i];
|
||||
while (offset >= gstate->dash[i]) {
|
||||
offset -= gstate->dash[i];
|
||||
on = 1-on;
|
||||
if (++i == gstate->ndashes)
|
||||
if (++i == gstate->num_dashes)
|
||||
i = 0;
|
||||
}
|
||||
stroker->dash_index = i;
|
||||
stroker->dash_on = on;
|
||||
stroker->dash_remain = gstate->dashes[i] - offset;
|
||||
stroker->dash_remain = gstate->dash[i] - offset;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -62,10 +62,10 @@ _XrStrokerStepDash (XrStroker *stroker, double step)
|
|||
stroker->dash_remain -= step;
|
||||
if (stroker->dash_remain <= 0) {
|
||||
stroker->dash_index++;
|
||||
if (stroker->dash_index == gstate->ndashes)
|
||||
if (stroker->dash_index == gstate->num_dashes)
|
||||
stroker->dash_index = 0;
|
||||
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_first = 0;
|
||||
stroker->is_first = 1;
|
||||
if (gstate->dashes)
|
||||
if (gstate->dash)
|
||||
_XrStrokerStartDash (stroker);
|
||||
}
|
||||
|
||||
|
|
@ -112,12 +112,9 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
{
|
||||
XrStatus status;
|
||||
XrGState *gstate = stroker->gstate;
|
||||
int clockwise = _XrStrokerFaceClockwise (in, out);
|
||||
int clockwise = _XrStrokerFaceClockwise (out, in);
|
||||
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
|
||||
&& in->cw.y == out->cw.y
|
||||
&& in->ccw.x == out->ccw.x
|
||||
|
|
@ -126,20 +123,57 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
}
|
||||
|
||||
if (clockwise) {
|
||||
inpt = &in->cw;
|
||||
outpt = &out->cw;
|
||||
} else {
|
||||
inpt = &in->ccw;
|
||||
outpt = &out->ccw;
|
||||
} else {
|
||||
inpt = &in->cw;
|
||||
outpt = &out->cw;
|
||||
}
|
||||
|
||||
switch (gstate->line_join) {
|
||||
case XrLineJoinRound:
|
||||
status = XrStatusSuccess;
|
||||
break;
|
||||
case XrLineJoinMiter: {
|
||||
case XrLineJoinRound: {
|
||||
int i;
|
||||
int start, step, stop;
|
||||
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;
|
||||
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;
|
||||
|
||||
_XrPolygonInit (&polygon);
|
||||
|
|
@ -152,14 +186,14 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
|
||||
x1 = XFixedToDouble(inpt->x);
|
||||
y1 = XFixedToDouble(inpt->y);
|
||||
dx1 = in->vector.x;
|
||||
dy1 = in->vector.y;
|
||||
dx1 = in->usr_vector.x;
|
||||
dy1 = in->usr_vector.y;
|
||||
_XrTransformDistance(&gstate->ctm, &dx1, &dy1);
|
||||
|
||||
x2 = XFixedToDouble(outpt->x);
|
||||
y2 = XFixedToDouble(outpt->y);
|
||||
dx2 = out->vector.x;
|
||||
dy2 = out->vector.y;
|
||||
dx2 = out->usr_vector.x;
|
||||
dy2 = out->usr_vector.y;
|
||||
_XrTransformDistance(&gstate->ctm, &dx2, &dy2);
|
||||
|
||||
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
||||
|
|
@ -179,7 +213,8 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
&polygon,
|
||||
XrFillRuleWinding);
|
||||
_XrPolygonDeinit (&polygon);
|
||||
break;
|
||||
|
||||
return status;
|
||||
}
|
||||
/* fall through ... */
|
||||
}
|
||||
|
|
@ -188,12 +223,10 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
tri[0] = in->pt;
|
||||
tri[1] = *inpt;
|
||||
tri[2] = *outpt;
|
||||
status = _XrTrapsTessellateTriangle (stroker->traps, tri);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
return _XrTrapsTessellateTriangle (stroker->traps, tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static XrStatus
|
||||
|
|
@ -201,53 +234,78 @@ _XrStrokerCap(XrStroker *stroker, XrStrokeFace *f)
|
|||
{
|
||||
XrStatus status;
|
||||
XrGState *gstate = stroker->gstate;
|
||||
XrPolygon polygon;
|
||||
|
||||
if (gstate->line_cap == XrLineCapButt)
|
||||
return XrStatusSuccess;
|
||||
|
||||
_XrPolygonInit (&polygon);
|
||||
switch (gstate->line_cap) {
|
||||
case XrLineCapRound:
|
||||
break;
|
||||
case XrLineCapRound: {
|
||||
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: {
|
||||
double dx, dy;
|
||||
XPointFixed fvector;
|
||||
XrSlopeFixed fvector;
|
||||
XPointFixed occw, ocw;
|
||||
dx = f->vector.x;
|
||||
dy = f->vector.y;
|
||||
XrPolygon polygon;
|
||||
|
||||
_XrPolygonInit (&polygon);
|
||||
|
||||
dx = f->usr_vector.x;
|
||||
dy = f->usr_vector.y;
|
||||
dx *= gstate->line_width / 2.0;
|
||||
dy *= gstate->line_width / 2.0;
|
||||
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
||||
fvector.x = XDoubleToFixed(dx);
|
||||
fvector.y = XDoubleToFixed(dy);
|
||||
occw.x = f->ccw.x + fvector.x;
|
||||
occw.y = f->ccw.y + fvector.y;
|
||||
ocw.x = f->cw.x + fvector.x;
|
||||
ocw.y = f->cw.y + fvector.y;
|
||||
fvector.dx = XDoubleToFixed(dx);
|
||||
fvector.dy = XDoubleToFixed(dy);
|
||||
occw.x = f->ccw.x + fvector.dx;
|
||||
occw.y = f->ccw.y + fvector.dy;
|
||||
ocw.x = f->cw.x + fvector.dx;
|
||||
ocw.y = f->cw.y + fvector.dy;
|
||||
|
||||
_XrPolygonAddEdge (&polygon, &f->cw, &ocw);
|
||||
_XrPolygonAddEdge (&polygon, &ocw, &occw);
|
||||
_XrPolygonAddEdge (&polygon, &occw, &f->ccw);
|
||||
_XrPolygonAddEdge (&polygon, &f->ccw, &f->cw);
|
||||
break;
|
||||
}
|
||||
case XrLineCapButt:
|
||||
break;
|
||||
}
|
||||
|
||||
status = _XrTrapsTessellatePolygon (stroker->traps, &polygon, XrFillRuleWinding);
|
||||
_XrPolygonDeinit (&polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
case XrLineCapButt:
|
||||
default:
|
||||
return XrStatusSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFace *face)
|
||||
{
|
||||
double mag, tmp;
|
||||
double dx, dy;
|
||||
XPointDouble user_vector;
|
||||
XPointDouble usr_vector;
|
||||
XPointFixed offset_ccw, offset_cw;
|
||||
|
||||
dx = XFixedToDouble(slope->dx);
|
||||
|
|
@ -264,8 +322,8 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
|||
dx /= mag;
|
||||
dy /= mag;
|
||||
|
||||
user_vector.x = dx;
|
||||
user_vector.y = dy;
|
||||
usr_vector.x = dx;
|
||||
usr_vector.y = dy;
|
||||
|
||||
tmp = dx;
|
||||
dx = - dy * (gstate->line_width / 2.0);
|
||||
|
|
@ -286,8 +344,10 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
|||
face->cw = *pt;
|
||||
_TranslatePoint(&face->cw, &offset_cw);
|
||||
|
||||
face->vector.x = user_vector.x;
|
||||
face->vector.y = user_vector.y;
|
||||
face->usr_vector.x = usr_vector.x;
|
||||
face->usr_vector.y = usr_vector.y;
|
||||
|
||||
face->dev_vector = *slope;
|
||||
}
|
||||
|
||||
static XrStatus
|
||||
|
|
@ -475,7 +535,7 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed
|
|||
XrSpline spline;
|
||||
XrPen pen;
|
||||
XrStrokeFace start, end;
|
||||
XrPenFlaggedPoint extra_points[4];
|
||||
XPointFixed extra_points[4];
|
||||
|
||||
status = _XrSplineInit(&spline, a, b, c, d);
|
||||
if (status == XrIntStatusDegenerate)
|
||||
|
|
@ -502,18 +562,18 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed
|
|||
stroker->prev = end;
|
||||
stroker->is_first = 0;
|
||||
|
||||
extra_points[0].pt = start.cw; extra_points[0].flag = XrPenVertexFlagForward;
|
||||
extra_points[0].pt.x -= start.pt.x;
|
||||
extra_points[0].pt.y -= start.pt.y;
|
||||
extra_points[1].pt = start.ccw; extra_points[1].flag = XrPenVertexFlagNone;
|
||||
extra_points[1].pt.x -= start.pt.x;
|
||||
extra_points[1].pt.y -= start.pt.y;
|
||||
extra_points[2].pt = end.cw; extra_points[2].flag = XrPenVertexFlagNone;
|
||||
extra_points[2].pt.x -= end.pt.x;
|
||||
extra_points[2].pt.y -= end.pt.y;
|
||||
extra_points[3].pt = end.ccw; extra_points[3].flag = XrPenVertexFlagReverse;
|
||||
extra_points[3].pt.x -= end.pt.x;
|
||||
extra_points[3].pt.y -= end.pt.y;
|
||||
extra_points[0] = start.cw;
|
||||
extra_points[0].x -= start.pt.x;
|
||||
extra_points[0].y -= start.pt.y;
|
||||
extra_points[1] = start.ccw;
|
||||
extra_points[1].x -= start.pt.x;
|
||||
extra_points[1].y -= start.pt.y;
|
||||
extra_points[2] = end.cw;
|
||||
extra_points[2].x -= end.pt.x;
|
||||
extra_points[2].y -= end.pt.y;
|
||||
extra_points[3] = end.ccw;
|
||||
extra_points[3].x -= end.pt.x;
|
||||
extra_points[3].y -= end.pt.y;
|
||||
|
||||
status = _XrPenAddPoints(&pen, extra_points, 4);
|
||||
if (status)
|
||||
|
|
@ -548,6 +608,15 @@ _XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
|
|||
/* fall through... */
|
||||
case XrSubPathDoneCap:
|
||||
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);
|
||||
if (status)
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -164,34 +164,66 @@ _ComparePointFixedByY (const void *av, const void *bv)
|
|||
XrStatus
|
||||
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
||||
{
|
||||
XrStatus status;
|
||||
XLineFixed line;
|
||||
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 */
|
||||
if (t[0].y == t[1].y) {
|
||||
if (t[0].x < t[1].x)
|
||||
_XrTrapsAddTrapFromPoints (traps, t[1].y, t[2].y, t[0], t[2], t[1], t[2]);
|
||||
if (tsort[0].y == tsort[1].y) {
|
||||
if (tsort[0].x < tsort[1].x)
|
||||
status = _XrTrapsAddTrapFromPoints (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[1], tsort[2]);
|
||||
else
|
||||
_XrTrapsAddTrapFromPoints (traps, t[1].y, t[2].y, t[1], t[2], t[0], t[2]);
|
||||
return;
|
||||
status = _XrTrapsAddTrapFromPoints (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[1], tsort[2],
|
||||
tsort[0], tsort[2]);
|
||||
return status;
|
||||
}
|
||||
|
||||
line.p1 = t[0];
|
||||
line.p2 = t[1];
|
||||
line.p1 = tsort[0];
|
||||
line.p2 = tsort[1];
|
||||
|
||||
intersect = _ComputeX (&line, t[2].y);
|
||||
intersect = _ComputeX (&line, tsort[2].y);
|
||||
|
||||
if (intersect < t[2].x) {
|
||||
_XrTrapsAddTrapFromPoints(traps, t[0].y, t[1].y, t[0], t[1], t[0], t[2]);
|
||||
_XrTrapsAddTrapFromPoints(traps, t[1].y, t[2].y, t[1], t[2], t[0], t[2]);
|
||||
if (intersect < tsort[2].x) {
|
||||
status = _XrTrapsAddTrapFromPoints(traps,
|
||||
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 {
|
||||
_XrTrapsAddTrapFromPoints(traps, t[0].y, t[1].y, t[0], t[2], t[0], t[1]);
|
||||
_XrTrapsAddTrapFromPoints(traps, t[1].y, t[2].y, t[0], t[2], t[1], t[2]);
|
||||
}
|
||||
status = _XrTrapsAddTrapFromPoints(traps,
|
||||
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
|
||||
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
||||
{
|
||||
|
|
@ -432,6 +464,8 @@ _SortEdgeList(XrEdge **active)
|
|||
active edges, forming a trapezoid between each adjacent pair. Then,
|
||||
either the even-odd or winding rule is used to determine whether to
|
||||
emit each of these trapezoids.
|
||||
|
||||
Warning: This function reorders the edges of the polygon provided.
|
||||
*/
|
||||
XrStatus
|
||||
_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->dashes = 0;
|
||||
gstate->ndashes = 0;
|
||||
gstate->dash = NULL;
|
||||
gstate->num_dashes = 0;
|
||||
gstate->dash_offset = 0.0;
|
||||
|
||||
gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8);
|
||||
|
|
@ -98,11 +98,11 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
|||
XrStatus status;
|
||||
|
||||
*gstate = *other;
|
||||
if (other->dashes) {
|
||||
gstate->dashes = malloc (other->ndashes * sizeof (double));
|
||||
if (gstate->dashes == NULL)
|
||||
if (other->dash) {
|
||||
gstate->dash = malloc (other->num_dashes * sizeof (double));
|
||||
if (gstate->dash == NULL)
|
||||
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);
|
||||
|
|
@ -130,8 +130,8 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
|||
CLEANUP_FONT:
|
||||
_XrFontDeinit(&gstate->font);
|
||||
CLEANUP_DASHES:
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = NULL;
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -158,9 +158,9 @@ _XrGStateDeinit(XrGState *gstate)
|
|||
|
||||
_XrPenDeinit(&gstate->pen_regular);
|
||||
|
||||
if (gstate->dashes) {
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = NULL;
|
||||
if (gstate->dash) {
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,19 +363,23 @@ _XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join)
|
|||
}
|
||||
|
||||
XrStatus
|
||||
_XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset)
|
||||
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset)
|
||||
{
|
||||
if (gstate->dashes) {
|
||||
free (gstate->dashes);
|
||||
if (gstate->dash) {
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
}
|
||||
|
||||
gstate->dashes = malloc (ndash * sizeof (double));
|
||||
if (!gstate->dashes) {
|
||||
gstate->ndashes = 0;
|
||||
gstate->num_dashes = num_dashes;
|
||||
if (gstate->num_dashes) {
|
||||
gstate->dash = malloc (gstate->num_dashes * sizeof (double));
|
||||
if (gstate->dash == NULL) {
|
||||
gstate->num_dashes = 0;
|
||||
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;
|
||||
|
||||
return XrStatusSuccess;
|
||||
|
|
@ -639,7 +643,7 @@ _XrGStateStroke(XrGState *gstate)
|
|||
_XrStrokerDoneSubPath,
|
||||
_XrStrokerDonePath
|
||||
};
|
||||
XrPathCallbacks *cbs = gstate->dashes ? &cb_dash : &cb;
|
||||
XrPathCallbacks *cbs = gstate->dash ? &cb_dash : &cb;
|
||||
|
||||
XrStroker stroker;
|
||||
XrTraps traps;
|
||||
|
|
|
|||
33
xrint.h
33
xrint.h
|
|
@ -137,20 +137,14 @@ typedef struct _XrSpline {
|
|||
XPointFixed *pts;
|
||||
} XrSpline;
|
||||
|
||||
typedef enum _XrPenVertexFlag {
|
||||
XrPenVertexFlagNone = 0,
|
||||
XrPenVertexFlagForward = 1,
|
||||
XrPenVertexFlagReverse = 2
|
||||
} XrPenVertexFlag;
|
||||
|
||||
typedef struct _XrPenFlaggedPoint {
|
||||
XPointFixed pt;
|
||||
XrPenVertexFlag flag;
|
||||
} XrPenFlaggedPoint;
|
||||
/* XXX: This can go away once incremental spline tessellation is working */
|
||||
typedef enum _XrPenStrokeDirection {
|
||||
XrPenStrokeDirectionForward,
|
||||
XrPenStrokeDirectionReverse
|
||||
} XrPenStrokeDirection;
|
||||
|
||||
typedef struct _XrPenVertex {
|
||||
XPointFixed pt;
|
||||
XrPenVertexFlag flag;
|
||||
|
||||
double theta;
|
||||
XrSlopeFixed slope_ccw;
|
||||
|
|
@ -244,8 +238,8 @@ typedef struct _XrGState {
|
|||
|
||||
XrFillRule fill_rule;
|
||||
|
||||
double *dashes;
|
||||
int ndashes;
|
||||
double *dash;
|
||||
int num_dashes;
|
||||
double dash_offset;
|
||||
|
||||
XcFormat *alphaFormat;
|
||||
|
|
@ -284,7 +278,8 @@ typedef struct _XrStrokeFace {
|
|||
XPointFixed ccw;
|
||||
XPointFixed pt;
|
||||
XPointFixed cw;
|
||||
XPointDouble vector;
|
||||
XrSlopeFixed dev_vector;
|
||||
XPointDouble usr_vector;
|
||||
} XrStrokeFace;
|
||||
|
||||
typedef struct _XrStroker {
|
||||
|
|
@ -387,7 +382,7 @@ XrStatus
|
|||
_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join);
|
||||
|
||||
XrStatus
|
||||
_XrGStateSetDash(XrGState *gstate, double *dashes, int ndash, double offset);
|
||||
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset);
|
||||
|
||||
XrStatus
|
||||
_XrGStateSetMiterLimit(XrGState *gstate, double limit);
|
||||
|
|
@ -640,11 +635,17 @@ void
|
|||
_XrPenDeinit(XrPen *pen);
|
||||
|
||||
XrStatus
|
||||
_XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts);
|
||||
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts);
|
||||
|
||||
XrStatus
|
||||
_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
|
||||
_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);
|
||||
|
||||
static XrStatus
|
||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline,
|
||||
XrPenVertexFlag dir, XrPolygon *polygon);
|
||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon);
|
||||
|
||||
XrStatus
|
||||
_XrPenInitEmpty(XrPen *pen)
|
||||
|
|
@ -93,7 +92,10 @@ _XrPenInit(XrPen *pen, double radius, XrGState *gstate)
|
|||
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
||||
v->pt.x = XDoubleToFixed(dx);
|
||||
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);
|
||||
|
|
@ -141,7 +143,7 @@ _XrPenVertexCompareByTheta(const void *a, const void *b)
|
|||
}
|
||||
|
||||
XrStatus
|
||||
_XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
||||
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts)
|
||||
{
|
||||
int i, j;
|
||||
XrPenVertex *v, *v_next, *new_vertex;
|
||||
|
|
@ -157,8 +159,7 @@ _XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
|||
/* initialize new vertices */
|
||||
for (i=0; i < num_pts; i++) {
|
||||
v = &pen->vertex[pen->num_vertices-(i+1)];
|
||||
v->pt = pt[i].pt;
|
||||
v->flag = pt[i].flag;
|
||||
v->pt = pt[i];
|
||||
v->theta = atan2(v->pt.y, v->pt.x);
|
||||
if (v->theta < 0)
|
||||
v->theta += 2 * M_PI;
|
||||
|
|
@ -171,7 +172,6 @@ _XrPenAddPoints(XrPen *pen, XrPenFlaggedPoint *pt, int num_pts)
|
|||
v = &pen->vertex[i];
|
||||
v_next = &pen->vertex[i+1];
|
||||
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++)
|
||||
pen->vertex[j] = pen->vertex[j+1];
|
||||
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
|
||||
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
||||
{
|
||||
|
|
@ -240,40 +246,90 @@ _SlopeCounterClockwise(XrSlopeFixed *a, XrSlopeFixed *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
|
||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline,
|
||||
XrPenVertexFlag dir, XrPolygon *polygon)
|
||||
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon)
|
||||
{
|
||||
int i;
|
||||
XrStatus status;
|
||||
int start, stop, step;
|
||||
int active = 0;
|
||||
XPointFixed hull_pt;
|
||||
XrSlopeFixed slope, final_slope;
|
||||
XrSlopeFixed slope, initial_slope, final_slope;
|
||||
XPointFixed *pt = spline->pts;
|
||||
int num_pts = spline->num_pts;
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
if (pen->vertex[i].flag & dir) {
|
||||
active = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == XrPenVertexFlagForward) {
|
||||
if (dir == XrPenStrokeDirectionForward) {
|
||||
start = 0;
|
||||
stop = num_pts;
|
||||
step = 1;
|
||||
initial_slope = spline->initial_slope;
|
||||
final_slope = spline->final_slope;
|
||||
} else {
|
||||
start = num_pts - 1;
|
||||
stop = -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.dx = -final_slope.dx;
|
||||
final_slope.dy = -final_slope.dy;
|
||||
}
|
||||
|
||||
_XrPenFindActiveCWVertexIndex(pen, &initial_slope, &active);
|
||||
|
||||
i = start;
|
||||
while (i != stop) {
|
||||
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
|
||||
|
|
@ -318,11 +374,11 @@ _XrPenStrokeSpline(XrPen *pen,
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenVertexFlagForward, &polygon);
|
||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionForward, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenVertexFlagReverse, &polygon);
|
||||
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionReverse, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
|
|
|
|||
199
xrstroker.c
199
xrstroker.c
|
|
@ -44,15 +44,15 @@ _XrStrokerStartDash (XrStroker *stroker)
|
|||
int i = 0;
|
||||
|
||||
offset = gstate->dash_offset;
|
||||
while (offset >= gstate->dashes[i]) {
|
||||
offset -= gstate->dashes[i];
|
||||
while (offset >= gstate->dash[i]) {
|
||||
offset -= gstate->dash[i];
|
||||
on = 1-on;
|
||||
if (++i == gstate->ndashes)
|
||||
if (++i == gstate->num_dashes)
|
||||
i = 0;
|
||||
}
|
||||
stroker->dash_index = i;
|
||||
stroker->dash_on = on;
|
||||
stroker->dash_remain = gstate->dashes[i] - offset;
|
||||
stroker->dash_remain = gstate->dash[i] - offset;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -62,10 +62,10 @@ _XrStrokerStepDash (XrStroker *stroker, double step)
|
|||
stroker->dash_remain -= step;
|
||||
if (stroker->dash_remain <= 0) {
|
||||
stroker->dash_index++;
|
||||
if (stroker->dash_index == gstate->ndashes)
|
||||
if (stroker->dash_index == gstate->num_dashes)
|
||||
stroker->dash_index = 0;
|
||||
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_first = 0;
|
||||
stroker->is_first = 1;
|
||||
if (gstate->dashes)
|
||||
if (gstate->dash)
|
||||
_XrStrokerStartDash (stroker);
|
||||
}
|
||||
|
||||
|
|
@ -112,12 +112,9 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
{
|
||||
XrStatus status;
|
||||
XrGState *gstate = stroker->gstate;
|
||||
int clockwise = _XrStrokerFaceClockwise (in, out);
|
||||
int clockwise = _XrStrokerFaceClockwise (out, in);
|
||||
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
|
||||
&& in->cw.y == out->cw.y
|
||||
&& in->ccw.x == out->ccw.x
|
||||
|
|
@ -126,20 +123,57 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
}
|
||||
|
||||
if (clockwise) {
|
||||
inpt = &in->cw;
|
||||
outpt = &out->cw;
|
||||
} else {
|
||||
inpt = &in->ccw;
|
||||
outpt = &out->ccw;
|
||||
} else {
|
||||
inpt = &in->cw;
|
||||
outpt = &out->cw;
|
||||
}
|
||||
|
||||
switch (gstate->line_join) {
|
||||
case XrLineJoinRound:
|
||||
status = XrStatusSuccess;
|
||||
break;
|
||||
case XrLineJoinMiter: {
|
||||
case XrLineJoinRound: {
|
||||
int i;
|
||||
int start, step, stop;
|
||||
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;
|
||||
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;
|
||||
|
||||
_XrPolygonInit (&polygon);
|
||||
|
|
@ -152,14 +186,14 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
|
||||
x1 = XFixedToDouble(inpt->x);
|
||||
y1 = XFixedToDouble(inpt->y);
|
||||
dx1 = in->vector.x;
|
||||
dy1 = in->vector.y;
|
||||
dx1 = in->usr_vector.x;
|
||||
dy1 = in->usr_vector.y;
|
||||
_XrTransformDistance(&gstate->ctm, &dx1, &dy1);
|
||||
|
||||
x2 = XFixedToDouble(outpt->x);
|
||||
y2 = XFixedToDouble(outpt->y);
|
||||
dx2 = out->vector.x;
|
||||
dy2 = out->vector.y;
|
||||
dx2 = out->usr_vector.x;
|
||||
dy2 = out->usr_vector.y;
|
||||
_XrTransformDistance(&gstate->ctm, &dx2, &dy2);
|
||||
|
||||
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
||||
|
|
@ -179,7 +213,8 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
&polygon,
|
||||
XrFillRuleWinding);
|
||||
_XrPolygonDeinit (&polygon);
|
||||
break;
|
||||
|
||||
return status;
|
||||
}
|
||||
/* fall through ... */
|
||||
}
|
||||
|
|
@ -188,12 +223,10 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
tri[0] = in->pt;
|
||||
tri[1] = *inpt;
|
||||
tri[2] = *outpt;
|
||||
status = _XrTrapsTessellateTriangle (stroker->traps, tri);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
return _XrTrapsTessellateTriangle (stroker->traps, tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static XrStatus
|
||||
|
|
@ -201,53 +234,78 @@ _XrStrokerCap(XrStroker *stroker, XrStrokeFace *f)
|
|||
{
|
||||
XrStatus status;
|
||||
XrGState *gstate = stroker->gstate;
|
||||
XrPolygon polygon;
|
||||
|
||||
if (gstate->line_cap == XrLineCapButt)
|
||||
return XrStatusSuccess;
|
||||
|
||||
_XrPolygonInit (&polygon);
|
||||
switch (gstate->line_cap) {
|
||||
case XrLineCapRound:
|
||||
break;
|
||||
case XrLineCapRound: {
|
||||
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: {
|
||||
double dx, dy;
|
||||
XPointFixed fvector;
|
||||
XrSlopeFixed fvector;
|
||||
XPointFixed occw, ocw;
|
||||
dx = f->vector.x;
|
||||
dy = f->vector.y;
|
||||
XrPolygon polygon;
|
||||
|
||||
_XrPolygonInit (&polygon);
|
||||
|
||||
dx = f->usr_vector.x;
|
||||
dy = f->usr_vector.y;
|
||||
dx *= gstate->line_width / 2.0;
|
||||
dy *= gstate->line_width / 2.0;
|
||||
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
||||
fvector.x = XDoubleToFixed(dx);
|
||||
fvector.y = XDoubleToFixed(dy);
|
||||
occw.x = f->ccw.x + fvector.x;
|
||||
occw.y = f->ccw.y + fvector.y;
|
||||
ocw.x = f->cw.x + fvector.x;
|
||||
ocw.y = f->cw.y + fvector.y;
|
||||
fvector.dx = XDoubleToFixed(dx);
|
||||
fvector.dy = XDoubleToFixed(dy);
|
||||
occw.x = f->ccw.x + fvector.dx;
|
||||
occw.y = f->ccw.y + fvector.dy;
|
||||
ocw.x = f->cw.x + fvector.dx;
|
||||
ocw.y = f->cw.y + fvector.dy;
|
||||
|
||||
_XrPolygonAddEdge (&polygon, &f->cw, &ocw);
|
||||
_XrPolygonAddEdge (&polygon, &ocw, &occw);
|
||||
_XrPolygonAddEdge (&polygon, &occw, &f->ccw);
|
||||
_XrPolygonAddEdge (&polygon, &f->ccw, &f->cw);
|
||||
break;
|
||||
}
|
||||
case XrLineCapButt:
|
||||
break;
|
||||
}
|
||||
|
||||
status = _XrTrapsTessellatePolygon (stroker->traps, &polygon, XrFillRuleWinding);
|
||||
_XrPolygonDeinit (&polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
case XrLineCapButt:
|
||||
default:
|
||||
return XrStatusSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFace *face)
|
||||
{
|
||||
double mag, tmp;
|
||||
double dx, dy;
|
||||
XPointDouble user_vector;
|
||||
XPointDouble usr_vector;
|
||||
XPointFixed offset_ccw, offset_cw;
|
||||
|
||||
dx = XFixedToDouble(slope->dx);
|
||||
|
|
@ -264,8 +322,8 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
|||
dx /= mag;
|
||||
dy /= mag;
|
||||
|
||||
user_vector.x = dx;
|
||||
user_vector.y = dy;
|
||||
usr_vector.x = dx;
|
||||
usr_vector.y = dy;
|
||||
|
||||
tmp = dx;
|
||||
dx = - dy * (gstate->line_width / 2.0);
|
||||
|
|
@ -286,8 +344,10 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac
|
|||
face->cw = *pt;
|
||||
_TranslatePoint(&face->cw, &offset_cw);
|
||||
|
||||
face->vector.x = user_vector.x;
|
||||
face->vector.y = user_vector.y;
|
||||
face->usr_vector.x = usr_vector.x;
|
||||
face->usr_vector.y = usr_vector.y;
|
||||
|
||||
face->dev_vector = *slope;
|
||||
}
|
||||
|
||||
static XrStatus
|
||||
|
|
@ -475,7 +535,7 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed
|
|||
XrSpline spline;
|
||||
XrPen pen;
|
||||
XrStrokeFace start, end;
|
||||
XrPenFlaggedPoint extra_points[4];
|
||||
XPointFixed extra_points[4];
|
||||
|
||||
status = _XrSplineInit(&spline, a, b, c, d);
|
||||
if (status == XrIntStatusDegenerate)
|
||||
|
|
@ -502,18 +562,18 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed
|
|||
stroker->prev = end;
|
||||
stroker->is_first = 0;
|
||||
|
||||
extra_points[0].pt = start.cw; extra_points[0].flag = XrPenVertexFlagForward;
|
||||
extra_points[0].pt.x -= start.pt.x;
|
||||
extra_points[0].pt.y -= start.pt.y;
|
||||
extra_points[1].pt = start.ccw; extra_points[1].flag = XrPenVertexFlagNone;
|
||||
extra_points[1].pt.x -= start.pt.x;
|
||||
extra_points[1].pt.y -= start.pt.y;
|
||||
extra_points[2].pt = end.cw; extra_points[2].flag = XrPenVertexFlagNone;
|
||||
extra_points[2].pt.x -= end.pt.x;
|
||||
extra_points[2].pt.y -= end.pt.y;
|
||||
extra_points[3].pt = end.ccw; extra_points[3].flag = XrPenVertexFlagReverse;
|
||||
extra_points[3].pt.x -= end.pt.x;
|
||||
extra_points[3].pt.y -= end.pt.y;
|
||||
extra_points[0] = start.cw;
|
||||
extra_points[0].x -= start.pt.x;
|
||||
extra_points[0].y -= start.pt.y;
|
||||
extra_points[1] = start.ccw;
|
||||
extra_points[1].x -= start.pt.x;
|
||||
extra_points[1].y -= start.pt.y;
|
||||
extra_points[2] = end.cw;
|
||||
extra_points[2].x -= end.pt.x;
|
||||
extra_points[2].y -= end.pt.y;
|
||||
extra_points[3] = end.ccw;
|
||||
extra_points[3].x -= end.pt.x;
|
||||
extra_points[3].y -= end.pt.y;
|
||||
|
||||
status = _XrPenAddPoints(&pen, extra_points, 4);
|
||||
if (status)
|
||||
|
|
@ -548,6 +608,15 @@ _XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
|
|||
/* fall through... */
|
||||
case XrSubPathDoneCap:
|
||||
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);
|
||||
if (status)
|
||||
return status;
|
||||
|
|
|
|||
64
xrtraps.c
64
xrtraps.c
|
|
@ -164,34 +164,66 @@ _ComparePointFixedByY (const void *av, const void *bv)
|
|||
XrStatus
|
||||
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
||||
{
|
||||
XrStatus status;
|
||||
XLineFixed line;
|
||||
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 */
|
||||
if (t[0].y == t[1].y) {
|
||||
if (t[0].x < t[1].x)
|
||||
_XrTrapsAddTrapFromPoints (traps, t[1].y, t[2].y, t[0], t[2], t[1], t[2]);
|
||||
if (tsort[0].y == tsort[1].y) {
|
||||
if (tsort[0].x < tsort[1].x)
|
||||
status = _XrTrapsAddTrapFromPoints (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[1], tsort[2]);
|
||||
else
|
||||
_XrTrapsAddTrapFromPoints (traps, t[1].y, t[2].y, t[1], t[2], t[0], t[2]);
|
||||
return;
|
||||
status = _XrTrapsAddTrapFromPoints (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[1], tsort[2],
|
||||
tsort[0], tsort[2]);
|
||||
return status;
|
||||
}
|
||||
|
||||
line.p1 = t[0];
|
||||
line.p2 = t[1];
|
||||
line.p1 = tsort[0];
|
||||
line.p2 = tsort[1];
|
||||
|
||||
intersect = _ComputeX (&line, t[2].y);
|
||||
intersect = _ComputeX (&line, tsort[2].y);
|
||||
|
||||
if (intersect < t[2].x) {
|
||||
_XrTrapsAddTrapFromPoints(traps, t[0].y, t[1].y, t[0], t[1], t[0], t[2]);
|
||||
_XrTrapsAddTrapFromPoints(traps, t[1].y, t[2].y, t[1], t[2], t[0], t[2]);
|
||||
if (intersect < tsort[2].x) {
|
||||
status = _XrTrapsAddTrapFromPoints(traps,
|
||||
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 {
|
||||
_XrTrapsAddTrapFromPoints(traps, t[0].y, t[1].y, t[0], t[2], t[0], t[1]);
|
||||
_XrTrapsAddTrapFromPoints(traps, t[1].y, t[2].y, t[0], t[2], t[1], t[2]);
|
||||
}
|
||||
status = _XrTrapsAddTrapFromPoints(traps,
|
||||
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
|
||||
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
||||
{
|
||||
|
|
@ -432,6 +464,8 @@ _SortEdgeList(XrEdge **active)
|
|||
active edges, forming a trapezoid between each adjacent pair. Then,
|
||||
either the even-odd or winding rule is used to determine whether to
|
||||
emit each of these trapezoids.
|
||||
|
||||
Warning: This function reorders the edges of the polygon provided.
|
||||
*/
|
||||
XrStatus
|
||||
_XrTrapsTessellatePolygon (XrTraps *traps,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue