diff options
| author | Thomas Martitz <kugel@rockbox.org> | 2011-03-05 18:36:51 +0000 |
|---|---|---|
| committer | Thomas Martitz <kugel@rockbox.org> | 2011-03-05 18:36:51 +0000 |
| commit | 9edd6d4ee912273690b2600e8c52183dfa058eb9 (patch) | |
| tree | cf6b0723f42c090022b94b38b3c4d856e9378d40 /firmware | |
| parent | 396ddd9fd79e458d1107f4065ce072eef99b6bce (diff) | |
| download | rockbox-9edd6d4ee912273690b2600e8c52183dfa058eb9.zip rockbox-9edd6d4ee912273690b2600e8c52183dfa058eb9.tar.gz rockbox-9edd6d4ee912273690b2600e8c52183dfa058eb9.tar.bz2 rockbox-9edd6d4ee912273690b2600e8c52183dfa058eb9.tar.xz | |
Anti-Aliased Fonts support.
This enables Rockbox to render anti-aliased fonts using an alpha blending method.
The input font bitmaps are 4bit, i.e. 4x larger, but the metadata size stays the same.
A tool, convttf, for converting ttf fonts directly to the Rockbox fnt format is provided.
It has a useful help output, but the parameter that works best is -c1 or -c2 (2 for larger font sizes).
Flyspray: FS#8961
Author: Initial work by Jonas Hurrelmann, further work by Fred Bauer, Andrew Mahone, Teruaki Kawashima and myself.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29523 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
| -rw-r--r-- | firmware/drivers/lcd-16bit.c | 252 | ||||
| -rw-r--r-- | firmware/drivers/lcd-bitmap-common.c | 10 | ||||
| -rw-r--r-- | firmware/export/font.h | 3 | ||||
| -rw-r--r-- | firmware/font.c | 31 |
4 files changed, 281 insertions, 15 deletions
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c index be4f21f..a2eb3e6 100644 --- a/firmware/drivers/lcd-16bit.c +++ b/firmware/drivers/lcd-16bit.c @@ -901,6 +901,258 @@ 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) +#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH) +#define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH) +#ifdef CPU_ARM +#define BLEND_INIT do {} while (0) +#define BLEND_START(acc, color, alpha) \ + asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha)) +#define BLEND_CONT(acc, color, alpha) \ + asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha)) +#define BLEND_OUT(acc) do {} while (0) +#elif defined(CPU_COLDFIRE) +#define ALPHA_BITMAP_READ_WORDS +#define BLEND_INIT coldfire_set_macsr(EMAC_UNSIGNED) +#define BLEND_START(acc, color, alpha) \ + asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha)) +#define BLEND_CONT BLEND_START +#define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc)) +#else +#define BLEND_INIT do {} while (0) +#define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha)) +#define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha)) +#define BLEND_OUT(acc) do {} while (0) +#endif + +/* Blend the given two colors */ +static inline unsigned blend_two_colors(unsigned c1, unsigned c2, unsigned a) +{ + a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1); +#if (LCD_PIXELFORMAT == RGB565SWAPPED) + c1 = swap16(c1); + c2 = swap16(c2); +#endif + unsigned c1l = (c1 | (c1 << 16)) & 0x07e0f81f; + unsigned c2l = (c2 | (c2 << 16)) & 0x07e0f81f; + unsigned p; + BLEND_START(p, c1l, a); + BLEND_CONT(p, c2l, ALPHA_COLOR_LOOKUP_SIZE + 1 - a); + BLEND_OUT(p); + p = (p >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f; + p |= (p >> 16); +#if (LCD_PIXELFORMAT == RGB565SWAPPED) + return swap16(p); +#else + return p; +#endif +} + +/* Blend the given color with the value from the alpha_color_lookup table */ +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) +{ + fb_data *dst, *backdrop; + unsigned dmask = 0x00000000; + int drmode = current_vp->drawmode; + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) + return; + /* initialize blending */ + BLEND_INIT; + + /* 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; + + if (drmode & DRMODE_INVERSEVID) + { + dmask = 0xffffffff; + drmode &= DRMODE_SOLID; /* mask out inversevid */ + } + if (drmode == DRMODE_BG) + { + dmask = ~dmask; + } + + dst = LCDADDR(current_vp->x + x, current_vp->y + y); + + int col, row = height; + unsigned data, pixels; + unsigned skip_end = (stride - width); + unsigned skip_start = src_y * stride + src_x; + +#ifdef ALPHA_BITMAP_READ_WORDS + uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3); + skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3); + src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD; + data = letoh32(*src_w++) ^ dmask; + pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD; +#else + src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE; + data = *src ^ dmask; + pixels = skip_start % ALPHA_COLOR_PIXEL_PER_BYTE; +#endif + data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; +#ifdef ALPHA_BITMAP_READ_WORDS + pixels = 8 - pixels; +#endif + + do + { + col = width; +#ifdef ALPHA_BITMAP_READ_WORDS +#define UPDATE_SRC_ALPHA do { \ + if (--pixels) \ + data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ + else \ + { \ + data = letoh32(*src_w++) ^ dmask; \ + pixels = ALPHA_COLOR_PIXEL_PER_WORD; \ + } \ + } while (0) +#elif ALPHA_COLOR_PIXEL_PER_BYTE == 2 +#define UPDATE_SRC_ALPHA do { \ + if (pixels ^= 1) \ + data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ + else \ + data = *(++src) ^ dmask; \ + } while (0) +#else +#define UPDATE_SRC_ALPHA do { \ + if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \ + data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ + else \ + data = *(++src) ^ dmask; \ + } while (0) +#endif + /* we don't want to have this in our inner + * loop and the codesize increase is minimal */ + switch (drmode) + { + case DRMODE_COMPLEMENT: + do + { + *dst=blend_two_colors(*dst, ~(*dst), + data & ALPHA_COLOR_LOOKUP_SIZE ); + dst++; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_BG: + if(lcd_backdrop) + { + backdrop = (fb_data *)((long)dst+lcd_backdrop_offset); + do + { + *dst=blend_two_colors(*dst, *(backdrop++), + data & ALPHA_COLOR_LOOKUP_SIZE ); + dst++; + UPDATE_SRC_ALPHA; + } + while (--col); + } + else + { + do + { + *dst=blend_two_colors(*dst, current_vp->bg_pattern, + data & ALPHA_COLOR_LOOKUP_SIZE ); + dst++; + UPDATE_SRC_ALPHA; + } + while (--col); + } + break; + case DRMODE_FG: + do + { + *dst=blend_color(*dst, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst++; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_SOLID: + if(lcd_backdrop) + { + backdrop = (fb_data *)((long)dst+lcd_backdrop_offset); + do + { + *(dst++)=blend_color(*(backdrop++), + data & ALPHA_COLOR_LOOKUP_SIZE ); + UPDATE_SRC_ALPHA; + } + while (--col); + } + else + { + do + { + *(dst++)=blend_color(current_vp->bg_pattern, + data & ALPHA_COLOR_LOOKUP_SIZE ); + UPDATE_SRC_ALPHA; + } + while (--col); + } + break; + } +#ifdef ALPHA_BITMAP_READ_WORDS + if (skip_end < pixels) + { + pixels -= skip_end; + data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; + } else { + pixels = skip_end - pixels; + src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD; + pixels %= ALPHA_COLOR_PIXEL_PER_WORD; + data = letoh32(*src_w++) ^ dmask; + data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; + pixels = 8 - pixels; + } +#else + if (skip_end) + { + pixels += skip_end; + if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE) + { + src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE; + pixels %= ALPHA_COLOR_PIXEL_PER_BYTE; + data = *src ^ dmask; + data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; + } else + data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; + } +#endif + dst += LCD_WIDTH - width; + } 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, diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c index 364fb3c..fc84fdd 100644 --- a/firmware/drivers/lcd-bitmap-common.c +++ b/firmware/drivers/lcd-bitmap-common.c @@ -203,9 +203,15 @@ static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str) } bits = font_get_bits(pf, *ucs); - LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x + base_ofs, y, - width - ofs, pf->height); +#if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR) + if (pf->depth) + lcd_alpha_bitmap_part(bits, ofs, 0, width, x + base_ofs, y, + width - ofs, pf->height); + else +#endif + LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x + base_ofs, + y, width - ofs, pf->height); if (is_diac) { current_vp->drawmode = drawmode; diff --git a/firmware/export/font.h b/firmware/export/font.h index 0a75768..a85f95e 100644 --- a/firmware/export/font.h +++ b/firmware/export/font.h @@ -68,7 +68,7 @@ enum { * USHORT maxwidth 2 font max width in pixels * 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=1bit and 1=4bit * ULONG firstchar 4 first character code in font * ULONG defaultchar 4 default character code in font * ULONG size 4 # characters in font @@ -92,6 +92,7 @@ struct font { int ascent; /* ascent (baseline) height*/ int firstchar; /* first character in bitmap*/ int size; /* font size in glyphs*/ + int depth; /* depth of the font, 0=1bit and 1=4bit */ const unsigned char *bits; /* 8-bit column bitmap data*/ const void *offset; /* offsets into bitmap data, uint16_t if bits_size < 0xFFDB else uint32_t*/ diff --git a/firmware/font.c b/firmware/font.c index 45ddef3a..0f9f453 100644 --- a/firmware/font.c +++ b/firmware/font.c @@ -89,7 +89,7 @@ static struct font* sysfonts[MAXFONTS] = { &sysfont, &font_ui, NULL}; /* Font cache structures */ -static void cache_create(struct font* pf, int maxwidth, int height); +static void cache_create(struct font* pf); static void glyph_cache_load(struct font* pf); /* End Font cache structures */ @@ -132,6 +132,13 @@ static int32_t readlong(struct font *pf) return l; } +static int glyph_bytes( struct font *pf, int width ) +{ + return pf->depth ? + (pf->height * width + 1) / 2: + width * ((pf->height + 7) / 8); +} + void font_reset(struct font *pf) { unsigned char* buffer = NULL; @@ -168,7 +175,7 @@ static struct font* font_load_header(struct font *pf) pf->maxwidth = readshort(pf); pf->height = readshort(pf); pf->ascent = readshort(pf); - pf->buffer_position += 2; /* Skip padding */ + pf->depth = readshort(pf); pf->firstchar = readlong(pf); pf->defaultchar = readlong(pf); pf->size = readlong(pf); @@ -308,7 +315,7 @@ static struct font* font_load_cached(struct font* pf) pf->buffer_position = oldfileptr; /* Create the cache */ - cache_create(pf, pf->maxwidth, pf->height); + cache_create(pf); return pf; } @@ -436,7 +443,8 @@ int font_load(struct font* pf, const char *path) { /* currently, font loading replaces earlier font allocation*/ buffer = (unsigned char *)(((intptr_t)main_buf + 3) & ~3); - buffer_size = MAX_FONT_SIZE; + /* make sure above doesn't exceed */ + buffer_size = MAX_FONT_SIZE-3; } else { @@ -516,24 +524,23 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data) } else { - bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code; + bitmap_offset = char_code * glyph_bytes(pf, p->width); } int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset; lseek(pf->fd, file_offset, SEEK_SET); - - int src_bytes = p->width * ((pf->height + 7) / 8); + int src_bytes = glyph_bytes(pf, p->width); read(pf->fd, p->bitmap, src_bytes); } /* * Converts cbuf into a font cache */ -static void cache_create(struct font* pf, int maxwidth, int height) +static void cache_create(struct font* pf) { /* maximum size of rotated bitmap */ - int bitmap_size = maxwidth * ((height + 7) / 8); - + int bitmap_size = glyph_bytes( pf, pf->maxwidth); + /* Initialise cache */ font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size); } @@ -578,7 +585,7 @@ const unsigned char* font_get_bits(struct font* pf, unsigned short char_code) bits += ((uint32_t*)(pf->offset))[char_code]; } else - bits += ((pf->height + 7) / 8) * pf->maxwidth * char_code; + bits += char_code * glyph_bytes(pf, pf->maxwidth); } return bits; @@ -655,7 +662,7 @@ int font_glyphs_to_bufsize(const char *path, int glyphs) bufsize = LRU_SLOT_OVERHEAD + sizeof(struct font_cache_entry) + sizeof( unsigned short); - bufsize += f.maxwidth * ((f.height + 7) / 8); + bufsize += glyph_bytes(&f, f.maxwidth); bufsize *= glyphs; if ( bufsize < FONT_HEADER_SIZE ) bufsize = FONT_HEADER_SIZE; |