/**
* Name: Tricky fountain
* Author: Arnaud Grignard - Alexis Drogoul 2021
* Description: This is a model that shows how the physics engine works using a tank, with a floor and 4 walls, and balls of water
* falling into it. The model is exploiting the viewpoint of the user (thanks to the camera_location and camera_target) to give the illusion
* of a fake gravity (in a completely unrealistic way, just for the demo !). 
* Tags: physics_engine, skill, 3d, spatial_computation
*/
model Tank

/**
 * The model is inheriting from 'physical_world' a special model species that provides access to the physics engine -- and the possibility
 * to manage physical agents. In this model, the world itself is not a physical agent
 */
global parent: physical_world {
	bool use_native_library <- false;
	//Dimensions of the environment
	int dim <- 100;
	//Step (in #sec) passed to the physics engine. The same step is used for the simulation and the physics engine. The accuracy and synchronization
	//between the two can be controlled by max_substeps 
	float step <- 0.1; 
	//When this variable is true (the default), all the agents that inherit from dynamic_body or static_body are automatically registered as
	//physical agents of this world. Otherwise, they have to be registered manually (using the 'register' action)
	bool automated_registration <- true;
	//The shape of the environment. Since it is not part of the physical world, could be anything
	geometry shape <- rectangle(dim, dim);
	
	

	init {
		//The floor is a large flat box in the middle of the world.
		create pillarAndFloor {
			shape <- box({dim * 2, dim * 2, 1}) at_location {dim / 2, dim / 2, -5};
		}
		//On which we create the bottom of the fountain 
		create wall {
			shape <- box({dim, dim, 10}) at_location {dim / 2, dim / 2, -5};
		}
		float depth <- dim/6;
		//We then create the walls of the fountain itself as four vertical flat boxes
		create wall from: [
			box({dim, 2, depth}) at_location {dim / 2, dim, 0}, 
			box({dim, 2, depth}) at_location {dim / 2, 0, 0}, 
			box({2, dim, depth}) at_location {0, dim / 2, 0}, 
			box({2, dim, depth}) at_location {dim, dim / 2, 0}];
		//And finally, the pillar, a vertical cylinder
		create pillarAndFloor {
			shape <- cylinder(4, dim - 10) at_location {dim / 2, dim / 2, 0};
		}

	}

	//Every 5 steps the world creates 5 water agents at the same place. No need to provide them with a velocity or
	//an impulse: the immediate resolution of the physical forces make them spring 
	reflex flow when: every(5 #cycle) {
		create water number: 5 {
				location <- {dim/2, dim/2, dim};
		}
	}
	
	
	//Here comes the trick of the model. The orientation of the view is estimated (very roughly) by the position and
	//target of the camera. Whenever the user changes it (by rotating or tilting the view, for the moment only around the x-axis),  
	//the gravity is adjusted in order for it to remain oriented towards the 'bottom' of the screen. The full control (which would involve Euler angles) 
	//is of course not implemented here, but left as a future exercise ! 
	reflex compute_gravity {
		point p <- #camera_location - #camera_target;
		p <- {p.x = 0 ? 1 : p.x, p.y = 0 ? -1 : -p.y, p.z = 0 ? 1 : p.z};
		point g <- {0, -1 / (p.y) * signum(p.z), -2 / abs(p.z)};
		gravity <- g / norm(g) * 9.81;
	}
}


/**
 * Species that represent the walls of the tank. They are static physical objects with no behavior
 */

species wall skills: [static_body];

species pillarAndFloor skills: [static_body];


/**
 * Species that represents the balls falling from the fountain, using the skill dynamic_body
 */
species water skills: [dynamic_body] {
	//The shape of water drops is a sphere between 1 and 2 of radius
	geometry shape <- sphere(rnd(2.0) + 1.0);
	//They are provided with a mass (otherwise they would 'float')
	float mass <- 3.0;
	rgb color <- one_of(brewer_colors("Blues")); 
	//This provides some 'bounciness' when they hit other agents
	float restitution <- 0.5;
	//This provides some stability
	float angular_damping <- 0.9;
	float contact_damping <- 0.9;
	
	//When water drops fall from the ground, they are eliminated (from the simulation and the physical world)
	reflex when: location.z < -20 {
		do die;
	}
} 

experiment "3D View" type: gui {
	output { 
		//The initial orientation of the display makes water drops 'fall' slightly towards the user... calling (hopefully) from immediate action!
		display Flow type: opengl background: #black axes: false  {
			camera #default location: {50,300,150} target: {dim/2,dim/2,10};
			species water {draw shape color: color;}
			species wall refresh: false {draw shape texture: image_file("../images/marble2.jpg");}
			species pillarAndFloor refresh: false {draw shape texture: image_file("../images/marble.jpg");}
		}

	}

}