acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_draw_sw_blend.c (27186B)
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 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 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 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 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 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 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 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 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 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 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 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