forked from PoliEcho-holding-org/kern
MAJOR RESTRUCTURE
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
#include <screen/gfxmode.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <stdint.h>
|
||||
|
||||
modeInfoBlock_t* gfxMode = (modeInfoBlock_t*)MODE_INFO_BLOCK_LOC;
|
||||
|
||||
uint32_t convertColor(uint32_t color) {
|
||||
if (gfxMode->bpp == 8) { // Uses VGA Color pallete, idk how to support that
|
||||
return color & 0xff;
|
||||
}
|
||||
|
||||
// TODO: !! Important !! - Is should be divided by 255.0 (for floats), but using '-mgeneral-regs-only' removes fp-registers and
|
||||
// wants to use some dumb functions for converting fp numbers in the stdlib (that we don't have)
|
||||
uint8_t red = ((color >> 16) & 0xff) * (((1 << gfxMode->linearRedMaskSize) - 1) / 255);
|
||||
uint8_t green = ((color >> 8 ) & 0xff) * (((1 << gfxMode->linearGreenMaskSize) - 1) / 255);
|
||||
uint8_t blue = ((color ) & 0xff) * (((1 << gfxMode->linearBlueMaskSize) - 1) / 255);
|
||||
|
||||
return (red << gfxMode->redFieldPos) | (green << gfxMode->greenFieldPos) | (blue << gfxMode->blueFieldPos);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
#include <screen/graphics.h>
|
||||
#include <screen/text.h>
|
||||
#include <screen/gfxmode.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
void drawPixel(int32_t x, int32_t y, uint32_t color) {
|
||||
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
|
||||
uint8_t bytesPerPx = gfxMode->bpp / 8;
|
||||
uint32_t convColor = convertColor(color); // Idk if i should convert this for every px or just put in a preconverted color
|
||||
|
||||
uint32_t offset = ((y * gfxMode->xRes) + x) * bytesPerPx;
|
||||
|
||||
for (uint8_t i = 0; i < bytesPerPx; i++) {
|
||||
vidmem[offset + i] = (uint8_t)(convColor >> (i*8));
|
||||
}
|
||||
}
|
||||
|
||||
// Source: https://en.wikipedia.org/wiki/Bresenham's_line_algorithm
|
||||
void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) {
|
||||
int32_t dx = abs(x2 - x1);
|
||||
int32_t dy = -abs(y2 - y1);
|
||||
int8_t sx = (x1 < x2) ? 1 : -1;
|
||||
int8_t sy = (y1 < y2) ? 1 : -1;
|
||||
int16_t err = dx + dy;
|
||||
|
||||
// TODO: Sometimes the condition isn't met for some reason and it breaks everything
|
||||
while (!(x1 == x2 && y1 == y2)) {
|
||||
drawPixel(x1, y1, color);
|
||||
|
||||
if (err * 2 >= dy) {
|
||||
err += dy;
|
||||
x1 += sx;
|
||||
}
|
||||
if (err * 2 <= dx) {
|
||||
err += dx;
|
||||
y1 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) {
|
||||
drawLine(x1, y1, x2, y1, color);
|
||||
drawLine(x2, y1, x2, y2, color);
|
||||
drawLine(x2, y2, x1, y2, color);
|
||||
drawLine(x1, y2, x1, y1, color);
|
||||
}
|
||||
|
||||
void drawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color) {
|
||||
drawLine(x1, y1, x2, y2, color);
|
||||
drawLine(x2, y2, x3, y3, color);
|
||||
drawLine(x3, y3, x1, y1, color);
|
||||
}
|
||||
|
||||
void drawCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color) {
|
||||
int16_t offX = 0;
|
||||
int16_t offY = radius;
|
||||
int16_t p = 1 - radius;
|
||||
|
||||
// Draw 8 octant points
|
||||
drawPixel(x + offX, y + offY, color);
|
||||
drawPixel(x - offX, y + offY, color);
|
||||
drawPixel(x + offX, y - offY, color);
|
||||
drawPixel(x - offX, y - offY, color);
|
||||
drawPixel(x + offY, y + offX, color);
|
||||
drawPixel(x - offY, y + offX, color);
|
||||
drawPixel(x + offY, y - offX, color);
|
||||
drawPixel(x - offY, y - offX, color);
|
||||
|
||||
while (offX < offY) {
|
||||
offX++;
|
||||
if (p < 0) p += 2 * offX + 1;
|
||||
else {
|
||||
offY--;
|
||||
p += 2 * (offX - offY) + 1;
|
||||
}
|
||||
|
||||
drawPixel(x + offX, y + offY, color);
|
||||
drawPixel(x - offX, y + offY, color);
|
||||
drawPixel(x + offX, y - offY, color);
|
||||
drawPixel(x - offX, y - offY, color);
|
||||
drawPixel(x + offY, y + offX, color);
|
||||
drawPixel(x - offY, y + offX, color);
|
||||
drawPixel(x + offY, y - offX, color);
|
||||
drawPixel(x - offY, y - offX, color);
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive (may need large stack)
|
||||
// TODO: Fix this for all bpp values
|
||||
void boundaryFill(int32_t x, int32_t y, uint32_t fillColor, uint32_t boundaryColor) {
|
||||
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
|
||||
uint8_t bytesPerPx = (gfxMode->bpp+1) / 8;
|
||||
uint32_t convColorF = convertColor(fillColor);
|
||||
uint32_t convColorB = convertColor(boundaryColor);
|
||||
|
||||
uint32_t offset = (y * gfxMode->xRes + x) * bytesPerPx;
|
||||
|
||||
uint8_t draw = 0;
|
||||
for (uint8_t i = 0; i < bytesPerPx; i++) {
|
||||
if (vidmem[offset + i] != (uint8_t)(convColorF >> (i*8)) && vidmem[offset + i] != (uint8_t)(convColorB >> (i*8))) {
|
||||
draw = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (draw) {
|
||||
for (uint8_t i = 0; i < bytesPerPx; i++) {
|
||||
vidmem[offset + i] = (uint8_t)(convColorF >> (i*8));
|
||||
}
|
||||
|
||||
boundaryFill(x + 1, y, fillColor, boundaryColor);
|
||||
boundaryFill(x, y + 1, fillColor, boundaryColor);
|
||||
boundaryFill(x - 1, y, fillColor, boundaryColor);
|
||||
boundaryFill(x, y - 1, fillColor, boundaryColor);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: After i fix boundary fill, uncomment it from these functions
|
||||
void fillRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) {
|
||||
int32_t cx = (x1 + x2) / 2;
|
||||
int32_t cy = (y1 + y2) / 2;
|
||||
|
||||
drawRect(x1, y1, x2, y2, color - 1);
|
||||
boundaryFill(cx, cy, color, color - 1);
|
||||
drawRect(x1, y1, x2, y2, color);
|
||||
}
|
||||
|
||||
void fillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color) {
|
||||
int32_t cx = (x1 + x2 + x3) / 3;
|
||||
int32_t cy = (y1 + y2 + y3) / 3;
|
||||
|
||||
drawTriangle(x1, y1, x2, y2, x3, y3, color - 1);
|
||||
boundaryFill(cx, cy, color, color - 1);
|
||||
drawTriangle(x1, y1, x2, y2, x3, y3, color);
|
||||
}
|
||||
|
||||
void fillCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color) {
|
||||
drawCircle(x, y, radius, color - 1);
|
||||
// boundaryFill(x, y, color, color - 1); TODO: It just doesn't feel like working here and hangs
|
||||
drawCircle(x, y, radius, color);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <screen/text.h>
|
||||
#include <screen/gfxmode.h>
|
||||
#include <screen/tty.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
// TODO: Reimplement larger text
|
||||
void drawChar(char c, uint32_t x, uint32_t y, uint32_t fgColor, uint32_t bgColor) {
|
||||
// Font info
|
||||
font_t* font = (font_t*)FONT_LOC;
|
||||
uint8_t charWidth = font->width;
|
||||
uint8_t charHeight = font->height;
|
||||
// uint8_t bitmapRowLen = (charWidth - 1) / 8 + 1; // TODO: Larger font support
|
||||
|
||||
// Video stuff
|
||||
uint8_t bytesPerPx = (gfxMode->bpp+7) / 8;
|
||||
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
|
||||
uint32_t offset = (gfxMode->xRes * y * charHeight + x * charWidth) * bytesPerPx;
|
||||
|
||||
uint8_t* bitmap = &font->data[(c - 1) * charHeight];
|
||||
for (uint8_t i = 0; i < charHeight; i++) { // Rows
|
||||
uint8_t bitmapRow = bitmap[i];
|
||||
uint32_t color = convertColor((bitmapRow & 0x80) ? fgColor : bgColor);
|
||||
|
||||
for (uint8_t j = 0; j < charWidth * bytesPerPx; ++j) { // Cols
|
||||
uint8_t byte = j % bytesPerPx;
|
||||
vidmem[offset + j] = (uint8_t)(color >> (8 * byte));
|
||||
|
||||
if (byte == bytesPerPx - 1) {
|
||||
bitmapRow = bitmapRow << 1;
|
||||
color = convertColor((bitmapRow & 0x80) ? fgColor : bgColor);
|
||||
}
|
||||
}
|
||||
|
||||
offset += gfxMode->linearBytesPerScanline; // gfxMode->xRes * bytesPerPx
|
||||
}
|
||||
}
|
||||
|
||||
void scroll() { // TODO: Make this faster (still kinda slow, but memcpy32() helped alot)
|
||||
uint8_t charHeight = ((font_t*)FONT_LOC)->height;
|
||||
if (console->y+1 < console->height) { return; } // Check if we should scroll
|
||||
|
||||
uint32_t bytesPerLine = charHeight * gfxMode->bytesPerScanline;
|
||||
uint32_t lines = console->height;
|
||||
uint32_t vidmem = gfxMode->physicalBasePtr;
|
||||
|
||||
for (uint32_t i = 1; i < lines; i++) {
|
||||
uint32_t address = vidmem + i * bytesPerLine;
|
||||
memcpy32((char*)address, (char*)(address - bytesPerLine), bytesPerLine);
|
||||
}
|
||||
|
||||
uint32_t color = convertColor(console->bg);
|
||||
uint8_t* lastLine = (uint8_t*)(vidmem + (lines-1) * bytesPerLine);
|
||||
uint8_t bytesPerPx = (gfxMode->bpp+1) / 8;
|
||||
|
||||
for (uint32_t i = 0; i < bytesPerLine; i++) {
|
||||
for (uint8_t j = 0; j < bytesPerPx; j++) {
|
||||
lastLine[j] = (uint8_t)(color >> (j * 8));
|
||||
}
|
||||
lastLine += bytesPerPx;
|
||||
}
|
||||
|
||||
console->y--;
|
||||
}
|
||||
|
||||
// TODO: Make this comply with the new console.h thing!
|
||||
void clearScreen(uint32_t bgColor) {
|
||||
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
|
||||
uint8_t bytesPerPx = (gfxMode->bpp+1) / 8;
|
||||
|
||||
console->x = 0;
|
||||
console->y = 0;
|
||||
|
||||
uint32_t color = convertColor(bgColor);
|
||||
|
||||
for (uint32_t i = 0; i < gfxMode->xRes; i++) { // Clear one line of pixels
|
||||
for (uint8_t j = 0; j < bytesPerPx; j++) {
|
||||
vidmem[j] = (uint8_t)(color >> (j * 8));
|
||||
}
|
||||
vidmem += bytesPerPx;
|
||||
}
|
||||
|
||||
vidmem -= gfxMode->bytesPerScanline;
|
||||
|
||||
for (uint32_t i = 0; i < gfxMode->yRes; i++) { // Copy that line to clear the entire screen (using memcpy32 is fast!)
|
||||
memcpy32(vidmem, vidmem + gfxMode->bytesPerScanline, gfxMode->bytesPerScanline);
|
||||
vidmem += gfxMode->bytesPerScanline;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#include <screen/tty.h>
|
||||
#include <screen/gfxmode.h>
|
||||
#include <screen/text.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/gfx.h>
|
||||
|
||||
console_t* console = (console_t*)CONSOLE_INFO_LOC;
|
||||
|
||||
int32_t consoleWrite(const void* buf, uint32_t len) { // TODO fix font size
|
||||
console->width = gfxMode->xRes / 8;//*(uint8_t*)(FONT_LOC);
|
||||
console->height = gfxMode->yRes / 16;//*(uint8_t*)(FONT_LOC+1);
|
||||
|
||||
char* str = (char*)buf;
|
||||
uint32_t i;
|
||||
|
||||
// Do we need to check for NULL? Can we just skip it/ignore it?
|
||||
for (i = 0; i < len && str[i] != '\0'; i++) {
|
||||
if (str[i] == '\n') {
|
||||
drawChar(' ', console->x, console->y, console->fg, console->bg);
|
||||
console->y++;
|
||||
console->x = 0;
|
||||
} else if (str[i] == '\b') {
|
||||
drawChar(' ', console->x, console->y, console->fg, console->bg);
|
||||
if (console->x == 0) {
|
||||
console->x = console->width - 1;
|
||||
console->y--; // Y could be 0?
|
||||
} else {
|
||||
console->x--;
|
||||
}
|
||||
drawChar(' ', console->x, console->y, console->fg, console->bg);
|
||||
} else if (str[i] == '\x1b') { // Escape sequence
|
||||
if (str[++i] != '[') { // TODO: Support more types of escape sequences
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
uint32_t args[8] = { 0 };
|
||||
uint8_t argc = 0;
|
||||
while (1) { // I'm not 100% sure this works, but i'd like to imagine it does
|
||||
if (argc > 8) break; // Max arg count? idk
|
||||
|
||||
uint32_t value = atoi(&str[i]);
|
||||
args[argc++] = value;
|
||||
|
||||
while (value != 0) { // Skip by the number string
|
||||
value /= 10;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (str[i] != ';') break;
|
||||
i++;
|
||||
}
|
||||
|
||||
switch (str[i]) { // TODO: Add default values (see docs/escape.txt)
|
||||
case 'A': // Cursor up
|
||||
console->y -= args[0];
|
||||
break;
|
||||
case 'B': // Cursor down
|
||||
console->y += args[0];
|
||||
break;
|
||||
case 'C': // Cursor left
|
||||
console->x -= args[0];
|
||||
break;
|
||||
case 'D': // Cursor right
|
||||
console->x += args[0];
|
||||
break;
|
||||
case 'E': // nth row
|
||||
console->x = args[0];
|
||||
break;
|
||||
case 'F': // nth col
|
||||
console->y = args[0];
|
||||
break;
|
||||
case 'G': // show/hide cursor
|
||||
console->hideCursor = args[0] ? false : true;
|
||||
break;
|
||||
case 'H': // move cursor to (x,y)
|
||||
console->x = args[0];
|
||||
console->y = args[1];
|
||||
break;
|
||||
case 'I': // RESERVED
|
||||
case 'J': // Erase screen
|
||||
clearScreen(console->bg);
|
||||
break;
|
||||
case 'K': // Erase line
|
||||
break; // TODO
|
||||
case 'L': // Erase collumn
|
||||
break; // TODO
|
||||
case 'M': // Set FG
|
||||
if (args[0] < 8) {
|
||||
console->fg = codeToColor(args[0]);
|
||||
} else if (args[0] == 8) {
|
||||
console->fg = FG_COLOR;
|
||||
}
|
||||
break;
|
||||
case 'N': // Set BG
|
||||
if (args[0] < 8) {
|
||||
console->bg = codeToColor(args[0]);
|
||||
} else if (args[0] == 8) {
|
||||
console->bg = BG_COLOR;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
drawChar(str[i], console->x, console->y, console->fg, console->bg);
|
||||
console->x++;
|
||||
|
||||
if (console->x >= console->width) { // Go to next line
|
||||
console->y++;
|
||||
console->x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
scroll();
|
||||
|
||||
return i; // Number of characters that were printed
|
||||
}
|
||||
|
||||
void toggleCursor() {
|
||||
static bool visible = false;
|
||||
visible = !visible;
|
||||
|
||||
drawChar(visible ? 127 : ' ', console->x, console->y, console->fg, console->bg);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user