mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-04-28 18:10:39 +02:00
Remove dead-code remnants of old tessellator
This commit is contained in:
parent
1f3a5b4e12
commit
5d23d0c90c
1 changed files with 0 additions and 372 deletions
|
|
@ -49,18 +49,9 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo
|
|||
static int
|
||||
_compare_point_fixed_by_y (const void *av, const void *bv);
|
||||
|
||||
static int
|
||||
_compare_cairo_edge_by_top (const void *av, const void *bv);
|
||||
|
||||
static int
|
||||
_compare_cairo_edge_by_slope (const void *av, const void *bv);
|
||||
|
||||
static cairo_fixed_16_16_t
|
||||
_compute_x (cairo_line_t *line, cairo_fixed_t y);
|
||||
|
||||
static int
|
||||
_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret);
|
||||
|
||||
void
|
||||
_cairo_traps_init (cairo_traps_t *traps)
|
||||
{
|
||||
|
|
@ -512,52 +503,6 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4])
|
|||
return traps->status;
|
||||
}
|
||||
|
||||
static int
|
||||
_compare_cairo_edge_by_top (const void *av, const void *bv)
|
||||
{
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
|
||||
return a->edge.p1.y - b->edge.p1.y;
|
||||
}
|
||||
|
||||
/* 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
|
||||
_compare_cairo_edge_by_slope (const void *av, const void *bv)
|
||||
{
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
cairo_fixed_32_32_t d;
|
||||
|
||||
cairo_fixed_48_16_t a_dx = a->edge.p2.x - a->edge.p1.x;
|
||||
cairo_fixed_48_16_t a_dy = a->edge.p2.y - a->edge.p1.y;
|
||||
cairo_fixed_48_16_t b_dx = b->edge.p2.x - b->edge.p1.x;
|
||||
cairo_fixed_48_16_t b_dy = b->edge.p2.y - b->edge.p1.y;
|
||||
|
||||
d = b_dy * a_dx - a_dy * b_dx;
|
||||
|
||||
if (d > 0)
|
||||
return 1;
|
||||
else if (d == 0)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
_compare_cairo_edge_by_current_x_slope (const void *av, const void *bv)
|
||||
{
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
int ret;
|
||||
|
||||
ret = a->current_x - b->current_x;
|
||||
if (ret == 0)
|
||||
ret = _compare_cairo_edge_by_slope (a, b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero
|
||||
for horizontal lines. Now, we "know" that when we are tessellating
|
||||
polygons that the polygon data structure discards all horizontal
|
||||
|
|
@ -578,128 +523,6 @@ _compare_cairo_edge_by_current_x_slope (const void *av, const void *bv)
|
|||
doesn't matter much anyway).
|
||||
*/
|
||||
|
||||
/* XXX: Keith's new intersection code is much cleaner, and uses
|
||||
* sufficient precision for correctly sorting intersections according
|
||||
* to the analysis in Hobby's paper.
|
||||
*
|
||||
* But, when we enable this code, some things are failing, (eg. the
|
||||
* stars in test/fill_rule get filled wrong). This could indicate a
|
||||
* bug in one of tree places:
|
||||
*
|
||||
* 1) The new intersection code in this file
|
||||
*
|
||||
* 2) cairo_wideint.c (which is only exercised here)
|
||||
*
|
||||
* 3) In the current tessellator, (where the old intersection
|
||||
* code, with its mystic increments could be masking the bug).
|
||||
*
|
||||
* It will likely be easier to revisit this when the new tessellation
|
||||
* code is in place. So, for now, we'll simply disable the new
|
||||
* intersection code.
|
||||
*/
|
||||
|
||||
#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0
|
||||
|
||||
#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
|
||||
static const cairo_fixed_32_32_t
|
||||
_det16_32 (cairo_fixed_16_16_t a,
|
||||
cairo_fixed_16_16_t b,
|
||||
cairo_fixed_16_16_t c,
|
||||
cairo_fixed_16_16_t d)
|
||||
{
|
||||
return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
|
||||
_cairo_int32x32_64_mul (b, c));
|
||||
}
|
||||
|
||||
static const cairo_fixed_64_64_t
|
||||
_det32_64 (cairo_fixed_32_32_t a,
|
||||
cairo_fixed_32_32_t b,
|
||||
cairo_fixed_32_32_t c,
|
||||
cairo_fixed_32_32_t d)
|
||||
{
|
||||
return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d),
|
||||
_cairo_int64x64_128_mul (b, c));
|
||||
}
|
||||
|
||||
static const cairo_fixed_32_32_t
|
||||
_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a)
|
||||
{
|
||||
return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16);
|
||||
}
|
||||
|
||||
static int
|
||||
_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection)
|
||||
{
|
||||
cairo_fixed_16_16_t dx1, dx2, dy1, dy2;
|
||||
cairo_fixed_32_32_t den_det;
|
||||
cairo_fixed_32_32_t l1_det, l2_det;
|
||||
cairo_fixed_64_64_t num_det;
|
||||
cairo_fixed_32_32_t intersect_32_32;
|
||||
cairo_fixed_48_16_t intersect_48_16;
|
||||
cairo_fixed_16_16_t intersect_16_16;
|
||||
cairo_quorem128_t qr;
|
||||
|
||||
dx1 = l1->p1.x - l1->p2.x;
|
||||
dy1 = l1->p1.y - l1->p2.y;
|
||||
dx2 = l2->p1.x - l2->p2.x;
|
||||
dy2 = l2->p1.y - l2->p2.y;
|
||||
den_det = _det16_32 (dx1, dy1,
|
||||
dx2, dy2);
|
||||
|
||||
if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0)))
|
||||
return 0;
|
||||
|
||||
l1_det = _det16_32 (l1->p1.x, l1->p1.y,
|
||||
l1->p2.x, l1->p2.y);
|
||||
l2_det = _det16_32 (l2->p1.x, l2->p1.y,
|
||||
l2->p2.x, l2->p2.y);
|
||||
|
||||
num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1),
|
||||
l2_det, _fixed_16_16_to_fixed_32_32 (dy2));
|
||||
|
||||
/*
|
||||
* Ok, this one is a bit tricky in fixed point, the denominator
|
||||
* needs to be left with 32-bits of fraction so that the
|
||||
* result of the divide ends up with 32-bits of fraction (64 - 32 = 32)
|
||||
*/
|
||||
qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det));
|
||||
|
||||
intersect_32_32 = _cairo_int128_to_int64 (qr.quo);
|
||||
|
||||
/*
|
||||
* Find the ceiling of the quotient -- divrem returns
|
||||
* the quotient truncated towards zero, so if the
|
||||
* quotient should be positive (num_den and den_det have same sign)
|
||||
* bump the quotient up by one.
|
||||
*/
|
||||
|
||||
if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) &&
|
||||
(_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) ==
|
||||
_cairo_int64_ge (den_det, _cairo_int32_to_int64 (0))))
|
||||
{
|
||||
intersect_32_32 = _cairo_int64_add (intersect_32_32,
|
||||
_cairo_int32_to_int64 (1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Now convert from 32.32 to 48.16 and take the ceiling;
|
||||
* this requires adding in 15 1 bits and shifting the result
|
||||
*/
|
||||
|
||||
intersect_32_32 = _cairo_int64_add (intersect_32_32,
|
||||
_cairo_int32_to_int64 ((1 << 16) - 1));
|
||||
intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16);
|
||||
|
||||
/*
|
||||
* And drop the top bits
|
||||
*/
|
||||
intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16);
|
||||
|
||||
*y_intersection = intersect_16_16;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
|
||||
|
||||
static cairo_fixed_16_16_t
|
||||
_compute_x (cairo_line_t *line, cairo_fixed_t y)
|
||||
|
|
@ -711,201 +534,6 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y)
|
|||
return line->p1.x + (ex / dy);
|
||||
}
|
||||
|
||||
#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
|
||||
static double
|
||||
_compute_inverse_slope (cairo_line_t *l)
|
||||
{
|
||||
return (_cairo_fixed_to_double (l->p2.x - l->p1.x) /
|
||||
_cairo_fixed_to_double (l->p2.y - l->p1.y));
|
||||
}
|
||||
|
||||
static double
|
||||
_compute_x_intercept (cairo_line_t *l, double inverse_slope)
|
||||
{
|
||||
return _cairo_fixed_to_double (l->p1.x) - inverse_slope * _cairo_fixed_to_double (l->p1.y);
|
||||
}
|
||||
|
||||
static int
|
||||
_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ret)
|
||||
{
|
||||
/*
|
||||
* x = m1y + b1
|
||||
* x = m2y + b2
|
||||
* m1y + b1 = m2y + b2
|
||||
* y * (m1 - m2) = b2 - b1
|
||||
* y = (b2 - b1) / (m1 - m2)
|
||||
*/
|
||||
cairo_fixed_16_16_t y_intersect;
|
||||
double m1 = _compute_inverse_slope (l1);
|
||||
double b1 = _compute_x_intercept (l1, m1);
|
||||
double m2 = _compute_inverse_slope (l2);
|
||||
double b2 = _compute_x_intercept (l2, m2);
|
||||
|
||||
if (m1 == m2)
|
||||
return 0;
|
||||
|
||||
y_intersect = _cairo_fixed_from_double ((b2 - b1) / (m1 - m2));
|
||||
|
||||
if (m1 < m2) {
|
||||
cairo_line_t *t;
|
||||
t = l1;
|
||||
l1 = l2;
|
||||
l2 = t;
|
||||
}
|
||||
|
||||
/* Assuming 56 bits of floating point precision, the intersection
|
||||
is accurate within one sub-pixel coordinate. We must ensure
|
||||
that we return a value that is at or after the intersection. At
|
||||
most, we must increment once. */
|
||||
if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
|
||||
y_intersect++;
|
||||
/* XXX: Hmm... Keith's error calculations said we'd at most be off
|
||||
by one sub-pixel. But, I found that the paint-fill-BE-01.svg
|
||||
test from the W3C SVG conformance suite definitely requires two
|
||||
increments.
|
||||
|
||||
It could be that we need one to overcome the error, and another
|
||||
to round up.
|
||||
|
||||
It would be nice to be sure this code is correct, (but we can't
|
||||
do the while loop as it will work for way to long on
|
||||
exceedingly distant intersections with large errors that we
|
||||
really don't care about anyway as they will be ignored by the
|
||||
calling function.
|
||||
*/
|
||||
if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
|
||||
y_intersect++;
|
||||
/* XXX: hmm... now I found "intersection_killer" inside xrspline.c
|
||||
that requires 3 increments. Clearly, we haven't characterized
|
||||
this completely yet. */
|
||||
if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
|
||||
y_intersect++;
|
||||
/* I think I've found the answer to our problems. The insight is
|
||||
that everytime we round we are changing the slopes of the
|
||||
relevant lines, so we may be introducing new intersections that
|
||||
we miss, so everything breaks apart. John Hobby wrote a paper
|
||||
on how to fix this:
|
||||
|
||||
[Hobby93c] John D. Hobby, Practical Segment Intersection with
|
||||
Finite Precision Output, Computation Geometry Theory and
|
||||
Applications, 13(4), 1999.
|
||||
|
||||
Available online (2003-08017):
|
||||
|
||||
http://cm.bell-labs.com/cm/cs/doc/93/2-27.ps.gz
|
||||
|
||||
Now we just need to go off and implement that.
|
||||
*/
|
||||
|
||||
*y_ret = y_intersect;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
|
||||
|
||||
/* 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) )
|
||||
|
||||
fill_traps (active, y, next_y, fill_rule)
|
||||
|
||||
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.
|
||||
|
||||
Warning: This function obliterates the edges of the polygon provided.
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_traps_tessellate_polygon (cairo_traps_t *traps,
|
||||
cairo_polygon_t *poly,
|
||||
cairo_fill_rule_t fill_rule)
|
||||
{
|
||||
int i, active, inactive;
|
||||
cairo_fixed_t y, y_next, intersect;
|
||||
int in_out, num_edges = poly->num_edges;
|
||||
cairo_edge_t *edges = poly->edges;
|
||||
|
||||
if (num_edges == 0)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
|
||||
|
||||
y = edges[0].edge.p1.y;
|
||||
active = 0;
|
||||
inactive = 0;
|
||||
while (active < num_edges) {
|
||||
while (inactive < num_edges && edges[inactive].edge.p1.y <= y)
|
||||
inactive++;
|
||||
|
||||
for (i = active; i < inactive; i++)
|
||||
edges[i].current_x = _compute_x (&edges[i].edge, y);
|
||||
|
||||
qsort (&edges[active], inactive - active,
|
||||
sizeof (cairo_edge_t), _compare_cairo_edge_by_current_x_slope);
|
||||
|
||||
/* find next inflection point */
|
||||
y_next = edges[active].edge.p2.y;
|
||||
|
||||
for (i = active; i < inactive; i++) {
|
||||
if (edges[i].edge.p2.y < y_next)
|
||||
y_next = edges[i].edge.p2.y;
|
||||
/* check intersect */
|
||||
if (i != inactive - 1 && edges[i].current_x != edges[i+1].current_x)
|
||||
if (_line_segs_intersect_ceil (&edges[i].edge, &edges[i+1].edge,
|
||||
&intersect))
|
||||
if (intersect > y && intersect < y_next)
|
||||
y_next = intersect;
|
||||
}
|
||||
/* check next inactive point */
|
||||
if (inactive < num_edges && edges[inactive].edge.p1.y < y_next)
|
||||
y_next = edges[inactive].edge.p1.y;
|
||||
|
||||
/* walk the active edges generating trapezoids */
|
||||
in_out = 0;
|
||||
for (i = active; i < inactive - 1; i++) {
|
||||
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
|
||||
if (edges[i].clockWise)
|
||||
in_out++;
|
||||
else
|
||||
in_out--;
|
||||
if (in_out == 0)
|
||||
continue;
|
||||
} else {
|
||||
in_out++;
|
||||
if ((in_out & 1) == 0)
|
||||
continue;
|
||||
}
|
||||
_cairo_traps_add_trap (traps, y, y_next, &edges[i].edge, &edges[i+1].edge);
|
||||
}
|
||||
|
||||
/* delete inactive edges */
|
||||
for (i = active; i < inactive; i++) {
|
||||
if (edges[i].edge.p2.y <= y_next) {
|
||||
memmove (&edges[active+1], &edges[active], (i - active) * sizeof (cairo_edge_t));
|
||||
active++;
|
||||
}
|
||||
}
|
||||
|
||||
y = y_next;
|
||||
}
|
||||
return traps->status;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue