Created
April 18, 2012 20:54
-
-
Save drslump/2416484 to your computer and use it in GitHub Desktop.
Fire model effect for ansi terminals
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# coding: utf-8 | |
""" | |
Fire model effect for ansi terminals. | |
Model based on http://freespace.virgin.net/hugo.elias/models/m_fire.htm | |
""" | |
__author__ = "Iván -DrSlump- Montes" | |
__copyright__ = "Public domain" | |
import os, sys, math, signal | |
from random import randint | |
from time import sleep | |
# black, red, light-red, yellow | |
COLORS = ( '0;30', '0;31', '1;31', '0;33' ) | |
DITHS = ( '░', '▒', '█', ) | |
# Build a palette from the colors and dithering characters list | |
palette = [' '] | |
for c in COLORS: | |
for d in DITHS: | |
palette.append( '\x1b[%sm%s' % (c, d) ) | |
#print ''.join(palette) | |
#sys.exit() | |
# Obtain size form the terminal | |
rows, cols = os.popen('stty size', 'r').read().split() | |
rows = int(rows) + 2 # two rows at bottom are only used to generate heat | |
cols = int(cols) | |
# Initialize buffers | |
buffer_a = bytearray(rows*cols) | |
buffer_b = bytearray(rows*cols) | |
map_rows = rows * 3 | |
map_cols = cols | |
map_buff = bytearray(map_rows*map_cols) | |
def box_blur(src, rows, cols, steps = 25): | |
""" Simple box blur implementation """ | |
dst = bytearray(rows*cols) | |
for s in range(steps): | |
for y in range(1, rows-1): | |
ofs = y * cols | |
for x in range(1, cols-1): | |
n1 = src[ ofs + x-1 ] | |
n2 = src[ ofs + x+1 ] | |
n3 = src[ ofs-cols + x ] | |
n4 = src[ ofs+cols + x ] | |
p = (n1+n2+n3+n4) // 4 | |
dst[ofs + x] = p | |
src, dst = dst, src | |
return dst | |
def coolit(from_buf, to_buf, map, map_ofs = 0): | |
for y in range(1, rows-1): | |
ofs = y * cols | |
for x in range(1, cols-1): | |
n1 = from_buf[ ofs + x-1 ] | |
n2 = from_buf[ ofs + x+1 ] | |
n3 = from_buf[ ofs-cols + x ] | |
n4 = from_buf[ ofs+cols + x ] | |
mofs = (map_ofs + y) % map_rows | |
p = (n1+n2+n3+n4) // 4 | |
p -= map[mofs*map_cols + x] / 12 | |
if p < 0: p = 0 | |
to_buf[ (y-1)*cols + x ] = int(p) | |
def render(buf): | |
# Calculate a conversion factor between the buffer and the palette | |
factor = math.ceil(256 / len(palette)) | |
sys.stdout.write('\x1b[2J') | |
for y in range(rows-2): | |
s = '' | |
for x in range(cols): | |
# Obtain the level and convert it to the palette scale | |
level = buf[ y * cols + x ] | |
level = max(1, math.floor(level / factor)) - 1 | |
s += palette[int(level)] | |
sys.stdout.write(s + '\n') | |
sys.stdout.write('\x1b[0m') | |
sys.stdout.flush() | |
# Configure the displacement map | |
for y in range(map_rows): | |
for x in range(map_cols): | |
map_buff[y * map_cols + x] = randint(0, 255) | |
map_buff = box_blur(map_buff, map_rows, map_cols, 15) | |
#render(map_buff) | |
#sys.exit() | |
def sigint_handler(signal, frame): | |
sys.exit() | |
signal.signal(signal.SIGINT, sigint_handler) | |
frame_cnt = 0 | |
while True: | |
# Heat up the bottom lines | |
for x in range(10): | |
col = randint(0, cols-1) | |
p = randint(220, 255) | |
buffer_a[ (rows-2)*cols + col] = p | |
buffer_a[ (rows-1)*cols + col] = p | |
# Cool the fire a bit and render it | |
coolit(buffer_a, buffer_b, map_buff, frame_cnt) | |
render(buffer_b) | |
# swap buffers | |
buffer_a, buffer_b = buffer_b, buffer_a | |
sleep(0.10) | |
frame_cnt += 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment