diff --git a/Makefile b/Makefile index e5c5861..0a47e19 100644 --- a/Makefile +++ b/Makefile @@ -13,13 +13,17 @@ BUILD = ./build # Main compilation target os: $(BUILD) bootloader kernel - @$(AS) -fbin -o $(BUILD)/filetable.bin $(SRC)/filetable.asm + @echo "Assembling $(SRC)/testfont.asm..." @$(AS) -fbin -o $(BUILD)/testfont.bin $(SRC)/testfont.asm + @echo "Building filesystem..." + @$(AS) -fbin -o $(BUILD)/filetable.bin $(SRC)/filetable.asm @cat $(BUILD)/boot.bin $(BUILD)/filetable.bin $(BUILD)/kernel.bin > $(BUILD)/os.bin - @dd if=/dev/zero of=kern.iso bs=512 count=2880 - @dd if=$(BUILD)/os.bin of=kern.iso conv=notrunc - @dd if=$(BUILD)/testfont.bin of=kern.iso bs=512 seek=25 conv=notrunc - @dd if=$(SRC)/fs/test.txt of=kern.iso bs=512 seek=29 conv=notrunc + @echo "Building kern.iso..." + @dd if=/dev/zero of=kern.iso bs=512 count=2880 status=none + @dd if=$(BUILD)/os.bin of=kern.iso conv=notrunc status=none + @dd if=$(BUILD)/testfont.bin of=kern.iso bs=512 seek=35 conv=notrunc status=none + @dd if=$(SRC)/fs/test.txt of=kern.iso bs=512 seek=39 conv=notrunc status=none + @echo "\nDone!\n" $(BUILD): @[ -d $(BUILD) ] || mkdir $(BUILD) @@ -27,13 +31,17 @@ $(BUILD): # Bootloader: This target is responsible for creating boot.bin bootloader: + @echo "Assembling $(SRC)/stage1.asm..." @$(AS) -fbin -o $(BUILD)/stage1.bin $(SRC)/stage1.asm + @echo "Assembling $(SRC)/stage2.asm..." @$(AS) -fbin -o $(BUILD)/stage2.bin $(SRC)/stage2.asm @cat $(BUILD)/stage1.bin $(BUILD)/stage2.bin > $(BUILD)/boot.bin # Kernel: This target is responsible for creating kernel.bin kernel: $(SRC)/kernel.c $(SRC)/entry.asm + @echo "Assembling $(SRC)/entry.asm..." @$(AS) -felf32 -o $(BUILD)/entry.o $(SRC)/entry.asm + @echo "Compiling $(SRC)/kernel.c..." @$(CC) $(CFLAGS) -o $(BUILD)/kernel.o -c $(SRC)/kernel.c @$(LD) -T $(SRC)/kernel.ld --oformat binary -o $(BUILD)/kernel.bin $(BUILD)/*.o diff --git a/include/graphics.h b/include/graphics.h new file mode 100644 index 0000000..d6cbddc --- /dev/null +++ b/include/graphics.h @@ -0,0 +1,133 @@ +#ifndef GRAPHICS_H +#define GRAPHICS_H + +#include "stdint.h" +#include "screen.h" +#include "math.h" + +// Basic full saturation colors +#define BLACK 0x00000000 // 0 +#define RED 0x00ff0000 // 1 +#define GREEN 0x0000ff00 // 2 +#define YELLOW 0x00ffff00 // 3 +#define BLUE 0x000000ff // 4 +#define MAGENTA 0x00ff00ff // 5 +#define CYAN 0x0000ffff // 6 +#define WHITE 0x00ffffff // 7 + +#define rgb(r,g,b) ( ((r) << 16 | (g) << 8 | (b)) & 0x00ffffff ) + +void drawPixel(int32_t x, int32_t y, uint32_t color) { + uint32_t offset = (y * WIDTH) + x; + vidmem[offset] = color; +} + +// 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) +void boundaryFill(int32_t x, int32_t y, uint32_t fillColor, uint32_t boundaryColor) { + uint32_t offset = y * WIDTH + x; + + if (vidmem[offset] != fillColor && vidmem[offset] != boundaryColor) { + vidmem[offset] = fillColor; + + boundaryFill(x + 1, y, fillColor, boundaryColor); + boundaryFill(x - 1, y, fillColor, boundaryColor); + boundaryFill(x, y + 1, fillColor, boundaryColor); + boundaryFill(x, y - 1, fillColor, boundaryColor); + } +} + +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); + drawCircle(x, y, radius, color); +} + +#endif diff --git a/include/math.h b/include/math.h new file mode 100644 index 0000000..df1d55e --- /dev/null +++ b/include/math.h @@ -0,0 +1,8 @@ +#ifndef MATH_H +#define MATH_H + +#define abs(x) ( (x) > 0 ? (x) : -(x) ) +#define sign(x) ( (x) == 0 ? 0 : ((x) < 0 ? -1 : 1 ) ) +#define round(x) ( (int)((x) + 0.5) ) + +#endif diff --git a/src/filetable.asm b/src/filetable.asm index 710cc97..65d7bf8 100644 --- a/src/filetable.asm +++ b/src/filetable.asm @@ -12,9 +12,9 @@ filetable: db "boot",0,0,0,0,0,0, "bin",0,0,4 db "filetable",0, "tab",0,4,1 - db "kernel",0,0,0,0, "bin",0,5,20 - db "testfont",0,0, "fnt",0,25,4 - db "test",0,0,0,0,0,0, "txt",0,29,1 + db "kernel",0,0,0,0, "bin",0,5,30 + db "testfont",0,0, "fnt",0,35,4 + db "test",0,0,0,0,0,0, "txt",0,39,1 times 512-($-$$) db 0 diff --git a/src/kernel.c b/src/kernel.c index 9d7546b..26d19a2 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -7,6 +7,7 @@ #include "system.h" #include "disk.h" #include "string.h" +#include "graphics.h" #define PROMPT "#> " @@ -25,7 +26,8 @@ void main() { timerPhase(1000); // 1 tick per ~1ms // Screen setup - diskRead(25, 4, (char*)0x6000); // Read font from disk + // TODO: Find font in filetable + diskRead(35, 4, (char*)0x6000); // Read font from disk setupScreen(); loadFont((char*)0x6000); @@ -112,12 +114,46 @@ void main() { print(args); } else if (strcmp(input, "exit") == 0) { break; + } else if (strcmp(input, "gfx") == 0) { + clear(); + + // Draw some stuff :) + for (size_t i = 0; i < 120; i++) { + for (size_t j = 0; j < 120; j++) { + drawPixel(200 + i, 200 + j, GREEN); + } + } + + fillRect(200, 200, 320, 320, GREEN); + + drawLine(200, 200, 320, 320, RED); + drawLine(320, 200, 200, 320, RED); + + drawLine(800, 300, 900, 400, BLUE); + drawLine(900, 400, 1000, 300, BLUE); + drawLine(1000, 300, 900, 200, BLUE); + drawLine(900, 200, 800, 300, BLUE); + + drawLine(400, 350, 420, 100, rgb(0xee, 0x9f, 0x00)); + + drawTriangle(200, 400, 400, 600, 200, 600, MAGENTA); + fillTriangle(750, 400, 800, 450, 700, 450, CYAN); + drawTriangle(960, 400, 1000, 500, 990, 580, YELLOW); + + drawRect(100, 650, 800, 900, rgb(0xe0, 0x0a, 0x3a)); + + drawCircle(1500, 600, 300, WHITE); + fillCircle(950, 750, 75, rgb(0xa2, 0xd6, 0xf9)); + + read('q'); // Wait until we get a 'q' + clear(); } else if (strcmp(input, "help") == 0) { print("Available Commands:\n"); print(" clear | Clears the screen\n"); print(" disk | Reads/Writes data from/to the disk\n"); print(" echo | Prints a message to stdout\n"); print(" exit | Exits shell\n"); + print(" gfx | Does a graphics test\n"); print(" help | Prints this message\n"); print(" ls | Lists all available files\n"); print(" reboot | Reboots the system\n"); diff --git a/src/stage1.asm b/src/stage1.asm index 90fb56c..b05f18b 100644 --- a/src/stage1.asm +++ b/src/stage1.asm @@ -4,7 +4,7 @@ %define VIDMEM 0xb800 %define KERNEL_LOC 0x1000 -%define KERNEL_SIZE 20 ; 10kB +%define KERNEL_SIZE 30 ; 15kB start: mov [driveNum], dl ; Store the drive number diff --git a/todo.txt b/todo.txt index 4a99a36..e1ac33e 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,7 @@ === Todo === - [*] Multistage Bootloader +- [ ] Bootloader reads filetable to find files - [ ] Write down where stuff is in memory (0x1000 - kernel, 0x4000? - filetable, 0x5000 - VBE Mode Info, 0x6000 - Font) - [ ] "Text" mode (not actually) - [ ] Scrolling @@ -12,11 +13,15 @@ - [*] Custom font - [*] Larger text size - [ ] Variable text size :) + - [ ] Make output overflow go to next line - [ ] Graphics - - [ ] Enter/exit a "graphics" mode - - [ ] Pixel drawing - - [ ] Line drawing (Raycaster Alert??) - - [ ] Triangles (3D?!!???) + - [ ] Enter/exit a "graphics" mode (idk if we need this) + - [x] Pixel drawing + - [x] Line drawing (Raycaster Alert??) + - [x] Triangles (3D?!!???) + - [x] Rectange :) + - [x] Circle! + - [x] Filled verisons - [ ] Math - [ ] Trigonometry - [ ] Sine @@ -25,7 +30,7 @@ - [ ] Cotangent - [ ] Arc (inverse) versions - [ ] Hyperbolic versions - - [ ] Absolute value + - [x] Absolute value - [ ] isOdd() 🗿 - [ ] Exponential fn (e^x) - [ ] Logarithm @@ -33,8 +38,9 @@ - [ ] Square Root - [ ] Nth Root - [ ] Floor - - [ ] Round + - [x] Round - [ ] Ceiling + - [x] Sign - [ ] INFINITY - [ ] NAN - [ ] Filesystem