1 /**
2 * @file lv_draw_sw_blend.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_draw_sw.h"
10 #include "../../misc/lv_math.h"
11 #include "../../hal/lv_hal_disp.h"
12 #include "../../core/lv_refr.h"
13
14 /*********************
15 * DEFINES
16 *********************/
17
18 /**********************
19 * TYPEDEFS
20 **********************/
21
22 /**********************
23 * STATIC PROTOTYPES
24 **********************/
25
26 static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride,
27 lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide);
28 LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
29 lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
30 #if LV_DRAW_COMPLEX
31 static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, lv_color_t color,
32 lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
33 #endif /*LV_DRAW_COMPLEX*/
34
35 static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
36 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
37
38 LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
39 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
40
41 #if LV_DRAW_COMPLEX
42 static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
43 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
44 const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
45
46 static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
47 static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
48 static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
49 #endif /*LV_DRAW_COMPLEX*/
50
51 /**********************
52 * STATIC VARIABLES
53 **********************/
54
55 /**********************
56 * MACROS
57 **********************/
58 #if LV_COLOR_SCREEN_TRANSP == 0
59 #define FILL_NORMAL_MASK_PX(color) \
60 if(*mask == LV_OPA_COVER) *dest_buf = color; \
61 else *dest_buf = lv_color_mix(color, *dest_buf, *mask); \
62 mask++; \
63 dest_buf++;
64
65 #else
66 #define FILL_NORMAL_MASK_PX(color) \
67 if(*mask == LV_OPA_COVER) *dest_buf = color; \
68 else if(disp->driver->screen_transp) lv_color_mix_with_alpha(*dest_buf, dest_buf->ch.alpha, color, *mask, dest_buf, &dest_buf->ch.alpha); \
69 else *dest_buf = lv_color_mix(color, *dest_buf, *mask); \
70 mask++; \
71 dest_buf++;
72 #endif
73
74 #define MAP_NORMAL_MASK_PX(x) \
75 if(*mask_tmp_x) { \
76 if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x]; \
77 else dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], *mask_tmp_x); \
78 } \
79 mask_tmp_x++;
80
81 #define MAP_NORMAL_MASK_PX_SCR_TRANSP(x) \
82 if(*mask_tmp_x) { \
83 if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x]; \
84 else if(disp->driver->screen_transp) lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, \
85 src_buf[x], *mask_tmp_x, &dest_buf[x], &dest_buf[x].ch.alpha); \
86 else dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], *mask_tmp_x); \
87 } \
88 mask_tmp_x++;
89
90
91 /**********************
92 * GLOBAL FUNCTIONS
93 **********************/
94
lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)95 void lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
96 {
97 /*Do not draw transparent things*/
98 if(dsc->opa <= LV_OPA_MIN) return;
99
100 lv_area_t blend_area;
101 if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
102
103 if(draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx);
104
105 ((lv_draw_sw_ctx_t *)draw_ctx)->blend(draw_ctx, dsc);
106 }
107
lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)108 LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
109 {
110 const lv_opa_t * mask;
111 if(dsc->mask_buf == NULL) mask = NULL;
112 if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
113 else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
114 else mask = dsc->mask_buf;
115
116 lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
117
118 lv_area_t blend_area;
119 if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
120
121 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
122 lv_color_t * dest_buf = draw_ctx->buf;
123 if(disp->driver->set_px_cb == NULL) {
124 dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
125 }
126
127 const lv_color_t * src_buf = dsc->src_buf;
128 lv_coord_t src_stride;
129 if(src_buf) {
130 src_stride = lv_area_get_width(dsc->blend_area);
131 src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1);
132 }
133 else {
134 src_stride = 0;
135 }
136
137 lv_coord_t mask_stride;
138 if(mask) {
139 mask_stride = lv_area_get_width(dsc->mask_area);
140 mask += mask_stride * (dsc->mask_area->y1 - blend_area.y1) + (dsc->mask_area->x1 - blend_area.x1);
141 }
142 else {
143 mask_stride = 0;
144 }
145
146 lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
147
148
149 if(disp->driver->set_px_cb) {
150 if(dsc->src_buf == NULL) {
151 fill_set_px(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
152 }
153 else {
154 map_set_px(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
155 }
156 }
157 else if(dsc->src_buf == NULL) {
158 if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
159 fill_normal(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
160 }
161 #if LV_DRAW_COMPLEX
162 else {
163 fill_blended(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride, dsc->blend_mode);
164 }
165 #endif
166 }
167 else {
168 if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
169 map_normal(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
170 }
171 #if LV_DRAW_COMPLEX
172 else {
173 map_blended(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride, dsc->blend_mode);
174 }
175 #endif
176 }
177 }
178
179
180 /**********************
181 * STATIC FUNCTIONS
182 **********************/
183
fill_set_px(lv_color_t * dest_buf,const lv_area_t * blend_area,lv_coord_t dest_stride,lv_color_t color,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stide)184 static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride,
185 lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide)
186 {
187 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
188
189 int32_t x;
190 int32_t y;
191
192 if(mask == NULL) {
193 for(y = blend_area->y1; y <= blend_area->y2; y++) {
194 for(x = blend_area->x1; x <= blend_area->x2; x++) {
195 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, x, y, color, opa);
196 }
197 }
198 }
199 else {
200 int32_t w = lv_area_get_width(blend_area);
201 int32_t h = lv_area_get_height(blend_area);
202
203 for(y = 0; y < h; y++) {
204 for(x = 0; x < w; x++) {
205 if(mask[x]) {
206 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, blend_area->x1 + x, blend_area->y1 + y, color,
207 (uint32_t)((uint32_t)opa * mask[x]) >> 8);
208 }
209 }
210 mask += mask_stide;
211 }
212 }
213 }
214
fill_normal(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,lv_color_t color,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride)215 LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
216 lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
217 {
218 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
219 int32_t w = lv_area_get_width(dest_area);
220 int32_t h = lv_area_get_height(dest_area);
221
222 int32_t x;
223 int32_t y;
224
225 /*No mask*/
226 if(mask == NULL) {
227 if(opa >= LV_OPA_MAX) {
228 for(y = 0; y < h; y++) {
229 lv_color_fill(dest_buf, color, w);
230 dest_buf += dest_stride;
231 }
232 }
233 /*Has opacity*/
234 else {
235 lv_color_t last_dest_color = lv_color_black();
236 lv_color_t last_res_color = lv_color_mix(color, last_dest_color, opa);
237
238 uint16_t color_premult[3];
239 lv_color_premult(color, opa, color_premult);
240 lv_opa_t opa_inv = 255 - opa;
241
242 for(y = 0; y < h; y++) {
243 for(x = 0; x < w; x++) {
244 if(last_dest_color.full != dest_buf[x].full) {
245 last_dest_color = dest_buf[x];
246
247 #if LV_COLOR_SCREEN_TRANSP
248 if(disp->driver->screen_transp) {
249 lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa, &last_res_color,
250 &last_res_color.ch.alpha);
251 }
252 else
253 #else
254 LV_UNUSED(disp);
255 #endif
256 {
257 last_res_color = lv_color_mix_premult(color_premult, dest_buf[x], opa_inv);
258 }
259 }
260 dest_buf[x] = last_res_color;
261 }
262 dest_buf += dest_stride;
263 }
264 }
265 }
266 /*Masked*/
267 else {
268 #if LV_COLOR_DEPTH == 16
269 uint32_t c32 = color.full + ((uint32_t)color.full << 16);
270 #endif
271 /*Only the mask matters*/
272 if(opa >= LV_OPA_MAX) {
273 int32_t x_end4 = w - 4;
274 for(y = 0; y < h; y++) {
275 for(x = 0; x < w && ((lv_uintptr_t)(mask) & 0x3); x++) {
276 FILL_NORMAL_MASK_PX(color)
277 }
278
279 for(; x <= x_end4; x += 4) {
280 uint32_t mask32 = *((uint32_t *)mask);
281 if(mask32 == 0xFFFFFFFF) {
282 #if LV_COLOR_DEPTH == 16
283 if((lv_uintptr_t)dest_buf & 0x3) {
284 *(dest_buf + 0) = color;
285 uint32_t * d = (uint32_t *)(dest_buf + 1);
286 *d = c32;
287 *(dest_buf + 3) = color;
288 }
289 else {
290 uint32_t * d = (uint32_t *)dest_buf;
291 *d = c32;
292 *(d + 1) = c32;
293 }
294 #else
295 dest_buf[0] = color;
296 dest_buf[1] = color;
297 dest_buf[2] = color;
298 dest_buf[3] = color;
299 #endif
300 dest_buf += 4;
301 mask += 4;
302 }
303 else if(mask32) {
304 FILL_NORMAL_MASK_PX(color)
305 FILL_NORMAL_MASK_PX(color)
306 FILL_NORMAL_MASK_PX(color)
307 FILL_NORMAL_MASK_PX(color)
308 }
309 else {
310 mask += 4;
311 dest_buf += 4;
312 }
313 }
314
315 for(; x < w ; x++) {
316 FILL_NORMAL_MASK_PX(color)
317 }
318 dest_buf += (dest_stride - w);
319 mask += (mask_stride - w);
320 }
321 }
322 /*With opacity*/
323 else {
324 /*Buffer the result color to avoid recalculating the same color*/
325 lv_color_t last_dest_color;
326 lv_color_t last_res_color;
327 lv_opa_t last_mask = LV_OPA_TRANSP;
328 last_dest_color.full = dest_buf[0].full;
329 last_res_color.full = dest_buf[0].full;
330 lv_opa_t opa_tmp = LV_OPA_TRANSP;
331
332 for(y = 0; y < h; y++) {
333 for(x = 0; x < w; x++) {
334 if(*mask) {
335 if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa :
336 (uint32_t)((uint32_t)(*mask) * opa) >> 8;
337 if(*mask != last_mask || last_dest_color.full != dest_buf[x].full) {
338 #if LV_COLOR_SCREEN_TRANSP
339 if(disp->driver->screen_transp) {
340 lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa_tmp, &last_res_color,
341 &last_res_color.ch.alpha);
342 }
343 else
344 #endif
345 {
346 if(opa_tmp == LV_OPA_COVER) last_res_color = color;
347 else last_res_color = lv_color_mix(color, dest_buf[x], opa_tmp);
348 }
349 last_mask = *mask;
350 last_dest_color.full = dest_buf[x].full;
351 }
352 dest_buf[x] = last_res_color;
353 }
354 mask++;
355 }
356 dest_buf += dest_stride;
357 mask += (mask_stride - w);
358 }
359 }
360 }
361 }
362
363 #if LV_DRAW_COMPLEX
fill_blended(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,lv_color_t color,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride,lv_blend_mode_t blend_mode)364 static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area,
365 lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride,
366 lv_blend_mode_t blend_mode)
367 {
368
369 int32_t w = lv_area_get_width(dest_area);
370 int32_t h = lv_area_get_height(dest_area);
371
372 int32_t x;
373 int32_t y;
374
375 lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t);
376 switch(blend_mode) {
377 case LV_BLEND_MODE_ADDITIVE:
378 blend_fp = color_blend_true_color_additive;
379 break;
380 case LV_BLEND_MODE_SUBTRACTIVE:
381 blend_fp = color_blend_true_color_subtractive;
382 break;
383 case LV_BLEND_MODE_MULTIPLY:
384 blend_fp = color_blend_true_color_multiply;
385 break;
386 default:
387 LV_LOG_WARN("fill_blended: unsupported blend mode");
388 return;
389 }
390
391 /*Simple fill (maybe with opacity), no masking*/
392 if(mask == NULL) {
393 lv_color_t last_dest_color = dest_buf[0];
394 lv_color_t last_res_color = blend_fp(color, dest_buf[0], opa);
395 for(y = 0; y < h; y++) {
396 for(x = 0; x < w; x++) {
397 if(last_dest_color.full != dest_buf[x].full) {
398 last_dest_color = dest_buf[x];
399 last_res_color = blend_fp(color, dest_buf[x], opa);
400 }
401 dest_buf[x] = last_res_color;
402 }
403 dest_buf += dest_stride;
404 }
405 }
406 /*Masked*/
407 else {
408 /*Buffer the result color to avoid recalculating the same color*/
409 lv_color_t last_dest_color;
410 lv_color_t last_res_color;
411 lv_opa_t last_mask = LV_OPA_TRANSP;
412 last_dest_color = dest_buf[0];
413 lv_opa_t opa_tmp = mask[0] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[0] * opa) >> 8;
414 last_res_color = blend_fp(color, last_dest_color, opa_tmp);
415
416 for(y = 0; y < h; y++) {
417 for(x = 0; x < w; x++) {
418 if(mask[x] == 0) continue;
419 if(mask[x] != last_mask || last_dest_color.full != dest_buf[x].full) {
420 opa_tmp = mask[x] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[x] * opa) >> 8;
421
422 last_res_color = blend_fp(color, dest_buf[x], opa_tmp);
423 last_mask = mask[x];
424 last_dest_color.full = dest_buf[x].full;
425 }
426 dest_buf[x] = last_res_color;
427 }
428 dest_buf += dest_stride;
429 mask += mask_stride;
430 }
431 }
432 }
433 #endif
434
map_set_px(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_coord_t src_stride,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride)435 static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
436 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
437
438 {
439 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
440
441 int32_t w = lv_area_get_width(dest_area);
442 int32_t h = lv_area_get_height(dest_area);
443
444 int32_t x;
445 int32_t y;
446
447 if(mask == NULL) {
448 for(y = 0; y < h; y++) {
449 for(x = 0; x < w; x++) {
450 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, dest_area->x1 + x, dest_area->y1 + y, src_buf[x],
451 opa);
452 }
453 src_buf += src_stride;
454 }
455 }
456 else {
457 for(y = 0; y < h; y++) {
458 for(x = 0; x < w; x++) {
459 if(mask[x]) {
460 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, dest_area->x1 + x, dest_area->y1 + y, src_buf[x],
461 (uint32_t)((uint32_t)opa * mask[x]) >> 8);
462 }
463 }
464 mask += mask_stride;
465 src_buf += src_stride;
466 }
467 }
468 }
469
map_normal(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_coord_t src_stride,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride)470 LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
471 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
472
473 {
474 int32_t w = lv_area_get_width(dest_area);
475 int32_t h = lv_area_get_height(dest_area);
476
477 int32_t x;
478 int32_t y;
479
480 #if LV_COLOR_SCREEN_TRANSP
481 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
482 #endif
483
484 /*Simple fill (maybe with opacity), no masking*/
485 if(mask == NULL) {
486 if(opa >= LV_OPA_MAX) {
487 for(y = 0; y < h; y++) {
488 lv_memcpy(dest_buf, src_buf, w * sizeof(lv_color_t));
489 dest_buf += dest_stride;
490 src_buf += src_stride;
491 }
492 }
493 else {
494 for(y = 0; y < h; y++) {
495 for(x = 0; x < w; x++) {
496 #if LV_COLOR_SCREEN_TRANSP
497 if(disp->driver->screen_transp) {
498 lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa, &dest_buf[x],
499 &dest_buf[x].ch.alpha);
500 }
501 else
502 #endif
503 {
504 dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa);
505 }
506 }
507 dest_buf += dest_stride;
508 src_buf += src_stride;
509 }
510 }
511 }
512 /*Masked*/
513 else {
514 /*Only the mask matters*/
515 if(opa > LV_OPA_MAX) {
516 int32_t x_end4 = w - 4;
517
518 for(y = 0; y < h; y++) {
519 const lv_opa_t * mask_tmp_x = mask;
520 #if 0
521 for(x = 0; x < w; x++) {
522 MAP_NORMAL_MASK_PX(x);
523 }
524 #else
525 for(x = 0; x < w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) {
526 #if LV_COLOR_SCREEN_TRANSP
527 MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
528 #else
529 MAP_NORMAL_MASK_PX(x)
530 #endif
531 }
532
533 uint32_t * mask32 = (uint32_t *)mask_tmp_x;
534 for(; x < x_end4; x += 4) {
535 if(*mask32) {
536 if((*mask32) == 0xFFFFFFFF) {
537 dest_buf[x] = src_buf[x];
538 dest_buf[x + 1] = src_buf[x + 1];
539 dest_buf[x + 2] = src_buf[x + 2];
540 dest_buf[x + 3] = src_buf[x + 3];
541 }
542 else {
543 mask_tmp_x = (const lv_opa_t *)mask32;
544 #if LV_COLOR_SCREEN_TRANSP
545 MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
546 MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 1)
547 MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 2)
548 MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 3)
549 #else
550 MAP_NORMAL_MASK_PX(x)
551 MAP_NORMAL_MASK_PX(x + 1)
552 MAP_NORMAL_MASK_PX(x + 2)
553 MAP_NORMAL_MASK_PX(x + 3)
554 #endif
555 }
556 }
557 mask32++;
558 }
559
560 mask_tmp_x = (const lv_opa_t *)mask32;
561 for(; x < w ; x++) {
562 #if LV_COLOR_SCREEN_TRANSP
563 MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
564 #else
565 MAP_NORMAL_MASK_PX(x)
566 #endif
567 }
568 #endif
569 dest_buf += dest_stride;
570 src_buf += src_stride;
571 mask += mask_stride;
572 }
573 }
574 /*Handle opa and mask values too*/
575 else {
576 for(y = 0; y < h; y++) {
577 for(x = 0; x < w; x++) {
578 if(mask[x]) {
579 lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
580 #if LV_COLOR_SCREEN_TRANSP
581 if(disp->driver->screen_transp) {
582 lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa_tmp,
583 &dest_buf[x], &dest_buf[x].ch.alpha);
584 }
585 else
586 #endif
587 {
588 dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa_tmp);
589 }
590 }
591 }
592 dest_buf += dest_stride;
593 src_buf += src_stride;
594 mask += mask_stride;
595 }
596 }
597 }
598 }
599 #if LV_DRAW_COMPLEX
map_blended(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_coord_t src_stride,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride,lv_blend_mode_t blend_mode)600 static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
601 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
602 const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode)
603 {
604
605 int32_t w = lv_area_get_width(dest_area);
606 int32_t h = lv_area_get_height(dest_area);
607
608 int32_t x;
609 int32_t y;
610
611 lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t);
612 switch(blend_mode) {
613 case LV_BLEND_MODE_ADDITIVE:
614 blend_fp = color_blend_true_color_additive;
615 break;
616 case LV_BLEND_MODE_SUBTRACTIVE:
617 blend_fp = color_blend_true_color_subtractive;
618 break;
619 case LV_BLEND_MODE_MULTIPLY:
620 blend_fp = color_blend_true_color_multiply;
621 break;
622 default:
623 LV_LOG_WARN("fill_blended: unsupported blend mode");
624 return;
625 }
626
627 /*Simple fill (maybe with opacity), no masking*/
628 if(mask == NULL) {
629 /*The map will be indexed from `draw_area->x1` so compensate it.*/
630
631 for(y = 0; y < h; y++) {
632 for(x = 0; x < w; x++) {
633 dest_buf[x] = blend_fp(src_buf[x], dest_buf[x], opa);
634 }
635 dest_buf += dest_stride;
636 src_buf += src_stride;
637 }
638 }
639 /*Masked*/
640 else {
641 for(y = 0; y < h; y++) {
642 for(x = 0; x < w; x++) {
643 if(mask[x] == 0) continue;
644 lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
645 dest_buf[x] = blend_fp(src_buf[x], dest_buf[x], opa_tmp);
646 }
647 dest_buf += dest_stride;
648 src_buf += src_stride;
649 mask += mask_stride;
650 }
651 }
652 }
653
color_blend_true_color_additive(lv_color_t fg,lv_color_t bg,lv_opa_t opa)654 static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
655 {
656
657 if(opa <= LV_OPA_MIN) return bg;
658
659 uint32_t tmp;
660 #if LV_COLOR_DEPTH == 1
661 tmp = bg.full + fg.full;
662 fg.full = LV_MIN(tmp, 1);
663 #else
664 tmp = bg.ch.red + fg.ch.red;
665 #if LV_COLOR_DEPTH == 8
666 fg.ch.red = LV_MIN(tmp, 7);
667 #elif LV_COLOR_DEPTH == 16
668 fg.ch.red = LV_MIN(tmp, 31);
669 #elif LV_COLOR_DEPTH == 32
670 fg.ch.red = LV_MIN(tmp, 255);
671 #endif
672
673 #if LV_COLOR_DEPTH == 8
674 tmp = bg.ch.green + fg.ch.green;
675 fg.ch.green = LV_MIN(tmp, 7);
676 #elif LV_COLOR_DEPTH == 16
677 #if LV_COLOR_16_SWAP == 0
678 tmp = bg.ch.green + fg.ch.green;
679 fg.ch.green = LV_MIN(tmp, 63);
680 #else
681 tmp = (bg.ch.green_h << 3) + bg.ch.green_l + (fg.ch.green_h << 3) + fg.ch.green_l;
682 tmp = LV_MIN(tmp, 63);
683 fg.ch.green_h = tmp >> 3;
684 fg.ch.green_l = tmp & 0x7;
685 #endif
686
687 #elif LV_COLOR_DEPTH == 32
688 tmp = bg.ch.green + fg.ch.green;
689 fg.ch.green = LV_MIN(tmp, 255);
690 #endif
691
692 tmp = bg.ch.blue + fg.ch.blue;
693 #if LV_COLOR_DEPTH == 8
694 fg.ch.blue = LV_MIN(tmp, 4);
695 #elif LV_COLOR_DEPTH == 16
696 fg.ch.blue = LV_MIN(tmp, 31);
697 #elif LV_COLOR_DEPTH == 32
698 fg.ch.blue = LV_MIN(tmp, 255);
699 #endif
700 #endif
701
702 if(opa == LV_OPA_COVER) return fg;
703
704 return lv_color_mix(fg, bg, opa);
705 }
706
color_blend_true_color_subtractive(lv_color_t fg,lv_color_t bg,lv_opa_t opa)707 static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
708 {
709 if(opa <= LV_OPA_MIN) return bg;
710
711 int32_t tmp;
712 tmp = bg.ch.red - fg.ch.red;
713 fg.ch.red = LV_MAX(tmp, 0);
714
715 #if LV_COLOR_16_SWAP == 0
716 tmp = bg.ch.green - fg.ch.green;
717 fg.ch.green = LV_MAX(tmp, 0);
718 #else
719 tmp = (bg.ch.green_h << 3) + bg.ch.green_l + (fg.ch.green_h << 3) + fg.ch.green_l;
720 tmp = LV_MAX(tmp, 0);
721 fg.ch.green_h = tmp >> 3;
722 fg.ch.green_l = tmp & 0x7;
723 #endif
724
725 tmp = bg.ch.blue - fg.ch.blue;
726 fg.ch.blue = LV_MAX(tmp, 0);
727
728 if(opa == LV_OPA_COVER) return fg;
729
730 return lv_color_mix(fg, bg, opa);
731 }
732
color_blend_true_color_multiply(lv_color_t fg,lv_color_t bg,lv_opa_t opa)733 static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
734 {
735 if(opa <= LV_OPA_MIN) return bg;
736
737 #if LV_COLOR_DEPTH == 32
738 fg.ch.red = (fg.ch.red * bg.ch.red) >> 8;
739 fg.ch.green = (fg.ch.green * bg.ch.green) >> 8;
740 fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 8;
741 #elif LV_COLOR_DEPTH == 16
742 fg.ch.red = (fg.ch.red * bg.ch.red) >> 5;
743 fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 5;
744 LV_COLOR_SET_G(fg, (LV_COLOR_GET_G(fg) * LV_COLOR_GET_G(bg)) >> 6);
745 #elif LV_COLOR_DEPTH == 8
746 fg.ch.red = (fg.ch.red * bg.ch.red) >> 3;
747 fg.ch.green = (fg.ch.green * bg.ch.green) >> 3;
748 fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 2;
749 #endif
750
751 if(opa == LV_OPA_COVER) return fg;
752
753 return lv_color_mix(fg, bg, opa);
754 }
755
756 #endif
757
758