vbe: Move graphical terminal code to gterm and ship font instead of dumping from graphics card
This commit is contained in:
parent
d4ea15e39e
commit
689e82dba7
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue