feat: Intel GPU fixes, add tcc compiler, spreadsheet improvements, paint app, file manager improvements

This commit is contained in:
2026-03-21 17:35:16 +01:00
parent 2fd9b7d027
commit 770dde5001
72 changed files with 45499 additions and 305 deletions
+238
View File
@@ -0,0 +1,238 @@
/*
* drawing.cpp
* Canvas drawing operations for Paint app
* Copyright (c) 2026 Daniel Hammer
*/
#include "paint.h"
// ============================================================================
// Basic canvas operations
// ============================================================================
void canvas_put_pixel(int x, int y, Color c) {
if (x < 0 || x >= g_canvas_w || y < 0 || y >= g_canvas_h) return;
g_canvas[y * g_canvas_w + x] = c.to_pixel();
}
void canvas_clear(Color c) {
uint32_t v = c.to_pixel();
int total = g_canvas_w * g_canvas_h;
for (int i = 0; i < total; i++)
g_canvas[i] = v;
}
// ============================================================================
// Brush (filled circle stamp)
// ============================================================================
void canvas_draw_brush(int cx, int cy, Color c, int size) {
if (size <= 1) {
canvas_put_pixel(cx, cy, c);
return;
}
int r = size / 2;
int r2 = r * r;
for (int dy = -r; dy <= r; dy++)
for (int dx = -r; dx <= r; dx++)
if (dx * dx + dy * dy <= r2)
canvas_put_pixel(cx + dx, cy + dy, c);
}
// ============================================================================
// Bresenham line
// ============================================================================
void canvas_draw_line(int x0, int y0, int x1, int y1, Color c, int thickness) {
int dx = x1 - x0;
int dy = y1 - y0;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
while (true) {
canvas_draw_brush(x0, y0, c, thickness);
if (x0 == x1 && y0 == y1) break;
int e2 = 2 * err;
if (e2 > -dy) { err -= dy; x0 += sx; }
if (e2 < dx) { err += dx; y0 += sy; }
}
}
// ============================================================================
// Rectangle
// ============================================================================
void canvas_draw_rect(int x0, int y0, int x1, int y1, Color c, int thickness) {
if (x0 > x1) { int t = x0; x0 = x1; x1 = t; }
if (y0 > y1) { int t = y0; y0 = y1; y1 = t; }
for (int t = 0; t < thickness; t++) {
for (int x = x0 + t; x <= x1 - t; x++) {
canvas_put_pixel(x, y0 + t, c);
canvas_put_pixel(x, y1 - t, c);
}
for (int y = y0 + t; y <= y1 - t; y++) {
canvas_put_pixel(x0 + t, y, c);
canvas_put_pixel(x1 - t, y, c);
}
}
}
void canvas_fill_rect(int x0, int y0, int x1, int y1, Color c) {
if (x0 > x1) { int t = x0; x0 = x1; x1 = t; }
if (y0 > y1) { int t = y0; y0 = y1; y1 = t; }
for (int y = y0; y <= y1; y++)
for (int x = x0; x <= x1; x++)
canvas_put_pixel(x, y, c);
}
// ============================================================================
// Ellipse (midpoint algorithm)
// ============================================================================
static void ellipse_plot4(int cx, int cy, int x, int y, Color c, int thickness) {
if (thickness <= 1) {
canvas_put_pixel(cx + x, cy + y, c);
canvas_put_pixel(cx - x, cy + y, c);
canvas_put_pixel(cx + x, cy - y, c);
canvas_put_pixel(cx - x, cy - y, c);
} else {
canvas_draw_brush(cx + x, cy + y, c, thickness);
canvas_draw_brush(cx - x, cy + y, c, thickness);
canvas_draw_brush(cx + x, cy - y, c, thickness);
canvas_draw_brush(cx - x, cy - y, c, thickness);
}
}
void canvas_draw_ellipse(int x0, int y0, int x1, int y1, Color c, int thickness) {
if (x0 > x1) { int t = x0; x0 = x1; x1 = t; }
if (y0 > y1) { int t = y0; y0 = y1; y1 = t; }
int cx = (x0 + x1) / 2;
int cy = (y0 + y1) / 2;
int a = (x1 - x0) / 2;
int b = (y1 - y0) / 2;
if (a == 0 || b == 0) {
canvas_draw_line(x0, y0, x1, y1, c, thickness);
return;
}
long long a2 = (long long)a * a;
long long b2 = (long long)b * b;
int x = 0, y = b;
long long d1 = b2 - a2 * b + a2 / 4;
while (a2 * y > b2 * x) {
ellipse_plot4(cx, cy, x, y, c, thickness);
if (d1 < 0) {
d1 += b2 * (2 * x + 3);
} else {
d1 += b2 * (2 * x + 3) + a2 * (-2 * y + 2);
y--;
}
x++;
}
long long d2 = b2 * ((long long)(x * 2 + 1) * (x * 2 + 1)) / 4
+ a2 * ((long long)(y - 1) * (y - 1))
- a2 * b2;
while (y >= 0) {
ellipse_plot4(cx, cy, x, y, c, thickness);
if (d2 > 0) {
d2 += a2 * (-2 * y + 3);
} else {
d2 += b2 * (2 * x + 2) + a2 * (-2 * y + 3);
x++;
}
y--;
}
}
void canvas_fill_ellipse(int x0, int y0, int x1, int y1, Color c) {
if (x0 > x1) { int t = x0; x0 = x1; x1 = t; }
if (y0 > y1) { int t = y0; y0 = y1; y1 = t; }
int cx = (x0 + x1) / 2;
int cy = (y0 + y1) / 2;
int a = (x1 - x0) / 2;
int b = (y1 - y0) / 2;
if (a == 0 || b == 0) return;
for (int dy = -b; dy <= b; dy++) {
// x^2/a^2 + y^2/b^2 <= 1 => x <= a * sqrt(1 - y^2/b^2)
long long x_extent = (long long)a * a * ((long long)b * b - (long long)dy * dy);
if (x_extent < 0) continue;
// Integer sqrt approximation
long long denom = (long long)b * b;
int w = 0;
while ((long long)(w + 1) * (w + 1) * denom <= x_extent) w++;
for (int dx = -w; dx <= w; dx++)
canvas_put_pixel(cx + dx, cy + dy, c);
}
}
// ============================================================================
// Flood fill (iterative scanline)
// ============================================================================
void canvas_flood_fill(int sx, int sy, Color fill_color) {
if (sx < 0 || sx >= g_canvas_w || sy < 0 || sy >= g_canvas_h) return;
uint32_t target = g_canvas[sy * g_canvas_w + sx];
uint32_t fill_px = fill_color.to_pixel();
if (target == fill_px) return;
// Simple stack-based flood fill with a bounded stack
static constexpr int STACK_MAX = 65536;
struct Pt { int16_t x, y; };
Pt* stack = (Pt*)montauk::malloc(STACK_MAX * sizeof(Pt));
if (!stack) return;
int sp = 0;
stack[sp++] = {(int16_t)sx, (int16_t)sy};
g_canvas[sy * g_canvas_w + sx] = fill_px;
while (sp > 0) {
Pt p = stack[--sp];
int x = p.x, y = p.y;
// Scan left
int left = x;
while (left > 0 && g_canvas[y * g_canvas_w + left - 1] == target) {
left--;
g_canvas[y * g_canvas_w + left] = fill_px;
}
// Scan right
int right = x;
while (right < g_canvas_w - 1 && g_canvas[y * g_canvas_w + right + 1] == target) {
right++;
g_canvas[y * g_canvas_w + right] = fill_px;
}
// Check above and below
for (int dir = -1; dir <= 1; dir += 2) {
int ny = y + dir;
if (ny < 0 || ny >= g_canvas_h) continue;
bool in_span = false;
for (int px = left; px <= right; px++) {
if (g_canvas[ny * g_canvas_w + px] == target) {
if (!in_span && sp < STACK_MAX) {
g_canvas[ny * g_canvas_w + px] = fill_px;
stack[sp++] = {(int16_t)px, (int16_t)ny};
in_span = true;
}
} else {
in_span = false;
}
}
}
}
montauk::mfree(stack);
}