diff --git a/CONFIG.md b/CONFIG.md index 5615aea4..0e9baa62 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -22,6 +22,8 @@ Some *local assignments* are shared between entries using any *protocol*, while *Globally assignable* keys are: * `TIMEOUT` - Specifies the timeout in seconds before the first *entry* is automatically booted. * `TEXTMODE` - If set to `on`, do not use graphical VESA framebuffer for the boot menu. +* `THEME_BLACK`, `THEME_RED`, `THEME_GREEN`, `THEME_BROWN`, `THEME_BLUE`, `THEME_MAGENTA`, `THEME_CYAN`, `THEME_GREY`, `THEME_WHITE` - Specifies the colors used by the terminal (RRGGBB). +* `THEME_MARGIN` - Set the amount of margin around the terminal. *Locally assignable (non protocol specific)* keys are: * `PROTOCOL` - The boot protocol that will be used to boot the kernel. Valid protocols are: `linux`, `stivale`, `chainload`. diff --git a/limine.bin b/limine.bin index 183bba7a..b92fdfbc 100644 Binary files a/limine.bin and b/limine.bin differ diff --git a/stage2/drivers/vbe.c b/stage2/drivers/vbe.c index 81484175..a80a1e12 100644 --- a/stage2/drivers/vbe.c +++ b/stage2/drivers/vbe.c @@ -28,22 +28,106 @@ static void vga_font_retrieve(void) { memcpy(vga_font, (void *)rm_desegment(r.es, r.ebp), VGA_FONT_MAX); } +static uint32_t ansi_colours[] = { + 0x00000000, // black + 0x00aa0000, // red + 0x0000aa00, // green + 0x00aa5500, // brown + 0x000000aa, // blue + 0x00aa00aa, // magenta + 0x0000aaaa, // cyan + 0x00aaaaaa, // grey + 0x00ffffff // white +}; + static uint32_t *vbe_framebuffer; static uint16_t vbe_pitch; static uint16_t vbe_width = 0; static uint16_t vbe_height = 0; static uint16_t vbe_bpp = 0; -static int frame_height, frame_width; +static int frame_height; +static int frame_width; +static int frame_margin = 64; static struct image *background; +#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 color_blend(uint32_t fg, uint32_t bg) +{ + uint8_t alpha = 255 - A(fg) ; + uint8_t inv_alpha = A(fg) - 1; + + uint8_t r = (uint8_t)((alpha * R(fg) + inv_alpha * R(bg)) / 255); + uint8_t g = (uint8_t)((alpha * G(fg) + inv_alpha * G(bg)) / 255); + uint8_t b = (uint8_t)((alpha * B(fg) + inv_alpha * B(bg)) / 255); + + 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; } +void vbe_blend_px(int x, int y, uint32_t hex) { + size_t fb_i = x + (vbe_pitch / sizeof(uint32_t)) * y; + + vbe_framebuffer[fb_i] = color_blend(hex, vbe_framebuffer[fb_i]); +} + +void vbe_fill_rect(int x, int y, int width, int height, uint32_t hex) +{ + for (int xx = 0; xx < width; xx++) + for (int yy = 0; yy < height; yy++) + vbe_plot_px(x + xx, y + yy, hex); +} + +void vbe_blend_rect(int x, int y, int width, int height, uint32_t hex) +{ + for (int xx = 0; xx < width; xx++) + for (int yy = 0; yy < height; yy++) + vbe_blend_px(x + xx, y + yy, hex); +} + +void vbe_plot_background(int x, int y, int width, int height) +{ + if (background) { + for (int xx = 0; xx < width; xx++) + for (int yy = 0; yy < height; yy++) + vbe_plot_px(x + xx, y + yy, background->get_pixel(background, x + xx, y + yy)); + } + else{ + for (int xx = 0; xx < width; xx++) + for (int yy = 0; yy < height; yy++) { + uint32_t pixel = color_blend(ansi_colours[0], 0x000000); + vbe_plot_px(x + xx, y + yy, pixel); + } + } +} + +void vbe_plot_background_colored(int x, int y, int width, int height, uint32_t hex){ + if (background) { + for (int xx = 0; xx < width; xx++) + for (int yy = 0; yy < height; yy++){ + uint32_t pixel = color_blend(hex, background->get_pixel(background, x + xx, y + yy)); + vbe_plot_px(x + xx, y + yy, pixel); + } + }else{ + for (int xx = 0; xx < width; xx++) + for (int yy = 0; yy < height; yy++) { + uint32_t pixel = color_blend(hex, 0x000000); + vbe_plot_px(x + xx, y + yy, pixel); + } + } +} + struct vbe_char { char c; uint32_t fg; @@ -51,15 +135,28 @@ struct vbe_char { }; void vbe_plot_char(struct vbe_char c, int x, int y) { - int orig_x = x; uint8_t *glyph = &vga_font[c.c * VGA_FONT_HEIGHT]; - for (int i = 0; i < VGA_FONT_HEIGHT; i++) { - for (int j = VGA_FONT_WIDTH - 1; j >= 0; j--) { - vbe_plot_px(x++, y, (glyph[i] & (1 << j)) ? c.fg : c.bg); + if (A(c.bg)) { + vbe_plot_background_colored(x, y, VGA_FONT_WIDTH, VGA_FONT_HEIGHT, c.bg); + } else { + vbe_fill_rect(x, y, VGA_FONT_WIDTH, VGA_FONT_HEIGHT, c.bg); + } + + if (A(c.fg)) { + for (int i = 0; i < VGA_FONT_HEIGHT; i++) { + for (int j = 0; j < VGA_FONT_WIDTH; j++) { + if ((glyph[i] & (0x80 >> j))) + vbe_blend_px(x + j, y + i, c.fg); + } + } + } else { + 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_px(x + j, y + i, c.fg); + } } - y++; - x = orig_x; } } @@ -123,11 +220,6 @@ static void scroll(void) { void vbe_clear(bool move) { clear_cursor(); - if (background != NULL) - for (int x = 0; x < vbe_width; x++) - for (int y = 0; y < vbe_height; y++) - vbe_plot_px(x, y, background->get_pixel(background, x, y)); - struct vbe_char empty; empty.c = ' '; empty.fg = text_fg; @@ -166,17 +258,6 @@ void vbe_get_cursor_pos(int *x, int *y) { *y = cursor_y; } -static uint32_t ansi_colours[] = { - 0x00000000, // black - 0x00aa0000, // red - 0x0000aa00, // green - 0x00aa5500, // brown - 0x000000aa, // blue - 0x00aa00aa, // magenta - 0x0000aaaa, // cyan - 0x00aaaaaa // grey -}; - void vbe_set_text_fg(int fg) { text_fg = ansi_colours[fg]; } @@ -185,6 +266,16 @@ void vbe_set_text_bg(int bg) { text_bg = ansi_colours[bg]; } +void vbe_set_colors(uint32_t *colors){ + memcpy(ansi_colours, colors, sizeof(ansi_colours)); + text_bg = colors[0]; + text_fg = colors[7]; +} + +void vbe_set_margin(int margin){ + frame_margin = margin; +} + void vbe_putchar(char c) { switch (c) { case '\b': @@ -234,14 +325,15 @@ void vbe_putchar(char c) { void vbe_tty_init(int *_rows, int *_cols, struct image *_background) { init_vbe(&vbe_framebuffer, &vbe_pitch, &vbe_width, &vbe_height, &vbe_bpp); vga_font_retrieve(); - *_cols = cols = 80; - *_rows = rows = 25; + *_cols = cols = (vbe_width - frame_margin * 2) / VGA_FONT_WIDTH; + *_rows = rows = (vbe_height - frame_margin * 2) / VGA_FONT_HEIGHT; grid = ext_mem_alloc(rows * cols * sizeof(struct vbe_char)); background = _background; 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); } diff --git a/stage2/drivers/vbe.h b/stage2/drivers/vbe.h index e1682df1..2dcc9bc9 100644 --- a/stage2/drivers/vbe.h +++ b/stage2/drivers/vbe.h @@ -17,5 +17,7 @@ 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_set_colors(uint32_t *colors); +void vbe_set_margin(int margin); #endif diff --git a/stage2/lib/blib.c b/stage2/lib/blib.c index a11f8c62..94296e7b 100644 --- a/stage2/lib/blib.c +++ b/stage2/lib/blib.c @@ -46,10 +46,31 @@ __attribute__((noreturn)) void panic(const char *fmt, ...) { } } +static int char_value(char c) { + if (c >= 'a' && c <= 'z') { + return (c - 'a') + 10; + } + if (c >= 'A' && c <= 'Z') { + return (c - 'A') + 10; + } + if (c >= '0' && c <= '9'){ + return c - '0'; + } + + return 0; +} + uint64_t strtoui(const char *s) { uint64_t n = 0; while (*s) - n = n * 10 + ((*(s++)) - '0'); + n = n * 10 + char_value(*(s++)); + return n; +} + +uint64_t strtoui16(const char *s) { + uint64_t n = 0; + while (*s) + n = n * 16 + char_value(*(s++)); return n; } diff --git a/stage2/lib/blib.h b/stage2/lib/blib.h index 67d34891..015d5839 100644 --- a/stage2/lib/blib.h +++ b/stage2/lib/blib.h @@ -21,6 +21,7 @@ int pit_sleep_and_quit_on_keypress(uint32_t pit_ticks); int getchar(void); void gets(const char *orig_str, char *buf, size_t limit); uint64_t strtoui(const char *s); +uint64_t strtoui16(const char *s); #define DIV_ROUNDUP(a, b) (((a) + ((b) - 1)) / (b)) diff --git a/stage2/lib/term.c b/stage2/lib/term.c index cf08ba44..5ceacfd5 100644 --- a/stage2/lib/term.c +++ b/stage2/lib/term.c @@ -113,6 +113,12 @@ static void term_putchar(char c) { } static void sgr(void) { + if (esc_value0 == 0){ + set_text_bg(0); + set_text_fg(7); + return; + } + if (esc_value0 >= 30 && esc_value0 <= 37) { set_text_fg(esc_value0 - 30); return; diff --git a/stage2/menu.c b/stage2/menu.c index 4b5d2e3e..92cbf746 100644 --- a/stage2/menu.c +++ b/stage2/menu.c @@ -9,12 +9,72 @@ #include #include #include +#include static char *cmdline; #define CMDLINE_MAX 1024 static char config_entry_name[1024]; +void load_theme_from_config(void) { + char buf[16]; + + uint32_t colorsheme[9] = { + 0x00191919, // black + 0x00aa0000, // red + 0x0000aa00, // green + 0x00aa5500, // brown + 0x000000aa, // blue + 0x009076DE, // magenta + 0x0000aaaa, // cyan + 0x00aaaaaa, // grey + 0x00ffffff, // white + }; + + + if (config_get_value(buf, 0, 16, "THEME_BLACK")) { + colorsheme[0] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_RED")) { + colorsheme[1] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_GREEN")) { + colorsheme[2] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_BROWN")) { + colorsheme[3] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_BLUE")) { + colorsheme[4] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_MAGENTA")) { + colorsheme[5] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_CYAN")) { + colorsheme[6] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_GREY")) { + colorsheme[7] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_WHITE")) { + colorsheme[8] = (int)strtoui16(buf); + } + + if (config_get_value(buf, 0, 16, "THEME_MARGIN")) { + vbe_set_margin((int)strtoui(buf)); + } + + vbe_set_colors(colorsheme); +} + char *menu(int boot_drive) { cmdline = conv_mem_alloc(CMDLINE_MAX); @@ -22,6 +82,8 @@ char *menu(int boot_drive) { // If there is no TEXTMODE config key or the value is not "on", enable graphics if (config_get_value(buf, 0, 16, "TEXTMODE") == NULL || strcmp(buf, "on")) { + load_theme_from_config(); + int bg_drive; if (!config_get_value(buf, 0, 16, "BACKGROUND_DRIVE")) { bg_drive = boot_drive; diff --git a/test/limine.cfg b/test/limine.cfg index 775a29a4..3617dc05 100644 --- a/test/limine.cfg +++ b/test/limine.cfg @@ -1,5 +1,16 @@ TIMEOUT=3 +THEME_BLACK=33000000 +THEME_RED=aa0000 +THEME_GREEN=00aaff +THEME_BROWN=aa5500 +THEME_BLUE=0000aa +THEME_MAGENTA=aa00aa +THEME_CYAN=9076DE +THEME_GREY=aaaaaa +THEME_WHITE=ffffff +THEME_MARGIN=16 + BACKGROUND_PARTITION=0 BACKGROUND_PATH=bg.bmp