diff options
-rw-r--r-- | apps/recorder/bmp.c | 87 | ||||
-rw-r--r-- | apps/recorder/bmp.h | 1 | ||||
-rw-r--r-- | firmware/drivers/lcd-16bit-common.c | 58 | ||||
-rw-r--r-- | firmware/export/lcd.h | 3 |
4 files changed, 109 insertions, 40 deletions
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index d6f61d1c87..819d2e6976 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c | |||
@@ -173,6 +173,7 @@ static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src) | |||
173 | dst->red = src.red; | 173 | dst->red = src.red; |
174 | dst->green = src.green; | 174 | dst->green = src.green; |
175 | dst->blue = src.blue; | 175 | dst->blue = src.blue; |
176 | dst->alpha = 0xff; | ||
176 | } | 177 | } |
177 | 178 | ||
178 | struct bmp_args { | 179 | struct bmp_args { |
@@ -189,6 +190,9 @@ struct bmp_args { | |||
189 | int cur_col; | 190 | int cur_col; |
190 | struct img_part part; | 191 | struct img_part part; |
191 | #endif | 192 | #endif |
193 | /* as read_part_line() goes through the rows it'll set this to true | ||
194 | * if it finds transparency. Initialize to false before calling */ | ||
195 | bool alpha_detected; | ||
192 | }; | 196 | }; |
193 | 197 | ||
194 | static unsigned int read_part_line(struct bmp_args *ba) | 198 | static unsigned int read_part_line(struct bmp_args *ba) |
@@ -233,6 +237,7 @@ static unsigned int read_part_line(struct bmp_args *ba) | |||
233 | #endif | 237 | #endif |
234 | return 0; | 238 | return 0; |
235 | } | 239 | } |
240 | |||
236 | while (ibuf < ba->buf + (BM_MAX_WIDTH << 2)) | 241 | while (ibuf < ba->buf + (BM_MAX_WIDTH << 2)) |
237 | { | 242 | { |
238 | switch (depth) | 243 | switch (depth) |
@@ -274,6 +279,7 @@ static unsigned int read_part_line(struct bmp_args *ba) | |||
274 | component = data & 0xf8; | 279 | component = data & 0xf8; |
275 | component |= component >> 5; | 280 | component |= component >> 5; |
276 | buf->red = component; | 281 | buf->red = component; |
282 | buf->alpha = 0xff; | ||
277 | buf++; | 283 | buf++; |
278 | ibuf += 2; | 284 | ibuf += 2; |
279 | break; | 285 | break; |
@@ -282,13 +288,12 @@ static unsigned int read_part_line(struct bmp_args *ba) | |||
282 | buf->blue = *ibuf++; | 288 | buf->blue = *ibuf++; |
283 | buf->green = *ibuf++; | 289 | buf->green = *ibuf++; |
284 | buf->red = *ibuf++; | 290 | buf->red = *ibuf++; |
285 | if (depth == 32) | 291 | buf->alpha = (depth == 32) ? *ibuf++ : 0xff; |
286 | ibuf++; | 292 | if (buf->alpha != 0xff) ba->alpha_detected = true; |
287 | buf++; | 293 | buf++; |
288 | break; | 294 | break; |
289 | } | 295 | } |
290 | } | 296 | } |
291 | |||
292 | #if !defined(HAVE_LCD_COLOR) && \ | 297 | #if !defined(HAVE_LCD_COLOR) && \ |
293 | ((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \ | 298 | ((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \ |
294 | defined(PLUGIN)) | 299 | defined(PLUGIN)) |
@@ -422,41 +427,40 @@ void output_row_8_native(uint32_t row, void * row_in, | |||
422 | } | 427 | } |
423 | #endif /* LCD_PIXELFORMAT */ | 428 | #endif /* LCD_PIXELFORMAT */ |
424 | #elif LCD_DEPTH == 16 | 429 | #elif LCD_DEPTH == 16 |
425 | #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE | ||
426 | /* M:Robe 500 */ | ||
427 | (void) fb_width; | ||
428 | fb_data *dest = (fb_data *)ctx->bm->data + row; | ||
429 | int delta = 127; | ||
430 | unsigned r, g, b; | ||
431 | for (col = 0; col < ctx->bm->width; col++) { | ||
432 | if (ctx->dither) | ||
433 | delta = DITHERXDY(col,dy); | ||
434 | r = qp->red; | ||
435 | g = qp->green; | ||
436 | b = (qp++)->blue; | ||
437 | r = (31 * r + (r >> 3) + delta) >> 8; | ||
438 | g = (63 * g + (g >> 2) + delta) >> 8; | ||
439 | b = (31 * b + (b >> 3) + delta) >> 8; | ||
440 | *dest = LCD_RGBPACK_LCD(r, g, b); | ||
441 | dest += ctx->bm->height; | ||
442 | } | ||
443 | #else | ||
444 | /* iriver h300, colour iPods, X5 */ | 430 | /* iriver h300, colour iPods, X5 */ |
445 | fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row; | 431 | (void)fb_width; |
432 | fb_data *dest = STRIDE_MAIN((fb_data *)ctx->bm->data + fb_width * row, | ||
433 | (fb_data *)ctx->bm->data + row); | ||
446 | int delta = 127; | 434 | int delta = 127; |
447 | unsigned r, g, b; | 435 | unsigned r, g, b; |
436 | /* setup alpha channel buffer */ | ||
437 | unsigned char *bm_alpha = NULL; | ||
438 | if (ctx->bm->alpha_offset > 0) | ||
439 | bm_alpha = ctx->bm->data + ctx->bm->alpha_offset; | ||
440 | if (bm_alpha) | ||
441 | bm_alpha += ctx->bm->width*row/2; | ||
442 | |||
448 | for (col = 0; col < ctx->bm->width; col++) { | 443 | for (col = 0; col < ctx->bm->width; col++) { |
449 | if (ctx->dither) | 444 | if (ctx->dither) |
450 | delta = DITHERXDY(col,dy); | 445 | delta = DITHERXDY(col,dy); |
451 | r = qp->red; | 446 | r = qp->red; |
452 | g = qp->green; | 447 | g = qp->green; |
453 | b = (qp++)->blue; | 448 | b = qp->blue; |
454 | r = (31 * r + (r >> 3) + delta) >> 8; | 449 | r = (31 * r + (r >> 3) + delta) >> 8; |
455 | g = (63 * g + (g >> 2) + delta) >> 8; | 450 | g = (63 * g + (g >> 2) + delta) >> 8; |
456 | b = (31 * b + (b >> 3) + delta) >> 8; | 451 | b = (31 * b + (b >> 3) + delta) >> 8; |
457 | *dest++ = LCD_RGBPACK_LCD(r, g, b); | 452 | *dest = LCD_RGBPACK_LCD(r, g, b); |
453 | dest += STRIDE_MAIN(1, ctx->bm->height); | ||
454 | if (bm_alpha) { | ||
455 | /* pack alpha channel for 2 pixels into 1 byte */ | ||
456 | unsigned alpha = 255-qp->alpha; | ||
457 | if (col%2) | ||
458 | *bm_alpha++ |= alpha&0xf0; | ||
459 | else | ||
460 | *bm_alpha = alpha>>4; | ||
461 | } | ||
462 | qp++; | ||
458 | } | 463 | } |
459 | #endif | ||
460 | #endif /* LCD_DEPTH */ | 464 | #endif /* LCD_DEPTH */ |
461 | } | 465 | } |
462 | #endif | 466 | #endif |
@@ -480,6 +484,7 @@ int read_bmp_fd(int fd, | |||
480 | int depth, numcolors, compression, totalsize; | 484 | int depth, numcolors, compression, totalsize; |
481 | int ret; | 485 | int ret; |
482 | bool return_size = format & FORMAT_RETURN_SIZE; | 486 | bool return_size = format & FORMAT_RETURN_SIZE; |
487 | bool read_alpha = format & FORMAT_TRANSPARENT; | ||
483 | 488 | ||
484 | unsigned char *bitmap = bm->data; | 489 | unsigned char *bitmap = bm->data; |
485 | struct uint8_rgb palette[256]; | 490 | struct uint8_rgb palette[256]; |
@@ -608,8 +613,14 @@ int read_bmp_fd(int fd, | |||
608 | 613 | ||
609 | if (cformat) | 614 | if (cformat) |
610 | totalsize = cformat->get_size(bm); | 615 | totalsize = cformat->get_size(bm); |
611 | else | 616 | else { |
612 | totalsize = BM_SIZE(bm->width,bm->height,format,remote); | 617 | totalsize = BM_SIZE(bm->width,bm->height,format,remote); |
618 | #ifdef HAVE_REMOTE_LCD | ||
619 | if (!remote) | ||
620 | #endif | ||
621 | if (depth == 32 && read_alpha) /* account for possible 4bit alpha per pixel */ | ||
622 | totalsize += bm->width * bm->height / 2; | ||
623 | } | ||
613 | 624 | ||
614 | if(return_size) | 625 | if(return_size) |
615 | { | 626 | { |
@@ -704,13 +715,21 @@ int read_bmp_fd(int fd, | |||
704 | 715 | ||
705 | memset(bitmap, 0, totalsize); | 716 | memset(bitmap, 0, totalsize); |
706 | 717 | ||
718 | #ifdef HAVE_LCD_COLOR | ||
719 | if (read_alpha && depth == 32) | ||
720 | bm->alpha_offset = totalsize - (bm->width * bm->height / 2); | ||
721 | else | ||
722 | bm->alpha_offset = 0; | ||
723 | #endif | ||
724 | |||
707 | struct bmp_args ba = { | 725 | struct bmp_args ba = { |
708 | .fd = fd, .padded_width = padded_width, .read_width = read_width, | 726 | .fd = fd, .padded_width = padded_width, .read_width = read_width, |
709 | .width = src_dim.width, .depth = depth, .palette = palette, | 727 | .width = src_dim.width, .depth = depth, .palette = palette, |
710 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ | 728 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
711 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) | 729 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
712 | .cur_row = 0, .cur_col = 0, .part = {0,0} | 730 | .cur_row = 0, .cur_col = 0, .part = {0,0}, |
713 | #endif | 731 | #endif |
732 | .alpha_detected = false, | ||
714 | }; | 733 | }; |
715 | 734 | ||
716 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ | 735 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
@@ -759,7 +778,6 @@ int read_bmp_fd(int fd, | |||
759 | return -6; | 778 | return -6; |
760 | } | 779 | } |
761 | #endif | 780 | #endif |
762 | |||
763 | int row; | 781 | int row; |
764 | /* loop to read rows and put them to buffer */ | 782 | /* loop to read rows and put them to buffer */ |
765 | for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { | 783 | for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { |
@@ -858,5 +876,14 @@ int read_bmp_fd(int fd, | |||
858 | } | 876 | } |
859 | #endif | 877 | #endif |
860 | } | 878 | } |
879 | #ifdef HAVE_LCD_COLOR | ||
880 | if (!ba.alpha_detected) | ||
881 | { /* if this has an alpha channel, totalsize accounts for it as well | ||
882 | * subtract if no actual alpha information was found */ | ||
883 | if (bm->alpha_offset > 0) | ||
884 | totalsize -= bm->width*bm->height/2; | ||
885 | bm->alpha_offset = 0; | ||
886 | } | ||
887 | #endif | ||
861 | return totalsize; /* return the used buffer size. */ | 888 | return totalsize; /* return the used buffer size. */ |
862 | } | 889 | } |
diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h index 31bd0730bd..3ddc3b66df 100644 --- a/apps/recorder/bmp.h +++ b/apps/recorder/bmp.h | |||
@@ -39,6 +39,7 @@ struct uint8_rgb { | |||
39 | uint8_t blue; | 39 | uint8_t blue; |
40 | uint8_t green; | 40 | uint8_t green; |
41 | uint8_t red; | 41 | uint8_t red; |
42 | uint8_t alpha; | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | struct dim { | 45 | struct dim { |
diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c index bbac2b295a..7b37bf7c30 100644 --- a/firmware/drivers/lcd-16bit-common.c +++ b/firmware/drivers/lcd-16bit-common.c | |||
@@ -229,7 +229,6 @@ void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int heig | |||
229 | lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height); | 229 | lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height); |
230 | } | 230 | } |
231 | 231 | ||
232 | /* draw alpha bitmap for anti-alias font */ | ||
233 | #define ALPHA_COLOR_FONT_DEPTH 2 | 232 | #define ALPHA_COLOR_FONT_DEPTH 2 |
234 | #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH) | 233 | #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH) |
235 | #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1) | 234 | #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1) |
@@ -285,11 +284,17 @@ static inline unsigned blend_color(unsigned c, unsigned a) | |||
285 | return blend_two_colors(c, current_vp->fg_pattern, a); | 284 | return blend_two_colors(c, current_vp->fg_pattern, a); |
286 | } | 285 | } |
287 | 286 | ||
288 | void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, | 287 | /* Blend an image with an alpha channel |
289 | int src_y, int stride, int x, int y, | 288 | * if image is NULL, drawing will happen according to the drawmode |
290 | int width, int height) | 289 | * src is the alpha channel (4bit per pixel) */ |
290 | static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image, | ||
291 | const unsigned char *src, int src_x, | ||
292 | int src_y, int x, int y, | ||
293 | int width, int height, | ||
294 | int stride_image, int stride_src) | ||
291 | { | 295 | { |
292 | fb_data *dst, *dst_row; | 296 | fb_data *dst, *dst_row; |
297 | const fb_data *image_row; | ||
293 | unsigned dmask = 0x00000000; | 298 | unsigned dmask = 0x00000000; |
294 | int drmode = current_vp->drawmode; | 299 | int drmode = current_vp->drawmode; |
295 | /* nothing to draw? */ | 300 | /* nothing to draw? */ |
@@ -356,13 +361,22 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, | |||
356 | { | 361 | { |
357 | dmask = ~dmask; | 362 | dmask = ~dmask; |
358 | } | 363 | } |
364 | /* sourcing from an image ignore drawmode. | ||
365 | * Set to DRMODE_BG as we use its code path in the switch below */ | ||
366 | if (image != NULL) | ||
367 | { | ||
368 | dmask = 0; | ||
369 | drmode = DRMODE_BG; | ||
370 | } | ||
359 | 371 | ||
360 | dst_row = LCDADDR(x, y); | 372 | dst_row = LCDADDR(x, y); |
361 | 373 | ||
362 | int col, row = height; | 374 | int col, row = height; |
363 | unsigned data, pixels; | 375 | unsigned data, pixels; |
364 | unsigned skip_end = (stride - width); | 376 | unsigned skip_end = (stride_src - width); |
365 | unsigned skip_start = src_y * stride + src_x; | 377 | unsigned skip_start = src_y * stride_src + src_x; |
378 | unsigned skip_start_image = STRIDE_MAIN(src_y * stride_image + src_x, | ||
379 | src_x * stride_image + src_y); | ||
366 | 380 | ||
367 | #ifdef ALPHA_BITMAP_READ_WORDS | 381 | #ifdef ALPHA_BITMAP_READ_WORDS |
368 | uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3); | 382 | uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3); |
@@ -379,6 +393,9 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, | |||
379 | #ifdef ALPHA_BITMAP_READ_WORDS | 393 | #ifdef ALPHA_BITMAP_READ_WORDS |
380 | pixels = 8 - pixels; | 394 | pixels = 8 - pixels; |
381 | #endif | 395 | #endif |
396 | if (image) | ||
397 | image += skip_start_image; | ||
398 | image_row = image; | ||
382 | 399 | ||
383 | /* go through the rows and update each pixel */ | 400 | /* go through the rows and update each pixel */ |
384 | do | 401 | do |
@@ -386,6 +403,12 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, | |||
386 | col = width; | 403 | col = width; |
387 | dst = dst_row; | 404 | dst = dst_row; |
388 | dst_row += ROW_INC; | 405 | dst_row += ROW_INC; |
406 | if (image_row) { | ||
407 | image = image_row; | ||
408 | image_row += STRIDE_MAIN(stride_image,1); | ||
409 | } | ||
410 | else | ||
411 | image = dst; | ||
389 | #ifdef ALPHA_BITMAP_READ_WORDS | 412 | #ifdef ALPHA_BITMAP_READ_WORDS |
390 | #define UPDATE_SRC_ALPHA do { \ | 413 | #define UPDATE_SRC_ALPHA do { \ |
391 | if (--pixels) \ | 414 | if (--pixels) \ |
@@ -431,10 +454,11 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, | |||
431 | uintptr_t bo = lcd_backdrop_offset; | 454 | uintptr_t bo = lcd_backdrop_offset; |
432 | do | 455 | do |
433 | { | 456 | { |
434 | *dst = blend_two_colors(*dst, *(fb_data *)((uintptr_t)dst + bo), | 457 | *dst = blend_two_colors(*(fb_data *)((uintptr_t)dst + bo), |
435 | data & ALPHA_COLOR_LOOKUP_SIZE ); | 458 | *image, data & ALPHA_COLOR_LOOKUP_SIZE ); |
436 | 459 | ||
437 | dst += COL_INC; | 460 | dst += COL_INC; |
461 | image += STRIDE_MAIN(1, stride_image); | ||
438 | UPDATE_SRC_ALPHA; | 462 | UPDATE_SRC_ALPHA; |
439 | } | 463 | } |
440 | while (--col); | 464 | while (--col); |
@@ -443,9 +467,10 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, | |||
443 | { | 467 | { |
444 | do | 468 | do |
445 | { | 469 | { |
446 | *dst = blend_two_colors(*dst, current_vp->bg_pattern, | 470 | *dst = blend_two_colors(current_vp->bg_pattern, |
447 | data & ALPHA_COLOR_LOOKUP_SIZE ); | 471 | *image, data & ALPHA_COLOR_LOOKUP_SIZE ); |
448 | dst += COL_INC; | 472 | dst += COL_INC; |
473 | image += STRIDE_MAIN(1, stride_image); | ||
449 | UPDATE_SRC_ALPHA; | 474 | UPDATE_SRC_ALPHA; |
450 | } | 475 | } |
451 | while (--col); | 476 | while (--col); |
@@ -516,6 +541,15 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, | |||
516 | } while (--row); | 541 | } while (--row); |
517 | } | 542 | } |
518 | 543 | ||
544 | |||
545 | /* draw alpha bitmap for anti-alias font */ | ||
546 | void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, | ||
547 | int src_y, int stride, int x, int y, | ||
548 | int width, int height) | ||
549 | { | ||
550 | lcd_alpha_bitmap_part_mix(NULL, src, src_x, src_y, x, y, width, height, 0, stride); | ||
551 | } | ||
552 | |||
519 | /* Draw a partial bitmap (mono or native) including alpha channel */ | 553 | /* Draw a partial bitmap (mono or native) including alpha channel */ |
520 | void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y, | 554 | void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y, |
521 | int x, int y, int width, int height) | 555 | int x, int y, int width, int height) |
@@ -523,6 +557,10 @@ void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y, | |||
523 | int bitmap_stride = STRIDE_MAIN(bm->width, bm->height); | 557 | int bitmap_stride = STRIDE_MAIN(bm->width, bm->height); |
524 | if (bm->format == FORMAT_MONO) | 558 | if (bm->format == FORMAT_MONO) |
525 | lcd_mono_bitmap_part(bm->data, src_x, src_y, bitmap_stride, x, y, width, height); | 559 | lcd_mono_bitmap_part(bm->data, src_x, src_y, bitmap_stride, x, y, width, height); |
560 | else if (bm->alpha_offset > 0) | ||
561 | lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset, | ||
562 | src_x, src_y, x, y, width, height, | ||
563 | bitmap_stride, bm->width); | ||
526 | else | 564 | else |
527 | lcd_bitmap_transparent_part((fb_data*)bm->data, | 565 | lcd_bitmap_transparent_part((fb_data*)bm->data, |
528 | src_x, src_y, bitmap_stride, x, y, width, height); | 566 | src_x, src_y, bitmap_stride, x, y, width, height); |
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 47ea94bca9..ad579820ad 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h | |||
@@ -468,6 +468,9 @@ struct bitmap { | |||
468 | int format; | 468 | int format; |
469 | unsigned char *maskdata; | 469 | unsigned char *maskdata; |
470 | #endif | 470 | #endif |
471 | #ifdef HAVE_LCD_COLOR | ||
472 | int alpha_offset; /* byte-offset of alpha channel in data */ | ||
473 | #endif | ||
471 | unsigned char *data; | 474 | unsigned char *data; |
472 | }; | 475 | }; |
473 | 476 | ||