summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-11-11 19:05:11 +0000
committerThomas Martitz <kugel@rockbox.org>2011-11-11 19:05:11 +0000
commit312b2a2de7a35f8c4b0dc355b7b291085a9a5ea4 (patch)
tree922fc139712760cd89c0caa7c3724b5a5020765c
parent158e14a8c696b29ec7fa21da5b1a801c31c473e9 (diff)
downloadrockbox-312b2a2de7a35f8c4b0dc355b7b291085a9a5ea4.tar.gz
rockbox-312b2a2de7a35f8c4b0dc355b7b291085a9a5ea4.zip
Document the internal alpha channel format better, and fixes for 32bit alpha bitmaps.
For images, rows need to be even (this is not true for anti-aliased font files). Fix stride and size calculation. This makes images that have odd pixel rows display properly and fixes buffer overflows. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30966 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/recorder/bmp.c12
-rw-r--r--apps/recorder/resize.c4
-rw-r--r--firmware/drivers/lcd-16bit-common.c30
3 files changed, 33 insertions, 13 deletions
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index 26be4e48cf..75165528e7 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -438,7 +438,7 @@ void output_row_8_native(uint32_t row, void * row_in,
438 if (ctx->bm->alpha_offset > 0) 438 if (ctx->bm->alpha_offset > 0)
439 bm_alpha = ctx->bm->data + ctx->bm->alpha_offset; 439 bm_alpha = ctx->bm->data + ctx->bm->alpha_offset;
440 if (bm_alpha) 440 if (bm_alpha)
441 bm_alpha += ctx->bm->width*row/2; 441 bm_alpha += ALIGN_UP(ctx->bm->width, 2) * row/2;
442 442
443 for (col = 0; col < ctx->bm->width; col++) { 443 for (col = 0; col < ctx->bm->width; col++) {
444 if (ctx->dither) 444 if (ctx->dither)
@@ -453,7 +453,7 @@ void output_row_8_native(uint32_t row, void * row_in,
453 dest += STRIDE_MAIN(1, ctx->bm->height); 453 dest += STRIDE_MAIN(1, ctx->bm->height);
454 if (bm_alpha) { 454 if (bm_alpha) {
455 /* pack alpha channel for 2 pixels into 1 byte */ 455 /* pack alpha channel for 2 pixels into 1 byte */
456 unsigned alpha = 255-qp->alpha; 456 unsigned alpha = qp->alpha;
457 if (col%2) 457 if (col%2)
458 *bm_alpha++ |= alpha&0xf0; 458 *bm_alpha++ |= alpha&0xf0;
459 else 459 else
@@ -612,6 +612,8 @@ int read_bmp_fd(int fd,
612 rset.rowstop = -1; 612 rset.rowstop = -1;
613 } 613 }
614 614
615 /* need even rows (see lcd-16bit-common.c for details) */
616 int alphasize = ALIGN_UP(bm->width, 2) * bm->height / 2;
615 if (cformat) 617 if (cformat)
616 totalsize = cformat->get_size(bm); 618 totalsize = cformat->get_size(bm);
617 else { 619 else {
@@ -620,7 +622,7 @@ int read_bmp_fd(int fd,
620 if (!remote) 622 if (!remote)
621#endif 623#endif
622 if (depth == 32 && read_alpha) /* account for possible 4bit alpha per pixel */ 624 if (depth == 32 && read_alpha) /* account for possible 4bit alpha per pixel */
623 totalsize += bm->width * bm->height / 2; 625 totalsize += alphasize;
624 } 626 }
625 627
626 if(return_size) 628 if(return_size)
@@ -718,7 +720,7 @@ int read_bmp_fd(int fd,
718 720
719#ifdef HAVE_LCD_COLOR 721#ifdef HAVE_LCD_COLOR
720 if (read_alpha && depth == 32) 722 if (read_alpha && depth == 32)
721 bm->alpha_offset = totalsize - (bm->width * bm->height / 2); 723 bm->alpha_offset = totalsize - alphasize;
722 else 724 else
723 bm->alpha_offset = 0; 725 bm->alpha_offset = 0;
724#endif 726#endif
@@ -882,7 +884,7 @@ int read_bmp_fd(int fd,
882 { /* if this has an alpha channel, totalsize accounts for it as well 884 { /* if this has an alpha channel, totalsize accounts for it as well
883 * subtract if no actual alpha information was found */ 885 * subtract if no actual alpha information was found */
884 if (bm->alpha_offset > 0) 886 if (bm->alpha_offset > 0)
885 totalsize -= bm->width*bm->height/2; 887 totalsize -= alphasize;
886 bm->alpha_offset = 0; 888 bm->alpha_offset = 0;
887 } 889 }
888#endif 890#endif
diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c
index a68a5f2e9f..dd1f3edf88 100644
--- a/apps/recorder/resize.c
+++ b/apps/recorder/resize.c
@@ -775,7 +775,7 @@ static void output_row_32_native(uint32_t row, void * row_in,
775 if (ctx->bm->alpha_offset > 0) 775 if (ctx->bm->alpha_offset > 0)
776 bm_alpha = ctx->bm->data + ctx->bm->alpha_offset; 776 bm_alpha = ctx->bm->data + ctx->bm->alpha_offset;
777 if (bm_alpha) 777 if (bm_alpha)
778 bm_alpha += ctx->bm->width*row/2; 778 bm_alpha += ALIGN_UP(ctx->bm->width, 2)*row/2;
779 779
780 for (col = 0; col < ctx->bm->width; col++) { 780 for (col = 0; col < ctx->bm->width; col++) {
781 if (ctx->dither) 781 if (ctx->dither)
@@ -791,7 +791,7 @@ static void output_row_32_native(uint32_t row, void * row_in,
791 dest += STRIDE_MAIN(1, ctx->bm->height); 791 dest += STRIDE_MAIN(1, ctx->bm->height);
792 if (bm_alpha) { 792 if (bm_alpha) {
793 /* pack alpha channel for 2 pixels into 1 byte */ 793 /* pack alpha channel for 2 pixels into 1 byte */
794 unsigned alpha = 255-SC_OUT(q0.a, ctx); 794 unsigned alpha = SC_OUT(q0.a, ctx);
795 if (col%2) 795 if (col%2)
796 *bm_alpha++ |= alpha&0xf0; 796 *bm_alpha++ |= alpha&0xf0;
797 else 797 else
diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c
index 7b37bf7c30..47f5968228 100644
--- a/firmware/drivers/lcd-16bit-common.c
+++ b/firmware/drivers/lcd-16bit-common.c
@@ -229,6 +229,25 @@ 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
233/* About Rockbox' internal alpha channel format (for ALPHA_COLOR_FONT_DEPTH == 2)
234 *
235 * For each pixel, 4bit of alpha information is stored in a byte-stream,
236 * so two pixels are packed into one byte.
237 * The lower nibble is the first pixel, the upper one the second. The stride is
238 * horizontal. E.g row0: pixel0: byte0[0:3], pixel1: byte0[4:7], pixel2: byte1[0:3],...
239 * The format is independant of the internal display orientation, as to
240 * support the same font files on
241 * The values go linear from 0 (fully transparent) to 15 (fully opaque).
242 *
243 * This might suggest that rows need to have an even number of pixels.
244 * However this is generally not the case. lcd_alpha_bitmap_part_mix() can deal
245 * with uneven colums (i.e. two rows can share one byte). And font files do
246 * exploit this.
247 * However, this is difficult to do for image files, especially bottom-up bitmaps,
248 * so lcd_bmp() do expect even rows.
249 */
250
232#define ALPHA_COLOR_FONT_DEPTH 2 251#define ALPHA_COLOR_FONT_DEPTH 2
233#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH) 252#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
234#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1) 253#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
@@ -357,17 +376,16 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
357 dmask = 0xffffffff; 376 dmask = 0xffffffff;
358 drmode &= DRMODE_SOLID; /* mask out inversevid */ 377 drmode &= DRMODE_SOLID; /* mask out inversevid */
359 } 378 }
360 if (drmode == DRMODE_BG)
361 {
362 dmask = ~dmask;
363 }
364 /* sourcing from an image ignore drawmode. 379 /* sourcing from an image ignore drawmode.
365 * Set to DRMODE_BG as we use its code path in the switch below */ 380 * Set to DRMODE_BG as we use its code path in the switch below */
366 if (image != NULL) 381 if (image != NULL)
367 { 382 {
368 dmask = 0;
369 drmode = DRMODE_BG; 383 drmode = DRMODE_BG;
370 } 384 }
385 if (drmode == DRMODE_BG)
386 {
387 dmask = ~dmask;
388 }
371 389
372 dst_row = LCDADDR(x, y); 390 dst_row = LCDADDR(x, y);
373 391
@@ -560,7 +578,7 @@ void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y,
560 else if (bm->alpha_offset > 0) 578 else if (bm->alpha_offset > 0)
561 lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset, 579 lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset,
562 src_x, src_y, x, y, width, height, 580 src_x, src_y, x, y, width, height,
563 bitmap_stride, bm->width); 581 bitmap_stride, ALIGN_UP(bm->width, 2));
564 else 582 else
565 lcd_bitmap_transparent_part((fb_data*)bm->data, 583 lcd_bitmap_transparent_part((fb_data*)bm->data,
566 src_x, src_y, bitmap_stride, x, y, width, height); 584 src_x, src_y, bitmap_stride, x, y, width, height);