mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 07:38:22 +02:00
Note that the only rectangles could be quickly converted to traps. Add miter joins
This commit is contained in:
parent
e55de618e7
commit
ba3bce9d7e
6 changed files with 126 additions and 74 deletions
|
|
@ -190,6 +190,7 @@ typedef struct _XrStrokeFace {
|
|||
XPointFixed ccw;
|
||||
XPointFixed pt;
|
||||
XPointFixed cw;
|
||||
XPointDouble vector;
|
||||
} XrStrokeFace;
|
||||
|
||||
typedef struct _XrStroker {
|
||||
|
|
@ -432,10 +433,7 @@ void
|
|||
XrTrapsDestroy(XrTraps *traps);
|
||||
|
||||
void
|
||||
XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3]);
|
||||
|
||||
void
|
||||
XrTrapsTessellateConvexQuad (XrTraps *traps, XPointFixed q[4]);
|
||||
XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4]);
|
||||
|
||||
void
|
||||
XrTrapsTessellatePolygon (XrTraps *traps, XrPolygon *poly, int winding);
|
||||
|
|
|
|||
|
|
@ -68,32 +68,69 @@ XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
{
|
||||
XrGState *gstate = stroker->gstate;
|
||||
int clockwise = XrStrokerFaceClockwise (in, out);
|
||||
XrPolygon polygon;
|
||||
XPointFixed *inpt, *outpt;
|
||||
|
||||
if (clockwise)
|
||||
{
|
||||
inpt = &in->cw;
|
||||
outpt = &out->cw;
|
||||
}
|
||||
else
|
||||
{
|
||||
inpt = &in->ccw;
|
||||
outpt = &out->ccw;
|
||||
}
|
||||
XrPolygonInit (&polygon);
|
||||
switch (gstate->stroke_style.line_join) {
|
||||
case XrLineJoinRound: {
|
||||
}
|
||||
case XrLineJoinMiter: {
|
||||
XDouble c = in->vector.x * out->vector.x + in->vector.y * out->vector.y;
|
||||
double ml = gstate->stroke_style.miter_limit;
|
||||
if (2 <= ml * ml * (1 + c))
|
||||
{
|
||||
XDouble x1, y1, x2, y2;
|
||||
XDouble mx, my;
|
||||
XDouble dx1, dx2, dy1, dy2;
|
||||
XPointFixed outer;
|
||||
|
||||
x1 = XFixedToDouble(inpt->x);
|
||||
y1 = XFixedToDouble(inpt->y);
|
||||
dx1 = XFixedToDouble(inpt->y - in->pt.y);
|
||||
dy1 = -XFixedToDouble(inpt->x - in->pt.x);
|
||||
|
||||
x2 = XFixedToDouble(outpt->x);
|
||||
y2 = XFixedToDouble(outpt->y);
|
||||
dx2 = -XFixedToDouble(outpt->y - out->pt.y);
|
||||
dy2 = XFixedToDouble(outpt->x - out->pt.x);
|
||||
|
||||
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
||||
(dx1 * dy2 - dx2 * dy1));
|
||||
if (dy1)
|
||||
mx = (my - y1) * dx1 / dy1 + x1;
|
||||
else
|
||||
mx = (my - y2) * dx2 / dy2 + x2;
|
||||
|
||||
outer.x = XDoubleToFixed(mx);
|
||||
outer.y = XDoubleToFixed(my);
|
||||
XrPolygonAddEdge (&polygon, &in->pt, inpt);
|
||||
XrPolygonAddEdge (&polygon, inpt, &outer);
|
||||
XrPolygonAddEdge (&polygon, &outer, outpt);
|
||||
XrPolygonAddEdge (&polygon, outpt, &in->pt);
|
||||
break;
|
||||
}
|
||||
/* fall through ... */
|
||||
}
|
||||
case XrLineJoinBevel: {
|
||||
XPointFixed t[3];
|
||||
|
||||
t[0].x = in->pt.x;
|
||||
t[0].y = in->pt.y;
|
||||
if (clockwise) {
|
||||
t[1].x = in->cw.x;
|
||||
t[1].y = in->cw.y;
|
||||
t[2].x = out->cw.x;
|
||||
t[2].y = out->cw.y;
|
||||
} else {
|
||||
t[1].x = in->ccw.x;
|
||||
t[1].y = in->ccw.y;
|
||||
t[2].x = out->ccw.x;
|
||||
t[2].y = out->ccw.y;
|
||||
}
|
||||
XrTrapsTessellateTriangle (stroker->traps, t);
|
||||
XrPolygonAddEdge (&polygon, &in->pt, inpt);
|
||||
XrPolygonAddEdge (&polygon, inpt, outpt);
|
||||
XrPolygonAddEdge (&polygon, outpt, &in->pt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
XrTrapsTessellatePolygon (stroker->traps, &polygon, 1);
|
||||
XrPolygonDeinit (&polygon);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -110,6 +147,7 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
XrTraps *traps = stroker->traps;
|
||||
double mag, tmp;
|
||||
XPointDouble vector;
|
||||
XPointDouble user_vector;
|
||||
XPointFixed offset_ccw, offset_cw;
|
||||
XPointFixed quad[4];
|
||||
XrStrokeFace face;
|
||||
|
|
@ -117,6 +155,8 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
vector.x = XFixedToDouble(p2->x - p1->x);
|
||||
vector.y = XFixedToDouble(p2->y - p1->y);
|
||||
|
||||
XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &vector);
|
||||
|
||||
mag = sqrt(vector.x * vector.x + vector.y * vector.y);
|
||||
if (mag == 0) {
|
||||
return;
|
||||
|
|
@ -125,7 +165,7 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
vector.x /= mag;
|
||||
vector.y /= mag;
|
||||
|
||||
XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &vector);
|
||||
user_vector = vector;
|
||||
|
||||
tmp = vector.x;
|
||||
vector.x = vector.y * (style->line_width / 2.0);
|
||||
|
|
@ -153,6 +193,7 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
face.cw = quad[0];
|
||||
face.pt = *p1;
|
||||
face.ccw = quad[1];
|
||||
face.vector = user_vector;
|
||||
|
||||
if (stroker->have_prev)
|
||||
XrStrokerJoin (stroker, &stroker->prev, &face);
|
||||
|
|
@ -164,8 +205,9 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
stroker->prev.ccw = quad[2];
|
||||
stroker->prev.pt = *p2;
|
||||
stroker->prev.cw = quad[3];
|
||||
stroker->prev.vector = user_vector;
|
||||
|
||||
XrTrapsTessellateConvexQuad(traps, quad);
|
||||
XrTrapsTessellateRectangle(traps, quad);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -173,21 +173,7 @@ _ComparePointFixedByY (const void *v1, const void *v2)
|
|||
}
|
||||
|
||||
void
|
||||
XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
||||
{
|
||||
qsort(t, 3, sizeof(XPointFixed), _ComparePointFixedByY);
|
||||
|
||||
if (t[1].x > t[2].x) {
|
||||
_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]);
|
||||
} else {
|
||||
_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]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XrTrapsTessellateConvexQuad (XrTraps *traps, XPointFixed q[4])
|
||||
XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
||||
{
|
||||
qsort(q, 4, sizeof(XPointFixed), _ComparePointFixedByY);
|
||||
|
||||
|
|
|
|||
6
xrint.h
6
xrint.h
|
|
@ -190,6 +190,7 @@ typedef struct _XrStrokeFace {
|
|||
XPointFixed ccw;
|
||||
XPointFixed pt;
|
||||
XPointFixed cw;
|
||||
XPointDouble vector;
|
||||
} XrStrokeFace;
|
||||
|
||||
typedef struct _XrStroker {
|
||||
|
|
@ -432,10 +433,7 @@ void
|
|||
XrTrapsDestroy(XrTraps *traps);
|
||||
|
||||
void
|
||||
XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3]);
|
||||
|
||||
void
|
||||
XrTrapsTessellateConvexQuad (XrTraps *traps, XPointFixed q[4]);
|
||||
XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4]);
|
||||
|
||||
void
|
||||
XrTrapsTessellatePolygon (XrTraps *traps, XrPolygon *poly, int winding);
|
||||
|
|
|
|||
78
xrstroker.c
78
xrstroker.c
|
|
@ -68,32 +68,69 @@ XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
|
|||
{
|
||||
XrGState *gstate = stroker->gstate;
|
||||
int clockwise = XrStrokerFaceClockwise (in, out);
|
||||
XrPolygon polygon;
|
||||
XPointFixed *inpt, *outpt;
|
||||
|
||||
if (clockwise)
|
||||
{
|
||||
inpt = &in->cw;
|
||||
outpt = &out->cw;
|
||||
}
|
||||
else
|
||||
{
|
||||
inpt = &in->ccw;
|
||||
outpt = &out->ccw;
|
||||
}
|
||||
XrPolygonInit (&polygon);
|
||||
switch (gstate->stroke_style.line_join) {
|
||||
case XrLineJoinRound: {
|
||||
}
|
||||
case XrLineJoinMiter: {
|
||||
XDouble c = in->vector.x * out->vector.x + in->vector.y * out->vector.y;
|
||||
double ml = gstate->stroke_style.miter_limit;
|
||||
if (2 <= ml * ml * (1 + c))
|
||||
{
|
||||
XDouble x1, y1, x2, y2;
|
||||
XDouble mx, my;
|
||||
XDouble dx1, dx2, dy1, dy2;
|
||||
XPointFixed outer;
|
||||
|
||||
x1 = XFixedToDouble(inpt->x);
|
||||
y1 = XFixedToDouble(inpt->y);
|
||||
dx1 = XFixedToDouble(inpt->y - in->pt.y);
|
||||
dy1 = -XFixedToDouble(inpt->x - in->pt.x);
|
||||
|
||||
x2 = XFixedToDouble(outpt->x);
|
||||
y2 = XFixedToDouble(outpt->y);
|
||||
dx2 = -XFixedToDouble(outpt->y - out->pt.y);
|
||||
dy2 = XFixedToDouble(outpt->x - out->pt.x);
|
||||
|
||||
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
||||
(dx1 * dy2 - dx2 * dy1));
|
||||
if (dy1)
|
||||
mx = (my - y1) * dx1 / dy1 + x1;
|
||||
else
|
||||
mx = (my - y2) * dx2 / dy2 + x2;
|
||||
|
||||
outer.x = XDoubleToFixed(mx);
|
||||
outer.y = XDoubleToFixed(my);
|
||||
XrPolygonAddEdge (&polygon, &in->pt, inpt);
|
||||
XrPolygonAddEdge (&polygon, inpt, &outer);
|
||||
XrPolygonAddEdge (&polygon, &outer, outpt);
|
||||
XrPolygonAddEdge (&polygon, outpt, &in->pt);
|
||||
break;
|
||||
}
|
||||
/* fall through ... */
|
||||
}
|
||||
case XrLineJoinBevel: {
|
||||
XPointFixed t[3];
|
||||
|
||||
t[0].x = in->pt.x;
|
||||
t[0].y = in->pt.y;
|
||||
if (clockwise) {
|
||||
t[1].x = in->cw.x;
|
||||
t[1].y = in->cw.y;
|
||||
t[2].x = out->cw.x;
|
||||
t[2].y = out->cw.y;
|
||||
} else {
|
||||
t[1].x = in->ccw.x;
|
||||
t[1].y = in->ccw.y;
|
||||
t[2].x = out->ccw.x;
|
||||
t[2].y = out->ccw.y;
|
||||
}
|
||||
XrTrapsTessellateTriangle (stroker->traps, t);
|
||||
XrPolygonAddEdge (&polygon, &in->pt, inpt);
|
||||
XrPolygonAddEdge (&polygon, inpt, outpt);
|
||||
XrPolygonAddEdge (&polygon, outpt, &in->pt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
XrTrapsTessellatePolygon (stroker->traps, &polygon, 1);
|
||||
XrPolygonDeinit (&polygon);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -110,6 +147,7 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
XrTraps *traps = stroker->traps;
|
||||
double mag, tmp;
|
||||
XPointDouble vector;
|
||||
XPointDouble user_vector;
|
||||
XPointFixed offset_ccw, offset_cw;
|
||||
XPointFixed quad[4];
|
||||
XrStrokeFace face;
|
||||
|
|
@ -117,6 +155,8 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
vector.x = XFixedToDouble(p2->x - p1->x);
|
||||
vector.y = XFixedToDouble(p2->y - p1->y);
|
||||
|
||||
XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &vector);
|
||||
|
||||
mag = sqrt(vector.x * vector.x + vector.y * vector.y);
|
||||
if (mag == 0) {
|
||||
return;
|
||||
|
|
@ -125,7 +165,7 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
vector.x /= mag;
|
||||
vector.y /= mag;
|
||||
|
||||
XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &vector);
|
||||
user_vector = vector;
|
||||
|
||||
tmp = vector.x;
|
||||
vector.x = vector.y * (style->line_width / 2.0);
|
||||
|
|
@ -153,6 +193,7 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
face.cw = quad[0];
|
||||
face.pt = *p1;
|
||||
face.ccw = quad[1];
|
||||
face.vector = user_vector;
|
||||
|
||||
if (stroker->have_prev)
|
||||
XrStrokerJoin (stroker, &stroker->prev, &face);
|
||||
|
|
@ -164,8 +205,9 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
stroker->prev.ccw = quad[2];
|
||||
stroker->prev.pt = *p2;
|
||||
stroker->prev.cw = quad[3];
|
||||
stroker->prev.vector = user_vector;
|
||||
|
||||
XrTrapsTessellateConvexQuad(traps, quad);
|
||||
XrTrapsTessellateRectangle(traps, quad);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
16
xrtraps.c
16
xrtraps.c
|
|
@ -173,21 +173,7 @@ _ComparePointFixedByY (const void *v1, const void *v2)
|
|||
}
|
||||
|
||||
void
|
||||
XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
||||
{
|
||||
qsort(t, 3, sizeof(XPointFixed), _ComparePointFixedByY);
|
||||
|
||||
if (t[1].x > t[2].x) {
|
||||
_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]);
|
||||
} else {
|
||||
_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]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XrTrapsTessellateConvexQuad (XrTraps *traps, XPointFixed q[4])
|
||||
XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
||||
{
|
||||
qsort(q, 4, sizeof(XPointFixed), _ComparePointFixedByY);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue