colors, rotations, and more

This commit is contained in:
2024-10-11 00:58:24 -04:00
parent e29f27266a
commit 823a8f79d3
9 changed files with 367 additions and 149 deletions

View File

@@ -1,107 +1,110 @@
draw :: (screen: *Screen, x: s64, y: s64, char: PIXEL_CHAR = .PIXEL_SOLID, color: COLOR = .FG_WHITE) {
using screen;
if x >= 0 && x < width && y >= 0 && y < height {
buffer[y * width + x].char = char;
buffer[y * width + x].color = color;
// "Squashes" two dimensional coordinates onto the one dimensional screen buffer
draw :: (using screen: *Screen, p: Vec2s64, char: u8 = DEFAULT_PIXEL_CHAR) {
if p.x >= 0 && p.x < width && p.y >= 0 && p.y < height {
buffer[p.y * width + p.x] = cast(u8)char;
}
}
draw_line :: (screen: *Screen, x1: s64, y1: s64, x2: s64, y2: s64, char: PIXEL_CHAR = .PIXEL_SOLID, color: COLOR = .FG_WHITE) {
x, y, dx, dy, dx1, dy1, xe, ye, px, py : s64;
// Implementation of the Bresenham line algorithm
// https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
draw_line :: (screen: *Screen, p1: Vec2s64, p2: Vec2s64, char: u8 = DEFAULT_PIXEL_CHAR) {
p1_c := p1;
p2_c := p2;
dx = x2 - x1;
dy = y2 - y1;
// p1_c.y /= 2;
// p2_c.y /= 2;
dx1 = abs(dx);
dy1 = abs(dy);
dx := abs(p2_c.x - p1_c.x);
dy := -abs(p2_c.y - p1_c.y);
sx := ifx p1_c.x < p2_c.x then 1 else -1;
sy := ifx p1_c.y < p2_c.y then 1 else -1;
px = 2 * dy1 - dx1;
py = 2 * dx1 - dy1;
err := dx + dy;
e2 : s64;
if dy1 <= dx1 {
if dx >= 0 {
x = x1;
y = y1;
xe = x2;
} else {
x = x2;
y = y2;
xe = x1;
while true {
draw(screen, Vec2s64.{p1_c.x, p1_c.y}, char);
if p1_c.x == p2_c.x && p1_c.y == p2_c.y then break;
e2 = 2 * err;
if e2 >= dy {
err += dy;
p1_c.x += sx;
}
draw(screen, x, y, char, color);
for 0..xe {
x = x + 1;
if px < 0 {
px = px + 2 * dy1;
} else {
if (dx < 0 && dy < 0) || (dx > 0 && dy > 0) then y = y + 1; else y = y - 1;
px = px + 2 * (dy1 - dx1);
}
draw(screen, x, y, char, color);
}
} else {
if dy >= 0 {
x = x1;
y = y1;
ye = y2;
} else {
x = x2;
y = y2;
ye = y1;
}
draw(screen, x, y, char, color);
for 0..ye {
y = y + 1;
if py <= 0 {
py = py + 2 * dx1;
} else {
if (dx < 0 && dy < 0 ) || (dx > 0 && dy > 0) then x = x + 1; else x = x - 1;
py = py + 2 * (dx1 - dy1);
}
draw(screen, x, y, char, color);
if e2 <= dx {
err += dx;
p1_c.y += sy;
}
}
}
draw_triangle :: (screen: *Screen, x1: s64, y1: s64, x2: s64, y2: s64, x3: s64, y3: s64, char: PIXEL_CHAR = .PIXEL_SOLID, color: COLOR = .FG_WHITE) {
draw_line(x1, y1, x2, y2, char, color);
draw_line(x2, y2, x3, y3, char, color);
draw_line(x3, y3, x1, y1, char, color);
draw_triangle :: (screen: *Screen, p1: Vec2s64, p2: Vec2s64, p3: Vec2s64, char: u8 = DEFAULT_PIXEL_CHAR) {
draw_line(screen, p1, p2, char);
draw_line(screen, p2, p3, char);
draw_line(screen, p3, p1, char);
}
clip :: (screen: *Screen, x: *s64, y: *s64) {
using screen;
if x.* < 0 then x.* = 0;
if x.* >= width then x.* = width;
if y.* < 0 then y.* = 0;
if y.* >= height then y.* = height;
draw_triangle :: (screen: *Screen, t: Triangle, char: u8 = DEFAULT_PIXEL_CHAR) {
draw_triangle(screen, t.p1, t.p2, t.p3, char);
}
fill :: (screen: *Screen, x1: s64, y1: s64, x2: s64, y2: s64, char: PIXEL_CHAR = .PIXEL_SOLID, color: COLOR = .FG_WHITE) {
clip(screen, *x1, *y1);
clip(screen, *x2, *y2);
draw_quad :: (screen: *Screen, p1: Vec2s64, p2: Vec2s64, char: u8 = DEFAULT_PIXEL_CHAR) {
// (x1, y1) => top left
// (x2, y2) => bottom right
for x: x1..x2 {
for y: y1..y2 {
draw(screen, x, y, char, color);
draw_line(screen, .{p1.x, p1.y}, .{p1.x, p2.y}, char);
draw_line(screen, .{p1.x, p2.y}, .{p2.x, p2.y}, char);
draw_line(screen, .{p2.x, p2.y}, .{p2.x, p1.y}, char);
draw_line(screen, .{p2.x, p1.y}, .{p1.x, p1.y}, char);
}
draw_quad :: (screen: *Screen, p1: Vec2s64, p2: Vec2s64, p3: Vec2s64, p4: Vec2s64, char: u8 = DEFAULT_PIXEL_CHAR) {
// (x1, y1) => top left
// (x2, y2) => bottom left
// (x3, y3) => bottom right
// (x4, y4) => top right
draw_line(screen, .{p1.x, p1.y}, .{p2.x, p2.y}, char);
draw_line(screen, .{p2.x, p2.y}, .{p3.x, p3.y}, char);
draw_line(screen, .{p3.x, p3.y}, .{p4.x, p4.y}, char);
draw_line(screen, .{p4.x, p4.y}, .{p1.x, p1.y}, char);
}
draw_quad :: (screen: *Screen, q: Quad, char: u8 = DEFAULT_PIXEL_CHAR) {
draw_quad(screen, q.p1, q.p2, q.p3, q.p4, char);
}
draw_text :: (using screen: *Screen, p: Vec2s64, s: string) {
if p.x >= 0 && p.x < width && p.y >= 0 && p.y < height {
for cast([]u8)s {
buffer[(p.y * width + p.x) + it_index] = it;
}
}
}
fill_entire_screen :: (screen: *Screen, char: PIXEL_CHAR = .PIXEL_SOLID, color: COLOR = .BG_BLACK) {
fill(screen, 0, 0, screen.width, screen.height, char, color);
// When attempting to draw outside of the visible screen, "clip" the pixels
// by setting their position to the maximum width / height available
clip :: (using screen: *Screen, p: *Vec2s64) {
if p.x < 0 then p.x = 0;
if p.x >= width then p.x = width;
if p.y < 0 then p.y = 0;
if p.y >= height then p.y = height;
}
draw_string :: (screen: *Screen, x: s64, y: s64, text: string, c: COLOR = .FG_WHITE) {
assert(false, "not implemented");
fill :: (screen: *Screen, p1: Vec2s64, p2: Vec2s64, char: u8 = DEFAULT_PIXEL_CHAR) {
clip(screen, *p1);
clip(screen, *p2);
for x: p1.x..p2.x {
for y: p1.y..p2.y {
draw(screen, .{x, y}, char);
}
}
}
fill_entire_screen :: (screen: *Screen, char: u8 = DEFAULT_PIXEL_CHAR) {
fill(screen, .{0,0}, .{screen.width, screen.height}, char);
}