Bitmap Fonts: Refactor and support for pound/degrees.

feature/unicode-ish
Phil Howard 2022-04-01 15:21:08 +01:00
rodzic b2ff46b516
commit 0d43973326
8 zmienionych plików z 148 dodań i 34 usunięć

Wyświetl plik

@ -11,6 +11,16 @@ table to map anything prefixed with 0xc3 to its non-accented equivilent.
namespace unicode_sorta {
const char PAGE_194_START = 194;
const char PAGE_195_START = 195;
// Codepage is probably completely the wrong terminology here
// but character pairs come in the form 0xc2 0x00 and 0xc3 0x00.
enum codepage_t : uint8_t {
PAGE_194,
PAGE_195
};
const uint8_t UNICODE_PREFIX = 0xc3;
enum accents : uint8_t {
@ -92,7 +102,46 @@ static const accents char_accent[] = {
ACCENT_DIAERESIS
};
static const char char_base[] = {
// Codepage 194. Starts at 0x80 but the first 32 are non-printable
// Since we're already implementing LUTs for various accented characters,
// it makes sense for us poor brits to grab a usable £, too!
static const char char_base_194[] = {
' ', // - c2 a0 - NO-BREAK SPACE
'i', // ¡ - c2 a1 - INVERTED EXCLAMATION MARK
' ', // ¢ - c2 a2 - CENT SIGN
'\x85', // £ - c2 a3 - POUND SIGN
' ', // ¤ - c2 a4 - CURRENCY SIGN
'\x86', // ¥ - c2 a5 - YEN SIGN
' ', // ¦ - c2 a6 - BROKEN BAR
'S', // § - c2 a7 - SECTION SIGN
' ', // ¨ - c2 a8 - DIAERESIS
'\x87', // © - c2 a9 - COPYRIGHT SIGN
'a', // ª - c2 aa - FEMININE ORDINAL INDICATOR
'<', // « - c2 ab - LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
' ', // ¬ - c2 ac - NOT SIGN
' ', // ­ - c2 ad - SOFT HYPHEN
'R', // ® - c2 ae - REGISTERED SIGN
' ', // ¯ - c2 af - MACRON
'\x88', // ° - c2 b0 - DEGREE SIGN
' ', // ± - c2 b1 - PLUS-MINUS SIGN
'2', // ² - c2 b2 - SUPERSCRIPT TWO
'3', // ³ - c2 b3 - SUPERSCRIPT THREE
' ', // ´ - c2 b4 - ACUTE ACCENT
' ', // µ - c2 b5 - MICRO SIGN
' ', // ¶ - c2 b6 - PILCROW SIGN
' ', // · - c2 b7 - MIDDLE DOT
' ', // ¸ - c2 b8 - CEDILLA
' ', // ¹ - c2 b9 - SUPERSCRIPT ONE
' ', // º - c2 ba - MASCULINE ORDINAL INDICATOR
' ', // » - c2 bb - RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
' ', // ¼ - c2 bc - VULGAR FRACTION ONE QUARTER
' ', // ½ - c2 bd - VULGAR FRACTION ONE HALF
' ', // ¾ - c2 be - VULGAR FRACTION THREE QUARTERS
' ', // ¿ - c2 bf - INVERTED QUESTION MARK
};
// Codepage 195. Starts at 0x80
static const char char_base_195[] = {
'A', // À - c3 80 - A + GRAVE
'A', // Á - c3 81 - A + ACUTE
'A', // Â - c3 82 - A + CIRCUMFLEX

Wyświetl plik

@ -1,8 +1,7 @@
#include "bitmap_fonts.hpp"
#include "common/unicode_sorta.hpp"
namespace bitmap {
int32_t measure_character(const font_t *font, const char c, const uint8_t scale) {
int32_t measure_character(const font_t *font, const char c, const uint8_t scale, unicode_sorta::codepage_t codepage) {
if(c < 32 || c > 127 + 64) { // + 64 char remappings defined in unicode_sorta.hpp
return 0;
}
@ -10,7 +9,11 @@ namespace bitmap {
uint8_t char_index = c;
if(char_index > 127) {
char_index = unicode_sorta::char_base[c - 128];
if(codepage == unicode_sorta::PAGE_195) {
char_index = unicode_sorta::char_base_195[c - 128];
} else {
char_index = unicode_sorta::char_base_194[c - 128 - 32];
}
}
char_index -= 32;
@ -20,13 +23,22 @@ namespace bitmap {
int32_t measure_text(const font_t *font, const std::string &t, const uint8_t scale) {
int32_t text_width = 0;
unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195;
for(auto c : t) {
text_width += measure_character(font, c, scale);
if(c == unicode_sorta::PAGE_194_START) {
codepage = unicode_sorta::PAGE_194;
continue;
} else if (c == unicode_sorta::PAGE_195_START) {
continue;
}
text_width += measure_character(font, c, scale, codepage);
text_width += 1 * scale;
codepage = unicode_sorta::PAGE_195; // Reset back to default
}
return text_width;
}
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale) {
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale, unicode_sorta::codepage_t codepage) {
if(c < 32 || c > 127 + 64) { // + 64 char remappings defined in unicode_sorta.hpp
return;
}
@ -37,8 +49,13 @@ namespace bitmap {
// Remap any chars that fall outside of the 7-bit ASCII range
// using our unicode fudge lookup table.
if(char_index > 127) {
char_index = unicode_sorta::char_base[c - 128];
char_accent = unicode_sorta::char_accent[c - 128];
if(codepage == unicode_sorta::PAGE_195) {
char_index = unicode_sorta::char_base_195[c - 128];
char_accent = unicode_sorta::char_accent[c - 128];
} else {
char_index = unicode_sorta::char_base_194[c - 128 - 32];
char_accent = unicode_sorta::ACCENT_NONE;
}
}
// We don't map font data for the first 32 non-printable ASCII chars
@ -55,7 +72,7 @@ namespace bitmap {
// Accents can be up to 8 pixels tall on both 8bit and 16bit fonts
// Each accent's data is font->max_width bytes + 2 offset bytes long
const uint8_t *a = &font->data[101 * bytes_per_char + char_accent * (font->max_width + 2)];
const uint8_t *a = &font->data[(base_chars + extra_chars) * bytes_per_char + char_accent * (font->max_width + 2)];
// Effectively shift off the first two bytes of accent data-
// these are the lower and uppercase accent offsets
@ -104,6 +121,7 @@ namespace bitmap {
void text(const font_t *font, rect_func rectangle, const std::string &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale) {
uint32_t co = 0, lo = 0; // character and line (if wrapping) offset
unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195;
size_t i = 0;
while(i < t.length()) {
@ -116,7 +134,14 @@ namespace bitmap {
uint16_t word_width = 0;
for(size_t j = i; j < next_space; j++) {
word_width += measure_character(font, t[j], scale);
if (t[j] == unicode_sorta::PAGE_194_START) {
codepage = unicode_sorta::PAGE_194;
continue;
} else if (t[j] == unicode_sorta::PAGE_195_START) {
continue;
}
word_width += measure_character(font, t[j], scale, codepage);
codepage = unicode_sorta::PAGE_195;
}
// if this word would exceed the wrap limit then
@ -128,8 +153,16 @@ namespace bitmap {
// draw word
for(size_t j = i; j < next_space; j++) {
character(font, rectangle, t[j], x + co, y + lo, scale);
co += measure_character(font, t[j], scale);
if (t[j] == unicode_sorta::PAGE_194_START) {
codepage = unicode_sorta::PAGE_194;
continue;
} else if (t[j] == unicode_sorta::PAGE_195_START) {
continue;
}
character(font, rectangle, t[j], x + co, y + lo, scale, codepage);
co += measure_character(font, t[j], scale, codepage);
co += 1 * scale;
codepage = unicode_sorta::PAGE_195;
}
// move character offset to end of word and add a space

Wyświetl plik

@ -3,20 +3,24 @@
#include <functional>
#include <string>
#include <cstdint>
#include "common/unicode_sorta.hpp"
namespace bitmap {
const int base_chars = 96; // 96 printable ASCII chars
const int extra_chars = 9; // Extra chars we've rempped that aren't just an ASCII char plus an accent
struct font_t {
const uint8_t height;
const uint8_t max_width;
const uint8_t widths[96 + 5]; // 96 printable ASCII chars plus 5 exta we can't easily remap and decorate with accents
const uint8_t widths[base_chars + extra_chars];
const uint8_t data[];
};
typedef std::function<void(int32_t x, int32_t y, int32_t w, int32_t h)> rect_func;
int32_t measure_character(const font_t *font, const char c, const uint8_t scale);
int32_t measure_character(const font_t *font, const char c, const uint8_t scale, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195);
int32_t measure_text(const font_t *font, const std::string &t, const uint8_t scale);
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale = 2);
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale = 2, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195);
void text(const font_t *font, rect_func rectangle, const std::string &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale = 2);
}

Wyświetl plik

@ -12,7 +12,9 @@ const bitmap::font_t font14_outline {
6, 9, 6, 6, 7, 7, 7, 9, 7, 7, 7, 5, 7, 5, 7, 8,
5, 8, 6, 5, 6, 6, 5, 7, 6, 3, 5, 6, 5, 9, 6, 7,
6, 7, 5, 5, 6, 6, 7, 9, 7, 7, 7, 5, 3, 5, 8, 5,
9, 6, 6, 10, 6 // Extra
// Extra
// Æ Þ ß æ þ £ ¥ © °
9, 6, 6, 10, 6, 6, 6, 6, 5
},
.data = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
@ -122,6 +124,10 @@ const bitmap::font_t font14_outline {
0x0f, 0xfc, 0x08, 0x04, 0x0f, 0xb4, 0x0b, 0xb4, 0x0c, 0x4c, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ß
0x07, 0xc0, 0x0c, 0x60, 0x0b, 0xa0, 0x0a, 0xa0, 0x0b, 0xa0, 0x0c, 0x60, 0x0a, 0xa0, 0x0a, 0xa0, 0x0b, 0x60, 0x0f, 0xc0, // æ
0x3f, 0xe0, 0x20, 0x20, 0x3d, 0xa0, 0x05, 0xa0, 0x06, 0x60, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // þ
0x00, 0xe0, 0x0f, 0xb8, 0x08, 0x04, 0x0b, 0xb4, 0x0a, 0xb4, 0x0e, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // £
0x00, 0x3c, 0x00, 0xe4, 0x0f, 0x9c, 0x08, 0x70, 0x0f, 0x9c, 0x00, 0xe4, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ¥
0x07, 0xc0, 0x0c, 0x60, 0x0b, 0xa0, 0x0a, 0xa0, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ©
0x00, 0x38, 0x00, 0x44, 0x00, 0x54, 0x00, 0x44, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // °
// Accents + Offsets
// All chars are shifted 8px down into a 32 pixel canvas for combining with accents.
// Accent shift values (the first two numbers in each line below) move the accent down to meet them.

Wyświetl plik

@ -6,13 +6,15 @@ const bitmap::font_t font6 {
.height = 6,
.max_width = 6,
.widths = {
3, 2, 4, 6, 6, 6, 7, 2, 3, 3, 4, 4, 2, 4, 2, 4,
6, 3, 5, 5, 6, 5, 6, 6, 6, 6, 2, 2, 4, 4, 4, 5,
7, 6, 6, 5, 6, 5, 5, 6, 5, 4, 5, 5, 5, 6, 6, 6,
6, 6, 6, 5, 6, 6, 6, 6, 5, 5, 5, 3, 4, 3, 4, 4,
3, 6, 6, 5, 6, 5, 5, 6, 5, 4, 5, 5, 5, 6, 6, 6,
6, 6, 6, 5, 6, 6, 6, 6, 5, 5, 5, 4, 2, 4, 4, 2,
6, 5, 5, 6, 5 // Extra
3, 1, 3, 5, 5, 5, 6, 1, 2, 2, 3, 3, 1, 3, 1, 3,
5, 2, 4, 4, 5, 4, 5, 5, 5, 5, 1, 1, 3, 3, 3, 4,
6, 5, 5, 4, 5, 4, 4, 5, 4, 3, 4, 4, 4, 5, 5, 5,
5, 5, 5, 4, 5, 5, 5, 5, 4, 4, 4, 2, 3, 2, 3, 3,
2, 5, 5, 4, 5, 4, 4, 5, 4, 3, 4, 4, 4, 5, 5, 5,
5, 5, 5, 4, 5, 5, 5, 5, 4, 4, 4, 3, 1, 3, 3, 1,
// Extra
// Æ Þ ß æ þ £ ¥ © °
5, 5, 4, 5, 5, 4, 4, 4, 3
},
.data = {
0x00,0x00,0x00,0x00,0x00,0x00, //
@ -117,6 +119,10 @@ const bitmap::font_t font6 {
0x3e,0x0a,0x2a,0x34,0x00,0x00, // ß
0x3c,0x12,0x3c,0x2a,0x2a,0x00, // æ
0x3f,0x12,0x12,0x12,0x0e,0x00, // þ
0x08,0x3c,0x2a,0x2a,0x00,0x00, // £
0x26,0x28,0x28,0x1e,0x00,0x00, // ¥s
0x1c,0x22,0x22,0x22,0x00,0x00, // ©
0x02,0x05,0x02,0x00,0x00,0x00, // °
// Accents + Offsets
// All chars are shifted 8px down into a 32 pixel canvas for combining with accents.
// Accent shift values (the first two numbers in each line below) move the accent down to meet them.

Wyświetl plik

@ -6,13 +6,15 @@ const bitmap::font_t font8 {
.height = 8,
.max_width = 6,
.widths = {
2, 2, 4, 6, 5, 5, 5, 2, 4, 4, 4, 4, 3, 4, 3, 5,
5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 2, 3, 4, 4, 4, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 6, 5, 5,
5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 5, 3, 5, 3, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 4, 6, 5, 5,
5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 4, 2, 4, 5, 2,
6, 5, 5, 6, 5 // Extra
3, 1, 3, 5, 4, 4, 4, 1, 3, 3, 3, 3, 2, 3, 2, 4,
4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 1, 2, 3, 3, 3, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 5, 4, 4,
4, 4, 4, 4, 5, 4, 4, 5, 4, 4, 4, 2, 4, 2, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 3, 5, 4, 4,
4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 3, 1, 3, 4, 1,
// Extra
// Æ Þ ß æ þ £ ¥ © °
5, 4, 4, 5, 4, 4, 4, 4, 3
},
.data = {
0x00,0x00,0x00,0x00,0x00,0x00, //
@ -117,6 +119,10 @@ const bitmap::font_t font8 {
0x7e,0x09,0x49,0x36,0x00,0x00, // ß
0x20,0x54,0x78,0x54,0x58,0x00, // æ
0x7f,0x24,0x24,0x18,0x00,0x00, // þ
0x08,0x7e,0x49,0x41,0x00,0x00, // £
0x47,0x48,0x48,0x3f,0x00,0x00, // ¥
0x38,0x44,0x44,0x28,0x00,0x00, // ©
0x02,0x05,0x02,0x00,0x00,0x00, // °
// Accents + Offsets
// All chars are shifted 8px down into a 32 pixel canvas for combining with accents.
// Accent shift values (the first two numbers in each line below) move the accent down to meet them.

Wyświetl plik

@ -24,7 +24,7 @@ namespace hershey {
}
if(c > 127) {
c = unicode_sorta::char_base[c - 128];
c = unicode_sorta::char_base_195[c - 128];
}
return &font->chars[c - 32];

Wyświetl plik

@ -444,7 +444,7 @@ mp_obj_t Badger2040_glyph(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
enum { ARG_self, ARG_char, ARG_x, ARG_y, ARG_scale, ARG_rotation };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_char, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_char, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} },
@ -455,7 +455,8 @@ mp_obj_t Badger2040_glyph(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
int c = args[ARG_char].u_int;
int c = 0;
int x = args[ARG_x].u_int;
int y = args[ARG_y].u_int;
float scale = 1.0f;
@ -468,7 +469,16 @@ mp_obj_t Badger2040_glyph(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
}
_Badger2040_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Badger2040_obj_t);
self->badger2040->glyph(c, x, y, scale, rotation);
if (mp_obj_is_int(args[ARG_char].u_obj)) {
c = (uint8_t)mp_obj_get_int(args[ARG_char].u_obj);
self->badger2040->glyph(c, x, y, scale, rotation);
} else if (mp_obj_is_str_or_bytes(args[ARG_char].u_obj)) {
std::string message = mp_obj_to_string_r(args[ARG_char].u_obj);
self->badger2040->text(message, x, y, scale, rotation);
} else {
mp_raise_TypeError("glyph: expected char or string.");
}
return mp_const_none;
}