Index: tools/convbdf.c =================================================================== --- tools/convbdf.c (revision 17342) +++ tools/convbdf.c (working copy) @@ -970,6 +970,7 @@ " %d, /* ascent */\n" " %d, /* firstchar */\n" " %d, /* size */\n" + " 0, /* depth */\n" " _font_bits, /* bits */\n" " %s /* offset */\n" " %s\n" Index: firmware/export/font.h =================================================================== --- firmware/export/font.h (revision 17342) +++ firmware/export/font.h (working copy) @@ -75,6 +75,7 @@ * USHORT height 2 font height in pixels * USHORT ascent 2 font ascent (baseline) in pixels * USHORT pad 2 unused, pad to 32-bit boundary + * USHORT depth 2 depth of the font, 0=1-bit and 1=4-bit * ULONG firstchar 4 first character code in font * ULONG defaultchar 4 default character code in font * ULONG size 4 # characters in font @@ -99,6 +99,7 @@ int ascent; /* ascent (baseline) height*/ int firstchar; /* first character in bitmap*/ int size; /* font size in glyphs*/ + int depth; /* depth of the font, 0=1-bit and 1=4-bit */ const unsigned char *bits; /* 8-bit column bitmap data*/ const unsigned short *offset; /* offsets into bitmap data*/ const unsigned char *width; /* character widths or NULL if fixed*/ Index: firmware/font.c =================================================================== --- firmware/font.c (revision 17342) +++ firmware/font.c (working copy) @@ -63,7 +63,7 @@ /* Font cache structures */ static struct font_cache sys_font_cache[MAXCACHEFONTS]; static struct font_file_info fntfile[MAXCACHEFONTS]; -static void cache_create(int maxwidth, int height, int font); +static void cache_create(int maxwidth, int height, int font, int depth); static void font_cache_init(void); /* End Font cache structures */ @@ -171,7 +171,7 @@ static struct font* font_load_header(struct font *pf, int font) { char version[4+1]; - unsigned short maxwidth, height, ascent, pad; + unsigned short maxwidth, height, ascent, depth; uint32_t firstchar, defaultchar, size; uint32_t nbits; @@ -134,8 +134,9 @@ return NULL; pf->ascent = ascent; - if (!readshort(&pad, font)) + if (!readshort(&depth, font)) return NULL; + pf->depth = depth; if (!readlong(&firstchar, font)) return NULL; @@ -274,7 +274,7 @@ fileptr = oldfileptr; /* Create the cache */ - cache_create(pf->maxwidth, pf->height, font); + cache_create(pf->maxwidth, pf->height, font, pf->depth); return pf; } @@ -440,18 +440,18 @@ int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset; lseek(fntfile[font].font_fd, file_offset, SEEK_SET); - int src_bytes = p->width * ((pf->height + 7) / 8); + int src_bytes = p->width * ((pf->height + 7) / 8) * (1 << pf->depth); read(fntfile[font].font_fd, p->bitmap, src_bytes); } /* * Converts cbuf into a font cache */ -static void cache_create(int maxwidth, int height, int font) +static void cache_create(int maxwidth, int height, int font, int depth) { /* maximum size of rotated bitmap */ - int bitmap_size = maxwidth * ((height + 7) / 8); - + int bitmap_size = maxwidth * ((height + 7) / 8) * (1 << depth); + /* Initialise cache */ font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size); } Index: firmware/drivers/lcd-16bit.c =================================================================== --- firmware/drivers/lcd-16bit.c (revision 17342) +++ firmware/drivers/lcd-16bit.c (working copy) @@ -74,6 +74,21 @@ struct viewport* current_vp IDATA_ATTR = &default_vp; #endif +static fb_data alpha_color_lookup[] = {0xffff, 0xdefb, 0xce79, 0xbdf7, + 0xad75, 0x9cf3, 0x8c71, 0x7bef, + 0x6b6d, 0x5aeb, 0x4a69, 0x39e7, + 0x2965, 0x18e3, 0x861}; + +#if 0 +static unsigned char alpha_color_lookup_shift = 4; +static unsigned char alpha_color_lookup_size = 15; +#else +#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) +#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH) +#endif + /* LCD init */ void lcd_init(void) { @@ -802,6 +817,268 @@ lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height); } + +#if (ALPHA_COLOR_LOOKUP_SIZE==255) +/* Blend the given color with the foreground color **very slow** */ +static inline fb_data blend_color(fb_data c, unsigned char a) +{ + if ( a == ALPHA_COLOR_LOOKUP_SIZE ) return c; + if ( a == 0 ) return current_vp->fg_pattern; + + unsigned char sr = RGB_UNPACK_RED(c); + unsigned char sg = RGB_UNPACK_GREEN(c); + unsigned char sb = RGB_UNPACK_BLUE(c); + + unsigned char dr = RGB_UNPACK_RED(current_vp->fg_pattern); + unsigned char dg = RGB_UNPACK_GREEN(current_vp->fg_pattern); + unsigned char db = RGB_UNPACK_BLUE(current_vp->fg_pattern); + + fb_data red = (a * (sr - dr) >> 8) + dr; + fb_data green = (a * (sg - dg) >> 8) + dg; + fb_data blue = (a * (sb - db) >> 8) + db; + + return LCD_RGBPACK(red, green, blue); +} +#else +/* Blend the given color with the value from the alpha_color_lookup table */ +static inline fb_data blend_color(fb_data c, unsigned char a) +{ + /* no computation on full opaque/transparent */ + if ( a == ALPHA_COLOR_LOOKUP_SIZE ) return c; + if ( a == 0 ) return current_vp->fg_pattern; + /*if ( alpha_color_lookup_size == 255 ) return slow_blend_color(c,a);*/ +#if (LCD_PIXELFORMAT == RGB565SWAPPED) + c = swap16(c); +#endif + /* alpha-blend colors using integer based approach with additional lookup table */ + unsigned int p = ((((c|(c<<16)) & 0x07e0f81f) * (a)) >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f; +#if (LCD_PIXELFORMAT == RGB565SWAPPED) + return swap16((fb_data)(p | ( p >> 16 ))) + alpha_color_lookup[a]; +#else + return (fb_data)(p | ( p >> 16 )) + alpha_color_lookup[a]; +#endif +} +#endif + +/* Update the alpha_color_lookup table */ +static void update_alpha_color_lookup(fb_data c) +{ + int i; + unsigned int p; + if ( ALPHA_COLOR_LOOKUP_SIZE == 255 ) return; + alpha_color_lookup[0] = c; +#if (LCD_PIXELFORMAT == RGB565SWAPPED) + c = swap16(c); +#endif + for (i = 1; i < ALPHA_COLOR_LOOKUP_SIZE; i++) + { + p = ((((c|(c<<16)) & 0x07e0f81f) * (ALPHA_COLOR_LOOKUP_SIZE-i)) >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f; +#if (LCD_PIXELFORMAT == RGB565SWAPPED) + alpha_color_lookup[i] = swap16((fb_data)(p | ( p >> 16 ))); +#else + alpha_color_lookup[i] = (fb_data)(p | ( p >> 16 )); +#endif + } +} + + +void lcd_alpha_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) + ICODE_ATTR; +void lcd_alpha_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) +{ + bool has_backdrop; + fb_data *dst, *backdrop; + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) + return; + + /* update the lookup table if foreground color has changed */ +#if 0 + /* support for 2-bit and 8-bit depth */ + if ( current_vp->fg_pattern != alpha_color_lookup[0] || alpha_color_lookup_shift != (1 << depth) ) { + alpha_color_lookup_shift = 1 << depth; + alpha_color_lookup_size = (1 << alpha_color_lookup_shift) - 1; + update_alpha_color_lookup(current_vp->fg_pattern); + } + unsigned char pixel_per_byte = 8 >> depth; +#endif + if ( current_vp->fg_pattern != alpha_color_lookup[0] ) + update_alpha_color_lookup(current_vp->fg_pattern); + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + dst = LCDADDR(current_vp->x + x, current_vp->y + y); + has_backdrop = (lcd_backdrop != NULL); + if (current_vp->drawmode == DRMODE_FG) + backdrop = dst; + else + backdrop = lcd_backdrop + (current_vp->y + y) * LCD_WIDTH + current_vp->x + x; + + const int row_inc = LCD_WIDTH - width; + + const char skip_start = src_y * stride + src_x; + const char skip_end = (stride - width); + +#if (ALPHA_COLOR_PIXEL_PER_BYTE == 2) + const char skip_start_bytes = skip_start >> 1; + const char skip_start_bits = skip_start & 1; + + const char skip_end_bytes = skip_end >> 1; + const char skip_end_bits = skip_end & 1; +#else + /* the div and modulo operations could be optimized */ + const char skip_start_bytes = skip_start / ALPHA_COLOR_PIXEL_PER_BYTE; + const char skip_start_bits = skip_start % ALPHA_COLOR_PIXEL_PER_BYTE; + + const char skip_end_bytes = skip_end / ALPHA_COLOR_PIXEL_PER_BYTE; + const char skip_end_bits = skip_end % ALPHA_COLOR_PIXEL_PER_BYTE; +#endif + + int col; + int row = height; + unsigned char current_data; + unsigned char numbits = ALPHA_COLOR_PIXEL_PER_BYTE; + if ( skip_start ) + { + if ( numbits <= skip_start_bits) + { + src++; + numbits += ALPHA_COLOR_PIXEL_PER_BYTE; + } + numbits -= skip_start_bits; + src += skip_start_bytes; + current_data = *src; + current_data >>= ALPHA_COLOR_LOOKUP_SHIFT * ALPHA_COLOR_PIXEL_PER_BYTE - ( numbits << ALPHA_COLOR_FONT_DEPTH ); + } + else + current_data = *src; + do + { + col = width; +#if 0 + do + { + unsigned char font_bits = current_data & ALPHA_COLOR_LOOKUP_SIZE; + switch (current_vp->drawmode) + { + case DRMODE_FG: + *(dst++)=blend_color( *(backdrop++), font_bits ); + break; + case (DRMODE_FG|DRMODE_INVERSEVID): + *(dst++)=blend_color( *(backdrop++), ALPHA_COLOR_LOOKUP_SIZE-font_bits ); + break; + case (DRMODE_SOLID|DRMODE_INVERSEVID): + *(dst++)=blend_color( has_backdrop ? *(backdrop++) : bg_pattern, ALPHA_COLOR_LOOKUP_SIZE-font_bits ); + break; + case DRMODE_SOLID: + default: + *(dst++)=blend_color( has_backdrop ? *(backdrop++) : bg_pattern, font_bits ); + break; + } + if (--numbits == 0) + { + current_data = *(++src); + numbits = ALPHA_COLOR_PIXEL_PER_BYTE; + } + else + current_data >>= ALPHA_COLOR_LOOKUP_SHIFT; + } while (--col); +#endif + /* we don't want to have this in our inner loop and the codesize increase is minimal */ + switch (current_vp->drawmode) + { + case DRMODE_FG: + do + { + *(dst++)=blend_color( *(backdrop++), current_data & ALPHA_COLOR_LOOKUP_SIZE ); + if (--numbits == 0) + { + current_data = *(++src); + numbits = ALPHA_COLOR_PIXEL_PER_BYTE; + } + else + current_data >>= ALPHA_COLOR_LOOKUP_SHIFT; + } while (--col); + break; + case (DRMODE_FG|DRMODE_INVERSEVID): + do + { + *(dst++)=blend_color( *(backdrop++), ALPHA_COLOR_LOOKUP_SIZE-(current_data & ALPHA_COLOR_LOOKUP_SIZE) ); + if (--numbits == 0) + { + current_data = *(++src); + numbits = ALPHA_COLOR_PIXEL_PER_BYTE; + } + else + current_data >>= ALPHA_COLOR_LOOKUP_SHIFT; + } while (--col); + break; + case (DRMODE_SOLID|DRMODE_INVERSEVID): + do + { + *(dst++)=blend_color( has_backdrop ? *(backdrop++) : + current_vp->bg_pattern, ALPHA_COLOR_LOOKUP_SIZE-(current_data & ALPHA_COLOR_LOOKUP_SIZE) ); + if (--numbits == 0) + { + current_data = *(++src); + numbits = ALPHA_COLOR_PIXEL_PER_BYTE; + } + else + current_data >>= ALPHA_COLOR_LOOKUP_SHIFT; + } while (--col); + break; + case DRMODE_SOLID: + default: + do + { + *(dst++)=blend_color( has_backdrop ? *(backdrop++) : current_vp->bg_pattern, current_data & ALPHA_COLOR_LOOKUP_SIZE ); + if (--numbits == 0) + { + current_data = *(++src); + numbits = ALPHA_COLOR_PIXEL_PER_BYTE; + } + else + current_data >>= ALPHA_COLOR_LOOKUP_SHIFT; + } while (--col); + break; + } + if ( skip_end ) + { + if ( numbits <= skip_end_bits ) + { + src++; + numbits += ALPHA_COLOR_PIXEL_PER_BYTE; + } + numbits -= skip_end_bits; + src += skip_end_bytes; + current_data = *src; + current_data >>= ALPHA_COLOR_LOOKUP_SHIFT * ALPHA_COLOR_PIXEL_PER_BYTE - ( numbits << ALPHA_COLOR_FONT_DEPTH ); + } + dst += row_inc; + backdrop += row_inc; + } while (--row); +} + /* Draw a partial native bitmap */ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y, int stride, int x, int y, int width, @@ -936,7 +1213,10 @@ bits = font_get_bits(pf, ch); - lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); + if (pf->depth) + lcd_alpha_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); + else + lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); x += width - ofs; ofs = 0;