// in this context include refers to another shader file
includes = [ "core/stingray_renderer/shader_libraries/common.shader_source" "core/stingray_renderer/shader_libraries/lighting_common.shader_source" ] 

// TODO: disable sun if it's disabled in environment settings.

// TODO: velocity vectors important for SSR

// TODO: we are using clip depth as linear depth, which is incorrect

render_states = {
	filter_max = {
		inherits = "default"
		states = {
			z_write_enable = "false"

			blend_enable = "true"
			blend_op = "blend_op_max"
			dest_blend = "blend_one"
			src_blend = "blend_one"

			write_mask0 = "alpha"
		}
	}

	water_mask = {
		inherits = "default"
		states = {
			z_write_enable="false"
			write_mask0 = "red"
			cull_mode = "cull_none"
		}
	}
	
	water_depth_only = {
		inherits = "default"
		states = {
			defined_ONE_SIDED = {
				cull_mode = "cull_cw"
			}
			ndefined_ONE_SIDED = {
				cull_mode = "cull_none"
			}
		}
	}

	water_opacity = {
		inherits = "opacity"
		states = {
			defined_ONE_SIDED = {
				cull_mode = "cull_cw"
			}
		}
	}	
	
	wireframe = {
		inherits = "opacity"
		states = {
			fill_mode = "fill_wireframe"	
			defined_D3D11 = {
				depth_bias = "-1"
				depth_bias_clamp = "-0.00015"
				slope_scale_depth_bias = "-2.0"
			}
			defined_D3D12 = {
				depth_bias = "-1"
				depth_bias_clamp = "-0.00015"
				slope_scale_depth_bias = "-2.0"
			}
		}		
	}
}  

hlsl_shaders = {
	water_displaced = { 
		includes = [ "common", "gbuffer_access", "fog", "brdf" "taa_offsets" ]
		
		samplers = {
			ndefined_MASK = {
				defined_COLOR_EXTINCTION = {
					linear_depth = { sampler_states = "clamp_linear" }
				}
				ndefined_COLOR_EXTINCTION = {
					defined_FOAM = {
						linear_depth = { sampler_states = "clamp_linear" }
					}
					ndefined_FOAM = {
						defined_GEOMETRY_FADE_OUT = {
							linear_depth = { sampler_states = "clamp_linear" }
						}
					}
				}

				normal_map = { sampler_states = "wrap_anisotropic" }
				blend_normal_map = { sampler_states = "wrap_anisotropic" }
				
				hdr0 = { sampler_states = "clamp_linear" }
				ldr0 = { sampler_states = "clamp_point" }
				defined_CUSTOM_DIFFUSE_CUBEMAP = {
					diffuse_cubemap = { sampler_states = "clamp_linear"}
				}
				ndefined_CUSTOM_DIFFUSE_CUBEMAP = {
					global_diffuse_map = { sampler_states = "clamp_linear"}
				}

				defined_FOAM = {
					diffuse_map = { sampler_states = "wrap_anisotropic_srgb" }
					defined_FOAM_NORMAL_ROUGHNESS_MAP = {
						foam_normal_roughness_map = { sampler_states = "wrap_anisotropic" }
					}
				}
				ndefined_FOAM = {
					defined_CREST_FOAM = {
						diffuse_map = { sampler_states = "wrap_anisotropic_srgb" }
						defined_FOAM_NORMAL_ROUGHNESS_MAP = {
							foam_normal_roughness_map = { sampler_states = "wrap_anisotropic" }
						}
					}
				}

				defined_FORWARD_LIGHTING = {
					brdf_lut = { sampler_states = "clamp_linear"} 
					defined_CUSTOM_SPECULAR_CUBEMAP = {
						specular_cubemap = { sampler_states = "clamp_linear"}
					}
					ndefined_CUSTOM_SPECULAR_CUBEMAP = {
						global_specular_map = { sampler_states = "clamp_linear"}
					}
				}

				water_mask = { sampler_states = "clamp_point" }
			}
		}	
		
		code="""
			#ifdef VERTEX_DISPLACEMENT
				// Gerstner waves
				// http://http.developer.nvidia.com/GPUGems/gpugems_ch01.html
				// http://graphics.ucsd.edu/courses/rendering/2005/jdewall/tessendorf.pdf
				float3 gerstner_wave_displacement( float2 wave_direction, float wave_length, float wave_amplitude, float wave_steepness, float3 wp )
				{
					const float GRAVITY = 9.82;

					float w = 2 * PI / wave_length; 				// angular frequency
					float s = sqrt( GRAVITY * w );					// phase animation multiplier
					float q = wave_steepness/(w*wave_amplitude); 	// steepness 0 -> 1
					
					float2 xy = q * wave_amplitude * wave_direction * cos( w * dot( wave_direction, wp.xy ) + s * time );
					float z = wave_amplitude * sin( w * dot( wave_direction, wp.xy ) + s * time );
				
					return float3(xy, z);
				}
				
				float2 wave_direction_to_vector(float dir)
				{
					float x = dir < 0.5 ? dir*4-1 : (1-dir)*4-1;
					float y = dir < 0.5 ? abs(x)-1 : 1-abs(x);
					
					return float2(x,y);
				}
			#endif
				
			#if !defined(MASK)
				DECLARE_SAMPLER_2D(water_mask);

				#if defined(COLOR_EXTINCTION) || defined(FOAM) || defined(GEOMETRY_FADE_OUT)
					DECLARE_SAMPLER_2D(linear_depth);
				#endif

				DECLARE_SAMPLER_2D(normal_map); // exports={ name="Normal Map" type="resource" }
				DECLARE_SAMPLER_2D(blend_normal_map); // exports={ name="Perlin Noise Map" type="resource" }

				DECLARE_SAMPLER_2D(hdr0);
				DECLARE_SAMPLER_2D(ldr0);
				#ifdef CUSTOM_DIFFUSE_CUBEMAP
					DECLARE_SAMPLER_CUBE(diffuse_cubemap); // exports={ name="Diffuse Cubemap" type="resource" }
				#else
					DECLARE_SAMPLER_CUBE(global_diffuse_map);
					#define diffuse_cubemap global_diffuse_map
				#endif

				#if defined(FOAM) || defined(CREST_FOAM)
					DECLARE_SAMPLER_2D(diffuse_map); // exports={ name="Foam Map" type="resource" }
					#if defined(FOAM_NORMAL_ROUGHNESS_MAP)
						DECLARE_SAMPLER_2D(foam_normal_roughness_map); // exports={ name="Foam Normal Roughness Map" type="resource" }
					#endif
				#endif

				#ifdef FORWARD_LIGHTING
					DECLARE_SAMPLER_2D(brdf_lut);
					#ifdef CUSTOM_SPECULAR_CUBEMAP
						DECLARE_SAMPLER_CUBE(specular_cubemap); // exports={ name="Specular Cubemap" type="resource" }
					#else
						DECLARE_SAMPLER_CUBE(global_specular_map);
						#define specular_cubemap global_specular_map
					#endif
				#endif
			#endif

			struct VS_INPUT {
				float4 position : POSITION;
				#if !defined(MASK)
					float3 normal : NORMAL0;
					#ifndef WORLD_XY_AS_UV
						float3 tangent : TANGENT;
						float3 binormal : BINORMAL;
						float2 uv : TEXCOORD0;
					#endif
				#endif
			};
			
			struct PS_INPUT {
				float4 position : SV_POSITION;
				#if !defined(MASK)
					float4 wp : TEXCOORD0;
					#if defined(COLOR_EXTINCTION) || defined(FOAM)	
						float4 w : TEXCOORD1;
					#endif
					float3 tsm0 : TEXCOORD3;
					float3 tsm1 : TEXCOORD4;
					float3 tsm2 : TEXCOORD5;
					float4 uv : TEXCOORD2;
					#if defined(BLEND_TO_PERLIN_NOISE)
						float2 perlin_uv : TEXCOORD6;
					#endif
					#if defined(FOAM) || defined(CREST_FOAM)
						float2 foam_uv : TEXCOORD7;
					#endif 
					#if defined(CREST_FOAM)
						float wave_height : TEXCOORD8;
					#endif
				#endif
			};			
			
			CBUFFER_START(c0)
				float4x4 world;
				float4x4 view_proj;
				#if defined(VERTEX_DISPLACEMENT)
					float wave_direction; // exports = { name="Wave #1 Direction" type="scalar" min=0 max=1 value=0 step=0.001 }
					float wave_length; // exports = { name="Wave #1 Length" type="scalar" min=0.01 max=200 value=100.0 step=0.01 }
					float wave_amplitude; // exports = { name="Wave #1 Amplitude" type="scalar" min=0.01 max=3.0 value=0.3 step=0.01 }
					float wave_steepness; // exports = { name="Wave #1 Wave Steepness" type="scalar" min=0.0 max=1.0 value=0.1 step=0.01 }
					#if defined(VERTEX_DISPLACEMENT_2)
						float wave_direction_2; // exports = { name="Wave #2 Direction" type="scalar" min=0 max=1 value=0 step=0.001 }
						float wave_length_2; // exports = { name="Wave #2 Length" type="scalar" min=0.01 max=200 value=100.0 step=0.01 }
						float wave_amplitude_2; // exports = { name="Wave #2 Amplitude" type="scalar" min=0.01 max=3.0 value=0.3 step=0.01 }
						float wave_steepness_2; // exports = { name="Wave #2 Steepness" type="scalar" min=0.0 max=1.0 value=0.1 step=0.01 }
					#endif
				#endif

				float4 dev_wireframe_color;
			CBUFFER_END	
					
			#if !defined(MASK) && !defined(DRAW_WIREFRAME)
				CBUFFER_START(c_water)
					#ifdef WORLD_XY_AS_UV
						float2 layer0_normal_tile_size; // exports={ name="Layer 0 Normal Map Tile" type="vector2" value=[2.0 2.0] min=[0 0] max=[30 30] step=[0.01 0.01]}				
						float2 layer1_normal_tile_size; // exports={ name="Layer 1 Normal Map Tile" type="vector2" value=[1.0 1.0] min=[0 0] max=[30 30] step=[0.01 0.01]}
						#ifdef BLEND_TO_PERLIN_NOISE
							float2 perlin_noise_tile_size; //  exports={ name="Perlin Normal Map Tile" type="vector2" value=[1.0 1.0] min=[0 0] max=[30 30] step=[0.01 0.01]}
						#endif
						#if defined(FOAM) || defined(CREST_FOAM)
							float2 foam_tile_size; // exports={ name="Foam Map Tile" type="vector2" value=[2.0 2.0] min=[0 0] max=[30 30] step=[0.01 0.01]}
						#endif
					#else
						float2 layer0_normal_tile_scale; // exports={ name="Layer 0 Normal Map Scale" type="vector2" value=[2.0 2.0] min=[0 0] max=[30 30] step=[0.01 0.01]}				
						float2 layer1_normal_tile_scale; // exports={ name="Layer 1 Normal Map Scale" type="vector2" value=[1.0 1.0] min=[0 0] max=[30 30] step=[0.01 0.01]}
						#ifdef BLEND_TO_PERLIN_NOISE
							float2 perlin_noise_tile_size; //  exports={ name="Perlin Normal Map Scale" type="vector2" value=[1.0 1.0] min=[0 0] max=[30 30] step=[0.01 0.01]}
						#endif
						#if defined(FOAM) || defined(CREST_FOAM)
							float2 foam_tile_scale; // exports={ name="Foam Map Scale" type="vector2" value=[2.0 2.0] min=[0 0] max=[30 30] step=[0.01 0.01]}				
						#endif						
					#endif	
					float2 layer0_normal_tile_scroll_speed; // exports={ name="Layer 0 Normal Map Scroll Speed" type="vector2" value=[0.1 0.1] min=[-2 -2] max=[2 2] step=[0.005 0.005]}
					float2 layer1_normal_tile_scroll_speed; // exports={ name="Layer 1 Normal Map Scroll Speed" type="vector2" value=[0.1 0.1] min=[-2 -2] max=[2 2] step=[0.005 0.005]}
					#ifdef BLEND_TO_PERLIN_NOISE
						float2 perlin_noise_tile_scroll_speed; // exports={ name="Perlin Noise Scroll Speed" type="vector2" value=[0.1 0.1] min=[-2 -2] max=[2 2] step=[0.005 0.005]}					
						float3 perlin_noise_octaves; // exports={ name="Perlin Noise Octaves" type="vector3" value=[1.12 0.59 0.23] min=[0 0 0] max=[2 2 2] step=[0.005 0.005 0.005]}
						float3 perlin_noise_gradients; // exports={ name="Perlin Noise Gradients" type="vector3" value=[1.4 1.6 2.2] min=[0 0 0] max=[3 3 3] step=[0.005 0.005 0.005]} 
						float2 perlin_noise_blend; // exports = { name="Perlin Noise Blend Start/Distance" type="vector2" value=[80 150] min=[10 10] max=[1000 1000] step=[0.5 0.5]}
					#endif
					#if defined(FOAM) || defined(CREST_FOAM)
						float2 foam_tile_scroll_speed; // exports={ name="Foam Map Scroll Speed" type="vector2" value=[0.1 0.1] min=[-2 -2] max=[2 2] step=[0.005 0.005]}				
						#if defined(FOAM)
							float foam_fade_in; // exports={ name="Foam Fade in Depth" type="scalar" value=0.2 min=0.01 max=2.0 step=0.005 }
						#endif
					#endif
					float2 fresnel_settings; // exports={ name="Fresnel Settings [bias, exp]" type="vector2" value=[0.1 3] min=[0 0] max=[1 10] step=[0.001 0.005]}
					float refraction_amount; // exports={ name="Refraction Amount" type="scalar" value=0.01 min=0.0 max=1.0 step=0.001 }
					float water_metallic; // exports={ name="Metallic" type="scalar" value=1.0 min=0.0 max=1.0 step=0.001 }
					float water_roughness; // exports={ name="Roughness" type="scalar" value=0.0 min=0.0 max=1.0 step=0.001 }
					#if defined(FOAM) || defined(CREST_FOAM)
						float foam_metallic; // exports={ name="Foam Metallic" type="scalar" value=0.0 min=0.0 max=1.0 step=0.001 }
						#if !defined(defined_FOAM_NORMAL_ROUGHNESS_MAP)
							float foam_roughness; // exports={ name="Foam Roughness" type="scalar" value=0.3 min=0.0 max=1.0 step=0.001 }
						#endif
					#endif

					float normal_contrast; // exports={ name="Normal Contrast" type="scalar" value=1 min=0.0 max=1.0 step=0.001 }	
					float3 base_color; // exports={ name="Surface Color" type="vector3" value=[0.02 0.02 0.02] min=[0 0 0] max=[1 1 1] step=[0.001 0.001 0.001]}										
					#ifdef COLOR_EXTINCTION	
						float3 color_extinction; // exports={ name="RGB color extinction depth" type="vector3" value=[4.5 75 300] min=[0 0 0] max=[300 300 300] step=[0.2 0.2 0.2] }	
						float3 depth_color; // exports={ name="Deep Water Color" type="vector3" value=[0.1 0.1 0.4] min=[0 0 0] max=[4 4 4] step=[0.005 0.005 0.005] }	
					#endif
					#ifdef GEOMETRY_FADE_OUT
						float geometry_fade_out_distance; // exports={ name="Geometry Fade out Distance" type="scalar" value=0.2 min=0.01 max=0.8 step=0.005 }
					#endif
					
					#if defined(CREST_FOAM)
						half crest_foam_min_height; // exports = { name="Crest Foam Min Height" type="scalar" min=-3.0 max=3.0 value=0.0 step=0.01 }
						half crest_foam_max_height; // exports = { name="Crest Foam Max Height" type="scalar" min=-3.0 max=3.0 value=0.5 step=0.01 }
						half crest_foam_strength; // exports = { name="Crest Foam Strength" type="scalar" min=0.0 max=1.0 value=0.5 step=0.01 }
					#endif

					float3 ambient_tint;
					float sun_enabled;
					float  ambient_diffuse_fade_type;
					float3 ambient_diffuse_fade; // min multiplier, height offset, falloff
				CBUFFER_END			
			#endif

			DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
			PS_INPUT vs_main(VS_INPUT input) {
				PS_INPUT o;
				float3 wp = mul(input.position, world);

				#if defined(VERTEX_DISPLACEMENT)
					float3 displacement = gerstner_wave_displacement( wave_direction_to_vector(wave_direction), wave_length, wave_amplitude, wave_steepness, wp );
					#ifdef VERTEX_DISPLACEMENT_2
						displacement += gerstner_wave_displacement( wave_direction_to_vector(wave_direction_2), wave_length_2, wave_amplitude_2, wave_steepness_2, wp );
					#endif
					wp += displacement;
					
					// Frequency adjusted to water depth
					//float D = 50;
					//float k = 2 * PI / l;
					//float w = sqrt( GRAVITY * k * tanh(k*D) );
				#endif
				float4 p = mul(float4(wp, 1), view_proj);

				float4 view_space = p / p.w;
				view_space.xy += get_vs_halton_offset(frame_number);
				o.position = view_space * p.w;

				#if defined(MASK) || defined(DRAW_WIREFRAME)
					return o;
				#else
					#if defined(CREST_FOAM)
						o.wave_height = displacement.z;
					#endif

					#if defined(COLOR_EXTINCTION) || defined(FOAM)
						o.w = encode_world_pos(o.position);
					#endif
					o.wp.xyz = wp;
					o.wp.w = linearize_depth(o.position.z / o.position.w);
					
					#define layer0_scroll layer0_normal_tile_scroll_speed
					#define layer1_scroll layer1_normal_tile_scroll_speed
					#define foam_scroll foam_tile_scroll_speed
						
					float3 normal = input.normal;
					#ifdef WORLD_XY_AS_UV
						float3 tangent = float3(-1,0,0);
						float3 binormal = float3(0,-1,0);
					#else
						float3 tangent = input.tangent;
						float3 binormal = input.binormal;
					#endif
					tspace_transform_transpose(o.tsm0, o.tsm1, o.tsm2, tangent, binormal, normal, (float3x3)world);

					#ifdef WORLD_XY_AS_UV	
						o.uv = float4(	(wp.xy / layer0_normal_tile_size) + time * layer0_scroll,
										(wp.xy / layer1_normal_tile_size) + time * layer1_scroll);
						#ifdef BLEND_TO_PERLIN_NOISE
							o.perlin_uv.xy = (wp.xy / perlin_noise_tile_size);
						#endif
						
						#if defined(FOAM) || defined(CREST_FOAM)
							o.foam_uv = float2((wp.xy / foam_tile_size) + time * foam_scroll);
						#endif
					#else
						o.uv = float4(	(input.uv * layer0_normal_tile_scale) + time * layer0_scroll,
										(input.uv * layer1_normal_tile_scale) + time * layer1_scroll);
						#ifdef BLEND_TO_PERLIN_NOISE
							o.perlin_uv.xy = (wp.xy * perlin_noise_tile_size);
						#endif
						
						#if defined(FOAM) || defined(CREST_FOAM)
							o.foam_uv = float2((input.uv * foam_tile_scale) + time * foam_scroll);
						#endif												
					#endif

					return o;
				#endif
			}
			
			half fresnel(half n_dot_e, half bias, half power) {
				return saturate(bias + (1-bias) * pow(1-n_dot_e, power));
			}
			
			#if defined(MASK)
				DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
				float4 ps_main(PS_INPUT input) : SV_TARGET0 {
					return float4(1,1,1,1);
				}
			#elif defined(DRAW_WIREFRAME)
				DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
				float4 ps_main(PS_INPUT input) : SV_TARGET0 {
					return dev_wireframe_color;
				}
			#else
				DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
				float4 ps_main(PS_INPUT input
					#if !defined(ONE_SIDED)
						#if defined(GNM)
							, bool vface : S_FRONT_FACE
						#else
							, float vface : VFACE
						#endif
					#endif
					) : SV_TARGET0 
				{					
					#if !defined(AVOID_CAMERA_CULLING)
						if (camera_pos.z < input.wp.z) {
							// Camera is under water surface
							discard;
						} 	
					#endif
					
					#if defined(GL2)
						half2 screen_uv = wpos.xy / back_buffer_size;
					#else
						half2 screen_uv = input.position.xy / back_buffer_size;				
					#endif
					
					float3 view_vector = camera_pos - input.wp;
					float3 view_dir = normalize(view_vector);
					
					#ifdef BLEND_TO_PERLIN_NOISE
						half blend = saturate((length(view_vector.xy) - perlin_noise_blend.x) / perlin_noise_blend.y);
						normal_contrast = lerp(1, normal_contrast, blend);
					
						half2 perlin0_uv = blend > 0 ? input.perlin_uv.xy * perlin_noise_octaves.x + perlin_noise_tile_scroll_speed * time : 0;
						half2 perlin1_uv = blend > 0 ? input.perlin_uv.xy * perlin_noise_octaves.y + perlin_noise_tile_scroll_speed * time : 0;
						half2 perlin2_uv = blend > 0 ? input.perlin_uv.xy * perlin_noise_octaves.z + perlin_noise_tile_scroll_speed * time : 0;				
						half2 perlin0 = TEX2D(blend_normal_map, perlin0_uv).xy;
						half2 perlin1 = TEX2D(blend_normal_map, perlin1_uv).xy;
						half2 perlin2 = TEX2D(blend_normal_map, perlin2_uv).xy;
						
						half2 perlin = perlin0 * perlin_noise_gradients.x + perlin1 * perlin_noise_gradients.y + perlin2 * perlin_noise_gradients.z;				
						
						input.uv *= blend > 1 ? 0 : 1;
					#endif
					
					half2 tnormal_grad = decode_normal_grad(TEX2D(normal_map, input.uv.xy)) + decode_normal_grad(TEX2D(normal_map, input.uv.zw));
									
					//float3 tnormal = normalize(float3(normal_contrast,normal_contrast,1) * (decode_normal_map(TEX2D(normal_map, input.uv.xy)) + decode_normal_map(TEX2D(normal_map, input.uv.zw))));
					#ifdef BLEND_TO_PERLIN_NOISE					
						float3 tnormal = normalize(float3(normal_contrast * lerp(tnormal_grad, perlin, blend), 1));
					#else
						float3 tnormal = normalize(float3(normal_contrast * tnormal_grad, 1));
					#endif
					
					#if !defined(ONE_SIDED)
						if (!front_facing(vface)) {
							input.tsm0.z = -input.tsm0.z;
							input.tsm1.z = -input.tsm1.z;
							input.tsm2.z = -input.tsm2.z;
						}
					#endif
					float3 wn = rotate_vector3(tnormal, input.tsm0, input.tsm1, input.tsm2);						

					// calc under water color
					half2 refracted_uv = screen_uv + tnormal.xy * refraction_amount;
					half refraction_mask = TEX2D(water_mask, refracted_uv).r;
					refracted_uv = lerp(screen_uv, refracted_uv, refraction_mask);
					half3 refracted_texel = TEX2D(hdr0, refracted_uv);
					float3 under_water_color = refracted_texel;
					
					// calc fresnel term
					half cosNV = saturate(dot(wn, view_dir));
					half f = fresnel(cosNV, fresnel_settings.x, fresnel_settings.y);				
					
					#if defined(COLOR_EXTINCTION) || defined(FOAM) || defined(GEOMETRY_FADE_OUT)
						float d = gbuffer_decode_depth(TEX2D(linear_depth, screen_uv));
					#endif

					#if defined(COLOR_EXTINCTION) || defined(FOAM)					
						float3 wp = decode_world_pos(input.w, d);					
						float water_depth = abs(wp.z - input.wp.z);
					#endif

					#if defined(COLOR_EXTINCTION)
						under_water_color = lerp(under_water_color, depth_color, saturate(water_depth / color_extinction));
					#endif
					
					#ifdef GEOMETRY_FADE_OUT				
						half op = saturate(abs(d - input.wp.w) / geometry_fade_out_distance);
					#else
						half op = 1;
					#endif

					#ifdef MASK_WITH_DEFERRED_SHADOW
						// TODO: The correct way, would be to sample the depth values from the shadows slices and then compare to the surface depth, however this is probably to expensive.
						half4 shadow = TEX2D(ldr0, screen_uv).r; 
					#else
						half shadow = 1;
					#endif

					half roughness = water_roughness; 
					half metallic = water_metallic;
					
					#if defined(FOAM) || defined(CREST_FOAM)
						#if defined(FOAM_GEOMETRY_NORMALS)
							float3 foam_wn = normalize(float3(input.tsm0.z, input.tsm1.z, input.tsm2.z));
						#elif defined(FOAM_NORMAL_ROUGHNESS_MAP)
							float4 foam_normal_roughness = TEX2D(foam_normal_roughness_map, input.foam_uv);
							float3 foam_wn = normalize(2.0*foam_normal_roughness.rgb - 1.0);
							float foam_roughness = foam_normal_roughness.a;
						#else
							float3 foam_wn = wn;
						#endif

						half4 foam_texel = TEX2D(diffuse_map, input.foam_uv);
						#if defined(FOAM)
							#if defined(ALPHA_WEIGHT_FOAM)
								half foam_intensity = foam_texel.a - saturate(water_depth / foam_fade_in) * foam_texel.a;
							#else
								half foam_intensity = 1.0 - saturate(water_depth / foam_fade_in);
							#endif
							#if !defined(SEPERABLE_LIGHTING)
								#if defined(FOAM_GEOMETRY_NORMALS) || defined(FOAM_NORMAL_ROUGHNESS_MAP)
									wn = lerp(wn, foam_wn, foam_intensity);
								#endif
								metallic = lerp(metallic, foam_metallic, foam_intensity); 
								roughness = lerp(roughness, foam_roughness, foam_intensity); 
								base_color = lerp(base_color, foam_texel.rgb, foam_intensity);
								f = lerp(f, 1.0, foam_intensity);
							#endif
						#endif
						
						#if defined(CREST_FOAM)
							#if defined(ALPHA_WEIGHT_CREST_FOAM)
								half crest_foam_intensity = saturate((input.wave_height - crest_foam_min_height) / (crest_foam_max_height - crest_foam_min_height)) * foam_texel.a * crest_foam_strength;
							#else
								half crest_foam_intensity = saturate((input.wave_height - crest_foam_min_height) / (crest_foam_max_height - crest_foam_min_height)) * crest_foam_strength;
							#endif
							#if !defined(SEPERABLE_LIGHTING)
								#if defined(FOAM_GEOMETRY_NORMALS) || defined(FOAM_NORMAL_ROUGHNESS_MAP)
									wn = lerp(wn, foam_wn, crest_foam_intensity);
								#endif
								metallic = lerp(metallic, foam_metallic, crest_foam_intensity); 
								roughness = lerp(roughness, foam_roughness, crest_foam_intensity);
								base_color = lerp(base_color, foam_texel.rgb, crest_foam_intensity);
								f = lerp(f, 1.0, crest_foam_intensity);
							#endif
						#endif
					#endif

					#if defined(D3D11)
						ambient_tint = (capture_cubemap == 1) ? 1.0 : ambient_tint;
					#endif

					// TODO: use clustered shading instead!

					float3 indirect_light_tint = ambient_tint;
					float fade_type = ambient_diffuse_fade_type;
					float3 fade_params = ambient_diffuse_fade;
					[branch]
					if(fade_type != 0.0) {
						if(fade_type == 1.0) {
							indirect_light_tint *= max(fade_params.x, 1.0 - exp((input.wp.z - fade_params.y)/fade_params.z));
						} else if(fade_type == 2.0) {
							indirect_light_tint *= max(fade_params.x, 1.0 - exp((fade_params.y - input.wp.z)/fade_params.z));
						} else {
							indirect_light_tint *= max(fade_params.x, 1.0 - exp(-abs(fade_params.y - input.wp.z)/fade_params.z));
						}
					}

					// Same lighting code as in global_lighting
					// 0.04 is taken as a common value for dielectrics. Source: Real-time rendering 3rd edition.
					float3 specular_color = lerp(float3(0.04,0.04,0.04), base_color, metallic); 
					float3 diffuse_color = lerp(base_color, float3(0,0,0), metallic);

					float3 L = normalize(-sun_direction); // TODO: unnecessary normalization?
					float2 scale_bias = TEX2D(brdf_lut, float2(cosNV, roughness).xy).xy;

					float mipmap_index = roughness * 7;
					#ifdef FLIP_DIFFUSE_CUBEMAP
						float3 ambient = rgbm_decode(TEXCUBELOD(diffuse_cubemap, -wn, 0)) * indirect_light_tint * diffuse_color;
					#else
						float3 ambient = rgbm_decode(TEXCUBELOD(diffuse_cubemap, wn, 0)) * indirect_light_tint * diffuse_color;
					#endif
					#ifdef FLIP_SPECULAR_CUBEMAP
						ambient += rgbm_decode(TEXCUBELOD(specular_cubemap, -reflect(-view_dir, wn), mipmap_index)) * (specular_color * scale_bias.x + scale_bias.y) * indirect_light_tint;
					#else
						ambient += rgbm_decode(TEXCUBELOD(specular_cubemap, reflect(-view_dir, wn), mipmap_index)) * (specular_color * scale_bias.x + scale_bias.y) * indirect_light_tint;
					#endif

					//#if defined(SUN_ENABLED)
						float3 acc_diff = 0;
						float3 acc_spec = 0;
						if (sun_enabled)
							bsdf(L, view_dir, wn, sun_color, diffuse_color, specular_color, roughness, shadow, acc_diff, acc_spec);

						float3 surface_color = ambient + acc_diff + acc_spec;
					//#else
					//	float3 surface_color = ambient;
					//#endif

					// lerp between them				
					float3 c = lerp(under_water_color, surface_color, f);

					// Do lighting again for foam
					// Reusing ambient, even if this is incorrect.
					#if defined(SEPERABLE_LIGHTING)
						float foam_alpha = 0.0;
						#if defined(FOAM)
							foam_alpha += foam_intensity;
						#endif
						#if defined(CREST_FOAM)
							foam_alpha += crest_foam_intensity;
						#endif
						foam_alpha = min(foam_alpha, 1.0);
						float3 foam_specular_color = lerp(float3(0.04,0.04,0.04), foam_texel.rgb, foam_metallic); 
						float3 foam_diffuse_color = lerp(foam_texel.rgb, float3(0,0,0), foam_roughness);
						float2 foam_scale_bias = TEX2D(brdf_lut, float2(dot(foam_wn, view_dir), foam_roughness).xy).xy;
						float foam_mipmap_index = foam_roughness * 7;
						#ifdef FLIP_DIFFUSE_CUBEMAP
							float3 foam_ambient = rgbm_decode(TEXCUBELOD(diffuse_cubemap, -foam_wn, 0)) * diffuse_tint * foam_diffuse_color;
						#else
							float3 foam_ambient = rgbm_decode(TEXCUBELOD(diffuse_cubemap, foam_wn, 0)) * diffuse_tint * foam_diffuse_color;
						#endif
						#ifdef FLIP_SPECULAR_CUBEMAP
							foam_ambient += rgbm_decode(TEXCUBELOD(specular_cubemap, -reflect(-view_dir, foam_wn), foam_mipmap_index)) * (foam_specular_color * foam_scale_bias.x + foam_scale_bias.y) * reflections_tint;
						#else
							foam_ambient += rgbm_decode(TEXCUBELOD(specular_cubemap, reflect(-view_dir, foam_wn), foam_mipmap_index)) * (foam_specular_color * foam_scale_bias.x + foam_scale_bias.y) * reflections_tint;
						#endif
						float3 foam_acc_diff = 0;
						float3 foam_acc_spec = 0;
						if (sun_enabled)
							bsdf(L, view_dir, foam_wn, sun_color, foam_diffuse_color, foam_specular_color, foam_roughness, shadow, foam_acc_diff, foam_acc_spec);
						float3 foam_color = foam_ambient + foam_acc_diff + foam_acc_spec;
						c = lerp(c, foam_color, foam_alpha);
					#endif
					
					return apply_fog(float4(c, op), input.wp.xyz, input.wp.w);
				}
			#endif
		"""
	}
}  
   
shaders = {
	water = {
		editor_options = [
			{
				name="Water Shading"
				options = [
					{ name="Seperable Foam Lighting" define="SEPERABLE_LIGHTING" condition="FOAM || CREST_FOAM"}
				]
			}
			{
				name="UV Generation"
				options = [
					{ name="Base UV coordinates on World XY" define="WORLD_XY_AS_UV" }					
				]
			}
			{
				name="Water Surface Features"
				options = [
					{ name="Depth color extinction" define="COLOR_EXTINCTION" }
					{ name="Geometry Fade out" define="GEOMETRY_FADE_OUT" }
					{ name="Depth Foam" define="FOAM" }
					{ name="Crest Foam" define="CREST_FOAM" condition="VERTEX_DISPLACEMENT" }
					{ name="Weight Depth Foam with Alpha" define="ALPHA_WEIGHT_FOAM" condition="FOAM" }
					{ name="Weight Crest Foam with Alpha" define="ALPHA_WEIGHT_CREST_FOAM" condition="CREST_FOAM" }
					{ name="Foam Uses Geometry Normals" define="FOAM_GEOMETRY_NORMALS" condition="!FOAM_NORMAL_ROUGHNESS_MAP && (FOAM || CREST_FOAM)" }
					{ name="Foam Normal-Roughness Map" define="FOAM_NORMAL_ROUGHNESS_MAP" condition="!FOAM_GEOMETRY_NORMALS && (FOAM || CREST_FOAM)" }
					{ name="Blend to perlin noise to hide tiling" define="BLEND_TO_PERLIN_NOISE" }
					{ name="Mask sun with deferred shadows" define="MASK_WITH_DEFERRED_SHADOW" }
					
				]
			}
			{
				name="Vertex Displacement"
				options = [
					{ name="Vertex Displaced Wave" define="VERTEX_DISPLACEMENT" }
					{ name=" - Wave #2" define="VERTEX_DISPLACEMENT_2" }
				]
			}
			{
				name="Vertex Displacement"
				options = [
					{ name="Vertex Displaced Wave" define="VERTEX_DISPLACEMENT" }
					{ name=" - Wave #2" define="VERTEX_DISPLACEMENT_2" }
				]
			}
			{
				name="Pixel Modifiers"
				options = [
					{ name="Avoid Culling Water with Camera Z" define="AVOID_CAMERA_CULLING" }
					{ name="Use Custom Specular Cubemap" define="CUSTOM_SPECULAR_CUBEMAP" }
					{ name="Use Custom Diffuse Cubemap" define="CUSTOM_DIFFUSE_CUBEMAP" }
					{ name="Flip Specular Cubemap" define="FLIP_SPECULAR_CUBEMAP" }
					{ name="Flip Diffuse Cubemap" define="FLIP_DIFFUSE_CUBEMAP" }
				]
			}
			{
				name="Misc"
				options = [
					{ name="One Sided" define="ONE_SIDED" }
				]
			}
		]
		
		contexts = {
			default = {	
				passes = [
					{ layer="water_mask" hlsl_shader="water_displaced" defines="MASK" render_states="water_mask" }
					{ layer="water" hlsl_shader="water_displaced" defines="FORWARD_LIGHTING" render_states="water_opacity" }
					{ layer="wireframe" hlsl_shader="water_displaced" defines="DRAW_WIREFRAME" render_states="wireframe" branch_key="dev_wireframe" }
				]			
			}
		}	
		
		compile = {
			default = [
				{ defines=[] }
			]	
		} 
	}
} 
