// Michael Tartaglia
// 12 July 2002
// Trippy Recursion: draws series of recursive boxes on off-screen
//		buffer; changing the position of the box and the sign of the
//		slope help create randomized psychadellic camera views

import java.awt.Font;
import java.awt.Graphics;
import java.awt.*;
import java.applet.Applet;

public class DrawRecurseBoxes extends Applet {
	public Image canvas, nameCanvas;
	public Graphics painting, namePainting;
	public int width = 300,		// original canvas box width
	           boxWidth=75,		// first drawn box's width
	           colorCount = 10,// colors to use
	           separation = 8,	// distance btw boxes
                   branches = 10,	// # of branches to box tree
	           points = 5,		// vertices per branch (360/points)
	           angle = 45,		// original branch separation angle
	           q1 = 1, q2 = 1;	// camera quadrant position
	public double mod = 1.5;	// spread speed modifier
	public boolean go = true;
	public Color[] colors = new Color[colorCount];	// COLORS TO SHOW IN DESIGN

	public DrawRecurseBoxes() {}

	public void init() {
		canvas = this.createImage(300,300);		// MAKE IMAGE BUFFER
		painting = canvas.getGraphics();			// GET IMG BUFFER'S GRAPHICS PKG

		nameCanvas = this.createImage(300,14);		// MAKE NAMEPLATE BUFFER
		namePainting = nameCanvas.getGraphics();	// GET NAMEPLATE BUFFER GRAPHICS PKG

		// CREATE NAMEPLATE
		painting.setColor(Color.white);
		painting.fillRect(0,0,width,width);
		namePainting.setColor(Color.white);
		namePainting.fillRect(0,0,width,14);
		namePainting.setColor(Color.black);
		namePainting.drawRect(0,0,299,13);
		namePainting.setFont(new Font("San Serif", Font.BOLD, 11));
		namePainting.setColor(Color.darkGray);
		namePainting.drawString("Trippy Recursion",3,11);
		namePainting.setFont(new Font("San Serif", Font.PLAIN, 11));
		namePainting.setColor(Color.black);
		namePainting.drawString("by Michael Tartaglia, FCRH 2003",141,11);

		setColors(colorCount, colors);	// UPDATE ARRAY OF COLORS
	}

	// APPLET'S BUILT IN FUNCTIONS
	public void start() {go = true;}
	public void stop() {go = false;}
	public void destroy() {stop();}

	public void update(Graphics g) {paint(g);}

	// CREATE NEW COLORS TO SHOW IN APPLET, EACH CELL REPRESENTS
	//		ONE LAYER OF THE DESIGN
	public void setColors(int cCount, Color[] c) {
		int r, g, b;
		for (int i = 0; i < cCount; ++i) {
			r = (int)Math.round(Math.random()*255);
			g = (int)Math.round(Math.random()*255);
			b = (int)Math.round(Math.random()*255);
			c[i] = new Color(r,g,b);
	}	}

	public void drawBoxDesign(Graphics g, int posX, int posY, int thisWidth,
	                          int theta, int d, int i) {
	// READS IN: graphics package to draw on, XY coordinate of box position,
	//           current width of box, current angle derivation from previous
	//           box, quadrants of branch pair (- = 3rd & 4th; + = 1st & 2nd),
	//           current depth marker
	// RETURNS:  nothing, but does modify "canvas" image
		if (i > 0) {
			int offX, offY;
			offY = (int)(separation*d*Math.sin(theta*Math.PI/180)) + posY;
			offX = (int)(separation*d*Math.cos(theta*Math.PI/180)) + posX;
			drawBoxDesign(painting, offX, offY, (int)(thisWidth*.75),
			              theta-(360/points)/i, d, i-1);
			drawBoxDesign(painting, offX, offY, (int)(thisWidth*.75),
			              theta+(360/points)/i, d, i-1);
		}
      g.setColor(colors[i%colors.length]);     // set color
		g.fill3DRect(posX-thisWidth/2,posY-thisWidth/2,
		             thisWidth,thisWidth,true);  // draw box
		g.setColor(Color.black);                 // reset color
		g.drawRect(0,0,299,299);                 // re-draw frame
	}

	public void paint(Graphics g) {
		painting.setColor(Color.black);
		drawBoxDesign(painting, q1*width/2, q2*width/2, boxWidth,
		              angle, 1, branches);
		drawBoxDesign(painting, q1*width/2, q2*width/2, boxWidth,
		              -angle, -1, branches);
		drawBoxDesign(painting, q1*width/2, q2*width/2, boxWidth,
		              -angle, 1, branches);
		drawBoxDesign(painting, q1*width/2, q2*width/2, boxWidth,
		              angle, -1, branches);

		g.drawImage(canvas,0,13,this);
		g.drawImage(nameCanvas,0,0,this);

		// THIS NEXT IF-ELSE BLOCK JUST PLACES THE DESIGN ORIGIN POINT
		//    ARBITRARILY. THE SEQUENCE, QUANTITIES, AND CALCULATIONS
		//		DO NOT MATTER, HOWEVER, THEY ALL MUST BE CONSISTENT WITH
		//		EACH OTHER, FOR THE SAKE OF THE IF-ELSE BLOCK'S FUNCTIONALITY
		if (separation * branches <= width*1.5) {
			separation+=2;
		} else if (angle < 45*4) {
			separation /= branches;
			angle += 45;
			setColors(colorCount, colors);
		} else {
			separation /= branches;
			angle = 45;
			switch ((int)(Math.random()*4)) {
				case 0: q1=-1;q2=1;break;
				case 1: q1=-1;q2=-1;break;
				case 2: q1=1;q2=1;break;
				case 3: q1=1;q2=-1;break;
			}
			switch (width) {
				case 200: width=600;break;
				case 300: width=200;break;
				case 600: width=300;break;
			}
			setColors(colorCount, colors);
		}

		// LOOP DESIGN IF CLEARED TO
		if (go) {
			try {Thread.sleep(10);paint(g);}
			catch (InterruptedException ie) {}
		}

	}
}
