#include "ball.hpp"
#include "terrain.hpp"
#include "settings.hpp"

void ball::initialize(int n)
{

	N = n;
	pos.resize(N);
	v.resize(N);
	color.resize(N);

	mesh.initialize_data_on_gpu(mesh_primitive_sphere(0.1f));

	for (int i = 0; i < N; i++) {
		color[i] = { rand_interval(0.0f, 1.0f), rand_interval(0.0f, 1.0f), rand_interval(0.0f, 1.0f) };
		pos[i] = { 0,0,40 };
		v[i] = { 2 * cos(360 * i / N) ,2 * sin(360 * i / N),10 };
	}
}

void ball::reset() {
	N = 0;
	pos.resize(N);
	v.resize(N);
	color.resize(N);
}

void ball::add_ball(vec3 new_pos, vec3 new_dir) {
	N++;
	pos.resize(N);
	v.resize(N);
	color.resize(N);


	color[N-1] = { rand_interval(0.0f, 1.0f), rand_interval(0.0f, 1.0f), rand_interval(0.0f, 1.0f) };
	pos[N-1] = new_pos;
	v[N-1] = new_dir;

}

void ball::simulate(float dt) {
	for (int i = 0; i < N; i++) {
		if (pos[i][2] < -1 || cgp::abs(pos[i][0]) > terrain_length() / 2 || cgp::abs(pos[i][1]) > terrain_length() / 2) {
			pos[i] = { 0,0, evaluate_terrain_height(0,0) };
			v[i] = { 3 * rand_interval(), 3 * rand_interval(), 4 + i };
		}
		else {
			pos[i] += v[i] * dt;
			v[i][2] -= 10 * dt;
		}

		if (pos[i][2] < evaluate_terrain_height(pos[i][0], pos[i][1])) {
			vec3 normal = normalize(terrain_orientation(pos[i][0], pos[i][1]));

			vec3 temp = v[i] - dot(v[i], normal) * normal;

			v[i] -= 2 * temp;
			v[i] = -v[i];

			float diffusion = 1.1;
			v[i] /= diffusion;
		}

	}
}

vec3 terrain_orientation(float x, float y) {
	float z = evaluate_terrain_height(x, y);
	float step = 0.1f;
	vec3 u = { step, 0, evaluate_terrain_height(x + step,y) - z };
	vec3 v = { 0, step, evaluate_terrain_height(x,y + step) - z };

	return cross(v, u);
}