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; //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 (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 (y[0] == y[1]) side = x[0] > x[1]; if (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 }