152 lines
3.0 KiB
C
152 lines
3.0 KiB
C
// Terminal output
|
|
/*
|
|
There are a couple of bugs here and there but for now I don't care too much
|
|
because this shitty implementation will be replaced one day by Flanterm
|
|
(once memory management is okay: paging & kernel malloc)
|
|
*/
|
|
|
|
#include <limine.h>
|
|
#include <stddef.h>
|
|
#include <kernel.h>
|
|
#include "term.h"
|
|
|
|
extern struct boot_context boot_ctx;
|
|
|
|
// Importing the PSF object file
|
|
extern unsigned char _binary_zap_light16_psf_start[];
|
|
extern unsigned char _binary_zap_light16_psf_end[];
|
|
|
|
PSF1_Header* font = (PSF1_Header*)_binary_zap_light16_psf_start;
|
|
uint8_t* glyphs = _binary_zap_light16_psf_start + sizeof(PSF1_Header);
|
|
|
|
#define FONT_WIDTH 8
|
|
#define FONT_HEIGHT font->characterSize
|
|
|
|
// Character cursor
|
|
typedef struct
|
|
{
|
|
unsigned int x;
|
|
unsigned int y;
|
|
} Cursor;
|
|
|
|
Cursor cursor = {0};
|
|
|
|
unsigned char* fb;
|
|
|
|
struct limine_framebuffer* framebuffer;
|
|
|
|
int term_init()
|
|
{
|
|
// Get framebuffer address from Limine struct
|
|
|
|
if (boot_ctx.fb)
|
|
{
|
|
fb = boot_ctx.fb->address;
|
|
framebuffer = boot_ctx.fb;
|
|
DEBUG("terminal initialized");
|
|
return 0;
|
|
}
|
|
return -ENOMEM;
|
|
}
|
|
|
|
// These are marked "static" because we don't wanna expose them all around
|
|
// AKA they should just be seen here (kind of like private functions in cpp)
|
|
static void putpixel(int x, int y, int color)
|
|
{
|
|
// Depth isn't part of limine_framebuffer attributes so it will be 4
|
|
unsigned pos = x*4 + y*framebuffer->pitch;
|
|
fb[pos] = color & 255; // blue channel
|
|
fb[pos+1] = (color >> 8) & 255; // green
|
|
fb[pos+2] = (color >> 16) & 255; // blue
|
|
}
|
|
|
|
static void draw_char(char c, int px, int py, int fg, int bg)
|
|
{
|
|
uint8_t* glyph = glyphs + ((unsigned char)c * FONT_HEIGHT);
|
|
|
|
for (size_t y=0; y<FONT_HEIGHT; y++)
|
|
{
|
|
uint8_t row = glyph[y];
|
|
for (size_t x=0; x<8; x++)
|
|
{
|
|
int color = (row & (0x80 >> x)) ? fg : bg;
|
|
putpixel(px+x, py+y, color);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void erase_char(int px, int py)
|
|
{
|
|
for (size_t y=0; y<FONT_HEIGHT; y++)
|
|
{
|
|
for (size_t x=0; x<8; x++)
|
|
{
|
|
// Black
|
|
putpixel(px+x, py+y, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void putchar(char c)
|
|
{
|
|
if (c == '\n')
|
|
{
|
|
cursor.x = 0;
|
|
cursor.y++;
|
|
return;
|
|
}
|
|
|
|
// TODO: Improperly handled.
|
|
// When we're on an empty line it should get to the upper line's last character
|
|
// NOT just the last position possible; we would need to track the last line's character amount for that
|
|
if (c == '\b')
|
|
{
|
|
if (cursor.x == 0 && cursor.y == 0)
|
|
{
|
|
// Top-left corner
|
|
return;
|
|
}
|
|
|
|
if (cursor.x == 0)
|
|
{
|
|
cursor.y--;
|
|
cursor.x = (framebuffer->width / FONT_WIDTH) -1; // here
|
|
}
|
|
else {
|
|
cursor.x--;
|
|
}
|
|
|
|
int px = cursor.x * FONT_WIDTH;
|
|
int py = cursor.y * FONT_HEIGHT;
|
|
erase_char(px, py);
|
|
return;
|
|
}
|
|
|
|
if ((cursor.x+1)*FONT_WIDTH >= framebuffer->width)
|
|
{
|
|
cursor.x = 0;
|
|
cursor.y++;
|
|
}
|
|
|
|
int px = cursor.x * FONT_WIDTH;
|
|
int py = cursor.y * FONT_HEIGHT;
|
|
draw_char(c, px, py, WHITE, BLACK);
|
|
cursor.x++;
|
|
}
|
|
|
|
// Overhead that could be avoided, right? (for printf)
|
|
void _putchar(char character)
|
|
{
|
|
putchar(character);
|
|
}
|
|
|
|
// Debug-printing
|
|
void kputs(const char* str)
|
|
{
|
|
unsigned int i=0;
|
|
while (str[i] != 0)
|
|
{
|
|
putchar(str[i]);
|
|
i++;
|
|
}
|
|
} |