summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHermet Park <hermetpark@gmail.com>2018-04-10 11:09:35 +0900
committerHermet Park <hermetpark@gmail.com>2018-04-10 11:19:19 +0900
commitd62ee3bea190c7828834c60b6d6ac901323c05b4 (patch)
tree4781fabdd35e29c138b7f9d768454cf2d66265c9
parent0088189eee8baf87070f1924a1e657164f9b2962 (diff)
evas: improve evas map anti-alising rendering quality.
Old version algorithm was imperfection a bit, quality was poor at some specific degrees, specifically, when pixel increment pattern on the diagonal lines is unstable. This revised version was better than old one even source code is much cleaner and simpler. See belows. *NonAA vs AA: https://ibb.co/bCNfMc *Compare the worst case aa in the old version: https://ibb.co/bEJsZx *Test video: https://youtu.be/Wn20Tym5lfg
-rw-r--r--src/lib/evas/common/evas_map_image_aa.c388
1 files changed, 166 insertions, 222 deletions
diff --git a/src/lib/evas/common/evas_map_image_aa.c b/src/lib/evas/common/evas_map_image_aa.c
index bd55cdb3df..444755c333 100644
--- a/src/lib/evas/common/evas_map_image_aa.c
+++ b/src/lib/evas/common/evas_map_image_aa.c
@@ -1,113 +1,53 @@
1#define READY_TX() \ 1#define PUSH_EDGE_POINT() \
2do \
2{ \ 3{ \
3 if (eidx == 0) \ 4 p_edge.x = spans[y].span[0].x[eidx]; \
4 { \ 5 p_edge.y = y; \
5 tx[0] = edge2.x; \ 6 ptx[0] = tx[0]; \
6 tx[1] = spans[y].span[0].x[0]; \ 7 ptx[1] = tx[1]; \
7 } \ 8} while (0)
8 else \
9 { \
10 tx[0] = spans[y].span[0].x[1]; \
11 tx[1] = edge2.x; \
12 } \
13}
14
15#define READY_TX2() \
16{ \
17 if (eidx == 0) \
18 { \
19 tx2[0] = edge2.x; \
20 tx2[1] = edge1.x; \
21 } \
22 else \
23 { \
24 tx2[0] = edge1.x; \
25 tx2[1] = edge2.x; \
26 } \
27}
28
29#define PUSH_EDGES(xx) \
30{ \
31 if (!leftover) \
32 { \
33 edge1.x = edge2.x; \
34 edge1.y = edge2.y; \
35 edge2.x = (xx); \
36 edge2.y = y; \
37 } \
38 else \
39 { \
40 edge1.y = edge2.y; \
41 edge2.y = y; \
42 } \
43 reset_tx2 = EINA_TRUE; \
44}
45 9
46//Vertical Inside Direction 10static void
47#define VERT_INSIDE(rewind, y_advance) \ 11calc_irregular_coverage(Line* spans, int eidx, int y, int diagonal,
48{ \ 12 int edge_dist, Eina_Bool reverse)
49 int cov_range = edge2.y - edge1.y; \ 13{
50 int coverage = (256 / (cov_range + 1)); \ 14 if (eidx == 1) reverse = !reverse;
51 int ry; \ 15 int coverage = (256 / (diagonal + 2));
52 int val; \ 16 int tmp;
53 for (ry = 1; ry < ((rewind) + 1); ry++) \ 17 for (int ry = 0; ry < (diagonal + 2); ry++)
54 { \ 18 {
55 int ridx = (y - ry) + (y_advance); \ 19 tmp = y - ry - edge_dist;
56 if (spans[ridx].aa_len[eidx] > 1) continue; \ 20 if (tmp < 0) return;
57 if (eidx == 1) \ 21 spans[tmp].aa_len[eidx] = 1;
58 val = (256 - (coverage * (ry + (cov_range - (rewind))))); \ 22 if (reverse) spans[tmp].aa_cov[eidx] = 256 - (coverage * ry);
59 else \ 23 else spans[tmp].aa_cov[eidx] = (coverage * ry);
60 val = (coverage * (ry + (cov_range - (rewind)))); \ 24 }
61 if ((spans[ridx].aa_len[eidx] == 0) || \
62 (val < spans[ridx].aa_cov[eidx])) \
63 spans[ridx].aa_cov[eidx] = val; \
64 spans[ridx].aa_len[eidx] = 1; \
65 } \
66 prev_aa = 4; \
67}
68
69//Vertical Outside Direction
70#define VERT_OUTSIDE(rewind, y_advance, cov_range) \
71{ \
72 int coverage = (256 / ((cov_range) + 1)); \
73 int ry = 1; \
74 for (; ry < ((rewind) + 1); ry++) \
75 { \
76 int ridx = (y - ry) + (y_advance); \
77 if (spans[ridx].aa_len[(eidx)] > 1) continue; \
78 spans[ridx].aa_len[(eidx)] = 1; \
79 if (eidx == 1) \
80 { \
81 spans[ridx].aa_cov[(eidx)] = \
82 (coverage * (ry + (cov_range - (rewind)))); \
83 } \
84 else \
85 { \
86 spans[ridx].aa_cov[(eidx)] = \
87 (256 - (coverage * (ry + ((cov_range) - (rewind))))); \
88 } \
89 } \
90 prev_aa = 2; \
91} 25}
92 26
93//Horizontal Inside Direction 27static void
94#define HORIZ_INSIDE(yy, xx, xx2) \ 28calc_vert_coverage(Line *spans, int eidx, int y, int rewind, Eina_Bool reverse)
95{ \ 29{
96 if (((xx) - (xx2)) > spans[(yy)].aa_len[(eidx)]) \ 30 if (eidx == 1) reverse = !reverse;
97 { \ 31 int coverage = (256 / (rewind + 1));
98 spans[(yy)].aa_len[(eidx)] = ((xx) - (xx2)); \ 32 int tmp;
99 spans[(yy)].aa_cov[(eidx)] = (256 / (spans[(yy)].aa_len[(eidx)] + 1)); \ 33 for (int ry = 1; ry < (rewind + 1); ry++)
100 } \ 34 {
35 tmp = y - ry;
36 if (tmp < 0 ) return;
37 spans[tmp].aa_len[eidx] = 1;
38 if (reverse) spans[tmp].aa_cov[eidx] = (256 - (coverage * ry));
39 else spans[tmp].aa_cov[eidx] = (coverage * ry);
40 }
101} 41}
102 42
103//Horizontal Outside Direction 43static void
104#define HORIZ_OUTSIDE(yy, xx, xx2) \ 44calc_horiz_coverage(Line *spans, int eidx, int y, int x, int x2)
105{ \ 45{
106 if (((xx) - (xx2)) > spans[(yy)].aa_len[(eidx)]) \ 46 if (spans[y].aa_len[eidx] < abs(x - x2))
107 { \ 47 {
108 spans[(yy)].aa_len[(eidx)] = ((xx) - (xx2)); \ 48 spans[y].aa_len[eidx] = abs(x - x2);
109 spans[(yy)].aa_cov[(eidx)] = (256 / (spans[(yy)].aa_len[(eidx)] + 1)); \ 49 spans[y].aa_cov[eidx] = (256 / (spans[y].aa_len[eidx] + 1));
110 } \ 50 }
111} 51}
112 52
113static inline DATA32 53static inline DATA32
@@ -130,29 +70,31 @@ _aa_coverage_apply(Line *line, int ww, int w, DATA32 val, Eina_Bool src_alpha)
130 if (((val & 0xff000000) >> 24) < 0xff) 70 if (((val & 0xff000000) >> 24) < 0xff)
131 return (val | 0xff000000); 71 return (val | 0xff000000);
132 } 72 }
133
134 return val; 73 return val;
135} 74}
136 75
137void 76static void
138_calc_aa_edges_internal(Line *spans, int eidx, int ystart, int yend) 77_calc_aa_edges_internal(Line *spans, int eidx, int ystart, int yend)
139{ 78{
140 int y; 79 int y;
141 Evas_Coord_Point edge1 = { -1, -1 }; //prev-previous edge pixel 80 Evas_Coord_Point p_edge = {-1, -1}; //previous edge point
142 Evas_Coord_Point edge2 = { -1, -1 }; //previous edge pixel 81 Evas_Coord_Point edge_diff = {0, 0}; //temporary used for point distance
143 82
144 /* store larger to tx[0] between prev and current edge's x positions. */ 83 /* store bigger to tx[0] between prev and current edge's x positions. */
145 int tx[2] = {0, 0}; 84 int tx[2] = {0, 0};
85 /* back up prev tx values */
86 int ptx[2] = {0, 0};
87 int diagonal = 0; //straight diagonal pixels counti
146 88
147 /* store lager to tx2[0] between edge1 and edge2's x positions. */ 89//Previous edge direction:
148 int tx2[2] = {0, 0}; 90#define DirOutHor 0x0011
91#define DirOutVer 0x0001
92#define DirInHor 0x0010
93#define DirInVer 0x0000
94#define DirNone 0x1000
149 95
150 /* previous edge anti-aliased type. 96 int prev_dir = DirNone;
151 2: vertical outside 97 int cur_dir = DirNone;
152 4: vertical inside */
153 int prev_aa = 0;
154
155 Eina_Bool reset_tx2 = EINA_TRUE;
156 98
157 yend -= ystart; 99 yend -= ystart;
158 100
@@ -160,129 +102,131 @@ _calc_aa_edges_internal(Line *spans, int eidx, int ystart, int yend)
160 for (y = 0; y < yend; y++) 102 for (y = 0; y < yend; y++)
161 { 103 {
162 if (spans[y].span[0].x[0] == -1) continue; 104 if (spans[y].span[0].x[0] == -1) continue;
163 edge1.x = edge2.x = spans[y].span[0].x[eidx]; 105 p_edge.x = spans[y].span[0].x[eidx];
164 edge1.y = edge2.y = y; 106 p_edge.y = y;
165 break; 107 break;
166 } 108 }
167 109
168 //Calculates AA Edges 110 //Calculates AA Edges
169 for (y++; y <= yend; y++) 111 for (y++; y < yend; y++)
170 { 112 {
171 Eina_Bool leftover = EINA_FALSE; 113 //Ready tx
114 if (eidx == 0)
115 {
116 tx[0] = p_edge.x;
117 tx[1] = spans[y].span[0].x[0];
118 }
119 else
120 {
121 tx[0] = spans[y].span[0].x[1];
122 tx[1] = p_edge.x;
123 }
172 124
173 if (spans[y].span[0].x[eidx] == -1) leftover = EINA_TRUE; 125 edge_diff.x = (tx[0] - tx[1]);
126 edge_diff.y = (y - p_edge.y);
174 127
175 if (!leftover) READY_TX() 128 //Confirm current edge direction
129 if (edge_diff.x > 0)
130 {
131 if (edge_diff.y == 1) cur_dir = DirOutHor;
132 else cur_dir = DirOutVer;
133 }
134 else if (edge_diff.x < 0)
135 {
136 if (edge_diff.y == 1) cur_dir = DirInHor;
137 else cur_dir = DirInVer;
138 }
139 else cur_dir = DirNone;
176 140
177 //Case1. Outside Incremental 141 //straight diagonal increase
178 if (tx[0] > tx[1]) 142 if ((cur_dir == prev_dir) && (y < yend))
179 { 143 {
180 //Horizontal Edge 144 if ((abs(edge_diff.x) == 1) && (edge_diff.y == 1))
181 if ((y - edge2.y) == 1)
182 {
183 HORIZ_OUTSIDE(y, tx[0], tx[1])
184 }
185 //Vertical Edge
186 else if (tx[0] > tx[1])
187 { 145 {
188 VERT_OUTSIDE((y - edge2.y), 0, (y - edge2.y)) 146 ++diagonal;
189 147 PUSH_EDGE_POINT();
190 //Just in case: 1 pixel alias next to vertical edge? 148 continue;
191 if (abs(spans[(y + 1)].span[0].x[eidx] -
192 spans[y].span[0].x[eidx]) >= 1)
193 {
194 HORIZ_OUTSIDE(y, tx[0], tx[1])
195 }
196 } 149 }
197 PUSH_EDGES(spans[y].span[0].x[eidx])
198 } 150 }
199 //Case2. Inside Incremental 151 switch (cur_dir)
200 else if (tx[1] > tx[0])
201 { 152 {
202 //Just in case: direction is reversed at the outside vertical edge? 153 case DirOutHor:
203 if (prev_aa == 2) 154 {
204 { 155 calc_horiz_coverage(spans, eidx, y, tx[0], tx[1]);
205 VERT_OUTSIDE((y - edge2.y), 0, (y - edge2.y)) 156 if (diagonal > 0)
206 edge1.x = spans[y - 1].span[0].x[eidx]; 157 {
207 edge1.y = y - 1; 158 calc_irregular_coverage(spans, eidx, y, diagonal, 0,
208 edge2.x = spans[y].span[0].x[eidx]; 159 EINA_TRUE);
209 edge2.y = y; 160 diagonal = 0;
210 } 161 }
211 else 162 /* Increment direction is changed:
212 PUSH_EDGES(spans[y].span[0].x[eidx]) 163 Outside Vertical -> Outside Horizontal */
213 164 if (prev_dir == DirOutVer)
214 /* Find next edge. We go forward 2 more index since this logic 165 calc_horiz_coverage(spans, eidx, p_edge.y, ptx[0], ptx[1]);
215 computes aa edges by looking back in advance 2 spans. */ 166 PUSH_EDGE_POINT();
216 for (y++; y <= (yend + 2); y++) 167 }
217 { 168 break;
218 leftover = EINA_FALSE; 169 case DirOutVer:
219 170 {
220 if ((spans[y].span[0].x[eidx] == -1) || (y > yend)) 171 calc_vert_coverage(spans, eidx, y, edge_diff.y, EINA_TRUE);
221 leftover = EINA_TRUE; 172 if (diagonal > 0)
222 173 {
223 if (!leftover) READY_TX() 174 calc_irregular_coverage(spans, eidx, y, diagonal,
224 if (reset_tx2) READY_TX2() 175 edge_diff.y, EINA_FALSE);
225 176 diagonal = 0;
226 //Case 1. Inside Direction 177 }
227 if (tx[1] > tx[0]) 178 /* Increment direction is changed:
228 { 179 Outside Horizontal -> Outside Vertical */
229 //Horizontal Edge 180 if (prev_dir == DirOutHor)
230 if ((edge2.y - edge1.y) == 1) 181 calc_horiz_coverage(spans, eidx, p_edge.y, ptx[0], ptx[1]);
231 { 182 PUSH_EDGE_POINT();
232 HORIZ_INSIDE(edge1.y, tx2[0], tx2[1]); 183 }
233 } 184 break;
234 //Vertical Edge 185 case DirInHor:
235 else if ((tx2[0] - tx2[1]) == 1) 186 {
236 { 187 calc_horiz_coverage(spans, eidx, (y - 1), tx[0], tx[1]);
237 VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y)) 188 if (diagonal > 0)
238 } 189 {
239 //Just in case: Right Side Square Edge...? 190 calc_irregular_coverage(spans, eidx, y, diagonal, 0,
240 else if (prev_aa == 4) 191 EINA_FALSE);
241 { 192 diagonal = 0;
242 VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y)) 193 }
243 if ((y - edge2.y) == 1) 194 /* Increment direction is changed:
244 { 195 Outside Horizontal -> Inside Horizontal */
245 HORIZ_INSIDE((edge2.y - 1), edge2.x, 196 if (prev_dir == DirOutHor)
246 spans[y].span[0].x[eidx]); 197 calc_horiz_coverage(spans, eidx, p_edge.y, ptx[0], ptx[1]);
247 } 198 PUSH_EDGE_POINT();
248 } 199 }
249 PUSH_EDGES(spans[y].span[0].x[eidx]) 200 break;
250 } 201 case DirInVer:
251 //Case 2. Reversed. Outside Direction 202 {
252 else if (tx[1] < tx[0]) 203 calc_vert_coverage(spans, eidx, y, edge_diff.y, EINA_FALSE);
253 { 204 if (diagonal > 0)
254 //Horizontal Edge 205 {
255 if ((edge2.y - edge1.y) == 1) 206 calc_irregular_coverage(spans, eidx, y, diagonal,
256 HORIZ_INSIDE(edge1.y, tx2[0], tx2[1]) 207 edge_diff.y, EINA_TRUE);
257 //Vertical Edge 208 diagonal = 0;
258 else 209 }
259 VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y)) 210 /* Increment direction is changed:
260 211 Outside Horizontal -> Inside Vertical */
261 PUSH_EDGES(spans[y].span[0].x[eidx]) 212 if (prev_dir == DirOutHor)
262 break; 213 calc_horiz_coverage(spans, eidx, p_edge.y, ptx[0], ptx[1]);
263 } 214 PUSH_EDGE_POINT();
264 } 215 }
216 break;
265 } 217 }
218 if (cur_dir != DirNone) prev_dir = cur_dir;
266 } 219 }
267 220
268 y = yend; 221 //leftovers...?
269 222 if ((edge_diff.y == 1) && (edge_diff.x != 0))
270 //Leftovers for verticals.
271 if (prev_aa == 2)
272 {
273 if (((eidx == 0) && (edge1.x > edge2.x)) ||
274 ((eidx == 1) && (edge1.x < edge2.x)))
275 VERT_OUTSIDE((y - edge2.y + 1), 1, (edge2.y - edge1.y));
276 }
277 else if (prev_aa == 4)
278 { 223 {
279 if (((eidx == 0) && (edge1.x < edge2.x)) || 224 calc_horiz_coverage(spans, eidx, y - 1, ptx[0], ptx[1]);
280 ((eidx == 1) && (edge1.x > edge2.x))) 225 calc_horiz_coverage(spans, eidx, y, tx[0], tx[1]);
281 {
282 VERT_INSIDE((edge2.y - edge1.y), -(y - edge2.y))
283 VERT_INSIDE((y - edge2.y) + 1, 1);
284 }
285 } 226 }
227 else
228 calc_vert_coverage(spans, eidx, (y + 1), (edge_diff.y + 2),
229 (prev_dir & 0x00000001));
286} 230}
287 231
288static void 232static void