diff options
Diffstat (limited to 'src/gdisp/gdisp.c')
-rw-r--r-- | src/gdisp/gdisp.c | 545 |
1 files changed, 185 insertions, 360 deletions
diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 4c005079..5ad06f96 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -16,10 +16,6 @@ #if GFX_USE_GDISP -#ifdef GDISP_NEED_TEXT - #include "gdisp/fonts.h" -#endif - /* Include the low level driver information */ #include "gdisp/lld/gdisp_lld.h" @@ -399,43 +395,6 @@ void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t r } #endif -#if (GDISP_NEED_TEXT && GDISP_NEED_MULTITHREAD) - void gdispDrawChar(coord_t x, coord_t y, char c, font_t font, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_char(x, y, c, font, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_TEXT && GDISP_NEED_ASYNC - void gdispDrawChar(coord_t x, coord_t y, char c, font_t font, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWCHAR); - p->drawchar.x = x; - p->drawchar.y = y; - p->drawchar.c = c; - p->drawchar.font = font; - p->drawchar.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif - -#if (GDISP_NEED_TEXT && GDISP_NEED_MULTITHREAD) - void gdispFillChar(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_char(x, y, c, font, color, bgcolor); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_TEXT && GDISP_NEED_ASYNC - void gdispFillChar(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLCHAR); - p->fillchar.x = x; - p->fillchar.y = y; - p->fillchar.c = c; - p->fillchar.font = font; - p->fillchar.color = color; - p->fillchar.bgcolor = bgcolor; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif - #if (GDISP_NEED_PIXELREAD && (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC)) color_t gdispGetPixelColor(coord_t x, coord_t y) { color_t c; @@ -619,377 +578,243 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { } #endif - #if GDISP_NEED_TEXT - void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color) { +#if GDISP_NEED_TEXT + #include "mcufont.h" + + #if GDISP_NEED_ANTIALIAS && GDISP_NEED_PIXELREAD + static void text_draw_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + if (alpha == 255) { + if (count == 1) + gdispDrawPixel(x, y, ((color_t *)state)[0]); + else + gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + } else { + while (count--) { + gdispDrawPixel(x, y, gdispBlendColor(((color_t *)state)[0], gdispGetPixelColor(x, y), alpha)); + x++; + } + } + } + #else + static void text_draw_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + if (alpha > 0x80) { // A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased + if (count == 1) + gdispDrawPixel(x, y, ((color_t *)state)[0]); + else + gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + } + } + #endif + + void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { /* No mutex required as we only call high level functions which have their own mutex */ - coord_t w, p; - char c; - int first; - - if (!str) return; - - first = 1; - p = font->charPadding * font->xscale; - while(*str) { - /* Get the next printable character */ - c = *str++; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) - x += p; + mf_render_character(font, x, y, c, text_draw_char_callback, &color); + } + + #if GDISP_NEED_ANTIALIAS + static void text_fill_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + if (alpha == 255) { + if (count == 1) + gdispDrawPixel(x, y, ((color_t *)state)[0]); else - first = 0; + gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + } else { + while (count--) { + gdispDrawPixel(x, y, gdispBlendColor(((color_t *)state)[0], ((color_t *)state)[1], alpha)); + x++; + } } - - /* Print the character */ - gdispDrawChar(x, y, c, font, color); - x += w; } + #else + #define text_fill_char_callback text_draw_char_callback + #endif + + void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) { + /* No mutex required as we only call high level functions which have their own mutex */ + color_t state[2]; + + state[0] = color; + state[1] = bgcolor; + + gdispFillArea(x, y, mf_character_width(font, c) + font->baseline_x, font->height, bgcolor); + mf_render_character(font, x, y, c, text_fill_char_callback, state); } -#endif - -#if GDISP_NEED_TEXT - void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) { + + typedef struct + { + font_t font; + color_t color; + coord_t x, y; + coord_t cx, cy; + } gdispDrawString_state_t; + + /* Callback to render characters. */ + static uint8_t gdispDrawString_callback(int16_t x, int16_t y, mf_char character, void *state) + { + gdispDrawString_state_t *s = state; + uint8_t w; + + w = mf_character_width(s->font, character); + if (x >= s->x && x+w < s->x + s->cx && y >= s->y && y+s->font->height <= s->y + s->cy) + mf_render_character(s->font, x, y, character, text_draw_char_callback, &s->color); + return w; + } + + void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color) { /* No mutex required as we only call high level functions which have their own mutex */ - coord_t w, h, p; - char c; - int first; + gdispDrawString_state_t state; - if (!str) return; + state.font = font; + state.color = color; + state.x = x; + state.y = y; + state.cx = GDISP.Width - x; + state.cy = GDISP.Height - y; - first = 1; - h = font->height * font->yscale; - p = font->charPadding * font->xscale; - while(*str) { - /* Get the next printable character */ - c = *str++; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) { - gdispFillArea(x, y, p, h, bgcolor); - x += p; - } else - first = 0; - } + mf_render_aligned(font, x, y, MF_ALIGN_LEFT, str, 0, gdispDrawString_callback, &state); + } - /* Print the character */ - gdispFillChar(x, y, c, font, color, bgcolor); - x += w; - } + typedef struct + { + font_t font; + color_t color[2]; + coord_t x, y; + coord_t cx, cy; + } gdispFillString_state_t; + + /* Callback to render characters. */ + static uint8_t gdispFillString_callback(int16_t x, int16_t y, mf_char character, void *state) + { + gdispFillString_state_t *s = state; + uint8_t w; + + w = mf_character_width(s->font, character); + if (x >= s->x && x+w < s->x + s->cx && y >= s->y && y+s->font->height <= s->y + s->cy) + mf_render_character(s->font, x, y, character, text_fill_char_callback, s->color); + return w; } -#endif - -#if GDISP_NEED_TEXT - void gdispDrawStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) { + + void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) { /* No mutex required as we only call high level functions which have their own mutex */ - coord_t w, h, p, ypos, xpos; - char c; - int first; - const char *rstr; + gdispFillString_state_t state; - if (!str) str = ""; - - h = font->height * font->yscale; - p = font->charPadding * font->xscale; - - /* Oops - font too large for the area */ - if (h > cy) return; + state.font = font; + state.color[0] = color; + state.color[1] = bgcolor; + state.x = x; + state.y = y; + state.cx = mf_get_string_width(font, str, 0, 0); + state.cy = font->height; + + gdispFillArea(x, y, state.cx, state.cy, bgcolor); + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, gdispFillString_callback, &state); + } - /* See if we need to fill above the font */ - ypos = (cy - h + 1)/2; - if (ypos > 0) { - y += ypos; - cy -= ypos; - } + void gdispDrawStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) { + /* No mutex required as we only call high level functions which have their own mutex */ + gdispDrawString_state_t state; - /* See if we need to fill below the font */ - ypos = cy - h; - if (ypos > 0) - cy -= ypos; + state.font = font; + state.color = color; + state.x = x; + state.y = y; + state.cx = cx; + state.cy = cy; - /* get the start of the printable string and the xpos */ + /* Select the anchor position */ switch(justify) { case justifyCenter: - /* Get the length of the entire string */ - w = gdispGetStringWidth(str, font); - if (w <= cx) - xpos = x + (cx - w)/2; - else { - /* Calculate how much of the string we need to get rid of */ - ypos = (w - cx)/2; - xpos = 0; - first = 1; - while(*str) { - /* Get the next printable character */ - c = *str++; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) { - xpos += p; - if (xpos > ypos) break; - } else - first = 0; - } - - /* Print the character */ - xpos += w; - if (xpos > ypos) break; - } - xpos = ypos - xpos + x; - } + x += (cx + 1) / 2; break; case justifyRight: - /* Find the end of the string */ - for(rstr = str; *str; str++); - xpos = x+cx - 2; - first = 1; - for(str--; str >= rstr; str--) { - /* Get the next printable character */ - c = *str; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) { - if (xpos - p < x) break; - xpos -= p; - } else - first = 0; - } - - /* Print the character */ - if (xpos - w < x) break; - xpos -= w; - } - str++; + x += cx; break; - case justifyLeft: - /* Fall through */ - default: - xpos = x+1; + default: // justifyLeft + x += font->baseline_x; break; } - - /* Print characters until we run out of room */ - first = 1; - while(*str) { - /* Get the next printable character */ - c = *str++; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) { - if (xpos + p > x+cx) break; - xpos += p; - } else - first = 0; - } + y += (cy+1 - font->height)/2; - /* Print the character */ - if (xpos + w > x+cx) break; - gdispDrawChar(xpos, y, c, font, color); - xpos += w; - } + mf_render_aligned(font, x, y, justify, str, 0, gdispDrawString_callback, &state); } -#endif - -#if GDISP_NEED_TEXT + void gdispFillStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) { /* No mutex required as we only call high level functions which have their own mutex */ - coord_t w, h, p, ypos, xpos; - char c; - int first; - const char *rstr; - - if (!str) str = ""; - - h = font->height * font->yscale; - p = font->charPadding * font->xscale; + gdispFillString_state_t state; - /* Oops - font too large for the area */ - if (h > cy) return; + state.font = font; + state.color[0] = color; + state.color[1] = bgcolor; + state.x = x; + state.y = y; + state.cx = cx; + state.cy = cy; - /* See if we need to fill above the font */ - ypos = (cy - h + 1)/2; - if (ypos > 0) { - gdispFillArea(x, y, cx, ypos, bgcolor); - y += ypos; - cy -= ypos; - } - - /* See if we need to fill below the font */ - ypos = cy - h; - if (ypos > 0) { - gdispFillArea(x, y+cy-ypos, cx, ypos, bgcolor); - cy -= ypos; - } + gdispFillArea(x, y, cx, cy, bgcolor); - /* get the start of the printable string and the xpos */ + /* Select the anchor position */ switch(justify) { case justifyCenter: - /* Get the length of the entire string */ - w = gdispGetStringWidth(str, font); - if (w <= cx) - xpos = x + (cx - w)/2; - else { - /* Calculate how much of the string we need to get rid of */ - ypos = (w - cx)/2; - xpos = 0; - first = 1; - while(*str) { - /* Get the next printable character */ - c = *str++; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) { - xpos += p; - if (xpos > ypos) break; - } else - first = 0; - } - - /* Print the character */ - xpos += w; - if (xpos > ypos) break; - } - xpos = ypos - xpos + x; - } + x += (cx + 1) / 2; break; case justifyRight: - /* Find the end of the string */ - for(rstr = str; *str; str++); - xpos = x+cx - 2; - first = 1; - for(str--; str >= rstr; str--) { - /* Get the next printable character */ - c = *str; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) { - if (xpos - p < x) break; - xpos -= p; - } else - first = 0; - } - - /* Print the character */ - if (xpos - w < x) break; - xpos -= w; - } - str++; + x += cx; break; - case justifyLeft: - /* Fall through */ - default: - xpos = x+1; + default: // justifyLeft + x += font->baseline_x; break; } + y += (cy+1 - font->height)/2; - /* Fill any space to the left */ - if (x < xpos) - gdispFillArea(x, y, xpos-x, cy, bgcolor); - - /* Print characters until we run out of room */ - first = 1; - while(*str) { - /* Get the next printable character */ - c = *str++; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) { - if (xpos + p > x+cx) break; - gdispFillArea(xpos, y, p, cy, bgcolor); - xpos += p; - } else - first = 0; - } - - /* Print the character */ - if (xpos + w > x+cx) break; - gdispFillChar(xpos, y, c, font, color, bgcolor); - xpos += w; - } - - /* Fill any space to the right */ - if (xpos < x+cx) - gdispFillArea(xpos, y, x+cx-xpos, cy, bgcolor); + /* Render */ + mf_render_aligned(font, x, y, justify, str, 0, gdispFillString_callback, &state); } -#endif - -#if GDISP_NEED_TEXT + coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) { /* No mutex required as we only read static data */ switch(metric) { - case fontHeight: return font->height * font->yscale; - case fontDescendersHeight: return font->descenderHeight * font->yscale; - case fontLineSpacing: return font->lineSpacing * font->yscale; - case fontCharPadding: return font->charPadding * font->xscale; - case fontMinWidth: return font->minWidth * font->xscale; - case fontMaxWidth: return font->maxWidth * font->xscale; + case fontHeight: return font->height; + case fontDescendersHeight: return font->height - font->baseline_y; + case fontLineSpacing: return font->line_height; + case fontCharPadding: return 0; + case fontMinWidth: return font->min_x_advance; + case fontMaxWidth: return font->max_x_advance; } return 0; } -#endif - -#if GDISP_NEED_TEXT + coord_t gdispGetCharWidth(char c, font_t font) { /* No mutex required as we only read static data */ - return _getCharWidth(font, c) * font->xscale; + return mf_character_width(font, c); } -#endif - -#if GDISP_NEED_TEXT + coord_t gdispGetStringWidth(const char* str, font_t font) { /* No mutex required as we only read static data */ - coord_t w, p, x; - char c; - int first; - - first = 1; - x = 0; - p = font->charPadding * font->xscale; - while(*str) { - /* Get the next printable character */ - c = *str++; - w = _getCharWidth(font, c) * font->xscale; - if (!w) continue; - - /* Handle inter-character padding */ - if (p) { - if (!first) - x += p; - else - first = 0; - } - - /* Add the character width */ - x += w; - } - return x; + return mf_get_string_width(font, str, 0, 0); } #endif +color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha) +{ + uint16_t fg_ratio = alpha + 1; + uint16_t bg_ratio = 256 - alpha; + uint16_t r, g, b; + + r = RED_OF(fg) * fg_ratio; + g = GREEN_OF(fg) * fg_ratio; + b = BLUE_OF(fg) * fg_ratio; + + r += RED_OF(bg) * bg_ratio; + g += GREEN_OF(bg) * bg_ratio; + b += BLUE_OF(bg) * bg_ratio; + + r /= 256; + g /= 256; + b /= 256; + + return RGB2COLOR(r, g, b); +} + #if (!defined(gdispPackPixels) && !defined(GDISP_PIXELFORMAT_CUSTOM)) void gdispPackPixels(pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color) { /* No mutex required as we only read static data */ |