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