1 /**
2 * @file lv_draw_sw_tranform.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_draw_sw.h"
10 #include "../../misc/lv_assert.h"
11 #include "../../misc/lv_area.h"
12 #include "../../core/lv_refr.h"
13
14 #if LV_DRAW_COMPLEX
15 /*********************
16 * DEFINES
17 *********************/
18
19 /**********************
20 * TYPEDEFS
21 **********************/
22 typedef struct {
23 int32_t x_in;
24 int32_t y_in;
25 int32_t x_out;
26 int32_t y_out;
27 int32_t sinma;
28 int32_t cosma;
29 int32_t zoom;
30 int32_t angle;
31 int32_t pivot_x_256;
32 int32_t pivot_y_256;
33 lv_point_t pivot;
34 } point_transform_dsc_t;
35
36 /**********************
37 * STATIC PROTOTYPES
38 **********************/
39 /**
40 * Transform a point with 1/256 precision (the output coordinates are upscaled by 256)
41 * @param t pointer to n initialized `point_transform_dsc_t` structure
42 * @param xin X coordinate to rotate
43 * @param yin Y coordinate to rotate
44 * @param xout upscaled, transformed X
45 * @param yout upscaled, transformed Y
46 */
47 static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
48 int32_t * yout);
49
50 static void argb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
51 int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
52 int32_t x_end, lv_color_t * cbuf, uint8_t * abuf);
53
54 static void rgb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
55 int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
56 int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, lv_img_cf_t cf);
57
58 #if LV_COLOR_DEPTH == 16
59 static void rgb565a8_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
60 int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
61 int32_t x_end, lv_color_t * cbuf, uint8_t * abuf);
62 #endif
63
64 static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
65 int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
66 int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, lv_img_cf_t cf);
67
68 /**********************
69 * STATIC VARIABLES
70 **********************/
71
72 /**********************
73 * MACROS
74 **********************/
75
76 /**********************
77 * GLOBAL FUNCTIONS
78 **********************/
79
lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx,const lv_area_t * dest_area,const void * src_buf,lv_coord_t src_w,lv_coord_t src_h,lv_coord_t src_stride,const lv_draw_img_dsc_t * draw_dsc,lv_img_cf_t cf,lv_color_t * cbuf,lv_opa_t * abuf)80 void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
81 lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
82 const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
83 {
84 LV_UNUSED(draw_ctx);
85
86 point_transform_dsc_t tr_dsc;
87 tr_dsc.angle = -draw_dsc->angle;
88 tr_dsc.zoom = (256 * 256) / draw_dsc->zoom;
89 tr_dsc.pivot = draw_dsc->pivot;
90
91 int32_t angle_low = tr_dsc.angle / 10;
92 int32_t angle_high = angle_low + 1;
93 int32_t angle_rem = tr_dsc.angle - (angle_low * 10);
94
95 int32_t s1 = lv_trigo_sin(angle_low);
96 int32_t s2 = lv_trigo_sin(angle_high);
97
98 int32_t c1 = lv_trigo_sin(angle_low + 90);
99 int32_t c2 = lv_trigo_sin(angle_high + 90);
100
101 tr_dsc.sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
102 tr_dsc.cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
103 tr_dsc.sinma = tr_dsc.sinma >> (LV_TRIGO_SHIFT - 10);
104 tr_dsc.cosma = tr_dsc.cosma >> (LV_TRIGO_SHIFT - 10);
105 tr_dsc.pivot_x_256 = tr_dsc.pivot.x * 256;
106 tr_dsc.pivot_y_256 = tr_dsc.pivot.y * 256;
107
108 lv_coord_t dest_w = lv_area_get_width(dest_area);
109 lv_coord_t dest_h = lv_area_get_height(dest_area);
110 lv_coord_t y;
111 for(y = 0; y < dest_h; y++) {
112 int32_t xs1_ups, ys1_ups, xs2_ups, ys2_ups;
113
114 transform_point_upscaled(&tr_dsc, dest_area->x1, dest_area->y1 + y, &xs1_ups, &ys1_ups);
115 transform_point_upscaled(&tr_dsc, dest_area->x2, dest_area->y1 + y, &xs2_ups, &ys2_ups);
116
117 int32_t xs_diff = xs2_ups - xs1_ups;
118 int32_t ys_diff = ys2_ups - ys1_ups;
119 int32_t xs_step_256 = 0;
120 int32_t ys_step_256 = 0;
121 if(dest_w > 1) {
122 xs_step_256 = (256 * xs_diff) / (dest_w - 1);
123 ys_step_256 = (256 * ys_diff) / (dest_w - 1);
124 }
125 int32_t xs_ups = xs1_ups + 0x80;
126 int32_t ys_ups = ys1_ups + 0x80;
127
128 if(draw_dsc->antialias == 0) {
129 switch(cf) {
130 case LV_IMG_CF_TRUE_COLOR_ALPHA:
131 argb_no_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf);
132 break;
133 case LV_IMG_CF_TRUE_COLOR:
134 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
135 rgb_no_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf, cf);
136 break;
137
138 #if LV_COLOR_DEPTH == 16
139 case LV_IMG_CF_RGB565A8:
140 rgb565a8_no_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf);
141 break;
142 #endif
143 default:
144 break;
145 }
146 }
147 else {
148 argb_and_rgb_aa(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, cbuf, abuf, cf);
149 }
150
151 cbuf += dest_w;
152 abuf += dest_w;
153 }
154 }
155
156 /**********************
157 * STATIC FUNCTIONS
158 **********************/
159
rgb_no_aa(const uint8_t * src,lv_coord_t src_w,lv_coord_t src_h,lv_coord_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,lv_color_t * cbuf,uint8_t * abuf,lv_img_cf_t cf)160 static void rgb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
161 int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
162 int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, lv_img_cf_t cf)
163 {
164 int32_t xs_ups_start = xs_ups;
165 int32_t ys_ups_start = ys_ups;
166 lv_disp_t * d = _lv_refr_get_disp_refreshing();
167 lv_color_t ck = d->driver->color_chroma_key;
168
169 lv_memset_ff(abuf, x_end);
170
171 lv_coord_t x;
172 for(x = 0; x < x_end; x++) {
173 xs_ups = xs_ups_start + ((xs_step * x) >> 8);
174 ys_ups = ys_ups_start + ((ys_step * x) >> 8);
175
176 int32_t xs_int = xs_ups >> 8;
177 int32_t ys_int = ys_ups >> 8;
178 if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
179 abuf[x] = 0x00;
180 }
181 else {
182
183 #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
184 const uint8_t * src_tmp = src;
185 src_tmp += ys_int * src_stride + xs_int;
186 cbuf[x].full = src_tmp[0];
187 #elif LV_COLOR_DEPTH == 16
188 const lv_color_t * src_tmp = (const lv_color_t *)src;
189 src_tmp += ys_int * src_stride + xs_int;
190 cbuf[x] = *src_tmp;
191 #elif LV_COLOR_DEPTH == 32
192 const uint8_t * src_tmp = src;
193 src_tmp += (ys_int * src_stride * sizeof(lv_color_t)) + xs_int * sizeof(lv_color_t);
194 cbuf[x].full = *((uint32_t *)src_tmp);
195 #endif
196 }
197 if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && cbuf[x].full == ck.full) {
198 abuf[x] = 0x00;
199 }
200 }
201 }
202
argb_no_aa(const uint8_t * src,lv_coord_t src_w,lv_coord_t src_h,lv_coord_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,lv_color_t * cbuf,uint8_t * abuf)203 static void argb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
204 int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
205 int32_t x_end, lv_color_t * cbuf, uint8_t * abuf)
206 {
207 int32_t xs_ups_start = xs_ups;
208 int32_t ys_ups_start = ys_ups;
209
210 lv_coord_t x;
211 for(x = 0; x < x_end; x++) {
212 xs_ups = xs_ups_start + ((xs_step * x) >> 8);
213 ys_ups = ys_ups_start + ((ys_step * x) >> 8);
214
215 int32_t xs_int = xs_ups >> 8;
216 int32_t ys_int = ys_ups >> 8;
217 if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
218 abuf[x] = 0;
219 }
220 else {
221 const uint8_t * src_tmp = src;
222 src_tmp += (ys_int * src_stride * LV_IMG_PX_SIZE_ALPHA_BYTE) + xs_int * LV_IMG_PX_SIZE_ALPHA_BYTE;
223
224 #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
225 cbuf[x].full = src_tmp[0];
226 #elif LV_COLOR_DEPTH == 16
227 cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
228 #elif LV_COLOR_DEPTH == 32
229 cbuf[x].full = *((uint32_t *)src_tmp);
230 #endif
231 abuf[x] = src_tmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
232 }
233 }
234 }
235
236 #if LV_COLOR_DEPTH == 16
rgb565a8_no_aa(const uint8_t * src,lv_coord_t src_w,lv_coord_t src_h,lv_coord_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,lv_color_t * cbuf,uint8_t * abuf)237 static void rgb565a8_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
238 int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
239 int32_t x_end, lv_color_t * cbuf, uint8_t * abuf)
240 {
241 int32_t xs_ups_start = xs_ups;
242 int32_t ys_ups_start = ys_ups;
243
244 lv_coord_t x;
245 for(x = 0; x < x_end; x++) {
246 xs_ups = xs_ups_start + ((xs_step * x) >> 8);
247 ys_ups = ys_ups_start + ((ys_step * x) >> 8);
248
249 int32_t xs_int = xs_ups >> 8;
250 int32_t ys_int = ys_ups >> 8;
251 if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
252 abuf[x] = 0;
253 }
254 else {
255 const lv_color_t * src_tmp = (const lv_color_t *)src;
256 src_tmp += ys_int * src_stride + xs_int;
257 cbuf[x] = *src_tmp;
258
259 const lv_opa_t * a_tmp = src + src_stride * src_h * sizeof(lv_color_t);
260 a_tmp += ys_int * src_stride + xs_int;
261 abuf[x] = *a_tmp;
262 }
263 }
264 }
265 #endif
266
267
argb_and_rgb_aa(const uint8_t * src,lv_coord_t src_w,lv_coord_t src_h,lv_coord_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,lv_color_t * cbuf,uint8_t * abuf,lv_img_cf_t cf)268 static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
269 int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
270 int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, lv_img_cf_t cf)
271 {
272 int32_t xs_ups_start = xs_ups;
273 int32_t ys_ups_start = ys_ups;
274 bool has_alpha;
275 int32_t px_size;
276 lv_color_t ck = {0};
277 switch(cf) {
278 case LV_IMG_CF_TRUE_COLOR:
279 has_alpha = false;
280 px_size = sizeof(lv_color_t);
281 break;
282 case LV_IMG_CF_TRUE_COLOR_ALPHA:
283 has_alpha = true;
284 px_size = LV_IMG_PX_SIZE_ALPHA_BYTE;
285 break;
286 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: {
287 has_alpha = true;
288 px_size = sizeof(lv_color_t);
289 lv_disp_t * d = _lv_refr_get_disp_refreshing();
290 ck = d->driver->color_chroma_key;
291 break;
292 }
293 #if LV_COLOR_DEPTH == 16
294 case LV_IMG_CF_RGB565A8:
295 has_alpha = true;
296 px_size = sizeof(lv_color_t);
297 break;
298 #endif
299 default:
300 return;
301 }
302
303 lv_coord_t x;
304 for(x = 0; x < x_end; x++) {
305 xs_ups = xs_ups_start + ((xs_step * x) >> 8);
306 ys_ups = ys_ups_start + ((ys_step * x) >> 8);
307
308 int32_t xs_int = xs_ups >> 8;
309 int32_t ys_int = ys_ups >> 8;
310
311 /*Fully out of the image*/
312 if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
313 abuf[x] = 0x00;
314 continue;
315 }
316
317 /*Get the direction the hor and ver neighbor
318 *`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
319 int32_t xs_fract = xs_ups & 0xFF;
320 int32_t ys_fract = ys_ups & 0xFF;
321
322 int32_t x_next;
323 int32_t y_next;
324 if(xs_fract < 0x80) {
325 x_next = -1;
326 xs_fract = (0x7F - xs_fract) * 2;
327 }
328 else {
329 x_next = 1;
330 xs_fract = (xs_fract - 0x80) * 2;
331 }
332 if(ys_fract < 0x80) {
333 y_next = -1;
334 ys_fract = (0x7F - ys_fract) * 2;
335 }
336 else {
337 y_next = 1;
338 ys_fract = (ys_fract - 0x80) * 2;
339 }
340
341 const uint8_t * src_tmp = src;
342 src_tmp += (ys_int * src_stride * px_size) + xs_int * px_size;
343
344
345 if(xs_int + x_next >= 0 &&
346 xs_int + x_next <= src_w - 1 &&
347 ys_int + y_next >= 0 &&
348 ys_int + y_next <= src_h - 1) {
349
350 const uint8_t * px_base = src_tmp;
351 const uint8_t * px_hor = src_tmp + x_next * px_size;
352 const uint8_t * px_ver = src_tmp + y_next * src_stride * px_size;
353 lv_color_t c_base;
354 lv_color_t c_ver;
355 lv_color_t c_hor;
356
357 if(has_alpha) {
358 lv_opa_t a_base;
359 lv_opa_t a_ver;
360 lv_opa_t a_hor;
361 if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
362 a_base = px_base[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
363 a_ver = px_ver[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
364 a_hor = px_hor[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
365 }
366 #if LV_COLOR_DEPTH == 16
367 else if(cf == LV_IMG_CF_RGB565A8) {
368 const lv_opa_t * a_tmp = src + src_stride * src_h * sizeof(lv_color_t);
369 a_base = *(a_tmp + (ys_int * src_stride) + xs_int);
370 a_hor = *(a_tmp + (ys_int * src_stride) + xs_int + x_next);
371 a_ver = *(a_tmp + ((ys_int + y_next) * src_stride) + xs_int);
372 }
373 #endif
374 else if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
375 if(((lv_color_t *)px_base)->full == ck.full ||
376 ((lv_color_t *)px_ver)->full == ck.full ||
377 ((lv_color_t *)px_hor)->full == ck.full) {
378 abuf[x] = 0x00;
379 continue;
380 }
381 else {
382 a_base = 0xff;
383 a_ver = 0xff;
384 a_hor = 0xff;
385 }
386 }
387 else {
388 a_base = 0xff;
389 a_ver = 0xff;
390 a_hor = 0xff;
391 }
392
393 if(a_ver != a_base) a_ver = ((a_ver * ys_fract) + (a_base * (0x100 - ys_fract))) >> 8;
394 if(a_hor != a_base) a_hor = ((a_hor * xs_fract) + (a_base * (0x100 - xs_fract))) >> 8;
395 abuf[x] = (a_ver + a_hor) >> 1;
396
397 if(abuf[x] == 0x00) continue;
398
399 #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
400 c_base.full = px_base[0];
401 c_ver.full = px_ver[0];
402 c_hor.full = px_hor[0];
403 #elif LV_COLOR_DEPTH == 16
404 c_base.full = px_base[0] + (px_base[1] << 8);
405 c_ver.full = px_ver[0] + (px_ver[1] << 8);
406 c_hor.full = px_hor[0] + (px_hor[1] << 8);
407 #elif LV_COLOR_DEPTH == 32
408 c_base.full = *((uint32_t *)px_base);
409 c_ver.full = *((uint32_t *)px_ver);
410 c_hor.full = *((uint32_t *)px_hor);
411 #endif
412 }
413 /*No alpha channel -> RGB*/
414 else {
415 c_base = *((const lv_color_t *) px_base);
416 c_hor = *((const lv_color_t *) px_hor);
417 c_ver = *((const lv_color_t *) px_ver);
418 abuf[x] = 0xff;
419 }
420
421 if(c_base.full == c_ver.full && c_base.full == c_hor.full) {
422 cbuf[x] = c_base;
423 }
424 else {
425 c_ver = lv_color_mix(c_ver, c_base, ys_fract);
426 c_hor = lv_color_mix(c_hor, c_base, xs_fract);
427 cbuf[x] = lv_color_mix(c_hor, c_ver, LV_OPA_50);
428 }
429 }
430 /*Partially out of the image*/
431 else {
432 #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
433 cbuf[x].full = src_tmp[0];
434 #elif LV_COLOR_DEPTH == 16
435 cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
436 #elif LV_COLOR_DEPTH == 32
437 cbuf[x].full = *((uint32_t *)src_tmp);
438 #endif
439 lv_opa_t a;
440 switch(cf) {
441 case LV_IMG_CF_TRUE_COLOR_ALPHA:
442 a = src_tmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
443 break;
444 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
445 a = cbuf[x].full == ck.full ? 0x00 : 0xff;
446 break;
447 #if LV_COLOR_DEPTH == 16
448 case LV_IMG_CF_RGB565A8:
449 a = *(src + src_stride * src_h * sizeof(lv_color_t) + (ys_int * src_stride) + xs_int);
450 break;
451 #endif
452 default:
453 a = 0xff;
454 }
455
456 if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0)) {
457 abuf[x] = (a * (0xFF - xs_fract)) >> 8;
458 }
459 else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0)) {
460 abuf[x] = (a * (0xFF - ys_fract)) >> 8;
461 }
462 else {
463 abuf[x] = 0x00;
464 }
465 }
466 }
467 }
468
transform_point_upscaled(point_transform_dsc_t * t,int32_t xin,int32_t yin,int32_t * xout,int32_t * yout)469 static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
470 int32_t * yout)
471 {
472 if(t->angle == 0 && t->zoom == LV_IMG_ZOOM_NONE) {
473 *xout = xin * 256;
474 *yout = yin * 256;
475 return;
476 }
477
478 xin -= t->pivot.x;
479 yin -= t->pivot.y;
480
481 if(t->angle == 0) {
482 *xout = ((int32_t)(xin * t->zoom)) + (t->pivot_x_256);
483 *yout = ((int32_t)(yin * t->zoom)) + (t->pivot_y_256);
484 }
485 else if(t->zoom == LV_IMG_ZOOM_NONE) {
486 *xout = ((t->cosma * xin - t->sinma * yin) >> 2) + (t->pivot_x_256);
487 *yout = ((t->sinma * xin + t->cosma * yin) >> 2) + (t->pivot_y_256);
488 }
489 else {
490 *xout = (((t->cosma * xin - t->sinma * yin) * t->zoom) >> 10) + (t->pivot_x_256);
491 *yout = (((t->sinma * xin + t->cosma * yin) * t->zoom) >> 10) + (t->pivot_y_256);
492 }
493 }
494
495 #endif
496
497