mirror of https://github.com/fairyglade/ly.git
133 lines
3.8 KiB
Zig
133 lines
3.8 KiB
Zig
const std = @import("std");
|
|
const math = std.math;
|
|
|
|
const ly_ui = @import("ly-ui");
|
|
const Cell = ly_ui.Cell;
|
|
const TerminalBuffer = ly_ui.TerminalBuffer;
|
|
const Widget = ly_ui.Widget;
|
|
|
|
const ly_core = ly_ui.ly_core;
|
|
const interop = ly_core.interop;
|
|
const TimeOfDay = interop.TimeOfDay;
|
|
|
|
const ColorMix = @This();
|
|
|
|
const Vec2 = @Vector(2, f32);
|
|
|
|
const time_scale: f32 = 0.01;
|
|
const palette_len: usize = 12;
|
|
|
|
fn length(vec: Vec2) f32 {
|
|
return math.sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
|
|
}
|
|
|
|
instance: ?Widget = null,
|
|
start_time: TimeOfDay,
|
|
terminal_buffer: *TerminalBuffer,
|
|
animate: *bool,
|
|
timeout_sec: u12,
|
|
frame_delay: u16,
|
|
frames: u64,
|
|
pattern_cos_mod: f32,
|
|
pattern_sin_mod: f32,
|
|
palette: [palette_len]Cell,
|
|
|
|
pub fn init(
|
|
terminal_buffer: *TerminalBuffer,
|
|
col1: u32,
|
|
col2: u32,
|
|
col3: u32,
|
|
animate: *bool,
|
|
timeout_sec: u12,
|
|
frame_delay: u16,
|
|
) !ColorMix {
|
|
return .{
|
|
.instance = null,
|
|
.start_time = try interop.getTimeOfDay(),
|
|
.terminal_buffer = terminal_buffer,
|
|
.animate = animate,
|
|
.timeout_sec = timeout_sec,
|
|
.frame_delay = frame_delay,
|
|
.frames = 0,
|
|
.pattern_cos_mod = terminal_buffer.random.float(f32) * math.pi * 2.0,
|
|
.pattern_sin_mod = terminal_buffer.random.float(f32) * math.pi * 2.0,
|
|
.palette = [palette_len]Cell{
|
|
Cell.init(0x2588, col1, col2),
|
|
Cell.init(0x2593, col1, col2),
|
|
Cell.init(0x2592, col1, col2),
|
|
Cell.init(0x2591, col1, col2),
|
|
Cell.init(0x2588, col2, col3),
|
|
Cell.init(0x2593, col2, col3),
|
|
Cell.init(0x2592, col2, col3),
|
|
Cell.init(0x2591, col2, col3),
|
|
Cell.init(0x2588, col3, col1),
|
|
Cell.init(0x2593, col3, col1),
|
|
Cell.init(0x2592, col3, col1),
|
|
Cell.init(0x2591, col3, col1),
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn widget(self: *ColorMix) *Widget {
|
|
if (self.instance) |*instance| return instance;
|
|
self.instance = Widget.init(
|
|
"ColorMix",
|
|
null,
|
|
self,
|
|
null,
|
|
null,
|
|
draw,
|
|
update,
|
|
null,
|
|
calculateTimeout,
|
|
);
|
|
return &self.instance.?;
|
|
}
|
|
|
|
fn draw(self: *ColorMix) void {
|
|
if (!self.animate.*) return;
|
|
|
|
self.frames +%= 1;
|
|
const time: f32 = @as(f32, @floatFromInt(self.frames)) * time_scale;
|
|
|
|
for (0..self.terminal_buffer.width) |x| {
|
|
for (0..self.terminal_buffer.height) |y| {
|
|
const xi: i32 = @intCast(x);
|
|
const yi: i32 = @intCast(y);
|
|
const wi: i32 = @intCast(self.terminal_buffer.width);
|
|
const hi: i32 = @intCast(self.terminal_buffer.height);
|
|
|
|
var uv: Vec2 = .{
|
|
@as(f32, @floatFromInt(xi * 2 - wi)) / @as(f32, @floatFromInt(self.terminal_buffer.height * 2)),
|
|
@as(f32, @floatFromInt(yi * 2 - hi)) / @as(f32, @floatFromInt(self.terminal_buffer.height)),
|
|
};
|
|
|
|
var uv2: Vec2 = @splat(uv[0] + uv[1]);
|
|
|
|
for (0..3) |_| {
|
|
uv2 += uv + @as(Vec2, @splat(length(uv)));
|
|
uv += @as(Vec2, @splat(0.5)) * Vec2{
|
|
math.cos(self.pattern_cos_mod + uv2[1] * 0.2 + time * 0.1),
|
|
math.sin(self.pattern_sin_mod + uv2[0] - time * 0.1),
|
|
};
|
|
uv -= @splat(1.0 * math.cos(uv[0] + uv[1]) - math.sin(uv[0] * 0.7 - uv[1]));
|
|
}
|
|
|
|
const cell = self.palette[@as(usize, @intFromFloat(math.floor(length(uv) * 5.0))) % palette_len];
|
|
cell.put(x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn update(self: *ColorMix, _: *anyopaque) !void {
|
|
const time = try interop.getTimeOfDay();
|
|
|
|
if (self.timeout_sec > 0 and time.seconds - self.start_time.seconds > self.timeout_sec) {
|
|
self.animate.* = false;
|
|
}
|
|
}
|
|
|
|
fn calculateTimeout(self: *ColorMix, _: *anyopaque) !?usize {
|
|
return self.frame_delay;
|
|
}
|