aboutsummaryrefslogtreecommitdiffstats
path: root/src/gdisp/gdisp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gdisp/gdisp.c')
-rw-r--r--src/gdisp/gdisp.c545
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 */