// This whole file consist of place holder shaders -- will be removed and authored using the graph based system soon.

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

render_states = {
	ambient_no_depth_write = {
		inherits = "ambient"
		states = {
			z_write_enable = "false"
		}
	}
	filter = {
		inherits = "default"
		states = {
			cull_mode = "cull_none"
			z_write_enable = "false"
			z_enable = "false"
		}
	}
	wireframe = {
		inherits = "opacity"
		states = {
			fill_mode = "fill_wireframe"
			z_write_enable = "true"
			z_func = "less"
			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 = {
	gbuffer_base = {
		includes = [ "common", "gbuffer_access", "taa_offsets" ]

		samplers = {
			// global_diffuse_map = { sampler_states = "clamp_linear"}
		}

		glsl_code = """
			CBUFFER_START(c_per_object)
				UNIFORM mat4 world_view_proj;
				UNIFORM mat4 world;
				UNIFORM vec3 diffuse_rgb;
			CBUFFER_END

			#if defined(VC_TINT_RGB)
				#define VERTEX_COLOR
			#endif

			#if defined(STAGE_VERTEX)
				layout(location = POSITION0) in vec4 in_position;
				layout(location = NORMAL) in vec3 in_normal;

				#if defined(VERTEX_COLOR)
					layout(location = COLOR0) in vec4 in_color;
					out vec4 v_color;
				#endif

				out vec3 v_normal;

				void main() {
					v_normal = in_normal * mat3(world);

					#if defined(VERTEX_COLOR)
						#if defined(VC_COMPRESSED)
							v_color = decode_vertex_color(in_color);
						#else
							v_color = in_color;
						#endif
					#endif

					gl_Position = in_position * world_view_proj;
				}
			#elif defined(STAGE_FRAGMENT)
				GBUFFER_OUTPUT;
				in vec3 v_normal;

				#if defined(VERTEX_COLOR)
					in vec4 v_color;
				#endif

				DECLARE_SAMPLER_CUBE(global_diffuse_map);

				void main() {
					// Base color
					out_base_color = gbuffer_encode_base_color(diffuse_rgb);
					#if defined(VC_TINT_RGB)
						out_base_color *= fast_gamma_to_linear_rgb(v_color.rgb);
					#endif

					// Normal
					mediump vec3 wn = normalize(v_normal);
					out_normal = gbuffer_encode_normal(wn);

					// Metallic
					out_metallic = gbuffer_encode_metallic_mask(0.0);

					// Roughness
					out_roughness = gbuffer_encode_roughness(0.75);

					// Ambient Diffuse
					mediump vec3 ambient = rgbm_decode(TEXCUBELOD(global_diffuse_map, wn, 0.0));
					out_ambient_diffuse_light = gbuffer_encode_ambient_diffuse_light(ambient);

					out_ambient_occlusion = gbuffer_encode_ambient_occlusion(1.0f);
				}
			#endif
		"""

		code = """
			#if defined(VC_TINT_RGB)
				#define VERTEX_COLOR
			#endif

			struct VS_INPUT {
				float4 position : POSITION;
				float3 normal : NORMAL0;
				#if defined(VERTEX_COLOR)
					float4 color : COLOR0;
				#endif

			};

			struct PS_INPUT {
				float4 position : SV_POSITION;
				float3 normal : TEXCOORD0;
				#if defined(VERTEX_COLOR)
					float4 color : COLOR0;
				#endif
				#if defined(MOTION_BLUR)
					float3 last_clip_position : TEXCOORD1;
				#endif				
			};

			CBUFFER_START(c_per_object)
				float4x4 world_view_proj;
				float4x4 world;
				float4x4 last_world;
				float3 diffuse_rgb; // exports={ name="Diffuse RGB" type="vector3" value=[0.5 0.5 0.5] min=[0 0 0] max=[1 1 1] step=[0.001 0.001 0.001] }
				float4 dev_wireframe_color;
			CBUFFER_END

			// DECLARE_SAMPLER_CUBE(global_diffuse_map);

			DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
			PS_INPUT vs_main(VS_INPUT input) {
				PS_INPUT o;

				float4 p = mul(input.position, world_view_proj);

				#if defined(DRAW_WIREFRAME) 
					o.position = p;
				#else
					float4 view_space = p / p.w;
					// Multiply the halton offset by 2 since we are adding the offset in view space (non projected frustrum width and height ranges [-1, 1])
					view_space.xy += get_vs_halton_offset(frame_number);
					o.position = view_space * p.w;
				#endif

				o.normal = mul(input.normal, (float3x3)world);

				#if defined(VERTEX_COLOR)
					#if defined(VC_COMPRESSED)
						o.color = decode_vertex_color(input.color);
					#else
						o.color = input.color;
					#endif
				#endif				

				#if defined(MOTION_BLUR)
					float4 last_wp = mul(input.position, last_world);
					float4 last_clip_pos = mul(last_wp, camera_last_view_projection);
					float4 last_view_space = last_clip_pos / last_clip_pos.w;
					last_view_space.xy += get_vs_halton_offset(frame_number);
					last_view_space.xy = last_view_space.xy * 0.5 + 0.5;
					last_view_space.y = 1.0 - last_view_space.y;					
					last_clip_pos = last_view_space * last_clip_pos.w;
					o.last_clip_position = last_clip_pos.xyw;
 				#endif

				return o;
			}

			#ifdef DRAW_WIREFRAME
				DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
				float4 ps_main(PS_INPUT input) : SV_TARGET0 {
					return dev_wireframe_color;
				}
			#else
				DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
				GBUFFER_OUT ps_main(PS_INPUT input) {
					GBUFFER_OUT o;

					half4 diffuse = half4(diffuse_rgb, 1);

					#if defined(VC_TINT_RGB)
						diffuse.rgb *= fast_gamma_to_linear_rgb(input.color.rgb);
					#endif					

					float3 wn = normalize(input.normal);					
					BASE_COLOR(o) = gbuffer_encode_base_color(diffuse.rgb);
					NORMAL(o) = gbuffer_encode_normal(wn);
					METALLIC(o) = gbuffer_encode_metallic_mask(0);
					ROUGHNESS(o) = gbuffer_encode_roughness(0.75);

					// Since we don't have baked lighting, we don't use this
					// float3 ambient = rgbm_decode(TEXCUBELOD(global_diffuse_map, wn, 0));
					// AMBIENT_DIFFUSE_LIGHT(o) = gbuffer_encode_ambient_diffuse_light(ambient);

					#if defined(MOTION_BLUR)
						float3 last_clip_pos = input.last_clip_position;
						float2 screen_pos = (input.position.xy / back_buffer_size - viewport.zw) / viewport.xy;
						float2 last_screen_pos = last_clip_pos.xy / last_clip_pos.z;
						VELOCITY(o) = encode_velocity(viewport.xy*(screen_pos - last_screen_pos));
					#else
						// Velocity and occlusion is written to gbuffer2. If not written to but
						// writes to gbuffer3 are done the gpu on PS4 will crash.
						VELOCITY(o) = encode_velocity(float2(0.0, 0.0));
					#endif

					AMBIENT_OCCLUSION(o) = 1.f;
					DENSITY(o) = 1.0;
					return o;
				}
			#endif
		"""
	}

	depth_only = {
		includes = [ "common" ]

		samplers = {
		}

		glsl_code = """
			CBUFFER_START(c_per_object)
				UNIFORM mat4 world_view_proj;
			CBUFFER_END

			#if defined(STAGE_VERTEX)
				layout(location = POSITION0) in vec4 in_position;
				void main() {
					gl_Position = in_position * world_view_proj;
				}
			#elif defined(STAGE_FRAGMENT)
				void main() { }
			#endif
		"""

		code = """
			struct VS_INPUT {
				float4 position : POSITION;
			};

			struct PS_INPUT {
				float4 position : SV_POSITION;
			};

			CBUFFER_START(c0)
				float4x4 world_view_proj;
			CBUFFER_END

			DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
			PS_INPUT vs_main(VS_INPUT input) {
				PS_INPUT o;
				o.position = mul(input.position, world_view_proj);
				return o;
			}

			DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
			float4 ps_main() : SV_TARGET0 {
				return float4(1,1,1,1);
			}
		"""
	}

	forward_emissive = {
		includes = [ "common", "gbuffer_access" ]

		samplers = {
			defined_SKYDOME = {
				skydome_map = { sampler_states = "wrap_anisotropic" }
			}
		}

		vp_code = """
			layout(location = POSITION0) in vec4 in_pos;
			layout(location = TEXCOORD0) in vec2 in_uv0;

			#if defined(SKYDOME)
				out lowp vec2 v_uv;
			#endif

			CBUFFER_START(c0)
				UNIFORM mat4 world;
				UNIFORM mat4 view;
				UNIFORM mat4 proj;
			CBUFFER_END

			void main() {
				HIGHP mat4 v = view;
				HIGHP vec4 wp = in_pos * world;

				#ifdef CAMERA_LOCK_XY
					v[0][3] = 0.0;
					v[1][3] = 0.0;
					#ifdef CAMERA_LOCK_Z
						v[2][3] = 0.0;
					#endif
				#endif

				wp = wp * v * proj;
				#ifdef PROJECT_TO_FAR_PLANE
					wp.z = wp.w;
				#endif
				#if defined(SKYDOME)
					v_uv = in_uv0;
				#endif
				gl_Position = wp;
			}
		"""

		fp_code = """
			#if defined(SKYDOME)
				in lowp vec2 v_uv;
				DECLARE_SAMPLER_2D(skydome_map);

				CBUFFER_START(c1)
					UNIFORM float skydome_intensity;
				CBUFFER_END
			#endif

			layout(location = 0) out vec4 color;

			void main() {
				#if defined(SKYDOME)
					lowp vec4 c = texture(skydome_map, v_uv);
					c.rgb *= skydome_intensity;
					color = c;
				#else
					color = vec4(0.5, 0.5, 0.5, 1);
				#endif
			}
		"""

		code="""
			#if defined(SKYDOME)
				#define UV0
				DECLARE_SAMPLER_2D(skydome_map);
			#endif

			struct VS_INPUT {
				float4 position : POSITION;
				#if defined(UV0)
					float2 uv : TEXCOORD0;
				#endif
			};

			struct PS_INPUT {
				float4 position : SV_POSITION;
				#if defined(UV0)
					float2 uv : TEXCOORD0;
				#endif
				#if defined(FOG_BLEND)
					float4 w : TEXCOORD1;
				#endif
			};

			CBUFFER_START(c0)
				#ifdef CAMERA_LOCK_XY
					float4x4 world;
					float4x4 view;
					float4x4 proj;
				#endif
				float4x4 world_view_proj;
				#ifdef SKYDOME
					float skydome_u_offset;
					float skydome_intensity;
					#ifdef TINT_COLOR
						float3 skydome_tint_color;
					#endif
				#endif
			CBUFFER_END

			#ifdef FOG_BLEND
				CBUFFER_START(c_fog)
					// float2 fog_depth_range;
					float3 fog_color;
					float3 sun_direction;
					float3 sun_color;
					float3 fog_sun_blend;
					float2 skydome_fog_height_falloff;
				CBUFFER_END
			#endif

			DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
			PS_INPUT vs_main(VS_INPUT input)
			{
				PS_INPUT o;

				float4 position;
				position = input.position;

				float4 p;
				#if defined(CAMERA_LOCK_XY)
					float3 wp = mul(position, world).xyz;
					#ifdef CAMERA_LOCK_Z
						view._m30_m31_m32 = float3(0,0,0);
					#else
						view._m30_m31 = float2(0,0);
					#endif
					p = mul(mul(float4(wp,1),view), proj);
				#else
					p = mul(position, world_view_proj);
				#endif

				#ifdef PROJECT_TO_FAR_PLANE
					p.z = p.w;
				#endif

				o.position = p;

				#if defined(FOG_BLEND)
					o.w = encode_world_pos(o.position, camera_unprojection);
				#endif

				#if defined(UV0)
					o.uv = input.uv;
				#endif
				#if defined(MATERIAL_TRANSFER) && defined(UV0)
					float2 tmp = input.uv;
					tmp.y = 1 - tmp.y;
					o.position = float4(tmp * 2 - 1, 0, 1);
				#endif

				return o;
			}

			DEFAULT_ROOT_SIGNATURE_ATTRIBUTE
			half4 ps_main(PS_INPUT input) : SV_TARGET0
			{
				half4 c = half4(0,0,0,0);

				#if defined(SKYDOME)
					c = TEX2D(skydome_map, input.uv + float2(skydome_u_offset, 0));
					#if defined(SKYDOME_RGBM)
						c.rgb = rgbm_decode(c);
					#endif
					c.rgb *= skydome_intensity;
					
					#if defined(TINT_COLOR)
						c.rgb *= skydome_tint_color;
					#endif

					#if defined(FOG_BLEND)
						float3 wp = decode_world_pos(input.w, 1);
						float3 view_dir = normalize(camera_world._m30_m31_m32 - wp);
						float sa = fog_sun_blend.x * pow(saturate(dot(view_dir, sun_direction)), fog_sun_blend.y);
						float3 fog_c = lerp(fog_color, fog_sun_blend.z * sun_color, sa);

						// Soft fog-skybox transition
						// TODO: make better falloff, e.g. exp(max(x - skydome_fog_height_falloff.x, 0) * skydome_fog_height_falloff.y) 
						half inv_denom = 1.0 / (skydome_fog_height_falloff.y - skydome_fog_height_falloff.x);
						half weight0 = 1.0 - saturate((1.0 - input.uv.g - skydome_fog_height_falloff.x) * inv_denom);

						// Skybox fog calculation
						// TODO: would be nice if we could calculate correct fog on skydome two, but then I think we also need to account the height.
						/*
						float start = fog_depth_range.x;
						float end = fog_depth_range.y;
						float b = 1.f / (end-start);
						half dist = 1000000.0;
						half weight1 = clamp(exp(-camera_world._m32 * b) * (1-exp(-dist * -view_dir.z * b)) / -view_dir.z, 0.0, 1.0);
						return half4(lerp(c.rgb, fog_c, max(weight0, weight1)), c.a);
						*/

						return half4(lerp(c.rgb, fog_c, weight0), 1.0);
					#endif
				#endif

				//#if defined(MATERIAL_TRANSFER)
				//	c.rgb = pow(c.rgb, 1.f / 2.2f);
				//#endif

				return c;
			}
		"""
	}
}

shaders = {
	skydome = {
		editor_options = [
			{
				name="Vertex Modifiers"
				options = [
					{ name="Lock Camera in XY-plane" define="CAMERA_LOCK_XY" }
					{ name="Lock Camera in Z-plane" define="CAMERA_LOCK_Z" }
				]
			}
			{
				name="Pixel Modifiers"
				options = [
					{ name="Skydome Texture RGBM encoded" define = "SKYDOME_RGBM" }
					{ name="Tint Color" define = "TINT_COLOR" }
					{ name="Blend in fog" define = "FOG_BLEND" }
				]
			}
		]

		contexts = {
			default = {
				passes = [
					{ layer="skydome" hlsl_shader="forward_emissive" defines=["PROJECT_TO_FAR_PLANE" "SKYDOME"] render_states="ambient_no_depth_write" }
				]
			}

			material_transfer = {
				passes_sort_mode="immediate"
				passes = [
					{  hlsl_shader="forward_emissive" defines=["MATERIAL_TRANSFER" "SKYDOME"] render_states="filter" }
				]
			}
		}

		compile = {
			default = [
				{ defines=[] }
			]
			material_transfer = [
				{ defines=[] }
			]
		}
	}

	base = {
		editor_options = [
		]

		contexts = {
			shadow_caster = {
				passes_sort_mode="immediate"
				passes = [
					{ hlsl_shader="depth_only" render_states="shadow_caster" }
				]
			}

			default = {
				passes = [
					{ layer="gbuffer" hlsl_shader="gbuffer_base" defines=["MOTION_BLUR"] render_states="gbuffer_material" }
					{ defined="RENDERER_D3D11"
						pass = [
							{ layer="wireframe" hlsl_shader="gbuffer_base" defines=["DRAW_WIREFRAME"] render_states="wireframe" branch_key="dev_wireframe" }
						]
					}
					{ defined="RENDERER_D3D12"
						pass = [
							{ layer="wireframe" hlsl_shader="gbuffer_base" defines=["DRAW_WIREFRAME"] render_states="wireframe" branch_key="dev_wireframe" }
						]
					}
				]
			}
		}

		compile = {
			shadow_caster = [
				{ defines=[] }
			]
			default = [
				{ defines=[] }
			]
		}
	}
}
