From 208e29d4d60bd3c843eba61d417fbe539d0cf023 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Sat, 29 Aug 2009 13:00:24 +0200 Subject: [PATCH] FS#8961 - Anti-Aliased Fonts. --- firmware/drivers/lcd-16bit.c | 252 +++++++++++++++++++++++++++++++++++ firmware/drivers/lcd-bitmap-common.c | 10 +- firmware/export/font.h | 3 +- firmware/font.c | 20 ++- 4 files changed, 275 insertions(+), 10 deletions(-) diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c index 7238d7a92..c04d04325 100644 --- a/firmware/drivers/lcd-16bit.c +++ b/firmware/drivers/lcd-16bit.c @@ -804,6 +804,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; +#else + src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE; + data = *src ^ dmask; +#endif + pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD; + 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 c1efd9097..775b56bb3 100644 --- a/firmware/drivers/lcd-bitmap-common.c +++ b/firmware/drivers/lcd-bitmap-common.c @@ -102,8 +102,14 @@ static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str) bits = font_get_bits(pf, ch); - LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, 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, y, width - ofs, + pf->height); + else +#endif + LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, y, width - ofs, + pf->height); x += width - ofs; ofs = 0; diff --git a/firmware/export/font.h b/firmware/export/font.h index d17fa18b8..f8a4589c3 100644 --- a/firmware/export/font.h +++ b/firmware/export/font.h @@ -79,7 +79,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=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 @@ -103,6 +103,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=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*/ diff --git a/firmware/font.c b/firmware/font.c index e02f276ef..46502328e 100644 --- a/firmware/font.c +++ b/firmware/font.c @@ -68,7 +68,7 @@ static struct font_cache font_cache_ui; static int fnt_file = -1; /* >=0 if font is cached */ static uint32_t file_width_offset; /* offset to file width data */ static uint32_t file_offset_offset; /* offset to file offset data */ -static void cache_create(int maxwidth, int height); +static void cache_create(int maxwidth, int height, int depth); static int long_offset = 0; static int glyph_file; /* End Font cache structures */ @@ -139,7 +139,7 @@ static struct font* font_load_header(struct font *pf) pf->maxwidth = readshort(); pf->height = readshort(); pf->ascent = readshort(); - fileptr += 2; /* Skip padding */ + pf->depth = readshort(); pf->firstchar = readlong(); pf->defaultchar = readlong(); pf->size = readlong(); @@ -279,7 +279,7 @@ static struct font* font_load_cached(struct font* pf) fileptr = oldfileptr; /* Create the cache */ - cache_create(pf->maxwidth, pf->height); + cache_create(pf->maxwidth, pf->height, pf->depth); return pf; } @@ -418,23 +418,29 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data) } else { - bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code; + bitmap_offset = pf->depth + ? (pf->height * p->width + 1) / 2 * char_code + : ((pf->height + 7) / 8) * p->width * char_code; } int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset; lseek(fnt_file, file_offset, SEEK_SET); - int src_bytes = p->width * ((pf->height + 7) / 8); + int src_bytes = pf->depth + ? (pf->height * p->width + 1) / 2 + : p->width * ((pf->height + 7) / 8); read(fnt_file, p->bitmap, src_bytes); } /* * Converts cbuf into a font cache */ -static void cache_create(int maxwidth, int height) +static void cache_create(int maxwidth, int height, int depth) { /* maximum size of rotated bitmap */ - int bitmap_size = maxwidth * ((height + 7) / 8); + int bitmap_size = depth + ? (maxwidth * height + 1) / 2 + : maxwidth * ((height + 7) / 8); /* Initialise cache */ font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size); -- 2.11.4.GIT