topical media & game development
graphic-processing-site-examples-Topics-Effects-FireCube-FireCube.pde / pde
Fire Cube demo effect
by luis2048.
A rotating wireframe cube with flames rising up the screen.
The fire effect has been used quite often for oldskool demos.
First you create a palette of 256 colors ranging from red to
yellow (including black). For every frame, calculate each row
of pixels based on the two rows below it: The value of each pixel,
becomes the sum of the 3 pixels below it (one directly below, one
to the left, and one to the right), and one pixel directly two
rows below it. Then divide the sum so that the fire dies out as
it rises.
// This will contain the pixels used to calculate the fire effect
int[][] fire;
// Flame colors
color[] palette;
float angle;
int[] calc1,calc2,calc3,calc4,calc5;
PGraphics pg;
void setup(){
size(640, 360, P3D);
// Create buffered image for 3d cube
pg = createGraphics(width, height, P3D);
calc1 = new int[width];
calc3 = new int[width];
calc4 = new int[width];
calc2 = new int[height];
calc5 = new int[height];
colorMode(HSB);
fire = new int[width][height];
palette = new color[255];
// Generate the palette
for(int x = 0; x < palette.length; x++) {
//Hue goes from 0 to 85: red to yellow
//Saturation is always the maximum: 255
//Lightness is 0..255 for x=0..128, and 255 for x=128..255
palette[x] = color(x/3, 255, constrain(x*3, 0, 255));
}
// Precalculate which pixel values to add during animation loop
// this speeds up the effect by 10fps
for (int x = 0; x < width; x++) {
calc1[x] = x % width;
calc3[x] = (x - 1 + width) % width;
calc4[x] = (x + 1) % width;
}
for(int y = 0; y < height; y++) {
calc2[y] = (y + 1) % height;
calc5[y] = (y + 2) % height;
}
}
void draw() {
angle = angle + 0.05;
// Rotating wireframe cube
pg.beginDraw();
pg.translate(width >> 1, height >> 1);
pg.rotateX(sin(angle/2));
pg.rotateY(cos(angle/2));
pg.background(0);
pg.stroke(128);
pg.scale(25);
pg.noFill();
pg.box(4);
pg.endDraw();
// Randomize the bottom row of the fire buffer
for(int x = 0; x < width; x++)
{
fire[x][height-1] = int(random(0,190)) ;
}
loadPixels();
int counter = 0;
// Do the fire calculations for every pixel, from top to bottom
for (int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
// Add pixel values around current pixel
fire[x][y] =
((fire[calc3[x]][calc2[y]]
+ fire[calc1[x]][calc2[y]]
+ fire[calc4[x]][calc2[y]]
+ fire[calc1[x]][calc5[y]]) << 5) / 129;
// Output everything to screen using our palette colors
pixels[counter] = palette[fire[x][y]];
// Extract the red value using right shift and bit mask
// equivalent of red(pg.pixels[x+y*w])
if ((pg.pixels[counter++] >> 16 & 0xFF) == 128) {
// Only map 3D cube 'lit' pixels onto fire array needed for next frame
fire[x][y] = 128;
}
}
}
updatePixels();
}
(C) Æliens
20/2/2008
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.