mirror of
https://codeberg.org/fairyglade/ly.git
synced 2026-08-19 20:14:19 +02:00
feat(doom): add hue shifting to fire colors
Adds the ability to shift the hue of the DOOM fire animation by a configurable amount and rate.
This commit is contained in:
parent
de8579854c
commit
152ee0141c
4 changed files with 115 additions and 0 deletions
|
|
@ -174,6 +174,12 @@ doom_fire_spread = 2
|
|||
# DOOM animation custom top color (low intensity flames)
|
||||
doom_top_color = 0x009F2707
|
||||
|
||||
# DOOM animation delay before shifting hue in miliseconds
|
||||
doom_hue_shift_delay = 100
|
||||
|
||||
# DOOM animation amount of hue shift in degrees [0.0, 360.0]
|
||||
doom_hue_shift_amount = 5
|
||||
|
||||
# DOOM animation custom middle color (medium intensity flames)
|
||||
doom_middle_color = 0x00C78F17
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ buffer: []u8,
|
|||
height: u8,
|
||||
spread: u8,
|
||||
fire: [STEPS + 1]Cell,
|
||||
hue_shift_amount: u16,
|
||||
hue_shift_delay: usize,
|
||||
hue_shift_time: TimeOfDay,
|
||||
|
||||
pub fn init(
|
||||
allocator: Allocator,
|
||||
|
|
@ -39,6 +42,8 @@ pub fn init(
|
|||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
frame_delay: u16,
|
||||
hue_shift_amount: u16,
|
||||
hue_shift_delay: usize,
|
||||
) !Doom {
|
||||
const buffer = try allocator.alloc(u8, terminal_buffer.width * terminal_buffer.height);
|
||||
initBuffer(buffer, terminal_buffer.width);
|
||||
|
|
@ -72,6 +77,96 @@ pub fn init(
|
|||
.height = @min(HEIGHT_MAX, fire_height),
|
||||
.spread = @min(SPREAD_MAX, fire_spread),
|
||||
.fire = levels,
|
||||
.hue_shift_amount = hue_shift_amount,
|
||||
.hue_shift_delay = hue_shift_delay,
|
||||
.hue_shift_time = try interop.getTimeOfDay(),
|
||||
};
|
||||
}
|
||||
|
||||
/// dupdate the fire character array
|
||||
fn update_fire(self: *Doom, top_color: u32, middle_color: u32, bottom_color: u32) void {
|
||||
self.fire = .{
|
||||
Cell.init(' ', self.terminal_buffer.bg, self.terminal_buffer.bg),
|
||||
Cell.init(0x2591, top_color, self.terminal_buffer.bg),
|
||||
Cell.init(0x2592, top_color, self.terminal_buffer.bg),
|
||||
Cell.init(0x2593, top_color, self.terminal_buffer.bg),
|
||||
Cell.init(0x2588, top_color, self.terminal_buffer.bg),
|
||||
Cell.init(0x2591, middle_color, top_color),
|
||||
Cell.init(0x2592, middle_color, top_color),
|
||||
Cell.init(0x2593, middle_color, top_color),
|
||||
Cell.init(0x2588, middle_color, top_color),
|
||||
Cell.init(0x2591, bottom_color, middle_color),
|
||||
Cell.init(0x2592, bottom_color, middle_color),
|
||||
Cell.init(0x2593, bottom_color, middle_color),
|
||||
Cell.init(0x2588, bottom_color, middle_color),
|
||||
};
|
||||
}
|
||||
|
||||
/// Hue shift the fire colours
|
||||
fn shift_hue(self: *Doom) void {
|
||||
var colors = [_]u32{ self.fire[1].fg, self.fire[5].fg, self.fire[9].fg };
|
||||
for (colors, 0..) |color, i| {
|
||||
const r, const g, const b = .{
|
||||
(color & 0x00ff0000) >> 16,
|
||||
(color & 0x0000ff00) >> 8,
|
||||
(color & 0x000000ff),
|
||||
};
|
||||
|
||||
var hue, const saturation, const lightness = rgb_to_hsl(r, g, b);
|
||||
|
||||
hue = @mod(hue + self.hue_shift_amount + 360, 360.0);
|
||||
|
||||
const red, const green, const blue = hsl_to_rgb(hue, saturation, lightness);
|
||||
|
||||
colors[i] = (red << 16 | green << 8 | blue);
|
||||
}
|
||||
self.update_fire(colors[0], colors[1], colors[2]);
|
||||
}
|
||||
|
||||
fn rgb_to_hsl(red: u32, green: u32, blue: u32) struct { f64, f64, f64 } {
|
||||
// Normalise to [0, 1]
|
||||
const r, const g, const b = .{ @as(f64, red) / 255, @as(f64, green) / 255, @as(f64, blue) / 255 };
|
||||
|
||||
const c_max: f64 = @max(r, g, b);
|
||||
const c_min: f64 = @min(r, g, b);
|
||||
const chroma = c_max - c_min;
|
||||
|
||||
const hue = if (chroma == 0)
|
||||
0
|
||||
else if (c_max == r)
|
||||
60.0 * (((g - b) / chroma) + @as(f64, if (g < b) 6 else 0))
|
||||
else if (c_max == g)
|
||||
60.0 * (((b - r) / chroma) + 2)
|
||||
else
|
||||
60.0 * (((r - g) / chroma) + 4);
|
||||
|
||||
const lightness = (c_max + c_min) / 2;
|
||||
const saturation = if (chroma == 0) 0 else chroma / (1 - @abs(2 * lightness - 1));
|
||||
|
||||
return .{ hue, saturation, lightness };
|
||||
}
|
||||
fn hsl_to_rgb(hue: f64, saturation: f64, lightness: f64) struct { u32, u32, u32 } {
|
||||
const c = (1 - @abs(2 * lightness - 1)) * saturation;
|
||||
const x = c * (1 - @abs(@mod((hue / 60.0), 2.0) - 1));
|
||||
const m = lightness - c / 2;
|
||||
|
||||
const red: f64, const green: f64, const blue: f64 = if (hue < 60)
|
||||
.{ c, x, 0.0 }
|
||||
else if (hue < 120)
|
||||
.{ x, c, 0.0 }
|
||||
else if (hue < 180)
|
||||
.{ 0.0, c, x }
|
||||
else if (hue < 240)
|
||||
.{ 0.0, x, c }
|
||||
else if (hue < 300)
|
||||
.{ x, 0.0, c }
|
||||
else
|
||||
.{ c, 0.0, x };
|
||||
|
||||
return .{
|
||||
@trunc((red + m) * 255),
|
||||
@trunc((green + m) * 255),
|
||||
@trunc((blue + m) * 255),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +251,16 @@ fn update(self: *Doom, _: *anyopaque) !void {
|
|||
if (self.timeout_sec > 0 and time.seconds - self.start_time.seconds > self.timeout_sec) {
|
||||
self.animate.* = false;
|
||||
}
|
||||
|
||||
const dt_us =
|
||||
(time.seconds - self.hue_shift_time.seconds) * 1_000_000 +
|
||||
(time.microseconds - self.hue_shift_time.microseconds);
|
||||
if (self.hue_shift_delay > 0 and self.hue_shift_amount > 0) {
|
||||
if (dt_us > self.hue_shift_delay * 1000) {
|
||||
self.shift_hue();
|
||||
self.hue_shift_time = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calculateTimeout(self: *Doom, _: *anyopaque) !?usize {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ doom_fire_spread: u8 = 2,
|
|||
doom_top_color: u32 = 0x00FF0000,
|
||||
doom_middle_color: u32 = 0x00FFFF00,
|
||||
doom_bottom_color: u32 = 0x00FFFFFF,
|
||||
doom_hue_shift_delay: usize = 0,
|
||||
doom_hue_shift_amount: u16 = 0,
|
||||
dur_file_path: []const u8 = build_options.config_directory ++ "/ly/example.dur",
|
||||
dur_offset_alignment: DurOffsetAlignment = .center,
|
||||
dur_x_offset: i32 = 0,
|
||||
|
|
|
|||
|
|
@ -1038,6 +1038,8 @@ pub fn main(init: std.process.Init) !void {
|
|||
&state.animate,
|
||||
state.config.animation_timeout_sec,
|
||||
state.config.animation_frame_delay,
|
||||
state.config.doom_hue_shift_amount,
|
||||
state.config.doom_hue_shift_delay,
|
||||
);
|
||||
animation = doom.widget();
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue