├── README.textile └── fire.rb /README.textile: -------------------------------------------------------------------------------- 1 | h2. Fire in Ruby Processing 2 | 3 | This code draws fire with a simple algorithm in "Ruby Processing":http://wiki.github.com/jashkenas/ruby-processing 4 | 5 | !http://dl.getdropbox.com/u/221414/blogs/burn_baby.png! 6 | 7 | Here's a video: "Fire video":http://screencast.com/t/69TnHrKqG4 8 | 9 | h3. Algorithm: 10 | 11 | 1. Create an indexed palette of red, orange and yellows 12 | 13 | 2. Loop over the following: 14 | 15 | * Draw a random set of colours from the palette at the bottom of the screen 16 | * Loop through each pixel and average the colour index value around it 17 | * Reduce the average by a fire intensity factor 18 | 19 | -------------------------------------------------------------------------------- /fire.rb: -------------------------------------------------------------------------------- 1 | # Fire 2 | 3 | # Algorithm: 4 | # 1. Create an indexed palette of red, orange and yellows 5 | # 2. Loop: 6 | # 3. Draw a random set of colours from the palette at the bottom of the screen 7 | # 4. Loop through each pixel and average the colour index value around it 8 | # 5. Reduce the average by a fire intensity factor 9 | 10 | # rp5 run fire.rb 11 | 12 | class Fire < Processing::App 13 | 14 | def setup 15 | color_mode RGB, 255 16 | background 0 17 | frame_rate 30 18 | 19 | @palette = make_palette 20 | @fire = [] 21 | 22 | @scale = 8 23 | @width = width / @scale 24 | @height = height / @scale 25 | 26 | @intensity = 2 27 | end 28 | 29 | def draw 30 | update_fire 31 | end 32 | 33 | def update_fire 34 | random_line @height - 1 35 | (0..@height - 2).each do |y| 36 | (0..@width).each do |x| 37 | # Wrap 38 | left = (x == 0) ? fire_data(@width - 1, y) : fire_data(x - 1, y) 39 | right = (x == @width - 1) ? fire_data(0, y) : fire_data(x + 1, y) 40 | below = fire_data(x, y + 1) 41 | 42 | # Get the average pixel value 43 | average = (left.to_i + right.to_i + (below.to_i * 2)) / 4 44 | 45 | # Fade the flames 46 | average -= @intensity if average > @intensity 47 | 48 | set_fire_data x, y, average 49 | 50 | fill color(*@palette[average]) 51 | stroke color(*@palette[average]) 52 | 53 | rect x * @scale, (y + 1) * @scale, @scale, @scale 54 | end 55 | end 56 | end 57 | 58 | def fire_data(x, y) 59 | @fire[offset(x, y)] 60 | end 61 | 62 | def set_fire_data(x, y, value) 63 | @fire[offset(x, y)] = value 64 | end 65 | 66 | def make_palette 67 | palette = [] 68 | # Create the bands of colour for the palette (256 is the maximum colour) 69 | limit = 64 70 | multiplier = 256 / limit 71 | (0..limit).each do |i| 72 | # Range of reds 73 | palette[i] = [i * multiplier, 0, 0] 74 | # Orange 75 | palette[i + limit] = [255, i * multiplier, 0] 76 | # Yellow 77 | palette[i + limit * 2] = [255, 255, i * multiplier] 78 | # Also try making this white, I prefer a strong red (in wine terms too) 79 | palette[i + limit * 3] = [180, 0, 0] 80 | end 81 | palette 82 | end 83 | 84 | def random_colour 85 | color *@palette[rand(@palette.size)] 86 | end 87 | 88 | def random_offset 89 | rand @palette.size 90 | end 91 | 92 | def random_line(y) 93 | (0..@width - 1).each do |x| 94 | @fire[offset(x, y)] = random_offset 95 | end 96 | end 97 | 98 | def offset(x, y) 99 | (y * @width) + x 100 | end 101 | end 102 | 103 | Fire.new :title => "Fire", :width => 320, :height => 240 104 | --------------------------------------------------------------------------------