298 lines
8.2 KiB
C
298 lines
8.2 KiB
C
#define READY_TX() \
|
|
{ \
|
|
if (eidx == 0) \
|
|
{ \
|
|
tx[0] = edge2.x; \
|
|
tx[1] = spans[y].span[0].x[0]; \
|
|
} \
|
|
else \
|
|
{ \
|
|
tx[0] = spans[y].span[0].x[1]; \
|
|
tx[1] = edge2.x; \
|
|
} \
|
|
}
|
|
|
|
#define READY_TX2() \
|
|
{ \
|
|
if (eidx == 0) \
|
|
{ \
|
|
tx2[0] = edge2.x; \
|
|
tx2[1] = edge1.x; \
|
|
} \
|
|
else \
|
|
{ \
|
|
tx2[0] = edge1.x; \
|
|
tx2[1] = edge2.x; \
|
|
} \
|
|
}
|
|
|
|
#define PUSH_EDGES(xx) \
|
|
{ \
|
|
if (!leftover) \
|
|
{ \
|
|
edge1.x = edge2.x; \
|
|
edge1.y = edge2.y; \
|
|
edge2.x = (xx); \
|
|
edge2.y = y; \
|
|
} \
|
|
else \
|
|
{ \
|
|
edge1.y = edge2.y; \
|
|
edge2.y = y; \
|
|
} \
|
|
reset_tx2 = EINA_TRUE; \
|
|
}
|
|
|
|
//Vertical Inside Direction
|
|
#define VERT_INSIDE(rewind, y_advance) \
|
|
{ \
|
|
int cov_range = edge2.y - edge1.y; \
|
|
int coverage = (256 / (cov_range + 1)); \
|
|
int ry; \
|
|
int val; \
|
|
for (ry = 1; ry < ((rewind) + 1); ry++) \
|
|
{ \
|
|
int ridx = (y - ry) + (y_advance); \
|
|
if (spans[ridx].aa_len[eidx] > 1) continue; \
|
|
if (eidx == 1) \
|
|
val = (256 - (coverage * (ry + (cov_range - (rewind))))); \
|
|
else \
|
|
val = (coverage * (ry + (cov_range - (rewind)))); \
|
|
if ((spans[ridx].aa_len[eidx] == 0) || \
|
|
(val < spans[ridx].aa_cov[eidx])) \
|
|
spans[ridx].aa_cov[eidx] = val; \
|
|
spans[ridx].aa_len[eidx] = 1; \
|
|
} \
|
|
prev_aa = 4; \
|
|
}
|
|
|
|
//Vertical Outside Direction
|
|
#define VERT_OUTSIDE(rewind, y_advance, cov_range) \
|
|
{ \
|
|
int coverage = (256 / ((cov_range) + 1)); \
|
|
int ry = 1; \
|
|
for (; ry < ((rewind) + 1); ry++) \
|
|
{ \
|
|
int ridx = (y - ry) + (y_advance); \
|
|
if (spans[ridx].aa_len[(eidx)] > 1) continue; \
|
|
spans[ridx].aa_len[(eidx)] = 1; \
|
|
if (eidx == 1) \
|
|
{ \
|
|
spans[ridx].aa_cov[(eidx)] = \
|
|
(coverage * (ry + (cov_range - (rewind)))); \
|
|
} \
|
|
else \
|
|
{ \
|
|
spans[ridx].aa_cov[(eidx)] = \
|
|
(256 - (coverage * (ry + ((cov_range) - (rewind))))); \
|
|
} \
|
|
} \
|
|
prev_aa = 2; \
|
|
}
|
|
|
|
//Horizontal Inside Direction
|
|
#define HORIZ_INSIDE(yy, xx, xx2) \
|
|
{ \
|
|
if (((xx) - (xx2)) > spans[(yy)].aa_len[(eidx)]) \
|
|
{ \
|
|
spans[(yy)].aa_len[(eidx)] = ((xx) - (xx2)); \
|
|
spans[(yy)].aa_cov[(eidx)] = (256 / (spans[(yy)].aa_len[(eidx)] + 1)); \
|
|
} \
|
|
}
|
|
|
|
//Horizontal Outside Direction
|
|
#define HORIZ_OUTSIDE(yy, xx, xx2) \
|
|
{ \
|
|
if (((xx) - (xx2)) > spans[(yy)].aa_len[(eidx)]) \
|
|
{ \
|
|
spans[(yy)].aa_len[(eidx)] = ((xx) - (xx2)); \
|
|
spans[(yy)].aa_cov[(eidx)] = (256 / (spans[(yy)].aa_len[(eidx)] + 1)); \
|
|
} \
|
|
}
|
|
|
|
static inline DATA32
|
|
_aa_coverage_apply(Line *line, int ww, int w, DATA32 val, Eina_Bool src_alpha)
|
|
{
|
|
//Left Edge Anti Anliasing
|
|
if ((w - line->aa_len[0]) < ww)
|
|
{
|
|
return MUL_256((line->aa_cov[0] * (w - ww + 1)), val);
|
|
}
|
|
//Right Edge Anti Aliasing
|
|
if (line->aa_len[1] >= ww)
|
|
{
|
|
return MUL_256(256 - (line->aa_cov[1] * (line->aa_len[1] - ww + 1)),
|
|
val);
|
|
}
|
|
//Remove Transparency if src image alpha is off.
|
|
if (!src_alpha)
|
|
{
|
|
if (((val & 0xff000000) >> 24) < 0xff)
|
|
return (val | 0xff000000);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
void
|
|
_calc_aa_edges_internal(Line *spans, int eidx, int ystart, int yend)
|
|
{
|
|
int y;
|
|
Evas_Coord_Point edge1 = { -1, -1 }; //prev-previous edge pixel
|
|
Evas_Coord_Point edge2 = { -1, -1 }; //previous edge pixel
|
|
|
|
/* store larger to tx[0] between prev and current edge's x positions. */
|
|
int tx[2] = {0, 0};
|
|
|
|
/* store lager to tx2[0] between edge1 and edge2's x positions. */
|
|
int tx2[2] = {0, 0};
|
|
|
|
/* previous edge anti-aliased type.
|
|
2: vertical outside
|
|
4: vertical inside */
|
|
int prev_aa = 0;
|
|
|
|
Eina_Bool reset_tx2 = EINA_TRUE;
|
|
|
|
yend -= ystart;
|
|
|
|
//Find Start Edge
|
|
for (y = 0; y < yend; y++)
|
|
{
|
|
if (spans[y].span[0].x[0] == -1) continue;
|
|
edge1.x = edge2.x = spans[y].span[0].x[eidx];
|
|
edge1.y = edge2.y = y;
|
|
break;
|
|
}
|
|
|
|
//Calculates AA Edges
|
|
for (y++; y <= yend; y++)
|
|
{
|
|
Eina_Bool leftover = EINA_FALSE;
|
|
|
|
if (spans[y].span[0].x[eidx] == -1) leftover = EINA_TRUE;
|
|
|
|
if (!leftover) READY_TX()
|
|
|
|
//Case1. Outside Incremental
|
|
if (tx[0] > tx[1])
|
|
{
|
|
//Horizontal Edge
|
|
if ((y - edge2.y) == 1)
|
|
{
|
|
HORIZ_OUTSIDE(y, tx[0], tx[1])
|
|
}
|
|
//Vertical Edge
|
|
else if (tx[0] > tx[1])
|
|
{
|
|
VERT_OUTSIDE((y - edge2.y), 0, (y - edge2.y))
|
|
|
|
//Just in case: 1 pixel alias next to vertical edge?
|
|
if (abs(spans[(y + 1)].span[0].x[eidx] -
|
|
spans[y].span[0].x[eidx]) >= 1)
|
|
{
|
|
HORIZ_OUTSIDE(y, tx[0], tx[1])
|
|
}
|
|
}
|
|
PUSH_EDGES(spans[y].span[0].x[eidx])
|
|
}
|
|
//Case2. Inside Incremental
|
|
else if (tx[1] > tx[0])
|
|
{
|
|
//Just in case: direction is reversed at the outside vertical edge?
|
|
if (prev_aa == 2)
|
|
{
|
|
VERT_OUTSIDE((y - edge2.y), 0, (y - edge2.y))
|
|
edge1.x = spans[y - 1].span[0].x[eidx];
|
|
edge1.y = y - 1;
|
|
edge2.x = spans[y].span[0].x[eidx];
|
|
edge2.y = y;
|
|
}
|
|
else
|
|
PUSH_EDGES(spans[y].span[0].x[eidx])
|
|
|
|
/* Find next edge. We go forward 2 more index since this logic
|
|
computes aa edges by looking back in advance 2 spans. */
|
|
for (y++; y <= (yend + 2); y++)
|
|
{
|
|
leftover = EINA_FALSE;
|
|
|
|
if ((spans[y].span[0].x[eidx] == -1) || (y > yend))
|
|
leftover = EINA_TRUE;
|
|
|
|
if (!leftover) READY_TX()
|
|
if (reset_tx2) READY_TX2()
|
|
|
|
//Case 1. Inside Direction
|
|
if (tx[1] > tx[0])
|
|
{
|
|
//Horizontal Edge
|
|
if ((edge2.y - edge1.y) == 1)
|
|
{
|
|
HORIZ_INSIDE(edge1.y, tx2[0], tx2[1]);
|
|
}
|
|
//Vertical Edge
|
|
else if ((tx2[0] - tx2[1]) == 1)
|
|
{
|
|
VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
|
|
}
|
|
//Just in case: Right Side Square Edge...?
|
|
else if (prev_aa == 4)
|
|
{
|
|
VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
|
|
if ((y - edge2.y) == 1)
|
|
{
|
|
HORIZ_INSIDE((edge2.y - 1), edge2.x,
|
|
spans[y].span[0].x[eidx]);
|
|
}
|
|
}
|
|
PUSH_EDGES(spans[y].span[0].x[eidx])
|
|
}
|
|
//Case 2. Reversed. Outside Direction
|
|
else if (tx[1] < tx[0])
|
|
{
|
|
//Horizontal Edge
|
|
if ((edge2.y - edge1.y) == 1)
|
|
HORIZ_INSIDE(edge1.y, tx2[0], tx2[1])
|
|
//Vertical Edge
|
|
else
|
|
VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
|
|
|
|
PUSH_EDGES(spans[y].span[0].x[eidx])
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
y = yend;
|
|
|
|
//Leftovers for verticals.
|
|
if (prev_aa == 2)
|
|
{
|
|
if (((eidx == 0) && (edge1.x > edge2.x)) ||
|
|
((eidx == 1) && (edge1.x < edge2.x)))
|
|
VERT_OUTSIDE((y - edge2.y + 1), 1, (edge2.y - edge1.y));
|
|
}
|
|
else if (prev_aa == 4)
|
|
{
|
|
if (((eidx == 0) && (edge1.x < edge2.x)) ||
|
|
((eidx == 1) && (edge1.x > edge2.x)))
|
|
{
|
|
VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
|
|
VERT_INSIDE((y - edge2.y) + 1, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_calc_aa_edges(Line *spans, int ystart, int yend)
|
|
{
|
|
//FIXME: support 2 span case.
|
|
|
|
//left side
|
|
_calc_aa_edges_internal(spans, 0, ystart, yend);
|
|
//right side
|
|
_calc_aa_edges_internal(spans, 1, ystart, yend);
|
|
}
|