#define M_PI 3.1415926535897932384626433832795
#define PI 3.1415926535897932384626433832795

struct Input {
	// Goes from 0 to 1
	float2 vertex_position:SV_Target0;
	float2 normal_direction:SV_Target1;
	float2 direction:SV_Target2;
	float2 texture_coord:SV_Target3;
	float codepoint_tn:SV_Target4;
	float thickness:SV_Target5;
	bool is_globe_map;
};

struct Output {
	float2 texture_coord;
	float type;
	float4 position;
};

// Camera position
float2 offset:SV_Target0;
float aspect_ratio:SV_Target1;
// Zoom: big numbers = close
float zoom:SV_Target2;
// The size of the map in pixels
float2 map_size:SV_Target3;
float3x3 rotation:SV_Target4;

float4 globe_coords(float2 world_pos) {

	float3 new_world_pos;
	float section_x = 200;
	float angle_x1 = 2 * PI * floor(world_pos.x * section_x) / section_x;
	float angle_x2 = 2 * PI * floor(world_pos.x * section_x + 1) / section_x;
	float angle_x = lerp(angle_x1, angle_x2, fmod(world_pos.x * section_x, 1));
	new_world_pos.x = lerp(cos(angle_x1), cos(angle_x2), fmod(world_pos.x * section_x, 1));
	new_world_pos.y = lerp(sin(angle_x1), sin(angle_x2), fmod(world_pos.x * section_x, 1));
	float section_y = 200;
	float angle_y1 = PI * floor(world_pos.y * section_y) / section_y;
	float angle_y2 = PI * floor(world_pos.y * section_y + 1) / section_y;
	new_world_pos.x *= lerp(sin(angle_y1), sin(angle_y2), fmod(world_pos.y * section_y, 1));
	new_world_pos.y *= lerp(sin(angle_y1), sin(angle_y2), fmod(world_pos.y * section_y, 1));
	new_world_pos.z = lerp(cos(angle_y1), cos(angle_y2), fmod(world_pos.y * section_y, 1));
	new_world_pos =  new_world_pos * rotation;
	new_world_pos /= PI; 		// Will make the zoom be the same for the globe and flat map
	new_world_pos.y *= 0.02; 	// Sqeeze the z coords. Needs to be between -1 and 1
	new_world_pos.xz *= -1; 	// Invert the globe
	new_world_pos.xyz += 0.5; 	// Move the globe to the center

	return float4(
		(2. * new_world_pos.x - 1.f) / aspect_ratio  * zoom,
		(2. * new_world_pos.z - 1.f) * zoom,
		(2. * new_world_pos.y - 1.f), 1.0);
}

float4 flat_coords(float2 world_pos) {
	world_pos += float2(-offset.x, offset.y);
	world_pos.x = fmod(world_pos.x, 1.0f);
	return float4(
		(2. * world_pos.x - 1.f) * zoom / aspect_ratio * map_size.x / map_size.y,
		(2. * world_pos.y - 1.f) * zoom,
		0.0, 1.0);
}

float4 calc_gl_position(float2 world_pos, bool is_globe_map) {
	return is_globe_map ? globe_coords(world_pos) : flat_coords(world_pos);
}

// The borders are drawn by seperate quads.
// Each triangle in the quad is made up by two vertices on the same position and
// another one in the "direction" vector. Then all the vertices are offset in the "normal_direction".
Output main(Input input) {
	//float2 rot_direction = float2(-direction.y, direction.x);
	//float2 normal_vector = normalize(normal_direction) * thickness;
	//float2 extend_vector = -normalize(direction) * thickness;
	
	//float2 world_pos = vertex_position;


	float x_adj = 1.0f / aspect_ratio;
	
	float2 unadj_direction = float2(input.direction.x / 2.0f, input.direction.y);
	float2 unadj_normal = float2(-input.direction.y / 2.0f, input.direction.x);
	
	float4 center_point = calc_gl_position(input.vertex_position, input.is_globe_map);
	float4 right_point = input.thickness * 10000 * (calc_gl_position(input.vertex_position + unadj_direction * 0.0001, input.is_globe_map) - center_point);
	
	float4 top_point = input.thickness * 10000 * (calc_gl_position(input.vertex_position + unadj_normal * 0.0001, input.is_globe_map) - center_point);
	
	//float2 offset = normal_vector + extend_vector;
	//world_pos += offset * scale;
	
	float4 temp_result = center_point + (input.normal_direction.x * right_point + input.normal_direction.y * top_point);
	temp_result.x *= x_adj;
	temp_result.z = 0.01f / (input.thickness * zoom);

	Output output;
	output.position = temp_result;
	output.texture_coord = input.texture_coord;
	output.type = input.codepoint_tn;
	return output;
}
