Luna/kernel/src/video/TextConsole.cpp

189 lines
4.0 KiB
C++
Raw Normal View History

2022-11-20 16:55:22 +00:00
#include "video/TextConsole.h"
#include "boot/bootboot.h"
#include "video/Framebuffer.h"
#include <luna/CString.h>
#include <luna/Format.h>
2022-12-07 10:40:02 +00:00
#include <luna/Result.h>
#include <luna/Utf8.h>
2022-12-07 10:40:02 +00:00
#include <stdarg.h>
2022-11-20 16:55:22 +00:00
extern const BOOTBOOT bootboot;
2022-11-20 16:55:22 +00:00
#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 Utf8StateDecoder decoder;
static void putwchar_at(wchar_t c, u32 x, u32 y)
2022-11-20 16:55:22 +00:00
{
2022-12-05 12:06:12 +00:00
const u8* glyph = &font[c * 16];
2022-11-20 16:55:22 +00:00
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 putwchar(wchar_t c)
2022-11-20 16:55:22 +00:00
{
// Unprintable (not in the built-in font) characters get represented as a box
if (c > (wchar_t)255) c = (wchar_t)256;
2022-11-20 16:55:22 +00:00
switch (c)
{
case L'\n': {
2022-11-20 16:55:22 +00:00
next_line();
if (should_scroll()) scroll();
break;
}
case L'\r': g_x_position = 0; break;
case L'\b':
2022-11-20 16:55:22 +00:00
if (g_x_position != 0)
{
prev_char();
erase_current_char();
}
break;
default: {
putwchar_at(c, g_x_position, g_y_position);
2022-11-20 16:55:22 +00:00
next_char();
if (at_end_of_screen())
{
next_line();
if (should_scroll()) scroll();
}
break;
}
}
}
// FIXME: Should this function propagate errors?
void putchar(char c)
{
auto rc = decoder.feed(c);
if (rc.has_error())
{
decoder.reset();
return;
}
auto maybe_wchar = rc.value();
if (maybe_wchar.has_value()) putwchar(maybe_wchar.value());
}
2022-11-20 16:55:22 +00:00
void set_foreground(u32 color)
{
g_foreground_color = color;
}
void set_background(u32 color)
{
g_background_color = color;
}
2022-11-30 12:29:28 +00:00
u32 foreground()
{
return g_foreground_color;
}
u32 background()
{
return g_background_color;
}
2022-11-20 16:55:22 +00:00
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, ...)
2022-11-20 16:55:22 +00:00
{
va_list ap;
va_start(ap, format);
auto rc = pure_cstyle_format(
format, [](char c, void*) { putchar(c); }, nullptr, ap);
2022-11-20 16:55:22 +00:00
va_end(ap);
return rc;
}
}