diff --git a/meson.build b/meson.build index 5ccea935..be8efd89 100644 --- a/meson.build +++ b/meson.build @@ -18,10 +18,10 @@ openrtx_src = ['openrtx/src/main.c', 'openrtx/src/threads.c'] openrtx_inc = ['openrtx/include/interfaces', - 'openrtx/include/fonts', 'openrtx/include', 'platform/drivers/ADC', - 'platform/drivers/tones'] + 'platform/drivers/tones', + 'openrtx/include/fonts/adafruit'] ## RTOS rtos_src = ['rtos/uC-OS3/Source/__dbg_uCOS-III.c', diff --git a/openrtx/include/interfaces/graphics.h b/openrtx/include/interfaces/graphics.h index ee6b607b..5ea371c1 100644 --- a/openrtx/include/interfaces/graphics.h +++ b/openrtx/include/interfaces/graphics.h @@ -23,6 +23,12 @@ #include #include #include +#include "gfxfont.h" +#include "TomThumb.h" +#include "FreeSans9pt7b.h" +#include "FreeSans12pt7b.h" +#include "FreeSans18pt7b.h" +#include "FreeSans24pt7b.h" /** * Standard high-level graphic interface for all display types. @@ -72,20 +78,29 @@ typedef struct color_t typedef enum { - FONT_SIZE_1 = 0, - FONT_SIZE_1_BOLD, - FONT_SIZE_2, - FONT_SIZE_3, - FONT_SIZE_4 + FONT_SIZE_6PT = 0, + FONT_SIZE_9PT, + FONT_SIZE_12PT, + FONT_SIZE_18PT, + FONT_SIZE_24PT } fontSize_t; typedef enum { - TEXT_ALIGN_LEFT = 0, - TEXT_ALIGN_CENTER, - TEXT_ALIGN_RIGHT + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_CENTER, + TEXT_ALIGN_RIGHT } textAlign_t; +/** + * Selection of the fonts, ordered by the fontSize_t enum. + */ +static GFXfont fonts[] = { TomThumb, // 6pt + FreeSans9pt7b, // 9pt + FreeSans12pt7b, // 12pt + FreeSans18pt7b, // 18pt + FreeSans24pt7b }; // 24pt + /** * This function calls the correspondent method of the low level interface display.h * It initializes the display. diff --git a/openrtx/src/graphics/graphics_bw.c b/openrtx/src/graphics/graphics_bw.c index 736fac02..0c21cedf 100644 --- a/openrtx/src/graphics/graphics_bw.c +++ b/openrtx/src/graphics/graphics_bw.c @@ -27,7 +27,6 @@ #include #include "display.h" #include "graphics.h" -#include "font_OpenGD77.h" typedef enum { @@ -158,92 +157,104 @@ void gfx_drawRect(point_t start, uint16_t width, uint16_t height, color_t color, } } -void gfx_print(point_t start, const char *text, fontSize_t size, textAlign_t alignment, color_t color) -{ - uint8_t *currentCharData; - uint8_t *currentFont; - uint16_t *writePos; - uint8_t *readPos; - - bw_t bw = _color2bw(color); - - switch(size) - { - case FONT_SIZE_1: - currentFont = (uint8_t *) font_6x8; - break; - case FONT_SIZE_1_BOLD: - currentFont = (uint8_t *) font_6x8_bold; - break; - case FONT_SIZE_2: - currentFont = (uint8_t *) font_8x8; - break; - case FONT_SIZE_3: - currentFont = (uint8_t *) font_8x16; - break; - case FONT_SIZE_4: - currentFont = (uint8_t *) font_16x32; - break; - default: - return;// Invalid font selected +/** + * Compute the pixel size of the first text line + * @param f: font used as the source of glyphs + * @param text: the input text + * @param length: the length of the input text, used for boundary checking + */ +static inline uint16_t get_line_size(GFXfont f, + const char *text, + uint16_t length) { + uint16_t line_size = 0; + for(unsigned i = 0; + i < length && text[i] != '\n' && text[i] != '\r'; + i++) { + GFXglyph glyph = f.glyph[text[i] - f.first]; + if (line_size + glyph.xAdvance < SCREEN_WIDTH) + line_size += glyph.xAdvance; + else break; } + return line_size; +} - int16_t startCode = currentFont[2]; // get first defined character - int16_t endCode = currentFont[3]; // get last defined character - int16_t charWidthPixels = currentFont[4]; // width in pixel of one char - int16_t charHeightPixels = currentFont[5]; // page count per char - int16_t bytesPerChar = currentFont[7]; // bytes per char - - int16_t sLen = strlen(text); - // Compute amount of letters that fit till the end of the screen - if ((charWidthPixels*sLen) + start.x > SCREEN_WIDTH) - { - sLen = (SCREEN_WIDTH-start.x)/charWidthPixels; - } - - if (sLen < 0) return; - +/** + * Compute the start x coordinate of a new line of given pixel size + * @param alinment: enum representing the text alignment + * @param line_size: the size of the current text line in pixels + */ +static inline uint16_t get_reset_x(textAlign_t alignment, uint16_t line_size) { switch(alignment) { case TEXT_ALIGN_LEFT: - // left aligned, do nothing. - break; + return 0; case TEXT_ALIGN_CENTER: - start.x = (SCREEN_WIDTH - (charWidthPixels * sLen))/2; - break; + return (SCREEN_WIDTH - line_size)/2; case TEXT_ALIGN_RIGHT: - start.x = SCREEN_WIDTH - (charWidthPixels * sLen); - break; + return SCREEN_WIDTH - line_size; } + return 0; +} - for (int16_t i=0; i endCode) - { - charOffset = ('?' - startCode); // Substitute unsupported ASCII code by a question mark + bw_t bw = _color2bw(color); + + GFXfont f = fonts[size]; + + size_t len = strlen(text); + + // Compute size of the first row in pixels + uint16_t line_size = get_line_size(f, text, len); + uint16_t reset_x = get_reset_x(alignment, line_size); + start.x = reset_x; + + /* For each char in the string */ + for(unsigned i = 0; i < len; i++) { + char c = text[i]; + GFXglyph glyph = f.glyph[c - f.first]; + uint8_t *bitmap = f.bitmap; + + uint16_t bo = glyph.bitmapOffset; + uint8_t w = glyph.width, h = glyph.height; + int8_t xo = glyph.xOffset, + yo = glyph.yOffset; + uint8_t xx, yy, bits = 0, bit = 0; + + // Handle newline and carriage return + if (c == '\n') { + start.x = reset_x; + start.y += f.yAdvance; + continue; + } else if (c == '\r') { + start.x = reset_x; + continue; } - currentCharData = (uint8_t *)¤tFont[8 + (charOffset * bytesPerChar)]; + // Handle wrap around + if (start.x + glyph.xAdvance > SCREEN_WIDTH) { + // Compute size of the first row in pixels + line_size = get_line_size(f, text, len); + start.x = reset_x = get_reset_x(alignment, line_size); + start.y += f.yAdvance; + } - // We print the character from up-left to bottom right - for(int16_t vscan=0; vscan < charHeightPixels; vscan++) { - for(int16_t hscan=0; hscan < charWidthPixels; hscan++) { - int16_t charChunk = vscan / 8; - int16_t bitIndex = (hscan + charChunk * charWidthPixels) * 8 + - vscan % 8; - int16_t byte = bitIndex >> 3; - int16_t bitMask = 1 << (bitIndex & 7); - if (currentCharData[byte] & bitMask) - { - point_t pos = {start.x + hscan + i * charWidthPixels, - start.y + vscan}; - _bw_setPixel(pos, bw); + // Draw bitmap + for (yy = 0; yy < h; yy++) { + for (xx = 0; xx < w; xx++) { + if (!(bit++ & 7)) { + bits = bitmap[bo++]; } + if (bits & 0x80) { + if (start.y + yo + yy < SCREEN_HEIGHT && start.x + xo + xx < SCREEN_WIDTH && start.y + yo + yy > 0 && start.x + xo + xx > 0) { + point_t pos = {start.x + xo + xx, start.y + yo + yy}; + _bw_setPixel(pos, bw); + } + } + bits <<= 1; } } + start.x += glyph.xAdvance; } } diff --git a/openrtx/src/graphics/graphics_rgb565.c b/openrtx/src/graphics/graphics_rgb565.c index 23111692..833cf6ac 100644 --- a/openrtx/src/graphics/graphics_rgb565.c +++ b/openrtx/src/graphics/graphics_rgb565.c @@ -27,7 +27,6 @@ #include #include "display.h" #include "graphics.h" -#include "font_OpenGD77.h" /* This graphics driver is meant for an RGB565 little endian pixel format. * Thus, to accomodate for the endianness, the fields in struct rgb565_t have to @@ -147,89 +146,103 @@ void gfx_drawRect(point_t start, uint16_t width, uint16_t height, color_t color, } } -void gfx_print(point_t start, const char *text, fontSize_t size, textAlign_t alignment, color_t color) -{ - uint8_t *currentCharData; - uint8_t *currentFont; - uint16_t *writePos; - uint8_t *readPos; - - rgb565_t color_565 = _true2highColor(color); - - switch(size) - { - case FONT_SIZE_1: - currentFont = (uint8_t *) font_6x8; - break; - case FONT_SIZE_1_BOLD: - currentFont = (uint8_t *) font_6x8_bold; - break; - case FONT_SIZE_2: - currentFont = (uint8_t *) font_8x8; - break; - case FONT_SIZE_3: - currentFont = (uint8_t *) font_8x16; - break; - case FONT_SIZE_4: - currentFont = (uint8_t *) font_16x32; - break; - default: - return;// Invalid font selected +/** + * Compute the pixel size of the first text line + * @param f: font used as the source of glyphs + * @param text: the input text + * @param length: the length of the input text, used for boundary checking + */ +static inline uint16_t get_line_size(GFXfont f, + const char *text, + uint16_t length) { + uint16_t line_size = 0; + for(unsigned i = 0; + i < length && text[i] != '\n' && text[i] != '\r'; + i++) { + GFXglyph glyph = f.glyph[text[i] - f.first]; + if (line_size + glyph.xAdvance < SCREEN_WIDTH) + line_size += glyph.xAdvance; + else break; } + return line_size; +} - int16_t startCode = currentFont[2]; // get first defined character - int16_t endCode = currentFont[3]; // get last defined character - int16_t charWidthPixels = currentFont[4]; // width in pixel of one char - int16_t charHeightPixels = currentFont[5]; // page count per char - int16_t bytesPerChar = currentFont[7]; // bytes per char - - int16_t sLen = strlen(text); - // Compute amount of letters that fit till the end of the screen - if ((charWidthPixels*sLen) + start.x > SCREEN_WIDTH) - { - sLen = (SCREEN_WIDTH-start.x)/charWidthPixels; - } - - if (sLen < 0) return; - +/** + * Compute the start x coordinate of a new line of given pixel size + * @param alinment: enum representing the text alignment + * @param line_size: the size of the current text line in pixels + */ +static inline uint16_t get_reset_x(textAlign_t alignment, uint16_t line_size) { switch(alignment) { case TEXT_ALIGN_LEFT: - // left aligned, do nothing. - break; + return 0; case TEXT_ALIGN_CENTER: - start.x = (SCREEN_WIDTH - (charWidthPixels * sLen))/2; - break; + return (SCREEN_WIDTH - line_size)/2; case TEXT_ALIGN_RIGHT: - start.x = SCREEN_WIDTH - (charWidthPixels * sLen); - break; + return SCREEN_WIDTH - line_size; } + return 0; +} - for (int16_t i=0; i endCode) - { - charOffset = ('?' - startCode); // Substitute unsupported ASCII code by a question mark + rgb565_t color_565 = _true2highColor(color); + + GFXfont f = fonts[size]; + + size_t len = strlen(text); + + // Compute size of the first row in pixels + uint16_t line_size = get_line_size(f, text, len); + uint16_t reset_x = get_reset_x(alignment, line_size); + start.x = reset_x; + + /* For each char in the string */ + for(unsigned i = 0; i < len; i++) { + char c = text[i]; + GFXglyph glyph = f.glyph[c - f.first]; + uint8_t *bitmap = f.bitmap; + + uint16_t bo = glyph.bitmapOffset; + uint8_t w = glyph.width, h = glyph.height; + int8_t xo = glyph.xOffset, + yo = glyph.yOffset; + uint8_t xx, yy, bits = 0, bit = 0; + + // Handle newline and carriage return + if (c == '\n') { + start.x = reset_x; + start.y += f.yAdvance; + continue; + } else if (c == '\r') { + start.x = reset_x; + continue; } - currentCharData = (uint8_t *)¤tFont[8 + (charOffset * bytesPerChar)]; + // Handle wrap around + if (start.x + glyph.xAdvance > SCREEN_WIDTH) { + // Compute size of the first row in pixels + line_size = get_line_size(f, text, len); + start.x = reset_x = get_reset_x(alignment, line_size); + start.y += f.yAdvance; + } - // We print the character from up-left to bottom right - for(int16_t vscan=0; vscan < charHeightPixels; vscan++) { - for(int16_t hscan=0; hscan < charWidthPixels; hscan++) { - int16_t charChunk = vscan / 8; - int16_t bitIndex = (hscan + charChunk * charWidthPixels) * 8 + - vscan % 8; - int16_t byte = bitIndex >> 3; - int16_t bitMask = 1 << (bitIndex & 7); - if (currentCharData[byte] & bitMask) - buf[(start.y + vscan) * SCREEN_WIDTH + - start.x + hscan + i * charWidthPixels] = color_565; + // Draw bitmap + for (yy = 0; yy < h; yy++) { + for (xx = 0; xx < w; xx++) { + if (!(bit++ & 7)) { + bits = bitmap[bo++]; + } + if (bits & 0x80) { + if (start.y + yo + yy < SCREEN_HEIGHT && start.x + xo + xx < SCREEN_WIDTH && start.y + yo + yy > 0 && start.x + xo + xx > 0) + buf[(start.y + yo + yy) * SCREEN_WIDTH + + start.x + xo + xx] = color_565; + } + bits <<= 1; } } + start.x += glyph.xAdvance; } } diff --git a/openrtx/src/threads.c b/openrtx/src/threads.c index bbb299ab..f68f063d 100644 --- a/openrtx/src/threads.c +++ b/openrtx/src/threads.c @@ -62,7 +62,7 @@ static void ui_task(void *arg) color_t yellow_fab413 = {250, 180, 19}; char *splash_buf = "OpenRTX"; gfx_clearScreen(); - gfx_print(splash_origin, "OpenRTX", FONT_SIZE_4, TEXT_ALIGN_CENTER, + gfx_print(splash_origin, "OpenRTX", FONT_SIZE_18PT, TEXT_ALIGN_CENTER, yellow_fab413); gfx_render(); while(gfx_renderingInProgress()); diff --git a/openrtx/src/ui.c b/openrtx/src/ui.c index 4adb2a9e..a0b21d80 100644 --- a/openrtx/src/ui.c +++ b/openrtx/src/ui.c @@ -107,13 +107,13 @@ layout_t _ui_calculateLayout() const uint16_t bottom_pad = 4; // Top bar font: 8 pt - const fontSize_t top_font = FONT_SIZE_1; + const fontSize_t top_font = FONT_SIZE_9PT; // Middle line fonts: 16 pt - const fontSize_t line1_font = FONT_SIZE_3; - const fontSize_t line2_font = FONT_SIZE_3; - const fontSize_t line3_font = FONT_SIZE_3; + const fontSize_t line1_font = FONT_SIZE_12PT; + const fontSize_t line2_font = FONT_SIZE_12PT; + const fontSize_t line3_font = FONT_SIZE_12PT; // Bottom bar font: 8 pt - const fontSize_t bottom_font = FONT_SIZE_1; + const fontSize_t bottom_font = FONT_SIZE_9PT; // Radioddity GD-77 #elif SCREEN_HEIGHT > 63