Sync/kernel/graphics.c

219 lines
8.6 KiB
C
Raw Normal View History

/************************
*** Team Kitty, 2019 ***
*** Sync ***
***********************/
/* ==================== Kernel Graphics ==================== */
// This file allows the kernel to draw to the framebuffer provided by Syncboot.
// It provides the setup, printing and drawing functions.
// Eventually this will be split up into printing and drawing to provide room for expansion.
// I'm thinking about making a 3D interface.
#include <kernel.h>
//#include <bitfont.h>
// Get it? Default Font
// Defaunt
// Defont
#define DEFONT bitfont_latin
void SetupPrinting(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU) {
Print_Info.defaultGPU = GPU;
Print_Info.charHeight = 8;
Print_Info.charWidth = 8;
Print_Info.charFGColor = 0x00FFFFFF;
Print_Info.charBGColor = 0x00000000;
Print_Info.charHLColor = 0x00000000;
// per UEFI Spec 2.7 Errata A, (0,0) is always the top left in-bounds pixel.
Print_Info.screenMinX = 0;
Print_Info.screenMinY = 0;
Print_Info.charScale = 1;
Print_Info.cursorPos = 0;
Print_Info.scrollMode = 0;
}
void WriteScaledFormatString(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU,
uint32_t Height,
uint32_t Width,
uint32_t FontColor,
uint32_t HighlightColor,
uint32_t x,
uint32_t y,
uint32_t Scale,
const char* String,
...) {
if(Height > GPU.Info->VerticalResolution || Width > GPU.Info->HorizontalResolution) {
// Turn the screen red.
// TODO: Write a function to turn the *borders* of the screen a certain color.
FillScreen(GPU, 0x00FF00000);
} else if (y > GPU.Info->VerticalResolution || x > GPU.Info->HorizontalResolution) {
// Turn the screen green.
FillScreen(GPU, 0x0000FF00);
} else if ((y + Scale * Height) > GPU.Info->VerticalResolution || (x + Scale * Width) > GPU.Info->HorizontalResolution) {
// Turn the screen blue.
FillScreen(GPU, 0x000000FF);
}
// Take the ... arguments into a buffer and pass them to a reasonable function.
va_list Args;
va_start(Args, String);
char Output[128] = {0};
vsprintf(Output, String, Args);
va_end(Args);
WriteScaledString(GPU, Output, Height, Width, FontColor, HighlightColor, x, y, Scale);
}
void ResetScreen() {
Print_Info.screenMinX = 0;
Print_Info.screenMinY = 0;
Print_Info.cursorPos = 0;
ClearScreen(Print_Info.defaultGPU);
}
void ResetFillScreen() {
ResetScreen();
FillScreen(Print_Info.defaultGPU, Print_Info.charBGColor);
}
void ClearScreen(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU) {
FillScreen(GPU, 0x00000000);
}
void FillScreen(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU, uint32_t Color) {
Print_Info.charBGColor = Color;
// The fastest way to do this is using AVX fills.
// However, if AVX isn't supported, we'll need to fall back to filling the screen the old fashioned way.
// The performance benefit by using AVX Parallel operations is huge.
memsetAVX_By4Bytes( (EFI_PHYSICAL_ADDRESS* )GPU.FrameBufferBase, Color, GPU.Info->VerticalResolution * GPU.Info->PixelsPerScanline);
// If AVX isn't supported, we can use this instead:
/*
for(size_t Row = 0; Row < GPU.Info->VerticalResolution; Row++) {
for(size_t Column = 0; Column < GPU.Info->PixelsPerScanline - (GPU.Info->PixelsPerScanline - GPU.Info->HorizontalResolution); Column++) {
*(uint32_t *)GPU.FrameBufferBase + 4 * (GPU.Info->PixelsPerScanline * Row * Column)) = Color;
}
}
*/
// TODO: Implement a switching mechanism.
}
// Plot a single pixel at the specified location with the specified color.
void DrawPixel(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU, uint32_t x, uint32_t y, uint32_t Color) {
// We can't draw off the screen, so fill the screen in that case.
// TODO: implement the border coloring here
if(y > GPU.Info->VerticalResolution || x > GPU.Info->HorizontalResolution) {
FillScreen(GPU, Color);
} else {
// If the pixel is in bounds:
// Find the offset from the base of the framebuffer by:
// y * width + x
// 4 bits per pixel, so multiply by 4 to get the start of the correct pixel
// Set it to the color we want.
*(uint32_t* )(GPU.FrameBufferBase + (y * GPU.Info->PixelsPerScanline + x) * 4) = Color;
}
}
// TODO: Rectangle, Triangle drawing.
void WriteChar(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU, int Char, uint32_t Height, uint32_t Width, uint32_t FontColor, uint32_t HighlightColor) {
if(Height > GPU.Info->VerticalResolution || Width > GPU.Info->HorizontalResolution) {
FillScreen(GPU, FontColor);
} else {
// This writes to the top left of the screen.
// TODO: Automatically determine the next position using GPU.Info->cursorPos
RenderText(GPU, Char, Height, Width, FontColor, HighlightColor, 0, 0, 1, 0);
}
}
void WriteCharPos(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU, int Char, uint32_t Height, uint32_t Width, uint32_t FontColor, uint32_t HighlightColor, uint32_t x, uint32_t y) {
if(Height > GPU.Info->VerticalResolution || Width > GPU.Info->HorizontalResolution) {
FillScreen(GPU, 0x00FF0000);
} else if(y > GPU.Info->VerticalResolution || x > GPU.Info->HorizontalResolution) {
FillScreen(GPU, 0x0000FF00);
} else if ((y + Height) > GPU.Info->VerticalResolution || (x + Width) > GPU.Info->HorizontalResolution) {
FillScreen(GPU, 0x000000FF);
}
RenderText(GPU, Char, Height, Width, FontColor, HighlightColor, x, y, 1, 0);
}
void WriteScaledString(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU, const char* String, uint32_t Height, uint32_t Width, uint32_t FontColor, uint32_t HighlightColor, uint32_t x, uint32_t y, uint32_t Scale) {
if(Height > GPU.Info->VerticalResolution || Width > GPU.Info->HorizontalResolution) {
FillScreen(GPU, 0x00FF0000);
} else if( y > GPU.Info->VerticalResolution || x > GPU.Info->HorizontalResolution) {
FillScreen(GPU, 0x0000FF00);
} else if ((y + Scale * Height) > GPU.Info->VerticalResolution || (x + Scale * Width) > GPU.Info->HorizontalResolution) {
FillScreen(GPU, 0x000000FF);
}
uint32_t Char = 0;
while(String[Char] != '\0') {
RenderText(GPU, String[Char], Height, Width, FontColor, HighlightColor, x, y, Scale, Char);
Char++;
}
}
// Render characters to the screen.
void RenderText(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GPU, int Char, uint32_t Height, uint32_t Width, uint32_t FontColor, uint32_t HighlightColor, uint32_t x, uint32_t y, uint32_t Scale, uint32_t INDX) {
uint32_t Y = Width >> 3, X = 0;
if((Width & 0x7) != 0) {
Y++;
}
for(uint32_t Row = 0; Row < Height; Row++) {
for(uint32_t Bit = 0; Bit < Width; Bit++) {
if ( ((Bit & 0x7) == 0) && (Bit > 0)) {
X++;
}
if((DEFONT[Char][Row * Y + X] >> (Bit & 0x7)) & 1) {
for(uint32_t ScaleY = 0; ScaleY < Scale; ScaleY++) {
for(uint32_t ScaleX = 0; ScaleX < Scale; ScaleX++) {
// This one is crazy. Stick with me.
*(uint32_t* )(GPU.FrameBufferBase + // Offset from the framebuffer, find the pixel..
((y * GPU.Info->PixelsPerScanline + x) + // which is this many rows down, and this many pixels across,
Scale * (Row * GPU.Info->PixelsPerScanline + Bit) + // shift it around according to our scale..
(ScaleY * GPU.Info->PixelsPerScanline + ScaleX) +
Scale * INDX * Width) * 4) // and find which column we need to be in. Multiply by 4 to navigate the 4bpp array,
= FontColor; // And set the color of the pixel.
}
}
} else {
// We need to draw the pixel transparently..
for(uint32_t ScaleY = 0; ScaleY < Scale; ScaleY++) {
for(uint32_t ScaleX = 0; ScaleX < Scale; ScaleX++) {
if(HighlightColor != 0xFF000000) {
*(UINT32*)(GPU.FrameBufferBase +
((y*GPU.Info->PixelsPerScanline + x) +
Scale * (Row * GPU.Info->PixelsPerScanline + Bit) +
(ScaleY * GPU.Info->PixelsPerScanline + ScaleX) +
Scale * INDX * Width)*4)
= HighlightColor;
}
}
}
}
}
}
}
// TODO: Custom Bitmap functions