import java.applet.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 

public class bTreeBomb extends BApplet {
// Fire and Forget Broccoli Tree Bombs
// by Carlos Nazareno
// May 31, 2003
//
// Exploration into ordered chaos
// Working proof of trees as naturally occurring fractals
//
// By visually presenting and recursively iterating a branching
// and decaying function, the natural growth patterns of trees
// can be emulated. Visual representation of a trinary variant
// of the computer science subject of binary trees.
//
// It is interesting to note that the emergent behavior of the
// recursive system in this particular code rendition resembles
// Trees in the botanical sense, broccoli, and the resulting
// mushroom clouds from dropping atomic bombs.
// Similar too, is the point and click interface to the 
// relative ease and simplicity with which superpowers can
// destroy the world
//
// This piece echoes the work of the Spanish-born Neo-Realist
// graphic artist and painter Juvenal Sanso with whom attention
// to intricate detail through "natural laws" as seen in such
// subjects as gnarled roots, branching trees and vegetation
// is a common theme.
//  
// Usage: Click anywhere on the bottom half to generate 
// trees. Press a key to reset the painting

float minDecay = 0.1f;
float maxDecay = 0.75f;
float branchDecay = 0.8f;
float decayInc = 0.001f;
int maxTreeDepth = 16;
float trunkLength=1;
float xroot = 400;
float yroot = 600;
float sky = 0.5f;
float angle;
int blinky;

void setup() {
  size(600,400);
  noBackground();
  framerate(30);
  blinky=0;
}

void loop() {
  if (blinky == 0) {
    blinky = 1;
    wipe();
  }
}

void mousePressed() {
  float nx = mouseX;
  float ny = mouseY;
  if (ny > height*sky) {
    node((50+random(100)*branchDecay)*((ny+5)-height*sky)/(height-height*sky),5,3*PI/2,nx,ny,0);
  }
}

void keyPressed() {
  wipe();
}

void wipe() {
  //draw sky
  float gmax = height*sky;
  for (int g=0; g < gmax; g++) {
    float c = 255*g/gmax;
    stroke(c,c,c);
    line(0,g,width,g);
  }
  //draw dirt
  float c = height-gmax;
  for (int g=0; g<c; g++) {
//    stroke(153+51*g/c,204+51*g/c,0);
    stroke(153+51*g/c,153+51*g/c,153+51*g/c);
    line(0,g+gmax,width,g+gmax);
  }
}

void node(float branchLength, float branchWidth, float rootAngle, float rootX, float rootY, int treeDepth) {
  if (treeDepth < maxTreeDepth) {
    float tipX = rootX+branchLength*cos(rootAngle);
    float tipY = rootY+branchLength*sin(rootAngle);
    if (((rootX>=0 && rootX <=width) && (rootY>=0 && rootY<=height)) || ((tipX>=0 && tipX <=width) && (tipY>=0 && tipY<=height))) {
      if (branchLength < 3) {
        stroke(0,51+random(102),0);
      } else stroke(0xff000000);
      line(rootX, rootY, tipX, tipY);
    }
    float lnodeLength = branchLength*branchDecay*(1-random(0.4f));
    if (lnodeLength >= 0.8f && random(10) < 75) {
      angle = rootAngle-random(PI/3);
      while (angle < 2*PI/3) {
        angle += random(PI/8);
      }
      node(lnodeLength, branchWidth, angle, tipX, tipY, treeDepth+1);
    }
    float mnodeLength = branchLength*branchDecay*(1-random(0.4f));
    if (mnodeLength >= 0.8f && random(10) < 90) {
      angle = rootAngle+PI/4-random(PI/2);
      while (angle < 2*PI/3 && angle >= PI/2) {
        angle += random(PI/8);
      }
      while (angle > PI/3 && angle <= PI/2) {
        angle -= random(PI/8);
      }
      node(mnodeLength, branchWidth, angle, tipX, tipY, treeDepth+1);
    }
    float rnodeLength = branchLength*branchDecay*(1-random(0.4f));
    if (rnodeLength >= 0.8f && random(10) < 75) {
      angle = rootAngle+random(PI/3);
      while (angle > PI/3 && angle <= PI/2) {
        angle -= random(PI/8);
      }
      node(rnodeLength, branchWidth, angle, tipX, tipY, treeDepth+1);
    }
  }
}

}