From b990688443cc5dfeb267d703c61c5aadb2c77723 Mon Sep 17 00:00:00 2001 From: Douglas Reis Date: Tue, 29 Apr 2025 21:46:57 +0100 Subject: [PATCH 1/3] [font] Add the font m5x7 by Daniel Linssen Signed-off-by: Douglas Reis --- src/CMakeLists.txt | 1 + src/core/m5x7_16pt.c | 1165 ++++++++++++++++++++++++++++++++++++++++++ src/core/m5x7_16pt.h | 21 + 3 files changed, 1187 insertions(+) create mode 100644 src/core/m5x7_16pt.c create mode 100644 src/core/m5x7_16pt.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 842eadb..f904236 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(${NAME} STATIC "core/lcd_base.c" "core/lucida_console_10pt.c" "core/m3x6_16pt.c" + "core/m5x7_16pt.c" "st7735/lcd_st7735.c" ) diff --git a/src/core/m5x7_16pt.c b/src/core/m5x7_16pt.c new file mode 100644 index 0000000..4ebb17d --- /dev/null +++ b/src/core/m5x7_16pt.c @@ -0,0 +1,1165 @@ +// Copyright (c) 2025 Douglas Reis. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This is a rasterized version of the m5x7 font. +// The m5x7 font is created by Daniel Linssen and is free to use with +// attribution. The original TTF font can be found at +// https://managore.itch.io/m5x7 + +#include "m5x7_16pt.h" +// Character bitmaps for m5x7_16pt +const unsigned char m5x7_16ptBitmaps[] = { + // @32 ' ' (5 pixels wide) + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + + // @33 '!' (2 pixels wide) + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x00, // + 0x01, // # + 0x00, // + 0x00, // + + // @34 '"' (4 pixels wide) + 0x05, // # # + 0x05, // # # + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + + // @35 '#' (6 pixels wide) + 0x00, // + 0x0a, // # # + 0x1f, // ##### + 0x0a, // # # + 0x0a, // # # + 0x1f, // ##### + 0x0a, // # # + 0x00, // + 0x00, // + + // @36 '$' (6 pixels wide) + 0x04, // # + 0x1e, // #### + 0x05, // # # + 0x0e, // ### + 0x14, // # # + 0x0f, // #### + 0x04, // # + 0x00, // + 0x00, // + + // @37 '%' (6 pixels wide) + 0x13, // ## # + 0x13, // ## # + 0x08, // # + 0x04, // # + 0x02, // # + 0x19, // # ## + 0x19, // # ## + 0x00, // + 0x00, // + + // @38 '&' (7 pixels wide) + 0x04, // # + 0x0a, // # # + 0x0a, // # # + 0x06, // ## + 0x11, // # # + 0x11, // # # + 0x2e, // ### # + 0x00, // + 0x00, // + + // @39 ''' (2 pixels wide) + 0x01, // # + 0x01, // # + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + + // @40 '(' (3 pixels wide) + 0x02, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x02, // # + 0x00, // + + // @41 ')' (3 pixels wide) + 0x01, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x01, // # + 0x00, // + + // @42 '*' (4 pixels wide) + 0x05, // # # + 0x02, // # + 0x05, // # # + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + + // @43 '+' (6 pixels wide) + 0x00, // + 0x04, // # + 0x04, // # + 0x1f, // ##### + 0x04, // # + 0x04, // # + 0x00, // + 0x00, // + 0x00, // + + // @44 ',' (3 pixels wide) + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x02, // # + 0x01, // # + 0x00, // + + // @45 '-' (6 pixels wide) + 0x00, // + 0x00, // + 0x00, // + 0x1f, // ##### + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + + // @46 '.' (2 pixels wide) + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x01, // # + 0x00, // + 0x00, // + + // @47 '/' (4 pixels wide) + 0x04, // # + 0x04, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x01, // # + 0x01, // # + 0x00, // + 0x00, // + + // @48 '0' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0e, // ### + 0x00, // + 0x00, // + + // @49 '1' (6 pixels wide) + 0x04, // # + 0x06, // ## + 0x04, // # + 0x04, // # + 0x04, // # + 0x04, // # + 0x1f, // ##### + 0x00, // + 0x00, // + + // @50 '2' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x10, // # + 0x08, // # + 0x04, // # + 0x02, // # + 0x1f, // ##### + 0x00, // + 0x00, // + + // @51 '3' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x10, // # + 0x0c, // ## + 0x10, // # + 0x11, // # # + 0x0e, // ### + 0x00, // + 0x00, // + + // @52 '4' (6 pixels wide) + 0x08, // # + 0x0c, // ## + 0x0a, // # # + 0x09, // # # + 0x1f, // ##### + 0x08, // # + 0x08, // # + 0x00, // + 0x00, // + + // @53 '5' (6 pixels wide) + 0x1f, // ##### + 0x01, // # + 0x0f, // #### + 0x10, // # + 0x10, // # + 0x10, // # + 0x0f, // #### + 0x00, // + 0x00, // + + // @54 '6' (6 pixels wide) + 0x0e, // ### + 0x01, // # + 0x0f, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0e, // ### + 0x00, // + 0x00, // + + // @55 '7' (6 pixels wide) + 0x1f, // ##### + 0x10, // # + 0x10, // # + 0x08, // # + 0x08, // # + 0x04, // # + 0x04, // # + 0x00, // + 0x00, // + + // @56 '8' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x0e, // ### + 0x00, // + 0x00, // + + // @57 '9' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x1e, // #### + 0x10, // # + 0x0e, // ### + 0x00, // + 0x00, // + + // @58 ':' (2 pixels wide) + 0x00, // + 0x00, // + 0x00, // + 0x01, // # + 0x00, // + 0x00, // + 0x01, // # + 0x00, // + 0x00, // + + // @59 ';' (3 pixels wide) + 0x00, // + 0x00, // + 0x00, // + 0x02, // # + 0x00, // + 0x00, // + 0x02, // # + 0x01, // # + 0x00, // + + // @60 '<' (4 pixels wide) + 0x00, // + 0x04, // # + 0x02, // # + 0x01, // # + 0x02, // # + 0x04, // # + 0x00, // + 0x00, // + 0x00, // + + // @61 '=' (5 pixels wide) + 0x00, // + 0x00, // + 0x0f, // #### + 0x00, // + 0x0f, // #### + 0x00, // + 0x00, // + 0x00, // + 0x00, // + + // @62 '>' (4 pixels wide) + 0x00, // + 0x01, // # + 0x02, // # + 0x04, // # + 0x02, // # + 0x01, // # + 0x00, // + 0x00, // + 0x00, // + + // @63 '?' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x10, // # + 0x08, // # + 0x04, // # + 0x00, // + 0x04, // # + 0x00, // + 0x00, // + + // @64 '@' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x1d, // # ### + 0x15, // # # # + 0x1d, // # ### + 0x01, // # + 0x1e, // #### + 0x00, // + 0x00, // + + // @65 'A' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x1f, // ##### + 0x11, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @66 'B' (6 pixels wide) + 0x0f, // #### + 0x11, // # # + 0x0f, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0f, // #### + 0x00, // + 0x00, // + + // @67 'C' (6 pixels wide) + 0x1c, // ### + 0x02, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x1e, // #### + 0x00, // + 0x00, // + + // @68 'D' (6 pixels wide) + 0x07, // ### + 0x09, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0f, // #### + 0x00, // + 0x00, // + + // @69 'E' (6 pixels wide) + 0x1e, // #### + 0x01, // # + 0x0f, // #### + 0x01, // # + 0x01, // # + 0x01, // # + 0x1e, // #### + 0x00, // + 0x00, // + + // @70 'F' (6 pixels wide) + 0x1e, // #### + 0x01, // # + 0x0f, // #### + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x00, // + 0x00, // + + // @71 'G' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x01, // # + 0x1d, // # ### + 0x11, // # # + 0x11, // # # + 0x0e, // ### + 0x00, // + 0x00, // + + // @72 'H' (6 pixels wide) + 0x11, // # # + 0x11, // # # + 0x1f, // ##### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @73 'I' (6 pixels wide) + 0x1f, // ##### + 0x04, // # + 0x04, // # + 0x04, // # + 0x04, // # + 0x04, // # + 0x1f, // ##### + 0x00, // + 0x00, // + + // @74 'J' (6 pixels wide) + 0x1f, // ##### + 0x10, // # + 0x10, // # + 0x10, // # + 0x10, // # + 0x08, // # + 0x07, // ### + 0x00, // + 0x00, // + + // @75 'K' (6 pixels wide) + 0x11, // # # + 0x11, // # # + 0x09, // # # + 0x07, // ### + 0x09, // # # + 0x11, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @76 'L' (6 pixels wide) + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x1e, // #### + 0x00, // + 0x00, // + + // @77 'M' (8 pixels wide) + 0x36, // ## ## + 0x49, // # # # + 0x49, // # # # + 0x49, // # # # + 0x49, // # # # + 0x49, // # # # + 0x41, // # # + 0x00, // + 0x00, // + + // @78 'N' (6 pixels wide) + 0x07, // ### + 0x09, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @79 'O' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0e, // ### + 0x00, // + 0x00, // + + // @80 'P' (6 pixels wide) + 0x0f, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0f, // #### + 0x01, // # + 0x01, // # + 0x00, // + 0x00, // + + // @81 'Q' (6 pixels wide) + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x15, // # # # + 0x09, // # # + 0x16, // ## # + 0x00, // + 0x00, // + + // @82 'R' (6 pixels wide) + 0x0f, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0f, // #### + 0x11, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @83 'S' (6 pixels wide) + 0x1e, // #### + 0x01, // # + 0x01, // # + 0x0e, // ### + 0x10, // # + 0x10, // # + 0x0f, // #### + 0x00, // + 0x00, // + + // @84 'T' (6 pixels wide) + 0x1f, // ##### + 0x04, // # + 0x04, // # + 0x04, // # + 0x04, // # + 0x04, // # + 0x04, // # + 0x00, // + 0x00, // + + // @85 'U' (6 pixels wide) + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0e, // ### + 0x00, // + 0x00, // + + // @86 'V' (6 pixels wide) + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0a, // # # + 0x04, // # + 0x00, // + 0x00, // + + // @87 'W' (8 pixels wide) + 0x41, // # # + 0x41, // # # + 0x49, // # # # + 0x49, // # # # + 0x49, // # # # + 0x49, // # # # + 0x36, // ## ## + 0x00, // + 0x00, // + + // @88 'X' (6 pixels wide) + 0x11, // # # + 0x11, // # # + 0x0a, // # # + 0x04, // # + 0x0a, // # # + 0x11, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @89 'Y' (6 pixels wide) + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0a, // # # + 0x04, // # + 0x04, // # + 0x04, // # + 0x00, // + 0x00, // + + // @90 'Z' (6 pixels wide) + 0x1f, // ##### + 0x10, // # + 0x08, // # + 0x04, // # + 0x02, // # + 0x01, // # + 0x1f, // ##### + 0x00, // + 0x00, // + + // @91 '[' (3 pixels wide) + 0x03, // ## + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x03, // ## + 0x00, // + + // @92 '\' (4 pixels wide) + 0x01, // # + 0x01, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x04, // # + 0x04, // # + 0x00, // + 0x00, // + + // @93 ']' (3 pixels wide) + 0x03, // ## + 0x02, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x03, // ## + 0x00, // + + // @94 '^' (6 pixels wide) + 0x04, // # + 0x0a, // # # + 0x11, // # # + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + + // @95 '_' (6 pixels wide) + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x1f, // ##### + 0x00, // + 0x00, // + + // @96 '`' (3 pixels wide) + 0x01, // # + 0x02, // # + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + 0x00, // + + // @97 'a' (6 pixels wide) + 0x00, // + 0x00, // + 0x0e, // ### + 0x10, // # + 0x1e, // #### + 0x11, // # # + 0x1e, // #### + 0x00, // + 0x00, // + + // @98 'b' (6 pixels wide) + 0x01, // # + 0x01, // # + 0x0f, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0f, // #### + 0x00, // + 0x00, // + + // @99 'c' (5 pixels wide) + 0x00, // + 0x00, // + 0x0e, // ### + 0x01, // # + 0x01, // # + 0x01, // # + 0x0e, // ### + 0x00, // + 0x00, // + + // @100 'd' (6 pixels wide) + 0x10, // # + 0x10, // # + 0x1e, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x1e, // #### + 0x00, // + 0x00, // + + // @101 'e' (6 pixels wide) + 0x00, // + 0x00, // + 0x0e, // ### + 0x11, // # # + 0x1f, // ##### + 0x01, // # + 0x0e, // ### + 0x00, // + 0x00, // + + // @102 'f' (5 pixels wide) + 0x0c, // ## + 0x02, // # + 0x0f, // #### + 0x02, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x00, // + 0x00, // + + // @103 'g' (6 pixels wide) + 0x00, // + 0x00, // + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x1e, // #### + 0x10, // # + 0x0e, // ### + + // @104 'h' (6 pixels wide) + 0x01, // # + 0x01, // # + 0x0f, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @105 'i' (3 pixels wide) + 0x02, // # + 0x00, // + 0x03, // ## + 0x02, // # + 0x02, // # + 0x02, // # + 0x02, // # + 0x00, // + 0x00, // + + // @106 'j' (4 pixels wide) + 0x04, // # + 0x00, // + 0x06, // ## + 0x04, // # + 0x04, // # + 0x04, // # + 0x04, // # + 0x04, // # + 0x03, // ## + + // @107 'k' (5 pixels wide) + 0x01, // # + 0x01, // # + 0x09, // # # + 0x05, // # # + 0x03, // ## + 0x05, // # # + 0x09, // # # + 0x00, // + 0x00, // + + // @108 'l' (3 pixels wide) + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x02, // # + 0x00, // + 0x00, // + + // @109 'm' (8 pixels wide) + 0x00, // + 0x00, // + 0x3d, // # #### + 0x4b, // ## # # + 0x49, // # # # + 0x49, // # # # + 0x49, // # # # + 0x00, // + 0x00, // + + // @110 'n' (6 pixels wide) + 0x00, // + 0x00, // + 0x0d, // # ## + 0x13, // ## # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @111 'o' (6 pixels wide) + 0x00, // + 0x00, // + 0x0e, // ### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0e, // ### + 0x00, // + 0x00, // + + // @112 'p' (6 pixels wide) + 0x00, // + 0x00, // + 0x0f, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0f, // #### + 0x01, // # + 0x01, // # + + // @113 'q' (6 pixels wide) + 0x00, // + 0x00, // + 0x1e, // #### + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x1e, // #### + 0x10, // # + 0x10, // # + + // @114 'r' (5 pixels wide) + 0x00, // + 0x00, // + 0x0d, // # ## + 0x03, // ## + 0x01, // # + 0x01, // # + 0x01, // # + 0x00, // + 0x00, // + + // @115 's' (6 pixels wide) + 0x00, // + 0x00, // + 0x1e, // #### + 0x01, // # + 0x0e, // ### + 0x10, // # + 0x0f, // #### + 0x00, // + 0x00, // + + // @116 't' (5 pixels wide) + 0x02, // # + 0x02, // # + 0x0f, // #### + 0x02, // # + 0x02, // # + 0x02, // # + 0x0c, // ## + 0x00, // + 0x00, // + + // @117 'u' (6 pixels wide) + 0x00, // + 0x00, // + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x19, // # ## + 0x16, // ## # + 0x00, // + 0x00, // + + // @118 'v' (6 pixels wide) + 0x00, // + 0x00, // + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x0a, // # # + 0x04, // # + 0x00, // + 0x00, // + + // @119 'w' (8 pixels wide) + 0x00, // + 0x00, // + 0x41, // # # + 0x49, // # # # + 0x49, // # # # + 0x49, // # # # + 0x36, // ## ## + 0x00, // + 0x00, // + + // @120 'x' (6 pixels wide) + 0x00, // + 0x00, // + 0x11, // # # + 0x0a, // # # + 0x04, // # + 0x0a, // # # + 0x11, // # # + 0x00, // + 0x00, // + + // @121 'y' (6 pixels wide) + 0x00, // + 0x00, // + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x11, // # # + 0x1e, // #### + 0x10, // # + 0x0e, // ### + + // @122 'z' (6 pixels wide) + 0x00, // + 0x00, // + 0x1f, // ##### + 0x08, // # + 0x04, // # + 0x02, // # + 0x1f, // ##### + 0x00, // + 0x00, // + + // @123 '{' (4 pixels wide) + 0x06, // ## + 0x02, // # + 0x02, // # + 0x03, // ## + 0x02, // # + 0x02, // # + 0x02, // # + 0x06, // ## + 0x00, // + + // @124 '|' (2 pixels wide) + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x01, // # + 0x00, // + 0x00, // + + // @125 '}' (4 pixels wide) + 0x03, // ## + 0x02, // # + 0x02, // # + 0x06, // ## + 0x02, // # + 0x02, // # + 0x02, // # + 0x03, // ## + 0x00, // + + // @126 '~' (6 pixels wide) + 0x00, // + 0x00, // + 0x02, // # + 0x15, // # # # + 0x08, // # + 0x00, // + 0x00, // + 0x00, // + 0x00, // +}; + +// Character descriptors for 16pt +const FontCharInfo m5x7_16ptDescriptors[] = { + {5, 0}, // ' ' + {2, 9}, // '!' + {4, 18}, // '"' + {6, 27}, // '#' + {6, 36}, // '$' + {6, 45}, // '%' + {7, 54}, // '&' + {2, 63}, // ''' + {3, 72}, // '(' + {3, 81}, // ')' + {4, 90}, // '*' + {6, 99}, // '+' + {3, 108}, // ',' + {6, 117}, // '-' + {2, 126}, // '.' + {4, 135}, // '/' + {6, 144}, // '0' + {6, 153}, // '1' + {6, 162}, // '2' + {6, 171}, // '3' + {6, 180}, // '4' + {6, 189}, // '5' + {6, 198}, // '6' + {6, 207}, // '7' + {6, 216}, // '8' + {6, 225}, // '9' + {2, 234}, // ':' + {3, 243}, // ';' + {4, 252}, // '<' + {5, 261}, // '=' + {4, 270}, // '>' + {6, 279}, // '?' + {6, 288}, // '@' + {6, 297}, // 'A' + {6, 306}, // 'B' + {6, 315}, // 'C' + {6, 324}, // 'D' + {6, 333}, // 'E' + {6, 342}, // 'F' + {6, 351}, // 'G' + {6, 360}, // 'H' + {6, 369}, // 'I' + {6, 378}, // 'J' + {6, 387}, // 'K' + {6, 396}, // 'L' + {8, 405}, // 'M' + {6, 414}, // 'N' + {6, 423}, // 'O' + {6, 432}, // 'P' + {6, 441}, // 'Q' + {6, 450}, // 'R' + {6, 459}, // 'S' + {6, 468}, // 'T' + {6, 477}, // 'U' + {6, 486}, // 'V' + {8, 495}, // 'W' + {6, 504}, // 'X' + {6, 513}, // 'Y' + {6, 522}, // 'Z' + {3, 531}, // '[' + {4, 540}, // '\' + {3, 549}, // ']' + {6, 558}, // '^' + {6, 567}, // '_' + {3, 576}, // '`' + {6, 585}, // 'a' + {6, 594}, // 'b' + {5, 603}, // 'c' + {6, 612}, // 'd' + {6, 621}, // 'e' + {5, 630}, // 'f' + {6, 639}, // 'g' + {6, 648}, // 'h' + {3, 657}, // 'i' + {4, 666}, // 'j' + {5, 675}, // 'k' + {3, 684}, // 'l' + {8, 693}, // 'm' + {6, 702}, // 'n' + {6, 711}, // 'o' + {6, 720}, // 'p' + {6, 729}, // 'q' + {5, 738}, // 'r' + {6, 747}, // 's' + {5, 756}, // 't' + {6, 765}, // 'u' + {6, 774}, // 'v' + {8, 783}, // 'w' + {6, 792}, // 'x' + {6, 801}, // 'y' + {6, 810}, // 'z' + {4, 819}, // '{' + {2, 828}, // '|' + {4, 837}, // '}' + {6, 846}, // '~' +}; + +// Font information for 16pt +const Font m5x7_16ptFont = { + 9, // Character height + ' ', // Start character + '~', // End character + m5x7_16ptDescriptors, // Character descriptor array + m5x7_16ptBitmaps, // Character bitmap array +}; diff --git a/src/core/m5x7_16pt.h b/src/core/m5x7_16pt.h new file mode 100644 index 0000000..d6aed2c --- /dev/null +++ b/src/core/m5x7_16pt.h @@ -0,0 +1,21 @@ +// Copyright (c) 2025 Douglas Reis. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This is a rasterized version of the m5x7 font. +// The m5x7 font is created by Daniel Linssen and is free to use with +// attribution. The original TTF font can be found at +// https://managore.itch.io/m5x7 + +#ifndef M5X7_16PT_H_ +#define M5X7_16PT_H_ + +#include + +#include "font.h" + +extern const unsigned char m5x7_16ptBitmaps[]; +extern const Font m5x7_16ptFont; +extern const FontCharInfo m5x7_16ptDescriptors[]; + +#endif /* M5X7_16PT_H_ */ From 723bf4d7eb40f8e06369aeb98e3bd9034c70f9d7 Mon Sep 17 00:00:00 2001 From: Douglas Reis Date: Tue, 29 Apr 2025 22:50:45 +0100 Subject: [PATCH 2/3] [font] Add attribution to the font m3x6 Signed-off-by: Douglas Reis --- src/core/m3x6_16pt.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/m3x6_16pt.h b/src/core/m3x6_16pt.h index 9d34aaa..6c767b7 100644 --- a/src/core/m3x6_16pt.h +++ b/src/core/m3x6_16pt.h @@ -2,6 +2,10 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +// This is a rasterized version of the m3x6 font. +// The m3x6 font is created by Daniel Linssen and is free to use with attribution. +// The original TTF font can be found at https://managore.itch.io/m3x6 + #ifndef M3X6_16PT_H_ #define M3X6_16PT_H_ From b8446ddce56fd4f68d346b54aa52b9bb861f832d Mon Sep 17 00:00:00 2001 From: Douglas Reis Date: Tue, 29 Apr 2025 22:52:07 +0100 Subject: [PATCH 3/3] [test] Test fonts m3x6 and m5x7 Signed-off-by: Douglas Reis --- CMakeLists.txt | 5 ++ tests/golden_files/test_font_m5x7_16pt.png | Bin 0 -> 3293 bytes tests/main.cc | 60 +++++++++++++++++++-- 3 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 tests/golden_files/test_font_m5x7_16pt.png diff --git a/CMakeLists.txt b/CMakeLists.txt index d928fe9..3c00c2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # For lsp set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") + +set(CMAKE_C_FLAGS_DEBUG "-O0 -g") +set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") set(NAME st7735_driver) diff --git a/tests/golden_files/test_font_m5x7_16pt.png b/tests/golden_files/test_font_m5x7_16pt.png new file mode 100644 index 0000000000000000000000000000000000000000..6b32627dbef3ab49ae2dd560f3888495fe628f38 GIT binary patch literal 3293 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 a1j=KDF1=`Z_N({X0$R>n#cfQIX#W?l>vVSj literal 0 HcmV?d00001 diff --git a/tests/main.cc b/tests/main.cc index 2d1c43e..92a08de 100644 --- a/tests/main.cc +++ b/tests/main.cc @@ -69,9 +69,9 @@ class DisplayTest : public testing::Test { #define GET_GOLDEN_FILE() \ std::format("./tests/golden_files/test_{}.png", testing::UnitTest::GetInstance()->current_test_info()->name()) - template - T rotate_left(T& v) { - v = v << 8 | v >> (32 - 8); + template + T rotate_left(T &v) { + v = v << 8 | v >> (32 - 8); return v; } std::string make_temp_filename() { @@ -191,7 +191,7 @@ TEST_F(st7735SimTest, draw_rectangles) { Result res = lcd_st7735_clean(&ctx_); EXPECT_EQ(res.code, 0); size_t increment = 20; - uint32_t rgb = 0x0000FF; + uint32_t rgb = 0x0000FF; { LCD_rectangle rec{.origin = {.x = 0, .y = 0}, .width = DisplayWidth, .height = 10}; @@ -282,6 +282,58 @@ TEST_F(st7735SimTest, draw_text) { compare_img(filename, GET_GOLDEN_FILE()); } +#include +#include +TEST_F(st7735SimTest, font_m5x7_16pt) { + Result res = lcd_st7735_clean(&ctx_); + EXPECT_EQ(res.code, 0); + + std::string ascii = ""; + for (int i = 32; i <= 126; ++i) { + if (std::isprint(static_cast(i))) { + ascii += static_cast(i); + } + } + size_t font_h(0), rows(0), columns(0), ascii_index(0); + uint32_t bg(0xff), fg(0x00); + LCD_Point pos{.x = 0, .y = 0}; + + auto set_font = [&](const Font *font) { + res = lcd_st7735_set_font(&ctx_, font); + EXPECT_EQ(res.code, 0); + font_h = ctx_.parent.font->height; + rows = DisplayHeight / ctx_.parent.font->height; + columns = DisplayWidth / (ctx_.parent.font->descriptor_table->width + 1); + ascii_index = 0; + }; + + auto draw_text = [&]() { + res = lcd_st7735_set_font_colors(&ctx_, bg, fg); + EXPECT_EQ(res.code, 0); + std::string print = ascii.substr(ascii_index, columns); + res = lcd_st7735_puts(&ctx_, pos, print.c_str()); + EXPECT_EQ(res.code, print.size()); + ascii_index += columns; + pos.y += font_h; + bg = bg << 8 | bg >> (32 - 8); // Rotate left + fg = bg ^ 0xffffff; + }; + + set_font(&m5x7_16ptFont); + do { + draw_text(); + } while (ascii_index < ascii.size()); + + set_font(&m3x6_16ptFont); + do { + draw_text(); + } while (pos.y < DisplayHeight - font_h && ascii_index < ascii.size()); + + std::string filename = make_temp_filename(); + mock_.simulator.png(filename); + compare_img(filename, GET_GOLDEN_FILE()); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();