Files
nt-lite/code/hal/hal_screen.c
T

165 lines
5.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// hal_screen.c - GOP framebuffer screen driver with embedded 8x16 font
//
// The 8x16 bitmap font is a standard VGA/PC font. We embed just the
// printable ASCII range (0x20–0x7E). Each glyph is 16 bytes; bit 7 of
// each byte is the leftmost pixel.
#include "hal_api.h"
#include <stdint.h>
#include <string.h>
#include <intrin.h>
static uint32_t* gFb = (uint32_t *)0;
static int gWidth = 0;
static int gHeight = 0;
static int gStride = 0; // pixels per row
static int gCursorX = 0, gCursorY = 0;
#define FONT_W 8
#define FONT_H 16
// ---------------------------------------------------------------------------
// 8x16 VGA font - printable ASCII only (glyph 0 = space = 0x20)
// ---------------------------------------------------------------------------
#include "font8x16.h" // see font8x16.h below
// ---------------------------------------------------------------------------
// Internals
// ---------------------------------------------------------------------------
static inline void PutPixelRaw(int x, int y, uint32_t color) {
if ((unsigned)x < (unsigned)gWidth && (unsigned)y < (unsigned)gHeight)
gFb[y * gStride + x] = color;
}
// ---------------------------------------------------------------------------
// HAL_SCREEN implementations
// ---------------------------------------------------------------------------
static void ScreenClear(uint32_t color) {
for (int y = 0; y < gHeight; y++)
for (int x = 0; x < gWidth; x++)
gFb[y * gStride + x] = color;
gCursorX = 0; gCursorY = 0;
}
static void ScreenPutPixel(int x, int y, uint32_t color) {
PutPixelRaw(x, y, color);
}
static void ScreenBlit(int x, int y, int w, int h, const uint32_t* pixels) {
// Calculate clipping bounds
int startX = (x < 0) ? 0 : x;
int startY = (y < 0) ? 0 : y;
int endX = (x + w > gWidth) ? gWidth : (x + w);
int endY = (y + h > gHeight) ? gHeight : (y + h);
int drawW = endX - startX;
int drawH = endY - startY;
// If the image is entirely off-screen, do nothing
if (drawW <= 0 || drawH <= 0) {
return;
}
// Adjust the source pointer if the image was clipped on the top or left
int srcOffsetX = startX - x;
int srcOffsetY = startY - y;
// Calculate bytes to copy per row
size_t bytesPerRow = (size_t)drawW * sizeof(uint32_t);
// If the width we are drawing exactly matches the physical screen stride,
// AND it matches the original source image width, memory is perfectly contiguous.
if (drawW == gStride && drawW == w) {
uint32_t* dst = gFb + (startY * gStride) + startX;
const uint32_t* src = pixels + (srcOffsetY * w) + srcOffsetX;
memcpy(dst, src, bytesPerRow * drawH);
return;
}
// Copy row-by-row
for (int row = 0; row < drawH; row++) {
// Destination in the actual framebuffer (accounting for stride)
uint32_t* dst = gFb + ((startY + row) * gStride) + startX;
// Source from the provided pixel buffer
const uint32_t* src = pixels + ((srcOffsetY + row) * w) + srcOffsetX;
memcpy(dst, src, bytesPerRow);
}
}
static void ScreenGetSize(int* w, int* h) { *w = gWidth; *h = gHeight; }
static void ScreenScroll(int lines) {
if (lines <= 0 || lines >= gHeight) { ScreenClear(0); return; }
int rowBytes = gStride * sizeof(uint32_t);
memmove(gFb, gFb + lines * gStride,
(size_t)(gHeight - lines) * rowBytes);
// Clear the revealed rows at the bottom.
memset(gFb + (gHeight - lines) * gStride, 0,
(size_t)lines * rowBytes);
}
static void ScreenPutChar(char c, int x, int y, uint32_t fg, uint32_t bg) {
if ((unsigned char)c < 0x20 || (unsigned char)c > 0x7E) c = '?';
const uint8_t* glyph = Font8x16 + ((unsigned char)c - 0x20) * 16;
for (int row = 0; row < 16; row++) {
uint8_t bits = glyph[row];
for (int col = 0; col < 8; col++) {
uint32_t color = (bits & (1 << col)) ? fg : bg; // i don't know why, i don't want to know why
// i shouldn't have to wonder why but the font is backwards unless we do this terriblness
PutPixelRaw(x + col, y + row, color);
}
}
}
static void ScreenPrintChar(char c, uint32_t fg, uint32_t bg) {
int cols = gWidth / FONT_W;
int rows = gHeight / FONT_H;
// Mirror to serial
while ((__inbyte(0x3FD) & 0x20) == 0);
if (c == '\n') __outbyte(0x3F8, '\r');
__outbyte(0x3F8, c);
if (c == '\n') {
gCursorX = 0;
gCursorY++;
} else if (c == '\r') {
gCursorX = 0;
} else if (c == '\b') {
if (gCursorX > 0) {
gCursorX--;
} else if (gCursorY > 0) {
gCursorY--;
gCursorX = cols - 1;
}
} else {
ScreenPutChar(c, gCursorX * FONT_W, gCursorY * FONT_H, fg, bg);
if (++gCursorX >= cols) { gCursorX = 0; gCursorY++; }
}
if (gCursorY >= rows) {
ScreenScroll(FONT_H);
gCursorY = rows - 1;
}
}
// ---------------------------------------------------------------------------
// Populate the HAL_SCREEN vtable
// ---------------------------------------------------------------------------
void HalScreenInitialize(uintptr_t fb, int w, int h, int stride,
HAL_SCREEN* out) {
gFb = (uint32_t *)fb;
gWidth = w;
gHeight = h;
gStride = stride;
out->Clear = ScreenClear;
out->PutPixel = ScreenPutPixel;
out->Blit = ScreenBlit;
out->GetSize = ScreenGetSize;
out->Scroll = ScreenScroll;
out->PutChar = ScreenPutChar;
out->PrintChar = ScreenPrintChar;
ScreenClear(0x000000);
}