Shader "Custom/WaveSurfaceShader" 
{
	Properties 
	{
        _EdgeLength ("Edge length", Range(2,50)) = 15
        _Tess ("Tessellation", Range(1,8)) = 3
		_Color ("Color", Color) = (1,1,1,1)
		_ShadowColor ("Shadow Color", Color) = (1,1,1,1)
		_WaveColor ("Wave Color", Color) = (1,1,1,1)
     	_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader 
	{
		Tags { "RenderType"="Opaque" }
		LOD 300
		
		CGPROGRAM
        #pragma surface surf NoLighting noambient novertexlights nodynlightmap nodirlightmap nolightmap noshadow nofog vertex:disp tessellate:tessEdge
        #pragma target 4.6
        #include "Tessellation.cginc"

        struct appdata 
        {
            float4 vertex : POSITION;
            float4 tangent : TANGENT;
            float3 normal : NORMAL;
            float2 texcoord : TEXCOORD0;
        };

        fixed4 LightingNoLighting(SurfaceOutput s, fixed3 lightDir, fixed atten)
   		{
         	fixed4 c;
         	c.rgb = s.Albedo; 
         	c.a = s.Alpha;
         	return c;
     	}

        float _Tess;

        sampler2D _MainTex;
		fixed4 _Color;
		fixed4 _ShadowColor;
		fixed4 _WaveColor;
		float _WaveWidth;
		float _WaveHeight;
		float _FadePow;
		float _SizePow;
		float _ShadowSize;
		float _MinShadowHeight;
		float _MaxShadowHeight;
		half4 _PlayerPoints[4];
		half4 _Waves[32];

        float4 tessFixed()
        {
            return _Tess;
        }

        float _EdgeLength;

        float4 tessEdge (appdata v0, appdata v1, appdata v2)
        {
            return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);
        }

        float3 GetHeightAtPoint(float2 p)
        {
        	float height = 0;
        	float2 tangeant = float2(0.0, 0.0);
	    	const float PI = 3.14159;
			float distFromMid = clamp( 5.0 * length(float2(float2(0.5, 0.5) - p))*2 - 4.0, 0, 1);

	    	// Shadows
			float shadowStrength = 0;
			for(int i = 0; i<4; i++)
			{
				float distFromShadow = length(float2(_PlayerPoints[i].xz - p));
				float bendDepth = lerp(0.0, 1.0, min(_PlayerPoints[i].y,0.0)/_MinShadowHeight)* (1.0-pow(distFromMid, 4.0));
				shadowStrength = max(shadowStrength, bendDepth*smoothstep(_ShadowSize*2.0, 0.0, distFromShadow)) ;// max(shadowStrength, smoothstep(0, _ShadowSize, _ShadowSize-distFromShadow))*bendDepth;
			}
			height -= shadowStrength;
			//col = lerp(_Color, _ShadowColor, shadowStrength);

			// Waves
			for(int i = 0; i<32; i++)
			{
				float distFromWave = length(float2(_Waves[i].xy - p));
				float steppedWave = smoothstep(distFromWave, distFromWave+_WaveWidth, 1.0-pow(1.0-_Waves[i].z, _SizePow));

				float shapedWave = 0.5*(sin(steppedWave*2.0*PI - 0.5*PI)+1.0);
				tangeant += normalize(float2(p - _Waves[i].xy)) * sin(steppedWave*2.0*PI);
				float finalWave = shapedWave*_Waves[i].w*max(1.0-pow(_Waves[i].z, _FadePow), 0.0) * (1.0-pow(distFromMid, 4.0));
				finalWave = shapedWave*_Waves[i].w*max(1.0-pow(_Waves[i].z, _FadePow), 0.0) * (1.0-pow(distFromMid, 4.0));
				height = max(height + 0.5*finalWave, min(height, 0.0) + finalWave);
			}

			return float3(height, tangeant*height);
        }

        float _Displacement;

        void disp (inout appdata v)
        {
            v.vertex.xyz += v.normal * GetHeightAtPoint(v.texcoord).x * _WaveHeight;
        }

        struct Input 
        {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o) 
        {
            fixed4 col;
	    	const float PI = 3.14159;

			// Shadows
			float shadowStrength = 0;
			for(int i = 0; i<4; i++)
			{
				float distFromShadow = length(float2(_PlayerPoints[i].xz - IN.uv_MainTex));
				float shadowSize = lerp(_ShadowSize*0.5, _ShadowSize, 1.0- (_PlayerPoints[i].y-_MinShadowHeight)/(_MaxShadowHeight-_MinShadowHeight));
				//float shadowSize = lerp(_ShadowSize*0.5, _ShadowSize, smoothstep(_MaxShadowHeight-_MinShadowHeight, _MinShadowHeight, _PlayerPoints[i].y));
				shadowStrength = max(shadowStrength, smoothstep(distFromShadow, distFromShadow+0.0025, shadowSize ));
			}

			// Waves
			float3 heightInfo = GetHeightAtPoint(IN.uv_MainTex);

		    float2 dirFromMid = float2(float2(0.5, 0.5) - IN.uv_MainTex); 
		    float dirDot = pow(max(dot(normalize(-dirFromMid), normalize(float2(1.0,1.0))), 0.0), 1.0);
		    float heightStep = dot(normalize(float3(heightInfo.y, 1.0, heightInfo.z)), normalize(float3(1.0, 1.0, 1.0)));
		    heightStep = heightInfo.x;
		    heightStep = 0.5*(smoothstep(0.1, 0.12, heightStep) + smoothstep(0.8, 0.82, heightStep));
		    //heightStep = lerp(1.0, heightStep, smoothstep(0.1, 0.12, heightInfo.x));
			col = lerp(_WaveColor, _Color, heightStep);
			col = lerp(col, _ShadowColor, shadowStrength);
			//col.rgb = heightStep;
            o.Albedo = col.rgb;
            o.Specular = 0.2;
            o.Gloss = 1.0;
            //o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
        }
        ENDCG
    }
    FallBack "Diffuse"
}