1 /**
2  * @file lv_draw_sw_transform.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_sw.h"
10 #if LV_USE_DRAW_SW
11 
12 #include "../../misc/lv_assert.h"
13 #include "../../misc/lv_area.h"
14 #include "../../core/lv_refr.h"
15 #include "../../misc/lv_color.h"
16 #include "../../stdlib/lv_string.h"
17 
18 /*********************
19  *      DEFINES
20  *********************/
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 typedef struct {
26     int32_t x_in;
27     int32_t y_in;
28     int32_t x_out;
29     int32_t y_out;
30     int32_t sinma;
31     int32_t cosma;
32     int32_t scale_x;
33     int32_t scale_y;
34     int32_t angle;
35     int32_t pivot_x_256;
36     int32_t pivot_y_256;
37     lv_point_t pivot;
38 } point_transform_dsc_t;
39 
40 /**********************
41  *  STATIC PROTOTYPES
42  **********************/
43 /**
44  * Transform a point with 1/256 precision (the output coordinates are upscaled by 256)
45  * @param t         pointer to n initialized `point_transform_dsc_t` structure
46  * @param xin       X coordinate to rotate
47  * @param yin       Y coordinate to rotate
48  * @param xout      upscaled, transformed X
49  * @param yout      upscaled, transformed Y
50  */
51 static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
52                                      int32_t * yout);
53 
54 #if LV_DRAW_SW_SUPPORT_RGB888 || LV_DRAW_SW_SUPPORT_XRGB8888
55 static void transform_rgb888(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
56                              int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
57                              int32_t x_end, uint8_t * dest_buf, bool aa, uint32_t px_size);
58 #endif
59 
60 #if LV_DRAW_SW_SUPPORT_ARGB8888
61 static void transform_argb8888(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
62                                int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
63                                int32_t x_end, uint8_t * dest_buf, bool aa);
64 #endif
65 
66 #if LV_DRAW_SW_SUPPORT_RGB565A8
67 static void transform_rgb565a8(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
68                                int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
69                                int32_t x_end, uint16_t * cbuf, uint8_t * abuf, bool src_has_a8, bool aa);
70 #endif
71 
72 #if LV_DRAW_SW_SUPPORT_A8
73 static void transform_a8(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
74                          int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
75                          int32_t x_end, uint8_t * abuf, bool aa);
76 #endif
77 
78 #if LV_DRAW_SW_SUPPORT_L8
79 #if LV_DRAW_SW_SUPPORT_AL88
80 static void transform_l8_to_al88(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
81                                  int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
82                                  int32_t x_end, uint8_t * abuf, bool aa);
83 #endif
84 #endif /*LV_DRAW_SW_SUPPORT_L8*/
85 
86 /**********************
87  *  STATIC VARIABLES
88  **********************/
89 
90 /**********************
91  *      MACROS
92  **********************/
93 
94 /**********************
95  *   GLOBAL FUNCTIONS
96  **********************/
97 
lv_draw_sw_transform(lv_draw_unit_t * draw_unit,const lv_area_t * dest_area,const void * src_buf,int32_t src_w,int32_t src_h,int32_t src_stride,const lv_draw_image_dsc_t * draw_dsc,const lv_draw_image_sup_t * sup,lv_color_format_t src_cf,void * dest_buf)98 void lv_draw_sw_transform(lv_draw_unit_t * draw_unit, const lv_area_t * dest_area, const void * src_buf,
99                           int32_t src_w, int32_t src_h, int32_t src_stride,
100                           const lv_draw_image_dsc_t * draw_dsc, const lv_draw_image_sup_t * sup, lv_color_format_t src_cf, void * dest_buf)
101 {
102     LV_UNUSED(draw_unit);
103     LV_UNUSED(sup);
104 
105     point_transform_dsc_t tr_dsc;
106     tr_dsc.angle = -draw_dsc->rotation;
107     tr_dsc.scale_x = draw_dsc->scale_x;
108     tr_dsc.scale_y = draw_dsc->scale_y;
109     tr_dsc.pivot = draw_dsc->pivot;
110 
111     int32_t angle_low = tr_dsc.angle / 10;
112     int32_t angle_high = angle_low + 1;
113     int32_t angle_rem = tr_dsc.angle  - (angle_low * 10);
114 
115     int32_t s1 = lv_trigo_sin(angle_low);
116     int32_t s2 = lv_trigo_sin(angle_high);
117 
118     int32_t c1 = lv_trigo_sin(angle_low + 90);
119     int32_t c2 = lv_trigo_sin(angle_high + 90);
120 
121     tr_dsc.sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
122     tr_dsc.cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
123     tr_dsc.sinma = tr_dsc.sinma >> (LV_TRIGO_SHIFT - 10);
124     tr_dsc.cosma = tr_dsc.cosma >> (LV_TRIGO_SHIFT - 10);
125     tr_dsc.pivot_x_256 = tr_dsc.pivot.x * 256;
126     tr_dsc.pivot_y_256 = tr_dsc.pivot.y * 256;
127 
128     int32_t dest_w = lv_area_get_width(dest_area);
129     int32_t dest_h = lv_area_get_height(dest_area);
130 
131     int32_t dest_stride_a8 = dest_w;
132     int32_t dest_stride;
133     if(src_cf == LV_COLOR_FORMAT_RGB888) {
134         dest_stride = dest_w * lv_color_format_get_size(LV_COLOR_FORMAT_ARGB8888);
135     }
136     else if((src_cf == LV_COLOR_FORMAT_RGB565A8) || (src_cf == LV_COLOR_FORMAT_L8)) {
137         dest_stride = dest_w * 2;
138     }
139     else {
140         dest_stride = dest_w * lv_color_format_get_size(src_cf);
141     }
142 
143     uint8_t * alpha_buf;
144     if(src_cf == LV_COLOR_FORMAT_RGB565 || src_cf == LV_COLOR_FORMAT_RGB565A8) {
145         alpha_buf = dest_buf;
146         alpha_buf += dest_stride * dest_h;
147     }
148     else {
149         alpha_buf = NULL;
150     }
151 
152     bool aa = (bool) draw_dsc->antialias;
153     bool is_rotated = draw_dsc->rotation;
154 
155     int32_t xs_ups = 0, ys_ups = 0, ys_ups_start = 0, ys_step_256_original = 0;
156     int32_t xs_step_256 = 0, ys_step_256 = 0;
157 
158     /*When some of the color formats are disabled, these variables could be unused, avoid warning here*/
159     LV_UNUSED(aa);
160     LV_UNUSED(xs_ups);
161     LV_UNUSED(ys_ups);
162     LV_UNUSED(xs_step_256);
163     LV_UNUSED(ys_step_256);
164 
165     /*If scaled only make some simplification to avoid rounding errors.
166      *For example if there is a 100x100 image zoomed to 300%
167      *The destination area in X will be x1=0; x2=299
168      *When the step is calculated below it will think that stepping
169      *1/3 pixels on the original image will result in 300% zoom.
170      *However this way the last pixel will be on the 99.67 coordinate.
171      *As it's larger than 99.5 LVGL will start to mix the next coordinate
172      *which is out of the image, so will make the pixel more transparent.
173      *To avoid it in case of scale only limit the coordinates to the 0..297 range,
174      *that is to 0..(src_w-1)*zoom */
175     if(is_rotated == false) {
176         int32_t xs1_ups, ys1_ups, xs2_ups, ys2_ups;
177 
178         int32_t x_max = (((src_w - 1 - draw_dsc->pivot.x) * draw_dsc->scale_x) >> 8) + draw_dsc->pivot.x;
179         int32_t y_max = (((src_h - 1 - draw_dsc->pivot.y) * draw_dsc->scale_y) >> 8) + draw_dsc->pivot.y;
180 
181         lv_area_t dest_area_limited;
182         dest_area_limited.x1 = dest_area->x1 > x_max ? x_max : dest_area->x1;
183         dest_area_limited.x2 = dest_area->x2 > x_max ? x_max : dest_area->x2;
184         dest_area_limited.y1 = dest_area->y1 > y_max ? y_max : dest_area->y1;
185         dest_area_limited.y2 = dest_area->y2 > y_max ? y_max : dest_area->y2;
186 
187         transform_point_upscaled(&tr_dsc, dest_area_limited.x1, dest_area_limited.y1, &xs1_ups, &ys1_ups);
188         transform_point_upscaled(&tr_dsc, dest_area_limited.x2, dest_area_limited.y2, &xs2_ups, &ys2_ups);
189 
190         int32_t xs_diff = xs2_ups - xs1_ups;
191         int32_t ys_diff = ys2_ups - ys1_ups;
192         xs_step_256 = 0;
193         ys_step_256_original = 0;
194         if(dest_w > 1) {
195             xs_step_256 = (256 * xs_diff) / (dest_w - 1);
196         }
197         if(dest_h > 1) {
198             ys_step_256_original = (256 * ys_diff) / (dest_h - 1);
199         }
200 
201         xs_ups = xs1_ups + 0x80;
202         ys_ups_start = ys1_ups + 0x80;
203     }
204 
205     int32_t y;
206     for(y = 0; y < dest_h; y++) {
207         if(is_rotated == false) {
208             ys_ups = ys_ups_start + ((ys_step_256_original * y) >> 8);
209             ys_step_256 = 0;
210         }
211         else {
212             int32_t xs1_ups, ys1_ups, xs2_ups, ys2_ups;
213             transform_point_upscaled(&tr_dsc, dest_area->x1, dest_area->y1 + y, &xs1_ups, &ys1_ups);
214             transform_point_upscaled(&tr_dsc, dest_area->x2, dest_area->y1 + y, &xs2_ups, &ys2_ups);
215 
216             int32_t xs_diff = xs2_ups - xs1_ups;
217             int32_t ys_diff = ys2_ups - ys1_ups;
218             xs_step_256 = 0;
219             ys_step_256 = 0;
220             if(dest_w > 1) {
221                 xs_step_256 = (256 * xs_diff) / (dest_w - 1);
222                 ys_step_256 = (256 * ys_diff) / (dest_w - 1);
223             }
224 
225             xs_ups = xs1_ups + 0x80;
226             ys_ups = ys1_ups + 0x80;
227         }
228 
229         switch(src_cf) {
230 #if LV_DRAW_SW_SUPPORT_XRGB8888
231             case LV_COLOR_FORMAT_XRGB8888:
232                 transform_rgb888(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, dest_buf, aa,
233                                  4);
234                 break;
235 #endif
236 #if LV_DRAW_SW_SUPPORT_RGB888
237             case LV_COLOR_FORMAT_RGB888:
238                 transform_rgb888(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, dest_buf, aa,
239                                  3);
240                 break;
241 #endif
242 #if LV_DRAW_SW_SUPPORT_A8
243             case LV_COLOR_FORMAT_A8:
244                 transform_a8(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, dest_buf, aa);
245                 break;
246 #endif
247 #if LV_DRAW_SW_SUPPORT_ARGB8888
248             case LV_COLOR_FORMAT_ARGB8888:
249                 transform_argb8888(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, dest_buf,
250                                    aa);
251                 break;
252 #endif
253 #if LV_DRAW_SW_SUPPORT_RGB565 && LV_DRAW_SW_SUPPORT_RGB565A8
254             case LV_COLOR_FORMAT_RGB565:
255                 transform_rgb565a8(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, dest_buf,
256                                    alpha_buf, false, aa);
257                 break;
258 #endif
259 #if LV_DRAW_SW_SUPPORT_RGB565A8
260             case LV_COLOR_FORMAT_RGB565A8:
261                 transform_rgb565a8(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w,
262                                    (uint16_t *)dest_buf,
263                                    alpha_buf, true, aa);
264                 break;
265 #endif
266 
267 #if LV_DRAW_SW_SUPPORT_L8 && LV_DRAW_SW_SUPPORT_AL88
268             case LV_COLOR_FORMAT_L8:
269                 transform_l8_to_al88(src_buf, src_w, src_h, src_stride, xs_ups, ys_ups, xs_step_256, ys_step_256, dest_w, dest_buf, aa);
270                 break;
271 #endif /*LV_DRAW_SW_SUPPORT_L8 && (LV_DRAW_SW_SUPPORT_ARGB8888 || LV_DRAW_SW_SUPPORT_AL88)*/
272             default:
273                 LV_LOG_WARN("Color format 0x%02X is not enabled. "
274                             "See lv_color.h to find the name of the color formats and "
275                             "enable the related LV_DRAW_SW_SUPPORT_* in lv_conf.h.",
276                             src_cf);
277                 return;
278         }
279 
280         dest_buf = (uint8_t *)dest_buf + dest_stride;
281         if(alpha_buf) alpha_buf += dest_stride_a8;
282     }
283 }
284 
285 /**********************
286  *   STATIC FUNCTIONS
287  **********************/
288 
289 #if LV_DRAW_SW_SUPPORT_RGB888 || LV_DRAW_SW_SUPPORT_XRGB8888
290 
transform_rgb888(const uint8_t * src,int32_t src_w,int32_t src_h,int32_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,uint8_t * dest_buf,bool aa,uint32_t px_size)291 static void transform_rgb888(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
292                              int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
293                              int32_t x_end, uint8_t * dest_buf, bool aa, uint32_t px_size)
294 {
295     int32_t xs_ups_start = xs_ups;
296     int32_t ys_ups_start = ys_ups;
297     lv_color32_t * dest_c32 = (lv_color32_t *) dest_buf;
298 
299     int32_t x;
300     for(x = 0; x < x_end; x++) {
301         xs_ups = xs_ups_start + ((xs_step * x) >> 8);
302         ys_ups = ys_ups_start + ((ys_step * x) >> 8);
303 
304         int32_t xs_int = xs_ups >> 8;
305         int32_t ys_int = ys_ups >> 8;
306 
307         /*Fully out of the image*/
308         if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
309             dest_c32[x].alpha = 0x00;
310             continue;
311         }
312 
313         /*Get the direction the hor and ver neighbor
314          *`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
315         int32_t xs_fract = xs_ups & 0xFF;
316         int32_t ys_fract = ys_ups & 0xFF;
317 
318         int32_t x_next;
319         int32_t y_next;
320         if(xs_fract < 0x80) {
321             x_next = -1;
322             xs_fract = 0x7F - xs_fract;
323         }
324         else {
325             x_next = 1;
326             xs_fract = xs_fract - 0x80;
327         }
328         if(ys_fract < 0x80) {
329             y_next = -1;
330             ys_fract = 0x7F - ys_fract;
331         }
332         else {
333             y_next = 1;
334             ys_fract = ys_fract - 0x80;
335         }
336 
337         const uint8_t * src_u8 = &src[ys_int * src_stride + xs_int * px_size];
338 
339         dest_c32[x].red = src_u8[2];
340         dest_c32[x].green = src_u8[1];
341         dest_c32[x].blue = src_u8[0];
342         dest_c32[x].alpha = 0xff;
343 
344         if(aa &&
345            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             const uint8_t * px_hor_u8 = src_u8 + (int32_t)(x_next * px_size);
350             lv_color32_t px_hor;
351             px_hor.red = px_hor_u8[2];
352             px_hor.green = px_hor_u8[1];
353             px_hor.blue = px_hor_u8[0];
354             px_hor.alpha = 0xff;
355 
356             const uint8_t * px_ver_u8 = src_u8 + (int32_t)(y_next * src_stride);
357             lv_color32_t px_ver;
358             px_ver.red = px_ver_u8[2];
359             px_ver.green = px_ver_u8[1];
360             px_ver.blue = px_ver_u8[0];
361             px_ver.alpha = 0xff;
362 
363             if(!lv_color32_eq(dest_c32[x], px_ver)) {
364                 px_ver.alpha = ys_fract;
365                 dest_c32[x] = lv_color_mix32(px_ver, dest_c32[x]);
366             }
367 
368             if(!lv_color32_eq(dest_c32[x], px_hor)) {
369                 px_hor.alpha = xs_fract;
370                 dest_c32[x] = lv_color_mix32(px_hor, dest_c32[x]);
371             }
372         }
373         /*Partially out of the image*/
374         else {
375             lv_opa_t a = 0xff;
376 
377             if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0))  {
378                 dest_c32[x].alpha = (a * (0xFF - xs_fract)) >> 8;
379             }
380             else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0))  {
381                 dest_c32[x].alpha = (a * (0xFF - ys_fract)) >> 8;
382             }
383         }
384     }
385 }
386 
387 #endif
388 
389 #if LV_DRAW_SW_SUPPORT_ARGB8888
390 
transform_argb8888(const uint8_t * src,int32_t src_w,int32_t src_h,int32_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,uint8_t * dest_buf,bool aa)391 static void transform_argb8888(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
392                                int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
393                                int32_t x_end, uint8_t * dest_buf, bool aa)
394 {
395     int32_t xs_ups_start = xs_ups;
396     int32_t ys_ups_start = ys_ups;
397     lv_color32_t * dest_c32 = (lv_color32_t *) dest_buf;
398 
399     int32_t x;
400     for(x = 0; x < x_end; x++) {
401         xs_ups = xs_ups_start + ((xs_step * x) >> 8);
402         ys_ups = ys_ups_start + ((ys_step * x) >> 8);
403 
404         int32_t xs_int = xs_ups >> 8;
405         int32_t ys_int = ys_ups >> 8;
406 
407         /*Fully out of the image*/
408         if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
409             ((uint32_t *)dest_buf)[x] = 0x00000000;
410             continue;
411         }
412 
413         /*Get the direction the hor and ver neighbor
414          *`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
415         int32_t xs_fract = xs_ups & 0xFF;
416         int32_t ys_fract = ys_ups & 0xFF;
417 
418         int32_t x_next;
419         int32_t y_next;
420         if(xs_fract < 0x80) {
421             x_next = -1;
422             xs_fract = 0x7F - xs_fract;
423         }
424         else {
425             x_next = 1;
426             xs_fract = xs_fract - 0x80;
427         }
428         if(ys_fract < 0x80) {
429             y_next = -1;
430             ys_fract = 0x7F - ys_fract;
431         }
432         else {
433             y_next = 1;
434             ys_fract = ys_fract - 0x80;
435         }
436 
437         const lv_color32_t * src_c32 = (const lv_color32_t *)(src + ys_int * src_stride + xs_int * 4);
438 
439         dest_c32[x] = src_c32[0];
440 
441         if(aa &&
442            xs_int + x_next >= 0 &&
443            xs_int + x_next <= src_w - 1 &&
444            ys_int + y_next >= 0 &&
445            ys_int + y_next <= src_h - 1) {
446 
447             lv_color32_t px_hor = src_c32[x_next];
448             lv_color32_t px_ver = *(const lv_color32_t *)((uint8_t *)src_c32 + y_next * src_stride);
449 
450             if(px_ver.alpha == 0) {
451                 dest_c32[x].alpha = (dest_c32[x].alpha * (0xFF - ys_fract)) >> 8;
452             }
453             else if(!lv_color32_eq(dest_c32[x], px_ver)) {
454                 if(dest_c32[x].alpha) dest_c32[x].alpha = ((px_ver.alpha * ys_fract) + (dest_c32[x].alpha * (0xFF - ys_fract))) >> 8;
455                 px_ver.alpha = ys_fract;
456                 dest_c32[x] = lv_color_mix32(px_ver, dest_c32[x]);
457             }
458 
459             if(px_hor.alpha == 0) {
460                 dest_c32[x].alpha = (dest_c32[x].alpha * (0xFF - xs_fract)) >> 8;
461             }
462             else if(!lv_color32_eq(dest_c32[x], px_hor)) {
463                 if(dest_c32[x].alpha) dest_c32[x].alpha = ((px_hor.alpha * xs_fract) + (dest_c32[x].alpha * (0xFF - xs_fract))) >> 8;
464                 px_hor.alpha = xs_fract;
465                 dest_c32[x] = lv_color_mix32(px_hor, dest_c32[x]);
466             }
467         }
468         /*Partially out of the image*/
469         else {
470             if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0))  {
471                 dest_c32[x].alpha = (dest_c32[x].alpha * (0x7F - xs_fract)) >> 7;
472             }
473             else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0))  {
474                 dest_c32[x].alpha = (dest_c32[x].alpha * (0x7F - ys_fract)) >> 7;
475             }
476         }
477     }
478 }
479 
480 #endif
481 
482 #if LV_DRAW_SW_SUPPORT_RGB565A8
483 
transform_rgb565a8(const uint8_t * src,int32_t src_w,int32_t src_h,int32_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,uint16_t * cbuf,uint8_t * abuf,bool src_has_a8,bool aa)484 static void transform_rgb565a8(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
485                                int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
486                                int32_t x_end, uint16_t * cbuf, uint8_t * abuf, bool src_has_a8, bool aa)
487 {
488     int32_t xs_ups_start = xs_ups;
489     int32_t ys_ups_start = ys_ups;
490 
491     const lv_opa_t * src_alpha = src + src_stride * src_h;
492 
493     /*Must be signed type, because we would use negative array index calculated from stride*/
494     int32_t alpha_stride = src_stride / 2; /*alpha map stride is always half of RGB map stride*/
495 
496     int32_t x;
497     for(x = 0; x < x_end; x++) {
498         xs_ups = xs_ups_start + ((xs_step * x) >> 8);
499         ys_ups = ys_ups_start + ((ys_step * x) >> 8);
500 
501         int32_t xs_int = xs_ups >> 8;
502         int32_t ys_int = ys_ups >> 8;
503 
504         /*Fully out of the image*/
505         if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
506             abuf[x] = 0x00;
507             continue;
508         }
509 
510         /*Get the direction the hor and ver neighbor
511          *`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
512         int32_t xs_fract = xs_ups & 0xFF;
513         int32_t ys_fract = ys_ups & 0xFF;
514 
515         int32_t x_next;
516         int32_t y_next;
517         if(xs_fract < 0x80) {
518             x_next = -1;
519             xs_fract = (0x7F - xs_fract) * 2;
520         }
521         else {
522             x_next = 1;
523             xs_fract = (xs_fract - 0x80) * 2;
524         }
525         if(ys_fract < 0x80) {
526             y_next = -1;
527             ys_fract = (0x7F - ys_fract) * 2;
528         }
529         else {
530             y_next = 1;
531             ys_fract = (ys_fract - 0x80) * 2;
532         }
533 
534         const uint16_t * src_tmp_u16 = (const uint16_t *)(src + (ys_int * src_stride) + xs_int * 2);
535         cbuf[x] = src_tmp_u16[0];
536 
537         if(aa &&
538            xs_int + x_next >= 0 &&
539            xs_int + x_next <= src_w - 1 &&
540            ys_int + y_next >= 0 &&
541            ys_int + y_next <= src_h - 1) {
542 
543             uint16_t px_hor = src_tmp_u16[x_next];
544             uint16_t px_ver = *(const uint16_t *)((uint8_t *)src_tmp_u16 + (y_next * src_stride));
545 
546             if(src_has_a8) {
547                 const lv_opa_t * src_alpha_tmp = src_alpha;
548                 src_alpha_tmp += (ys_int * alpha_stride) + xs_int;
549                 abuf[x] = src_alpha_tmp[0];
550 
551                 lv_opa_t a_hor = src_alpha_tmp[x_next];
552                 lv_opa_t a_ver = src_alpha_tmp[y_next * alpha_stride];
553 
554                 if(a_ver != abuf[x]) a_ver = ((a_ver * ys_fract) + (abuf[x] * (0x100 - ys_fract))) >> 8;
555                 if(a_hor != abuf[x]) a_hor = ((a_hor * xs_fract) + (abuf[x] * (0x100 - xs_fract))) >> 8;
556                 abuf[x] = (a_ver + a_hor) >> 1;
557 
558                 if(abuf[x] == 0x00) continue;
559             }
560             else {
561                 abuf[x] = 0xff;
562             }
563 
564             if(cbuf[x] != px_ver || cbuf[x] != px_hor) {
565                 uint16_t v = lv_color_16_16_mix(px_ver, cbuf[x], ys_fract);
566                 uint16_t h = lv_color_16_16_mix(px_hor, cbuf[x], xs_fract);
567                 cbuf[x] = lv_color_16_16_mix(h, v, LV_OPA_50);
568             }
569         }
570         /*Partially out of the image*/
571         else {
572             lv_opa_t a;
573             if(src_has_a8) {
574                 const lv_opa_t * src_alpha_tmp = src_alpha;
575                 src_alpha_tmp += (ys_int * alpha_stride) + xs_int;
576                 a = src_alpha_tmp[0];
577             }
578             else {
579                 a = 0xff;
580             }
581 
582             if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0))  {
583                 abuf[x] = (a * (0xFF - xs_fract)) >> 8;
584             }
585             else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0))  {
586                 abuf[x] = (a * (0xFF - ys_fract)) >> 8;
587             }
588             else {
589                 abuf[x] = a;
590             }
591         }
592     }
593 }
594 
595 #endif
596 
597 #if LV_DRAW_SW_SUPPORT_A8
598 
transform_a8(const uint8_t * src,int32_t src_w,int32_t src_h,int32_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,uint8_t * abuf,bool aa)599 static void transform_a8(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
600                          int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
601                          int32_t x_end, uint8_t * abuf, bool aa)
602 {
603     int32_t xs_ups_start = xs_ups;
604     int32_t ys_ups_start = ys_ups;
605 
606     int32_t x;
607     for(x = 0; x < x_end; x++) {
608         xs_ups = xs_ups_start + ((xs_step * x) >> 8);
609         ys_ups = ys_ups_start + ((ys_step * x) >> 8);
610 
611         int32_t xs_int = xs_ups >> 8;
612         int32_t ys_int = ys_ups >> 8;
613 
614         /*Fully out of the image*/
615         if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
616             abuf[x] = 0x00;
617             continue;
618         }
619 
620         /*Get the direction the hor and ver neighbor
621          *`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
622         int32_t xs_fract = xs_ups & 0xFF;
623         int32_t ys_fract = ys_ups & 0xFF;
624 
625         int32_t x_next;
626         int32_t y_next;
627         if(xs_fract < 0x80) {
628             x_next = -1;
629             xs_fract = (0x7F - xs_fract) * 2;
630         }
631         else {
632             x_next = 1;
633             xs_fract = (xs_fract - 0x80) * 2;
634         }
635         if(ys_fract < 0x80) {
636             y_next = -1;
637             ys_fract = (0x7F - ys_fract) * 2;
638         }
639         else {
640             y_next = 1;
641             ys_fract = (ys_fract - 0x80) * 2;
642         }
643 
644         const uint8_t * src_tmp = src;
645         src_tmp += ys_int * src_stride + xs_int;
646         abuf[x] = src_tmp[0];
647 
648         if(aa &&
649            xs_int + x_next >= 0 &&
650            xs_int + x_next <= src_w - 1 &&
651            ys_int + y_next >= 0 &&
652            ys_int + y_next <= src_h - 1) {
653 
654             lv_opa_t a_ver = src_tmp[x_next];
655             lv_opa_t a_hor = src_tmp[y_next * src_stride];
656 
657             if(a_ver != abuf[x]) a_ver = ((a_ver * ys_fract) + (abuf[x] * (0x100 - ys_fract))) >> 8;
658             if(a_hor != abuf[x]) a_hor = ((a_hor * xs_fract) + (abuf[x] * (0x100 - xs_fract))) >> 8;
659             abuf[x] = (a_ver + a_hor) >> 1;
660         }
661         else {
662             /*Partially out of the image*/
663             if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0))  {
664                 abuf[x] = (src_tmp[0] * (0xFF - xs_fract)) >> 8;
665             }
666             else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0))  {
667                 abuf[x] = (src_tmp[0] * (0xFF - ys_fract)) >> 8;
668             }
669         }
670     }
671 }
672 
673 #endif
674 
675 #if LV_DRAW_SW_SUPPORT_L8 && LV_DRAW_SW_SUPPORT_AL88
676 
transform_l8_to_al88(const uint8_t * src,int32_t src_w,int32_t src_h,int32_t src_stride,int32_t xs_ups,int32_t ys_ups,int32_t xs_step,int32_t ys_step,int32_t x_end,uint8_t * dest_buf,bool aa)677 static void transform_l8_to_al88(const uint8_t * src, int32_t src_w, int32_t src_h, int32_t src_stride,
678                                  int32_t xs_ups, int32_t ys_ups, int32_t xs_step, int32_t ys_step,
679                                  int32_t x_end, uint8_t * dest_buf, bool aa)
680 {
681     int32_t xs_ups_start = xs_ups;
682     int32_t ys_ups_start = ys_ups;
683     lv_color16a_t * dest_al88 = (lv_color16a_t *)dest_buf;
684 
685     int32_t x;
686     for(x = 0; x < x_end; x++) {
687         xs_ups = xs_ups_start + ((xs_step * x) >> 8);
688         ys_ups = ys_ups_start + ((ys_step * x) >> 8);
689 
690         int32_t xs_int = xs_ups >> 8;
691         int32_t ys_int = ys_ups >> 8;
692 
693         /*Fully out of the image*/
694         if(xs_int < 0 || xs_int >= src_w || ys_int < 0 || ys_int >= src_h) {
695             dest_al88[x].lumi = 0x00;
696             dest_al88[x].alpha = 0x00;
697             continue;
698         }
699 
700         /*Get the direction the hor and ver neighbor
701          *`fract` will be in range of 0x00..0xFF and `next` (+/-1) indicates the direction*/
702         int32_t xs_fract = xs_ups & 0xFF;
703         int32_t ys_fract = ys_ups & 0xFF;
704 
705         int32_t x_next;
706         int32_t y_next;
707         if(xs_fract < 0x80) {
708             x_next = -1;
709             xs_fract = (0x7F - xs_fract) * 2;
710         }
711         else {
712             x_next = 1;
713             xs_fract = (xs_fract - 0x80) * 2;
714         }
715         if(ys_fract < 0x80) {
716             y_next = -1;
717             ys_fract = (0x7F - ys_fract) * 2;
718         }
719         else {
720             y_next = 1;
721             ys_fract = (ys_fract - 0x80) * 2;
722         }
723 
724         const uint8_t * src_tmp = src;
725         src_tmp += ys_int * src_stride + xs_int;
726         dest_al88[x].lumi = src_tmp[0];
727         dest_al88[x].alpha = 255;
728         if(aa &&
729            xs_int + x_next >= 0 &&
730            xs_int + x_next <= src_w - 1 &&
731            ys_int + y_next >= 0 &&
732            ys_int + y_next <= src_h - 1) {
733 
734             lv_opa_t a_ver = src_tmp[x_next];
735             lv_opa_t a_hor = src_tmp[y_next * src_stride];
736 
737             if(a_ver != dest_al88[x].lumi) a_ver = ((a_ver * ys_fract) + (dest_al88[x].lumi * (0x100 - ys_fract))) >> 8;
738             if(a_hor != dest_al88[x].lumi) a_hor = ((a_hor * xs_fract) + (dest_al88[x].lumi * (0x100 - xs_fract))) >> 8;
739             dest_al88[x].lumi = (a_ver + a_hor) >> 1;
740         }
741         else {
742             /*Partially out of the image*/
743             if((xs_int == 0 && x_next < 0) || (xs_int == src_w - 1 && x_next > 0)) {
744                 dest_al88[x].alpha = (src_tmp[0] * (0xFF - xs_fract)) >> 8;
745             }
746             else if((ys_int == 0 && y_next < 0) || (ys_int == src_h - 1 && y_next > 0)) {
747                 dest_al88[x].alpha = (src_tmp[0] * (0xFF - ys_fract)) >> 8;
748             }
749         }
750     }
751 }
752 
753 #endif /*LV_DRAW_SW_SUPPORT_L8 && LV_DRAW_SW_SUPPORT_AL88*/
754 
transform_point_upscaled(point_transform_dsc_t * t,int32_t xin,int32_t yin,int32_t * xout,int32_t * yout)755 static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int32_t yin, int32_t * xout,
756                                      int32_t * yout)
757 {
758     if(t->angle == 0 && t->scale_x == LV_SCALE_NONE && t->scale_y == LV_SCALE_NONE) {
759         *xout = xin * 256;
760         *yout = yin * 256;
761         return;
762     }
763 
764     xin -= t->pivot.x;
765     yin -= t->pivot.y;
766 
767     if(t->angle == 0) {
768         *xout = ((int32_t)(xin * 256 * 256 / t->scale_x)) + (t->pivot_x_256);
769         *yout = ((int32_t)(yin * 256 * 256 / t->scale_y)) + (t->pivot_y_256);
770     }
771     else if(t->scale_x == LV_SCALE_NONE && t->scale_y == LV_SCALE_NONE) {
772         *xout = ((t->cosma * xin - t->sinma * yin) >> 2) + (t->pivot_x_256);
773         *yout = ((t->sinma * xin + t->cosma * yin) >> 2) + (t->pivot_y_256);
774     }
775     else {
776         *xout = (((t->cosma * xin - t->sinma * yin) * 256 / t->scale_x) >> 2) + (t->pivot_x_256);
777         *yout = (((t->sinma * xin + t->cosma * yin) * 256 / t->scale_y) >> 2) + (t->pivot_y_256);
778     }
779 }
780 
781 #endif /*LV_USE_DRAW_SW*/
782