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