#define M_PI 3.1415926535897932384626433832795
#define PI 3.1415926535897932384626433832795

struct Input {
	float2 tex_coord:SV_Target0;
	bool is_political_map;
};

struct Output {
	float4 frag_color;
};

Texture2D provinces_texture:register(t0);
SamplerState provinces_texture_sampler:register(s0);

Texture2D terrain_texture:register(t1);
SamplerState terrain_texture_sampler:register(s1);

Texture2D terrainsheet_texture:register(t2);
SamplerState terrainsheet_texture_sampler:register(s2);

Texture2D water_normal:register(t3);
SamplerState water_normal_sampler:register(s3);

Texture2D colormap_water:register(t4);
SamplerState colormap_water_sampler:register(s4);

Texture2D colormap_terrain:register(t5);
SamplerState colormap_terrain_sampler:register(s5);

Texture2D overlay:register(t6);
SamplerState overlay_sampler:register(s6);

Texture2DArray province_color:register(t7);
SamplerState province_color_sampler:register(s7);

Texture2D colormap_political:register(t8);
SamplerState colormap_political_sampler:register(s8);

Texture2D province_highlight:register(t9);
SamplerState province_highlight_sampler:register(s9);

Texture2D stripes_texture:register(t10);
SamplerState stripes_texture_sampler:register(s10);

Texture2D province_fow:register(t11);
SamplerState province_fow_sampler:register(s11);

//uniform usampler2D diag_border_identifier;
Texture2D diag_border_identifier;
SamplerState diag_border_identifier_sampler;

// location 0 : offset
// location 1 : zoom
// location 2 : screen_size
float2 map_size:SV_Target3;
float time:SV_Target4;


float gamma:SV_Target7;
float4 gamma_correct(float4 colour) {
	return float4(pow(colour.rgb, float3(1.f / gamma)), colour.a);
}

// sheet is composed of 64 files, in 4 cubes of 4 rows of 4 columns
// so each column has 8 tiles, and each row has 8 tiles too
float xx = 1 / map_size.x;
float yy = 1 / map_size.y;
float2 pix = float2(xx, yy);

float2 get_corrected_coords(float2 coords) {
	coords.y -= (1 - 1 / 1.3) * 3 / 5;
	coords.y *= 1.3;
	return coords;
}


// The water effect
float4 get_water_terrain(float2 tex_coord)
{
	float2 prov_id = provinces_texture.Sample(provinces_texture_sampler, tex_coord).xy;

	// Water effect taken from Vic2 fx/water/PixelShader_HoiWater_2_0
	const float WRAP = 0.8;
	const float WaveModOne = 3.0;
	const float WaveModTwo = 4.0;
	const float SpecValueOne = 8.0;
	const float SpecValueTwo = 2.0;
	const float vWaterTransparens = 1.0; //more transparance lets you see more of background
	const float vColorMapFactor = 1.0f; //how much colormap

	float2 tex_coord = tex_coord;
	float2 corrected_coord = get_corrected_coords(tex_coord);
	float3 WorldColorColor = colormap_water.Sample(colormap_water_sampler, corrected_coord).rgb;
	if (corrected_coord.y > 1)
		WorldColorColor = float3(0.14, 0.23, 0.36);
	if (corrected_coord.y < 0)
		WorldColorColor = float3(0.20, 0.35, 0.43);
	tex_coord *= 100.;
	tex_coord = tex_coord * 0.25 + time * 0.002;

	const float3 eyeDirection = float3(0.0, 1.0, 1.0);
	const float3 lightDirection = float3(0.0, 1.0, 1.0);

	float2 coordA = tex_coord * 3 + float2(0.10, 0.10);
	float2 coordB = tex_coord * 1 + float2(0.00, 0.10);
	float2 coordC = tex_coord * 2 + float2(0.00, 0.15);
	float2 coordD = tex_coord * 5 + float2(0.00, 0.30);

	// Uses textureNoTile for non repeting textures,
	// probably unnecessarily expensive
	float4 vBumpA = water_normal.Sample(water_normal_sampler, coordA);
	coordB += float2(0.03, -0.02) * time;
	float4 vBumpB = water_normal.Sample(water_normal_sampler, coordB);
	coordC += float2(0.03, -0.01) * time;
	float4 vBumpC = water_normal.Sample(water_normal_sampler, coordC);
	coordD += float2(0.02, -0.01) * time;
	float4 vBumpD = water_normal.Sample(water_normal_sampler, coordD);

	float3 vBumpTex = normalize(WaveModOne * (vBumpA.xyz + vBumpB.xyz +
		vBumpC.xyz + vBumpD.xyz) - WaveModTwo);


	float3 eyeDir = normalize(eyeDirection);
	float NdotL = max(dot(eyeDir, (vBumpTex / 2)), 0);

	NdotL = clamp((NdotL + WRAP) / (1 + WRAP), 0.f, 1.f);
	NdotL = lerp(NdotL, 1.0, 0.0);

	float3 OutColor = NdotL * (WorldColorColor * vColorMapFactor);

	float3	reflVector = -reflect(lightDirection, vBumpTex);
	float	specular = dot(normalize(reflVector), eyeDir);
	specular = clamp(specular, 0.0, 1.0);

	specular = pow(specular, SpecValueOne);
	OutColor += (specular / SpecValueTwo);
	OutColor *= 1.5;

	OutColor *= province_fow.Sample(province_fow_sampler, prov_id).rgb;

	return float4(OutColor, vWaterTransparens);
}

float4 get_water_political(float2 tex_coord) {
	float3 water_background = float3(0.21, 0.38, 0.45);
	float3 color = water_background.rgb;

	// The "foldable map" overlay effect
	float4 OverlayColor = overlay.Sample(overlay_sampler, tex_coord * float2(11., 11.*map_size.y/map_size.x));
	float4 OutColor;
	OutColor.r = OverlayColor.r < .5 ? (2. * OverlayColor.r * color.r) : (1. - 2. * (1. - OverlayColor.r) * (1. - color.r));
	OutColor.g = OverlayColor.r < .5 ? (2. * OverlayColor.g * color.g) : (1. - 2. * (1. - OverlayColor.g) * (1. - color.g));
	OutColor.b = OverlayColor.b < .5 ? (2. * OverlayColor.b * color.b) : (1. - 2. * (1. - OverlayColor.b) * (1. - color.b));
	OutColor.a = OverlayColor.a;

	return OutColor;
}

// The terrain color from the current texture coordinate offset with one pixel in the "corner" direction
float4 get_terrain(float2 corner, float2 offset, float2 tex_coord) {
	float index = terrain_texture.Sample(terrain_texture_sampler, floor(tex_coord * map_size + float2(0.5, 0.5)) / map_size + 0.5 * pix * corner).r;
	index = floor(index * 256);
	float is_water = step(64, index);
	float4 colour = terrain_texture.Sample(terrainsheet_texture_sampler, float3(offset, index));
	return lerp(colour, float4(0.), is_water);
}

float4 get_terrain_mix(float2 tex_coord) {
	// Pixel size on map texture
	float2 scaling = frac(tex_coord * map_size + float2(0.5, 0.5));

	float2 offset = tex_coord / (16. * pix);

	float4 colourlu = get_terrain(float2(-1, -1), offset, tex_coord);
	float4 colourld = get_terrain(float2(-1, +1), offset, tex_coord);
	float4 colourru = get_terrain(float2(+1, -1), offset, tex_coord);
	float4 colourrd = get_terrain(float2(+1, +1), offset, tex_coord);

	// Mix together the terrains based on close they are to the current texture coordinate
	float4 colour_u = lerp(colourlu, colourru, scaling.x);
	float4 colour_d = lerp(colourld, colourrd, scaling.x);
	float4 terrain = lerp(colour_u, colour_d, scaling.y);

	// Mixes the terrains from "texturesheet.tga" with the "colormap.dds" background color.
	float4 terrain_background = colormap_terrain.Sample(colormap_terrain_sampler, get_corrected_coords(tex_coord));
	terrain.xyz = (terrain.xyz * 2. + terrain_background.xyz) / 3.;
	return terrain;
}

float4 get_land_terrain(float2 tex_coord) {
	return get_terrain_mix(tex_coord);
}

float4 get_land_political_close(float2 tex_coord) {
	float4 terrain = get_terrain_mix(tex_coord);
	float is_land = terrain.a;

	// Make the terrain a gray scale color
	const float3 GREYIFY = float3( 0.212671, 0.715160, 0.072169 );
    float grey = dot( terrain.rgb, GREYIFY );
 	terrain.rgb = float3(grey);

	float2 tex_coords = tex_coord;
	float2 rounded_tex_coords = (floor(tex_coord * map_size) + float2(0.5, 0.5)) / map_size;
	
	uint test = diag_border_identifier.Sample(diag_border_identifier_sampler, rounded_tex_coords).x;
	float2 rel_coord = tex_coord * map_size - floor(tex_coord * map_size) - float2(0.5);
	int shift = int(sign(rel_coord.x) + 2 * sign(rel_coord.y) + 3);
	
	rounded_tex_coords.y += (((test >> shift) & 1) != 0) && (abs(rel_coord.x) + abs(rel_coord.y) > 0.5) ? sign(rel_coord.y) / map_size.y : 0;

	float2 prov_id = provinces_texture.Sample(provinces_texture_sampler, rounded_tex_coords).xy;

	// The primary and secondary map mode province colors
	float4 prov_color = province_color.Sample(province_color_sampler, float3(prov_id, 0.));
	float4 stripe_color = province_color.Sample(province_color_sampler, float3(prov_id, 1.));

	float2 stripe_coord = tex_coord * float2(512., 512. * map_size.y / map_size.x);

	// Mix together the primary and secondary colors with the stripes
	float stripeFactor = stripes_texture.Sample(stripes_texture_sampler, stripe_coord).a;
	float prov_highlight = province_highlight.Sample(province_highlight_sampler, prov_id).r * (abs(cos(time * 3.f)) + 1.f);
	float3 political = clamp(lerp(prov_color, stripe_color, stripeFactor) + float4(prov_highlight), 0.0, 1.0).rgb;
	political *= province_fow.Sample(province_fow_sampler, prov_id).rgb;
	political = political - 0.7;

	// Mix together the terrain and map mode color
	terrain.rgb = lerp(terrain.rgb, political, 0.3);
	terrain.rgb *= 1.5;
	//terrain.rgb += float3((test * 255) == id);
	//terrain.r += ((abs(rel_coord.y) + abs(rel_coord.x)) > 0.5 ? 6 : 0) * 0.3;
	return terrain;
}

float4 get_terrain_political_far(float2 tex_coord) {
	float4 terrain = get_terrain(float2(0, 0), float2(0), tex_coord);
	float is_land = terrain.a;
	float2 prov_id = provinces_texture.Sample(provinces_texture_sampler, tex_coord).xy;

	// The primary and secondary map mode province colors
	float4 prov_color = province_color.Sample(province_color_sampler, float3(prov_id, 0.));
	float4 stripe_color = province_color.Sample(province_color_sampler, float3(prov_id, 1.));

	float2 stripe_coord = tex_coord * float2(512., 512. * map_size.y / map_size.x);

	// Mix together the primary and secondary colors with the stripes
	float stripeFactor = stripes_texture.Sample(stripes_texture_sampler, stripe_coord).a;
	float prov_highlight = province_highlight.Sample(province_highlight_sampler, prov_id).r * (abs(cos(time * 3.f)) + 1.f);
	float3 political = clamp(lerp(prov_color, stripe_color, stripeFactor) + float4(prov_highlight), 0.0, 1.0).rgb;
	political = political - 0.7;

	// The "foldable map" overlay effect
	float4 OverlayColor = overlay.Sample(overlay_sampler, tex_coord * float2(11., 11.*map_size.y/map_size.x));
	float4 OutColor;
	OutColor.r = OverlayColor.r < .5 ? (2. * OverlayColor.r * political.r) : (1. - 2. * (1. - OverlayColor.r) * (1. - political.r));
	OutColor.g = OverlayColor.r < .5 ? (2. * OverlayColor.g * political.g) : (1. - 2. * (1. - OverlayColor.g) * (1. - political.g));
	OutColor.b = OverlayColor.b < .5 ? (2. * OverlayColor.b * political.b) : (1. - 2. * (1. - OverlayColor.b) * (1. - political.b));
	OutColor.a = OverlayColor.a;

	float3 background = colormap_political.Sample(colormap_political_sampler, get_corrected_coords(tex_coord)).rgb;
	OutColor.rgb = lerp(background, OutColor.rgb, 0.3);

	OutColor.rgb *= 1.5;
	OutColor.a = is_land;

	return OutColor;
}

// The terrain map
// No province color is used here
Output main(Input input) {
	float4 terrain = input.is_political_map ? get_land_political_close(input.tex_coord) : get_land_terrain(input.tex_coord);
	float is_land = terrain.a;
	float4 water = float4(0.21, 0.38, 0.55, 1.0f);
	water = input.is_political_map ? get_water_political(input.tex_coord) : get_water_terrain(input.tex_coord);

	Output output;
	output.frag_color = lerp(water, terrain, is_land);
	output.frag_color.a = 1;

	output.frag_color = gamma_correct(output.frag_color);
	return output;
}
