module Seed extends Point;
module Tree(int age) extends Sphere(0.1);
module Leaf extends Sphere(0.1).(setShader(GREEN));
module X(int r, float l);
module Dummy(int x);

const float c1 = 0.9f, c2 = 0.5f;
const float[] angle = {60, 45}, minLength = {0.6f, 0.35f};

Sphere sun = new Sphere (0.3).(setTransform(0, 0, 12), setShader(YELLOW));

private static boolean isShaded (Node s)
{
	return !empty ((* f:F, (f in cone(s, false, 20)) *));
}

protected void init ()
[
	Axiom ==>
		Seed.(setTransform(0, 0, 1)),
		^ sun Dummy(0);
]

public void run ()
[
	d:Dummy ::> d[x] :+= 1; // sorgt dafuer, dass in jedem Schritt
	// etwas geschieht ("Run run" wird gestoppt, sobald in einem
	// Schritt keine Aktion erfolgte)

	s:Leaf ==>>
		s
		if (random(0, 1) < 0.008) (//{println(s);}
			, ^ Seed.(setTransform(location(s)))
		);

	s:Seed ==>>
		if (s[z] <= 0) (
			^ Null(s[x],s[y],0) Tree(0) X(0, 1)
		) else {
			s[x] += random (-1, 1);
			s[z] -= random (0.1f, 0.3f);
			break;
		};

	Tree(a), (a == 30) ==>> ;

	t:Tree ::> t.age++;

	x:X(r, l) ==>
		if (r == 2) (
			if (!isShaded(x)) (
				tropism(x, sun, 0.4f)
				F(l, 0.02f) Leaf
			)
		) else if ((l > minLength[r]) && !isShaded(x)) (
			tropism(x, sun, 0.2f) F(l, 0.04f)
			[RU(angle[r]) X(r+1, l*c2)]
			[RU(-angle[r]) X(r+1, l*c2)]
			X(r, l*c1)
		);
]

