Added font renderer and terminal emulator

This commit is contained in:
Jozef Nagy 2025-05-15 00:55:59 +02:00
parent bc4ec556e2
commit dd4fda27bb
Signed by untrusted user who does not match committer: crz
GPG key ID: 459A4811CEAC7068
22 changed files with 1921 additions and 5151 deletions

View file

@ -2,6 +2,7 @@
default = 0
timeout = 30
ui = text
[AurixOS]
protocol = aurix

View file

@ -1,5 +0,0 @@
The fonts included in this archive are released under a “no rights reserved” Creative Commons Zero license. Please do not ask permission to do anything with these fonts. Whatever you want to do with this font, the answer will be yes. Please read about the CC0 Public Domain license before contacting me.
https://creativecommons.org/publicdomain/zero/1.0/
To the extent possible under law, Raymond Larabie has waived all copyright and related or neighboring rights to the fonts in this archive. This work is published from: Japan.

Binary file not shown.

Binary file not shown.

View file

@ -42,6 +42,7 @@ char *config_paths[] = {
struct axboot_cfg cfg = {
.default_entry = DEFAULT_ENTRY,
.timeout = DEFAULT_TIMEOUT,
.ui_mode = UI_TEXT,
//.entry_count = 0
.entry_count = 2
@ -103,4 +104,9 @@ int config_get_entry_count()
struct axboot_entry *config_get_entries()
{
return entries;
}
int config_get_ui_mode()
{
return cfg.ui_mode;
}

View file

@ -38,9 +38,9 @@ void axboot_init()
//config_init();
//ui_init();
ui_init();
//debug("axboot_init(): Returned from main menu, something went wrong. Halting!");
debug("axboot_init(): Returned from main menu, something went wrong. Halting!");
//UNREACHABLE();
// just boot aurixos for now

View file

@ -62,10 +62,7 @@ void debug(const char *fmt, ...)
uart_sendstr(buf);
}
void snprintf(char *buf, size_t size, const char *fmt, ...)
void snprintf(char *buf, size_t size, const char *fmt, va_list args)
{
va_list args;
va_start(args, fmt);
npf_vsnprintf(buf, size, fmt, args);
va_end(args);
}
}

View file

@ -17,62 +17,75 @@
/* SOFTWARE. */
/*********************************************************************************/
// TODO: Remove this if statement once I fix stb_truetype compilation
#if 0
#include <mm/mman.h>
#include <arch/lib/math.h>
#include <lib/string.h>
#include <lib/assert.h>
#include <vfs/vfs.h>
#define FONT_IMPLEMENTATION
#include <ui/ui.h>
#include <ui/font.h>
#include <print.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
__attribute__((used)) static volatile int _fltused = 0;
#define STB_TRUETYPE_IMPLEMENTATION
#define STBTT_ifloor(x) _ifloor(x)
#define STBTT_iceil(x) _iceil(x)
#define STBTT_sqrt(x) _sqrt(x)
#define STBTT_pow(x, y) _pow(x, y)
#define STBTT_fmod(x, y) _fmod(x, y)
#define STBTT_cos(x) _cos(x)
#define STBTT_acos(x) _acos(x)
#define STBTT_fabs(x) __builtin_fabs(x)
#define STBTT_malloc(x, u) ((void)(u), mem_alloc(x))
#define STBTT_free(x, u) ((void)(u), mem_free(x))
#define STBTT_assert(x) assert(x, #x)
#define STBTT_strlen(x) strlen(x)
#define STBTT_memcpy memcpy
#define STBTT_memset memset
#include "stb_truetype.h"
unsigned char *font_buf = NULL;
stbtt_fontinfo font_info;
float font_scale;
int font_ascent, font_descent;
int font_linegap;
int font_size;
void font_init(char *font_path, int initial_size)
bool font_init(struct ui_context *ctx, char *font_path, int size)
{
vfs_read(font_path, &font_buf);
vfs_read(font_path, &(ctx->font_file));
if (!ctx->font_file) {
return false;
}
int ssfn_status;
ssfn_status = ssfn_load(&(ctx->font), (void *)(ctx->font_file));
if (ssfn_status != SSFN_OK) {
debug("font_init(): SSFN failed to load font: %s!\n", ssfn_error(ssfn_status));
goto error;
}
ssfn_status = ssfn_select(&(ctx->font), SSFN_FAMILY_ANY, NULL, SSFN_STYLE_REGULAR, size);
if (ssfn_status != SSFN_OK) {
debug("font_init(): SSFN failed to select font: %s!\n", ssfn_error(ssfn_status));
goto error;
}
// initialize terminal
ctx->terminal.font_size = size;
ctx->terminal.cx = 0;
ctx->terminal.cy = size;
return true;
error:
mem_free(ctx->font_file);
return false;
}
void font_write(struct ui_context *ctx, char *s, uint32_t cx, uint32_t cy)
{
ctx->font_buf.x = cx;
ctx->font_buf.y = cy;
ssfn_render(&(ctx->font), &(ctx->font_buf), s);
}
void font_free(struct ui_context *ctx)
{
ssfn_free(&(ctx->font));
mem_free(ctx->font_file);
}
/*
void font_ttf_init(char *font_path, int initial_size)
{
vfs_read(font_path, (char **)&font_buf);
if (!font_buf) {
debug("Font not loaded, returning...\n");
return;
}
font_size = initial_size;
stbtt_InitFont(&font_info, &font_buf, 0);
font_scale = stbtt_ScaleForPixelHeight(&font_info, font_size);
stbtt_GetFontVMetrics(&font_info, &font_ascent, &font_descent, &font_linegap);
font_ascent *= font_scale;
font_descent *= font_scale;
}
#endif
void font_psf2_init()
{
}
*/

File diff suppressed because it is too large Load diff

86
boot/common/ui/terminal.c Normal file
View file

@ -0,0 +1,86 @@
/*********************************************************************************/
/* Module Name: terminal.c */
/* Project: AurixOS */
/* */
/* Copyright (c) 2024-2025 Jozef Nagy */
/* */
/* This source is subject to the MIT License. */
/* See License.txt in the root of this repository. */
/* All other rights reserved. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */
/* SOFTWARE. */
/*********************************************************************************/
#include <ui/ui.h>
#include <ui/terminal.h>
#include <axboot.h>
#include <print.h>
#include <stdarg.h>
#define HORIZONTAL_TAB_WIDTH 8
void terminal_print(struct ui_context *ctx, char *fmt, ...)
{
va_list args;
char buf[4096] = {0};
char *s = (char *)&buf;
va_start(args, fmt);
snprintf((char *)&buf, sizeof(buf), fmt, args);
va_end(args);
while (*s) {
switch (*s) {
case '\t': {
// horizontal tab - 4 spaces
int w, h;
ssfn_bbox(&(ctx->font), " ", &w, &h, NULL, NULL);
if (ctx->terminal.cx >= ctx->fb_modes[ctx->current_mode].width - (w * HORIZONTAL_TAB_WIDTH)) {
for (int i = 1; i <= HORIZONTAL_TAB_WIDTH; i++) {
if (ctx->terminal.cx >= ctx->fb_modes[ctx->current_mode].width - (w * i)) {
ctx->terminal.cx = ((HORIZONTAL_TAB_WIDTH * (w + 1)) - (w * i));
ctx->terminal.cy += h;
break;
}
}
} else {
ctx->terminal.cx += w * HORIZONTAL_TAB_WIDTH;
}
break;
}
case '\n': {
// newline
ctx->terminal.cx = 0;
ctx->terminal.cy += ctx->terminal.font_size;
break;
}
default: {
// printable character
const char str[2] = {*s, 0};
int w, h;
ssfn_bbox(&(ctx->font), (char *)&str, &w, &h, NULL, NULL);
if (ctx->terminal.cx + w >= ctx->fb_modes[ctx->current_mode].width) {
ctx->terminal.cx = 0;
ctx->terminal.cy += h;
}
font_write(ctx, (char *)&str, ctx->terminal.cx, ctx->terminal.cy);
ctx->terminal.cx += w;
break;
}
}
s++;
}
}
void terminal_setcur(struct ui_context *ui, uint32_t x, uint32_t y)
{
ui->terminal.cx = x;
ui->terminal.cy = y;
}

View file

@ -17,40 +17,110 @@
/* SOFTWARE. */
/*********************************************************************************/
#include <config/config.h>
#include <lib/string.h>
#include <ui/framebuffer.h>
#include <ui/mouse.h>
#include <ui/font.h>
#include <ui/ui.h>
#include <config/config.h>
#include <axboot.h>
#include <print.h>
#include <stdint.h>
bool gui_init(struct ui_context *ctx)
{
if (!font_init(ctx, "\\AxBoot\\fonts\\vera\\Vera.sfn", 16)) {
return false;
}
return false;
}
bool tui_init(struct ui_context *ctx)
{
if (!font_init(ctx, "\\AxBoot\\fonts\\u_vga16\\u_vga16.sfn", 16)) {
return false;
}
char *top_string = BOOTLOADER_NAME_STR " ver. " BOOTLOADER_VERSION_STR;
int top_string_w;
ssfn_bbox(&(ctx->font), top_string, &top_string_w, NULL, NULL, NULL);
terminal_setcur(ctx, ctx->fb_modes[ctx->current_mode].width / 2 - (top_string_w / 2), ctx->fb_modes[ctx->current_mode].height / 32);
terminal_print(ctx, top_string);
return true;
}
void gui_draw(void *mouse_status, void *event)
{
(void)mouse_status;
(void)event;
}
void tui_draw(void *mouse_status, void *event)
{
(void)mouse_status;
(void)event;
}
void ui_init()
{
struct ui_context ctx;
struct ui_context ctx = {0};
if (!get_framebuffer(&ctx.fb_addr, &ctx.fb_modes, &ctx.total_modes, &ctx.current_mode)) {
debug("Failed to acquire a framebuffer!\n");
debug("ui_init(): Failed to acquire a framebuffer!\n");
while (1);
}
ctx.ui = config_get_ui_mode();
debug("Dumping framebuffer information\n");
debug("--------------------------------\n");
debug("Address: 0x%llx\n", ctx.fb_addr);
for (int i = 0; i < ctx.total_modes; i++) {
debug("\nMode %u:%s\n", i, (i == ctx.current_mode) ? " (current)" : "");
debug("Resolution: %ux%u\n", ctx.fb_modes[i].width, ctx.fb_modes[i].height);
debug("Bits Per Pixel: %u\n", ctx.fb_modes[i].bpp);
debug("Pitch: %u\n", ctx.fb_modes[i].pitch);
debug("Mode %u:%s | ", i, (i == ctx.current_mode) ? " (current)" : "");
debug("Resolution: %ux%u | ", ctx.fb_modes[i].width, ctx.fb_modes[i].height);
debug("Bits Per Pixel: %u | ", ctx.fb_modes[i].bpp);
debug("Pitch: %u | ", ctx.fb_modes[i].pitch);
debug("Format: %s\n", ctx.fb_modes[i].format == FB_RGBA ? "RGBA" : "BGRA");
}
//font_init("\\AxBoot\\fonts\\DreamOrphans.ttf", 20);
ctx.font_buf.ptr = (uint8_t *)ctx.fb_addr;
ctx.font_buf.w = ctx.fb_modes[ctx.current_mode].width;
ctx.font_buf.h = ctx.fb_modes[ctx.current_mode].height;
ctx.font_buf.p = ctx.fb_modes[ctx.current_mode].pitch;
ctx.font_buf.x = 0;
ctx.font_buf.y = 0;
ctx.font_buf.fg = 0xFFFFFFFF;
//while (1) {
void (*ui_callback)(void*,void*) = NULL;
switch (ctx.ui) {
case UI_MODERN: {
if (!gui_init(&ctx)) {
debug("ui_init(): Failed to initialize modern UI, booting default selection...\n");
break;
}
ui_callback = gui_draw;
break;
}
default:
case UI_TEXT: {
if (!tui_init(&ctx)) {
debug("ui_init(): Failed to initialize text UI, booting default selection...\n");
break;
}
ui_callback = tui_draw;
break;
}
}
while (1) {
ui_callback(NULL, NULL);
//get_mouse(&m_x, &m_y, &m_but);
//debug("Mouse X = %u | Mouse Y = %u\n", m_x, m_y);
//}
}
}

View file

@ -20,10 +20,16 @@
#ifndef _CONFIG_CONFIG_H
#define _CONFIG_CONFIG_H
enum {
UI_TEXT = 0,
UI_MODERN = 1
};
struct axboot_cfg {
// overridable stuff
int default_entry;
int timeout;
int ui_mode;
int entry_count;
};
@ -37,6 +43,10 @@ struct axboot_entry {
void config_init(void);
int config_get_timeout();
int config_get_default();
int config_get_entry_count();
struct axboot_entry *config_get_entries();
int config_get_ui_mode();
#endif /* _CONFIG_CONFIG_H */

View file

@ -30,6 +30,6 @@ void debug(const char *fmt, ...);
void printstr(const char *str);
void snprintf(char *buf, size_t size, const char *fmt, ...);
void snprintf(char *buf, size_t size, const char *fmt, va_list args);
#endif /* _PRINT_H */

View file

@ -20,6 +20,14 @@
#ifndef _UI_FONT_H
#define _UI_FONT_H
void font_init(char *font_path, int initial_size);
#include <stdbool.h>
#include <stdint.h>
struct ui_context;
bool font_init(struct ui_context *ctx, char *font_path, int size);
void font_free(struct ui_context *ctx);
void font_write(struct ui_context *ctx, char *s, uint32_t cx, uint32_t cy);
#endif /* _UI_FONT_H */

1604
boot/include/ui/ssfn.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,37 @@
/*********************************************************************************/
/* Module Name: terminal.h */
/* Project: AurixOS */
/* */
/* Copyright (c) 2024-2025 Jozef Nagy */
/* */
/* This source is subject to the MIT License. */
/* See License.txt in the root of this repository. */
/* All other rights reserved. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */
/* SOFTWARE. */
/*********************************************************************************/
#ifndef _UI_TERMINAL_H
#define _UI_TERMINAL_H
#include <stdint.h>
struct terminal {
uint32_t cx;
uint32_t cy;
int font_size;
};
struct ui_context;
void terminal_print(struct ui_context *ctx, char *fmt, ...);
void terminal_setcur(struct ui_context *ui, uint32_t x, uint32_t y);
#endif /* _UI_TERMINAL_H */

View file

@ -21,6 +21,21 @@
#define _UI_UI_H
#include <ui/framebuffer.h>
#include <ui/terminal.h>
#include <ui/font.h>
// this is so hacky... but it works
#ifdef FONT_IMPLEMENTATION
#include <lib/string.h>
#include <mm/mman.h>
#define SSFN_memcmp memcmp
#define SSFN_memset memset
#define SSFN_realloc mem_realloc
#define SSFN_free mem_free
#define SSFN_IMPLEMENTATION
#endif
#include <ui/ssfn.h>
#include <stdint.h>
@ -29,6 +44,13 @@ struct ui_context {
struct fb_mode *fb_modes;
int total_modes;
int current_mode;
int ui;
struct terminal terminal;
ssfn_t font;
ssfn_buf_t font_buf;
char *font_file;
};
void ui_init();

View file

@ -57,7 +57,7 @@ EFI_STATUS uefi_entry(EFI_HANDLE ImageHandle,
// disable UEFI watchdog
Status = gSystemTable->BootServices->SetWatchdogTimer(0, 0, 0, NULL);
if (EFI_ERROR(Status)) {
debug("Couldn't disable UEFI watchdog: %s (%x)\n", efi_status_to_str(Status), Status);
debug("uefi_entry(): Couldn't disable UEFI watchdog: %s (%x)\n", efi_status_to_str(Status), Status);
}
// load that mouse up
@ -75,7 +75,7 @@ EFI_STATUS uefi_entry(EFI_HANDLE ImageHandle,
continue;
}
debug("Found SPP with ResX=%u, ResY=%u\n", spp[i]->Mode->ResolutionX, spp[i]->Mode->ResolutionY);
debug("uefi_entry(): Found SPP with ResX=%u, ResY=%u\n", spp[i]->Mode->ResolutionX, spp[i]->Mode->ResolutionY);
if (spp[i]->Reset(spp[i], EFI_TRUE) == EFI_DEVICE_ERROR) {
debug("uefi_entry(): Failed to reset device\n");
continue;