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: u64 = @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] = self.color.mix(&previous_color, factor); previous_color = canvas.buffer[canvas.width * x + y + 1]; canvas.buffer[x * canvas.width + y + 1] = previous_color.mix(&self.color, factor); intersect_y += gradient; } } else { for (start.x..end.x + 1) |x| { const y: u64 = @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] = self.color.mix(&previous_color, factor); previous_color = canvas.buffer[x + canvas.width * (y + 1)]; canvas.buffer[x + canvas.width * (y + 1)] = previous_color.mix(&self.color, factor); intersect_y += gradient; } } } };