diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-02-12 12:48:11 +0100 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-02-12 12:48:11 +0100 |
| commit | 9fd81c0b38b2b843c24fb61bf8cb5b7873deaa72 (patch) | |
| tree | a2d4d76a4fcc1334d83c5538e684061913be24d3 /src/estd/graphics/line.zig | |
| parent | dae5bc02b1c934075e95694953b4330676e21611 (diff) | |
graphics: add line
Diffstat (limited to 'src/estd/graphics/line.zig')
| -rw-r--r-- | src/estd/graphics/line.zig | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/estd/graphics/line.zig b/src/estd/graphics/line.zig new file mode 100644 index 0000000..93f17ff --- /dev/null +++ b/src/estd/graphics/line.zig @@ -0,0 +1,76 @@ +const std = @import("std"); +const graphics = @import("root.zig"); + +pub const Line = struct { + const Self = @This(); + const Point = struct { + x: u32, + y: u32, + }; + + start: Point, + end: Point, + + color: graphics.Color, + + fn distance(a: u32, b: u32) u32 { + if (a < b) { + return b - a; + } else { + return a - b; + } + } + + pub fn render(self: *const Self, canvas: *const graphics.Canvas) void { + var start = self.start; + var end = self.end; + const steep = distance(start.y, end.y) > distance(start.x, end.x); + + if (steep) { + std.mem.swap(u32, &start.x, &start.y); + std.mem.swap(u32, &end.x, &end.y); + } + + if (start.x > end.x) { + std.mem.swap(Point, &start, &end); + } + + const dx: f64 = @floatFromInt(end.x - start.x); + const dy: f64 = @floatFromInt(@as(i64, @intCast(end.y)) - @as(i64, @intCast(start.y))); + var gradient: f64 = dy / dx; + if (dx == 0) { + gradient = 1; + } + + + var intersect_y: f64 = @floatFromInt(start.y); + + if (steep) { + for (start.x..end.x + 1) |x| { + const y: usize = @intFromFloat(intersect_y); + const factor = intersect_y - @as(f64, @floatFromInt(y)); + + var previous_color = canvas.buffer[canvas.width * x + y]; + canvas.buffer[x * canvas.width + y] = previous_color.mix(&self.color, factor); + + previous_color = canvas.buffer[x * canvas.width + y - 1]; + canvas.buffer[x * canvas.width + y - 1] = self.color.mix(&previous_color, factor); + + intersect_y += gradient; + } + } else { + for (start.x..end.x + 1) |x| { + const y: u32 = @intFromFloat(intersect_y); + const factor = intersect_y - @as(f64, @floatFromInt(y)); + + var previous_color = canvas.buffer[x + canvas.width * y]; + canvas.buffer[x + canvas.width * y] = previous_color.mix(&self.color, factor); + + previous_color = canvas.buffer[x + canvas.width * (y - 1)]; + canvas.buffer[x + canvas.width * (y - 1)] = self.color.mix(&previous_color, factor); + + intersect_y += gradient; + } + } + } +}; |