root/src/lib/polygon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __imlib_polygon_new
  2. __imlib_polygon_add_point
  3. __imlib_polygon_free
  4. __imlib_polygon_get_bounds
  5. __imlib_point_delta_from_line
  6. __imlib_segments_intersect
  7. __imlib_polygon_contains_point
  8. poly_value_sorter
  9. poly_edge_sorter
  10. __imlib_Polygon_DrawToData
  11. __imlib_Polygon_DrawToData_AA
  12. __imlib_Polygon_DrawToImage
  13. __imlib_Polygon_FillToData
  14. __imlib_Polygon_FillToData_AA
  15. __imlib_Polygon_FillToImage

#include "common.h"
#include "colormod.h"
#include "image.h"
#include "blend.h"
#include "span.h"
#include "updates.h"
#include "rgbadraw.h"

ImlibPoly
__imlib_polygon_new()
{
   ImlibPoly           poly;

   poly = malloc(sizeof(_ImlibPoly));
   if (!poly)
      return NULL;
   memset(poly, 0, sizeof(_ImlibPoly));
   return poly;
}

void
__imlib_polygon_add_point(ImlibPoly poly, int x, int y)
{
   if (!poly->points)
     {
        poly->points = (ImlibPoint *) malloc(sizeof(ImlibPoint));
        if (!poly->points)
           return;

        poly->pointcount++;
        poly->lx = poly->rx = x;
        poly->ty = poly->by = y;
     }
   else
     {
        poly->pointcount++;
        poly->points =
           (ImlibPoint *) realloc(poly->points,
                                  (poly->pointcount * sizeof(ImlibPoint)));

        if (!poly->points)
          {
             poly->pointcount = 0;
             return;
          }

        if (x < poly->lx)
           poly->lx = x;
        if (poly->rx < x)
           poly->rx = x;
        if (y < poly->ty)
           poly->ty = y;
        if (poly->by < y)
           poly->by = y;
     }

   poly->points[poly->pointcount - 1].x = x;
   poly->points[poly->pointcount - 1].y = y;
}

void
__imlib_polygon_free(ImlibPoly poly)
{
   if (poly->points)
      free(poly->points);
   free(poly);
}

#define TRUE 1
#define FALSE 0

/* Check if p lies on segment [ s1, s2 ] given that
      it lies on the line defined by s1 and s2. */
#define __imlib_point_inside_segment(p_x, p_y, s1_x, s1_y, s2_x,s2_y) \
(s1_y != s2_y) ? (p_y <= MAX(s1_y, s2_y) && p_y >= MIN(s1_y, s2_y)) : (p_x <= MAX(s1_x, s2_x) && p_x >= MIN(s1_x, s2_x))

#define __imlib_point_on_segment(p_x, p_y, s1_x, s1_y, s2_x, s2_y) \
__imlib_segments_intersect(p_x, p_y, p_x, p_y, s1_x, s1_y, s2_x, s2_y)

void
__imlib_polygon_get_bounds(ImlibPoly poly, int *px1, int *py1, int *px2,
                           int *py2)
{
   if (!poly || !poly->points || (poly->pointcount < 1))
      return;

   if (px1)
      *px1 = poly->lx;
   if (py1)
      *py1 = poly->ty;
   if (px2)
      *px2 = poly->rx;
   if (py2)
      *py2 = poly->by;
}

static double
__imlib_point_delta_from_line(int p_x, int p_y, int s1_x, int s1_y, int s2_x,
                              int s2_y)
{
   if (s2_x - s1_x == 0.0)
      return p_x - s1_x;
   else
     {
        double              m = (double)(s2_y - s1_y) / (double)(s2_x - s1_x);

        return (p_y - s1_y - (double)(p_x - s1_x) * m);
     }
}

static unsigned char
__imlib_segments_intersect(int r1_x, int r1_y, int r2_x, int r2_y, int s1_x,
                           int s1_y, int s2_x, int s2_y)
{
   double              testS1R =
      __imlib_point_delta_from_line(s1_x, s1_y, r1_x, r1_y, r2_x, r2_y);
   double              testS2R =
      __imlib_point_delta_from_line(s2_x, s2_y, r1_x, r1_y, r2_x, r2_y);
   double              testR1S =
      __imlib_point_delta_from_line(r1_x, r1_y, s1_x, s1_y, s2_x, s2_y);
   double              testR2S =
      __imlib_point_delta_from_line(r2_x, r2_y, s1_x, s1_y, s2_x, s2_y);

   /* check if segments are collinear */
   if (testS1R == 0.0 && testS2R == 0.0)
     {
        if (__imlib_point_inside_segment(s1_x, s1_y, r1_x, r1_y, r2_x, r2_y)
            || __imlib_point_inside_segment(s2_x, s2_y, r1_x, r1_y, r2_x, r2_y)
            || __imlib_point_inside_segment(r1_x, r1_y, s1_x, s1_y, s2_x, s2_y)
            || __imlib_point_inside_segment(r2_x, r2_y, s1_x, s1_y, s2_x, s2_y))
           return TRUE;
        else
           return FALSE;
     }

   if (testS1R * testS2R <= 0.0 && testR1S * testR2S <= 0.0)
      return TRUE;
   else
      return FALSE;
}

unsigned char
__imlib_polygon_contains_point(ImlibPoly poly, int x, int y)
{
   int                 count = 0;
   int                 start = 0;
   int                 ysave = 0;       /* initial value arbitrary */
   int                 cx, nx, out_x, out_y, i, n;
   int                 curr_x, curr_y, next_x, next_y;

   /* find a vertex of poly that does not lie on the test line */
   while (start < poly->pointcount && poly->points[start].y == y)
      start++;
   /* if one doesn't exist we will use point on segment test
    * and can start with vertex 0 anyway */
   cx = start % poly->pointcount;

   out_x = poly->points[0].x;
   out_y = y;

   for (i = 1; i < poly->pointcount; i++)
     {
        out_x = MAX(out_x, poly->points[i].x);
     }
   out_x++;                     /* out now guaranteed to be outside poly */

   for (n = 0; n < poly->pointcount; n++)
     {
        nx = (cx + 1) % poly->pointcount;

        curr_x = poly->points[cx].x;
        curr_y = poly->points[cx].y;
        next_x = poly->points[nx].x;
        next_y = poly->points[nx].y;

        if (__imlib_point_on_segment(x, y, curr_x, curr_y, next_x, next_y))
           return TRUE;

        /* ignore horizontal segments from this point on */
        if (poly->points[cx].y != poly->points[nx].y)
          {
             if (__imlib_segments_intersect
                 (curr_x, curr_y, next_x, next_y, x, y, out_x, out_y))
               {
                  count++;

                  if (__imlib_point_on_segment
                      (next_x, next_y, x, y, out_x, out_y))
                    {
                       /* current seg intersects test seg @ 2nd vtx
                        * reset ysave */
                       ysave = curr_y;
                    }
                  if (__imlib_point_on_segment
                      (curr_x, curr_y, x, y, out_x, out_y)
                      && ((ysave < y) != (next_y < y)))
                    {
                       /* current seg xsects test seg @ 1st vtx and
                        * ysave on opposite side of test line from
                        * curr seg 2nd vtx;
                        * decrement hits (2-1) for odd parity */
                       count--;
                    }
               }
          }
        cx = nx;
     }
   return (count % 2 == 1);
}

/** Polygon Drawing and Filling **/

#define STEEP_EDGE      0
#define SHALLOW_EDGE    1
#define HORZ_EDGE       2

typedef struct _PolyEdge PolyEdge;
typedef struct _IndexedValue IndexedValue;

struct _PolyEdge {
   int                 type;
   int                 xx;
   int                 dxx, dyy;
   ImlibPoint         *v0, *v1;
   int                 index;
};

struct _IndexedValue {
   int                 val;
   int                 index;
};

static int
poly_value_sorter(const void *a, const void *b)
{
   IndexedValue       *p, *q;

   p = (IndexedValue *) a;
   q = (IndexedValue *) b;
   if (p->val <= q->val)
      return -1;
   return 1;
}

static int
poly_edge_sorter(const void *a, const void *b)
{
   PolyEdge           *p, *q;

   p = (PolyEdge *) a;
   q = (PolyEdge *) b;
   if (p->xx < q->xx)
      return -1;
   if (p->xx > q->xx)
      return 1;
   if (p->dxx <= q->dxx)
      return -1;
   return 1;
}

/* general macros */

#define DEL_EDGE(j)             \
do {                                                                    \
   int m;                                                               \
   for (m = 0; (m < nactive_edges) && (edge[m].index != (j)); m++);     \
                                                                        \
   if (m < nactive_edges)                                               \
     {                                                                  \
        if (edge[m].type == HORZ_EDGE) nactive_horz_edges--;            \
        nactive_edges--;                                                \
        memmove(edge + m, edge + m + 1,                                 \
              (nactive_edges - m) * sizeof(PolyEdge));                  \
     }                                                                  \
} while (0)

#define DEL_HORZ_EDGES()                \
do {                                                                    \
   int m = 0;                                                           \
                                                                        \
   while (m < nactive_edges)                                            \
     {                                                                  \
        if (edge[m].type == HORZ_EDGE)                                  \
          {                                                             \
            nactive_edges--;                                            \
            memmove(edge + m, edge + m + 1,                             \
              (nactive_edges - m) * sizeof(PolyEdge));                  \
            m--;                                                        \
          }                                                             \
        m++;                                                            \
     }                                                                  \
   nactive_horz_edges = 0;                                              \
} while (0)

#define ADD_EDGE(i)             \
do {                                                                    \
    int m;                                                              \
                                                                        \
    for (m = 0; (m < nactive_edges) && (edge[m].index != i); m++);      \
                                                                        \
    if ((m == nactive_edges) && (i < nvertices) &&                      \
        (nactive_edges < (nvertices - 1)))                              \
      {                                                                 \
        ImlibPoint *v0, *v1, *w;                                        \
        PolyEdge *ne;                                                   \
        int  dx, dy;                                                    \
                                                                        \
        if (i < (nvertices - 1))  m = i + 1;                            \
        else  m = 0;                                                    \
                                                                        \
        v0 = (poly->points) + i;                                        \
        v1 = (poly->points) + m;                                        \
        if ((v1->y) < (v0->y))                                          \
          {                                                             \
            w = v0;                                                     \
            v0 = v1;                                                    \
            v1 = w;                                                     \
          }                                                             \
                                                                        \
        dx = (v1->x) - (v0->x);                                         \
        dy = (v1->y) - (v0->y);                                         \
        ne = edge + nactive_edges;                                      \
        ne->index = i;                                                  \
        if (dy == 0)                                                    \
          {                                                             \
            ne->type = HORZ_EDGE;                                       \
            ne->dxx = 0;                                                \
            if ((v1->x) < (v0->x))                                      \
              {                                                         \
                w = v0;                                                 \
                v0 = v1;                                                \
                v1 = w;                                                 \
              }                                                         \
            ne->xx = (v0->x) << 16;                                     \
            nactive_horz_edges++;                                       \
          }                                                             \
        else                                                            \
          {                                                             \
            ne->type = STEEP_EDGE;                                      \
            ne->dxx = ((dx << 16) / dy);                                \
            ne->xx = ((ne->dxx) * (y - (v0->y))) + ((v0->x) << 16);     \
            if ((dy < dx) || (dy < (-dx)))                              \
              {                                                         \
                ne->type = SHALLOW_EDGE;                                \
                ne->dyy = ((dy << 16) / dx);                            \
              }                                                         \
          }                                                             \
        ne->v0 = v0;                                                    \
        ne->v1 = v1;                                                    \
        nactive_edges++;                                                \
      }                                                                 \
} while (0)

#define GET_EDGE_RANGE(e, elx, erx)   \
do { \
   switch(e->type)                                                      \
   {                                                                    \
    case SHALLOW_EDGE:                                                  \
     {                                                                  \
        elx = (e->xx - (2 * e->dxx)) >> 16;                             \
        erx = (e->xx + (2 * e->dxx)) >> 16;                             \
        if (e->dxx < 0)                                                 \
          { lx = elx; elx = erx; erx = lx; }                            \
        break;                                                          \
     }                                                                  \
    case STEEP_EDGE:                                                    \
      {                                                                 \
        lx = (e->xx >> 16);                                             \
        elx = erx = lx;                                                 \
        break;                                                          \
      }                                                                 \
    case HORZ_EDGE:                                                     \
      {                                                                 \
        elx = e->v0->x;                                                 \
        erx = e->v1->x;                                                 \
        break;                                                          \
      }                                                                 \
    default:                                                            \
      break;                                                            \
   }                                                                    \
} while (0)

#define CLIP_SPAN(lx, rx, clx, clrx)     \
do { \
   if (lx < (clx)) lx = (clx);           \
   if (rx > (clrx)) rx = (clrx);         \
} while (0)

#define BLEND_ALPHA(dst, a, tmp) \
do { \
   if (*dst)                                    \
     {                                          \
       tmp = ((a) * (255 - (*(dst)))) + 0x80;   \
       *(dst) += ((tmp + (tmp >> 8)) >> 8);     \
     }                                          \
   else                                         \
       *(dst) = (a);                            \
} while (0)

/* initializing macro used in drawing/filling functions */

#define INIT_POLY()             \
do { \
   sfunc = __imlib_GetShapedSpanDrawFunction(op, dst_alpha, blend);     \
   if (!sfunc)  return;                                                 \
                                                                        \
   nvertices = poly->pointcount;                                        \
   if (nvertices < 1) return;                                           \
                                                                        \
   clrx = clx + clw - 1;                                                \
   clby = cly + clh - 1;                                                \
                                                                        \
   CLIP_SPAN(clx, clrx, poly->lx, a_a + poly->rx);                      \
   if (clrx < clx) return;                                              \
                                                                        \
   CLIP_SPAN(cly, clby, poly->ty, poly->by);                            \
   if (clby < cly) return;                                              \
                                                                        \
   clw = clrx - clx + 1;                                                \
   clh = clby - cly + 1;                                                \
                                                                        \
   edge = (PolyEdge *)malloc(nvertices * sizeof(PolyEdge));             \
   if (!edge) return;                                                   \
                                                                        \
   ysort = (IndexedValue *)malloc(nvertices * sizeof(IndexedValue));    \
   if (!ysort) { free(edge); return; }                                  \
                                                                        \
   s0 = (DATA8 *)malloc(clw * sizeof(DATA8));                           \
   if (!s0) { free(edge); free(ysort); return; }                        \
                                                                        \
   s1 = (DATA8 *)malloc(clw * sizeof(DATA8));                           \
   if (!s1) { free(edge); free(ysort); free(s0); return; }              \
                                                                        \
   memset(s0,0,clw);                                                    \
                                                                        \
   k = 0;                                                               \
   while (k < nvertices)                                                \
     {                                                                  \
        ysort[k].val = poly->points[k].y;                               \
        ysort[k].index = k;                                             \
        k++;                                                            \
     }                                                                  \
                                                                        \
   qsort(ysort, nvertices, sizeof(IndexedValue), poly_value_sorter);    \
                                                                        \
   s0 -= clx;                                                           \
   s1 -= clx;                                                           \
                                                                        \
   x0 = clx;                                                            \
   x1 = clrx;                                                           \
                                                                        \
   nx0 = clrx + 1;                                                      \
   nx1 = clx - 1;                                                       \
                                                                        \
   if (cly > poly->ty)                                                  \
      ty = cly - 1;                                                     \
   else                                                                 \
      ty = cly;                                                         \
   by = clby;                                                           \
                                                                        \
   p = dst + (dstw * ty);                                               \
   k = 0;                                                               \
   nactive_edges = 0;                                                   \
   nactive_horz_edges = 0;                                              \
   y = ty;                                                              \
} while (0)

#define DE_INIT_POLY()  \
do { \
   free(edge);        \
   free(ysort);       \
   s0 += clx;         \
   free(s0);          \
   s1 += clx;         \
   free(s1);          \
} while (0)

/** Polygon Drawing **/

/* aliased drawing */
/* draws the poly-line defined by the sequence of vertices */

static void
__imlib_Polygon_DrawToData(ImlibPoly poly, char close, DATA32 color,
                           DATA32 * dst, int dstw,
                           int clx, int cly, int clw, int clh,
                           ImlibOp op, char dst_alpha, char blend)
{
   ImlibShapedSpanDrawFunction sfunc;
   IndexedValue       *ysort;
   PolyEdge           *edge;
   int                 k, a_a = 0;
   int                 nactive_edges, nactive_horz_edges, nvertices;
   int                 clrx, clby, ty, by, y;
   int                 x0, x1, nx0, nx1;
   DATA32             *p;
   DATA8              *s0, *s1, *ps;

   INIT_POLY();

   while (y <= by)
     {
        int                 j;

        while ((k < nvertices) && (poly->points[ysort[k].index].y <= y))
          {
             int                 i = ysort[k].index;

             j = i - 1;
             if (close && (i == 0))
                j = nvertices - 1;

             if (j >= 0)
               {
                  if (poly->points[j].y < y)
                     DEL_EDGE(j);
                  else
                     ADD_EDGE(j);
               }

             j = i + 1;
             if (close && (i == (nvertices - 1)))
                j = 0;

             if (j < nvertices)
               {
                  if (poly->points[j].y < y)
                     DEL_EDGE(i);
                  else
                     ADD_EDGE(i);
               }

             k++;
          }

        /* not really needed, but... */
        qsort(edge, nactive_edges, sizeof(PolyEdge), poly_edge_sorter);

        /* clear alpha buffer */
        if (x0 <= x1)
           memset(s1 + x0, 0, x1 - x0 + 1);

        x0 = nx0;
        x1 = nx1;
        nx0 = clrx + 1;
        nx1 = clx - 1;

        /* draw to alpha buffer */
        j = 0;
        while (j < nactive_edges)
          {
             int                 lx, rx;
             int                 e_lx, e_rx;
             PolyEdge           *e;

             e = edge + j;

             GET_EDGE_RANGE(e, e_lx, e_rx);
             if ((e_lx < e->v0->x) && (e->dxx > 0))
                e_lx = e->v0->x;
             if ((e_rx > e->v0->x) && (e->dxx < 0))
                e_rx = e->v0->x;

             /* draw edge */
             switch (e->type)
               {
               case STEEP_EDGE:
                  {
                     lx = e_lx;
                     lx += (e->xx - (lx << 16)) >> 15;
                     if (IN_SEGMENT(lx, clx, clw))
                       {
                          *(s0 + lx) = 255;
                          if (lx < x0)
                             x0 = lx;
                          if (lx > x1)
                             x1 = lx;
                       }

                     if ((e->v1->y == (y + 1)) && (y < clby))
                       {
                          lx = e->v1->x;
                          if (IN_SEGMENT(lx, clx, clw))
                            {
                               *(s1 + lx) = 255;
                               if (lx < nx0)
                                  nx0 = lx;
                               if (lx > nx1)
                                  nx1 = lx;
                            }
                       }
                     break;
                  }
               case SHALLOW_EDGE:
                  {
                     int                 x, ey, eyy;

                     if (e->dyy > 0)
                        x = e_lx;
                     else
                        x = e_rx;

                     eyy = ((e->v0->y) << 16) + (x - (e->v0->x)) * (e->dyy);
                     ey = eyy >> 16;
                     ey += (eyy - (ey << 16)) >> 15;

                     if (e->dyy > 0)
                       {
                          if (x < x0)
                             x0 = x;
                          while (ey <= y)
                            {
                               if ((ey == y) && IN_SEGMENT(x, clx, clw))
                                  *(s0 + x) = 255;
                               eyy += e->dyy;
                               ey = eyy >> 16;
                               ey += (eyy - (ey << 16)) >> 15;
                               x++;
                            }
                          if (x > x1)
                             x1 = x;

                          if (((y + 1) == e->v1->y) && (y < clby))
                            {
                               if (x < nx0)
                                  nx0 = x;
                               rx = e->v1->x;
                               while ((ey == (y + 1)) && (x <= rx))
                                 {
                                    if (IN_SEGMENT(x, clx, clw))
                                       *(s1 + x) = 255;
                                    eyy += e->dyy;
                                    ey = eyy >> 16;
                                    ey += (eyy - (ey << 16)) >> 15;
                                    x++;
                                 }
                               if (x > nx1)
                                  nx1 = x;
                            }
                          break;
                       }

                     if (x > x1)
                        x1 = x;
                     while (ey <= y)
                       {
                          if ((ey == y) && IN_SEGMENT(x, clx, clw))
                             *(s0 + x) = 255;
                          eyy -= e->dyy;
                          ey = eyy >> 16;
                          ey += (eyy - (ey << 16)) >> 15;
                          x--;
                       }
                     if (x < x0)
                        x0 = x;

                     if (((y + 1) == e->v1->y) && (y < clby))
                       {
                          if (x > nx1)
                             nx1 = x;
                          lx = e->v1->x;
                          while ((ey == (y + 1)) && (x >= lx))
                            {
                               if (IN_SEGMENT(x, clx, clw))
                                  *(s1 + x) = 255;
                               eyy -= e->dyy;
                               ey = eyy >> 16;
                               ey += (eyy - (ey << 16)) >> 15;
                               x--;
                            }
                          if (x < nx0)
                             nx0 = x;
                       }
                     break;
                  }
               case HORZ_EDGE:
                  {
                     lx = e_lx;
                     rx = e_rx;
                     CLIP_SPAN(lx, rx, clx, clrx);
                     if (lx <= rx)
                       {
                          memset(s0 + lx, 255, rx - lx + 1);
                          if (lx < x0)
                             x0 = lx;
                          if (rx > x1)
                             x1 = rx;
                       }
                     break;
                  }

               default:
                  break;
               }

             e->xx += e->dxx;
             j++;
          }

        if (nactive_horz_edges > 0)
           DEL_HORZ_EDGES();

        /* draw alpha buffer to dst */
        CLIP_SPAN(x0, x1, clx, clrx);
        if ((x0 <= x1) && (y >= cly))
           sfunc(s0 + x0, color, p + x0, x1 - x0 + 1);

        /* exchange alpha buffers */
        ps = s0;
        s0 = s1;
        s1 = ps;

        y++;
        p += dstw;
     }

   DE_INIT_POLY();
}

/* anti-aliased drawing */

static void
__imlib_Polygon_DrawToData_AA(ImlibPoly poly, char close, DATA32 color,
                              DATA32 * dst, int dstw,
                              int clx, int cly, int clw, int clh,
                              ImlibOp op, char dst_alpha, char blend)
{
   ImlibShapedSpanDrawFunction sfunc;
   IndexedValue       *ysort;
   PolyEdge           *edge;
   int                 k, a_a = 1;
   int                 nactive_edges, nactive_horz_edges, nvertices;
   int                 clrx, clby, ty, by, y, yy, prev_y, prev_yy;
   int                 x0, x1, nx0, nx1;
   DATA32             *p;
   DATA8              *s0, *s1, *ps;

   INIT_POLY();

   yy = y << 16;
   prev_y = y - 1;
   prev_yy = prev_y << 16;

   while (y <= by)
     {
        int                 j;

        while ((k < nvertices) && (poly->points[ysort[k].index].y <= y))
          {
             int                 i = ysort[k].index;

             j = i - 1;
             if (close && (i == 0))
                j = nvertices - 1;

             if (j >= 0)
               {
                  if (poly->points[j].y < y)
                     DEL_EDGE(j);
                  else
                     ADD_EDGE(j);
               }

             j = i + 1;
             if (close && (i == (nvertices - 1)))
                j = 0;

             if (j < nvertices)
               {
                  if (poly->points[j].y <= y)
                     DEL_EDGE(i);
                  else
                     ADD_EDGE(i);
               }

             k++;
          }

        /* not really needed, but... */
        qsort(edge, nactive_edges, sizeof(PolyEdge), poly_edge_sorter);

        /* clear alpha buffer */
        if (x0 <= x1)
           memset(s1 + x0, 0, x1 - x0 + 1);

        x0 = nx0;
        x1 = nx1;
        nx0 = clrx + 1;
        nx1 = clx - 1;

        /* draw to alpha buffer */
        j = 0;
        while (j < nactive_edges)
          {
             int                 lx, rx;
             int                 e_lx, e_rx;
             PolyEdge           *e;

             e = edge + j;

             GET_EDGE_RANGE(e, e_lx, e_rx);
             if ((e_lx < e->v0->x) && (e->dxx > 0))
                e_lx = e->v0->x;
             if ((e_rx > e->v0->x) && (e->dxx < 0))
                e_rx = e->v0->x;

             /* draw aa edge */
             switch (e->type)
               {
               case STEEP_EDGE:
                  {
                     DATA32              tmp;
                     DATA8               aa;

                     aa = (e->xx - (e_lx << 16)) >> 8;
                     rx = e_lx + 1;
                     if (IN_SEGMENT(rx, clx, clw))
                       {
                          ps = s0 + rx;
                          BLEND_ALPHA(ps, aa, tmp);
                          if (rx > x1)
                             x1 = rx;
                       }
                     if (IN_SEGMENT(e_lx, clx, clw))
                       {
                          aa = 255 - aa;
                          ps = s0 + e_lx;
                          BLEND_ALPHA(ps, aa, tmp);
                          if (e_lx < x0)
                             x0 = e_lx;
                       }

                     if ((e->v1->y == (y + 1)) && (y < clby))
                       {
                          lx = (e->xx + e->dxx) >> 16;
                          aa = ((e->xx + e->dxx - (lx << 16)) >> 8);
                          rx = lx + 1;
                          if (IN_SEGMENT(rx, clx, clw))
                            {
                               ps = s1 + rx;
                               BLEND_ALPHA(ps, aa, tmp);
                               if (rx > nx1)
                                  nx1 = rx;
                            }
                          if (IN_SEGMENT(lx, clx, clw))
                            {
                               aa = 255 - aa;
                               ps = s1 + lx;
                               BLEND_ALPHA(ps, aa, tmp);
                               if (lx < nx0)
                                  nx0 = lx;
                            }
                       }
                     break;
                  }
               case SHALLOW_EDGE:
                  {
                     int                 x, ey, eyy;

                     if (e->dyy > 0)
                        x = e_lx;
                     else
                        x = e_rx;

                     eyy = ((e->v0->y) << 16) + (x - (e->v0->x)) * (e->dyy);
                     ey = eyy >> 16;

                     if (e->dyy > 0)
                       {
                          if (x < x0)
                             x0 = x;
                          while (ey < y)
                            {
                               DATA32              tmp;
                               DATA8               aa;

                               if ((ey == prev_y) && IN_SEGMENT(x, clx, clw))
                                 {
                                    aa = ((eyy - prev_yy) >> 8);
                                    ps = s0 + x;
                                    BLEND_ALPHA(ps, aa, tmp);
                                 }
                               eyy += e->dyy;
                               ey = eyy >> 16;
                               x++;
                            }
                          lx = x;
                          while (ey == y)
                            {
                               DATA32              tmp;
                               DATA8               aa;

                               if (IN_SEGMENT(x, clx, clw))
                                 {
                                    aa = 255 - ((eyy - yy) >> 8);
                                    ps = s0 + x;
                                    BLEND_ALPHA(ps, aa, tmp);
                                 }
                               eyy += e->dyy;
                               ey = eyy >> 16;
                               x++;
                            }
                          if (x > x1)
                             x1 = x;

                          if (((y + 1) == e->v1->y) && (y < clby))
                            {
                               x = lx;
                               if (x < nx0)
                                  nx0 = x;
                               rx = e->v1->x;
                               eyy =
                                  ((e->v0->y) << 16) + (x -
                                                        (e->v0->x)) * (e->dyy);
                               ey = eyy >> 16;
                               while ((ey == y) && (x <= rx))
                                 {
                                    DATA32              tmp;
                                    DATA8               aa;

                                    if (IN_SEGMENT(x, clx, clw))
                                      {
                                         aa = ((eyy - yy) >> 8);
                                         ps = s1 + x;
                                         BLEND_ALPHA(ps, aa, tmp);
                                      }
                                    eyy += e->dyy;
                                    ey = eyy >> 16;
                                    x++;
                                 }
                               if (x > nx1)
                                  nx1 = x;
                            }
                          break;
                       }

                     if (x > x1)
                        x1 = x;
                     while (ey < y)
                       {
                          DATA32              tmp;
                          DATA8               aa;

                          if ((ey == prev_y) && IN_SEGMENT(x, clx, clw))
                            {
                               aa = ((eyy - prev_yy) >> 8);
                               ps = s0 + x;
                               BLEND_ALPHA(ps, aa, tmp);
                            }
                          eyy -= e->dyy;
                          ey = eyy >> 16;
                          x--;
                       }
                     rx = x;
                     while (ey == y)
                       {
                          DATA32              tmp;
                          DATA8               aa;

                          if (IN_SEGMENT(x, clx, clw))
                            {
                               aa = 255 - ((eyy - yy) >> 8);
                               ps = s0 + x;
                               BLEND_ALPHA(ps, aa, tmp);
                            }
                          eyy -= e->dyy;
                          ey = eyy >> 16;
                          x--;
                       }
                     if (x < x0)
                        x0 = x;

                     if (((y + 1) == e->v1->y) && (y < clby))
                       {
                          x = rx;
                          if (x > nx1)
                             nx1 = x;
                          lx = e->v1->x;
                          eyy =
                             ((e->v0->y) << 16) + (x - (e->v0->x)) * (e->dyy);
                          ey = eyy >> 16;
                          while ((ey == y) && (x >= lx))
                            {
                               DATA32              tmp;
                               DATA8               aa;

                               if (IN_SEGMENT(x, clx, clw))
                                 {
                                    aa = ((eyy - yy) >> 8);
                                    ps = s1 + x;
                                    BLEND_ALPHA(ps, aa, tmp);
                                 }
                               eyy -= e->dyy;
                               ey = eyy >> 16;
                               x--;
                            }
                          if (x < nx0)
                             nx0 = x;
                       }
                     break;
                  }
               case HORZ_EDGE:
                  {
                     lx = e_lx;
                     rx = e_rx;
                     CLIP_SPAN(lx, rx, clx, clrx);
                     if (lx <= rx)
                       {
                          memset(s0 + lx, 255, rx - lx + 1);
                          if (lx < x0)
                             x0 = lx;
                          if (rx > x1)
                             x1 = rx;
                       }
                     break;
                  }

               default:
                  break;
               }

             e->xx += e->dxx;
             j++;
          }

        if (nactive_horz_edges > 0)
           DEL_HORZ_EDGES();

        /* draw alpha buffer to dst */
        CLIP_SPAN(x0, x1, clx, clrx);
        if ((x0 <= x1) && (y >= cly))
           sfunc(s0 + x0, color, p + x0, x1 - x0 + 1);

        /* exchange alpha buffers */
        ps = s0;
        s0 = s1;
        s1 = ps;

        prev_yy = yy;
        prev_y = y;

        y++;
        yy = y << 16;

        p += dstw;
     }

   DE_INIT_POLY();
}

void
__imlib_Polygon_DrawToImage(ImlibPoly poly, char close, DATA32 color,
                            ImlibImage * im, int clx, int cly, int clw, int clh,
                            ImlibOp op, char blend, char anti_alias)
{
   if ((!poly) || (!poly->points) || (poly->pointcount < 1) || (clw < 0))
      return;
   if (blend && (!A_VAL(&color)))
      return;
   if (poly->pointcount == 1)
     {
        (void)__imlib_Point_DrawToImage(poly->points[0].x, poly->points[0].y,
                                        color, im, clx, cly, clw, clh, op,
                                        blend, 0);
        return;
     }
   if (poly->pointcount == 2)
     {
        (void)__imlib_Line_DrawToImage(poly->points[0].x, poly->points[0].y,
                                       poly->points[1].x, poly->points[1].y,
                                       color, im, clx, cly, clw, clh, op, blend,
                                       anti_alias, 0);
        return;
     }

   if (clw == 0)
     {
        clw = im->w;
        clx = 0;
        clh = im->h;
        cly = 0;
     }

   CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h);
   if ((clw < 1) || (clh < 1))
      return;

   if (blend && IMAGE_HAS_ALPHA(im))
      __imlib_build_pow_lut();

   if (anti_alias)
      __imlib_Polygon_DrawToData_AA(poly, close, color,
                                    im->data, im->w,
                                    clx, cly, clw, clh,
                                    op, IMAGE_HAS_ALPHA(im), blend);
   else
      __imlib_Polygon_DrawToData(poly, close, color,
                                 im->data, im->w,
                                 clx, cly, clw, clh,
                                 op, IMAGE_HAS_ALPHA(im), blend);
}

/** Polygon Filling **/

/* aliased filling */

static void
__imlib_Polygon_FillToData(ImlibPoly poly, DATA32 color,
                           DATA32 * dst, int dstw,
                           int clx, int cly, int clw, int clh,
                           ImlibOp op, char dst_alpha, char blend)
{
   ImlibShapedSpanDrawFunction sfunc;
   IndexedValue       *ysort;
   PolyEdge           *edge;
   int                 k, a_a = 0;
   int                 nactive_edges, nactive_horz_edges, nvertices;
   int                 clrx, clby, ty, by, y;
   int                 x0, x1, nx0, nx1;
   DATA32             *p;
   DATA8              *s0, *s1, *ps;

   INIT_POLY();

   while (y <= by)
     {
        int                 j;

        while ((k < nvertices) && (poly->points[ysort[k].index].y <= y))
          {
             int                 i = ysort[k].index;

             if (i > 0)
                j = i - 1;
             else
                j = nvertices - 1;

             if (poly->points[j].y < y)
                DEL_EDGE(j);
             else
                ADD_EDGE(j);

             if (i < (nvertices - 1))
                j = i + 1;
             else
                j = 0;

             if (poly->points[j].y < y)
                DEL_EDGE(i);
             else
                ADD_EDGE(i);

             k++;
          }

        qsort(edge, nactive_edges, sizeof(PolyEdge), poly_edge_sorter);

        /* clear alpha buffer */
        if (x0 <= x1)
           memset(s1 + x0, 0, x1 - x0 + 1);

        x0 = nx0;
        x1 = nx1;
        nx0 = clrx + 1;
        nx1 = clx - 1;

        /* draw to alpha buffer */
        j = 0;
        while (j < nactive_edges)
          {
             int                 lx, rx;
             int                 le_lx, le_rx;
             int                 re_lx, re_rx;
             PolyEdge           *le, *re;

             if (j < (nactive_edges - 1))
               {
                  le = edge + j;
                  re = le + 1;
               }
             else if (j > 0)
               {
                  le = edge + (j - 1);
                  le->xx -= le->dxx;
                  re = le + 1;
               }
             else
               {
                  re = le = edge;
               }

             GET_EDGE_RANGE(le, le_lx, le_rx);
             if ((le_lx < le->v0->x) && (le->dxx > 0))
                le_lx = le->v0->x;
             GET_EDGE_RANGE(re, re_lx, re_rx);
             if ((re_rx > re->v0->x) && (re->dxx < 0))
                re_rx = re->v0->x;

             /* draw left edge */
             switch (le->type)
               {
               case STEEP_EDGE:
                  {
                     le_rx += (le->xx - (le_rx << 16)) >> 15;
                     if (le_rx < x0)
                        x0 = le_rx;

                     if ((le->v1->y == (y + 1)) && (y < clby))
                       {
                          lx = le->v1->x;
                          if (IN_SEGMENT(lx, clx, clw))
                            {
                               *(s1 + lx) = 255;
                               if (lx < nx0)
                                  nx0 = lx;
                            }
                       }
                     break;
                  }
               case SHALLOW_EDGE:
                  {
                     int                 x, ey, eyy;

                     x = le_lx;
                     eyy = ((le->v0->y) << 16) + (x - (le->v0->x)) * (le->dyy);
                     ey = eyy >> 16;
                     ey += (eyy - (ey << 16)) >> 15;

                     if (le->dyy > 0)
                       {
                          while (ey < y)
                            {
                               eyy += le->dyy;
                               ey = eyy >> 16;
                               ey += (eyy - (ey << 16)) >> 15;
                               x++;
                            }
                          le_rx = x;
                          if (x < x0)
                             x0 = x;

                          if (((y + 1) == le->v1->y) && (y < clby))
                            {
                               if (x < nx0)
                                  nx0 = x;
                               rx = le->v1->x;
                               while ((ey <= (y + 1)) && (x <= rx))
                                 {
                                    if ((ey == (y + 1))
                                        && IN_SEGMENT(x, clx, clw))
                                       *(s1 + x) = 255;
                                    eyy += le->dyy;
                                    ey = eyy >> 16;
                                    ey += (eyy - (ey << 16)) >> 15;
                                    x++;
                                 }
                               if (x > nx1)
                                  nx1 = x;
                            }
                          break;
                       }

                     while (ey > y)
                       {
                          eyy += le->dyy;
                          ey = eyy >> 16;
                          ey += (eyy - (ey << 16)) >> 15;
                          x++;
                       }
                     le_rx = x;
                     if (x < x0)
                        x0 = x;
                     break;
                  }
               case HORZ_EDGE:
                  {
                     lx = le_lx;
                     rx = le_rx;
                     CLIP_SPAN(lx, rx, clx, clrx);
                     if (lx <= rx)
                       {
                          memset(s0 + lx, 255, rx - lx + 1);
                          if (lx < x0)
                             x0 = lx;
                       }
                     le_rx++;
                     break;
                  }

               default:
                  break;
               }

             /* draw right edge */
             switch (re->type)
               {
               case STEEP_EDGE:
                  {
                     re_lx += (re->xx - (re_lx << 16)) >> 15;
                     if (re_lx > x1)
                        x1 = re_lx;

                     if ((re->v1->y == (y + 1)) && (y < clby))
                       {
                          rx = re->v1->x;
                          if (IN_SEGMENT(rx, clx, clw))
                            {
                               *(s1 + rx) = 255;
                               if (rx > nx1)
                                  nx1 = rx;
                            }
                       }
                     break;
                  }
               case SHALLOW_EDGE:
                  {
                     int                 x, ey, eyy;

                     x = re_rx;
                     eyy = ((re->v0->y) << 16) + (x - (re->v0->x)) * (re->dyy);
                     ey = eyy >> 16;
                     ey += (eyy - (ey << 16)) >> 15;

                     if (re->dyy > 0)
                       {
                          while (ey > y)
                            {
                               eyy -= re->dyy;
                               ey = eyy >> 16;
                               ey += (eyy - (ey << 16)) >> 15;
                               x--;
                            }
                          re_lx = x;
                          if (x > x1)
                             x1 = x;
                          break;
                       }

                     while (ey < y)
                       {
                          eyy -= re->dyy;
                          ey = eyy >> 16;
                          ey += (eyy - (ey << 16)) >> 15;
                          x--;
                       }
                     re_lx = x;
                     if (x > x1)
                        x1 = x;

                     if (((y + 1) == re->v1->y) && (y < clby))
                       {
                          if (x > nx1)
                             nx1 = x;
                          lx = re->v1->x;
                          while ((ey <= (y + 1)) && (x >= lx))
                            {
                               if ((ey == (y + 1)) && IN_SEGMENT(x, clx, clw))
                                  *(s1 + x) = 255;
                               eyy -= re->dyy;
                               ey = eyy >> 16;
                               ey += (eyy - (ey << 16)) >> 15;
                               x--;
                            }
                          if (x < nx0)
                             nx0 = x;
                       }
                     break;
                  }
               case HORZ_EDGE:
                  {
                     lx = re_lx;
                     rx = re_rx;
                     CLIP_SPAN(lx, rx, clx, clrx);
                     if (lx <= rx)
                       {
                          memset(s0 + lx, 255, rx - lx + 1);
                          if (rx > x1)
                             x1 = rx;
                       }
                     re_lx--;
                     break;
                  }

               default:
                  break;
               }

             /* draw span between edges */
             lx = le_rx;
             rx = re_lx;
             CLIP_SPAN(lx, rx, clx, clrx);
             if ((lx <= rx) && (y >= cly))
                memset(s0 + lx, 255, rx - lx + 1);

             le->xx += le->dxx;
             if (le != re)
                re->xx += re->dxx;

             j += 2;
          }

        if (nactive_horz_edges > 0)
           DEL_HORZ_EDGES();

        /* draw alpha buffer to dst */
        CLIP_SPAN(x0, x1, clx, clrx);
        if ((x0 <= x1) && (y >= cly))
           sfunc(s0 + x0, color, p + x0, x1 - x0 + 1);

        /* exchange alpha buffers */
        ps = s0;
        s0 = s1;
        s1 = ps;

        y++;
        p += dstw;
     }

   DE_INIT_POLY();
}

/* anti-aliased filling */

static void
__imlib_Polygon_FillToData_AA(ImlibPoly poly, DATA32 color,
                              DATA32 * dst, int dstw,
                              int clx, int cly, int clw, int clh,
                              ImlibOp op, char dst_alpha, char blend)
{
   ImlibShapedSpanDrawFunction sfunc;
   IndexedValue       *ysort;
   PolyEdge           *edge;
   int                 k, a_a = 1;
   int                 nactive_edges, nactive_horz_edges, nvertices;
   int                 clrx, clby, ty, by, y, yy, prev_y, prev_yy;
   int                 x0, x1, nx0, nx1;
   DATA32             *p;
   DATA8              *s0, *s1, *ps;

   INIT_POLY();

   yy = y << 16;
   prev_y = y - 1;
   prev_yy = prev_y << 16;

   while (y <= by)
     {
        int                 j;

        while ((k < nvertices) && (poly->points[ysort[k].index].y <= y))
          {
             int                 i = ysort[k].index;

             if (i > 0)
                j = i - 1;
             else
                j = nvertices - 1;

             if (poly->points[j].y < y)
                DEL_EDGE(j);
             else
                ADD_EDGE(j);

             if (i < (nvertices - 1))
                j = i + 1;
             else
                j = 0;

             if (poly->points[j].y < y)
                DEL_EDGE(i);
             else
                ADD_EDGE(i);

             k++;
          }

        qsort(edge, nactive_edges, sizeof(PolyEdge), poly_edge_sorter);

        /* clear alpha buffer */
        if (x0 <= x1)
           memset(s1 + x0, 0, x1 - x0 + 1);

        x0 = nx0;
        x1 = nx1;
        nx0 = clrx + 1;
        nx1 = clx - 1;
        /* draw to alpha buffer */
        j = 0;
        while (j < nactive_edges)
          {
             int                 lx, rx;
             int                 le_lx, le_rx;
             int                 re_lx, re_rx;
             PolyEdge           *le, *re;

             if (j < (nactive_edges - 1))
               {
                  le = edge + j;
                  re = le + 1;
               }
             else if (j > 0)
               {
                  le = edge + (j - 1);
                  le->xx -= le->dxx;
                  re = le + 1;
               }
             else
               {
                  re = le = edge;
               }

             GET_EDGE_RANGE(le, le_lx, le_rx);
             if ((le_lx < le->v0->x) && (le->dxx > 0))
                le_lx = le->v0->x;
             GET_EDGE_RANGE(re, re_lx, re_rx);
             if ((re_rx > re->v0->x) && (re->dxx < 0))
                re_rx = re->v0->x;

             /* draw left aa edge */
             switch (le->type)
               {
               case STEEP_EDGE:
                  {
                     DATA32              tmp;
                     DATA8               aa;

                     if (le_lx < x0)
                        x0 = le_lx;
                     le_rx = le_lx + 1;

                     if (IN_SEGMENT(le_lx, clx, clw))
                       {
                          aa = 255 - ((le->xx - (le_lx << 16)) >> 8);
                          ps = s0 + le_lx;
                          BLEND_ALPHA(ps, aa, tmp);
                       }

                     if ((le->v1->y == (y + 1)) && (y < clby))
                       {
                          lx = (le->xx + le->dxx) >> 16;
                          if (IN_SEGMENT(lx, clx, clw))
                            {
                               aa =
                                  255 - ((le->xx + le->dxx - (lx << 16)) >> 8);
                               ps = s1 + lx;
                               BLEND_ALPHA(ps, aa, tmp);
                               if (lx < nx0)
                                  nx0 = lx;
                            }
                       }
                     break;
                  }
               case SHALLOW_EDGE:
                  {
                     int                 x, ey, eyy;

                     if (le_lx < x0)
                        x0 = le_lx;
                     x = le_lx;
                     eyy = ((le->v0->y) << 16) + (x - (le->v0->x)) * (le->dyy);
                     ey = eyy >> 16;

                     if (le->dyy > 0)
                       {
                          while (ey < y)
                            {
                               DATA32              tmp;
                               DATA8               aa;

                               if ((ey == prev_y) && IN_SEGMENT(x, clx, clw))
                                 {
                                    aa = ((eyy - prev_yy) >> 8);
                                    ps = s0 + x;
                                    BLEND_ALPHA(ps, aa, tmp);
                                 }
                               eyy += le->dyy;
                               ey = eyy >> 16;
                               x++;
                            }
                          le_rx = x;

                          if (((y + 1) == le->v1->y) && (y < clby))
                            {
                               if (x < nx0)
                                  nx0 = x;
                               rx = le->v1->x;
                               while ((ey == y) && (x <= rx))
                                 {
                                    DATA32              tmp;
                                    DATA8               aa;

                                    if (IN_SEGMENT(x, clx, clw))
                                      {
                                         aa = ((eyy - yy) >> 8);
                                         ps = s1 + x;
                                         BLEND_ALPHA(ps, aa, tmp);
                                      }
                                    eyy += le->dyy;
                                    ey = eyy >> 16;
                                    x++;
                                 }
                            }
                          break;
                       }

                     while (ey >= y)
                       {
                          DATA32              tmp;
                          DATA8               aa;

                          if ((ey == y) && IN_SEGMENT(x, clx, clw))
                            {
                               aa = 255 - ((eyy - yy) >> 8);
                               ps = s0 + x;
                               BLEND_ALPHA(ps, aa, tmp);
                            }
                          eyy += le->dyy;
                          ey = eyy >> 16;
                          x++;
                       }
                     le_rx = x;
                     break;
                  }
               case HORZ_EDGE:
                  {
                     lx = le_lx;
                     rx = le_rx;
                     CLIP_SPAN(lx, rx, clx, clrx);
                     if (lx <= rx)
                       {
                          memset(s0 + lx, 255, rx - lx + 1);
                          if (lx < x0)
                             x0 = lx;
                       }
                     le_rx++;
                     break;
                  }

               default:
                  break;
               }

             /* draw right aa edge */
             switch (re->type)
               {
               case STEEP_EDGE:
                  {
                     DATA32              tmp;
                     DATA8               aa;

                     rx = re_lx + 1;
                     if (rx > x1)
                        x1 = rx;

                     if (IN_SEGMENT(rx, clx, clw))
                       {
                          aa = (re->xx - (re_lx << 16)) >> 8;
                          ps = s0 + rx;
                          BLEND_ALPHA(ps, aa, tmp);
                       }

                     if ((re->v1->y == (y + 1)) && (y < clby))
                       {
                          lx = (re->xx + re->dxx) >> 16;
                          rx = lx + 1;
                          if (IN_SEGMENT(rx, clx, clw))
                            {
                               aa = ((re->xx + re->dxx - (lx << 16)) >> 8);
                               ps = s1 + rx;
                               BLEND_ALPHA(ps, aa, tmp);
                               if (rx > nx1)
                                  nx1 = rx;
                            }
                       }
                     break;
                  }
               case SHALLOW_EDGE:
                  {
                     int                 x, ey, eyy;

                     if (re_rx > x1)
                        x1 = re_rx;
                     x = re_rx;
                     eyy = ((re->v0->y) << 16) + (x - (re->v0->x)) * (re->dyy);
                     ey = eyy >> 16;

                     if (re->dyy > 0)
                       {
                          while (ey >= y)
                            {
                               DATA32              tmp;
                               DATA8               aa;

                               if ((ey == y) && IN_SEGMENT(x, clx, clw))
                                 {
                                    aa = 255 - ((eyy - yy) >> 8);
                                    ps = s0 + x;
                                    BLEND_ALPHA(ps, aa, tmp);
                                 }
                               eyy -= re->dyy;
                               ey = eyy >> 16;
                               x--;
                            }
                          re_lx = x;
                          break;
                       }

                     while (ey < y)
                       {
                          DATA32              tmp;
                          DATA8               aa;

                          if ((ey == prev_y) && IN_SEGMENT(x, clx, clw))
                            {
                               aa = ((eyy - prev_yy) >> 8);
                               ps = s0 + x;
                               BLEND_ALPHA(ps, aa, tmp);
                            }
                          eyy -= re->dyy;
                          ey = eyy >> 16;
                          x--;
                       }
                     re_lx = x;

                     if (((y + 1) == re->v1->y) && (y < clby))
                       {
                          if (x > nx1)
                             nx1 = x;
                          lx = re->v1->x;
                          while ((ey == y) && (x >= lx))
                            {
                               DATA32              tmp;
                               DATA8               aa;

                               if (IN_SEGMENT(x, clx, clw))
                                 {
                                    aa = ((eyy - yy) >> 8);
                                    ps = s1 + x;
                                    BLEND_ALPHA(ps, aa, tmp);
                                 }
                               eyy -= re->dyy;
                               ey = eyy >> 16;
                               x--;
                            }
                       }
                     break;
                  }
               case HORZ_EDGE:
                  {
                     lx = re_lx;
                     rx = re_rx;
                     CLIP_SPAN(lx, rx, clx, clrx);
                     if (lx <= rx)
                       {
                          memset(s0 + lx, 255, rx - lx + 1);
                          if (rx > x1)
                             x1 = rx;
                       }
                     re_lx--;
                     break;
                  }

               default:
                  break;
               }

             /* draw span between edges */
             lx = le_rx;
             rx = re_lx;
             CLIP_SPAN(lx, rx, clx, clrx);
             if ((lx <= rx) && (y >= cly))
                memset(s0 + lx, 255, rx - lx + 1);

             le->xx += le->dxx;
             if (le != re)
                re->xx += re->dxx;

             j += 2;
          }

        if (nactive_horz_edges > 0)
           DEL_HORZ_EDGES();

        /* draw alpha buffer to dst */
        CLIP_SPAN(x0, x1, clx, clrx);
        if ((x0 <= x1) && (y >= cly))
           sfunc(s0 + x0, color, p + x0, x1 - x0 + 1);

        /* exchange alpha buffers */
        ps = s0;
        s0 = s1;
        s1 = ps;

        prev_yy = yy;
        prev_y = y;

        y++;
        yy = y << 16;

        p += dstw;
     }

   DE_INIT_POLY();
}

void
__imlib_Polygon_FillToImage(ImlibPoly poly, DATA32 color,
                            ImlibImage * im, int clx, int cly, int clw, int clh,
                            ImlibOp op, char blend, char anti_alias)
{
   if ((!poly) || (!poly->points) || (poly->pointcount < 1) || (clw < 0))
      return;
   if (blend && (!A_VAL(&color)))
      return;
   if (poly->pointcount == 1)
     {
        (void)__imlib_Point_DrawToImage(poly->points[0].x, poly->points[0].y,
                                        color, im, clx, cly, clw, clh, op,
                                        blend, 0);
        return;
     }
   if (poly->pointcount == 2)
     {
        (void)__imlib_Line_DrawToImage(poly->points[0].x, poly->points[0].y,
                                       poly->points[1].x, poly->points[1].y,
                                       color, im, clx, cly, clw, clh, op, blend,
                                       anti_alias, 0);
        return;
     }

   if (clw == 0)
     {
        clw = im->w;
        clx = 0;
        clh = im->h;
        cly = 0;
     }

   CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h);
   if ((clw < 1) || (clh < 1))
      return;

   if (blend && IMAGE_HAS_ALPHA(im))
      __imlib_build_pow_lut();

   if (anti_alias)
      __imlib_Polygon_FillToData_AA(poly, color,
                                    im->data, im->w,
                                    clx, cly, clw, clh,
                                    op, IMAGE_HAS_ALPHA(im), blend);
   else
      __imlib_Polygon_FillToData(poly, color,
                                 im->data, im->w,
                                 clx, cly, clw, clh,
                                 op, IMAGE_HAS_ALPHA(im), blend);
}

/* [<][>][^][v][top][bottom][index][help] */