summaryrefslogtreecommitdiff
path: root/src/estd/graphics/box.zig
blob: 83868aa297b62a15718598dc280d3ef819aef5f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const std = @import("std");
const graphics = @import("root.zig");

pub const Box = struct {
	const Self = @This();

	x: u32,
	y: u32,
	width: u32,
	height: u32,
	color: graphics.Color,
	radius: u32 = 0,

	fn render_rect(
		self: *const Self,
		x: u32,
		y: u32,
		width: u32,
		height: u32,
		canvas: *const graphics.Canvas
	) void {
		if (x >= canvas.width or y >= canvas.height) {
			return;
		}

		const x_end = @min(x + width, canvas.width);
		const y_end = @min(y + height, canvas.height);

		for (y..y_end) |yp| {
			const offset = yp * canvas.width;
			@memset(
				canvas.buffer[(offset + x)..(offset + x_end)],
				self.color
			);
		}
	}

	pub fn render(self: *const Self, canvas: *const graphics.Canvas) void {
		if (self.radius == 0) {
			self.render_rect(self.x, self.y, self.width, self.height, canvas);
			return;
		}

		const radius = @min(self.radius, self.width / 2, self.height / 2);
		const core_width = self.width - 2 * radius;
		const core_height = self.height - 2 * radius;

		self.render_rect(
			self.x + radius,
			self.y,
			core_width,
			radius,
			canvas
		);

		self.render_rect(
			self.x + radius,
			self.y + radius + core_height,
			core_width,
			radius,
			canvas
		);

		self.render_rect(
			self.x,
			self.y + radius,
			self.width,
			core_height,
			canvas
		);

		for (0..radius) |yp| {
			const width: u32 = @intFromFloat(@round(std.math.sqrt(@as(f64, @floatFromInt(radius * radius - yp * yp)))));
			const spacing = radius - width;

			var offset = ((radius - yp) + self.y) * canvas.width + self.x + spacing;
			@memset(
				canvas.buffer[offset..offset + width],
				self.color
			);

			offset = ((radius - yp) + self.y) * canvas.width + self.x + core_width + radius;
			@memset(
				canvas.buffer[offset..offset + width],
				self.color
			);

			offset = (yp + self.y + radius + core_height) * canvas.width + self.x + spacing;
			@memset(
				canvas.buffer[offset..offset + width],
				self.color
			);

			offset = (yp + self.y + radius + core_height) * canvas.width + self.x + core_width + radius;
			@memset(
				canvas.buffer[offset..offset + width],
				self.color
			);
		}
	}
};