Reach 3

This example is for Processing version 1.1+. If you have a previous version, use the examples included with your software. If you see any errors or have suggestions, »please let us know.

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, P2D);
  
  // 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();
}