Poly.c revision 1f0ac6a5
11f0ac6a5Smrg/*
21f0ac6a5Smrg *
31f0ac6a5Smrg * Copyright © 2002 Keith Packard
41f0ac6a5Smrg *
51f0ac6a5Smrg * Permission to use, copy, modify, distribute, and sell this software and its
61f0ac6a5Smrg * documentation for any purpose is hereby granted without fee, provided that
71f0ac6a5Smrg * the above copyright notice appear in all copies and that both that
81f0ac6a5Smrg * copyright notice and this permission notice appear in supporting
91f0ac6a5Smrg * documentation, and that the name of Keith Packard not be used in
101f0ac6a5Smrg * advertising or publicity pertaining to distribution of the software without
111f0ac6a5Smrg * specific, written prior permission.  Keith Packard makes no
121f0ac6a5Smrg * representations about the suitability of this software for any purpose.  It
131f0ac6a5Smrg * is provided "as is" without express or implied warranty.
141f0ac6a5Smrg *
151f0ac6a5Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
161f0ac6a5Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
171f0ac6a5Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
181f0ac6a5Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
191f0ac6a5Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
201f0ac6a5Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
211f0ac6a5Smrg * PERFORMANCE OF THIS SOFTWARE.
221f0ac6a5Smrg */
231f0ac6a5Smrg
241f0ac6a5Smrg#ifdef HAVE_CONFIG_H
251f0ac6a5Smrg#include <config.h>
261f0ac6a5Smrg#endif
271f0ac6a5Smrg#include "Xrenderint.h"
281f0ac6a5Smrg
291f0ac6a5Smrgtypedef struct _Edge Edge;
301f0ac6a5Smrg
311f0ac6a5Smrgstruct _Edge {
321f0ac6a5Smrg    XLineFixed	edge;
331f0ac6a5Smrg    XFixed	current_x;
341f0ac6a5Smrg    Bool	clockWise;
351f0ac6a5Smrg    Edge	*next, *prev;
361f0ac6a5Smrg};
371f0ac6a5Smrg
381f0ac6a5Smrgstatic int
391f0ac6a5SmrgCompareEdge (const void *o1, const void *o2)
401f0ac6a5Smrg{
411f0ac6a5Smrg    const Edge	*e1 = o1, *e2 = o2;
421f0ac6a5Smrg
431f0ac6a5Smrg    return e1->edge.p1.y - e2->edge.p1.y;
441f0ac6a5Smrg}
451f0ac6a5Smrg
461f0ac6a5Smrgstatic XFixed
471f0ac6a5SmrgXRenderComputeX (XLineFixed *line, XFixed y)
481f0ac6a5Smrg{
491f0ac6a5Smrg    XFixed  dx = line->p2.x - line->p1.x;
501f0ac6a5Smrg    double  ex = (double) (y - line->p1.y) * (double) dx;
511f0ac6a5Smrg    XFixed  dy = line->p2.y - line->p1.y;
521f0ac6a5Smrg
531f0ac6a5Smrg    return (XFixed) line->p1.x + (XFixed) (ex / dy);
541f0ac6a5Smrg}
551f0ac6a5Smrg
561f0ac6a5Smrgstatic double
571f0ac6a5SmrgXRenderComputeInverseSlope (XLineFixed *l)
581f0ac6a5Smrg{
591f0ac6a5Smrg    return (XFixedToDouble (l->p2.x - l->p1.x) /
601f0ac6a5Smrg	    XFixedToDouble (l->p2.y - l->p1.y));
611f0ac6a5Smrg}
621f0ac6a5Smrg
631f0ac6a5Smrgstatic double
641f0ac6a5SmrgXRenderComputeXIntercept (XLineFixed *l, double inverse_slope)
651f0ac6a5Smrg{
661f0ac6a5Smrg    return XFixedToDouble (l->p1.x) - inverse_slope * XFixedToDouble (l->p1.y);
671f0ac6a5Smrg}
681f0ac6a5Smrg
691f0ac6a5Smrgstatic XFixed
701f0ac6a5SmrgXRenderComputeIntersect (XLineFixed *l1, XLineFixed *l2)
711f0ac6a5Smrg{
721f0ac6a5Smrg    /*
731f0ac6a5Smrg     * x = m1y + b1
741f0ac6a5Smrg     * x = m2y + b2
751f0ac6a5Smrg     * m1y + b1 = m2y + b2
761f0ac6a5Smrg     * y * (m1 - m2) = b2 - b1
771f0ac6a5Smrg     * y = (b2 - b1) / (m1 - m2)
781f0ac6a5Smrg     */
791f0ac6a5Smrg    double  m1 = XRenderComputeInverseSlope (l1);
801f0ac6a5Smrg    double  b1 = XRenderComputeXIntercept (l1, m1);
811f0ac6a5Smrg    double  m2 = XRenderComputeInverseSlope (l2);
821f0ac6a5Smrg    double  b2 = XRenderComputeXIntercept (l2, m2);
831f0ac6a5Smrg
841f0ac6a5Smrg    return XDoubleToFixed ((b2 - b1) / (m1 - m2));
851f0ac6a5Smrg}
861f0ac6a5Smrg
871f0ac6a5Smrgstatic int
881f0ac6a5SmrgXRenderComputeTrapezoids (Edge		*edges,
891f0ac6a5Smrg			  int		nedges,
901f0ac6a5Smrg			  int		winding,
911f0ac6a5Smrg			  XTrapezoid	*traps)
921f0ac6a5Smrg{
931f0ac6a5Smrg    int		ntraps = 0;
941f0ac6a5Smrg    int		inactive;
951f0ac6a5Smrg    Edge	*active;
961f0ac6a5Smrg    Edge	*e, *en, *next;
971f0ac6a5Smrg    XFixed	y, next_y, intersect;
981f0ac6a5Smrg
991f0ac6a5Smrg    qsort (edges, nedges, sizeof (Edge), CompareEdge);
1001f0ac6a5Smrg
1011f0ac6a5Smrg    y = edges[0].edge.p1.y;
1021f0ac6a5Smrg    active = 0;
1031f0ac6a5Smrg    inactive = 0;
1041f0ac6a5Smrg    while (active || inactive < nedges)
1051f0ac6a5Smrg    {
1061f0ac6a5Smrg	/* insert new active edges into list */
1071f0ac6a5Smrg	while (inactive < nedges)
1081f0ac6a5Smrg	{
1091f0ac6a5Smrg	    e = &edges[inactive];
1101f0ac6a5Smrg	    if (e->edge.p1.y > y)
1111f0ac6a5Smrg		break;
1121f0ac6a5Smrg	    /* move this edge into the active list */
1131f0ac6a5Smrg	    inactive++;
1141f0ac6a5Smrg	    e->next = active;
1151f0ac6a5Smrg	    e->prev = 0;
1161f0ac6a5Smrg	    if (active)
1171f0ac6a5Smrg		active->prev = e;
1181f0ac6a5Smrg	    active = e;
1191f0ac6a5Smrg	}
1201f0ac6a5Smrg	/* compute x coordinates along this group */
1211f0ac6a5Smrg	for (e = active; e; e = e->next)
1221f0ac6a5Smrg	    e->current_x = XRenderComputeX (&e->edge, y);
1231f0ac6a5Smrg
1241f0ac6a5Smrg	/* sort active list */
1251f0ac6a5Smrg	for (e = active; e; e = next)
1261f0ac6a5Smrg	{
1271f0ac6a5Smrg	    next = e->next;
1281f0ac6a5Smrg	    /*
1291f0ac6a5Smrg	     * Find one later in the list that belongs before the
1301f0ac6a5Smrg	     * current one
1311f0ac6a5Smrg	     */
1321f0ac6a5Smrg	    for (en = next; en; en = en->next)
1331f0ac6a5Smrg	    {
1341f0ac6a5Smrg		if (en->current_x < e->current_x ||
1351f0ac6a5Smrg		    (en->current_x == e->current_x &&
1361f0ac6a5Smrg		     en->edge.p2.x < e->edge.p2.x))
1371f0ac6a5Smrg		{
1381f0ac6a5Smrg		    /*
1391f0ac6a5Smrg		     * insert en before e
1401f0ac6a5Smrg		     *
1411f0ac6a5Smrg		     * extract en
1421f0ac6a5Smrg		     */
1431f0ac6a5Smrg		    en->prev->next = en->next;
1441f0ac6a5Smrg		    if (en->next)
1451f0ac6a5Smrg			en->next->prev = en->prev;
1461f0ac6a5Smrg		    /*
1471f0ac6a5Smrg		     * insert en
1481f0ac6a5Smrg		     */
1491f0ac6a5Smrg		    if (e->prev)
1501f0ac6a5Smrg			e->prev->next = en;
1511f0ac6a5Smrg		    else
1521f0ac6a5Smrg			active = en;
1531f0ac6a5Smrg		    en->prev = e->prev;
1541f0ac6a5Smrg		    e->prev = en;
1551f0ac6a5Smrg		    en->next = e;
1561f0ac6a5Smrg		    /*
1571f0ac6a5Smrg		     * start over at en
1581f0ac6a5Smrg		     */
1591f0ac6a5Smrg		    next = en;
1601f0ac6a5Smrg		    break;
1611f0ac6a5Smrg		}
1621f0ac6a5Smrg	    }
1631f0ac6a5Smrg	}
1641f0ac6a5Smrg#if 0
1651f0ac6a5Smrg	printf ("y: %6.3g:", y / 65536.0);
1661f0ac6a5Smrg	for (e = active; e; e = e->next)
1671f0ac6a5Smrg	{
1681f0ac6a5Smrg	    printf (" %6.3g", e->current_x / 65536.0);
1691f0ac6a5Smrg	}
1701f0ac6a5Smrg	printf ("\n");
1711f0ac6a5Smrg#endif
1721f0ac6a5Smrg	/* find next inflection point */
1731f0ac6a5Smrg	next_y = active->edge.p2.y;
1741f0ac6a5Smrg	for (e = active; e; e = en)
1751f0ac6a5Smrg	{
1761f0ac6a5Smrg	    if (e->edge.p2.y < next_y)
1771f0ac6a5Smrg		next_y = e->edge.p2.y;
1781f0ac6a5Smrg	    en = e->next;
1791f0ac6a5Smrg	    /* check intersect */
1801f0ac6a5Smrg	    if (en && e->edge.p2.x > en->edge.p2.x)
1811f0ac6a5Smrg	    {
1821f0ac6a5Smrg		intersect = XRenderComputeIntersect (&e->edge, &e->next->edge);
1831f0ac6a5Smrg		/* make sure this point is below the actual intersection */
1841f0ac6a5Smrg		intersect = intersect + 1;
1851f0ac6a5Smrg		if (intersect < next_y)
1861f0ac6a5Smrg		    next_y = intersect;
1871f0ac6a5Smrg	    }
1881f0ac6a5Smrg	}
1891f0ac6a5Smrg	/* check next inactive point */
1901f0ac6a5Smrg	if (inactive < nedges && edges[inactive].edge.p1.y < next_y)
1911f0ac6a5Smrg	    next_y = edges[inactive].edge.p1.y;
1921f0ac6a5Smrg
1931f0ac6a5Smrg	/* walk the list generating trapezoids */
1941f0ac6a5Smrg	for (e = active; e && (en = e->next); e = en->next)
1951f0ac6a5Smrg	{
1961f0ac6a5Smrg	    traps->top = y;
1971f0ac6a5Smrg	    traps->bottom = next_y;
1981f0ac6a5Smrg	    traps->left = e->edge;
1991f0ac6a5Smrg	    traps->right = en->edge;
2001f0ac6a5Smrg	    traps++;
2011f0ac6a5Smrg	    ntraps++;
2021f0ac6a5Smrg	}
2031f0ac6a5Smrg
2041f0ac6a5Smrg	y = next_y;
2051f0ac6a5Smrg
2061f0ac6a5Smrg	/* delete inactive edges from list */
2071f0ac6a5Smrg	for (e = active; e; e = next)
2081f0ac6a5Smrg	{
2091f0ac6a5Smrg	    next = e->next;
2101f0ac6a5Smrg	    if (e->edge.p2.y <= y)
2111f0ac6a5Smrg	    {
2121f0ac6a5Smrg		if (e->prev)
2131f0ac6a5Smrg		    e->prev->next = e->next;
2141f0ac6a5Smrg		else
2151f0ac6a5Smrg		    active = e->next;
2161f0ac6a5Smrg		if (e->next)
2171f0ac6a5Smrg		    e->next->prev = e->prev;
2181f0ac6a5Smrg	    }
2191f0ac6a5Smrg	}
2201f0ac6a5Smrg    }
2211f0ac6a5Smrg    return ntraps;
2221f0ac6a5Smrg}
2231f0ac6a5Smrg
2241f0ac6a5Smrgvoid
2251f0ac6a5SmrgXRenderCompositeDoublePoly (Display		    *dpy,
2261f0ac6a5Smrg			    int			    op,
2271f0ac6a5Smrg			    Picture		    src,
2281f0ac6a5Smrg			    Picture		    dst,
2291f0ac6a5Smrg			    _Xconst XRenderPictFormat	*maskFormat,
2301f0ac6a5Smrg			    int			    xSrc,
2311f0ac6a5Smrg			    int			    ySrc,
2321f0ac6a5Smrg			    int			    xDst,
2331f0ac6a5Smrg			    int			    yDst,
2341f0ac6a5Smrg			    _Xconst XPointDouble    *fpoints,
2351f0ac6a5Smrg			    int			    npoints,
2361f0ac6a5Smrg			    int			    winding)
2371f0ac6a5Smrg{
2381f0ac6a5Smrg    Edge	    *edges;
2391f0ac6a5Smrg    XTrapezoid	    *traps;
2401f0ac6a5Smrg    int		    i, nedges, ntraps;
2411f0ac6a5Smrg    XFixed	    x, y, prevx = 0, prevy = 0, firstx = 0, firsty = 0;
2421f0ac6a5Smrg    XFixed	    top = 0, bottom = 0;	/* GCCism */
2431f0ac6a5Smrg
2441f0ac6a5Smrg    edges = (Edge *) Xmalloc (npoints * sizeof (Edge) +
2451f0ac6a5Smrg			      (npoints * npoints * sizeof (XTrapezoid)));
2461f0ac6a5Smrg    if (!edges)
2471f0ac6a5Smrg	return;
2481f0ac6a5Smrg    traps = (XTrapezoid *) (edges + npoints);
2491f0ac6a5Smrg    nedges = 0;
2501f0ac6a5Smrg    for (i = 0; i <= npoints; i++)
2511f0ac6a5Smrg    {
2521f0ac6a5Smrg	if (i == npoints)
2531f0ac6a5Smrg	{
2541f0ac6a5Smrg	    x = firstx;
2551f0ac6a5Smrg	    y = firsty;
2561f0ac6a5Smrg	}
2571f0ac6a5Smrg	else
2581f0ac6a5Smrg	{
2591f0ac6a5Smrg	    x = XDoubleToFixed (fpoints[i].x);
2601f0ac6a5Smrg	    y = XDoubleToFixed (fpoints[i].y);
2611f0ac6a5Smrg	}
2621f0ac6a5Smrg	if (i)
2631f0ac6a5Smrg	{
2641f0ac6a5Smrg	    if (y < top)
2651f0ac6a5Smrg		top = y;
2661f0ac6a5Smrg	    else if (y > bottom)
2671f0ac6a5Smrg		bottom = y;
2681f0ac6a5Smrg	    if (prevy < y)
2691f0ac6a5Smrg	    {
2701f0ac6a5Smrg		edges[nedges].edge.p1.x = prevx;
2711f0ac6a5Smrg		edges[nedges].edge.p1.y = prevy;
2721f0ac6a5Smrg		edges[nedges].edge.p2.x = x;
2731f0ac6a5Smrg		edges[nedges].edge.p2.y = y;
2741f0ac6a5Smrg		edges[nedges].clockWise = True;
2751f0ac6a5Smrg		nedges++;
2761f0ac6a5Smrg	    }
2771f0ac6a5Smrg	    else if (prevy > y)
2781f0ac6a5Smrg	    {
2791f0ac6a5Smrg		edges[nedges].edge.p1.x = x;
2801f0ac6a5Smrg		edges[nedges].edge.p1.y = y;
2811f0ac6a5Smrg		edges[nedges].edge.p2.x = prevx;
2821f0ac6a5Smrg		edges[nedges].edge.p2.y = prevy;
2831f0ac6a5Smrg		edges[nedges].clockWise = False;
2841f0ac6a5Smrg		nedges++;
2851f0ac6a5Smrg	    }
2861f0ac6a5Smrg	    /* drop horizontal edges */
2871f0ac6a5Smrg	}
2881f0ac6a5Smrg	else
2891f0ac6a5Smrg	{
2901f0ac6a5Smrg	    top = y;
2911f0ac6a5Smrg	    bottom = y;
2921f0ac6a5Smrg	    firstx = x;
2931f0ac6a5Smrg	    firsty = y;
2941f0ac6a5Smrg	}
2951f0ac6a5Smrg	prevx = x;
2961f0ac6a5Smrg	prevy = y;
2971f0ac6a5Smrg    }
2981f0ac6a5Smrg    ntraps = XRenderComputeTrapezoids (edges, nedges, winding, traps);
2991f0ac6a5Smrg    /* XXX adjust xSrc/xDst */
3001f0ac6a5Smrg    XRenderCompositeTrapezoids (dpy, op, src, dst, maskFormat, xSrc, ySrc, traps, ntraps);
3011f0ac6a5Smrg    Xfree (edges);
3021f0ac6a5Smrg}
303