/**
 *  Author: Tri Nguyen-Huu
 *  Description: growing tree using L-systems.
 */
model tree

global {
	float rigidity;
	int max_level <- 8;
	float min_energy <- 300.0;
	float main_split_angle_alpha <- 30.0;
	float secondary_split_angle_alpha <- 90.0;
	float main_split_angle_beta <- 20.0;
	float secondary_split_angle_beta <- 90.0;
	float length_max <- 100.0;
	float width_ini <- 1.0;
	float level_step <- 0.8;
	seasons season;
	float width <- shape.width;
	float height <- shape.height;
	float env_size <- 0.5 * length_max / (1 - level_step);
	point seed_pos <- {width / 2, height / 2};

	init {
		create plant_seed {
			location <- seed_pos;
			write location;
		}

		create seasons number: 1 {
			season <- self;
		}
	}
}

species seasons {
	int season_duration <- 600;
	int shift_cycle <- season_duration * 4 update: season_duration * 4 + int(cycle - floor(season_duration / 2));
	list season_list <- ["winter", "spring", "summer", "autumn"];
	string current_season <- "winter" update: season_list[(cycle div season_duration) mod 4];
	int current_day <- 0 update:  cycle mod season_duration;
	int shift_current_day <- 0 update: shift_cycle mod season_duration;
	float energy <- 0.0 update: energy_map[current_season];
	int se <- 0 update: (shift_cycle div season_duration) mod 4;
	int next_se <- 1 update: (se + 1) mod 4;
	int ns_se <- 0 update: (cycle div season_duration) mod 4;
	int ns_next_se <- 1 update: (ns_se + 1) mod 4;
	list sky_color_list <- [rgb(238, 238, 238), rgb(129, 207, 224), rgb(25, 181, 254), rgb(254, 224, 144)];
	list leaf_color_list <- [rgb(150, 40, 27), rgb(134, 174, 83), rgb(30, 130, 76), rgb(192, 57, 43)];
	list ground_color_list <- [rgb(236, 240, 241), rgb(46, 204, 113), rgb(38, 166, 91), rgb(95, 104, 40)];
	//		list branch_color_list <- [rgb(97,73,52),rgb(90,139,140),rgb(90,139,140),rgb(90,139,140)];
	list branch_color_list <- [rgb(77, 67, 62), rgb(60, 45, 32), rgb(115, 77, 64), rgb(90, 68, 48)];
	list fruit_color_list <- [rgb(102, 62, 81), rgb(200, 247, 197), rgb(135, 211, 124), rgb(211, 84, 0)];
	rgb sky_color <- sky_color_list[0];
	rgb leaf_color <- leaf_color_list[0];
	rgb ground_color <- ground_color_list[0];
	rgb branch_color <- branch_color_list[0];
	rgb fruit_color <- fruit_color_list[0];
	map energy_map <- ["winter"::0.0, "spring"::0.3, "summer"::0.08, "autumn"::0];

	init {
		do change_color;
	}

	action change_color {
		leaf_color <- blend(leaf_color_list[se], leaf_color_list[next_se], 1 - shift_current_day / season_duration);
		sky_color <- blend(sky_color_list[se], sky_color_list[next_se], 1 - shift_current_day / season_duration);
		ground_color <- blend(ground_color_list[se], ground_color_list[next_se], 1 - shift_current_day / season_duration);
		branch_color <- blend(branch_color_list[ns_se], branch_color_list[ns_next_se], 1 - current_day / season_duration);
		float scale <- 500.0;
		fruit_color <- blend(fruit_color_list[ns_se], fruit_color_list[ns_next_se], exp(-current_day / scale));
	}

	reflex update {
		do change_color;
	}

}

species tree_part {
	tree_part parent <- nil;
	point vector <- {0, 0, 0};
	point base <- {0, 0, 0};
	point end <- {0, 0, 0};
	float alpha <- 0.0;
	float beta <- 0.0;
	float level <- 1.0;
	list children <- nil;
	float energy <- 0.0;
}

species plant_seed parent: tree_part {
	bool has_tree <- false;
	point end -> self.location;
	point vector <- {0, 0, 1};

	reflex create_tree when: (!has_tree and season.current_season = "spring") {
		create trunk {
			base <- myself.location;
			self.end <- self.base;
			alpha <- rnd(100) * 360 / 100;
			beta <- 90.0;
			level <- 1.0;
			parent <- myself;
		}

		has_tree <- true;
	}

	aspect default {
		draw
		polygon([location + {env_size / 2, 0, -1}, location + {0.5 * env_size / 2, 0.86 * env_size / 2, -1}, location + {-0.5 * env_size / 2, 0.86 * env_size / 2, -1}, location + {-env_size / 2, 0, -1}, location + {-0.5 * env_size / 2, -0.86 * env_size / 2, -1}, location + {0.5 * env_size / 2, -0.86 * env_size / 2, -1}])
		color: season.ground_color border: season.ground_color;
		draw cone3D(6, 6) at: location color: rgb(108, 122, 137);
		draw polygon([location + {0, 0, 3}, location + {env_size / 6, 0, 0}, location + {0.5 * env_size / 6, 0.86 * env_size / 6, 0}]) color: rgb(135, 121, 78) border:
		rgb(135, 121, 78);
		draw polygon([location + {0, 0, 3}, location + {0.5 * env_size / 6, 0.86 * env_size / 6, 0}, location + {-0.5 * env_size / 6, 0.86 * env_size / 6, 0}]) color: rgb(115, 101, 58)
		border: rgb(115, 101, 58);
		draw polygon([location + {0, 0, 3}, location + {-0.5 * env_size / 6, 0.86 * env_size / 6, 0}, location + {-env_size / 6, 0, 0}]) color: rgb(115, 101, 58) border:
		rgb(115, 101, 58);
		draw polygon([location + {0, 0, 3}, location + {-env_size / 6, 0, 0}, location + {-0.5 * env_size / 6, -0.86 * env_size / 6, 0}]) color: rgb(135, 121, 78) border:
		rgb(135, 121, 78);
		draw polygon([location + {0, 0, 3}, location + {-0.5 * env_size / 6, -0.86 * env_size / 6, 0}, location + {0.5 * env_size / 6, -0.86 * env_size / 6, 0}]) color:
		rgb(135, 121, 78) border: rgb(135, 121, 78);
		draw polygon([location + {0, 0, 3}, location + {0.5 * env_size / 6, -0.86 * env_size / 6, 0}, location + {env_size / 6, 0, 0}]) color: rgb(135, 121, 78) border:
		rgb(135, 121, 78);
	}

}

species burgeon parent: tree_part {

	reflex growth {
		energy <- energy + first(season).energy;
	}

	reflex bloom when: flip(energy / 1) {
		branch tmp <- nil;
		create branch number: 1 {
			tmp <- self;
			self.level <- myself.level;
			self.base <- myself.base;
			self.end <- self.base;
			self.alpha <- myself.alpha;
			self.beta <- myself.beta;
			self.parent <- myself.parent;
			if myself.parent != nil {
				myself.parent.children <- myself.parent.children + tmp;
			}

		}

		create leaf {
			self.level <- myself.level;
			self.parent <- tmp;
			self.alpha <- myself.alpha;
			self.beta <- myself.beta;
			self.base <- tmp.end;
			self.end <- self.base + {5 * cos(beta) * cos(alpha), 5 * cos(beta) * sin(alpha), 5 * sin(beta)};
			tmp.children <- tmp.children + self;
			self.creation_cycle <- cycle;
		}

		do die;
	}

}

species trunk parent: tree_part {
	float length <- 0.0;
	float width <- 0.0;
	bool can_split <- true;

	aspect default {
		draw line([base, end], width) color: season.branch_color; // border: #red;
	}

	reflex growth {
		base <- parent.end;
		energy <- energy + first(season).energy;
		float level_correction <- 1.8 * 0.3 ^ level;
		length <- level_correction * (length_max * (1 - min([1, exp(-energy / 1000)])));
		width <- length / level_correction / 13.0;
		end <- base + {length * cos(beta) * cos(alpha), length * cos(beta) * sin(alpha), length * sin(beta)};
	}

	reflex split when: can_split and (level < max_level) and (min_energy < energy) {
		float branch1_alpha <- rnd(100) / 100 * 360;
		float branch1_beta <- 30 + rnd(100) / 100 * 40;
		float branch2_alpha <- rnd(100) / 100 * 360;
		float branch2_beta <- 30 + rnd(100) / 100 * 40;
		can_split <- false;
		create burgeon number: 1 {
			self.level <- myself.level + 1.9;
			self.base <- myself.end;
			self.end <- self.base;
			self.alpha <- branch1_alpha;
			self.beta <- branch1_beta;
			self.parent <- myself;
		}

		if flip(0.7) {
			create burgeon number: 1 {
				self.level <- myself.level + 2.1;
				self.base <- myself.end;
				self.end <- self.base;
				self.alpha <- branch2_alpha;
				self.beta <- branch2_beta;
				self.parent <- myself;
			}

		}

		create trunk number: 1 {
			self.level <- myself.level + 0.3;
			self.base <- myself.end;
			self.end <- self.end;
			self.alpha <- myself.alpha - 10 + rnd(200) / 10;
			self.beta <- myself.beta - 10 + rnd(200) / 10;
			self.parent <- myself;
		}

	}

}

species branch parent: tree_part {
	float length <- 0.0;
	float width <- 0.0;
	bool can_split <- true;

	reflex growth {
		base <- parent.end;
		energy <- energy + first(season).energy;
		length <- level_step ^ level * (length_max * (1 - min([1, exp(-energy / 1000)])));
		width <- length / 10 * (4 + max_level - level) / (4 + max_level);
		end <- base + {length * cos(beta) * cos(alpha), length * cos(beta) * sin(alpha), length * sin(beta)};
	}

	aspect default {
		draw line([base, end], width) color: season.branch_color; // border: #green;
		if (season.current_season = "winter") and (abs(beta) < 50) {
			draw line([base + {0, 0, 1.2 * width}, end + {0, 0, 1.2 * width}], width * sin(180 * season.current_day / season.season_duration)) color: °white;
		}

	}

}

species leaf {
	int creation_cycle <- -1;
	float level <- 1.0;
	branch parent;
	point base;
	point end;
	float alpha <- 0.0;
	float beta <- 0.0;
	float fall <- 0.0;
	int fall_shift <- int(rnd(season.season_duration / 2.5));
	float size <- 3.0;
	pair rota <- rotation_composition(float(rnd(180))::{1, 0, 0}, float(rnd(180))::{0, 1, 0}, float(rnd(180))::{0, 0, 1}); //////////////////////////
	aspect default {
		draw line([base, end], min([parent.width, 1])) color: season.leaf_color;
		//			draw circle(size) at: (end - {0,0,fall*end.z}) color: season.leaf_color border: season.leaf_color;
		draw circle(size) rotate: rota at: (end - {0, 0, fall * end.z}) color: season.leaf_color; // border: #black; //season.leaf_color;
	}

	reflex update {
		base <- parent.end;
		end <- base + {5 * cos(beta) * cos(alpha), 5 * cos(beta) * sin(alpha), 5 * sin(beta)};
		if (season.current_season = "autumn") {
			fall <- 1 - exp(-max([0, 5 * (season.current_day - fall_shift) / season.season_duration * 3]));
		} else if (season.current_season = "winter") {
			size <- 3 * (season.season_duration - season.current_day) / season.season_duration;
		} else if (season.current_season = "spring") {
			fall <- 0.0;
			size <- 3 * season.current_day / season.season_duration;
		}

	}

	reflex split when: (level < max_level) and flip(1 - exp(level * (min_energy - parent.energy) / 50)) {
		int side1 <- -1 + 2 * rnd(1);
		int side2 <- -1 + 2 * rnd(1);
		int side3 <- -1 + 2 * rnd(1);
		int side4 <- -1 + 2 * rnd(1);
		float factor <- secondary_split_angle_alpha / 100;
		float branch1_alpha <- parent.alpha + side1 * rnd(100) / 100 * main_split_angle_alpha;
		float branch2_alpha <- parent.alpha - side1 * rnd(100) * factor;
		float branch3_alpha <- parent.alpha + side3 * rnd(100) * factor;
		float branch4_alpha <- parent.alpha - side3 * rnd(100) * factor;
		int sideb <- -1 + 2 * rnd(1);
		 factor <- secondary_split_angle_beta / 100;
		float branch1_beta <- parent.beta + sideb * rnd(100) / 100 * main_split_angle_beta;
		float branch2_beta <- -20 + rnd(100) * factor;
		float branch3_beta <- -20 + rnd(100) * factor;
		float branch4_beta <- -20 + rnd(100) * factor;
		create burgeon number: 1 {
			self.level <- myself.parent.level + 1;
			self.base <- myself.base;
			self.end <- self.base;
			self.alpha <- branch1_alpha;
			self.beta <- branch1_beta;
			self.parent <- myself.parent;
		}

		create burgeon number: 1 {
			self.level <- myself.parent.level + 1.2;
			self.base <- myself.base;
			self.end <- self.base;
			self.alpha <- branch2_alpha;
			self.beta <- branch2_beta;
			self.parent <- myself.parent;
		}

		if flip(0.6) {
			create burgeon number: 1 {
				self.level <- myself.parent.level + 1.7;
				self.base <- myself.base;
				self.end <- self.base;
				self.alpha <- branch3_alpha;
				self.beta <- branch3_beta;
				self.parent <- myself.parent;
			}

		}

		if flip(0.3) {
			create burgeon number: 1 {
				self.level <- myself.parent.level + 2;
				self.base <- myself.base;
				self.end <- self.base;
				self.alpha <- branch4_alpha;
				self.beta <- branch4_beta;
				self.parent <- myself.parent;
			}

		}

		if flip(0.8) {
			create burgeon number: 1 {
				self.level <- myself.parent.level + 3.5;
				self.base <- myself.base;
				self.end <- self.base;
				self.alpha <- branch4_alpha;
				self.beta <- branch4_beta;
				self.parent <- myself.parent;
			}

		}

		if flip(0.9) {
			create fruit number: (1 + rnd(2)) {
				self.base <- myself.base;
				self.end <- myself.base + {3 * cos(beta) * cos(alpha), 3 * cos(beta) * sin(alpha), 3 * sin(beta)};
				self.parent <- myself.parent;
				self.alpha <- myself.alpha + (-1 + 2 * rnd(1)) * 30;
				self.beta <- -40.0 + rnd(80);
			}

		}

		self.parent.children <- self.parent.children - self;
		do die;
	}

}

species fruit {
	branch parent;
	point base;
	point end;
	float alpha;
	float beta;
	float fall <- 0.0;
	int fall_shift <- int(rnd(season.season_duration / 2.5)); //unused
	aspect default {
		if (season.current_season = "spring") {
			draw line([base, end], 0.1) color: season.leaf_color;
			draw circle(1 * sin(180 * season.current_day / season.season_duration)) at: end color: #pink border: #pink;
		} else if (season.current_season = "summer") {
			draw line([base, end], 0.1) color: season.leaf_color;
			draw sphere(1 * sin(90 * season.current_day / season.season_duration)) at: end color: season.fruit_color border: season.fruit_color;
		}

	}

	reflex update {
		base <- parent.end;
		if (season.current_season = "spring") {
			end <- base + {3 * cos(beta) * cos(alpha), 3 * cos(beta) * sin(alpha), 3 * sin(beta)};
		} else if (season.current_season = "summer") {
			float beta2 <- -90 + (beta + 90) * exp(-season.current_day / 100);
			end <- base + {3 * cos(beta2) * cos(alpha), 3 * cos(beta2) * sin(alpha), 3 * sin(beta2)};
		}

	}

}

experiment "Random" type: gui autorun: true {
	output {
		display 'Tree' type: opengl background: season.sky_color axes: false toolbar: false fullscreen: true {
			light #ambient intensity: 150;
			rotation angle: cycle/1000000 dynamic: true;
			camera #default location: {50.0,450,250} target: {50.0,50.0,40+80*(1-exp(-cycle/50000))} dynamic: true;
			species branch aspect: default;
			species leaf aspect: default;
			species trunk aspect: default;
			species plant_seed aspect: default;
			species fruit aspect: default;
		}

	}

}

experiment "4 simulations" type: gui autorun: true {

	init {
		create simulation number: 3  {
			self.seed <- rnd(1000.0);
		}
	}

	output {
		display 'Tree' type: opengl background: season.sky_color axes: false toolbar: false {
			light #ambient intensity: 150;	
			rotation angle: cycle/1000000 dynamic: true;
			camera #default location: {50.0,450,250} target: {50.0,50.0,40+80*(1-exp(-cycle/50000))} dynamic: true;
			species branch aspect: default;
			species leaf aspect: default;
			species trunk aspect: default;
			species plant_seed aspect: default;
			species fruit aspect: default;
		}

		layout #split toolbars: false tabs: false parameters: false consoles: false navigator: false controls: false tray: false;
	}

}

experiment L_Tri type: gui autorun: true {
	float minimum_cycle_duration <- 0.0005;
	float seed <- 0.05387546426306633;
	output {
		display 'Tree' type: opengl background: season.sky_color axes: false toolbar: true {
			light #ambient intensity: 150;
			rotation angle: cycle/1000000 dynamic: true;
			camera #default location: {50.0,450,250} target: {50.0,50.0,40+80*(1-exp(-cycle/50000))} dynamic: true;
			species branch aspect: default;
			species leaf aspect: default;
			species trunk aspect: default;
			species plant_seed aspect: default;
			species fruit aspect: default;
		}

	}

}