2022-11-20 16:55:22 +00:00
|
|
|
#include "video/TextConsole.h"
|
|
|
|
#include "boot/bootboot.h"
|
|
|
|
#include "video/Framebuffer.h"
|
2022-12-16 19:40:04 +00:00
|
|
|
#include <luna/CString.h>
|
2022-12-04 11:42:43 +00:00
|
|
|
#include <luna/Format.h>
|
2022-12-07 10:40:02 +00:00
|
|
|
#include <luna/Result.h>
|
2022-12-21 16:38:19 +00:00
|
|
|
#include <luna/ScopeGuard.h>
|
2022-12-18 12:09:37 +00:00
|
|
|
#include <luna/Utf8.h>
|
2022-12-07 10:40:02 +00:00
|
|
|
#include <stdarg.h>
|
2022-11-20 16:55:22 +00:00
|
|
|
|
2022-12-05 12:04:01 +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;
|
|
|
|
|
2022-12-18 13:42:53 +00:00
|
|
|
static Utf8StateDecoder utf8_decoder;
|
2022-12-18 12:09:37 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2022-12-18 12:09:37 +00:00
|
|
|
void putwchar(wchar_t c)
|
2022-11-20 16:55:22 +00:00
|
|
|
{
|
2022-12-18 12:09:37 +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)
|
|
|
|
{
|
2022-12-18 12:09:37 +00:00
|
|
|
case L'\n': {
|
2022-11-20 16:55:22 +00:00
|
|
|
next_line();
|
|
|
|
if (should_scroll()) scroll();
|
|
|
|
break;
|
|
|
|
}
|
2022-12-18 12:09:37 +00:00
|
|
|
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: {
|
2022-12-18 12:09:37 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-21 16:38:19 +00:00
|
|
|
Result<void> putchar(char c)
|
2022-12-18 12:09:37 +00:00
|
|
|
{
|
2022-12-21 16:38:19 +00:00
|
|
|
auto guard = make_scope_guard([] { utf8_decoder.reset(); });
|
|
|
|
|
2023-01-10 18:31:41 +00:00
|
|
|
const Option<wchar_t> maybe_wchar = TRY(utf8_decoder.feed(c));
|
2022-12-21 16:38:19 +00:00
|
|
|
|
|
|
|
guard.deactivate();
|
2022-12-18 12:09:37 +00:00
|
|
|
|
|
|
|
if (maybe_wchar.has_value()) putwchar(maybe_wchar.value());
|
2022-12-21 16:38:19 +00:00
|
|
|
|
|
|
|
return {};
|
2022-12-18 12:09:37 +00:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-12-21 16:38:19 +00:00
|
|
|
Result<void> print(const char* str)
|
2022-11-20 16:55:22 +00:00
|
|
|
{
|
2022-12-21 16:38:19 +00:00
|
|
|
while (*str) TRY(putchar(*str++));
|
|
|
|
return {};
|
2022-11-20 16:55:22 +00:00
|
|
|
}
|
|
|
|
|
2023-03-18 19:09:10 +00:00
|
|
|
Result<void> write(const char* str, usize len)
|
|
|
|
{
|
|
|
|
while (len--) TRY(putchar(*str++));
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-12-21 18:41:13 +00:00
|
|
|
void wprint(const wchar_t* str)
|
|
|
|
{
|
|
|
|
while (*str) putwchar(*str++);
|
|
|
|
}
|
|
|
|
|
2022-12-21 16:38:19 +00:00
|
|
|
Result<void> println(const char* str)
|
2022-11-20 16:55:22 +00:00
|
|
|
{
|
2022-12-21 16:38:19 +00:00
|
|
|
TRY(print(str));
|
|
|
|
putwchar(L'\n');
|
|
|
|
return {};
|
2022-11-20 16:55:22 +00:00
|
|
|
}
|
|
|
|
|
2022-12-21 18:41:13 +00:00
|
|
|
void wprintln(const wchar_t* str)
|
|
|
|
{
|
|
|
|
wprint(str);
|
|
|
|
putwchar(L'\n');
|
|
|
|
}
|
|
|
|
|
2022-12-21 16:38:19 +00:00
|
|
|
Result<usize> printf(const char* format, ...)
|
2022-11-20 16:55:22 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
2023-01-10 18:31:41 +00:00
|
|
|
const usize rc = TRY(cstyle_format(
|
2022-12-21 16:38:19 +00:00
|
|
|
format, [](char c, void*) -> Result<void> { return putchar(c); }, nullptr, ap));
|
2022-11-20 16:55:22 +00:00
|
|
|
va_end(ap);
|
|
|
|
return rc;
|
|
|
|
}
|
2023-01-02 12:07:29 +00:00
|
|
|
}
|