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_hal_disp.c (22696B)
1 /** 2 * @file lv_hal_disp.c 3 * 4 * @description HAL layer for display driver 5 * 6 */ 7 8 /********************* 9 * INCLUDES 10 *********************/ 11 #include <stdint.h> 12 #include <stddef.h> 13 #include "lv_hal.h" 14 #include "../misc/lv_mem.h" 15 #include "../misc/lv_gc.h" 16 #include "../misc/lv_assert.h" 17 #include "../core/lv_obj.h" 18 #include "../core/lv_refr.h" 19 #include "../core/lv_theme.h" 20 #include "../draw/sdl/lv_draw_sdl.h" 21 #include "../draw/sw/lv_draw_sw.h" 22 #include "../draw/sdl/lv_draw_sdl.h" 23 #include "../draw/stm32_dma2d/lv_gpu_stm32_dma2d.h" 24 #include "../draw/arm2d/lv_gpu_arm2d.h" 25 26 #if LV_USE_THEME_DEFAULT 27 #include "../extra/themes/default/lv_theme_default.h" 28 #endif 29 30 /********************* 31 * DEFINES 32 *********************/ 33 34 /********************** 35 * TYPEDEFS 36 **********************/ 37 38 /********************** 39 * STATIC PROTOTYPES 40 **********************/ 41 static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_data); 42 43 static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, 44 lv_coord_t y, 45 lv_color_t color, lv_opa_t opa); 46 47 static void set_px_cb_alpha1(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, 48 lv_color_t color, lv_opa_t opa); 49 50 static void set_px_cb_alpha2(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, 51 lv_color_t color, lv_opa_t opa); 52 53 static void set_px_cb_alpha4(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, 54 lv_color_t color, lv_opa_t opa); 55 56 static void set_px_cb_alpha8(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, 57 lv_color_t color, lv_opa_t opa); 58 59 static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); 60 61 /********************** 62 * STATIC VARIABLES 63 **********************/ 64 static lv_disp_t * disp_def; 65 66 /********************** 67 * MACROS 68 **********************/ 69 70 /********************** 71 * GLOBAL FUNCTIONS 72 **********************/ 73 74 /** 75 * Initialize a display driver with default values. 76 * It is used to surly have known values in the fields ant not memory junk. 77 * After it you can set the fields. 78 * @param driver pointer to driver variable to initialize 79 */ 80 void lv_disp_drv_init(lv_disp_drv_t * driver) 81 { 82 lv_memset_00(driver, sizeof(lv_disp_drv_t)); 83 84 driver->hor_res = 320; 85 driver->ver_res = 240; 86 driver->physical_hor_res = -1; 87 driver->physical_ver_res = -1; 88 driver->offset_x = 0; 89 driver->offset_y = 0; 90 driver->antialiasing = LV_COLOR_DEPTH > 8 ? 1 : 0; 91 driver->screen_transp = LV_COLOR_SCREEN_TRANSP; 92 driver->dpi = LV_DPI_DEF; 93 driver->color_chroma_key = LV_COLOR_CHROMA_KEY; 94 95 96 #if LV_USE_GPU_STM32_DMA2D 97 driver->draw_ctx_init = lv_draw_stm32_dma2d_ctx_init; 98 driver->draw_ctx_deinit = lv_draw_stm32_dma2d_ctx_init; 99 driver->draw_ctx_size = sizeof(lv_draw_stm32_dma2d_ctx_t); 100 #elif LV_USE_GPU_NXP_PXP 101 driver->draw_ctx_init = lv_draw_nxp_pxp_init; 102 driver->draw_ctx_deinit = lv_draw_nxp_pxp_init; 103 driver->draw_ctx_size = sizeof(lv_draw_nxp_pxp_t); 104 #elif LV_USE_GPU_NXP_VG_LITE 105 driver->draw_ctx_init = lv_draw_nxp_vglite_init; 106 driver->draw_ctx_deinit = lv_draw_nxp_vglite_init; 107 driver->draw_ctx_size = sizeof(lv_draw_nxp_vglite_t); 108 #elif LV_USE_GPU_SDL 109 driver->draw_ctx_init = lv_draw_sdl_init_ctx; 110 driver->draw_ctx_deinit = lv_draw_sdl_deinit_ctx; 111 driver->draw_ctx_size = sizeof(lv_draw_sdl_ctx_t); 112 #elif LV_USE_GPU_ARM2D 113 driver->draw_ctx_init = lv_draw_arm2d_ctx_init; 114 driver->draw_ctx_deinit = lv_draw_arm2d_ctx_init; 115 driver->draw_ctx_size = sizeof(lv_draw_arm2d_ctx_t); 116 #else 117 driver->draw_ctx_init = lv_draw_sw_init_ctx; 118 driver->draw_ctx_deinit = lv_draw_sw_init_ctx; 119 driver->draw_ctx_size = sizeof(lv_draw_sw_ctx_t); 120 #endif 121 122 } 123 124 /** 125 * Initialize a display buffer 126 * @param draw_buf pointer `lv_disp_draw_buf_t` variable to initialize 127 * @param buf1 A buffer to be used by LVGL to draw the image. 128 * Always has to specified and can't be NULL. 129 * Can be an array allocated by the user. E.g. `static lv_color_t disp_buf1[1024 * 10]` 130 * Or a memory address e.g. in external SRAM 131 * @param buf2 Optionally specify a second buffer to make image rendering and image flushing 132 * (sending to the display) parallel. 133 * In the `disp_drv->flush` you should use DMA or similar hardware to send 134 * the image to the display in the background. 135 * It lets LVGL to render next frame into the other buffer while previous is being 136 * sent. Set to `NULL` if unused. 137 * @param size_in_px_cnt size of the `buf1` and `buf2` in pixel count. 138 */ 139 void lv_disp_draw_buf_init(lv_disp_draw_buf_t * draw_buf, void * buf1, void * buf2, uint32_t size_in_px_cnt) 140 { 141 lv_memset_00(draw_buf, sizeof(lv_disp_draw_buf_t)); 142 143 draw_buf->buf1 = buf1; 144 draw_buf->buf2 = buf2; 145 draw_buf->buf_act = draw_buf->buf1; 146 draw_buf->size = size_in_px_cnt; 147 } 148 149 /** 150 * Register an initialized display driver. 151 * Automatically set the first display as active. 152 * @param driver pointer to an initialized 'lv_disp_drv_t' variable. Only its pointer is saved! 153 * @return pointer to the new display or NULL on error 154 */ 155 lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver) 156 { 157 lv_disp_t * disp = _lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll)); 158 LV_ASSERT_MALLOC(disp); 159 if(!disp) { 160 return NULL; 161 } 162 163 /*Create a draw context if not created yet*/ 164 if(driver->draw_ctx == NULL) { 165 lv_draw_ctx_t * draw_ctx = lv_mem_alloc(driver->draw_ctx_size); 166 LV_ASSERT_MALLOC(draw_ctx); 167 if(draw_ctx == NULL) return NULL; 168 driver->draw_ctx_init(driver, draw_ctx); 169 driver->draw_ctx = draw_ctx; 170 } 171 172 lv_memset_00(disp, sizeof(lv_disp_t)); 173 174 disp->driver = driver; 175 176 lv_disp_t * disp_def_tmp = disp_def; 177 disp_def = disp; /*Temporarily change the default screen to create the default screens on the 178 new display*/ 179 /*Create a refresh timer*/ 180 disp->refr_timer = lv_timer_create(_lv_disp_refr_timer, LV_DISP_DEF_REFR_PERIOD, disp); 181 LV_ASSERT_MALLOC(disp->refr_timer); 182 if(disp->refr_timer == NULL) { 183 lv_mem_free(disp); 184 return NULL; 185 } 186 187 if(driver->full_refresh && driver->draw_buf->size < (uint32_t)driver->hor_res * driver->ver_res) { 188 driver->full_refresh = 0; 189 LV_LOG_WARN("full_refresh requires at least screen sized draw buffer(s)"); 190 } 191 192 disp->bg_color = lv_color_white(); 193 #if LV_COLOR_SCREEN_TRANSP 194 disp->bg_opa = LV_OPA_TRANSP; 195 #else 196 disp->bg_opa = LV_OPA_COVER; 197 #endif 198 199 #if LV_USE_THEME_DEFAULT 200 if(lv_theme_default_is_inited() == false) { 201 disp->theme = lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), 202 LV_THEME_DEFAULT_DARK, LV_FONT_DEFAULT); 203 } 204 else { 205 disp->theme = lv_theme_default_get(); 206 } 207 #endif 208 209 disp->act_scr = lv_obj_create(NULL); /*Create a default screen on the display*/ 210 disp->top_layer = lv_obj_create(NULL); /*Create top layer on the display*/ 211 disp->sys_layer = lv_obj_create(NULL); /*Create sys layer on the display*/ 212 lv_obj_remove_style_all(disp->top_layer); 213 lv_obj_remove_style_all(disp->sys_layer); 214 lv_obj_clear_flag(disp->top_layer, LV_OBJ_FLAG_CLICKABLE); 215 lv_obj_clear_flag(disp->sys_layer, LV_OBJ_FLAG_CLICKABLE); 216 217 lv_obj_set_scrollbar_mode(disp->top_layer, LV_SCROLLBAR_MODE_OFF); 218 lv_obj_set_scrollbar_mode(disp->sys_layer, LV_SCROLLBAR_MODE_OFF); 219 220 lv_obj_invalidate(disp->act_scr); 221 222 disp_def = disp_def_tmp; /*Revert the default display*/ 223 if(disp_def == NULL) disp_def = disp; /*Initialize the default display*/ 224 225 lv_timer_ready(disp->refr_timer); /*Be sure the screen will be refreshed immediately on start up*/ 226 227 return disp; 228 } 229 230 /** 231 * Update the driver in run time. 232 * @param disp pointer to a display. (return value of `lv_disp_drv_register`) 233 * @param new_drv pointer to the new driver 234 */ 235 void lv_disp_drv_update(lv_disp_t * disp, lv_disp_drv_t * new_drv) 236 { 237 disp->driver = new_drv; 238 239 if(disp->driver->full_refresh && 240 disp->driver->draw_buf->size < (uint32_t)disp->driver->hor_res * disp->driver->ver_res) { 241 disp->driver->full_refresh = 0; 242 LV_LOG_WARN("full_refresh requires at least screen sized draw buffer(s)"); 243 } 244 245 lv_coord_t w = lv_disp_get_hor_res(disp); 246 lv_coord_t h = lv_disp_get_ver_res(disp); 247 uint32_t i; 248 for(i = 0; i < disp->screen_cnt; i++) { 249 lv_area_t prev_coords; 250 lv_obj_get_coords(disp->screens[i], &prev_coords); 251 lv_area_set_width(&disp->screens[i]->coords, w); 252 lv_area_set_height(&disp->screens[i]->coords, h); 253 lv_event_send(disp->screens[i], LV_EVENT_SIZE_CHANGED, &prev_coords); 254 } 255 256 /* 257 * This method is usually called upon orientation change, thus the screen is now a 258 * different size. 259 * The object invalidated its previous area. That area is now out of the screen area 260 * so we reset all invalidated areas and invalidate the active screen's new area only. 261 */ 262 lv_memset_00(disp->inv_areas, sizeof(disp->inv_areas)); 263 lv_memset_00(disp->inv_area_joined, sizeof(disp->inv_area_joined)); 264 disp->inv_p = 0; 265 if(disp->act_scr != NULL) lv_obj_invalidate(disp->act_scr); 266 267 lv_obj_tree_walk(NULL, invalidate_layout_cb, NULL); 268 269 if(disp->driver->drv_update_cb) disp->driver->drv_update_cb(disp->driver); 270 } 271 272 /** 273 * Remove a display 274 * @param disp pointer to display 275 */ 276 void lv_disp_remove(lv_disp_t * disp) 277 { 278 bool was_default = false; 279 if(disp == lv_disp_get_default()) was_default = true; 280 281 /*Detach the input devices*/ 282 lv_indev_t * indev; 283 indev = lv_indev_get_next(NULL); 284 while(indev) { 285 if(indev->driver->disp == disp) { 286 indev->driver->disp = NULL; 287 } 288 indev = lv_indev_get_next(indev); 289 } 290 291 /** delete screen and other obj */ 292 if(disp->sys_layer) { 293 lv_obj_del(disp->sys_layer); 294 disp->sys_layer = NULL; 295 } 296 if(disp->top_layer) { 297 lv_obj_del(disp->top_layer); 298 disp->top_layer = NULL; 299 } 300 while(disp->screen_cnt != 0) { 301 /*Delete the screenst*/ 302 lv_obj_del(disp->screens[0]); 303 } 304 305 _lv_ll_remove(&LV_GC_ROOT(_lv_disp_ll), disp); 306 if(disp->refr_timer) lv_timer_del(disp->refr_timer); 307 lv_mem_free(disp); 308 309 if(was_default) lv_disp_set_default(_lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll))); 310 } 311 312 /** 313 * Set a default display. The new screens will be created on it by default. 314 * @param disp pointer to a display 315 */ 316 void lv_disp_set_default(lv_disp_t * disp) 317 { 318 disp_def = disp; 319 } 320 321 /** 322 * Get the default display 323 * @return pointer to the default display 324 */ 325 lv_disp_t * lv_disp_get_default(void) 326 { 327 return disp_def; 328 } 329 330 /** 331 * Get the horizontal resolution of a display 332 * @param disp pointer to a display (NULL to use the default display) 333 * @return the horizontal resolution of the display 334 */ 335 lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp) 336 { 337 if(disp == NULL) disp = lv_disp_get_default(); 338 339 if(disp == NULL) { 340 return 0; 341 } 342 else { 343 switch(disp->driver->rotated) { 344 case LV_DISP_ROT_90: 345 case LV_DISP_ROT_270: 346 return disp->driver->ver_res; 347 default: 348 return disp->driver->hor_res; 349 } 350 } 351 } 352 353 /** 354 * Get the vertical resolution of a display 355 * @param disp pointer to a display (NULL to use the default display) 356 * @return the vertical resolution of the display 357 */ 358 lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp) 359 { 360 if(disp == NULL) disp = lv_disp_get_default(); 361 362 if(disp == NULL) { 363 return 0; 364 } 365 else { 366 switch(disp->driver->rotated) { 367 case LV_DISP_ROT_90: 368 case LV_DISP_ROT_270: 369 return disp->driver->hor_res; 370 default: 371 return disp->driver->ver_res; 372 } 373 } 374 } 375 376 /** 377 * Get the full / physical horizontal resolution of a display 378 * @param disp pointer to a display (NULL to use the default display) 379 * @return the full / physical horizontal resolution of the display 380 */ 381 lv_coord_t lv_disp_get_physical_hor_res(lv_disp_t * disp) 382 { 383 if(disp == NULL) disp = lv_disp_get_default(); 384 385 if(disp == NULL) { 386 return 0; 387 } 388 else { 389 switch(disp->driver->rotated) { 390 case LV_DISP_ROT_90: 391 case LV_DISP_ROT_270: 392 return disp->driver->physical_ver_res > 0 ? disp->driver->physical_ver_res : disp->driver->ver_res; 393 default: 394 return disp->driver->physical_hor_res > 0 ? disp->driver->physical_hor_res : disp->driver->hor_res; 395 } 396 } 397 } 398 399 /** 400 * Get the full / physical vertical resolution of a display 401 * @param disp pointer to a display (NULL to use the default display) 402 * @return the full / physical vertical resolution of the display 403 */ 404 lv_coord_t lv_disp_get_physical_ver_res(lv_disp_t * disp) 405 { 406 if(disp == NULL) disp = lv_disp_get_default(); 407 408 if(disp == NULL) { 409 return 0; 410 } 411 else { 412 switch(disp->driver->rotated) { 413 case LV_DISP_ROT_90: 414 case LV_DISP_ROT_270: 415 return disp->driver->physical_hor_res > 0 ? disp->driver->physical_hor_res : disp->driver->hor_res; 416 default: 417 return disp->driver->physical_ver_res > 0 ? disp->driver->physical_ver_res : disp->driver->ver_res; 418 } 419 } 420 } 421 422 /** 423 * Get the horizontal offset from the full / physical display 424 * @param disp pointer to a display (NULL to use the default display) 425 * @return the horizontal offset from the full / physical display 426 */ 427 lv_coord_t lv_disp_get_offset_x(lv_disp_t * disp) 428 { 429 if(disp == NULL) disp = lv_disp_get_default(); 430 431 if(disp == NULL) { 432 return 0; 433 } 434 else { 435 switch(disp->driver->rotated) { 436 case LV_DISP_ROT_90: 437 return disp->driver->offset_y; 438 case LV_DISP_ROT_180: 439 return lv_disp_get_physical_hor_res(disp) - disp->driver->offset_x; 440 case LV_DISP_ROT_270: 441 return lv_disp_get_physical_hor_res(disp) - disp->driver->offset_y; 442 default: 443 return disp->driver->offset_x; 444 } 445 } 446 } 447 448 /** 449 * Get the vertical offset from the full / physical display 450 * @param disp pointer to a display (NULL to use the default display) 451 * @return the horizontal offset from the full / physical display 452 */ 453 lv_coord_t lv_disp_get_offset_y(lv_disp_t * disp) 454 { 455 if(disp == NULL) disp = lv_disp_get_default(); 456 457 if(disp == NULL) { 458 return 0; 459 } 460 else { 461 switch(disp->driver->rotated) { 462 case LV_DISP_ROT_90: 463 return disp->driver->offset_x; 464 case LV_DISP_ROT_180: 465 return lv_disp_get_physical_ver_res(disp) - disp->driver->offset_y; 466 case LV_DISP_ROT_270: 467 return lv_disp_get_physical_ver_res(disp) - disp->driver->offset_x; 468 default: 469 return disp->driver->offset_y; 470 } 471 } 472 } 473 474 /** 475 * Get if anti-aliasing is enabled for a display or not 476 * @param disp pointer to a display (NULL to use the default display) 477 * @return true: anti-aliasing is enabled; false: disabled 478 */ 479 bool lv_disp_get_antialiasing(lv_disp_t * disp) 480 { 481 if(disp == NULL) disp = lv_disp_get_default(); 482 if(disp == NULL) return false; 483 484 return disp->driver->antialiasing ? true : false; 485 } 486 487 /** 488 * Get the DPI of the display 489 * @param disp pointer to a display (NULL to use the default display) 490 * @return dpi of the display 491 */ 492 lv_coord_t lv_disp_get_dpi(const lv_disp_t * disp) 493 { 494 if(disp == NULL) disp = lv_disp_get_default(); 495 if(disp == NULL) return LV_DPI_DEF; /*Do not return 0 because it might be a divider*/ 496 return disp->driver->dpi; 497 } 498 499 /** 500 * Call in the display driver's `flush_cb` function when the flushing is finished 501 * @param disp_drv pointer to display driver in `flush_cb` where this function is called 502 */ 503 LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv) 504 { 505 /*If the screen is transparent initialize it when the flushing is ready*/ 506 #if LV_COLOR_SCREEN_TRANSP 507 if(disp_drv->screen_transp) { 508 if(disp_drv->clear_cb) { 509 disp_drv->clear_cb(disp_drv, disp_drv->draw_buf->buf_act, disp_drv->draw_buf->size); 510 } 511 else { 512 lv_memset_00(disp_drv->draw_buf->buf_act, disp_drv->draw_buf->size * sizeof(lv_color32_t)); 513 } 514 } 515 #endif 516 517 disp_drv->draw_buf->flushing = 0; 518 disp_drv->draw_buf->flushing_last = 0; 519 } 520 521 /** 522 * Tell if it's the last area of the refreshing process. 523 * Can be called from `flush_cb` to execute some special display refreshing if needed when all areas area flushed. 524 * @param disp_drv pointer to display driver 525 * @return true: it's the last area to flush; false: there are other areas too which will be refreshed soon 526 */ 527 LV_ATTRIBUTE_FLUSH_READY bool lv_disp_flush_is_last(lv_disp_drv_t * disp_drv) 528 { 529 return disp_drv->draw_buf->flushing_last; 530 } 531 532 /** 533 * Get the next display. 534 * @param disp pointer to the current display. NULL to initialize. 535 * @return the next display or NULL if no more. Give the first display when the parameter is NULL 536 */ 537 lv_disp_t * lv_disp_get_next(lv_disp_t * disp) 538 { 539 if(disp == NULL) 540 return _lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll)); 541 else 542 return _lv_ll_get_next(&LV_GC_ROOT(_lv_disp_ll), disp); 543 } 544 545 /** 546 * Get the internal buffer of a display 547 * @param disp pointer to a display 548 * @return pointer to the internal buffers 549 */ 550 lv_disp_draw_buf_t * lv_disp_get_draw_buf(lv_disp_t * disp) 551 { 552 return disp->driver->draw_buf; 553 } 554 555 /** 556 * Set the rotation of this display. 557 * @param disp pointer to a display (NULL to use the default display) 558 * @param rotation rotation angle 559 */ 560 void lv_disp_set_rotation(lv_disp_t * disp, lv_disp_rot_t rotation) 561 { 562 if(disp == NULL) disp = lv_disp_get_default(); 563 if(disp == NULL) return; 564 565 disp->driver->rotated = rotation; 566 lv_disp_drv_update(disp, disp->driver); 567 } 568 569 /** 570 * Get the current rotation of this display. 571 * @param disp pointer to a display (NULL to use the default display) 572 * @return rotation angle 573 */ 574 lv_disp_rot_t lv_disp_get_rotation(lv_disp_t * disp) 575 { 576 if(disp == NULL) disp = lv_disp_get_default(); 577 if(disp == NULL) return LV_DISP_ROT_NONE; 578 return disp->driver->rotated; 579 } 580 581 void lv_disp_drv_use_generic_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf) 582 { 583 switch(cf) { 584 case LV_IMG_CF_TRUE_COLOR_ALPHA: 585 disp_drv->set_px_cb = set_px_true_color_alpha; 586 break; 587 case LV_IMG_CF_ALPHA_1BIT: 588 disp_drv->set_px_cb = set_px_cb_alpha1; 589 break; 590 case LV_IMG_CF_ALPHA_2BIT: 591 disp_drv->set_px_cb = set_px_cb_alpha2; 592 break; 593 case LV_IMG_CF_ALPHA_4BIT: 594 disp_drv->set_px_cb = set_px_cb_alpha4; 595 break; 596 case LV_IMG_CF_ALPHA_8BIT: 597 disp_drv->set_px_cb = set_px_cb_alpha8; 598 break; 599 default: 600 disp_drv->set_px_cb = NULL; 601 } 602 } 603 604 /********************** 605 * STATIC FUNCTIONS 606 **********************/ 607 608 static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_data) 609 { 610 LV_UNUSED(user_data); 611 lv_obj_mark_layout_as_dirty(obj); 612 return LV_OBJ_TREE_WALK_NEXT; 613 } 614 615 static void set_px_cb_alpha1(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, 616 lv_color_t color, lv_opa_t opa) 617 { 618 (void) disp_drv; /*Unused*/ 619 620 if(opa <= LV_OPA_MIN) return; 621 lv_img_dsc_t d; 622 d.data = buf; 623 d.header.w = buf_w; 624 d.header.cf = LV_IMG_CF_ALPHA_1BIT; 625 626 set_px_alpha_generic(&d, x, y, color, opa); 627 } 628 629 static void set_px_cb_alpha2(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, 630 lv_color_t color, lv_opa_t opa) 631 { 632 (void) disp_drv; /*Unused*/ 633 634 if(opa <= LV_OPA_MIN) return; 635 lv_img_dsc_t d; 636 d.data = buf; 637 d.header.w = buf_w; 638 d.header.cf = LV_IMG_CF_ALPHA_2BIT; 639 640 set_px_alpha_generic(&d, x, y, color, opa); 641 } 642 643 static void set_px_cb_alpha4(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, 644 lv_color_t color, lv_opa_t opa) 645 { 646 (void) disp_drv; /*Unused*/ 647 648 if(opa <= LV_OPA_MIN) return; 649 lv_img_dsc_t d; 650 d.data = buf; 651 d.header.w = buf_w; 652 d.header.cf = LV_IMG_CF_ALPHA_4BIT; 653 654 set_px_alpha_generic(&d, x, y, color, opa); 655 } 656 657 static void set_px_cb_alpha8(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, 658 lv_color_t color, lv_opa_t opa) 659 { 660 (void) disp_drv; /*Unused*/ 661 662 if(opa <= LV_OPA_MIN) return; 663 lv_img_dsc_t d; 664 d.data = buf; 665 d.header.w = buf_w; 666 d.header.cf = LV_IMG_CF_ALPHA_8BIT; 667 668 set_px_alpha_generic(&d, x, y, color, opa); 669 } 670 671 static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) 672 { 673 d->header.always_zero = 0; 674 d->header.h = 1; /*Doesn't matter*/ 675 676 uint8_t br = lv_color_brightness(color); 677 if(opa < LV_OPA_MAX) { 678 uint8_t bg = lv_img_buf_get_px_alpha(d, x, y); 679 br = (uint16_t)((uint16_t)br * opa + (bg * (255 - opa))) >> 8; 680 } 681 682 lv_img_buf_set_px_alpha(d, x, y, br); 683 } 684 685 static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, 686 lv_coord_t y, 687 lv_color_t color, lv_opa_t opa) 688 { 689 (void) disp_drv; /*Unused*/ 690 691 if(opa <= LV_OPA_MIN) return; 692 lv_img_dsc_t d; 693 d.data = buf; 694 d.header.always_zero = 0; 695 d.header.h = 1; /*Doesn't matter*/; 696 d.header.w = buf_w; 697 d.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA; 698 699 lv_color_t bg_color = lv_img_buf_get_px_color(&d, x, y, lv_color_black()); 700 lv_opa_t bg_opa = lv_img_buf_get_px_alpha(&d, x, y); 701 702 lv_opa_t res_opa; 703 lv_color_t res_color; 704 705 lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &res_opa); 706 707 lv_img_buf_set_px_alpha(&d, x, y, res_opa); 708 lv_img_buf_set_px_color(&d, x, y, res_color); 709 }