typedef struct
{
   float x, y, u, v;
   DATA32 c;
} Map_Vertex;

typedef struct
{
   Map_Vertex v[3];
} Map_Tripoly;

typedef struct AALine
{
   int x[2];
   int aa_cov[2];
   int aa_len[2];
} AALine;

typedef struct AASpans
{
   AALine *lines;
   int ystart;
   int yend;
} AASpans;

static float dudx, dvdx, dcdx[4];
static float dxdya, dxdyb, dudya, dvdya, dcdya[4];
static float xa, xb, ua, va, ca[4];

#define SWAP(a, b, tmp) \
   tmp = a; \
   a = b; \
   b = tmp

/************************** ANTI-ALIASING CODE ********************************/
#ifdef MAP_HIGH_ANTI_ALIASING

static void
_map_irregular_coverage_calc(AALine* spans, int eidx, int y, int diagonal,
                       int edge_dist, Eina_Bool reverse)
{
   if (eidx == 1) reverse = !reverse;
   int coverage = (255 / (diagonal + 2));
   int tmp;
   for (int ry = 0; ry < (diagonal + 2); ry++)
     {
        tmp = y - ry - edge_dist;
        if (tmp < 0) return;
        spans[tmp].aa_len[eidx] = 1;
        if (reverse) spans[tmp].aa_cov[eidx] = 255 - (coverage * ry);
        else spans[tmp].aa_cov[eidx] = (coverage * ry);
     }
}

static void
_map_vert_coverage_calc(AALine *spans, int eidx, int y, int rewind, Eina_Bool reverse)
{
   if (eidx == 1) reverse = !reverse;
   int coverage = (255 / (rewind + 1));
   int tmp;
   for (int ry = 1; ry < (rewind + 1); ry++)
     {
        tmp = y - ry;
        if (tmp < 0 ) return;
        spans[tmp].aa_len[eidx] = 1;
        if (reverse) spans[tmp].aa_cov[eidx] = (255 - (coverage * ry));
        else spans[tmp].aa_cov[eidx] = (coverage * ry);
     }
}

static void
_map_horiz_coverage_calc(AALine *spans, int eidx, int y, int x, int x2)
{
   if (spans[y].aa_len[eidx] < abs(x - x2))
     {
        spans[y].aa_len[eidx] = abs(x - x2);
        spans[y].aa_cov[eidx] = (255 / (spans[y].aa_len[eidx] + 1));
     }
}

/*
 * To understand here AA main logic,
 * Please refer this page: www.hermet.pe.kr/122
*/
static void
_map_aa_edge_calc_internal(AALine *spans, int eidx, int ystart, int yend)
{
   int y = 0;
   Evas_Coord_Point p_edge = {-1, -1};  //previous edge point
   Evas_Coord_Point edge_diff = {0, 0}; //temporary used for point distance

   /* store bigger to tx[0] between prev and current edge's x positions. */
   int tx[2] = {0, 0};
   /* back up prev tx values */
   int ptx[2] = {0, 0};
   int diagonal = 0;                      //straight diagonal pixels counti

//Previous edge direction:
#define DirOutHor 0x0011
#define DirOutVer 0x0001
#define DirInHor  0x0010
#define DirInVer  0x0000
#define DirNone   0x1000

#define PUSH_VERTEX() \
do \
{ \
   p_edge.x = spans[y].x[eidx]; \
   p_edge.y = y; \
   ptx[0] = tx[0]; \
   ptx[1] = tx[1]; \
} while (0)

   int prev_dir = DirNone;
   int cur_dir = DirNone;

   yend -= ystart;

   //Start Edge
   if (y < yend)
     {
        p_edge.x = spans[y].x[eidx];
        p_edge.y = y;
     }

   //Calculates AA Edges
   for (y++; y < yend; y++)
     {
        //Ready tx
        if (eidx == 0)
          {
             tx[0] = p_edge.x;
             tx[1] = spans[y].x[0];
          }
        else
          {
             tx[0] = spans[y].x[1];
             tx[1] = p_edge.x;
          }

        edge_diff.x = (tx[0] - tx[1]);
        edge_diff.y = (y - p_edge.y);

        //Confirm current edge direction
        if (edge_diff.x > 0)
          {
             if (edge_diff.y == 1) cur_dir = DirOutHor;
             else cur_dir = DirOutVer;
          }
        else if (edge_diff.x < 0)
          {
             if (edge_diff.y == 1) cur_dir = DirInHor;
             else cur_dir = DirInVer;
          }
        else cur_dir = DirNone;

       //straight diagonal increase
       if ((cur_dir == prev_dir) && (y < yend))
         {
            if ((abs(edge_diff.x) == 1) && (edge_diff.y == 1))
              {
                 ++diagonal;
                 PUSH_VERTEX();
                 continue;
              }
         }
       switch (cur_dir)
         {
          case DirOutHor:
            {
               _map_horiz_coverage_calc(spans, eidx, y, tx[0], tx[1]);
               if (diagonal > 0)
                 {
                    _map_irregular_coverage_calc(spans, eidx, y, diagonal, 0,
                                            EINA_TRUE);
                    diagonal = 0;
                 }
               /* Increment direction is changed:
                  Outside Vertical -> Outside Horizontal */
               if (prev_dir == DirOutVer)
                 _map_horiz_coverage_calc(spans, eidx, p_edge.y, ptx[0], ptx[1]);

               //Trick, but fine-tunning!
               if (y == 1)
                 _map_horiz_coverage_calc(spans, eidx, p_edge.y, tx[0], tx[1]);

               PUSH_VERTEX();
            }
          break;
          case DirOutVer:
            {
               _map_vert_coverage_calc(spans, eidx, y, edge_diff.y, EINA_TRUE);
               if (diagonal > 0)
                 {
                    _map_irregular_coverage_calc(spans, eidx, y, diagonal,
                                            edge_diff.y, EINA_FALSE);
                    diagonal = 0;
                 }
               /* Increment direction is changed:
                  Outside Horizontal -> Outside Vertical */
               if (prev_dir == DirOutHor)
                 _map_horiz_coverage_calc(spans, eidx, p_edge.y, ptx[0], ptx[1]);
               PUSH_VERTEX();
            }
          break;
          case DirInHor:
            {
               _map_horiz_coverage_calc(spans, eidx, (y - 1), tx[0], tx[1]);
               if (diagonal > 0)
                 {
                    _map_irregular_coverage_calc(spans, eidx, y, diagonal, 0,
                                            EINA_FALSE);
                    diagonal = 0;
                 }
               /* Increment direction is changed:
                  Outside Horizontal -> Inside Horizontal */
               if (prev_dir == DirOutHor)
                 _map_horiz_coverage_calc(spans, eidx, p_edge.y, ptx[0], ptx[1]);
               PUSH_VERTEX();
            }
          break;
          case DirInVer:
            {
               _map_vert_coverage_calc(spans, eidx, y, edge_diff.y, EINA_FALSE);
               if (diagonal > 0)
                 {
                    _map_irregular_coverage_calc(spans, eidx, y, diagonal,
                                            edge_diff.y, EINA_TRUE);
                    diagonal = 0;
                 }
               /* Increment direction is changed:
                  Outside Horizontal -> Inside Vertical */
               if (prev_dir == DirOutHor)
                 _map_horiz_coverage_calc(spans, eidx, p_edge.y, ptx[0], ptx[1]);
               PUSH_VERTEX();
            }
          break;
         }
       if (cur_dir != DirNone) prev_dir = cur_dir;
     }

   //leftovers...?
   if ((edge_diff.y == 1) && (edge_diff.x != 0))
     {
        if (y >= yend) y = (yend - 1);
        _map_horiz_coverage_calc(spans, eidx, y - 1, ptx[0], ptx[1]);
        _map_horiz_coverage_calc(spans, eidx, y, tx[0], tx[1]);
     }
   else
     {
        ++y;
        if (y > yend) y = yend;
        _map_vert_coverage_calc(spans, eidx, y, (edge_diff.y + 1),
                                (prev_dir & 0x00000001));
     }
}

static void
_map_aa_edges_calc(AALine *spans, int ystart, int yend)
{
   //FIXME: support more than 2 span case.

   //left side
   _map_aa_edge_calc_internal(spans, 0, ystart, yend);
   //right side
   _map_aa_edge_calc_internal(spans, 1, ystart, yend);
}

static AASpans *
_map_aa_ready(int dw, int dh, int ystart, int yend)
{
   AASpans *aa_spans = (AASpans *) malloc(sizeof(AASpans));
   if (!aa_spans) return NULL;

   aa_spans->lines = (AALine*) calloc(sizeof(AALine), dh);
   for (int i = 0; i < dh; i++)
     {
        aa_spans->lines[i].x[0] = dw + 1;
        aa_spans->lines[i].x[1] = -1;
     }
   aa_spans->ystart = (int) ystart;
   aa_spans->yend = (int) yend;

   return aa_spans;
}

static void
_map_aa_apply(AASpans *aa_spans, DATA32 *dst, int dw)
{
   int y = aa_spans->ystart;
   int yend = aa_spans->yend;
   AALine *line;
   DATA32 *buf;
   DATA32 d;
   int w, offset, pos;

   _map_aa_edges_calc(aa_spans->lines, y, yend);

   while (y < yend)
     {
        line = &aa_spans->lines[y - aa_spans->ystart];
        w = line->x[1] - line->x[0];
        if (w > 0)
          {
             offset = y * dw;

             //Left edge
             buf = dst + (offset + line->x[0]);
             if (line->x[0] > 1) d = *(dst + (offset + (line->x[0] - 1)));
             else d = *buf;
             pos = 1;
             while (pos <= line->aa_len[0])
               {
                  *buf = INTERP_256((line->aa_cov[0] * pos), *buf, d);
                  ++buf;
                  ++pos;
               }

             //Right edge
             buf = dst + (offset + line->x[1] - 1);
             if (line->x[1] < (dw - 1)) d = *(dst + (offset + (line->x[1] + 1)));
             else d = *buf;
             pos = w;
             while (w - line->aa_len[1] < pos)
               {
                  *buf = INTERP_256(255 - (line->aa_cov[1] * (line->aa_len[1] - (w - pos))), *buf, d);
                  buf--;
                  pos--;
               }
          }
        y++;
     }

   free(aa_spans->lines);
   free(aa_spans);
}
#endif

/************************** TEXTURE MAPPING CODE ******************************/
static void
_map_triangle_draw_linear(RGBA_Image *src, RGBA_Image *dst,
                          int cx, int cy, int cw, int ch,
                          RGBA_Image *mask, int mx, int my,
                          int ystart, int yend,
                          DATA32 *tbuf, RGBA_Gfx_Func func, RGBA_Gfx_Func func2,
                          DATA32 mul_col, AASpans *aa_spans,
                          Eina_Bool col_blend)
{
   float _dudx = dudx, _dvdx = dvdx;
   float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya;
   float _xa = xa, _xb = xb, _ua = ua, _va = va;
   DATA32 *sbuf = src->image.data;
   DATA32 *dbuf = dst->image.data;
   int sw = src->cache_entry.w;
   int sh = src->cache_entry.h;
   int dw = dst->cache_entry.w;
   int x1, x2, x, y, uu, vv, ar, ab, iru, irv, px, ay;
   float dx, u, v, iptr;
   float _dcdx[4], _dcdya[4], _ca[4];
   float c[4] = {0, 0, 0, 0};
   DATA32 *buf, *tmp;
   DATA8 *mbuf;

   //Range exception handling
   if (ystart >= (cy + ch)) return;
   if (ystart < cy) ystart = cy;
   if (yend > (cy + ch)) yend = (cy + ch);

   if (col_blend)
     for (int i = 0; i < 4; i++)
       {
          _dcdx[i] = dcdx[i];
          _dcdya[i] = dcdya[i];
          _ca[i] = ca[i];
       }

   //Loop through all lines in the segment
   y = ystart;
   while (y < yend)
     {
        x1 = _xa;
        x2 = _xb;

        //Range exception handling
        if (x1 < cx) x1 = cx;
        if (x2 > (cx + cw)) x2 = (cx + cw);

        if (aa_spans)
          {
             ay = y - aa_spans->ystart;
             if (aa_spans->lines[ay].x[0] > x1) aa_spans->lines[ay].x[0] = x1;
             if (aa_spans->lines[ay].x[1] < x2) aa_spans->lines[ay].x[1] = x2;
          }
        if ((x2 - x1) < 1) goto next;
        if ((x1 >= (cx + cw)) || (x2 <= cx)) goto next;

        //Perform subtexel pre-stepping on UV
        dx = 1 - (_xa - x1);
        u = _ua + dx * _dudx;
        v = _va + dx * _dvdx;

        if (col_blend)
          {
             c[0] = _ca[0] + dx * _dcdx[0];
             c[1] = _ca[1] + dx * _dcdx[1];
             c[2] = _ca[2] + dx * _dcdx[2];
             c[3] = _ca[3] + dx * _dcdx[3];
          }

        //Direct draw or blending intervention?
        if (tbuf) buf = tbuf;
        else buf = dbuf + ((y * dw) + x1);

        x = x1;

        //Draw horizontal line
        while (x++ < x2)
          {
             uu = (int) u;
             vv = (int) v;
             // FIXME: sometimes u and v are < 0 - don'tc crash
             if (uu < 0) uu = 0;
             if (vv < 0) vv = 0;

             //Range exception handling
             //OPTIMIZE ME, handle in advance?
             if (uu >= sw) uu = sw - 1;
             if (vv >= sh) vv = sh - 1;

             ar = (int)(255 * (1 - modff(u, &iptr)));
             ab = (int)(255 * (1 - modff(v, &iptr)));
             iru = uu + 1;
             irv = vv + 1;
             px = *(sbuf + (vv * sw) + uu);

             //horizontal interpolate
             if (iru < sw)
               {
                  //right pixel
                  int px2 = *(sbuf + (vv * sw) + iru);
                  px = INTERP_256(ar, px, px2);
               }
             //vertical interpolate
             if (irv < sh)
               {
                  //bottom pixel
                  int px2 = *(sbuf + (irv * sw) + uu);

                  //horizontal interpolate
                  if (iru < sw)
                    {
                       //bottom right pixel
                       int px3 = *(sbuf + (irv * sw) + iru);
                       px2 = INTERP_256(ar, px2, px3);
                    }
                  px = INTERP_256(ab, px, px2);
               }

             if (!col_blend)
               {
                  *(buf++) = px;
               }
             //Vertex Color Blending
             else
               {
                  DATA32 tmp = (((int) c[0]) << 24) | (((int) c[1]) << 16) | (((int) c[2]) << 8) | ((int) c[3]);
                  *(buf++) = MUL4_SYM(tmp, px);
                  c[0] += _dcdx[0];
                  c[1] += _dcdx[1];
                  c[2] += _dcdx[2];
                  c[3] += _dcdx[3];
               }

             //Step UV horizontally
             u += _dudx;
             v += _dvdx;
          }

        if (tbuf)
          {
             tmp = dbuf + ((y *dw) + x1);
             int len = x2 - x1;
             if (!mask) func(tbuf, NULL, mul_col, tmp, len);
             else
               {
                  mbuf = mask->image.data8
                     + (y - my) * mask->cache_entry.w + (x1 - mx);
                  if (mul_col != 0xffffffff)
                    func2(tbuf, NULL, mul_col, tbuf, len);
                  func(tbuf, mbuf, 0, tmp, len);
               }
          }
next:
        //Step along both edges
        _xa += _dxdya;
        _xb += _dxdyb;
        _ua += _dudya;
        _va += _dvdya;

        if (col_blend)
          {
             _ca[0] += _dcdya[0];
             _ca[1] += _dcdya[1];
             _ca[2] += _dcdya[2];
             _ca[3] += _dcdya[3];
          }

        y++;
     }
   xa = _xa;
   xb = _xb;
   ua = _ua;
   va = _va;

   if (col_blend)
     {
        ca[0] = _ca[0];
        ca[1] = _ca[1];
        ca[2] = _ca[2];
        ca[3] = _ca[3];
     }
}

/* This mapping algorithm is based on Mikael Kalms's. */
static void
_map_triangle_draw(RGBA_Image *src, RGBA_Image *dst,
                   int cx, int cy, int cw, int ch,
                   RGBA_Image *mask, int mx, int my,
                   DATA32 *tbuf, RGBA_Gfx_Func func, RGBA_Gfx_Func func2,
                   Map_Tripoly *poly, DATA32 mul_col,
                   AASpans *aa_spans, Eina_Bool smooth EINA_UNUSED,
                   Eina_Bool col_blend)
{
   float x[3] = { poly->v[0].x, poly->v[1].x, poly->v[2].x };
   float y[3] = { poly->v[0].y, poly->v[1].y, poly->v[2].y };
   float u[3] = { poly->v[0].u, poly->v[1].u, poly->v[2].u };
   float v[3] = { poly->v[0].v, poly->v[1].v, poly->v[2].v };
   DATA32 c[3] = { poly->v[0].c, poly->v[1].c, poly->v[2].c };
   float off_y;
   float denom;
   float dxdy[3] = {0, 0, 0};
   float dudy, dvdy, dcdy[4];
   float tmp;
   int mc[3][4];     //3 vertex, 4 color channels.
   DATA32 tmpc;
   Eina_Bool side;
   Eina_Bool upper = EINA_FALSE;

   //Sort the vertices in ascending Y order
   if (y[0] > y[1])
     {
        SWAP(x[0], x[1], tmp);
        SWAP(y[0], y[1], tmp);
        SWAP(u[0], u[1], tmp);
        SWAP(v[0], v[1], tmp);
        SWAP(c[0], c[1], tmpc);
     }
   if (y[0] > y[2])
     {
        SWAP(x[0], x[2], tmp);
        SWAP(y[0], y[2], tmp);
        SWAP(u[0], u[2], tmp);
        SWAP(v[0], v[2], tmp);
        SWAP(c[0], c[2], tmpc);

     }
   if (y[1] > y[2])
     {
        SWAP(x[1], x[2], tmp);
        SWAP(y[1], y[2], tmp);
        SWAP(u[1], u[2], tmp);
        SWAP(v[1], v[2], tmp);
        SWAP(c[1], c[2], tmpc);
     }

   //Y indexes
   int yi[3] = { y[0], y[1], y[2] };

   //Skip drawing if it's too thin to cover any pixels at all.
   if ((yi[0] == yi[1] && yi[0] == yi[2]) ||
       ((int) x[0] == (int) x[1] && (int) x[0] == (int) x[2]))
     return;

   /* Calculate horizontal and vertical increments for UV axes (these
      calcs are certainly not optimal, although they're stable
      (handles any dy being 0) */
   denom = ((x[2] - x[0]) * (y[1] - y[0]) - (x[1] - x[0]) * (y[2] - y[0]));

   //Skip poly if it's an infinitely thin line
   if (EINA_DBL_EQ(denom, 0)) return;

   denom = 1 / denom;   //Reciprocal for speeding up
   dudx = ((u[2] - u[0]) * (y[1] - y[0]) - (u[1] - u[0]) * (y[2] - y[0])) * denom;
   dvdx = ((v[2] - v[0]) * (y[1] - y[0]) - (v[1] - v[0]) * (y[2] - y[0])) * denom;
   dudy = ((u[1] - u[0]) * (x[2] - x[0]) - (u[2] - u[0]) * (x[1] - x[0])) * denom;
   dvdy = ((v[1] - v[0]) * (x[2] - x[0]) - (v[2] - v[0]) * (x[1] - x[0])) * denom;

   if (col_blend)
     {
        for (int i = 0; i < 3; ++i)
          {
             mc[i][0] = (c[i] & 0xff000000) >> 24;
             mc[i][1] = (c[i] & 0x00ff0000) >> 16;
             mc[i][2] = (c[i] & 0x0000ff00) >> 8;
             mc[i][3] = (c[i] & 0x000000ff);
          }
        for (int i = 0; i < 4; ++i)
          {
             dcdx[i] = ((mc[2][i] - mc[0][i]) * (y[1] - y[0]) - (mc[1][i] - mc[0][i]) * (y[2] - y[0])) * denom;
             dcdy[i] = ((mc[1][i] - mc[0][i]) * (x[2] - x[0]) - (mc[2][i] - mc[0][i]) * (x[1] - x[0])) * denom;
          }
     }

   //Calculate X-slopes along the edges
   if (y[1] > y[0]) dxdy[0] = (x[1] - x[0]) / (y[1] - y[0]);
   if (y[2] > y[0]) dxdy[1] = (x[2] - x[0]) / (y[2] - y[0]);
   if (y[2] > y[1]) dxdy[2] = (x[2] - x[1]) / (y[2] - y[1]);

   //Determine which side of the polygon the longer edge is on
   side = (dxdy[1] > dxdy[0]) ? EINA_TRUE:EINA_FALSE;

   if (EINA_DBL_EQ(y[0], y[1])) side = x[0] > x[1];
   if (EINA_DBL_EQ(y[1], y[2])) side = x[2] > x[1];

   //Longer edge is on the left side
   if (!side)
     {
        //Calculate slopes along left edge
        dxdya = dxdy[1];
        dudya = dxdya * dudx + dudy;
        dvdya = dxdya * dvdx + dvdy;

        if (col_blend)
          for (int i = 0; i < 4; i++)
            dcdya[i] = dxdya * dcdx[i] + dcdy[i];

        //Perform subpixel pre-stepping along left edge
        float dy = 1 - (y[0] - yi[0]);
        xa = x[0] + dy * dxdya;
        ua = u[0] + dy * dudya;
        va = v[0] + dy * dvdya;

        if (col_blend)
          for (int i = 0; i < 4; i++)
            ca[i] = mc[0][i] + dy * dcdya[i];

        //Draw upper segment if possibly visible
        if (yi[0] < yi[1])
          {
             off_y = y[0] < cy ? (cy - y[0]) : 0;
             xa += (off_y * dxdya);
             ua += (off_y * dudya);
             va += (off_y * dvdya);

             if (col_blend)
               for (int i = 0; i < 4; i++)
                 ca[i] += (off_y * dcdya[i]);

             // Set right edge X-slope and perform subpixel pre-stepping
             dxdyb = dxdy[0];
             xb = x[0] + dy * dxdyb + (off_y * dxdyb);
             _map_triangle_draw_linear(src, dst, cx, cy, cw, ch, mask, mx, my,
                                       yi[0], yi[1], tbuf, func,
                                       func2, mul_col, aa_spans,
                                       col_blend);
             upper = EINA_TRUE;
          }
        //Draw lower segment if possibly visible
        if (yi[1] < yi[2])
          {
             off_y = y[1] < cy ? (cy - y[1]) : 0;
             if (!upper)
               {
                  xa += (off_y * dxdya);
                  ua += (off_y * dudya);
                  va += (off_y * dvdya);

                  if (col_blend)
                    for (int i = 0; i < 4; i++)
                      ca[i] += (off_y * dcdya[i]);
               }

             // Set right edge X-slope and perform subpixel pre-stepping
             dxdyb = dxdy[2];
             xb = x[1] + (1 - (y[1] - yi[1])) * dxdyb + (off_y * dxdyb);
             _map_triangle_draw_linear(src, dst, cx, cy, cw, ch, mask, mx, my,
                                       yi[1], yi[2], tbuf, func, func2,
                                       mul_col, aa_spans, col_blend);
          }
     }
   //Longer edge is on the right side
   else
     {
        //Set right edge X-slope and perform subpixel pre-stepping
        dxdyb = dxdy[1];
        float dy = 1 - (y[0] - yi[0]);
        xb = x[0] + dy * dxdyb;

        //Draw upper segment if possibly visible
        if (yi[0] < yi[1])
          {
             off_y = y[0] < cy ? (cy - y[0]) : 0;
             xb += (off_y *dxdyb);

             // Set slopes along left edge and perform subpixel pre-stepping
             dxdya = dxdy[0];
             dudya = dxdya * dudx + dudy;
             dvdya = dxdya * dvdx + dvdy;

             xa = x[0] + dy * dxdya + (off_y * dxdya);
             ua = u[0] + dy * dudya + (off_y * dudya);
             va = v[0] + dy * dvdya + (off_y * dvdya);

             if (col_blend)
               for (int i = 0; i < 4; i++)
                 {
                    dcdya[i] = dxdya * dcdx[i] + dcdy[i];
                    ca[i] = mc[0][i] + dy * dcdya[i] + (off_y * dcdya[i]);
                 }
             _map_triangle_draw_linear(src, dst, cx, cy, cw, ch, mask, mx, my,
                                       yi[0], yi[1], tbuf, func, func2,
                                       mul_col, aa_spans, col_blend);
             upper = EINA_TRUE;
          }
        //Draw lower segment if possibly visible
        if (yi[1] < yi[2])
          {
             off_y = y[1] < cy ? (cy - y[1]) : 0;
             if (!upper)
               xb += (off_y *dxdyb);

             // Set slopes along left edge and perform subpixel pre-stepping
             dxdya = dxdy[2];
             dudya = dxdya * dudx + dudy;
             dvdya = dxdya * dvdx + dvdy;
             dy = 1 - (y[1] - yi[1]);
             xa = x[1] + dy * dxdya + (off_y * dxdya);
             ua = u[1] + dy * dudya + (off_y * dudya);
             va = v[1] + dy * dvdya + (off_y * dvdya);

             if (col_blend)
               for (int i = 0; i < 4; i++)
                 {
                    dcdya[i] = dxdya * dcdx[i] + dcdy[i];
                    ca[i] = mc[1][i] + dy * dcdya[i] + (off_y * dcdya[i]);
                 }
             _map_triangle_draw_linear(src, dst, cx, cy, cw, ch, mask, mx, my,
                                       yi[1], yi[2], tbuf, func, func2,
                                       mul_col, aa_spans, col_blend);
          }
     }
}

static void
_evas_common_map_rgba_internal_high(RGBA_Image *src, RGBA_Image *dst,
                                    int cx, int cy, int cw, int ch,  //clip
                                    DATA32 mul_col, int render_op,
                                    RGBA_Map_Point *p, int smooth,
                                    int anti_alias, int level EINA_UNUSED,
                                    RGBA_Image *mask, int mask_x, int mask_y)
{
   float x[4], y[4], u[4], v[4];
   DATA32 c[4];
   RGBA_Gfx_Func func = NULL;
   RGBA_Gfx_Func func2 = NULL;
   DATA32 *tbuf = NULL;                //Temporarily used span buffer
   Eina_Bool have_alpha = EINA_FALSE;
   Eina_Bool src_alpha = src->cache_entry.flags.alpha;
   Eina_Bool ssrc_alpha = src->cache_entry.flags.alpha_sparse;
   Eina_Bool dst_alpha = dst->cache_entry.flags.alpha;
   Eina_Bool col_blend = EINA_FALSE;   //Necessary blending vertex color?

   //FIXME: we cannot apply anti_aliasing per polygons.
   anti_alias = EINA_FALSE;

   /* Prepare points data.
      Convert to float,
      shift XY coordinates to match the sub-pixeling technique.
      Check alpha transparency. */
   for (int i = 0; i < 4; i++)
     {
        x[i] = p[i].fx + 0.5;
        y[i] = p[i].fy + 0.5;
        u[i] = (p[i].u >> FP);
        v[i] = (p[i].v >> FP);
        c[i] = p[i].col;

        /* Exceptions:
           Limit u,v coords of points to be within the source image */
        if (u[i] < 0) u[i] = 0;
        else if (u[i] >= (float) src->cache_entry.w)
          u[i] = (float) (src->cache_entry.w - 1);

        if (v[i] < 0) v[i] = 0;
        else if (v[i] >= (float) src->cache_entry.h)
          v[i] = (float) (src->cache_entry.h - 1);

        if ((c[i] >> 24) < 0xff) have_alpha = EINA_TRUE;
        if (c[i] < 0xffffffff) col_blend = EINA_TRUE;
     }

   //Figure out alpha to choose a blend method.
   //If operation is solid, bypass buf and draw func and draw direct to dst.
   if (!(!src_alpha && !dst_alpha && (mul_col == 0xffffffff) &&
       !have_alpha && !anti_alias && !mask))
     {
        if (have_alpha) src_alpha = EINA_TRUE;
        ssrc_alpha = (anti_alias | src_alpha);
        if (!mask)
          {
             if (mul_col != 0xffffffff)
               func = evas_common_gfx_func_composite_pixel_color_span_get(ssrc_alpha, ssrc_alpha, mul_col, dst_alpha, cw, render_op);
             else
               func = evas_common_gfx_func_composite_pixel_span_get(ssrc_alpha, ssrc_alpha, dst_alpha, cw, render_op);
          }
        else
          {
             func = evas_common_gfx_func_composite_pixel_mask_span_get(ssrc_alpha, ssrc_alpha, dst_alpha, cw, render_op);
             if (mul_col != 0xffffffff)
               func2 = evas_common_gfx_func_composite_pixel_color_span_get(ssrc_alpha, ssrc_alpha, mul_col, dst_alpha, cw, EVAS_RENDER_COPY);
          }
        if (src_alpha) src->cache_entry.flags.alpha = EINA_TRUE;
        tbuf = alloca(cw * sizeof(DATA32));
     }

   //Setup Anti-Aliasing?
   AASpans *aa_spans = NULL;

#ifdef MAP_HIGH_ANTI_ALIASING
   if (anti_alias)
     {
        //Adjust AA Y range
        float ystart = 9999999.0f, yend = -1.0f;
        for (int i = 0; i < 4; i++)
          {
             if (y[i] < ystart) ystart = y[i];
             if (y[i] > yend) yend = y[i];
          }
        if (ystart < cy) ystart = cy;
        if (yend > cy + ch) yend = cy + ch;

        aa_spans =
           _map_aa_ready(dst->cache_entry.w, dst->cache_entry.h, ystart, yend);
     }
#endif

   /*
      1 polygon is consisted of 2 triangles, 4 polygons constructs 1 mesh.
      below figure illustrates vert[9] index info.
      If you need better quality, please divide a mesh by more number of triangles.

       0 -- 4 -- 1
       |  / |  / |
       | /  | /  |
       6 -- 8 -- 7
       |  / |  / |
       | /  | /  |
       3 -- 5 -- 2
   */

   //Interpolated color info
   DATA32 tmpc[5] = {
      INTERP_256(128, c[0], c[1]),
      INTERP_256(128, c[3], c[2]),
      INTERP_256(128, c[0], c[3]),
      INTERP_256(128, c[1], c[2]),
      INTERP_256(128, tmpc[2], tmpc[3])};

   //9 vertices (see above figure)
   Map_Vertex vert[9] = {
      {x[0], y[0], u[0], v[0], c[0]},
      {x[1], y[1], u[1], v[1], c[1]},
      {x[2], y[2], u[2], v[2], c[2]},
      {x[3], y[3], u[3], v[3], c[3]},
      {x[0] + (x[1] - x[0]) * 0.5, y[0] + (y[1] - y[0]) * 0.5, u[0] + (u[1] - u[0]) * 0.5, v[0] + (v[1] - v[0]) * 0.5, tmpc[0]},
      {x[3] + (x[2] - x[3]) * 0.5, y[3] + (y[2] - y[3]) * 0.5, u[3] + (u[2] - u[3]) * 0.5, v[3] + (v[2] - v[3]) * 0.5, tmpc[1]},
      {x[0] + (x[3] - x[0]) * 0.5, y[0] + (y[3] - y[0]) * 0.5, u[0] + (u[3] - u[0]) * 0.5, v[0] + (v[3] - v[0]) * 0.5, tmpc[2]},
      {x[1] + (x[2] - x[1]) * 0.5, y[1] + (y[2] - y[1]) * 0.5, u[1] + (u[2] - u[1]) * 0.5, v[1] + (v[2] - v[1]) * 0.5, tmpc[3]},
      {vert[6].x + (vert[7].x - vert[6].x) * 0.5, vert[4].y + (vert[5].y - vert[4].y) * 0.5, vert[6].u + (vert[7].u - vert[6].u) * 0.5, vert[4].v + (vert[5].v - vert[4].v) * 0.5, tmpc[4]}};

   //Vertex Indices
   int idx[4][4] = {{ 0, 4, 8, 6 }, {4, 1, 7, 8}, {6, 8, 5, 3}, {8, 7, 2, 5}};

   Map_Tripoly poly;

   //Draw a pair of triangles
   for (int i = 0; i < 4; ++i)
     {
        poly.v[0] = vert[idx[i][0]];
        poly.v[1] = vert[idx[i][1]];
        poly.v[2] = vert[idx[i][3]];

        _map_triangle_draw(src, dst, cx, cy, cw, ch,
                           mask, mask_x, mask_y,
                           tbuf, func, func2,
                           &poly, mul_col, aa_spans,
                           smooth, col_blend);

        poly.v[0] = vert[idx[i][1]];
        poly.v[1] = vert[idx[i][3]];
        poly.v[2] = vert[idx[i][2]];

        _map_triangle_draw(src, dst, cx, cy, cw, ch,
                           mask, mask_x, mask_y,
                           tbuf, func, func2,
                           &poly, mul_col, aa_spans,
                           smooth, col_blend);
     }
#ifdef MAP_HIGH_ANTI_ALIASING
   if (anti_alias)
     _map_aa_apply(aa_spans, dst->image.data, dst->cache_entry.w);
#endif
}
