reimplements PSX Doom fire animation; adds flame height control

This commit is contained in:
Matthew Rothlisberger 2025-06-18 09:59:20 -04:00
parent 1bcbb08202
commit ab23631e66
4 changed files with 61 additions and 20 deletions

View File

@ -104,13 +104,20 @@ colormix_col3 = 0x20000000
# Available inputs: info_line, session, login, password # Available inputs: info_line, session, login, password
default_input = login default_input = login
# DOOM animation top color (low intensity flames) # DOOM animation fire height (1 thru 9)
doom_fire_height = 6
# DOOM animation use natural fire colors
# If false, below custom colors used
doom_default_colors = true
# DOOM animation custom top color (low intensity flames)
doom_top_color = 0x00FF0000 doom_top_color = 0x00FF0000
# DOOM animation middle color (medium intensity flames) # DOOM animation custom middle color (medium intensity flames)
doom_middle_color = 0x00FFFF00 doom_middle_color = 0x00FFFF00
# DOOM animation bottom color (high intensity flames) # DOOM animation custom bottom color (high intensity flames)
doom_bottom_color = 0x00FFFFFF doom_bottom_color = 0x00FFFFFF
# Error background color id # Error background color id

View File

@ -11,17 +11,31 @@ pub const STEPS = 12;
allocator: Allocator, allocator: Allocator,
terminal_buffer: *TerminalBuffer, terminal_buffer: *TerminalBuffer,
buffer: []u8, buffer: []u8,
height: u8,
fire: [STEPS + 1]Cell, fire: [STEPS + 1]Cell,
pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u32, middle_color: u32, bottom_color: u32) !Doom { pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, fire_height: u8, default_colors: bool, top_color: u32, middle_color: u32, bottom_color: u32) !Doom {
const buffer = try allocator.alloc(u8, terminal_buffer.width * terminal_buffer.height); const buffer = try allocator.alloc(u8, terminal_buffer.width * terminal_buffer.height);
initBuffer(buffer, terminal_buffer.width); initBuffer(buffer, terminal_buffer.width);
return .{ const levels = if (default_colors)
.allocator = allocator, [_]Cell{
.terminal_buffer = terminal_buffer, Cell.init(' ', TerminalBuffer.Color.DEFAULT, TerminalBuffer.Color.DEFAULT),
.buffer = buffer, Cell.init(0x2591, 0x070707, TerminalBuffer.Color.DEFAULT),
.fire = [_]Cell{ Cell.init(0x2592, 0x470F07, TerminalBuffer.Color.DEFAULT),
Cell.init(0x2593, 0x771F07, TerminalBuffer.Color.DEFAULT),
Cell.init(0x2588, 0xAF3F07, TerminalBuffer.Color.DEFAULT),
Cell.init(0x2591, 0xC74707, 0xAF3F07),
Cell.init(0x2592, 0xDF5707, 0xAF3F07),
Cell.init(0x2593, 0xCF6F0F, 0xAF3F07),
Cell.init(0x2588, 0xC78F17, 0xAF3F07),
Cell.init(0x2591, 0xBF9F1F, 0xAF3F07),
Cell.init(0x2592, 0xBFAF2F, 0xAF3F07),
Cell.init(0x2593, 0xCFCF6F, 0xAF3F07),
Cell.init(0x2588, 0xFFFFFF, 0xAF3F07),
}
else
[_]Cell{
Cell.init(' ', TerminalBuffer.Color.DEFAULT, TerminalBuffer.Color.DEFAULT), Cell.init(' ', TerminalBuffer.Color.DEFAULT, TerminalBuffer.Color.DEFAULT),
Cell.init(0x2591, top_color, TerminalBuffer.Color.DEFAULT), Cell.init(0x2591, top_color, TerminalBuffer.Color.DEFAULT),
Cell.init(0x2592, top_color, TerminalBuffer.Color.DEFAULT), Cell.init(0x2592, top_color, TerminalBuffer.Color.DEFAULT),
@ -35,7 +49,14 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u
Cell.init(0x2592, bottom_color, middle_color), Cell.init(0x2592, bottom_color, middle_color),
Cell.init(0x2593, bottom_color, middle_color), Cell.init(0x2593, bottom_color, middle_color),
Cell.init(0x2588, bottom_color, middle_color), Cell.init(0x2588, bottom_color, middle_color),
}, };
return .{
.allocator = allocator,
.terminal_buffer = terminal_buffer,
.buffer = buffer,
.height = @min(9, fire_height),
.fire = levels,
}; };
} }
@ -57,20 +78,31 @@ fn draw(self: *Doom) void {
for (0..self.terminal_buffer.width) |x| { for (0..self.terminal_buffer.width) |x| {
// We start from 1 so that we always have the topmost line when spreading fire // We start from 1 so that we always have the topmost line when spreading fire
for (1..self.terminal_buffer.height) |y| { for (1..self.terminal_buffer.height) |y| {
// Get current cell // Get index of current cell in fire level buffer
const from = y * self.terminal_buffer.width + x; const from = y * self.terminal_buffer.width + x;
const cell_index = self.buffer[from];
// Spread fire // Generate random datum for fire propagation
const propagate = self.terminal_buffer.random.int(u1); const random = (self.terminal_buffer.random.int(u16) % 10);
const to = from - self.terminal_buffer.width; // Get the line above
self.buffer[to] = if (cell_index > 0) cell_index - propagate else cell_index; // Select semi-random target cell
const to = from -| self.terminal_buffer.width -| (random & 3) + 1;
// Put the cell // Get fire level of current cell
const cell = self.fire[cell_index]; const level_buf_from = self.buffer[from];
cell.put(x, y);
// Choose new fire level and store in level buffer
var level_buf_to = level_buf_from;
if (random >= self.height) level_buf_to -|= 1;
self.buffer[to] = @intCast(level_buf_to);
// Send fire level to terminal buffer
const to_cell = self.fire[level_buf_to];
to_cell.put(x, y);
} }
// Draw bottom line (fire source)
const src_cell = self.fire[STEPS];
src_cell.put(x, self.terminal_buffer.height - 1);
} }
} }

View File

@ -29,6 +29,8 @@ colormix_col1: u32 = 0x00FF0000,
colormix_col2: u32 = 0x000000FF, colormix_col2: u32 = 0x000000FF,
colormix_col3: u32 = 0x20000000, colormix_col3: u32 = 0x20000000,
default_input: Input = .login, default_input: Input = .login,
doom_fire_height: u8 = 6,
doom_default_colors: bool = true,
doom_top_color: u32 = 0x00FF0000, doom_top_color: u32 = 0x00FF0000,
doom_middle_color: u32 = 0x00FFFF00, doom_middle_color: u32 = 0x00FFFF00,
doom_bottom_color: u32 = 0x00FFFFFF, doom_bottom_color: u32 = 0x00FFFFFF,

View File

@ -354,7 +354,7 @@ pub fn main() !void {
animation = dummy.animation(); animation = dummy.animation();
}, },
.doom => { .doom => {
var doom = try Doom.init(allocator, &buffer, config.doom_top_color, config.doom_middle_color, config.doom_bottom_color); var doom = try Doom.init(allocator, &buffer, config.doom_fire_height, config.doom_default_colors, config.doom_top_color, config.doom_middle_color, config.doom_bottom_color);
animation = doom.animation(); animation = doom.animation();
}, },
.matrix => { .matrix => {