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 
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)267 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,
268                             int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
269                             int32_t x_end, lv_color_t * cbuf, uint8_t * abuf, lv_img_cf_t cf)
270 {
271     int32_t xs_ups_start = xs_ups;
272     int32_t ys_ups_start = ys_ups;
273     bool has_alpha;
274     int32_t px_size;
275     lv_color_t ck = _LV_COLOR_ZERO_INITIALIZER;
276     switch(cf) {
277         case LV_IMG_CF_TRUE_COLOR:
278             has_alpha = false;
279             px_size = sizeof(lv_color_t);
280             break;
281         case LV_IMG_CF_TRUE_COLOR_ALPHA:
282             has_alpha = true;
283             px_size = LV_IMG_PX_SIZE_ALPHA_BYTE;
284             break;
285         case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: {
286                 has_alpha = true;
287                 px_size = sizeof(lv_color_t);
288                 lv_disp_t * d = _lv_refr_get_disp_refreshing();
289                 ck = d->driver->color_chroma_key;
290                 break;
291             }
292 #if LV_COLOR_DEPTH == 16
293         case LV_IMG_CF_RGB565A8:
294             has_alpha = true;
295             px_size = sizeof(lv_color_t);
296             break;
297 #endif
298         default:
299             return;
300     }
301 
302     lv_coord_t x;
303     for(x = 0; x < x_end; x++) {
304         xs_ups = xs_ups_start + ((xs_step * x) >> 8);
305         ys_ups = ys_ups_start + ((ys_step * x) >> 8);
306 
307         int32_t xs_int = xs_ups >> 8;
308         int32_t ys_int = ys_ups >> 8;
309 
310         /*Fully out of the image*/
311         if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
312             abuf[x] = 0x00;
313             continue;
314         }
315 
316         /*Get the direction the hor and ver neighbor
317          *`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
318         int32_t xs_fract = xs_ups & 0xFF;
319         int32_t ys_fract = ys_ups & 0xFF;
320 
321         int32_t x_next;
322         int32_t y_next;
323         if(xs_fract < 0x80) {
324             x_next = -1;
325             xs_fract = (0x7F - xs_fract) * 2;
326         }
327         else {
328             x_next = 1;
329             xs_fract = (xs_fract - 0x80) * 2;
330         }
331         if(ys_fract < 0x80) {
332             y_next = -1;
333             ys_fract = (0x7F - ys_fract) * 2;
334         }
335         else {
336             y_next = 1;
337             ys_fract = (ys_fract - 0x80) * 2;
338         }
339 
340         const uint8_t * src_tmp = src;
341         src_tmp += (ys_int * src_stride * px_size) + xs_int * px_size;
342 
343         if(xs_int + x_next >= 0 &&
344            xs_int + x_next <= src_w - 1 &&
345            ys_int + y_next >= 0 &&
346            ys_int + y_next <= src_h - 1) {
347 
348             const uint8_t * px_base = src_tmp;
349             const uint8_t * px_hor = src_tmp + x_next * px_size;
350             const uint8_t * px_ver = src_tmp + y_next * src_stride * px_size;
351             lv_color_t c_base;
352             lv_color_t c_ver;
353             lv_color_t c_hor;
354 
355             if(has_alpha) {
356                 lv_opa_t a_base;
357                 lv_opa_t a_ver;
358                 lv_opa_t a_hor;
359                 if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
360                     a_base = px_base[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
361                     a_ver = px_ver[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
362                     a_hor = px_hor[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
363                 }
364 #if LV_COLOR_DEPTH == 16
365                 else if(cf == LV_IMG_CF_RGB565A8) {
366                     const lv_opa_t * a_tmp = src + src_stride * src_h * sizeof(lv_color_t);
367                     a_base = *(a_tmp + (ys_int * src_stride) + xs_int);
368                     a_hor = *(a_tmp + (ys_int * src_stride) + xs_int + x_next);
369                     a_ver = *(a_tmp + ((ys_int + y_next) * src_stride) + xs_int);
370                 }
371 #endif
372                 else if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
373                     if(((lv_color_t *)px_base)->full == ck.full ||
374                        ((lv_color_t *)px_ver)->full == ck.full ||
375                        ((lv_color_t *)px_hor)->full == ck.full) {
376                         abuf[x] = 0x00;
377                         continue;
378                     }
379                     else {
380                         a_base = 0xff;
381                         a_ver = 0xff;
382                         a_hor = 0xff;
383                     }
384                 }
385                 else {
386                     a_base = 0xff;
387                     a_ver = 0xff;
388                     a_hor = 0xff;
389                 }
390 
391                 if(a_ver != a_base) a_ver = ((a_ver * ys_fract) + (a_base * (0x100 - ys_fract))) >> 8;
392                 if(a_hor != a_base) a_hor = ((a_hor * xs_fract) + (a_base * (0x100 - xs_fract))) >> 8;
393                 abuf[x] = (a_ver + a_hor) >> 1;
394 
395                 if(abuf[x] == 0x00) continue;
396 
397 #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
398                 c_base.full = px_base[0];
399                 c_ver.full = px_ver[0];
400                 c_hor.full = px_hor[0];
401 #elif LV_COLOR_DEPTH == 16
402                 c_base.full = px_base[0] + (px_base[1] << 8);
403                 c_ver.full = px_ver[0] + (px_ver[1] << 8);
404                 c_hor.full = px_hor[0] + (px_hor[1] << 8);
405 #elif LV_COLOR_DEPTH == 32
406                 c_base.full = *((uint32_t *)px_base);
407                 c_ver.full = *((uint32_t *)px_ver);
408                 c_hor.full = *((uint32_t *)px_hor);
409 #endif
410             }
411             /*No alpha channel -> RGB*/
412             else {
413                 c_base = *((const lv_color_t *) px_base);
414                 c_hor = *((const lv_color_t *) px_hor);
415                 c_ver = *((const lv_color_t *) px_ver);
416                 abuf[x] = 0xff;
417             }
418 
419             if(c_base.full == c_ver.full && c_base.full == c_hor.full) {
420                 cbuf[x] = c_base;
421             }
422             else {
423                 c_ver = lv_color_mix(c_ver, c_base, ys_fract);
424                 c_hor = lv_color_mix(c_hor, c_base, xs_fract);
425                 cbuf[x] = lv_color_mix(c_hor, c_ver, LV_OPA_50);
426             }
427         }
428         /*Partially out of the image*/
429         else {
430 #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
431             cbuf[x].full = src_tmp[0];
432 #elif LV_COLOR_DEPTH == 16
433             cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8);
434 #elif LV_COLOR_DEPTH == 32
435             cbuf[x].full = *((uint32_t *)src_tmp);
436 #endif
437             lv_opa_t a;
438             switch(cf) {
439                 case LV_IMG_CF_TRUE_COLOR_ALPHA:
440                     a = src_tmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
441                     break;
442                 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
443                     a = cbuf[x].full == ck.full ? 0x00 : 0xff;
444                     break;
445 #if LV_COLOR_DEPTH == 16
446                 case LV_IMG_CF_RGB565A8:
447                     a = *(src + src_stride * src_h * sizeof(lv_color_t) + (ys_int * src_stride) + xs_int);
448                     break;
449 #endif
450                 default:
451                     a = 0xff;
452             }
453 
454             if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0))  {
455                 abuf[x] = (a * (0xFF - xs_fract)) >> 8;
456             }
457             else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0))  {
458                 abuf[x] = (a * (0xFF - ys_fract)) >> 8;
459             }
460             else {
461                 abuf[x] = 0x00;
462             }
463         }
464     }
465 }
466 
transform_point_upscaled(point_transform_dsc_t * t,int32_t xin,int32_t yin,int32_t * xout,int32_t * yout)467 static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
468                                      int32_t * yout)
469 {
470     if(t->angle == 0 && t->zoom == LV_IMG_ZOOM_NONE) {
471         *xout = xin * 256;
472         *yout = yin * 256;
473         return;
474     }
475 
476     xin -= t->pivot.x;
477     yin -= t->pivot.y;
478 
479     if(t->angle == 0) {
480         *xout = ((int32_t)(xin * t->zoom)) + (t->pivot_x_256);
481         *yout = ((int32_t)(yin * t->zoom)) + (t->pivot_y_256);
482     }
483     else if(t->zoom == LV_IMG_ZOOM_NONE) {
484         *xout = ((t->cosma * xin - t->sinma * yin) >> 2) + (t->pivot_x_256);
485         *yout = ((t->sinma * xin + t->cosma * yin) >> 2) + (t->pivot_y_256);
486     }
487     else {
488         *xout = (((t->cosma * xin - t->sinma * yin) * t->zoom) >> 10) + (t->pivot_x_256);
489         *yout = (((t->sinma * xin + t->cosma * yin) * t->zoom) >> 10) + (t->pivot_y_256);
490     }
491 }
492 
493 #endif
494