﻿#include "LVLiquidPassBase.cginc"

        float  _DitherStrength;
        float _SizeWorld;

        float _MurkinessSpeed;
        float3 _BubblesData; // x = scale, y = vertical speed, z = brightness


#if defined(WEBGL_OR_LEGACY)
        sampler2D _LayersPropertiesTex;
        sampler2D _LayersColorsTex;
        sampler2D _LayersColors2Tex;
        sampler2D _NoiseTexUnwrapped;

        // Lower quality with a single texture fetch
        /*
        inline float4 GetNoiseUnwrapped(float4 pos) {
            float4 f = frac(pos);
            f.z = (floor(f.y * 64.0) + 0.5) / 64.0 + f.z / 64.0;
            return tex2Dlod(_NoiseTexUnwrapped, float4(f.xz,0,0));
        }
        */

        inline float4 GetNoiseUnwrapped(float4 pos) {
            float4 f = frac(pos);
            float t = f.y * 64.0;
            float by = floor(t);
            float4 n0 = tex2Dlod(_NoiseTexUnwrapped, float4(f.x, (by + f.z) / 64.0,0,0));
            float4 n1 = tex2Dlod(_NoiseTexUnwrapped, float4(f.x, (by + 1.0 + f.z) / 64.0,0,0));
            return lerp(n0, n1, t-by);
        }


        #define SET_LAYER_INDEX(y) float layerIndex = -y / _SizeWorld;
        #define UPDATE_LAYER_INDEX(y) layerIndex = -y / _SizeWorld;
        #define SAMPLE_LAYER_PROPERTIES(index) tex2Dlod(_LayersPropertiesTex, float4(0,index,0,0))
        #define SAMPLE_LAYER_COLOR(index) tex2Dlod(_LayersColorsTex, float4(0,index,0,0))
        #define SAMPLE_LAYER_COLOR2(index) tex2Dlod(_LayersColors2Tex, float4(0,index,0,0))
        #define SAMPLE_NOISE_UNWRAPPED(pos) GetNoiseUnwrapped(pos)

#else
        half4 _LayersColors[256];
        half4 _LayersColors2[256];
        float4 _LayersProperties[256];

        #define SET_LAYER_INDEX(y) int layerIndex = clamp((int)(-255.0 * y / _SizeWorld), 0, 255);
        #define UPDATE_LAYER_INDEX(y) layerIndex = clamp((int)(-255.0 * y / _SizeWorld), 0, 255);
        #define SAMPLE_LAYER_PROPERTIES(index) _LayersProperties[index]
        #define SAMPLE_LAYER_COLOR(index) _LayersColors[index]
        #define SAMPLE_LAYER_COLOR2(index) _LayersColors2[index]
        #define SAMPLE_NOISE_UNWRAPPED(pos) tex3Dlod(_NoiseTex, pos)

#endif
      
		inline float getRandomFast(float2 uv) {
			float2 p = uv; // + _Time.ww;
			p -= floor(p * 0.01408450704) * 71.0;    
			p += float2( 26.0, 161.0 );                                
			p *= p;                                          
			return frac(p.x * p.y * 0.001051374728);
		}
        


		half4 raymarch(float4 vertex, float3 rd, float t0, float t1) {

	        float3 wpos = wsCameraPos + rd * t0;
	        
			float turbulence = (tex2D(_NoiseTex2D, vertex.xz).g - 0.5) * _Turbulence.x;
			turbulence += sin(vertex.w) * _Turbulence.y;
			turbulence *= 0.05 * _Size.y * _FoamTurbulence;
			_LevelPos += turbulence;
			_FoamMaxPos += turbulence;

			// compute level of surface liquid (t2)
			float2 rdy   = rd.xz / rd.y;
			float delta = sqrt(1.0 + dot (rdy, rdy));
			float h = abs(wpos.y - _LevelPos);
			float t2 = t0 + h * delta; // length(delta * h.xx);;
						
			// compute foam level (t3)
			float hf = abs(wpos.y - _FoamMaxPos);
			float t3 = t0 + hf * delta;

			// ray-march smoke
			float tmin, tmax;
			#if defined(LIQUID_VOLUME_SMOKE)
			half4 sumSmoke = half4(0,0,0,0);
			if (wpos.y > _LevelPos) {
				tmin = t0;
				tmax = rd.y<0 ? min(t2,t1) : t1;
				float stepSize = (tmax - tmin) / (float)_SmokeRaySteps;
				float4 dir  = float4(rd * stepSize, 0);
				float4 rpos = float4(wsCameraPos + rd * tmin, 0);
				float4 disp = float4(0, _Time.x * _Turbulence.x * _Size.y * _SmokeSpeed, 0, 0);
                BEGIN_LOOP(k,_SmokeRaySteps,5)
                    half n = SAMPLE_NOISE_3D(_NoiseTex, (rpos - disp) * _Scale.x).r;
					float py = (_LevelPos - rpos.y)/_Size.y;
					n = saturate(n + py * _SmokeHeightAtten);
					half4 lc  = half4(_SmokeColor.rgb, n * _SmokeColor.a);
					lc.rgb *= lc.aaa;
					half deep = exp(py * _SmokeAtten);
					lc *= deep;
					sumSmoke += lc * (1.0-sumSmoke.a);
                    rpos += dir;
				END_LOOP
			}
			#endif

			// ray-march foam
			tmax = min(t3,t1), tmin = t0;
			float sy = sign(rd.y);
			if (wpos.y > _FoamMaxPos) {
				tmin = tmax;
				tmax = min(t2, t1) * -sy;
			} else if (wpos.y < _LevelPos) {
				tmin  = min(t2,t1);
				tmax *= _FoamBottom * sy;
			} else if (rd.y<0) {
				tmax = min(t2, t1);
			}
			half4 sumFoam  = half4(0,0,0,0);
			if (tmax>tmin) {
				float stepSize = (tmax - tmin) / (float)_FoamRaySteps;
				float4 dir  = float4(rd * stepSize, 0);
				float4 rpos = float4(wsCameraPos + rd * tmin, 0);
				rpos.y -= _LevelPos;
				float foamThickness = _FoamMaxPos - _LevelPos;
				float4 disp = float4(_Time.x, 0, _Time.x, 0) * _Turbulence.x * _Size.w * _FoamTurbulence;
                BEGIN_LOOP(k,_FoamRaySteps,7)

					float h = saturate( rpos.y / foamThickness );
					float n = saturate(SAMPLE_NOISE_3D(_NoiseTex, (rpos - disp) * _Scale.y ).r + _FoamDensity);
					if (n>h) {
						half4 lc  = half4(_FoamColor.rgb, n-h);
						lc.a   *= _FoamColor.a;
						lc.rgb *= lc.aaa;
						half deep = saturate(rpos.y * _FoamWeight / foamThickness);
						lc *= deep;
						sumFoam += lc * (1.0 - sumFoam.a);
					}
                    
                    rpos += dir;

				END_LOOP
				sumFoam *= 1.0 + _FoamDensity;
			}	
            
			// ray-march liquid
			if (wpos.y > _LevelPos) {
				tmin = t2;
				tmax = t1 * -sy; // address case where ray does not cross liquid; this makes tmax < tmin in this case skipping the whole if block below
			} else {
				tmin = t0;
				tmax = min(t2,t1);
			}
			half4 sum = half4(0,0,0,0);
			if (tmax>tmin) {
                float4 rpos  = float4(wsCameraPos + rd * tmin, 0); // tmin or t0 ? does not matter to move to level pos; tmin will make bubbles position correct, so we stick with tmin (t0 may reduce banding on certain cases)
				float stepSize = (t1-t0) / (float)_LiquidRaySteps;
				float4 dir   = float4(rd * stepSize, 0);
            
                rpos += dir * (getRandomFast(rpos.xy * 100.0) * _DitherStrength);
                float4 disp  = float4(_Turbulence.y, 1.5, _Turbulence.y, 0) * (_MurkinessSpeed * _Size.y);
                disp.y -= _LevelPos - turbulence;
                rpos.y -= _LevelPos - turbulence;

                BEGIN_LOOP(k,_LiquidRaySteps,10)
                    
                    SET_LAYER_INDEX(rpos.y);

                    // turbulence
                    float layerTurbulence = SAMPLE_LAYER_PROPERTIES(layerIndex).z;
                    float4 xpos = float4(rpos.x, rpos.y + layerTurbulence * turbulence, rpos.z, 0);
                    UPDATE_LAYER_INDEX(xpos.y);

                    xpos.xyz -= _Center;

                    // murkiness
                    float4 properties = SAMPLE_LAYER_PROPERTIES(layerIndex);
                    float layerScale = properties.y;
					half n = SAMPLE_NOISE_3D(_NoiseTex, (xpos - disp * layerTurbulence) * layerScale).r;
                    
					// accumulate color
                    half muddy = properties.x;
                    half4 layerColor = SAMPLE_LAYER_COLOR(layerIndex);
                    half4 layerColor2 = SAMPLE_LAYER_COLOR2(layerIndex);
                    half4 lc  = lerp(layerColor, layerColor2, smoothstep(0, 1.0, n) * muddy);
					lc.a = layerColor.a;
					lc.rgb *= lc.aaa;
					sum += lc * (1.0-sum.a);

                    // bubbles; uses tex3Dlod
                    #if defined(LIQUID_VOLUME_BUBBLES)
                        half4 ba = SAMPLE_NOISE_UNWRAPPED ( (xpos - float4(turbulence, 0, turbulence, 0)) * _BubblesData.x - float4(0, _BubblesData.y, 0,0) );
                        half4 bb = SAMPLE_NOISE_UNWRAPPED ( (xpos + float4(turbulence, 0, turbulence, 0)) * _BubblesData.x - float4(0.5, _BubblesData.y * 1.5 + 0.5, 0.5, 0) );
                        half4 b = ba+bb;
                        half3 bnorm = b.yzw - 1.0;
                        half fresnel = abs(dot(rd, bnorm));
                        lc.rgb += fresnel * _BubblesData.z;
                        lc.a = fresnel;
                        lc.rgb *= lc.aaa; // 0.1
                        lc *= properties.w;
                        sum += lc * (1.0-sum.a);
                    #endif

                    rpos += dir;

				END_LOOP
			}
            
			// Final blend
			if (wpos.y>_LevelPos) {
				#if defined(LIQUID_VOLUME_SMOKE)
				    half4 lfoam = sumFoam * (1.0 - sumSmoke.a);
				    half4 liquid = sum * (1.0 - lfoam.a) * (1.0 - sumSmoke.a);
				    sum = sumSmoke + lfoam + liquid;
				#else
				    half4 liquid = sum * (1.0 - sumFoam.a);
				    sum = sumFoam + liquid;
				#endif
			} else {
				half4 lfoam = sumFoam * (1.0 - sum.a);
				sum = sum + lfoam;
			}

			#if !UNITY_COLORSPACE_GAMMA
				sum.rgb = SRGBToLinear(sum.rgb);
			#endif

			return sum;
		}
