This sketch is created with an older version of Processing,
and doesn't work on browsers anymore.
xxxxxxxxxx
/*
* --=[FIRE]=--
* by Jonsku, March 2010
* http://j-u-t-t-u.net
* --
* This is meant to be a tutorial for the old school fire effect.
* The code is well commented so you can easily add this effect to your own creation.
* It is also to some extent a tool to design the effect which is based on a custom colour palette.
* This implementation is very basic but if you play around with the first rows generation algorithm, and of course the palette you can get very nice results.
* Have fun!
*
* HOW IT WORKS:
* The fire effect is a smoothing of colours going upward: for each pixels, the average colour of its surrounding pixels is calculated,
* and this average is assigned to the pixel on top of it (if the current pixel is at coordinate (10,10) then the average color of 3 to 8 surrounding pixels
* is calculated and then this color is assigned to the pixel at the coordinate(10,9) - remember that the origin is at the top left corner of the window!).
* The fire can easily go in any direction, it is just a matter of deciding to which pixel to assign the averaged color.
*
* To animate the fire, at the begining of each frame a number of rows at the bottom of the buffer are filled with random colours from the palette.
* It is an important part of a good looking fire, it creates nice flames.
*
* The most important part is the colour palette, it tells about the type of fire or magical thingybob that you want to represent.
* That is why I made this palette editing tool. Try a lot of combinations.
* You can save the one you like most for a later time. (See instructions below)
* --
* Use the GUI to modify the palette (works like a simple Photoshup like gradient editor)
* Use the arrow buttons (<< and >>) to move to the previous or next color stop
* Click add/remove to add or remove a color stop at the current position
* Use the Red, Green, Blue and Alpha sliders to control the colour
* SPACE BAR to hide/show the GUI
* 0..9 to load different presets
* p to pause/unpause
* n to toggle between 3 pixels and 8 pixels smoothing
*
* If you run the sketch in Processing you can save your settings in a XML file by pressing 's'. (uncomment line 232)
* Latest saved change will be loaded next time you run the sketch.
*/
import controlP5.*;
//palette controls
Gradient palette;
boolean nice = true;
int currentPreset = 2;
String presetSelection = "0123456789";
Gradient[] presets = new Gradient[10];
ControlP5 controlP5;
boolean showControls = true;
Slider colourSelect;
Slider redSelect;
Slider greenSelect;
Slider blueSelect;
Slider alphaSelect;
controlP5.Button addButton;
controlP5.Button removeButton;
controlP5.Button previousButton;
controlP5.Button nextButton;
FireFX fire;
boolean pause = false;
PImage bg;
void setup(){
size(600,600);
bg = loadImage("juttu.png");
//load palette presets from an XML file
loadFromFile("presets.xml");
palette = presets[currentPreset];
//initialize the GUI
initControls();
//create a fire generated by 5 rows of random colors
fire = new FireFX(0,5);
}
void draw(){
//the background helps to see the effect of transparency in the palette
background(0);
image(bg,width/2-bg.width/2,height-bg.height);
//calculate a new frame
if(!pause)
fire.animateFire();
//draw the buffer where the effect is calculated
fire.draw(0, 0);
//show GUI
if(showControls){
palette.draw(20,20);
drawSelectedColor(300,20);
}
}
/* THE FOLLOWING METHODS ARE USED TO CONTROL THE PALETTE EDITOR
*
* Boring stuff, I won't go into details
*/
void initControls(){
controlP5 = new ControlP5(this);
controlP5.setColorLabel(color(0));
//slider to select a colour in the palette
colourSelect = controlP5.addSlider("Index select",1,256,0,20,100,256,30);
previousButton = controlP5.addButton("<<",1,20,130,20,20);
nextButton = controlP5.addButton(">>",1,256,130,20,20);
//used to set RGBA values for current colour stop in the gradient
redSelect = controlP5.addSlider("Red",0,255,0,20,170,256,30);
greenSelect = controlP5.addSlider("Green",0,255,0,20,220,256,30);
blueSelect = controlP5.addSlider("Blue",0,255,0,20,270,256,30);
alphaSelect = controlP5.addSlider("Alpha",0,255,0,20,320,256,30);
redSelect.captionLabel().setColor(color(255,0,0));
redSelect.captionLabel().style().marginLeft = -30;
greenSelect.captionLabel().setColor(color(0,255,0));
greenSelect.captionLabel().style().marginLeft = -30;
blueSelect.captionLabel().setColor(color(0,0,255));
blueSelect.captionLabel().style().marginLeft = -30;
alphaSelect.captionLabel().style().marginLeft = -30;
//add/remove colour stop buttons
addButton = controlP5.addButton("Add Colour", 1, 400, 20, 100, 30);
removeButton = controlP5.addButton("Remove Colour",1, 400, 20, 100, 30);
addButton.hide();
removeButton.hide();
}
void controlEvent(ControlEvent theEvent) {
if(theEvent.controller() == colourSelect ) {
if(palette.isColourStop(((int)colourSelect.value())-1)){
//show the color adjust slider
redSelect.show();
greenSelect.show();
blueSelect.show();
alphaSelect.show();
int colIndex = ((int)colourSelect.value())-1;
addButton.hide();
removeButton.hide();
if(colIndex > 0 && colIndex<palette.size()-1){
removeButton.show();
}
int c = palette.getColourAt(colIndex);
redSelect.setValue(c>> 16 & 0xFF);
greenSelect.setValue(c>> 8 & 0xFF);
blueSelect.setValue(c & 0xFF);
alphaSelect.setValue(alpha(c));
}
else{
//hide the color adjust slider
redSelect.hide();
greenSelect.hide();
blueSelect.hide();
alphaSelect.hide();
int colIndex = ((int)colourSelect.value())-1;
addButton.hide();
removeButton.hide();
if(colIndex > 0 && colIndex<palette.size()-1){
addButton.show();
}
}
return;
}
if(theEvent.controller() == redSelect || theEvent.controller() == greenSelect || theEvent.controller() == blueSelect || theEvent.controller() == alphaSelect) {
palette.setColour(((int)colourSelect.value())-1, color((int)redSelect.value(),(int)greenSelect.value(),(int)blueSelect.value(),(int)alphaSelect.value()));
return;
}
if(theEvent.controller() == removeButton){
palette.removeColour(((int)colourSelect.value())-1);
//hide the color adjust slider
redSelect.hide();
greenSelect.hide();
blueSelect.hide();
alphaSelect.hide();
removeButton.hide();
addButton.show();
return;
}
if(theEvent.controller() == addButton){
int colIndex = ((int)colourSelect.value())-1;
palette.setColour(colIndex, palette.getColourAt(colIndex));
//show the color adjust slider
redSelect.show();
greenSelect.show();
blueSelect.show();
alphaSelect.show();
addButton.hide();
removeButton.hide();
if(colIndex > 0 && colIndex<palette.size()-1){
removeButton.show();
}
int c = palette.getColourAt(colIndex);
redSelect.setValue(c>> 16 & 0xFF);
greenSelect.setValue(c>> 8 & 0xFF);
blueSelect.setValue(c & 0xFF);
alphaSelect.setValue(alpha(c));
return;
}
if(theEvent.controller() == previousButton){
colourSelect.setValue(palette.getPreviousStop(((int)colourSelect.value())-1)+1);
return;
}
if(theEvent.controller() == nextButton){
colourSelect.setValue(palette.getNextStop(((int)colourSelect.value())-1)+1);
return;
}
}
void keyPressed(){
int pr = presetSelection.indexOf(key);
if(pr>=0){
currentPreset = pr;
palette = presets[currentPreset];
return;
}
switch(key){
case 'n':
nice = !nice;
break;
case 'p':
pause = !pause;
break;
case 's':
//saveToFile("presets.xml");
break;
case 'l':
loadFromFile("presets.xml");
break;
case ' ':
showControls = !showControls;
if(showControls){
controlP5.show();
}else{
controlP5.hide();
}
break;
}
}
//display the selected color in a rectangle, with a checker pattern underneath
void drawSelectedColor(int x, int y){
pushStyle();
noStroke();
//draw the checker pattern
for(int iX=0;iX<10;iX++){
for(int iY=0;iY<10;iY++){
if((iX+iY)%2==0)
fill(100);
else
fill(255);
rect(x+iX*8,y+iY*8,8,8);
}
}
stroke(255);
strokeWeight(3);
fill(palette.getColourAt(((int)colourSelect.value())-1));
rect(x,y,80,80);
popStyle();
}
//load palette presets from XML file
void loadFromFile(String fileName){
System.out.println("Fire says > Loading palette presets from "+fileName);
XMLElement xml;
xml = new XMLElement(this, fileName);
int numPresets = xml.getChildCount();
presets = new Gradient[numPresets];
for (int i = 0; i < numPresets; i++) {
XMLElement preset = xml.getChild(i);
presets[i] = new Gradient();
//not in use for now (fixed palette size)
int numberOfColors = preset.getIntAttribute("numberOfColors");
int numStops = preset.getChildCount();
for (int j = 0; j < numStops; j++) {
XMLElement stop = preset.getChild(j);
presets[i].setColour(stop.getIntAttribute("position"), Integer.parseInt(stop.getContent()));
}
}
palette = presets[currentPreset];
}
//save palette presets from XML file
void saveToFile(String fileName){
System.out.println("Fire says > Saving palette presets to "+fileName);
PrintWriter output = createWriter(fileName);
output.println("<?xml version=\"1.0\"?>");
output.println("<palettepreset>");
for(int i=0;i<presets.length;i++){
output.println(presets[i].toXML());
}
output.println("</palettepreset>");
output.flush(); // Writes the remaining data to the file
output.close();
}
void mousePressed() {
// mouseEvent variable contains the current event information
if (mouseEvent.getClickCount()==2) fire.juttu(mouseX,mouseY);
}