/**
SPACE : cycla genom verktygen.
G : visa quadtree
P : pausa simulationen.
K : komprimera quadtree:et
F : ny brusig terräng.
V : ny konstant terräng.
A,Z : manipulera kompressionsgraden.
S,X : manipulera eldens livslängd.
D,C : manipulera eldens spridning.
*/
Node fire;
PFont font;
boolean showGrid = false;
boolean paused = false;
int timer = 0;
int compression = 16;
int fireGrowth = 4;
float fireSpread = 0.125;
float[][] flammability;
int tool = 0;
final int FIRE=0, MORE_FUEL=1, LESS_FUEL=2;
final String[] TOOL_NAMES = new String[]{"start fire","more fuel","less fuel"};
//-------------------------
void setup(){
size(256,276);
font = loadFont("Silkscreen-8.vlw");
textFont( font );
fire = new Node(0,0,width);
flammability = new float[width][width];
randomFlammability();
frameRate(60);
}
//-------------------------
void draw(){
if(!paused) update();
loadPixels();
fire.draw();
if(showGrid) fire.drawBoundaries( color(128) );
updatePixels();
fill(0);
noStroke();
rect(0,width,width,height-width);
fill(255);
textAlign(LEFT);
text( "burn speed: "+fireGrowth ,5, height-12);
text( memoryUsage() ,5, height-2);
textAlign(RIGHT);
text( fireSpread+" :fire spread" ,width-2, height-12);
text( fireAmount() ,width-2, height-2);
textAlign(CENTER);
text( TOOL_NAMES[tool],width/2, height-7);
stroke(255,128);
if(!paused) timer++;
line(timer%width,height,timer%width,width);
if(mousePressed && mouseY=0 && mouseY>=0){
if(tool==FIRE) startFire(mouseX,mouseY);
if(tool==MORE_FUEL) modifyFlammability(mouseX,mouseY, 0.2);
if(tool==LESS_FUEL) modifyFlammability(mouseX,mouseY,-0.2);
if(tool==MORE_FUEL || tool==LESS_FUEL) fire.redraw();
}
}
//-------------------------
void keyPressed(){
if( key==' ' ) tool = (tool+1)%3;
if( key=='k' ) fire.compress(64,16);
if( key=='g' ) {
showGrid = !showGrid;
fire.redraw();
}
if( key=='p' ) paused = !paused;
if( key=='n' ) fire = new Node(0,0,width);
if( key=='a' ) compression = min(128,compression*2);
if( key=='z' ) compression = max(1,compression/2);
if( key=='s' ) fireGrowth = min(128,fireGrowth*2);
if( key=='x' ) fireGrowth = max(1,fireGrowth/2);
if( key=='d' ) fireSpread = min(0.5,fireSpread*2);
if( key=='c' ) fireSpread = max(1f/256,fireSpread/2);
if( key=='f' ) randomFlammability();
if( key=='v' ) constantFlammability();
}
//-------------------------
void mousePressed(){
}
//------------
float posterize(float x){
return ((int)(8*x+1))/(float)8;
}
//-------------------------
void randomFlammability(){
float s = 0.02;
noiseDetail(2,0.8);
for(int i=0; idist(mx,my,x,y) ){
float d = (2.5/radius)*dist(mx,my,x,y);
float f = amount*exp(-d*d);
flammability[x][y] = constrain(0.02+flammability[x][y]+f,0,1);
}
}
//-------------------------
float ignitionProbability(int x, int y){
return fireSpread * getFlammability(x,y);
}
//-------------------------
float getFlammability(int x, int y){
return posterize( (x<0 || y<0 || x>width-1 || y>width-1) ? 1 : flammability[x][y] );
}
//-------------------------
color getPixelColor(int x, int y, int value){
color ash = color(32+64*getFlammability(x,y));
color flame = color( 255, random(128,255), 0 );
color grass = color(0,64+getFlammability(x,y)*128,0);
color c = (value<64 ? lerpColor(grass,flame,value/64f) : flame );
if(value>128)
c = lerpColor( flame, color(64), value/128f - 1 );
return c;
}
//-------------------------
String memoryUsage(){
if(mouseY=0 && mouseY>=0){
int bytes = fire.getBitSum()/8;
return "memory: "+( bytes/1024 )+"."+(bytes/102)%10+" kB";
}
else
return "- - -";
}
//-------------------------
String fireAmount(){
if(mouseY=0 && mouseY>=0){
return fire.get(mouseX,mouseY)+" :fire at cursor";
}
else
return "- - -";
}
//------------
void startFire(int x, int y){
fire.forceCellSize(x,y,minCellSize);
fire.node(x,y).value = 64;
fire.calculateExtremes();
fire.calculateAverages();
}
//------------
void update(){
//Node spread = new Node(0,0,w);
fire.spread( fire );
fire.update();
fire.calculateExtremes();
fire.calculateAverages();
fire.compress( compression ,compression );
}
//#########################