-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathember.c
More file actions
96 lines (84 loc) · 2.56 KB
/
Copy pathember.c
File metadata and controls
96 lines (84 loc) · 2.56 KB
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
/*
* ember.c - DOOM-style PSX fire effect in the terminal
*
* Implements the classic PSX DOOM fire algorithm: every cell
* above the bottom row takes its value from a randomly-chosen
* cell below, minus a small random decay. The bottom row is
* fixed at maximum intensity (the heat source).
*
* Rendering uses ANSI 256-color background codes so each cell
* becomes a solid colored pixel in the terminal.
*
* Build: gcc ember.c -o ember
* Run: ./ember
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#define WIDTH 80
#define HEIGHT 28
/* Fire palette as ANSI 256-color codes.
* Index 0 = black (no fire), last index = white hot. */
static const int palette[] = {
16, /* black */
52, /* deepest red */
88,
124,
160,
196, /* bright red */
202, /* red-orange */
208,
214,
220,
226, /* yellow */
227,
228,
229,
230,
231 /* white */
};
#define PALETTE_SIZE (int)(sizeof(palette) / sizeof(palette[0]))
int main(void) {
unsigned char fire[WIDTH * HEIGHT];
memset(fire, 0, sizeof fire);
/* Light the bottom row - this is the heat source */
for (int x = 0; x < WIDTH; x++) {
fire[(HEIGHT - 1) * WIDTH + x] = PALETTE_SIZE - 1;
}
/* Seed RNG */
srand((unsigned)time(NULL));
/* Hide cursor + clear screen */
printf("\x1b[?25l\x1b[2J");
for (;;) {
/* Propagate fire upward.
* For each row except the bottom, each cell takes its
* value from a random neighbor on the row BELOW it,
* minus a small random decay. */
for (int y = HEIGHT - 1; y > 0; y--) {
for (int x = 0; x < WIDTH; x++) {
int drift = (rand() % 3) - 1; /* -1, 0, or +1 */
int sx = x + drift;
if (sx < 0) sx = 0;
if (sx >= WIDTH) sx = WIDTH - 1;
int src = fire[y * WIDTH + sx];
int decay = rand() % 3; /* 0, 1, or 2 */
int val = src - decay;
if (val < 0) val = 0;
fire[(y - 1) * WIDTH + x] = (unsigned char)val;
}
}
/* Render frame */
printf("\x1b[H");
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int v = fire[y * WIDTH + x];
printf("\x1b[48;5;%dm ", palette[v]);
}
printf("\x1b[0m\n");
}
usleep(40000);
}
return 0;
}