// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

namespace Stride.Rendering.Images
{
    /// <summary>
	/// Screen Space Local Reflections shader with common variables and functions
    /// </summary>
    shader SSLRCommon : ImageEffectShader, Utilities, NormalPack
    {	
		cbuffer Data
        {
            stage float MaxColorMiplevel;
            stage float TraceSizeMax;
            stage float MaxTraceSamples;
            //stage float Padding0;

            stage float RoughnessFade;
            stage float TemporalTime;
            stage float BRDFBias;
            stage float ViewFarPlane;
            
            stage float4 ViewInfo;
			
            stage float3 CameraPosWS;
            stage float WorldAntiSelfOcclusionBias;

            stage float4x4 V;
            stage float4x4 IVP;
        };
		
		// Sample raw device depth buffer
		float SampleZ(in float2 uv)
		{
			return Texture1.SampleLevel(PointSampler, uv, 0).r;
		}
		
		// Linearize raw device depth
		float LinearizeZ(in float depth)
		{
			return ViewInfo.w / (depth - ViewInfo.z);
		}
		
		// Sample linear depth
		float SampleDepth(in float2 uv)
		{
			float depth = SampleZ(uv);
			return LinearizeZ(depth);
		}
		
		// 1:-1 to 0:1
        float2 ClipToUv(float2 clipPos)
        {
			return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5);
        }
		
        // 0:1 to 1:-1
        float2 UvToClip(float2 uv)
        {
			return uv * float2(2, -2) + float2(-1, 1);
        }
        
        float3 ComputeWorldPosition(float2 uv, float rawDepth)
        {
			float4 clipPos = float4(UvToClip(uv), rawDepth, 1);
			float4 pos = mul(clipPos, IVP);
			return pos.xyz / pos.w;
        }

		float3 ComputeWorldPosition(float2 uv)
        {
			float rawDepth = SampleZ(uv);
			return ComputeWorldPosition(uv, rawDepth);
        }
		
		float3 ComputeViewPosition(float2 uv, float rawDepth)
        {
			float eyeZ = LinearizeZ(rawDepth) * ViewFarPlane;
			return float3(UvToClip(uv) * ViewInfo.xy * eyeZ, eyeZ);
        }

        float3 SampleViewPosition(float2 uv)
        {
            float rawDepth = SampleZ(uv);
            return ComputeViewPosition(uv, rawDepth);
        }
        
        float3 ScreenToView(float2 uv, float depth)
        {
			return float3(UvToClip(uv) * ViewInfo.xy, depth);
        }

		float max2(float2 v)
		{
			return max(v.x, v.y);
		}

        float2 RandN2(float2 pos, float2 random)
        {
	        return frac(sin(dot(pos.xy + random, float2(12.9898, 78.233))) * float2(43758.5453, 28001.8384));
        }
    };
}