vbe: Move graphical terminal code to gterm and ship font instead of dumping from graphics card
diff --git a/stage23/Makefile b/stage23/Makefile
index f6148b59..c753cee3 100644
--- a/stage23/Makefile
+++ b/stage23/Makefile
@@ -12,7 +12,7 @@ LIMINE_VERSION := $(shell git describe --exact-match --tags `git log -n1 --prett
WERROR = -Werror
CFLAGS = -Os -pipe -Wall -Wextra $(WERROR)
-INTERNAL_CFLAGS = \
+INTERNAL_CFLAGS := \
-std=gnu11 \
-fplan9-extensions \
-ffreestanding \
@@ -21,11 +21,7 @@ INTERNAL_CFLAGS = \
-fno-omit-frame-pointer \
-Wno-address-of-packed-member \
-masm=intel \
- -mno-80387 \
- -mno-mmx \
- -mno-3dnow \
- -mno-sse \
- -mno-sse2 \
+ -mgeneral-regs-only \
-MMD \
-DBUILD_ID=$(BUILD_ID) \
-DLIMINE_VERSION='"$(LIMINE_VERSION)"' \
@@ -36,7 +32,7 @@ INTERNAL_CFLAGS = \
LDFLAGS = -Os
-INTERNAL_LDFLAGS = \
+INTERNAL_LDFLAGS := \
-lgcc \
-static-libgcc \
-nostdlib \
@@ -66,13 +62,16 @@ limine.sys: limine.elf
$(OBJCOPY) -O binary $< $@
limine_nomap.elf: $(OBJ)
- $(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o $@
- $(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -Wl,--gc-sections -Tlinker_stage2only.ld -o limine_stage2only.elf || \
+ $(LD) $(OBJ) font.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o $@
+ $(LD) $(OBJ) font.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Wl,--gc-sections -Tlinker_stage2only.ld -o limine_stage2only.elf || \
( echo "This error means that stage 2 was trying to use stage 3 symbols before loading stage 3" && \
false )
-limine.elf: $(OBJ) limine.map.o
- $(LD) $(OBJ) limine.map.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker.ld -o $@
+font.o:
+ $(OBJCOPY) -B i8086 -I binary -O default font.bin $@
+
+limine.elf: $(OBJ) font.o limine.map.o
+ $(LD) $(OBJ) font.o limine.map.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker.ld -o $@
-include $(HEADER_DEPS)
@@ -83,4 +82,4 @@ limine.elf: $(OBJ) limine.map.o
nasm $< -f elf32 -o $@
clean:
- rm -f limine.elf limine_nomap.elf limine_stage2only.elf limine.map.o limine.sys stage2.bin stage2.bin.gz $(OBJ) $(HEADER_DEPS)
+ rm -f limine.elf limine_nomap.elf limine_stage2only.elf font.o limine.map.o limine.sys stage2.bin stage2.bin.gz $(OBJ) $(HEADER_DEPS)
diff --git a/stage23/drivers/vbe.c b/stage23/drivers/vbe.c
index d5b2f5cf..726cc49d 100644
--- a/stage23/drivers/vbe.c
+++ b/stage23/drivers/vbe.c
@@ -12,416 +12,6 @@
#include <mm/pmm.h>
#include <mm/mtrr.h>
-#define VGA_FONT_WIDTH 8
-#define VGA_FONT_HEIGHT 16
-#define VGA_FONT_GLYPHS 256
-#define VGA_FONT_MAX (VGA_FONT_HEIGHT * VGA_FONT_GLYPHS)
-
-static uint8_t *vga_font;
-
-static void vga_font_retrieve(void) {
- struct rm_regs r = {0};
-
- r.eax = 0x1130;
- r.ebx = 0x0600;
- rm_int(0x10, &r, &r);
-
- vga_font = ext_mem_alloc(VGA_FONT_MAX);
-
- memcpy(vga_font, (void *)rm_desegment(r.es, r.ebp), VGA_FONT_MAX);
-}
-
-static uint32_t ansi_colours[8];
-
-static struct vbe_framebuffer_info fbinfo;
-static uint32_t *vbe_framebuffer;
-static uint16_t vbe_pitch;
-static uint16_t vbe_width;
-static uint16_t vbe_height;
-static uint16_t vbe_bpp;
-
-static int frame_height, frame_width;
-
-static struct image *background;
-
-static struct vbe_char *grid;
-static struct vbe_char *front_grid;
-
-static bool double_buffer_enabled = false;
-
-static bool cursor_status = true;
-
-static int cursor_x;
-static int cursor_y;
-
-static uint32_t cursor_fg = 0x00000000;
-static uint32_t cursor_bg = 0x00ffffff;
-static uint32_t text_fg;
-static uint32_t text_bg;
-
-static int rows;
-static int cols;
-static int margin_gradient;
-
-#define A(rgb) (uint8_t)(rgb >> 24)
-#define R(rgb) (uint8_t)(rgb >> 16)
-#define G(rgb) (uint8_t)(rgb >> 8)
-#define B(rgb) (uint8_t)(rgb)
-#define ARGB(a, r, g, b) (a << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF)
-
-static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) {
- unsigned alpha = 255 - A(fg);
- unsigned inv_alpha = A(fg) + 1;
-
- uint8_t r = (uint8_t)((alpha * R(fg) + inv_alpha * R(bg)) / 256);
- uint8_t g = (uint8_t)((alpha * G(fg) + inv_alpha * G(bg)) / 256);
- uint8_t b = (uint8_t)((alpha * B(fg) + inv_alpha * B(bg)) / 256);
-
- return ARGB(0, r, g, b);
-}
-
-void vbe_plot_px(int x, int y, uint32_t hex) {
- size_t fb_i = x + (vbe_pitch / sizeof(uint32_t)) * y;
-
- vbe_framebuffer[fb_i] = hex;
-}
-
-static void _vbe_plot_bg_blent_px(int x, int y, uint32_t hex) {
- vbe_plot_px(x, y, colour_blend(hex, background->get_pixel(background, x, y)));
-}
-
-void (*vbe_plot_bg_blent_px)(int x, int y, uint32_t hex) = vbe_plot_px;
-
-static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) {
- if (x >= frame_width && x < frame_width + VGA_FONT_WIDTH * cols
- && y >= frame_height && y < frame_height + VGA_FONT_HEIGHT * rows) {
- return hex;
- }
-
- uint32_t bg_px = background->get_pixel(background, x, y);
-
- if (margin_gradient == 0)
- return bg_px;
-
- int distance, x_distance, y_distance;
-
- if (x < frame_width)
- x_distance = frame_width - x;
- else
- 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);
-
- 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) {
- distance = x_distance;
- } else {
- distance = sqrt((uint64_t)x_distance * (uint64_t)x_distance
- + (uint64_t)y_distance * (uint64_t)y_distance);
- }
-
- if (distance > margin_gradient)
- return bg_px;
-
- uint8_t gradient_step = (0xff - A(hex)) / margin_gradient;
- uint8_t new_alpha = A(hex) + gradient_step * distance;
-
- return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px);
-}
-
-void vbe_plot_background(int x, int y, int width, int height) {
- if (background) {
- for (int yy = 0; yy < height; yy++) {
- for (int xx = 0; xx < width; xx++) {
- vbe_plot_px(x + xx, y + yy, blend_gradient_from_box(xx, yy, text_bg));
- }
- }
- } else {
- for (int yy = 0; yy < height; yy++) {
- for (int xx = 0; xx < width; xx++) {
- vbe_plot_px(x + xx, y + yy, text_bg);
- }
- }
- }
-}
-
-void vbe_plot_rect(int x, int y, int width, int height, uint32_t hex) {
- for (int yy = 0; yy < height; yy++) {
- for (int xx = 0; xx < width; xx++) {
- vbe_plot_px(x + xx, y + yy, hex);
- }
- }
-}
-
-void vbe_plot_bg_blent_rect(int x, int y, int width, int height, uint32_t hex) {
- for (int yy = 0; yy < height; yy++) {
- for (int xx = 0; xx < width; xx++) {
- vbe_plot_bg_blent_px(x + xx, y + yy, hex);
- }
- }
-}
-
-struct vbe_char {
- uint32_t c;
- uint32_t fg;
- uint32_t bg;
-};
-
-void vbe_plot_char(struct vbe_char *c, int x, int y) {
- uint8_t *glyph = &vga_font[(size_t)c->c * VGA_FONT_HEIGHT];
-
- vbe_plot_bg_blent_rect(x, y, VGA_FONT_WIDTH, VGA_FONT_HEIGHT, c->bg);
-
- for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
- for (int j = 0; j < VGA_FONT_WIDTH; j++) {
- if ((glyph[i] & (0x80 >> j)))
- vbe_plot_bg_blent_px(x + j, y + i, c->fg);
- }
- }
-}
-
-static void plot_char_grid(struct vbe_char *c, int x, int y) {
- if (!double_buffer_enabled) {
- vbe_plot_char(c, x * VGA_FONT_WIDTH + frame_width,
- y * VGA_FONT_HEIGHT + frame_height);
- }
- grid[x + y * cols] = *c;
-}
-
-static void clear_cursor(void) {
- struct vbe_char c = grid[cursor_x + cursor_y * cols];
- c.fg = text_fg;
- c.bg = text_bg;
- plot_char_grid(&c, cursor_x, cursor_y);
-}
-
-static void draw_cursor(void) {
- if (cursor_status) {
- struct vbe_char c = grid[cursor_x + cursor_y * cols];
- c.fg = cursor_fg;
- c.bg = cursor_bg;
- plot_char_grid(&c, cursor_x, cursor_y);
- }
-}
-
-static void scroll(void) {
- clear_cursor();
-
- for (int i = cols; i < rows * cols; i++) {
- plot_char_grid(&grid[i], (i - cols) % cols, (i - cols) / cols);
- }
-
- // Clear the last line of the screen.
- struct vbe_char empty;
- empty.c = ' ';
- empty.fg = text_fg;
- empty.bg = text_bg;
- for (int i = rows * cols - cols; i < rows * cols; i++) {
- plot_char_grid(&empty, i % cols, i / cols);
- }
-
- draw_cursor();
-}
-
-void vbe_clear(bool move) {
- clear_cursor();
-
- struct vbe_char empty;
- empty.c = ' ';
- empty.fg = text_fg;
- empty.bg = text_bg;
- for (int i = 0; i < rows * cols; i++) {
- plot_char_grid(&empty, i % cols, i / cols);
- }
-
- if (move) {
- cursor_x = 0;
- cursor_y = 0;
- }
-
- draw_cursor();
-}
-
-void vbe_enable_cursor(void) {
- cursor_status = true;
- draw_cursor();
-}
-
-void vbe_disable_cursor(void) {
- clear_cursor();
- cursor_status = false;
-}
-
-void vbe_set_cursor_pos(int x, int y) {
- clear_cursor();
- cursor_x = x;
- cursor_y = y;
- draw_cursor();
-}
-
-void vbe_get_cursor_pos(int *x, int *y) {
- *x = cursor_x;
- *y = cursor_y;
-}
-
-void vbe_set_text_fg(int fg) {
- text_fg = ansi_colours[fg];
-}
-
-void vbe_set_text_bg(int bg) {
- text_bg = ansi_colours[bg];
-}
-
-void vbe_double_buffer_flush(void) {
- for (size_t i = 0; i < (size_t)rows * cols; i++) {
- if (!memcmp(&grid[i], &front_grid[i], sizeof(struct vbe_char)))
- continue;
-
- front_grid[i] = grid[i];
-
- int x = i % cols;
- int y = i / cols;
-
- vbe_plot_char(&grid[i], x * VGA_FONT_WIDTH + frame_width,
- y * VGA_FONT_HEIGHT + frame_height);
- }
-}
-
-void vbe_double_buffer(bool state) {
- if (state) {
- memcpy(front_grid, grid, rows * cols * sizeof(struct vbe_char));
- double_buffer_enabled = true;
- vbe_clear(true);
- vbe_double_buffer_flush();
- } else {
- bool pcs = cursor_status;
- cursor_status = false;
- vbe_clear(true);
- vbe_double_buffer_flush();
- cursor_status = pcs;
- draw_cursor();
- double_buffer_enabled = false;
- }
-}
-
-void vbe_putchar(uint8_t c) {
- switch (c) {
- case '\b':
- if (cursor_x || cursor_y) {
- clear_cursor();
- if (cursor_x) {
- cursor_x--;
- } else {
- cursor_y--;
- cursor_x = cols - 1;
- }
- draw_cursor();
- }
- break;
- case '\r':
- vbe_set_cursor_pos(0, cursor_y);
- break;
- case '\n':
- if (cursor_y == (rows - 1)) {
- vbe_set_cursor_pos(0, rows - 1);
- scroll();
- } else {
- vbe_set_cursor_pos(0, cursor_y + 1);
- }
- break;
- default: {
- clear_cursor();
- struct vbe_char ch;
- ch.c = c;
- ch.fg = text_fg;
- ch.bg = text_bg;
- plot_char_grid(&ch, cursor_x++, cursor_y);
- if (cursor_x == cols) {
- cursor_x = 0;
- cursor_y++;
- }
- if (cursor_y == rows) {
- cursor_y--;
- scroll();
- }
- draw_cursor();
- break;
- }
- }
-}
-
-bool vbe_tty_init(int *_rows, int *_cols, uint32_t *_colours, int _margin, int _margin_gradient, struct image *_background) {
- int req_width = 0, req_height = 0, req_bpp = 0;
-
- char *menu_resolution = config_get_value(NULL, 0, "MENU_RESOLUTION");
- if (menu_resolution == NULL)
- parse_resolution(&req_width, &req_height, &req_bpp, menu_resolution);
-
- // We force bpp to 32
- req_bpp = 32;
-
- init_vbe(&fbinfo, req_width, req_height, req_bpp);
-
- // Ensure this is xRGB8888, we only support that for the menu
- if (fbinfo.red_mask_size != 8
- || fbinfo.red_mask_shift != 16
- || fbinfo.green_mask_size != 8
- || fbinfo.green_mask_shift != 8
- || fbinfo.blue_mask_size != 8
- || fbinfo.blue_mask_shift != 0)
- return false;
-
- vbe_framebuffer = (void *)fbinfo.framebuffer_addr;
- vbe_width = fbinfo.framebuffer_width;
- vbe_height = fbinfo.framebuffer_height;
- vbe_bpp = fbinfo.framebuffer_bpp;
- vbe_pitch = fbinfo.framebuffer_pitch;
-
- mtrr_set_range((uint64_t)(size_t)vbe_framebuffer,
- (uint64_t)vbe_pitch * vbe_height, MTRR_MEMORY_TYPE_WC);
-
- char *menu_font = config_get_value(NULL, 0, "MENU_FONT");
- if (menu_font == NULL) {
- vga_font_retrieve();
- } else {
- struct file_handle f;
- if (!uri_open(&f, menu_font)) {
- print("menu: Could not open font file.\n");
- vga_font_retrieve();
- } else {
- vga_font = ext_mem_alloc(VGA_FONT_MAX);
- fread(&f, vga_font, 0, VGA_FONT_MAX);
- }
- }
-
- *_cols = cols = (vbe_width - _margin * 2) / VGA_FONT_WIDTH;
- *_rows = rows = (vbe_height - _margin * 2) / VGA_FONT_HEIGHT;
- grid = ext_mem_alloc(rows * cols * sizeof(struct vbe_char));
- front_grid = ext_mem_alloc(rows * cols * sizeof(struct vbe_char));
- background = _background;
-
- if (background)
- vbe_plot_bg_blent_px = _vbe_plot_bg_blent_px;
-
- memcpy(ansi_colours, _colours, sizeof(ansi_colours));
- text_bg = ansi_colours[0];
- text_fg = ansi_colours[7];
-
- margin_gradient = _margin_gradient;
-
- frame_height = vbe_height / 2 - (VGA_FONT_HEIGHT * rows) / 2;
- frame_width = vbe_width / 2 - (VGA_FONT_WIDTH * cols) / 2;
-
- vbe_plot_background(0, 0, vbe_width, vbe_height);
- vbe_clear(true);
-
- return true;
-}
-
struct vbe_info_struct {
char signature[4];
uint8_t version_min;
diff --git a/stage23/drivers/vbe.h b/stage23/drivers/vbe.h
index ef6c4139..b13d0060 100644
--- a/stage23/drivers/vbe.h
+++ b/stage23/drivers/vbe.h
@@ -3,7 +3,6 @@
#include <stdint.h>
#include <stdbool.h>
-#include <lib/image.h>
struct vbe_framebuffer_info {
uint8_t memory_model;
@@ -23,18 +22,4 @@ struct vbe_framebuffer_info {
bool init_vbe(struct vbe_framebuffer_info *ret,
uint16_t target_width, uint16_t target_height, uint16_t target_bpp);
-bool vbe_tty_init(int *rows, int *cols, uint32_t *colours, int margin, int margin_gradient, struct image *background);
-
-void vbe_putchar(uint8_t c);
-void vbe_clear(bool move);
-void vbe_enable_cursor(void);
-void vbe_disable_cursor(void);
-void vbe_set_cursor_pos(int x, int y);
-void vbe_get_cursor_pos(int *x, int *y);
-void vbe_set_text_fg(int fg);
-void vbe_set_text_bg(int bg);
-
-void vbe_double_buffer_flush(void);
-void vbe_double_buffer(bool state);
-
#endif
diff --git a/stage23/font.bin b/stage23/font.bin
new file mode 100644
index 00000000..672d0e1a
Binary files /dev/null and b/stage23/font.bin differ
diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c
new file mode 100644
index 00000000..6642c1dd
--- /dev/null
+++ b/stage23/lib/gterm.c
@@ -0,0 +1,407 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <lib/gterm.h>
+#include <lib/blib.h>
+#include <lib/libc.h>
+#include <lib/config.h>
+#include <lib/print.h>
+#include <lib/uri.h>
+#include <mm/mtrr.h>
+#include <mm/pmm.h>
+
+#define VGA_FONT_WIDTH 8
+#define VGA_FONT_HEIGHT 16
+#define VGA_FONT_GLYPHS 256
+#define VGA_FONT_MAX (VGA_FONT_HEIGHT * VGA_FONT_GLYPHS)
+
+static struct vbe_framebuffer_info fbinfo;
+static uint32_t *gterm_framebuffer;
+static uint16_t gterm_pitch;
+static uint16_t gterm_width;
+static uint16_t gterm_height;
+static uint16_t gterm_bpp;
+
+extern symbol _binary_font_bin_start;
+
+static uint8_t *vga_font = (void *)_binary_font_bin_start;
+
+static uint32_t ansi_colours[8];
+
+static int frame_height, frame_width;
+
+static struct image *background;
+
+static struct gterm_char *grid;
+static struct gterm_char *front_grid;
+
+static bool double_buffer_enabled = false;
+
+static bool cursor_status = true;
+
+static int cursor_x;
+static int cursor_y;
+
+static uint32_t cursor_fg = 0x00000000;
+static uint32_t cursor_bg = 0x00ffffff;
+static uint32_t text_fg;
+static uint32_t text_bg;
+
+static int rows;
+static int cols;
+static int margin_gradient;
+
+#define A(rgb) (uint8_t)(rgb >> 24)
+#define R(rgb) (uint8_t)(rgb >> 16)
+#define G(rgb) (uint8_t)(rgb >> 8)
+#define B(rgb) (uint8_t)(rgb)
+#define ARGB(a, r, g, b) (a << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF)
+
+static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) {
+ unsigned alpha = 255 - A(fg);
+ unsigned inv_alpha = A(fg) + 1;
+
+ uint8_t r = (uint8_t)((alpha * R(fg) + inv_alpha * R(bg)) / 256);
+ uint8_t g = (uint8_t)((alpha * G(fg) + inv_alpha * G(bg)) / 256);
+ uint8_t b = (uint8_t)((alpha * B(fg) + inv_alpha * B(bg)) / 256);
+
+ return ARGB(0, r, g, b);
+}
+
+void gterm_plot_px(int x, int y, uint32_t hex) {
+ size_t fb_i = x + (gterm_pitch / sizeof(uint32_t)) * y;
+
+ gterm_framebuffer[fb_i] = hex;
+}
+
+static void _gterm_plot_bg_blent_px(int x, int y, uint32_t hex) {
+ gterm_plot_px(x, y, colour_blend(hex, background->get_pixel(background, x, y)));
+}
+
+void (*gterm_plot_bg_blent_px)(int x, int y, uint32_t hex) = gterm_plot_px;
+
+static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) {
+ if (x >= frame_width && x < frame_width + VGA_FONT_WIDTH * cols
+ && y >= frame_height && y < frame_height + VGA_FONT_HEIGHT * rows) {
+ return hex;
+ }
+
+ uint32_t bg_px = background->get_pixel(background, x, y);
+
+ if (margin_gradient == 0)
+ return bg_px;
+
+ int distance, x_distance, y_distance;
+
+ if (x < frame_width)
+ x_distance = frame_width - x;
+ else
+ 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);
+
+ 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) {
+ distance = x_distance;
+ } else {
+ distance = sqrt((uint64_t)x_distance * (uint64_t)x_distance
+ + (uint64_t)y_distance * (uint64_t)y_distance);
+ }
+
+ if (distance > margin_gradient)
+ return bg_px;
+
+ uint8_t gradient_step = (0xff - A(hex)) / margin_gradient;
+ uint8_t new_alpha = A(hex) + gradient_step * distance;
+
+ return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px);
+}
+
+void gterm_plot_background(int x, int y, int width, int height) {
+ if (background) {
+ for (int yy = 0; yy < height; yy++) {
+ for (int xx = 0; xx < width; xx++) {
+ gterm_plot_px(x + xx, y + yy, blend_gradient_from_box(xx, yy, text_bg));
+ }
+ }
+ } else {
+ for (int yy = 0; yy < height; yy++) {
+ for (int xx = 0; xx < width; xx++) {
+ gterm_plot_px(x + xx, y + yy, text_bg);
+ }
+ }
+ }
+}
+
+void gterm_plot_rect(int x, int y, int width, int height, uint32_t hex) {
+ for (int yy = 0; yy < height; yy++) {
+ for (int xx = 0; xx < width; xx++) {
+ gterm_plot_px(x + xx, y + yy, hex);
+ }
+ }
+}
+
+void gterm_plot_bg_blent_rect(int x, int y, int width, int height, uint32_t hex) {
+ for (int yy = 0; yy < height; yy++) {
+ for (int xx = 0; xx < width; xx++) {
+ gterm_plot_bg_blent_px(x + xx, y + yy, hex);
+ }
+ }
+}
+
+struct gterm_char {
+ uint32_t c;
+ uint32_t fg;
+ uint32_t bg;
+};
+
+void gterm_plot_char(struct gterm_char *c, int x, int y) {
+ uint8_t *glyph = &vga_font[(size_t)c->c * VGA_FONT_HEIGHT];
+
+ gterm_plot_bg_blent_rect(x, y, VGA_FONT_WIDTH, VGA_FONT_HEIGHT, c->bg);
+
+ for (int i = 0; i < VGA_FONT_HEIGHT; i++) {
+ for (int j = 0; j < VGA_FONT_WIDTH; j++) {
+ if ((glyph[i] & (0x80 >> j)))
+ gterm_plot_bg_blent_px(x + j, y + i, c->fg);
+ }
+ }
+}
+
+static void plot_char_grid(struct gterm_char *c, int x, int y) {
+ if (!double_buffer_enabled) {
+ gterm_plot_char(c, x * VGA_FONT_WIDTH + frame_width,
+ y * VGA_FONT_HEIGHT + frame_height);
+ }
+ grid[x + y * cols] = *c;
+}
+
+static void clear_cursor(void) {
+ struct gterm_char c = grid[cursor_x + cursor_y * cols];
+ c.fg = text_fg;
+ c.bg = text_bg;
+ plot_char_grid(&c, cursor_x, cursor_y);
+}
+
+static void draw_cursor(void) {
+ if (cursor_status) {
+ struct gterm_char c = grid[cursor_x + cursor_y * cols];
+ c.fg = cursor_fg;
+ c.bg = cursor_bg;
+ plot_char_grid(&c, cursor_x, cursor_y);
+ }
+}
+
+static void scroll(void) {
+ clear_cursor();
+
+ for (int i = cols; i < rows * cols; i++) {
+ plot_char_grid(&grid[i], (i - cols) % cols, (i - cols) / cols);
+ }
+
+ // Clear the last line of the screen.
+ struct gterm_char empty;
+ empty.c = ' ';
+ empty.fg = text_fg;
+ empty.bg = text_bg;
+ for (int i = rows * cols - cols; i < rows * cols; i++) {
+ plot_char_grid(&empty, i % cols, i / cols);
+ }
+
+ draw_cursor();
+}
+
+void gterm_clear(bool move) {
+ clear_cursor();
+
+ struct gterm_char empty;
+ empty.c = ' ';
+ empty.fg = text_fg;
+ empty.bg = text_bg;
+ for (int i = 0; i < rows * cols; i++) {
+ plot_char_grid(&empty, i % cols, i / cols);
+ }
+
+ if (move) {
+ cursor_x = 0;
+ cursor_y = 0;
+ }
+
+ draw_cursor();
+}
+
+void gterm_enable_cursor(void) {
+ cursor_status = true;
+ draw_cursor();
+}
+
+void gterm_disable_cursor(void) {
+ clear_cursor();
+ cursor_status = false;
+}
+
+void gterm_set_cursor_pos(int x, int y) {
+ clear_cursor();
+ cursor_x = x;
+ cursor_y = y;
+ draw_cursor();
+}
+
+void gterm_get_cursor_pos(int *x, int *y) {
+ *x = cursor_x;
+ *y = cursor_y;
+}
+
+void gterm_set_text_fg(int fg) {
+ text_fg = ansi_colours[fg];
+}
+
+void gterm_set_text_bg(int bg) {
+ text_bg = ansi_colours[bg];
+}
+
+void gterm_double_buffer_flush(void) {
+ for (size_t i = 0; i < (size_t)rows * cols; i++) {
+ if (!memcmp(&grid[i], &front_grid[i], sizeof(struct gterm_char)))
+ continue;
+
+ front_grid[i] = grid[i];
+
+ int x = i % cols;
+ int y = i / cols;
+
+ gterm_plot_char(&grid[i], x * VGA_FONT_WIDTH + frame_width,
+ y * VGA_FONT_HEIGHT + frame_height);
+ }
+}
+
+void gterm_double_buffer(bool state) {
+ if (state) {
+ memcpy(front_grid, grid, rows * cols * sizeof(struct gterm_char));
+ double_buffer_enabled = true;
+ gterm_clear(true);
+ gterm_double_buffer_flush();
+ } else {
+ bool pcs = cursor_status;
+ cursor_status = false;
+ gterm_clear(true);
+ gterm_double_buffer_flush();
+ cursor_status = pcs;
+ draw_cursor();
+ double_buffer_enabled = false;
+ }
+}
+
+void gterm_putchar(uint8_t c) {
+ switch (c) {
+ case '\b':
+ if (cursor_x || cursor_y) {
+ clear_cursor();
+ if (cursor_x) {
+ cursor_x--;
+ } else {
+ cursor_y--;
+ cursor_x = cols - 1;
+ }
+ draw_cursor();
+ }
+ break;
+ case '\r':
+ gterm_set_cursor_pos(0, cursor_y);
+ break;
+ case '\n':
+ if (cursor_y == (rows - 1)) {
+ gterm_set_cursor_pos(0, rows - 1);
+ scroll();
+ } else {
+ gterm_set_cursor_pos(0, cursor_y + 1);
+ }
+ break;
+ default: {
+ clear_cursor();
+ struct gterm_char ch;
+ ch.c = c;
+ ch.fg = text_fg;
+ ch.bg = text_bg;
+ plot_char_grid(&ch, cursor_x++, cursor_y);
+ if (cursor_x == cols) {
+ cursor_x = 0;
+ cursor_y++;
+ }
+ if (cursor_y == rows) {
+ cursor_y--;
+ scroll();
+ }
+ draw_cursor();
+ break;
+ }
+ }
+}
+
+bool gterm_init(int *_rows, int *_cols, uint32_t *_colours, int _margin, int _margin_gradient, struct image *_background) {
+ int req_width = 0, req_height = 0, req_bpp = 0;
+
+ char *menu_resolution = config_get_value(NULL, 0, "MENU_RESOLUTION");
+ if (menu_resolution == NULL)
+ parse_resolution(&req_width, &req_height, &req_bpp, menu_resolution);
+
+ // We force bpp to 32
+ req_bpp = 32;
+
+ init_vbe(&fbinfo, req_width, req_height, req_bpp);
+
+ // Ensure this is xRGB8888, we only support that for the menu
+ if (fbinfo.red_mask_size != 8
+ || fbinfo.red_mask_shift != 16
+ || fbinfo.green_mask_size != 8
+ || fbinfo.green_mask_shift != 8
+ || fbinfo.blue_mask_size != 8
+ || fbinfo.blue_mask_shift != 0)
+ return false;
+
+ gterm_framebuffer = (void *)fbinfo.framebuffer_addr;
+ gterm_width = fbinfo.framebuffer_width;
+ gterm_height = fbinfo.framebuffer_height;
+ gterm_bpp = fbinfo.framebuffer_bpp;
+ gterm_pitch = fbinfo.framebuffer_pitch;
+
+ mtrr_set_range((uint64_t)(size_t)gterm_framebuffer,
+ (uint64_t)gterm_pitch * gterm_height, MTRR_MEMORY_TYPE_WC);
+
+ char *menu_font = config_get_value(NULL, 0, "MENU_FONT");
+ if (menu_font != NULL) {
+ struct file_handle f;
+ if (!uri_open(&f, menu_font)) {
+ print("menu: Could not open font file.\n");
+ } else {
+ vga_font = ext_mem_alloc(VGA_FONT_MAX);
+ fread(&f, vga_font, 0, VGA_FONT_MAX);
+ }
+ }
+
+ *_cols = cols = (gterm_width - _margin * 2) / VGA_FONT_WIDTH;
+ *_rows = rows = (gterm_height - _margin * 2) / VGA_FONT_HEIGHT;
+ grid = ext_mem_alloc(rows * cols * sizeof(struct gterm_char));
+ front_grid = ext_mem_alloc(rows * cols * sizeof(struct gterm_char));
+ background = _background;
+
+ if (background)
+ gterm_plot_bg_blent_px = _gterm_plot_bg_blent_px;
+
+ memcpy(ansi_colours, _colours, sizeof(ansi_colours));
+ text_bg = ansi_colours[0];
+ text_fg = ansi_colours[7];
+
+ margin_gradient = _margin_gradient;
+
+ frame_height = gterm_height / 2 - (VGA_FONT_HEIGHT * rows) / 2;
+ frame_width = gterm_width / 2 - (VGA_FONT_WIDTH * cols) / 2;
+
+ gterm_plot_background(0, 0, gterm_width, gterm_height);
+ gterm_clear(true);
+
+ return true;
+}
diff --git a/stage23/lib/gterm.h b/stage23/lib/gterm.h
new file mode 100644
index 00000000..65b7565c
--- /dev/null
+++ b/stage23/lib/gterm.h
@@ -0,0 +1,24 @@
+#ifndef __LIB__GTERM_H__
+#define __LIB__GTERM_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <lib/image.h>
+#include <drivers/vbe.h>
+
+bool gterm_init(int *rows, int *cols, uint32_t *colours, int margin,
+ int margin_gradient, struct image *background);
+
+void gterm_putchar(uint8_t c);
+void gterm_clear(bool move);
+void gterm_enable_cursor(void);
+void gterm_disable_cursor(void);
+void gterm_set_cursor_pos(int x, int y);
+void gterm_get_cursor_pos(int *x, int *y);
+void gterm_set_text_fg(int fg);
+void gterm_set_text_bg(int bg);
+
+void gterm_double_buffer_flush(void);
+void gterm_double_buffer(bool state);
+
+#endif
diff --git a/stage23/lib/term.c b/stage23/lib/term.c
index b636f4be..441c924b 100644
--- a/stage23/lib/term.c
+++ b/stage23/lib/term.c
@@ -4,27 +4,28 @@
#include <lib/term.h>
#include <lib/image.h>
#include <lib/blib.h>
-#include <drivers/vbe.h>
+#include <lib/gterm.h>
void term_vbe(uint32_t *colours, int margin, int margin_gradient, struct image *background) {
term_deinit();
- if (!vbe_tty_init(&term_rows, &term_cols, colours, margin, margin_gradient, background)) {
+
+ if (!gterm_init(&term_rows, &term_cols, colours, margin, margin_gradient, background)) {
// Failed to set VBE properly, default to text mode
term_textmode();
return;
}
- raw_putchar = vbe_putchar;
- clear = vbe_clear;
- enable_cursor = vbe_enable_cursor;
- disable_cursor = vbe_disable_cursor;
- set_cursor_pos = vbe_set_cursor_pos;
- get_cursor_pos = vbe_get_cursor_pos;
- set_text_fg = vbe_set_text_fg;
- set_text_bg = vbe_set_text_bg;
+ raw_putchar = gterm_putchar;
+ clear = gterm_clear;
+ enable_cursor = gterm_enable_cursor;
+ disable_cursor = gterm_disable_cursor;
+ set_cursor_pos = gterm_set_cursor_pos;
+ get_cursor_pos = gterm_get_cursor_pos;
+ set_text_fg = gterm_set_text_fg;
+ set_text_bg = gterm_set_text_bg;
- term_double_buffer = vbe_double_buffer;
- term_double_buffer_flush = vbe_double_buffer_flush;
+ term_double_buffer = gterm_double_buffer;
+ term_double_buffer_flush = gterm_double_buffer_flush;
term_backend = VBE;
}
