short minCellSize = 1; //==================================================================== class Node{ boolean subdivide; short value; short change; short cellSize; short x, y; short maxVal, minVal; boolean redrawMe = true; Node[] nodes; //-------------------- Node(int x, int y, int cellSize){ this.x = (short)x; this.y = (short)y; this.cellSize = (short)cellSize; subdivide = false; value = 0; } //-------------------- Node node(int i, int j){ if(!subdivide) return this; int ch = cellSize/2; if(i< x+ch && j< y+ch) return nodes[0].node(i,j); if(i>=x+ch && j< y+ch) return nodes[1].node(i,j); if(i< x+ch && j>=y+ch) return nodes[2].node(i,j); if(i>=x+ch && j>=y+ch) return nodes[3].node(i,j); return null; } //-------------------- int get(int i, int j){ return node(i,j).value; } //-------------------- void set(int i, int j, int val){ node(i,j).value = (short) val; } //-------------------- void add(int i, int j, int val){ node(i,j).change += val; } //-------------------- void subdivide(){ subdivide = true; int ch = cellSize/2; nodes = new Node[4]; nodes[0] = new Node(x , y , ch); nodes[1] = new Node(x+ch, y , ch); nodes[2] = new Node(x , y+ch, ch); nodes[3] = new Node(x+ch, y+ch, ch); nodes[0].value = value; nodes[1].value = value; nodes[2].value = value; nodes[3].value = value; } //-------------------- void forceCellSize(int i, int j, int forceSize){ if( cellSize <= forceSize ){ return; } else { int ch = cellSize/2; if(!subdivide) subdivide(); node(i,j).forceCellSize(i,j,forceSize); } } //-------------------- void update(){ if( !subdivide ){ // fire increase if( value>0 || change>0 ) redrawMe = true; if( value>0 ) value += fireGrowth; value = (short) constrain(value+change,0,255); } else { nodes[0].update(); nodes[1].update(); nodes[2].update(); nodes[3].update(); } change = 0; } //-------------------- void spread(Node root){ if(maxVal==0) return; if( !subdivide ){ // fire spread if( value<192 ){ neighbourIgnition(x-1, y, root ); neighbourIgnition(x+cellSize, y, root ); neighbourIgnition(x, y-1, root ); neighbourIgnition(x, y+cellSize, root ); } } else { nodes[0].spread(root); nodes[1].spread(root); nodes[2].spread(root); nodes[3].spread(root); } } //-------------------- void neighbourIgnition(int x, int y, Node root){ if( random(1) < ignitionProbability(x,y) ){ root.forceCellSize(x,y, minCellSize ); root.node(x,y).change += 2; } } //-------------------- int getBitSum(){ if(subdivide){ return 1 + nodes[0].getBitSum() + nodes[1].getBitSum() + nodes[2].getBitSum() + nodes[3].getBitSum(); } else return 8+1; } //-------------------- void calculateExtremes(){ if(subdivide){ nodes[0].calculateExtremes(); nodes[1].calculateExtremes(); nodes[2].calculateExtremes(); nodes[3].calculateExtremes(); maxVal = (short)max( max(nodes[0].maxVal,nodes[1].maxVal) , max(nodes[2].maxVal,nodes[3].maxVal) ); minVal = (short)min( min(nodes[0].minVal,nodes[1].minVal) , min(nodes[2].minVal,nodes[3].minVal) ); } else maxVal = minVal = value; } //-------------------- void calculateAverages(){ if(subdivide){ nodes[0].calculateAverages(); nodes[1].calculateAverages(); nodes[2].calculateAverages(); nodes[3].calculateAverages(); value = (short)(( nodes[0].value + nodes[1].value + nodes[2].value + nodes[3].value )/4); } } //-------------------- void compress(int threshold, int minimum){ if(subdivide){ nodes[0].compress(threshold,minimum); nodes[1].compress(threshold,minimum); nodes[2].compress(threshold,minimum); nodes[3].compress(threshold,minimum); if( (maxVal-minVal) <= threshold && minVal>minimum){ nodes = null; subdivide = false; } } } //-------------------- void redraw(){ if(subdivide){ nodes[0].redraw(); nodes[1].redraw(); nodes[2].redraw(); nodes[3].redraw(); } else{ redrawMe = true; } } //-------------------- void draw(){ if(subdivide){ nodes[0].draw(); nodes[1].draw(); nodes[2].draw(); nodes[3].draw(); } else if(redrawMe){ if(cellSize == 1) pixels[x+width*y] = getPixelColor(x,y,value); else for(int i=x; i