Implement graphics subsystem with VGA mode 0x13 and drawing primitives (AI)

This commit is contained in:
AI
2026-02-24 08:01:20 +00:00
parent 57b2751a81
commit fc5fe9af63
8 changed files with 781 additions and 9 deletions

View File

@@ -76,7 +76,7 @@ Once a task is completed, it should be checked off.
- [x] Create a DHCP subsystem. Create the `dhcp` command to show current DHCP status information.
- [x] Create a UDP and TCP stack.
- [x] Implement a simple version of `ftp` and `wget`.
- [ ] Create a graphics subsystem. It should provide functionality to switch between the normal text mode, and a graphics mode.
- [x] Create a graphics subsystem. It should provide functionality to switch between the normal text mode, and a graphics mode.
- [ ] Create a simple game of pool. It should use graphics mode to render the game.
- [ ] Create a simple game of minigolf.

View File

@@ -31,6 +31,7 @@ typedef int int32_t;
#define SYS_SEND 15
#define SYS_RECV 16
#define SYS_SOCKSTATE 17
#define SYS_GFX 18
static inline int32_t syscall0(int num) {
int32_t ret;
@@ -194,6 +195,92 @@ static inline int32_t sockstate(int32_t sockfd) {
return syscall1(SYS_SOCKSTATE, (uint32_t)sockfd);
}
/* ================================================================
* Graphics system calls
* ================================================================ */
/** Graphics sub-commands. */
#define GFX_CMD_ENTER 0
#define GFX_CMD_LEAVE 1
#define GFX_CMD_PIXEL 2
#define GFX_CMD_CLEAR 3
#define GFX_CMD_FILL_RECT 4
#define GFX_CMD_LINE 5
#define GFX_CMD_CIRCLE 6
#define GFX_CMD_GET_INFO 7
/** Graphics mode dimensions. */
#define GFX_WIDTH 320
#define GFX_HEIGHT 200
/** Palette color constants. */
#define GFX_BLACK 0
#define GFX_BLUE 1
#define GFX_GREEN 2
#define GFX_CYAN 3
#define GFX_RED 4
#define GFX_MAGENTA 5
#define GFX_BROWN 6
#define GFX_LIGHT_GREY 7
#define GFX_DARK_GREY 8
#define GFX_LIGHT_BLUE 9
#define GFX_LIGHT_GREEN 10
#define GFX_LIGHT_CYAN 11
#define GFX_LIGHT_RED 12
#define GFX_LIGHT_MAGENTA 13
#define GFX_YELLOW 14
#define GFX_WHITE 15
/** Command structs for complex drawing operations. */
typedef struct { uint32_t x, y, w, h, color; } gfx_rect_t;
typedef struct { uint32_t x1, y1, x2, y2, color; } gfx_line_t;
typedef struct { uint32_t cx, cy, r, color; } gfx_circle_t;
/** Convert RGB (0-255) to palette index using 6x6x6 color cube. */
static inline uint32_t gfx_rgb(uint32_t r, uint32_t g, uint32_t b) {
return 16 + (r / 51) * 36 + (g / 51) * 6 + (b / 51);
}
/** Enter graphics mode (320x200x256). */
static inline int32_t gfx_enter(void) {
return syscall1(SYS_GFX, GFX_CMD_ENTER);
}
/** Leave graphics mode, return to text. */
static inline int32_t gfx_leave(void) {
return syscall1(SYS_GFX, GFX_CMD_LEAVE);
}
/** Set a pixel. */
static inline int32_t gfx_pixel(uint32_t x, uint32_t y, uint32_t color) {
return syscall3(SYS_GFX, GFX_CMD_PIXEL, (x | (y << 16)), color);
}
/** Clear screen with a color. */
static inline int32_t gfx_clear(uint32_t color) {
return syscall2(SYS_GFX, GFX_CMD_CLEAR, color);
}
/** Fill a rectangle. */
static inline int32_t gfx_fill_rect(const gfx_rect_t *r) {
return syscall2(SYS_GFX, GFX_CMD_FILL_RECT, (uint32_t)r);
}
/** Draw a line. */
static inline int32_t gfx_line(const gfx_line_t *l) {
return syscall2(SYS_GFX, GFX_CMD_LINE, (uint32_t)l);
}
/** Draw a filled circle. */
static inline int32_t gfx_circle(const gfx_circle_t *c) {
return syscall2(SYS_GFX, GFX_CMD_CIRCLE, (uint32_t)c);
}
/** Get graphics info: returns (width | height<<16). */
static inline int32_t gfx_get_info(void) {
return syscall1(SYS_GFX, GFX_CMD_GET_INFO);
}
/* Basic string operations for user-space */
static inline uint32_t strlen(const char *s) {
uint32_t len = 0;

View File

@@ -39,9 +39,9 @@ Building app: sh
Building app: wget
Built: /workspaces/claude-os/build/apps_bin/wget (2193 bytes)
[ 2%] Built target apps
[ 5%] Built target initrd
[ 7%] Building C object src/CMakeFiles/kernel.dir/syscall.c.o
[ 10%] Linking C executable ../bin/kernel
[ 4%] Built target initrd
[ 7%] Building C object src/CMakeFiles/kernel.dir/graphics.c.o
[ 9%] Linking C executable ../bin/kernel
[ 97%] Built target kernel
[100%] Generating bootable ISO image
xorriso 1.5.6 : RockRidge filesystem manipulator, libburnia project.
@@ -50,14 +50,14 @@ Drive current: -outdev 'stdio:/workspaces/claude-os/release/claude-os.iso'
Media current: stdio file, overwriteable
Media status : is blank
Media summary: 0 sessions, 0 data blocks, 0 data, 126g free
Added to ISO image: directory '/'='/tmp/grub.GnJedF'
Added to ISO image: directory '/'='/tmp/grub.EEhNkO'
xorriso : UPDATE : 581 files added in 1 seconds
Added to ISO image: directory '/'='/workspaces/claude-os/build/isodir'
xorriso : UPDATE : 586 files added in 1 seconds
xorriso : NOTE : Copying to System Area: 512 bytes from file '/usr/lib/grub/i386-pc/boot_hybrid.img'
xorriso : UPDATE : 65.27% done
ISO image produced: 6030 sectors
Written to medium : 6030 sectors at LBA 0
xorriso : UPDATE : 67.13% done
ISO image produced: 6054 sectors
Written to medium : 6054 sectors at LBA 0
Writing to 'stdio:/workspaces/claude-os/release/claude-os.iso' completed successfully.
[100%] Built target iso

View File

@@ -33,6 +33,7 @@ add_executable(kernel
dhcp.c
udp.c
tcp.c
graphics.c
env.c
keyboard.c
interrupts.S

450
src/graphics.c Normal file
View File

@@ -0,0 +1,450 @@
/**
* @file graphics.c
* @brief Graphics subsystem implementation.
*
* Provides VGA mode 0x13 (320x200, 256 colors) with drawing primitives.
* Handles switching between text mode (0x03) and graphics mode via
* direct VGA register programming.
*/
#include "graphics.h"
#include "port_io.h"
#include "font8x16.h"
#include "string.h"
#include "vga.h"
/* ================================================================
* VGA register programming constants
* ================================================================ */
/* VGA ports */
#define VGA_MISC_WRITE 0x3C2
#define VGA_MISC_READ 0x3CC
#define VGA_SEQ_INDEX 0x3C4
#define VGA_SEQ_DATA 0x3C5
#define VGA_CRTC_INDEX 0x3D4
#define VGA_CRTC_DATA 0x3D5
#define VGA_GC_INDEX 0x3CE
#define VGA_GC_DATA 0x3CF
#define VGA_AC_INDEX 0x3C0
#define VGA_AC_WRITE 0x3C0
#define VGA_AC_READ 0x3C1
#define VGA_INSTAT_READ 0x3DA
#define VGA_DAC_WRITE_IDX 0x3C8
#define VGA_DAC_DATA 0x3C9
/* Number of registers in each group */
#define VGA_NUM_SEQ_REGS 5
#define VGA_NUM_CRTC_REGS 25
#define VGA_NUM_GC_REGS 9
#define VGA_NUM_AC_REGS 21
/* ================================================================
* VGA register tables for Mode 0x13 (320x200x256)
* ================================================================ */
static const uint8_t mode13_misc = 0x63;
static const uint8_t mode13_seq[VGA_NUM_SEQ_REGS] = {
0x03, 0x01, 0x0F, 0x00, 0x0E
};
static const uint8_t mode13_crtc[VGA_NUM_CRTC_REGS] = {
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
0xFF
};
static const uint8_t mode13_gc[VGA_NUM_GC_REGS] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
0xFF
};
static const uint8_t mode13_ac[VGA_NUM_AC_REGS] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x41, 0x00, 0x0F, 0x00, 0x00
};
/* ================================================================
* VGA register tables for Mode 0x03 (80x25 text)
* ================================================================ */
static const uint8_t mode03_misc = 0x67;
static const uint8_t mode03_seq[VGA_NUM_SEQ_REGS] = {
0x03, 0x00, 0x03, 0x00, 0x02
};
static const uint8_t mode03_crtc[VGA_NUM_CRTC_REGS] = {
0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F,
0x00, 0x4F, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x50,
0x9C, 0x0E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
0xFF
};
static const uint8_t mode03_gc[VGA_NUM_GC_REGS] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00,
0xFF
};
static const uint8_t mode03_ac[VGA_NUM_AC_REGS] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x0C, 0x00, 0x0F, 0x08, 0x00
};
/* ================================================================
* Module state
* ================================================================ */
static int gfx_mode = GFX_MODE_TEXT;
static uint8_t *framebuffer = (uint8_t *)GFX_FRAMEBUFFER;
/* ================================================================
* VGA register programming helpers
* ================================================================ */
/**
* Write a set of VGA registers to switch modes.
*/
static void vga_write_regs(uint8_t misc, const uint8_t *seq,
const uint8_t *crtc, const uint8_t *gc,
const uint8_t *ac)
{
/* Miscellaneous output */
outb(VGA_MISC_WRITE, misc);
/* Sequencer */
for (int i = 0; i < VGA_NUM_SEQ_REGS; i++) {
outb(VGA_SEQ_INDEX, (uint8_t)i);
outb(VGA_SEQ_DATA, seq[i]);
}
/* Unlock CRTC (clear protect bit in register 0x11) */
outb(VGA_CRTC_INDEX, 0x11);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) & 0x7F);
/* CRTC */
for (int i = 0; i < VGA_NUM_CRTC_REGS; i++) {
outb(VGA_CRTC_INDEX, (uint8_t)i);
outb(VGA_CRTC_DATA, crtc[i]);
}
/* Graphics Controller */
for (int i = 0; i < VGA_NUM_GC_REGS; i++) {
outb(VGA_GC_INDEX, (uint8_t)i);
outb(VGA_GC_DATA, gc[i]);
}
/* Attribute Controller */
/* Reading port 0x3DA resets the AC flip-flop to index mode */
inb(VGA_INSTAT_READ);
for (int i = 0; i < VGA_NUM_AC_REGS; i++) {
outb(VGA_AC_INDEX, (uint8_t)i);
outb(VGA_AC_WRITE, ac[i]);
}
/* Re-enable display by setting bit 5 of the AC index */
outb(VGA_AC_INDEX, 0x20);
}
/* ================================================================
* VGA font restore for text mode
* ================================================================ */
/**
* Load the 8x16 font into VGA plane 2 after returning to text mode.
* This restores readable text after graphics mode.
*/
static void vga_load_font(void) {
volatile uint8_t *vmem = (volatile uint8_t *)0xA0000;
/* Set up sequencer for font loading:
* - Map Mask: select plane 2 only
* - Memory Mode: disable chain-4, enable odd/even */
outb(VGA_SEQ_INDEX, 0x02);
outb(VGA_SEQ_DATA, 0x04); /* Map Mask: plane 2 */
outb(VGA_SEQ_INDEX, 0x04);
outb(VGA_SEQ_DATA, 0x06); /* Memory Mode: enable sequential, disable chain-4 */
/* Set up graphics controller for font loading:
* - Read Map Select: plane 2
* - Graphics Mode: write mode 0, read mode 0
* - Miscellaneous: text mode mapping (B8000-BFFFF) */
outb(VGA_GC_INDEX, 0x04);
outb(VGA_GC_DATA, 0x02); /* Read Map Select: plane 2 */
outb(VGA_GC_INDEX, 0x05);
outb(VGA_GC_DATA, 0x00); /* Graphics Mode: write mode 0 */
outb(VGA_GC_INDEX, 0x06);
outb(VGA_GC_DATA, 0x04); /* Misc: map to A0000, no chain, no odd/even */
/* Write font data for 256 characters.
* Each char entry is 32 bytes (only first 16 used for 8x16 font).
* Characters outside our font range get a filled block. */
for (int ch = 0; ch < 256; ch++) {
for (int row = 0; row < 16; row++) {
uint8_t bits;
if (ch >= FONT_FIRST && ch <= FONT_LAST) {
bits = font8x16_data[ch - FONT_FIRST][row];
} else if (ch == 0) {
bits = 0x00; /* Null char = blank */
} else {
bits = 0xFF; /* Unknown = filled block */
}
vmem[ch * 32 + row] = bits;
}
/* Zero out remaining 16 bytes of the 32-byte slot */
for (int row = 16; row < 32; row++) {
vmem[ch * 32 + row] = 0x00;
}
}
/* Restore sequencer for text mode:
* - Map Mask: planes 0 and 1 (text attribute + char)
* - Memory Mode: enable odd/even, no chain-4 */
outb(VGA_SEQ_INDEX, 0x02);
outb(VGA_SEQ_DATA, 0x03); /* Map Mask: planes 0 and 1 */
outb(VGA_SEQ_INDEX, 0x04);
outb(VGA_SEQ_DATA, 0x02); /* Memory Mode: odd/even addressing */
/* Restore graphics controller for text mode */
outb(VGA_GC_INDEX, 0x04);
outb(VGA_GC_DATA, 0x00); /* Read Map Select: plane 0 */
outb(VGA_GC_INDEX, 0x05);
outb(VGA_GC_DATA, 0x10); /* Graphics Mode: odd/even */
outb(VGA_GC_INDEX, 0x06);
outb(VGA_GC_DATA, 0x0E); /* Misc: map to B8000, odd/even */
}
/* ================================================================
* 256-color palette setup
* ================================================================ */
/**
* Standard VGA 16-color palette (RGB 6-bit values).
*/
static const uint8_t vga_palette_16[16][3] = {
{ 0, 0, 0}, /* 0: Black */
{ 0, 0, 42}, /* 1: Blue */
{ 0, 42, 0}, /* 2: Green */
{ 0, 42, 42}, /* 3: Cyan */
{42, 0, 0}, /* 4: Red */
{42, 0, 42}, /* 5: Magenta */
{42, 21, 0}, /* 6: Brown */
{42, 42, 42}, /* 7: Light Grey */
{21, 21, 21}, /* 8: Dark Grey */
{21, 21, 63}, /* 9: Light Blue */
{21, 63, 21}, /* 10: Light Green */
{21, 63, 63}, /* 11: Light Cyan */
{63, 21, 21}, /* 12: Light Red */
{63, 21, 63}, /* 13: Light Magenta */
{63, 63, 21}, /* 14: Yellow */
{63, 63, 63}, /* 15: White */
};
/**
* Set up the 256-color palette.
* 0-15: Standard 16 VGA colors
* 16-231: 6x6x6 RGB color cube
* 232-255: 24-step grayscale
*/
static void setup_palette(void) {
/* VGA DAC: write index, then R, G, B (6-bit values, 0-63) */
/* Standard 16 colors */
outb(VGA_DAC_WRITE_IDX, 0);
for (int i = 0; i < 16; i++) {
outb(VGA_DAC_DATA, vga_palette_16[i][0]);
outb(VGA_DAC_DATA, vga_palette_16[i][1]);
outb(VGA_DAC_DATA, vga_palette_16[i][2]);
}
/* 6x6x6 RGB color cube (indices 16-231) */
outb(VGA_DAC_WRITE_IDX, 16);
for (int r = 0; r < 6; r++) {
for (int g = 0; g < 6; g++) {
for (int b = 0; b < 6; b++) {
outb(VGA_DAC_DATA, (uint8_t)(r * 63 / 5));
outb(VGA_DAC_DATA, (uint8_t)(g * 63 / 5));
outb(VGA_DAC_DATA, (uint8_t)(b * 63 / 5));
}
}
}
/* 24-step grayscale (indices 232-255) */
outb(VGA_DAC_WRITE_IDX, 232);
for (int i = 0; i < 24; i++) {
uint8_t v = (uint8_t)(i * 63 / 23);
outb(VGA_DAC_DATA, v);
outb(VGA_DAC_DATA, v);
outb(VGA_DAC_DATA, v);
}
}
/* ================================================================
* Mode switching
* ================================================================ */
void graphics_enter(void) {
if (gfx_mode == GFX_MODE_GRAPHICS) return;
/* Switch to mode 0x13 */
vga_write_regs(mode13_misc, mode13_seq, mode13_crtc, mode13_gc, mode13_ac);
/* Set up the color palette */
setup_palette();
/* Clear the framebuffer */
memset(framebuffer, 0, GFX_WIDTH * GFX_HEIGHT);
gfx_mode = GFX_MODE_GRAPHICS;
}
void graphics_leave(void) {
if (gfx_mode == GFX_MODE_TEXT) return;
/* Switch to mode 0x03 */
vga_write_regs(mode03_misc, mode03_seq, mode03_crtc, mode03_gc, mode03_ac);
/* Reload the VGA font into plane 2 */
vga_load_font();
/* Clear the text-mode framebuffer */
volatile uint16_t *text_buf = (volatile uint16_t *)0xB8000;
for (int i = 0; i < 80 * 25; i++) {
text_buf[i] = 0x0720; /* Light grey on black, space */
}
gfx_mode = GFX_MODE_TEXT;
/* Re-initialize the VGA text driver */
vga_init();
}
int graphics_get_mode(void) {
return gfx_mode;
}
/* ================================================================
* Drawing primitives
* ================================================================ */
void gfx_pixel(int x, int y, uint8_t color) {
if (x < 0 || x >= GFX_WIDTH || y < 0 || y >= GFX_HEIGHT) return;
framebuffer[y * GFX_WIDTH + x] = color;
}
void gfx_clear(uint8_t color) {
memset(framebuffer, color, GFX_WIDTH * GFX_HEIGHT);
}
void gfx_fill_rect(int x, int y, int w, int h, uint8_t color) {
/* Clip */
int x1 = x < 0 ? 0 : x;
int y1 = y < 0 ? 0 : y;
int x2 = (x + w > GFX_WIDTH) ? GFX_WIDTH : (x + w);
int y2 = (y + h > GFX_HEIGHT) ? GFX_HEIGHT : (y + h);
for (int row = y1; row < y2; row++) {
memset(&framebuffer[row * GFX_WIDTH + x1], color, (uint32_t)(x2 - x1));
}
}
void gfx_draw_line(int x1, int y1, int x2, int y2, uint8_t color) {
/* Bresenham's line algorithm */
int dx = x2 - x1;
int dy = y2 - y1;
int sx = dx >= 0 ? 1 : -1;
int sy = dy >= 0 ? 1 : -1;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
int err = dx - dy;
for (;;) {
gfx_pixel(x1, y1, color);
if (x1 == x2 && y1 == y2) break;
int e2 = 2 * err;
if (e2 > -dy) { err -= dy; x1 += sx; }
if (e2 < dx) { err += dx; y1 += sy; }
}
}
void gfx_fill_circle(int cx, int cy, int r, uint8_t color) {
if (r <= 0) { gfx_pixel(cx, cy, color); return; }
for (int y = -r; y <= r; y++) {
/* Horizontal span for this scanline */
int dx = 0;
while (dx * dx + y * y <= r * r) dx++;
dx--;
int left = cx - dx;
int right = cx + dx;
/* Clip */
if (cy + y < 0 || cy + y >= GFX_HEIGHT) continue;
if (left < 0) left = 0;
if (right >= GFX_WIDTH) right = GFX_WIDTH - 1;
if (left > right) continue;
memset(&framebuffer[(cy + y) * GFX_WIDTH + left], color,
(uint32_t)(right - left + 1));
}
}
void gfx_draw_circle(int cx, int cy, int r, uint8_t color) {
/* Midpoint circle algorithm */
int x = r, y = 0;
int err = 1 - r;
while (x >= y) {
gfx_pixel(cx + x, cy + y, color);
gfx_pixel(cx + y, cy + x, color);
gfx_pixel(cx - y, cy + x, color);
gfx_pixel(cx - x, cy + y, color);
gfx_pixel(cx - x, cy - y, color);
gfx_pixel(cx - y, cy - x, color);
gfx_pixel(cx + y, cy - x, color);
gfx_pixel(cx + x, cy - y, color);
y++;
if (err < 0) {
err += 2 * y + 1;
} else {
x--;
err += 2 * (y - x) + 1;
}
}
}
void gfx_draw_char(int x, int y, char c, uint8_t color) {
if (c < FONT_FIRST || c > FONT_LAST) return;
const uint8_t *glyph = font8x16_data[c - FONT_FIRST];
/* Draw at half vertical scale: 8x8 pixels per character.
* Sample every other row from the 8x16 font. */
for (int row = 0; row < 8; row++) {
uint8_t bits = glyph[row * 2]; /* Sample even rows */
for (int col = 0; col < 8; col++) {
if (bits & (0x80 >> col)) {
gfx_pixel(x + col, y + row, color);
}
}
}
}
void gfx_draw_text(int x, int y, const char *str, uint8_t color) {
int cx = x;
while (*str) {
if (*str == '\n') {
cx = x;
y += 8;
} else {
gfx_draw_char(cx, y, *str, color);
cx += 8;
}
str++;
}
}

173
src/graphics.h Normal file
View File

@@ -0,0 +1,173 @@
/**
* @file graphics.h
* @brief Graphics subsystem for ClaudeOS.
*
* Provides VGA mode 0x13 (320x200, 256 colors) graphics with
* drawing primitives. Supports switching between text mode (0x03)
* and graphics mode at runtime.
*
* Color palette:
* 0-15 : Standard 16 VGA colors
* 16-231: 6x6x6 RGB color cube (index = 16 + r*36 + g*6 + b, where r,g,b in 0-5)
* 232-255: 24-step grayscale
*/
#ifndef GRAPHICS_H
#define GRAPHICS_H
#include <stdint.h>
/** Graphics mode screen dimensions. */
#define GFX_WIDTH 320
#define GFX_HEIGHT 200
/** Framebuffer base address for mode 0x13. */
#define GFX_FRAMEBUFFER 0xA0000
/** Graphics mode state. */
#define GFX_MODE_TEXT 0
#define GFX_MODE_GRAPHICS 1
/* ================================================================
* Standard palette color indices (0-15)
* ================================================================ */
#define GFX_BLACK 0
#define GFX_BLUE 1
#define GFX_GREEN 2
#define GFX_CYAN 3
#define GFX_RED 4
#define GFX_MAGENTA 5
#define GFX_BROWN 6
#define GFX_LIGHT_GREY 7
#define GFX_DARK_GREY 8
#define GFX_LIGHT_BLUE 9
#define GFX_LIGHT_GREEN 10
#define GFX_LIGHT_CYAN 11
#define GFX_LIGHT_RED 12
#define GFX_LIGHT_MAGENTA 13
#define GFX_YELLOW 14
#define GFX_WHITE 15
/* ================================================================
* GFX syscall sub-commands
* ================================================================ */
#define GFX_CMD_ENTER 0 /**< Enter graphics mode. Returns 0. */
#define GFX_CMD_LEAVE 1 /**< Leave graphics mode (back to text). Returns 0. */
#define GFX_CMD_PIXEL 2 /**< Set pixel. ECX=(x|y<<16), EDX=color. */
#define GFX_CMD_CLEAR 3 /**< Clear screen. ECX=color. */
#define GFX_CMD_FILL_RECT 4 /**< Fill rect. ECX=ptr to gfx_rect_t. */
#define GFX_CMD_LINE 5 /**< Draw line. ECX=ptr to gfx_line_t. */
#define GFX_CMD_CIRCLE 6 /**< Draw filled circle. ECX=ptr to gfx_circle_t. */
#define GFX_CMD_GET_INFO 7 /**< Get info. Returns (width | height<<16). */
/* ================================================================
* Command structs (used with pointer-based sub-commands)
* ================================================================ */
typedef struct {
uint32_t x, y, w, h;
uint32_t color;
} gfx_rect_t;
typedef struct {
uint32_t x1, y1, x2, y2;
uint32_t color;
} gfx_line_t;
typedef struct {
uint32_t cx, cy, r;
uint32_t color;
} gfx_circle_t;
/* ================================================================
* Public API
* ================================================================ */
/**
* Convert RGB (0-255 each) to a palette index.
* Uses the 6x6x6 color cube (indices 16-231).
*/
static inline uint8_t gfx_rgb(uint8_t r, uint8_t g, uint8_t b) {
return (uint8_t)(16 + (r / 51) * 36 + (g / 51) * 6 + (b / 51));
}
/**
* Enter graphics mode (VGA 0x13: 320x200x256).
* Saves text mode state and initializes the color palette.
*/
void graphics_enter(void);
/**
* Leave graphics mode and return to text mode (VGA 0x03: 80x25).
* Restores the VGA font and text display.
*/
void graphics_leave(void);
/**
* Get the current graphics mode.
* @return GFX_MODE_TEXT or GFX_MODE_GRAPHICS.
*/
int graphics_get_mode(void);
/**
* Set a single pixel.
* @param x X coordinate (0 to GFX_WIDTH-1).
* @param y Y coordinate (0 to GFX_HEIGHT-1).
* @param color Palette color index (0-255).
*/
void gfx_pixel(int x, int y, uint8_t color);
/**
* Clear the screen with a color.
* @param color Palette color index.
*/
void gfx_clear(uint8_t color);
/**
* Draw a filled rectangle.
* @param x Top-left X.
* @param y Top-left Y.
* @param w Width.
* @param h Height.
* @param color Palette color index.
*/
void gfx_fill_rect(int x, int y, int w, int h, uint8_t color);
/**
* Draw a line (Bresenham).
* @param x1,y1 Start point.
* @param x2,y2 End point.
* @param color Palette color index.
*/
void gfx_draw_line(int x1, int y1, int x2, int y2, uint8_t color);
/**
* Draw a filled circle.
* @param cx,cy Center.
* @param r Radius.
* @param color Palette color index.
*/
void gfx_fill_circle(int cx, int cy, int r, uint8_t color);
/**
* Draw a circle outline.
* @param cx,cy Center.
* @param r Radius.
* @param color Palette color index.
*/
void gfx_draw_circle(int cx, int cy, int r, uint8_t color);
/**
* Draw a text string using the 8x16 font (scaled to 8x8 in mode 13).
* @param x,y Top-left position.
* @param str Null-terminated string.
* @param color Palette color index.
*/
void gfx_draw_text(int x, int y, const char *str, uint8_t color);
/**
* Draw a single character using the 8x16 font at half vertical scale (8x8).
*/
void gfx_draw_char(int x, int y, char c, uint8_t color);
#endif /* GRAPHICS_H */

View File

@@ -19,6 +19,7 @@
#include "pmm.h"
#include "tcp.h"
#include "udp.h"
#include "graphics.h"
#include <stddef.h>
#include <string.h>
@@ -465,6 +466,64 @@ static int32_t sys_sockstate(registers_t *regs) {
return -1;
}
/**
* Handle SYS_GFX: graphics operations.
* EBX = sub-command, ECX = arg1, EDX = arg2.
*/
static int32_t sys_gfx(registers_t *regs) {
uint32_t cmd = regs->ebx;
uint32_t arg1 = regs->ecx;
uint32_t arg2 = regs->edx;
switch (cmd) {
case GFX_CMD_ENTER:
graphics_enter();
return 0;
case GFX_CMD_LEAVE:
graphics_leave();
return 0;
case GFX_CMD_PIXEL: {
int x = (int)(arg1 & 0xFFFF);
int y = (int)(arg1 >> 16);
gfx_pixel(x, y, (uint8_t)arg2);
return 0;
}
case GFX_CMD_CLEAR:
gfx_clear((uint8_t)arg1);
return 0;
case GFX_CMD_FILL_RECT: {
const gfx_rect_t *r = (const gfx_rect_t *)arg1;
gfx_fill_rect((int)r->x, (int)r->y, (int)r->w, (int)r->h,
(uint8_t)r->color);
return 0;
}
case GFX_CMD_LINE: {
const gfx_line_t *l = (const gfx_line_t *)arg1;
gfx_draw_line((int)l->x1, (int)l->y1, (int)l->x2, (int)l->y2,
(uint8_t)l->color);
return 0;
}
case GFX_CMD_CIRCLE: {
const gfx_circle_t *c = (const gfx_circle_t *)arg1;
gfx_fill_circle((int)c->cx, (int)c->cy, (int)c->r,
(uint8_t)c->color);
return 0;
}
case GFX_CMD_GET_INFO:
return (int32_t)(GFX_WIDTH | (GFX_HEIGHT << 16));
default:
return -1;
}
}
/** System call dispatch table. */
typedef int32_t (*syscall_fn)(registers_t *);
static syscall_fn syscall_table[NUM_SYSCALLS] = {
@@ -486,6 +545,7 @@ static syscall_fn syscall_table[NUM_SYSCALLS] = {
[SYS_SEND] = sys_send,
[SYS_RECV] = sys_recv,
[SYS_SOCKSTATE] = sys_sockstate,
[SYS_GFX] = sys_gfx,
};
void syscall_handler(registers_t *regs) {

View File

@@ -32,9 +32,10 @@
#define SYS_SEND 15 /**< Send data on socket. sockfd=EBX, buf=ECX, len=EDX. Returns bytes sent. */
#define SYS_RECV 16 /**< Receive data from socket. sockfd=EBX, buf=ECX, len=EDX. Returns bytes. */
#define SYS_SOCKSTATE 17 /**< Get socket state. sockfd=EBX. Returns state constant. */
#define SYS_GFX 18 /**< Graphics operations. subcmd=EBX, arg1=ECX, arg2=EDX. */
/** Total number of system calls. */
#define NUM_SYSCALLS 18
#define NUM_SYSCALLS 19
/**
* Initialize the system call handler.