2002-08-07 19:48:49 +00:00
|
|
|
|
/*
|
|
|
|
|
|
* $XFree86: $
|
|
|
|
|
|
*
|
|
|
|
|
|
* Copyright <EFBFBD> 2002 Keith Packard, member of The XFree86 Project, Inc.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
|
|
* the above copyright notice appear in all copies and that both that
|
|
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
|
|
|
|
|
* documentation, and that the name of Keith Packard not be used in
|
|
|
|
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
|
|
|
|
* specific, written prior permission. Keith Packard makes no
|
|
|
|
|
|
* representations about the suitability of this software for any purpose. It
|
|
|
|
|
|
* is provided "as is" without express or implied warranty.
|
|
|
|
|
|
*
|
|
|
|
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
|
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
|
|
|
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
|
|
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
|
|
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
|
|
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
*
|
|
|
|
|
|
* 2002-07-15: Converted from XRenderCompositeDoublePoly to XrTrap. Carl D. Worth
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "xrint.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define XR_TRAPS_GROWTH_INC 10
|
|
|
|
|
|
|
|
|
|
|
|
/* private functions */
|
|
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
static XrStatus
|
2002-08-07 19:48:49 +00:00
|
|
|
|
_XrTrapsGrowBy(XrTraps *traps, int additional);
|
|
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus
|
2002-08-14 00:39:43 +00:00
|
|
|
|
_XrTrapsAddTrap(XrTraps *traps, XFixed top, XFixed bottom,
|
|
|
|
|
|
XLineFixed left, XLineFixed right);
|
|
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus
|
2002-08-14 00:39:43 +00:00
|
|
|
|
_XrTrapsAddTrapFromPoints(XrTraps *traps, XFixed top, XFixed bottom,
|
|
|
|
|
|
XPointFixed left_p1, XPointFixed left_p2,
|
|
|
|
|
|
XPointFixed right_p1, XPointFixed right_p2);
|
|
|
|
|
|
|
2002-08-07 19:48:49 +00:00
|
|
|
|
static int
|
2002-09-17 13:38:55 +00:00
|
|
|
|
_ComparePointFixedByY (const void *av, const void *bv);
|
2002-08-07 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
|
static int
|
2002-09-17 13:38:55 +00:00
|
|
|
|
_CompareXrEdgeByTop (const void *av, const void *bv);
|
2002-08-07 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
|
static XFixed
|
|
|
|
|
|
_ComputeX (XLineFixed *line, XFixed y);
|
|
|
|
|
|
|
|
|
|
|
|
static double
|
|
|
|
|
|
_ComputeInverseSlope (XLineFixed *l);
|
|
|
|
|
|
|
|
|
|
|
|
static double
|
|
|
|
|
|
_ComputeXIntercept (XLineFixed *l, double inverse_slope);
|
|
|
|
|
|
|
|
|
|
|
|
static XFixed
|
2002-09-17 14:44:52 +00:00
|
|
|
|
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *intersection);
|
2002-08-07 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
|
void
|
2002-10-16 12:57:00 +00:00
|
|
|
|
_XrTrapsInit(XrTraps *traps)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
|
|
|
|
|
traps->num_xtraps = 0;
|
|
|
|
|
|
|
|
|
|
|
|
traps->xtraps_size = 0;
|
|
|
|
|
|
traps->xtraps = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2002-10-16 12:57:00 +00:00
|
|
|
|
_XrTrapsDeinit(XrTraps *traps)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
|
|
|
|
|
if (traps->xtraps_size) {
|
|
|
|
|
|
free(traps->xtraps);
|
2002-09-10 08:01:00 +00:00
|
|
|
|
traps->xtraps = NULL;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
traps->xtraps_size = 0;
|
|
|
|
|
|
traps->num_xtraps = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus
|
2002-08-14 00:39:43 +00:00
|
|
|
|
_XrTrapsAddTrap(XrTraps *traps, XFixed top, XFixed bottom,
|
|
|
|
|
|
XLineFixed left, XLineFixed right)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus status;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
XTrapezoid *trap;
|
|
|
|
|
|
|
2002-08-12 09:38:05 +00:00
|
|
|
|
if (top == bottom) {
|
2002-10-16 12:57:00 +00:00
|
|
|
|
return XrStatusSuccess;
|
2002-08-12 09:38:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2002-08-07 19:48:49 +00:00
|
|
|
|
if (traps->num_xtraps >= traps->xtraps_size) {
|
2002-10-16 12:57:00 +00:00
|
|
|
|
status = _XrTrapsGrowBy(traps, XR_TRAPS_GROWTH_INC);
|
|
|
|
|
|
if (status)
|
|
|
|
|
|
return status;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
trap = &traps->xtraps[traps->num_xtraps];
|
|
|
|
|
|
trap->top = top;
|
|
|
|
|
|
trap->bottom = bottom;
|
|
|
|
|
|
trap->left = left;
|
|
|
|
|
|
trap->right = right;
|
|
|
|
|
|
|
|
|
|
|
|
traps->num_xtraps++;
|
2002-08-15 05:22:59 +00:00
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
return XrStatusSuccess;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus
|
2002-08-14 00:39:43 +00:00
|
|
|
|
_XrTrapsAddTrapFromPoints(XrTraps *traps, XFixed top, XFixed bottom,
|
|
|
|
|
|
XPointFixed left_p1, XPointFixed left_p2,
|
|
|
|
|
|
XPointFixed right_p1, XPointFixed right_p2)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
|
|
|
|
|
XLineFixed left;
|
|
|
|
|
|
XLineFixed right;
|
|
|
|
|
|
|
|
|
|
|
|
left.p1 = left_p1;
|
|
|
|
|
|
left.p2 = left_p2;
|
|
|
|
|
|
|
|
|
|
|
|
right.p1 = right_p1;
|
|
|
|
|
|
right.p2 = right_p2;
|
|
|
|
|
|
|
2002-08-15 05:22:59 +00:00
|
|
|
|
return _XrTrapsAddTrap(traps, top, bottom, left, right);
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
static XrStatus
|
2002-08-07 19:48:49 +00:00
|
|
|
|
_XrTrapsGrowBy(XrTraps *traps, int additional)
|
|
|
|
|
|
{
|
|
|
|
|
|
XTrapezoid *new_xtraps;
|
|
|
|
|
|
int old_size = traps->xtraps_size;
|
|
|
|
|
|
int new_size = traps->num_xtraps + additional;
|
|
|
|
|
|
|
|
|
|
|
|
if (new_size <= traps->xtraps_size) {
|
2002-10-16 12:57:00 +00:00
|
|
|
|
return XrStatusSuccess;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
traps->xtraps_size = new_size;
|
|
|
|
|
|
new_xtraps = realloc(traps->xtraps, traps->xtraps_size * sizeof(XTrapezoid));
|
|
|
|
|
|
|
2002-08-15 05:22:59 +00:00
|
|
|
|
if (new_xtraps == NULL) {
|
2002-08-07 19:48:49 +00:00
|
|
|
|
traps->xtraps_size = old_size;
|
2002-10-16 12:57:00 +00:00
|
|
|
|
return XrStatusNoMemory;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
2002-08-15 05:22:59 +00:00
|
|
|
|
|
|
|
|
|
|
traps->xtraps = new_xtraps;
|
|
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
return XrStatusSuccess;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-09-17 13:38:55 +00:00
|
|
|
|
_ComparePointFixedByY (const void *av, const void *bv)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
2002-09-17 13:38:55 +00:00
|
|
|
|
const XPointFixed *a = av, *b = bv;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
|
2002-09-17 13:38:55 +00:00
|
|
|
|
int ret = a->y - b->y;
|
2002-08-12 09:38:05 +00:00
|
|
|
|
if (ret == 0) {
|
2002-09-17 13:38:55 +00:00
|
|
|
|
ret = a->x - b->x;
|
2002-08-12 09:38:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
return ret;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus
|
|
|
|
|
|
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus status;
|
2002-08-15 05:22:59 +00:00
|
|
|
|
|
2002-08-07 19:48:49 +00:00
|
|
|
|
qsort(q, 4, sizeof(XPointFixed), _ComparePointFixedByY);
|
|
|
|
|
|
|
|
|
|
|
|
if (q[1].x > q[2].x) {
|
2002-10-16 12:57:00 +00:00
|
|
|
|
status = _XrTrapsAddTrapFromPoints(traps, q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
|
|
|
|
|
|
if (status)
|
|
|
|
|
|
return status;
|
|
|
|
|
|
status = _XrTrapsAddTrapFromPoints(traps, q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
|
|
|
|
|
|
if (status)
|
|
|
|
|
|
return status;
|
|
|
|
|
|
status = _XrTrapsAddTrapFromPoints(traps, q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
|
|
|
|
|
|
if (status)
|
|
|
|
|
|
return status;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
} else {
|
2002-10-16 12:57:00 +00:00
|
|
|
|
status = _XrTrapsAddTrapFromPoints(traps, q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
|
|
|
|
|
|
if (status)
|
|
|
|
|
|
return status;
|
|
|
|
|
|
status = _XrTrapsAddTrapFromPoints(traps, q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
|
|
|
|
|
|
if (status)
|
|
|
|
|
|
return status;
|
|
|
|
|
|
status = _XrTrapsAddTrapFromPoints(traps, q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
|
|
|
|
|
|
if (status)
|
|
|
|
|
|
return status;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
2002-08-15 05:22:59 +00:00
|
|
|
|
|
2002-10-16 12:57:00 +00:00
|
|
|
|
return XrStatusSuccess;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-09-17 13:38:55 +00:00
|
|
|
|
_CompareXrEdgeByTop (const void *av, const void *bv)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
2002-09-17 13:38:55 +00:00
|
|
|
|
const XrEdge *a = av, *b = bv;
|
2002-08-14 00:39:43 +00:00
|
|
|
|
int ret;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
|
2002-09-17 13:38:55 +00:00
|
|
|
|
ret = a->edge.p1.y - b->edge.p1.y;
|
2002-08-14 00:39:43 +00:00
|
|
|
|
if (ret == 0)
|
2002-09-17 13:38:55 +00:00
|
|
|
|
ret = a->edge.p1.x - b->edge.p1.x;
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return value is:
|
|
|
|
|
|
> 0 if a is "clockwise" from b, (in a mathematical, not a graphical sense)
|
|
|
|
|
|
== 0 if slope(a) == slope(b)
|
|
|
|
|
|
< 0 if a is "counter-clockwise" from b
|
|
|
|
|
|
*/
|
|
|
|
|
|
static int
|
|
|
|
|
|
_CompareXrEdgeBySlope (const void *av, const void *bv)
|
|
|
|
|
|
{
|
|
|
|
|
|
const XrEdge *a = av, *b = bv;
|
|
|
|
|
|
|
|
|
|
|
|
double a_dx = XFixedToDouble(a->edge.p2.x - a->edge.p1.x);
|
|
|
|
|
|
double a_dy = XFixedToDouble(a->edge.p2.y - a->edge.p1.y);
|
|
|
|
|
|
double b_dx = XFixedToDouble(b->edge.p2.x - b->edge.p1.x);
|
|
|
|
|
|
double b_dy = XFixedToDouble(b->edge.p2.y - b->edge.p1.y);
|
|
|
|
|
|
|
|
|
|
|
|
return b_dy * a_dx - a_dy * b_dx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
|
_CompareXrEdgeByCurrentXThenSlope (const void *av, const void *bv)
|
|
|
|
|
|
{
|
|
|
|
|
|
const XrEdge *a = av, *b = bv;
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
|
|
ret = a->current_x - b->current_x;
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
|
ret = _CompareXrEdgeBySlope(a, b);
|
2002-08-14 00:39:43 +00:00
|
|
|
|
return ret;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2002-09-20 09:43:42 +00:00
|
|
|
|
/* XXX: Both _ComputeX and _ComputeInverseSlope will divide by zero
|
|
|
|
|
|
for horizontal lines. Now, we "know" that when we are tessellating
|
|
|
|
|
|
polygons that the polygon data structure discards all horizontal
|
|
|
|
|
|
edges, but there's nothing here to guarantee that. I suggest the
|
|
|
|
|
|
following:
|
|
|
|
|
|
|
|
|
|
|
|
A) Move all of the polygon tessellation code out of xrtraps.c and
|
|
|
|
|
|
into xrpoly.c, (in order to be in the same module as the code
|
|
|
|
|
|
discarding horizontal lines).
|
|
|
|
|
|
|
|
|
|
|
|
OR
|
|
|
|
|
|
|
|
|
|
|
|
B) Re-implement the line intersection in a way that avoids all
|
|
|
|
|
|
division by zero. Here's one approach. The only disadvantage
|
|
|
|
|
|
might be that that there are not meaningful names for all of the
|
|
|
|
|
|
sub-computations -- just a bunch of determinants. I haven't
|
|
|
|
|
|
looked at complexity, (both are probably similar and it probably
|
|
|
|
|
|
doesn't matter much anyway).
|
|
|
|
|
|
|
|
|
|
|
|
static double
|
|
|
|
|
|
_det (double a, double b, double c, double d)
|
|
|
|
|
|
{
|
|
|
|
|
|
return a * d - b * c;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
|
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
|
|
|
|
|
{
|
|
|
|
|
|
double dx1 = XFixedToDouble(l1->p1.x - l1->p2.x);
|
|
|
|
|
|
double dy1 = XFixedToDouble(l1->p1.y - l1->p2.y);
|
|
|
|
|
|
|
|
|
|
|
|
double dx2 = XFixedToDouble(l2->p1.x - l2->p2.x);
|
|
|
|
|
|
double dy2 = XFixedToDouble(l2->p1.y - l2->p2.y);
|
|
|
|
|
|
|
|
|
|
|
|
double l1_det, l2_det;
|
|
|
|
|
|
|
|
|
|
|
|
double den_det = _det(dx1, dy1, dx2, dy2);
|
|
|
|
|
|
|
|
|
|
|
|
if (den_det == 0)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
l1_det = _det(l1->p1.x, l1->p1.y,
|
|
|
|
|
|
l1->p2.x, l1->p2.y);
|
|
|
|
|
|
l2_det = _det(l2->p1.x, l2->p1.y,
|
|
|
|
|
|
l2->p2.x, l2->p2.y);
|
|
|
|
|
|
|
|
|
|
|
|
*y_intersection = _det(l1_det, dy1,
|
|
|
|
|
|
l2_det, dy2) / den_det;
|
|
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
2002-08-07 19:48:49 +00:00
|
|
|
|
static XFixed
|
|
|
|
|
|
_ComputeX (XLineFixed *line, XFixed y)
|
|
|
|
|
|
{
|
|
|
|
|
|
XFixed dx = line->p2.x - line->p1.x;
|
|
|
|
|
|
double ex = (double) (y - line->p1.y) * (double) dx;
|
|
|
|
|
|
XFixed dy = line->p2.y - line->p1.y;
|
|
|
|
|
|
|
2002-09-20 09:43:42 +00:00
|
|
|
|
return line->p1.x + (ex / dy);
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static double
|
|
|
|
|
|
_ComputeInverseSlope (XLineFixed *l)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (XFixedToDouble (l->p2.x - l->p1.x) /
|
|
|
|
|
|
XFixedToDouble (l->p2.y - l->p1.y));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static double
|
|
|
|
|
|
_ComputeXIntercept (XLineFixed *l, double inverse_slope)
|
|
|
|
|
|
{
|
|
|
|
|
|
return XFixedToDouble (l->p1.x) - inverse_slope * XFixedToDouble (l->p1.y);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2002-09-17 14:44:52 +00:00
|
|
|
|
static int
|
2002-09-20 09:43:42 +00:00
|
|
|
|
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
|
|
|
|
|
/*
|
|
|
|
|
|
* x = m1y + b1
|
|
|
|
|
|
* x = m2y + b2
|
|
|
|
|
|
* m1y + b1 = m2y + b2
|
|
|
|
|
|
* y * (m1 - m2) = b2 - b1
|
|
|
|
|
|
* y = (b2 - b1) / (m1 - m2)
|
|
|
|
|
|
*/
|
|
|
|
|
|
double m1 = _ComputeInverseSlope (l1);
|
|
|
|
|
|
double b1 = _ComputeXIntercept (l1, m1);
|
|
|
|
|
|
double m2 = _ComputeInverseSlope (l2);
|
|
|
|
|
|
double b2 = _ComputeXIntercept (l2, m2);
|
|
|
|
|
|
|
2002-09-17 14:44:52 +00:00
|
|
|
|
if (m1 == m2)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
2002-09-20 09:43:42 +00:00
|
|
|
|
*y_intersection = XDoubleToFixed ((b2 - b1) / (m1 - m2));
|
2002-09-17 14:44:52 +00:00
|
|
|
|
return 1;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2002-09-13 19:01:01 +00:00
|
|
|
|
static void
|
|
|
|
|
|
_SortEdgeList(XrEdge **active)
|
|
|
|
|
|
{
|
|
|
|
|
|
XrEdge *e, *en, *next;
|
|
|
|
|
|
|
|
|
|
|
|
/* sort active list */
|
|
|
|
|
|
for (e = *active; e; e = next)
|
|
|
|
|
|
{
|
|
|
|
|
|
next = e->next;
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Find one later in the list that belongs before the
|
|
|
|
|
|
* current one
|
|
|
|
|
|
*/
|
|
|
|
|
|
for (en = next; en; en = en->next)
|
|
|
|
|
|
{
|
2002-09-17 13:38:55 +00:00
|
|
|
|
if (_CompareXrEdgeByCurrentXThenSlope(e, en) > 0)
|
2002-09-13 19:01:01 +00:00
|
|
|
|
{
|
|
|
|
|
|
/*
|
|
|
|
|
|
* insert en before e
|
|
|
|
|
|
*
|
|
|
|
|
|
* extract en
|
|
|
|
|
|
*/
|
|
|
|
|
|
en->prev->next = en->next;
|
|
|
|
|
|
if (en->next)
|
|
|
|
|
|
en->next->prev = en->prev;
|
|
|
|
|
|
/*
|
|
|
|
|
|
* insert en
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (e->prev)
|
|
|
|
|
|
e->prev->next = en;
|
|
|
|
|
|
else
|
|
|
|
|
|
*active = en;
|
|
|
|
|
|
en->prev = e->prev;
|
|
|
|
|
|
e->prev = en;
|
|
|
|
|
|
en->next = e;
|
|
|
|
|
|
/*
|
|
|
|
|
|
* start over at en
|
|
|
|
|
|
*/
|
|
|
|
|
|
next = en;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2002-09-17 14:21:36 +00:00
|
|
|
|
/* The algorithm here is pretty simple:
|
|
|
|
|
|
|
|
|
|
|
|
inactive = [edges]
|
|
|
|
|
|
y = min_p1_y(inactive)
|
|
|
|
|
|
|
|
|
|
|
|
while (num_active || num_inactive) {
|
|
|
|
|
|
active = all edges containing y
|
|
|
|
|
|
|
|
|
|
|
|
next_y = min( min_p2_y(active), min_p1_y(inactive), min_intersection(active) )
|
|
|
|
|
|
|
2002-10-24 11:27:29 +00:00
|
|
|
|
fill_traps(active, y, next_y, fill_rule)
|
2002-09-17 14:21:36 +00:00
|
|
|
|
|
|
|
|
|
|
y = next_y
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
The invariants that hold during fill_traps are:
|
|
|
|
|
|
|
|
|
|
|
|
All edges in active contain both y and next_y
|
|
|
|
|
|
No edges in active intersect within y and next_y
|
|
|
|
|
|
|
|
|
|
|
|
These invariants mean that fill_traps is as simple as sorting the
|
|
|
|
|
|
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.
|
|
|
|
|
|
*/
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus
|
|
|
|
|
|
_XrTrapsTessellatePolygon (XrTraps *traps,
|
|
|
|
|
|
XrPolygon *poly,
|
2002-10-24 11:27:29 +00:00
|
|
|
|
XrFillRule fill_rule)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
2002-10-16 12:57:00 +00:00
|
|
|
|
XrStatus status;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
int inactive;
|
2002-08-14 00:39:43 +00:00
|
|
|
|
XrEdge *active;
|
2002-09-17 13:38:55 +00:00
|
|
|
|
XrEdge *e, *en, *next;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
XFixed y, next_y, intersect;
|
2002-08-14 00:39:43 +00:00
|
|
|
|
int in_out, num_edges = poly->num_edges;
|
|
|
|
|
|
XrEdge *edges = poly->edges;
|
2002-08-14 00:44:28 +00:00
|
|
|
|
|
|
|
|
|
|
if (num_edges == 0)
|
2002-10-16 12:57:00 +00:00
|
|
|
|
return XrStatusSuccess;
|
2002-08-14 00:44:28 +00:00
|
|
|
|
|
2002-08-14 00:39:43 +00:00
|
|
|
|
qsort (edges, num_edges, sizeof (XrEdge), _CompareXrEdgeByTop);
|
2002-08-07 19:48:49 +00:00
|
|
|
|
|
|
|
|
|
|
y = edges[0].edge.p1.y;
|
|
|
|
|
|
active = 0;
|
|
|
|
|
|
inactive = 0;
|
2002-08-14 00:39:43 +00:00
|
|
|
|
while (active || inactive < num_edges)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
2002-09-17 13:38:55 +00:00
|
|
|
|
for (e = active; e; e = e->next) {
|
|
|
|
|
|
e->current_x = _ComputeX (&e->edge, y);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2002-08-07 19:48:49 +00:00
|
|
|
|
/* insert new active edges into list */
|
2002-08-14 00:39:43 +00:00
|
|
|
|
while (inactive < num_edges)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
|
|
|
|
|
e = &edges[inactive];
|
|
|
|
|
|
if (e->edge.p1.y > y)
|
|
|
|
|
|
break;
|
|
|
|
|
|
/* move this edge into the active list */
|
|
|
|
|
|
inactive++;
|
2002-09-13 12:55:37 +00:00
|
|
|
|
e->current_x = _ComputeX (&e->edge, y);
|
2002-08-14 00:39:43 +00:00
|
|
|
|
|
2002-09-17 13:38:55 +00:00
|
|
|
|
/* insert e at head of list */
|
|
|
|
|
|
e->next = active;
|
|
|
|
|
|
e->prev = NULL;
|
|
|
|
|
|
if (active)
|
|
|
|
|
|
active->prev = e;
|
|
|
|
|
|
active = e;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2002-09-17 13:38:55 +00:00
|
|
|
|
_SortEdgeList(&active);
|
|
|
|
|
|
|
2002-08-07 19:48:49 +00:00
|
|
|
|
/* find next inflection point */
|
2002-10-23 18:30:53 +00:00
|
|
|
|
if (active)
|
|
|
|
|
|
next_y = active->edge.p2.y;
|
|
|
|
|
|
else
|
|
|
|
|
|
next_y = edges[inactive].edge.p1.y;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
for (e = active; e; e = en)
|
|
|
|
|
|
{
|
2002-09-17 13:38:55 +00:00
|
|
|
|
en = e->next;
|
|
|
|
|
|
|
2002-08-07 19:48:49 +00:00
|
|
|
|
if (e->edge.p2.y < next_y)
|
|
|
|
|
|
next_y = e->edge.p2.y;
|
|
|
|
|
|
/* check intersect */
|
2002-09-13 12:55:37 +00:00
|
|
|
|
if (en && e->current_x != en->current_x)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
2002-09-17 14:44:52 +00:00
|
|
|
|
if (_LinesIntersect (&e->edge, &en->edge, &intersect))
|
|
|
|
|
|
if (intersect > y) {
|
|
|
|
|
|
/* Need to guarantee that we get all the way past
|
|
|
|
|
|
the intersection point so that the edges sort
|
|
|
|
|
|
properly next time through the loop. */
|
2002-09-20 09:43:42 +00:00
|
|
|
|
if (_ComputeX(&e->edge, intersect) < _ComputeX(&en->edge, intersect))
|
2002-09-17 14:44:52 +00:00
|
|
|
|
intersect++;
|
|
|
|
|
|
if (intersect < next_y)
|
|
|
|
|
|
next_y = intersect;
|
|
|
|
|
|
}
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/* check next inactive point */
|
2002-08-14 00:39:43 +00:00
|
|
|
|
if (inactive < num_edges && edges[inactive].edge.p1.y < next_y)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
next_y = edges[inactive].edge.p1.y;
|
|
|
|
|
|
|
|
|
|
|
|
/* walk the list generating trapezoids */
|
|
|
|
|
|
in_out = 0;
|
|
|
|
|
|
for (e = active; e && (en = e->next); e = e->next)
|
|
|
|
|
|
{
|
2002-10-24 11:27:29 +00:00
|
|
|
|
if (fill_rule == XrFillRuleWinding) {
|
2002-08-07 19:48:49 +00:00
|
|
|
|
if (e->clockWise) {
|
|
|
|
|
|
in_out++;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
in_out--;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (in_out == 0) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
in_out++;
|
|
|
|
|
|
if (in_out % 2 == 0) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2002-10-16 12:57:00 +00:00
|
|
|
|
status = _XrTrapsAddTrap(traps, y, next_y, e->edge, en->edge);
|
|
|
|
|
|
if (status)
|
|
|
|
|
|
return status;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* delete inactive edges from list */
|
|
|
|
|
|
for (e = active; e; e = next)
|
|
|
|
|
|
{
|
|
|
|
|
|
next = e->next;
|
2002-09-17 13:38:55 +00:00
|
|
|
|
if (e->edge.p2.y <= next_y)
|
2002-08-07 19:48:49 +00:00
|
|
|
|
{
|
|
|
|
|
|
if (e->prev)
|
|
|
|
|
|
e->prev->next = e->next;
|
|
|
|
|
|
else
|
|
|
|
|
|
active = e->next;
|
|
|
|
|
|
if (e->next)
|
|
|
|
|
|
e->next->prev = e->prev;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2002-09-17 13:38:55 +00:00
|
|
|
|
|
|
|
|
|
|
y = next_y;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|
2002-10-16 12:57:00 +00:00
|
|
|
|
return XrStatusSuccess;
|
2002-08-07 19:48:49 +00:00
|
|
|
|
}
|