From 867b4a5fa60814faaa80d8ac80ccd6344ee2a64b Mon Sep 17 00:00:00 2001 From: Hannu Hartikainen Date: Wed, 18 Aug 2021 14:36:39 +0300 Subject: [PATCH 1/5] gterm: fix custom MENU_FONT The default font being already loaded in stage2 prevented a custom font from being loaded in stage3 (at least in UEFI). If a custom font is configured, load it. --- stage23/lib/gterm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c index 61d5a5e3..19c98be9 100644 --- a/stage23/lib/gterm.c +++ b/stage23/lib/gterm.c @@ -658,7 +658,8 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { } } - if (vga_font_bool == NULL) { + // if not loaded (stage2) or custom font (stage3), load font + if (vga_font_bool == NULL || menu_font != NULL) { vga_font_bool = ext_mem_alloc(VGA_FONT_GLYPHS * VGA_FONT_HEIGHT * VGA_FONT_WIDTH * sizeof(bool)); for (size_t i = 0; i < VGA_FONT_GLYPHS; i++) { From a8a8af4c5fa426f396e0e02b15ca836546e522dc Mon Sep 17 00:00:00 2001 From: Hannu Hartikainen Date: Wed, 18 Aug 2021 15:06:55 +0300 Subject: [PATCH 2/5] gterm: support different font sizes --- CONFIG.md | 3 ++- stage23/lib/blib.c | 4 +++- stage23/lib/gterm.c | 41 ++++++++++++++++++++++++++++++++++------- stage23/menu.c | 1 + 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 57f57687..7b5757f3 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -56,8 +56,9 @@ Some keys take *URIs* as values; these are described in the next section. * `GRAPHICS` - If set to `yes`, use a graphical framebuffer for the boot menu, else use text mode. Ignored with Limine UEFI, forced to `yes`. * `MENU_RESOLUTION` - Specify screen resolution to be used by the Limine menu in the form `x`. This will *only* affect the menu, not any booted OS. If not specified, Limine will pick a resolution automatically. If the resolution is not available, Limine will pick another one automatically. Ignored if `GRAPHICS` is not `yes`. * `MENU_BRANDING` - A string that will be displayed on top of the Limine menu. -* `MENU_FONT` - URI path to a font file to be used instead of the default one for the menu and terminal. The font file must be a code page 437 character set comprised of 256 consecutive 8x16 glyphs bitmaps (4096 byte font file). Each glyph's bitmap must be expressed left to right (1 byte per row), and top to bottom (16 bytes per whole glyph). +* `MENU_FONT` - URI path to a font file to be used instead of the default one for the menu and terminal. The font file must be a code page 437 character set comprised of 256 consecutive glyph bitmaps. Each glyph's bitmap must be expressed left to right (1 byte per row), and top to bottom (16 bytes per whole glyph by default; see `MENU_FONT_SIZE`). See e.g. the [VGA text mode font collection](https://github.com/viler-int10h/vga-text-mode-fonts) for fonts. * `TERMINAL_FONT` - Alias of `MENU_FONT`. +* `MENU_FONT_SIZE` - The size of the font in dots, which must correspond to the font file or the display will be garbled. Note that glyphs are always one byte wide, and columns over 8 are empty. Many fonts may be used in both 8- and 9-dot wide variants. Defaults to `8x16`. * `THEME_COLOURS` - Specifies the colour palette used by the terminal (AARRGGBB). It is a `;` separated array of 10 colours: black, red, green, brown, blue, magenta, cyan, gray, background, and foreground respectively. While an alpha transparency value can be specified for every colour, it is ignored for all but background. Ignored if `GRAPHICS` is not `yes`. * `THEME_COLORS` - Alias of `THEME_COLOURS`. * `THEME_BACKGROUND` - Alias of the background value in `THEME_COLOURS`. diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c index 44745ecf..b8811a35 100644 --- a/stage23/lib/blib.c +++ b/stage23/lib/blib.c @@ -41,7 +41,9 @@ bool parse_resolution(size_t *width, size_t *height, size_t *bpp, const char *bu if (res[2] == 0) res[2] = 32; - *width = res[0], *height = res[1], *bpp = res[2]; + *width = res[0], *height = res[1]; + if (bpp != NULL) + *bpp = res[2]; return true; } diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c index 19c98be9..b7899bc8 100644 --- a/stage23/lib/gterm.c +++ b/stage23/lib/gterm.c @@ -10,10 +10,14 @@ #include #include -#define VGA_FONT_WIDTH 8 -#define VGA_FONT_HEIGHT 16 +static size_t VGA_FONT_WIDTH = 8; +static size_t VGA_FONT_HEIGHT = 16; #define VGA_FONT_GLYPHS 256 -#define VGA_FONT_MAX (VGA_FONT_HEIGHT * VGA_FONT_GLYPHS) + +// Maximum allowed font size in bytes. 16kB should be enough as 9x32 is the +// largest font I've seen, and that would take 9*32 * 256 * 1/8 byte = +// 9216 bytes. +#define VGA_FONT_MAX 16384 struct fb_info fbinfo; static uint32_t *gterm_framebuffer; @@ -640,21 +644,39 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { gterm_bpp = fbinfo.framebuffer_bpp; gterm_pitch = fbinfo.framebuffer_pitch; + size_t font_width = VGA_FONT_WIDTH, font_height = VGA_FONT_HEIGHT; + + char *menu_font_size = config_get_value(NULL, 0, "MENU_FONT_SIZE"); + if (menu_font_size != NULL) + parse_resolution(&font_width, &font_height, NULL, menu_font_size); + + size_t font_bytes = (font_width * font_height * VGA_FONT_GLYPHS) / 8; + if (vga_font_bits == NULL) { vga_font_bits = ext_mem_alloc(VGA_FONT_MAX); memcpy(vga_font_bits, (void *)_binary_font_bin_start, VGA_FONT_MAX); } - char *menu_font = config_get_value(NULL, 0, "MENU_FONT"); - if (menu_font == NULL) - menu_font = config_get_value(NULL, 0, "TERMINAL_FONT"); + char *menu_font = NULL; + + if (font_bytes > VGA_FONT_MAX) { + print("Font would be too large (%x bytes, %x bytes allowed). Not loading.\n"); + } else { + menu_font = config_get_value(NULL, 0, "MENU_FONT"); + if (menu_font == NULL) + menu_font = config_get_value(NULL, 0, "TERMINAL_FONT"); + } + if (menu_font != NULL) { struct file_handle f; if (!uri_open(&f, menu_font)) { print("menu: Could not open font file.\n"); } else { - fread(&f, vga_font_bits, 0, VGA_FONT_MAX); + if (fread(&f, vga_font_bits, 0, font_bytes) == 0) { + VGA_FONT_WIDTH = font_width; + VGA_FONT_HEIGHT = font_height; + } } } @@ -666,8 +688,13 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { uint8_t *glyph = &vga_font_bits[i * VGA_FONT_HEIGHT]; for (size_t y = 0; y < VGA_FONT_HEIGHT; y++) { + // NOTE: the characters in VGA fonts are always at most + // one byte wide. 9 dot wide fonts have 8 dots and one + // empty column, except characters 0xC0-0xDF replicate + // column 9 in Line Graphics Mode. (TODO: implement that) for (size_t x = 0; x < VGA_FONT_WIDTH; x++) { size_t offset = i * VGA_FONT_HEIGHT * VGA_FONT_WIDTH + y * VGA_FONT_WIDTH + x; + if ((glyph[y] & (0x80 >> x))) { vga_font_bool[offset] = true; } else { diff --git a/stage23/menu.c b/stage23/menu.c index 6720472f..43428ea4 100644 --- a/stage23/menu.c +++ b/stage23/menu.c @@ -79,6 +79,7 @@ static const char *VALID_KEYS[] = { "MENU_RESOLUTION", "MENU_BRANDING", "MENU_FONT", + "MENU_FONT_SIZE", "TERMINAL_FONT", "THEME_COLOURS", "THEME_COLORS", From c11dc2388d34a261f81cd95c46e78a91e82a213a Mon Sep 17 00:00:00 2001 From: Hannu Hartikainen Date: Wed, 18 Aug 2021 15:07:44 +0300 Subject: [PATCH 3/5] gterm: rename vga_font_{width,height} to lowercase Now that the values are editable, this is the correct letter case. However this deserves its own commit so the commit with the logical change is easier to read. --- stage23/lib/gterm.c | 76 ++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c index b7899bc8..23b81709 100644 --- a/stage23/lib/gterm.c +++ b/stage23/lib/gterm.c @@ -10,8 +10,8 @@ #include #include -static size_t VGA_FONT_WIDTH = 8; -static size_t VGA_FONT_HEIGHT = 16; +static size_t vga_font_width = 8; +static size_t vga_font_height = 16; #define VGA_FONT_GLYPHS 256 // Maximum allowed font size in bytes. 16kB should be enough as 9x32 is the @@ -106,16 +106,16 @@ static uint32_t blend_gradient_from_box(size_t x, size_t y, uint32_t bg_px, uint if (x < frame_width) x_distance = frame_width - x; else - x_distance = x - (frame_width + VGA_FONT_WIDTH * cols); + x_distance = x - (frame_width + vga_font_width * cols); if (y < frame_height) y_distance = frame_height - y; else - y_distance = y - (frame_height + VGA_FONT_HEIGHT * rows); + y_distance = y - (frame_height + vga_font_height * rows); - if (x >= frame_width && x < frame_width + VGA_FONT_WIDTH * cols) { + if (x >= frame_width && x < frame_width + vga_font_width * cols) { distance = y_distance; - } else if (y >= frame_height && y < frame_height + VGA_FONT_HEIGHT * rows) { + } else if (y >= frame_height && y < frame_height + vga_font_height * rows) { distance = x_distance; } else { distance = sqrt((uint64_t)x_distance * (uint64_t)x_distance @@ -208,7 +208,7 @@ static void loop_internal(size_t xstart, size_t xend, size_t ystart, size_t yend void gterm_generate_canvas(void) { if (background) { - const size_t frame_height_end = frame_height + VGA_FONT_HEIGHT * rows, frame_width_end = frame_width + VGA_FONT_WIDTH * cols; + const size_t frame_height_end = frame_height + vga_font_height * rows, frame_width_end = frame_width + vga_font_width * cols; const size_t fheight = frame_height - margin_gradient, fheight_end = frame_height_end + margin_gradient, fwidth = frame_width - margin_gradient, fwidth_end = frame_width_end + margin_gradient; @@ -242,28 +242,28 @@ struct gterm_char { }; void gterm_plot_char(struct gterm_char *c, size_t x, size_t y) { - bool *glyph = &vga_font_bool[c->c * VGA_FONT_HEIGHT * VGA_FONT_WIDTH]; - for (size_t i = 0; i < VGA_FONT_HEIGHT; i++) { + bool *glyph = &vga_font_bool[c->c * vga_font_height * vga_font_width]; + for (size_t i = 0; i < vga_font_height; i++) { uint32_t *fb_line = gterm_framebuffer + x + (y + i) * (gterm_pitch / 4); uint32_t *canvas_line = bg_canvas + x + (y + i) * gterm_width; - for (size_t j = 0; j < VGA_FONT_WIDTH; j++) { + for (size_t j = 0; j < vga_font_width; j++) { uint32_t bg = c->bg == 0xffffffff ? canvas_line[j] : c->bg; - bool draw = glyph[i * VGA_FONT_WIDTH + j]; + bool draw = glyph[i * vga_font_width + j]; fb_line[j] = draw ? c->fg : bg; } } } void gterm_plot_char_fast(struct gterm_char *old, struct gterm_char *c, size_t x, size_t y) { - bool *new_glyph = &vga_font_bool[c->c * VGA_FONT_HEIGHT * VGA_FONT_WIDTH]; - bool *old_glyph = &vga_font_bool[old->c * VGA_FONT_HEIGHT * VGA_FONT_WIDTH]; - for (size_t i = 0; i < VGA_FONT_HEIGHT; i++) { + bool *new_glyph = &vga_font_bool[c->c * vga_font_height * vga_font_width]; + bool *old_glyph = &vga_font_bool[old->c * vga_font_height * vga_font_width]; + for (size_t i = 0; i < vga_font_height; i++) { uint32_t *fb_line = gterm_framebuffer + x + (y + i) * (gterm_pitch / 4); uint32_t *canvas_line = bg_canvas + x + (y + i) * gterm_width; - for (size_t j = 0; j < VGA_FONT_WIDTH; j++) { + for (size_t j = 0; j < vga_font_width; j++) { uint32_t bg = c->bg == 0xffffffff ? canvas_line[j] : c->bg; - bool old_draw = old_glyph[i * VGA_FONT_WIDTH + j]; - bool new_draw = new_glyph[i * VGA_FONT_WIDTH + j]; + bool old_draw = old_glyph[i * vga_font_width + j]; + bool new_draw = new_glyph[i * vga_font_width + j]; if (old_draw == new_draw) continue; fb_line[j] = new_draw ? c->fg : bg; @@ -272,7 +272,7 @@ void gterm_plot_char_fast(struct gterm_char *old, struct gterm_char *c, size_t x } static void plot_char_grid_force(struct gterm_char *c, size_t x, size_t y) { - gterm_plot_char(c, frame_width + x * VGA_FONT_WIDTH, frame_height + y * VGA_FONT_HEIGHT); + gterm_plot_char(c, frame_width + x * vga_font_width, frame_height + y * vga_font_height); } static void plot_char_grid(struct gterm_char *c, size_t x, size_t y) { @@ -281,9 +281,9 @@ static void plot_char_grid(struct gterm_char *c, size_t x, size_t y) { if (old->c != c->c || old->fg != c->fg || old->bg != c->bg) { if (old->fg == c->fg && old->bg == c->bg) { - gterm_plot_char_fast(old, c, frame_width + x * VGA_FONT_WIDTH, frame_height + y * VGA_FONT_HEIGHT); + gterm_plot_char_fast(old, c, frame_width + x * vga_font_width, frame_height + y * vga_font_height); } else { - gterm_plot_char(c, frame_width + x * VGA_FONT_WIDTH, frame_height + y * VGA_FONT_HEIGHT); + gterm_plot_char(c, frame_width + x * vga_font_width, frame_height + y * vga_font_height); } } } @@ -403,8 +403,8 @@ void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y if (!double_buffer_enabled) { gterm_plot_char(&grid[old_x + old_y * cols], - frame_width + new_x * VGA_FONT_WIDTH, - frame_height + new_y * VGA_FONT_HEIGHT); + frame_width + new_x * vga_font_width, + frame_height + new_y * vga_font_height); } grid[new_x + new_y * cols] = grid[old_x + old_y * cols]; } @@ -443,8 +443,8 @@ void gterm_double_buffer_flush(void) { size_t x = i % cols; size_t y = i / cols; - gterm_plot_char(&grid[i], x * VGA_FONT_WIDTH + frame_width, - y * VGA_FONT_HEIGHT + frame_height); + gterm_plot_char(&grid[i], x * vga_font_width + frame_width, + y * vga_font_height + frame_height); } draw_cursor(); @@ -644,7 +644,7 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { gterm_bpp = fbinfo.framebuffer_bpp; gterm_pitch = fbinfo.framebuffer_pitch; - size_t font_width = VGA_FONT_WIDTH, font_height = VGA_FONT_HEIGHT; + size_t font_width = vga_font_width, font_height = vga_font_height; char *menu_font_size = config_get_value(NULL, 0, "MENU_FONT_SIZE"); if (menu_font_size != NULL) @@ -674,26 +674,26 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { print("menu: Could not open font file.\n"); } else { if (fread(&f, vga_font_bits, 0, font_bytes) == 0) { - VGA_FONT_WIDTH = font_width; - VGA_FONT_HEIGHT = font_height; + vga_font_width = font_width; + vga_font_height = font_height; } } } // if not loaded (stage2) or custom font (stage3), load font if (vga_font_bool == NULL || menu_font != NULL) { - vga_font_bool = ext_mem_alloc(VGA_FONT_GLYPHS * VGA_FONT_HEIGHT * VGA_FONT_WIDTH * sizeof(bool)); + vga_font_bool = ext_mem_alloc(VGA_FONT_GLYPHS * vga_font_height * vga_font_width * sizeof(bool)); for (size_t i = 0; i < VGA_FONT_GLYPHS; i++) { - uint8_t *glyph = &vga_font_bits[i * VGA_FONT_HEIGHT]; + uint8_t *glyph = &vga_font_bits[i * vga_font_height]; - for (size_t y = 0; y < VGA_FONT_HEIGHT; y++) { + for (size_t y = 0; y < vga_font_height; y++) { // NOTE: the characters in VGA fonts are always at most // one byte wide. 9 dot wide fonts have 8 dots and one // empty column, except characters 0xC0-0xDF replicate // column 9 in Line Graphics Mode. (TODO: implement that) - for (size_t x = 0; x < VGA_FONT_WIDTH; x++) { - size_t offset = i * VGA_FONT_HEIGHT * VGA_FONT_WIDTH + y * VGA_FONT_WIDTH + x; + for (size_t x = 0; x < vga_font_width; x++) { + size_t offset = i * vga_font_height * vga_font_width + y * vga_font_width + x; if ((glyph[y] & (0x80 >> x))) { vga_font_bool[offset] = true; @@ -705,8 +705,8 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { } } - *_cols = cols = (gterm_width - margin * 2) / VGA_FONT_WIDTH; - *_rows = rows = (gterm_height - margin * 2) / VGA_FONT_HEIGHT; + *_cols = cols = (gterm_width - margin * 2) / vga_font_width; + *_rows = rows = (gterm_height - margin * 2) / vga_font_height; size_t new_grid_size = rows * cols * sizeof(struct gterm_char); if (new_grid_size > last_grid_size) { @@ -720,8 +720,8 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { last_front_grid_size = new_front_grid_size; } - frame_height = gterm_height / 2 - (VGA_FONT_HEIGHT * rows) / 2; - frame_width = gterm_width / 2 - (VGA_FONT_WIDTH * cols) / 2; + frame_height = gterm_height / 2 - (vga_font_height * rows) / 2; + frame_width = gterm_width / 2 - (vga_font_width * cols) / 2; size_t new_bg_canvas_size = gterm_width * gterm_height * sizeof(uint32_t); if (new_bg_canvas_size > last_bg_canvas_size) { @@ -775,8 +775,8 @@ void gterm_full_refresh(void) { size_t x = i % cols; size_t y = i / cols; - gterm_plot_char(&grid[i], x * VGA_FONT_WIDTH + frame_width, - y * VGA_FONT_HEIGHT + frame_height); + gterm_plot_char(&grid[i], x * vga_font_width + frame_width, + y * vga_font_height + frame_height); } draw_cursor(); From 58d128b9f374727d3529b8a6e33e247a2ce30103 Mon Sep 17 00:00:00 2001 From: Hannu Hartikainen Date: Wed, 18 Aug 2021 15:49:25 +0300 Subject: [PATCH 4/5] gterm: support font scaling --- CONFIG.md | 1 + stage23/lib/gterm.c | 103 +++++++++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 7b5757f3..56e18367 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -59,6 +59,7 @@ Some keys take *URIs* as values; these are described in the next section. * `MENU_FONT` - URI path to a font file to be used instead of the default one for the menu and terminal. The font file must be a code page 437 character set comprised of 256 consecutive glyph bitmaps. Each glyph's bitmap must be expressed left to right (1 byte per row), and top to bottom (16 bytes per whole glyph by default; see `MENU_FONT_SIZE`). See e.g. the [VGA text mode font collection](https://github.com/viler-int10h/vga-text-mode-fonts) for fonts. * `TERMINAL_FONT` - Alias of `MENU_FONT`. * `MENU_FONT_SIZE` - The size of the font in dots, which must correspond to the font file or the display will be garbled. Note that glyphs are always one byte wide, and columns over 8 are empty. Many fonts may be used in both 8- and 9-dot wide variants. Defaults to `8x16`. +* `MENU_FONT_SCALE` - Scaling for the font in the x and y directions. `2x2` would display the font in double size, which is useful on high-DPI displays at native resolution. `2x1` only makes the font twice as wide, similar to the VGA 40 column mode. `4x2` might be good for a narrow font on a high resolution display. Values over 8 are disallowed. Default is no scaling, i.e. `1x1`. * `THEME_COLOURS` - Specifies the colour palette used by the terminal (AARRGGBB). It is a `;` separated array of 10 colours: black, red, green, brown, blue, magenta, cyan, gray, background, and foreground respectively. While an alpha transparency value can be specified for every colour, it is ignored for all but background. Ignored if `GRAPHICS` is not `yes`. * `THEME_COLORS` - Alias of `THEME_COLOURS`. * `THEME_BACKGROUND` - Alias of the background value in `THEME_COLOURS`. diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c index 23b81709..3fbdffbd 100644 --- a/stage23/lib/gterm.c +++ b/stage23/lib/gterm.c @@ -10,14 +10,19 @@ #include #include -static size_t vga_font_width = 8; -static size_t vga_font_height = 16; -#define VGA_FONT_GLYPHS 256 - // Maximum allowed font size in bytes. 16kB should be enough as 9x32 is the // largest font I've seen, and that would take 9*32 * 256 * 1/8 byte = // 9216 bytes. #define VGA_FONT_MAX 16384 +#define VGA_FONT_GLYPHS 256 + +static size_t vga_font_width = 8; +static size_t vga_font_height = 16; +static size_t glyph_width = 8; +static size_t glyph_height = 16; + +static size_t vga_font_scale_x = 1; +static size_t vga_font_scale_y = 1; struct fb_info fbinfo; static uint32_t *gterm_framebuffer; @@ -106,16 +111,16 @@ static uint32_t blend_gradient_from_box(size_t x, size_t y, uint32_t bg_px, uint if (x < frame_width) x_distance = frame_width - x; else - x_distance = x - (frame_width + vga_font_width * cols); + x_distance = x - (frame_width + glyph_width * cols); if (y < frame_height) y_distance = frame_height - y; else - y_distance = y - (frame_height + vga_font_height * rows); + y_distance = y - (frame_height + glyph_height * rows); - if (x >= frame_width && x < frame_width + vga_font_width * cols) { + if (x >= frame_width && x < frame_width + glyph_width * cols) { distance = y_distance; - } else if (y >= frame_height && y < frame_height + vga_font_height * rows) { + } else if (y >= frame_height && y < frame_height + glyph_height * rows) { distance = x_distance; } else { distance = sqrt((uint64_t)x_distance * (uint64_t)x_distance @@ -208,7 +213,7 @@ static void loop_internal(size_t xstart, size_t xend, size_t ystart, size_t yend void gterm_generate_canvas(void) { if (background) { - const size_t frame_height_end = frame_height + vga_font_height * rows, frame_width_end = frame_width + vga_font_width * cols; + const size_t frame_height_end = frame_height + glyph_height * rows, frame_width_end = frame_width + glyph_width * cols; const size_t fheight = frame_height - margin_gradient, fheight_end = frame_height_end + margin_gradient, fwidth = frame_width - margin_gradient, fwidth_end = frame_width_end + margin_gradient; @@ -243,13 +248,18 @@ struct gterm_char { void gterm_plot_char(struct gterm_char *c, size_t x, size_t y) { bool *glyph = &vga_font_bool[c->c * vga_font_height * vga_font_width]; - for (size_t i = 0; i < vga_font_height; i++) { - uint32_t *fb_line = gterm_framebuffer + x + (y + i) * (gterm_pitch / 4); - uint32_t *canvas_line = bg_canvas + x + (y + i) * gterm_width; - for (size_t j = 0; j < vga_font_width; j++) { - uint32_t bg = c->bg == 0xffffffff ? canvas_line[j] : c->bg; - bool draw = glyph[i * vga_font_width + j]; - fb_line[j] = draw ? c->fg : bg; + // naming: fx,fy for font coordinates, gx,gy for glyph coordinates + for (size_t gy = 0; gy < glyph_height; gy++) { + uint8_t fy = gy / vga_font_scale_y; + uint32_t *fb_line = gterm_framebuffer + x + (y + gy) * (gterm_pitch / 4); + uint32_t *canvas_line = bg_canvas + x + (y + gy) * gterm_width; + for (size_t fx = 0; fx < vga_font_width; fx++) { + bool draw = glyph[fy * vga_font_width + fx]; + for (size_t i = 0; i < vga_font_scale_x; i++) { + size_t gx = vga_font_scale_x * fx + i; + uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg; + fb_line[gx] = draw ? c->fg : bg; + } } } } @@ -257,22 +267,26 @@ void gterm_plot_char(struct gterm_char *c, size_t x, size_t y) { void gterm_plot_char_fast(struct gterm_char *old, struct gterm_char *c, size_t x, size_t y) { bool *new_glyph = &vga_font_bool[c->c * vga_font_height * vga_font_width]; bool *old_glyph = &vga_font_bool[old->c * vga_font_height * vga_font_width]; - for (size_t i = 0; i < vga_font_height; i++) { - uint32_t *fb_line = gterm_framebuffer + x + (y + i) * (gterm_pitch / 4); - uint32_t *canvas_line = bg_canvas + x + (y + i) * gterm_width; - for (size_t j = 0; j < vga_font_width; j++) { - uint32_t bg = c->bg == 0xffffffff ? canvas_line[j] : c->bg; - bool old_draw = old_glyph[i * vga_font_width + j]; - bool new_draw = new_glyph[i * vga_font_width + j]; + for (size_t gy = 0; gy < glyph_height; gy++) { + uint8_t fy = gy / vga_font_scale_y; + uint32_t *fb_line = gterm_framebuffer + x + (y + gy) * (gterm_pitch / 4); + uint32_t *canvas_line = bg_canvas + x + (y + gy) * gterm_width; + for (size_t fx = 0; fx < vga_font_width; fx++) { + bool old_draw = old_glyph[fy * vga_font_width + fx]; + bool new_draw = new_glyph[fy * vga_font_width + fx]; if (old_draw == new_draw) continue; - fb_line[j] = new_draw ? c->fg : bg; + for (size_t i = 0; i < vga_font_scale_x; i++) { + size_t gx = vga_font_scale_x * fx + i; + uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg; + fb_line[gx] = new_draw ? c->fg : bg; + } } } } static void plot_char_grid_force(struct gterm_char *c, size_t x, size_t y) { - gterm_plot_char(c, frame_width + x * vga_font_width, frame_height + y * vga_font_height); + gterm_plot_char(c, frame_width + x * glyph_width, frame_height + y * glyph_height); } static void plot_char_grid(struct gterm_char *c, size_t x, size_t y) { @@ -281,9 +295,9 @@ static void plot_char_grid(struct gterm_char *c, size_t x, size_t y) { if (old->c != c->c || old->fg != c->fg || old->bg != c->bg) { if (old->fg == c->fg && old->bg == c->bg) { - gterm_plot_char_fast(old, c, frame_width + x * vga_font_width, frame_height + y * vga_font_height); + gterm_plot_char_fast(old, c, frame_width + x * glyph_width, frame_height + y * glyph_height); } else { - gterm_plot_char(c, frame_width + x * vga_font_width, frame_height + y * vga_font_height); + gterm_plot_char(c, frame_width + x * glyph_width, frame_height + y * glyph_height); } } } @@ -403,8 +417,8 @@ void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y if (!double_buffer_enabled) { gterm_plot_char(&grid[old_x + old_y * cols], - frame_width + new_x * vga_font_width, - frame_height + new_y * vga_font_height); + frame_width + new_x * glyph_width, + frame_height + new_y * glyph_height); } grid[new_x + new_y * cols] = grid[old_x + old_y * cols]; } @@ -443,8 +457,8 @@ void gterm_double_buffer_flush(void) { size_t x = i % cols; size_t y = i / cols; - gterm_plot_char(&grid[i], x * vga_font_width + frame_width, - y * vga_font_height + frame_height); + gterm_plot_char(&grid[i], x * glyph_width + frame_width, + y * glyph_height + frame_height); } draw_cursor(); @@ -705,8 +719,19 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { } } - *_cols = cols = (gterm_width - margin * 2) / vga_font_width; - *_rows = rows = (gterm_height - margin * 2) / vga_font_height; + char *menu_font_scale = config_get_value(NULL, 0, "MENU_FONT_SCALE"); + if (menu_font_scale != NULL) { + parse_resolution(&vga_font_scale_x, &vga_font_scale_y, NULL, menu_font_scale); + if (vga_font_scale_x > 8 || vga_font_scale_y > 8) { + vga_font_scale_x = 1; + vga_font_scale_y = 1; + } + glyph_width = vga_font_width * vga_font_scale_x; + glyph_height = vga_font_height * vga_font_scale_y; + } + + *_cols = cols = (gterm_width - margin * 2) / glyph_width; + *_rows = rows = (gterm_height - margin * 2) / glyph_height; size_t new_grid_size = rows * cols * sizeof(struct gterm_char); if (new_grid_size > last_grid_size) { @@ -720,8 +745,8 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { last_front_grid_size = new_front_grid_size; } - frame_height = gterm_height / 2 - (vga_font_height * rows) / 2; - frame_width = gterm_width / 2 - (vga_font_width * cols) / 2; + frame_height = gterm_height / 2 - (glyph_height * rows) / 2; + frame_width = gterm_width / 2 - (glyph_width * cols) / 2; size_t new_bg_canvas_size = gterm_width * gterm_height * sizeof(uint32_t); if (new_bg_canvas_size > last_bg_canvas_size) { @@ -761,8 +786,8 @@ void gterm_context_restore(uint64_t ptr) { size_t x = i % cols; size_t y = i / cols; - gterm_plot_char(&grid[i], x * VGA_FONT_WIDTH + frame_width, - y * VGA_FONT_HEIGHT + frame_height); + gterm_plot_char(&grid[i], x * glyph_width + frame_width, + y * glyph_height + frame_height); } draw_cursor(); @@ -775,8 +800,8 @@ void gterm_full_refresh(void) { size_t x = i % cols; size_t y = i / cols; - gterm_plot_char(&grid[i], x * vga_font_width + frame_width, - y * vga_font_height + frame_height); + gterm_plot_char(&grid[i], x * glyph_width + frame_width, + y * glyph_height + frame_height); } draw_cursor(); From cd02860fc1efbc1ff37d0f1b502d88ac8489351c Mon Sep 17 00:00:00 2001 From: Hannu Hartikainen Date: Wed, 18 Aug 2021 16:03:02 +0300 Subject: [PATCH 5/5] gterm: expand font 9th column like VGA Implement column expansion like VGA Line Graphics Mode does it, e.g. the 8th column is replicated for characters 0xC0-0xDF. Do this for all columns above 8 so font sizes like 10x16 are also usable. --- stage23/lib/gterm.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c index 3fbdffbd..cdfad0e5 100644 --- a/stage23/lib/gterm.c +++ b/stage23/lib/gterm.c @@ -698,15 +698,15 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { if (vga_font_bool == NULL || menu_font != NULL) { vga_font_bool = ext_mem_alloc(VGA_FONT_GLYPHS * vga_font_height * vga_font_width * sizeof(bool)); + size_t bitwidth = vga_font_width > 8 ? 8 : vga_font_width; for (size_t i = 0; i < VGA_FONT_GLYPHS; i++) { uint8_t *glyph = &vga_font_bits[i * vga_font_height]; for (size_t y = 0; y < vga_font_height; y++) { - // NOTE: the characters in VGA fonts are always at most - // one byte wide. 9 dot wide fonts have 8 dots and one - // empty column, except characters 0xC0-0xDF replicate - // column 9 in Line Graphics Mode. (TODO: implement that) - for (size_t x = 0; x < vga_font_width; x++) { + // NOTE: the characters in VGA fonts are always one byte wide. + // 9 dot wide fonts have 8 dots and one empty column, except + // characters 0xC0-0xDF replicate column 9. + for (size_t x = 0; x < bitwidth; x++) { size_t offset = i * vga_font_height * vga_font_width + y * vga_font_width + x; if ((glyph[y] & (0x80 >> x))) { @@ -715,6 +715,16 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { vga_font_bool[offset] = false; } } + // fill columns above 8 like VGA Line Graphics Mode does + for (size_t x = 8; x < vga_font_width; x++) { + size_t offset = i * vga_font_height * vga_font_width + y * vga_font_width + x; + + if (i >= 0xC0 && i <= 0xDF) { + vga_font_bool[offset] = (glyph[y] & 1); + } else { + vga_font_bool[offset] = false; + } + } } } }