Support for transparency in 32bit bitmaps on color targets.
This uses the alpha blending capabilities introduced with anti-aliased fonts to draw bitmaps with transparency information. The bmp loader is extended to read this information (pass FORMAT_TRANSPARENT in format). The alpha information will be used when drawing the bitmap. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30937 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
13209604c1
commit
f443e7bbf7
4 changed files with 109 additions and 40 deletions
|
@ -173,6 +173,7 @@ static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src)
|
|||
dst->red = src.red;
|
||||
dst->green = src.green;
|
||||
dst->blue = src.blue;
|
||||
dst->alpha = 0xff;
|
||||
}
|
||||
|
||||
struct bmp_args {
|
||||
|
@ -189,6 +190,9 @@ struct bmp_args {
|
|||
int cur_col;
|
||||
struct img_part part;
|
||||
#endif
|
||||
/* as read_part_line() goes through the rows it'll set this to true
|
||||
* if it finds transparency. Initialize to false before calling */
|
||||
bool alpha_detected;
|
||||
};
|
||||
|
||||
static unsigned int read_part_line(struct bmp_args *ba)
|
||||
|
@ -233,6 +237,7 @@ static unsigned int read_part_line(struct bmp_args *ba)
|
|||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (ibuf < ba->buf + (BM_MAX_WIDTH << 2))
|
||||
{
|
||||
switch (depth)
|
||||
|
@ -274,6 +279,7 @@ static unsigned int read_part_line(struct bmp_args *ba)
|
|||
component = data & 0xf8;
|
||||
component |= component >> 5;
|
||||
buf->red = component;
|
||||
buf->alpha = 0xff;
|
||||
buf++;
|
||||
ibuf += 2;
|
||||
break;
|
||||
|
@ -282,13 +288,12 @@ static unsigned int read_part_line(struct bmp_args *ba)
|
|||
buf->blue = *ibuf++;
|
||||
buf->green = *ibuf++;
|
||||
buf->red = *ibuf++;
|
||||
if (depth == 32)
|
||||
ibuf++;
|
||||
buf->alpha = (depth == 32) ? *ibuf++ : 0xff;
|
||||
if (buf->alpha != 0xff) ba->alpha_detected = true;
|
||||
buf++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(HAVE_LCD_COLOR) && \
|
||||
((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
|
||||
defined(PLUGIN))
|
||||
|
@ -422,41 +427,40 @@ void output_row_8_native(uint32_t row, void * row_in,
|
|||
}
|
||||
#endif /* LCD_PIXELFORMAT */
|
||||
#elif LCD_DEPTH == 16
|
||||
#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
|
||||
/* M:Robe 500 */
|
||||
/* iriver h300, colour iPods, X5 */
|
||||
(void)fb_width;
|
||||
fb_data *dest = (fb_data *)ctx->bm->data + row;
|
||||
fb_data *dest = STRIDE_MAIN((fb_data *)ctx->bm->data + fb_width * row,
|
||||
(fb_data *)ctx->bm->data + row);
|
||||
int delta = 127;
|
||||
unsigned r, g, b;
|
||||
/* setup alpha channel buffer */
|
||||
unsigned char *bm_alpha = NULL;
|
||||
if (ctx->bm->alpha_offset > 0)
|
||||
bm_alpha = ctx->bm->data + ctx->bm->alpha_offset;
|
||||
if (bm_alpha)
|
||||
bm_alpha += ctx->bm->width*row/2;
|
||||
|
||||
for (col = 0; col < ctx->bm->width; col++) {
|
||||
if (ctx->dither)
|
||||
delta = DITHERXDY(col,dy);
|
||||
r = qp->red;
|
||||
g = qp->green;
|
||||
b = (qp++)->blue;
|
||||
b = qp->blue;
|
||||
r = (31 * r + (r >> 3) + delta) >> 8;
|
||||
g = (63 * g + (g >> 2) + delta) >> 8;
|
||||
b = (31 * b + (b >> 3) + delta) >> 8;
|
||||
*dest = LCD_RGBPACK_LCD(r, g, b);
|
||||
dest += ctx->bm->height;
|
||||
dest += STRIDE_MAIN(1, ctx->bm->height);
|
||||
if (bm_alpha) {
|
||||
/* pack alpha channel for 2 pixels into 1 byte */
|
||||
unsigned alpha = 255-qp->alpha;
|
||||
if (col%2)
|
||||
*bm_alpha++ |= alpha&0xf0;
|
||||
else
|
||||
*bm_alpha = alpha>>4;
|
||||
}
|
||||
#else
|
||||
/* iriver h300, colour iPods, X5 */
|
||||
fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
|
||||
int delta = 127;
|
||||
unsigned r, g, b;
|
||||
for (col = 0; col < ctx->bm->width; col++) {
|
||||
if (ctx->dither)
|
||||
delta = DITHERXDY(col,dy);
|
||||
r = qp->red;
|
||||
g = qp->green;
|
||||
b = (qp++)->blue;
|
||||
r = (31 * r + (r >> 3) + delta) >> 8;
|
||||
g = (63 * g + (g >> 2) + delta) >> 8;
|
||||
b = (31 * b + (b >> 3) + delta) >> 8;
|
||||
*dest++ = LCD_RGBPACK_LCD(r, g, b);
|
||||
qp++;
|
||||
}
|
||||
#endif
|
||||
#endif /* LCD_DEPTH */
|
||||
}
|
||||
#endif
|
||||
|
@ -480,6 +484,7 @@ int read_bmp_fd(int fd,
|
|||
int depth, numcolors, compression, totalsize;
|
||||
int ret;
|
||||
bool return_size = format & FORMAT_RETURN_SIZE;
|
||||
bool read_alpha = format & FORMAT_TRANSPARENT;
|
||||
|
||||
unsigned char *bitmap = bm->data;
|
||||
struct uint8_rgb palette[256];
|
||||
|
@ -608,8 +613,14 @@ int read_bmp_fd(int fd,
|
|||
|
||||
if (cformat)
|
||||
totalsize = cformat->get_size(bm);
|
||||
else
|
||||
else {
|
||||
totalsize = BM_SIZE(bm->width,bm->height,format,remote);
|
||||
#ifdef HAVE_REMOTE_LCD
|
||||
if (!remote)
|
||||
#endif
|
||||
if (depth == 32 && read_alpha) /* account for possible 4bit alpha per pixel */
|
||||
totalsize += bm->width * bm->height / 2;
|
||||
}
|
||||
|
||||
if(return_size)
|
||||
{
|
||||
|
@ -704,13 +715,21 @@ int read_bmp_fd(int fd,
|
|||
|
||||
memset(bitmap, 0, totalsize);
|
||||
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
if (read_alpha && depth == 32)
|
||||
bm->alpha_offset = totalsize - (bm->width * bm->height / 2);
|
||||
else
|
||||
bm->alpha_offset = 0;
|
||||
#endif
|
||||
|
||||
struct bmp_args ba = {
|
||||
.fd = fd, .padded_width = padded_width, .read_width = read_width,
|
||||
.width = src_dim.width, .depth = depth, .palette = palette,
|
||||
#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
|
||||
defined(HAVE_BMP_SCALING) || defined(PLUGIN)
|
||||
.cur_row = 0, .cur_col = 0, .part = {0,0}
|
||||
.cur_row = 0, .cur_col = 0, .part = {0,0},
|
||||
#endif
|
||||
.alpha_detected = false,
|
||||
};
|
||||
|
||||
#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
|
||||
|
@ -759,7 +778,6 @@ int read_bmp_fd(int fd,
|
|||
return -6;
|
||||
}
|
||||
#endif
|
||||
|
||||
int row;
|
||||
/* loop to read rows and put them to buffer */
|
||||
for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
|
||||
|
@ -858,5 +876,14 @@ int read_bmp_fd(int fd,
|
|||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
if (!ba.alpha_detected)
|
||||
{ /* if this has an alpha channel, totalsize accounts for it as well
|
||||
* subtract if no actual alpha information was found */
|
||||
if (bm->alpha_offset > 0)
|
||||
totalsize -= bm->width*bm->height/2;
|
||||
bm->alpha_offset = 0;
|
||||
}
|
||||
#endif
|
||||
return totalsize; /* return the used buffer size. */
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ struct uint8_rgb {
|
|||
uint8_t blue;
|
||||
uint8_t green;
|
||||
uint8_t red;
|
||||
uint8_t alpha;
|
||||
};
|
||||
|
||||
struct dim {
|
||||
|
|
|
@ -229,7 +229,6 @@ void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int heig
|
|||
lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
|
||||
}
|
||||
|
||||
/* draw alpha bitmap for anti-alias font */
|
||||
#define ALPHA_COLOR_FONT_DEPTH 2
|
||||
#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
|
||||
#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
|
||||
|
@ -285,11 +284,17 @@ static inline unsigned blend_color(unsigned c, unsigned a)
|
|||
return blend_two_colors(c, current_vp->fg_pattern, a);
|
||||
}
|
||||
|
||||
void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
|
||||
int src_y, int stride, int x, int y,
|
||||
int width, int height)
|
||||
/* Blend an image with an alpha channel
|
||||
* if image is NULL, drawing will happen according to the drawmode
|
||||
* src is the alpha channel (4bit per pixel) */
|
||||
static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
|
||||
const unsigned char *src, int src_x,
|
||||
int src_y, int x, int y,
|
||||
int width, int height,
|
||||
int stride_image, int stride_src)
|
||||
{
|
||||
fb_data *dst, *dst_row;
|
||||
const fb_data *image_row;
|
||||
unsigned dmask = 0x00000000;
|
||||
int drmode = current_vp->drawmode;
|
||||
/* nothing to draw? */
|
||||
|
@ -356,13 +361,22 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
|
|||
{
|
||||
dmask = ~dmask;
|
||||
}
|
||||
/* sourcing from an image ignore drawmode.
|
||||
* Set to DRMODE_BG as we use its code path in the switch below */
|
||||
if (image != NULL)
|
||||
{
|
||||
dmask = 0;
|
||||
drmode = DRMODE_BG;
|
||||
}
|
||||
|
||||
dst_row = LCDADDR(x, y);
|
||||
|
||||
int col, row = height;
|
||||
unsigned data, pixels;
|
||||
unsigned skip_end = (stride - width);
|
||||
unsigned skip_start = src_y * stride + src_x;
|
||||
unsigned skip_end = (stride_src - width);
|
||||
unsigned skip_start = src_y * stride_src + src_x;
|
||||
unsigned skip_start_image = STRIDE_MAIN(src_y * stride_image + src_x,
|
||||
src_x * stride_image + src_y);
|
||||
|
||||
#ifdef ALPHA_BITMAP_READ_WORDS
|
||||
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,
|
|||
#ifdef ALPHA_BITMAP_READ_WORDS
|
||||
pixels = 8 - pixels;
|
||||
#endif
|
||||
if (image)
|
||||
image += skip_start_image;
|
||||
image_row = image;
|
||||
|
||||
/* go through the rows and update each pixel */
|
||||
do
|
||||
|
@ -386,6 +403,12 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
|
|||
col = width;
|
||||
dst = dst_row;
|
||||
dst_row += ROW_INC;
|
||||
if (image_row) {
|
||||
image = image_row;
|
||||
image_row += STRIDE_MAIN(stride_image,1);
|
||||
}
|
||||
else
|
||||
image = dst;
|
||||
#ifdef ALPHA_BITMAP_READ_WORDS
|
||||
#define UPDATE_SRC_ALPHA do { \
|
||||
if (--pixels) \
|
||||
|
@ -431,10 +454,11 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
|
|||
uintptr_t bo = lcd_backdrop_offset;
|
||||
do
|
||||
{
|
||||
*dst = blend_two_colors(*dst, *(fb_data *)((uintptr_t)dst + bo),
|
||||
data & ALPHA_COLOR_LOOKUP_SIZE );
|
||||
*dst = blend_two_colors(*(fb_data *)((uintptr_t)dst + bo),
|
||||
*image, data & ALPHA_COLOR_LOOKUP_SIZE );
|
||||
|
||||
dst += COL_INC;
|
||||
image += STRIDE_MAIN(1, stride_image);
|
||||
UPDATE_SRC_ALPHA;
|
||||
}
|
||||
while (--col);
|
||||
|
@ -443,9 +467,10 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
|
|||
{
|
||||
do
|
||||
{
|
||||
*dst = blend_two_colors(*dst, current_vp->bg_pattern,
|
||||
data & ALPHA_COLOR_LOOKUP_SIZE );
|
||||
*dst = blend_two_colors(current_vp->bg_pattern,
|
||||
*image, data & ALPHA_COLOR_LOOKUP_SIZE );
|
||||
dst += COL_INC;
|
||||
image += STRIDE_MAIN(1, stride_image);
|
||||
UPDATE_SRC_ALPHA;
|
||||
}
|
||||
while (--col);
|
||||
|
@ -516,6 +541,15 @@ void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
|
|||
} while (--row);
|
||||
}
|
||||
|
||||
|
||||
/* draw alpha bitmap for anti-alias font */
|
||||
void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
|
||||
int src_y, int stride, int x, int y,
|
||||
int width, int height)
|
||||
{
|
||||
lcd_alpha_bitmap_part_mix(NULL, src, src_x, src_y, x, y, width, height, 0, stride);
|
||||
}
|
||||
|
||||
/* Draw a partial bitmap (mono or native) including alpha channel */
|
||||
void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y,
|
||||
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,
|
|||
int bitmap_stride = STRIDE_MAIN(bm->width, bm->height);
|
||||
if (bm->format == FORMAT_MONO)
|
||||
lcd_mono_bitmap_part(bm->data, src_x, src_y, bitmap_stride, x, y, width, height);
|
||||
else if (bm->alpha_offset > 0)
|
||||
lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset,
|
||||
src_x, src_y, x, y, width, height,
|
||||
bitmap_stride, bm->width);
|
||||
else
|
||||
lcd_bitmap_transparent_part((fb_data*)bm->data,
|
||||
src_x, src_y, bitmap_stride, x, y, width, height);
|
||||
|
|
|
@ -467,6 +467,9 @@ struct bitmap {
|
|||
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
|
||||
int format;
|
||||
unsigned char *maskdata;
|
||||
#endif
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
int alpha_offset; /* byte-offset of alpha channel in data */
|
||||
#endif
|
||||
unsigned char *data;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue