-
Notifications
You must be signed in to change notification settings - Fork 9
Add BIOS font support #169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
;; Stack probe helper | ||
;; Probes each page from rsp down to r11 to ensure the guard page is touched | ||
;; Input: | ||
;; r11 - lowest address of the allocated stack frame ([InitialSp - FrameSize]) | ||
;; rsp - some byte on the last probed page | ||
;; Output: | ||
;; rax - scratch (not preserved) | ||
;; r11 - preserved | ||
;; Notes: | ||
;; Probes at least one page below rsp. | ||
global RhpStackProbe | ||
section .text | ||
|
||
|
||
PROBE_STEP equ 0x1000 | ||
|
||
RhpStackProbe: | ||
; Align rax to the start of the current page | ||
mov rax, rsp | ||
and rax, -PROBE_STEP ; rax = lowest address on the last probed page | ||
|
||
ProbeLoop: | ||
sub rax, PROBE_STEP ; move to the next page to probe | ||
test dword [rax], eax ; touch the page | ||
cmp rax, r11 | ||
jg ProbeLoop ; continue if still above r11 | ||
|
||
ret |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,8 @@ public unsafe class Canvas | |
public static uint Height; | ||
public static uint Pitch; | ||
|
||
public static FontFormat DefaultFont = new BIOSFont(); | ||
|
||
public static void DrawPixel(uint color, int x, int y) | ||
{ | ||
if (x >= 0 && x < Width && y >= 0 && y < Height) | ||
|
@@ -83,16 +85,69 @@ public static void ClearScreen(uint color) | |
|
||
public static void DrawChar(char c, int x, int y, uint color) | ||
{ | ||
PCScreenFont.PutChar(c, x, y, color, Color.Transparent); | ||
DefaultFont.PutChar(c, x, y, color, Color.Transparent); | ||
} | ||
|
||
public static void DrawString(string text, int x, int y, uint color) | ||
{ | ||
PCScreenFont.PutString(text, x, y, color, Color.Transparent); | ||
DefaultFont.PutString(text, x, y, color, Color.Transparent); | ||
} | ||
|
||
public static unsafe void DrawString(char* text, int x, int y, uint color) | ||
{ | ||
PCScreenFont.PutString(text, x, y, color, Color.Transparent); | ||
DefaultFont.PutString(text, x, y, color, Color.Transparent); | ||
} | ||
|
||
public static unsafe void DrawQuadraticBezier(uint color, int x0, int y0, int x1, int y1, int x2, int y2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we sure we want to do this in kernel mode...? Why would we need Bezier curve drawing in the kernel? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was a sanity check to make sure floats weren't being wacky, I forgot to remove it |
||
{ | ||
//Smooth line, so first calculate the distance between the start and end points to determine the number of steps | ||
int dx = x2 - x0; | ||
int dy = y2 - y0; | ||
int distance = Math.Sqrt((int)(dx * dx + dy * dy)); | ||
int steps = distance * 2; // More steps for smoother curve | ||
for (int i = 0; i <= steps; i++) | ||
{ | ||
float t = (float)i / steps; | ||
float u = 1 - t; | ||
int x = (int)(u * u * x0 + 2 * u * t * x1 + t * t * x2); | ||
int y = (int)(u * u * y0 + 2 * u * t * y1 + t * t * y2); | ||
DrawPixel(color, x, y); | ||
} | ||
} | ||
|
||
public static unsafe void DrawQuadraticBezierAA(uint color, int x0, int y0, int x1, int y1, int x2, int y2) | ||
{ | ||
// First, calculate the distance between the start and end points to determine the number of steps, then each nearby pixel is drawn with an intensity based on its distance to the ideal curve | ||
int dx = x2 - x0; | ||
int dy = y2 - y0; | ||
int distance = Math.Sqrt((int)(dx * dx + dy * dy)); | ||
int steps = distance * 2; // More steps for smoother curve | ||
for (int i = 0; i <= steps; i++) | ||
{ | ||
float t = (float)i / steps; | ||
float u = 1 - t; | ||
int x = (int)(u * u * x0 + 2 * u * t * x1 + t * t * x2); | ||
int y = (int)(u * u * y0 + 2 * u * t * y1 + t * t * y2); | ||
|
||
// Draw the pixel with anti-aliasing | ||
for (int offsetX = -1; offsetX <= 1; offsetX++) | ||
{ | ||
for (int offsetY = -1; offsetY <= 1; offsetY++) | ||
{ | ||
int px = x + offsetX; | ||
int py = y + offsetY; | ||
if (px >= 0 && px < Width && py >= 0 && py < Height) | ||
{ | ||
float distanceToCurve = Math.Sqrt(offsetX * offsetX + offsetY * offsetY); | ||
if (distanceToCurve <= 1.5f) // Adjust the threshold for anti-aliasing effect | ||
{ | ||
float intensity = 1.5f - distanceToCurve; // Closer pixels are more intense | ||
uint blendedColor = Color.Blend(color, Address[py * (int)(Pitch / 4) + px], intensity); | ||
DrawPixel(blendedColor, px, py); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
using Cosmos.Kernel.Core.Memory; | ||
using Cosmos.Kernel.System.Conversion; | ||
|
||
namespace Cosmos.Kernel.System.Graphics.Fonts; | ||
|
||
public unsafe class BIOSFont : FontFormat | ||
{ | ||
public static class Default | ||
{ | ||
public static int Size = 4096; // Bytes array | ||
|
||
public static char* GetUnmanagedFontData() | ||
{ | ||
// 8x16 BIOS font | ||
string VGA816 = "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AAB4zMzM2MzGxsbMAAAAAAAA/sbGwMDAwMDAwAAAAAAAAAAA/mxsbGxsbGwAAAAAAAAA/sZgMBgwYMb+AAAAAAAAAAAAftjY2NjYcAAAAAAAAAAAZmZmZmZ8YGDAAAAAAAAAAHbcGBgYGBgYAAAAAAAAAH4YPGZmZjwYfgAAAAAAAAA4bMbG/sbGbDgAAAAAAAA4bMbGxmxsbGzuAAAAAAAAHjAYDD5mZmZmPAAAAAAAAAAAAH7b29t+AAAAAAAAAAAAAwZ+29vzfmDAAAAAAAAAHDBgYHxgYGAwHAAAAAAAAAB8xsbGxsbGxsYAAAAAAAAAAP4AAP4AAP4AAAAAAAAAAAAYGH4YGAAA/wAAAAAAAAAwGAwGDBgwAH4AAAAAAAAADBgwYDAYDAB+AAAAAAAADhsbGBgYGBgYGBgYGBgYGBgYGBgYGNjY2HAAAAAAAAAAABgYAH4AGBgAAAAAAAAAAAAAdtwAdtwAAAAAAAAAOGxsOAAAAAAAAAAAAAAAAAAAAAAAABgYAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAADwwMDAwM7GxsPBwAAAAAANhsbGxsbAAAAAAAAAAAAABw2DBgyPgAAAAAAAAAAAAAAAAAfHx8fHx8fAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should include fonts out-of-the-box. This is fine if temporary, but ideally we'd remove this in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's so we can have some form of display text output that isn't serial |
||
fixed (char* ptr = VGA816) | ||
{ | ||
return ptr; | ||
} | ||
} | ||
} | ||
|
||
public static uint* Framebuffer; | ||
private static bool _Initialized; | ||
|
||
private static uint Pitch; | ||
private static byte* FontData; | ||
|
||
public override int CharWidth => 8; | ||
|
||
public override int CharHeight => 16; | ||
|
||
private static void EnsureInitialized() | ||
{ | ||
if (!_Initialized) | ||
{ | ||
byte* fontData = Base64.Decode(Default.GetUnmanagedFontData(), (uint)Default.Size); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be able to use a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fonts were made awhile before we could, and base64 works for now so.. 🤷♂️ I never bothered changing it since it worked, but if you think readonlyspan works, be my guest! |
||
Init(Graphics.Canvas.Address, Graphics.Canvas.Pitch, fontData); | ||
_Initialized = true; | ||
} | ||
} | ||
|
||
public static void Init(uint* framebuffer, uint pitch, byte* fontData) | ||
{ | ||
Framebuffer = framebuffer; | ||
Pitch = pitch; | ||
FontData = fontData; | ||
} | ||
|
||
public override void PutChar(char c, int x, int y, uint fgcolor, uint bgcolor) | ||
{ | ||
EnsureInitialized(); | ||
|
||
// Since this is a BIOS font, each bit represents a pixel (1 = on, 0 = off) | ||
if (c < 0 || c > 127) | ||
{ | ||
c = '?'; // Replace unsupported characters with '?' | ||
} | ||
|
||
// If bgcolor is Transparent, we skip drawing background pixels | ||
bool drawBackground = bgcolor != Color.Transparent; | ||
byte* charData = FontData + (c * CharHeight); | ||
for (int row = 0; row < CharHeight; row++) | ||
{ | ||
byte rowData = charData[row]; | ||
for (int col = 0; col < CharWidth; col++) | ||
{ | ||
bool pixelOn = (rowData & (1 << (7 - col))) != 0; | ||
int fbX = x + col; | ||
int fbY = y + row; | ||
if (fbX < 0 || fbX >= Graphics.Canvas.Width || fbY < 0 || fbY >= Graphics.Canvas.Height) | ||
{ | ||
continue; // Skip pixels outside the framebuffer bounds | ||
} | ||
uint* pixelAddress = (uint*)((byte*)Framebuffer + (fbY * Pitch) + (fbX * 4)); | ||
if (pixelOn) | ||
{ | ||
*pixelAddress = fgcolor; | ||
} | ||
else if (drawBackground) | ||
{ | ||
*pixelAddress = bgcolor; | ||
} | ||
} | ||
} | ||
} | ||
|
||
public override void PutString(string str, int x, int y, uint fgcolor, uint bgcolor) | ||
{ | ||
EnsureInitialized(); | ||
|
||
for (int i = 0; i < str.Length; i++) | ||
{ | ||
PutChar(str[i], x + (i * CharWidth), y, fgcolor, bgcolor); | ||
} | ||
} | ||
|
||
public override unsafe void PutString(char* str, int x, int y, uint fgcolor, uint bgcolor) | ||
{ | ||
EnsureInitialized(); | ||
|
||
int i = 0; | ||
while (str[i] != '\0') | ||
{ | ||
PutChar(str[i], x + (i * CharWidth), y, fgcolor, bgcolor); | ||
i++; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace Cosmos.Kernel.System.Graphics.Fonts; | ||
|
||
public abstract class FontFormat | ||
{ | ||
public abstract int CharWidth { get; } | ||
public abstract int CharHeight { get; } | ||
public abstract void PutChar(char c, int x, int y, uint fgcolor, uint bgcolor); | ||
public abstract void PutString(string str, int x, int y, uint fgcolor, uint bgcolor); | ||
public abstract unsafe void PutString(char* str, int x, int y, uint fgcolor, uint bgcolor); | ||
public virtual void PutScaledChar(char c, int x, int y, uint fgcolor, uint bgcolor, int scale) {} | ||
public virtual void PutScaledString(string str, int x, int y, uint fgcolor, uint bgcolor, int scale) | ||
{ | ||
for (int i = 0; i < str.Length; i++) | ||
{ | ||
PutScaledChar(str[i], x, y, fgcolor, bgcolor, scale); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a no-op in kernel-mode!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know that raghhhhh I was just getting an error