#include "video/TextConsole.h" #include "boot/bootboot.h" #include "video/Framebuffer.h" #include #include #include #include extern const BOOTBOOT bootboot; #include "video/BuiltinFont.h" static constexpr u32 BLACK = 0xff000000; static constexpr u32 WHITE = 0xffffffff; static u32 g_background_color = BLACK; static u32 g_foreground_color = WHITE; static constexpr u32 FONT_HEIGHT = 16; static constexpr u32 FONT_WIDTH = 8; static u32 g_x_position = 0; static u32 g_y_position = 0; static void putchar_at(char c, u32 x, u32 y) { const u8* glyph = &font[c * 16]; for (u32 i = 0; i < FONT_HEIGHT; i++) { for (u32 j = 0; j < FONT_WIDTH; j++) { volatile u8 mask = *glyph; if (mask & (0b10000000 >> j)) Framebuffer::pixel(x + j, y + i, g_foreground_color); else Framebuffer::pixel(x + j, y + i, g_background_color); } glyph++; } } static void erase_current_line() { Framebuffer::rect(0, g_y_position, Framebuffer::width(), FONT_HEIGHT, BLACK); } static void scroll() { memcpy(Framebuffer::ptr(), Framebuffer::ptr() + (Framebuffer::scanline() * FONT_HEIGHT), Framebuffer::size() - (Framebuffer::scanline() * FONT_HEIGHT)); g_y_position -= FONT_HEIGHT; erase_current_line(); } static bool should_scroll() { return (g_y_position + FONT_HEIGHT) >= Framebuffer::height(); } static void next_line() { g_x_position = 0; g_y_position += FONT_HEIGHT; } static void next_char() { g_x_position += FONT_WIDTH; } static void prev_char() { g_x_position -= FONT_WIDTH; } static void erase_current_char() { Framebuffer::rect(g_x_position, g_y_position, FONT_WIDTH, FONT_HEIGHT, BLACK); } static bool at_end_of_screen() { return (g_x_position + FONT_WIDTH) > Framebuffer::width(); } namespace TextConsole { void putchar(char c) { switch (c) { case '\n': { next_line(); if (should_scroll()) scroll(); break; } case '\r': g_x_position = 0; break; case '\b': if (g_x_position != 0) { prev_char(); erase_current_char(); } break; default: { putchar_at(c, g_x_position, g_y_position); next_char(); if (at_end_of_screen()) { next_line(); if (should_scroll()) scroll(); } break; } } } void set_foreground(u32 color) { g_foreground_color = color; } void set_background(u32 color) { g_background_color = color; } u32 foreground() { return g_foreground_color; } u32 background() { return g_background_color; } void move_to(u32 x, u32 y) { g_x_position = x; g_y_position = y; } void clear() { move_to(0, 0); Framebuffer::rect(0, 0, Framebuffer::width(), Framebuffer::height(), BLACK); } void print(const char* str) { while (*str) putchar(*str++); } void println(const char* str) { print(str); putchar('\n'); } usize printf(const char* format, ...) { va_list ap; va_start(ap, format); auto rc = cstyle_format( format, [](char c, void*) -> Result { putchar(c); return {}; }, nullptr, ap) .expect_value("Sanity check failed in TextConsole::printf: Should never fail"); va_end(ap); return rc; } }