// based on Poi Vertex Glitching

#T#PoiGlitchEffectProperties
//ifex _GlitchEffectEnabled==0
[HideInInspector] m_start_glitchEffect ("Glitch Effect--{reference_property:_GlitchEffectEnabled}", Float) = 0
[HideInInspector][ThryToggle(POI_GLITCH_EFFECT)]_GlitchEffectEnabled ("Enabled", Float) = 0
[Vector3]_GlitchEffectDirection ("Direction of the Effect", Vector) = (0,1,0)

[HideInInspector] s_start_GlitchEffectLarge ("Main Glitch Effect--{reference_property:_GlitchEffectLargeEnabled,persistent_expand:true,default_expand:true}", Float) = 0
[HideInInspector][ThryToggle(POI_GLITCH_EFFECT_LARGE, true)]_GlitchEffectLargeEnabled ("Enabled", Float) = 0
_GlitchEffectLargeInterval ("Glitch Interval Hint", Float) = 1
_GlitchEffectWindowFalloff ("Glitch Falloff", Range(0,1)) = 0
[ThryIntRange]_GlitchEffectLargeActiveSinusPeriods ("Glitch Wave Number", Range(1, 10)) = 3
_GlitchEffectLargeStrength ("Glitch Strength", Range(0, 10)) = 1
_GlitchEffectLargeDensity ("Glitch Density", Range(0, 100)) = 20
_GlitchEffectLargeHardness ("Glitch Hardness", Range(1,50)) = 5
_GlitchEffectLargeSpeed ("Glitch Speed", Range(0,25)) = 10
[ThryToggle]_GlitchEffectLargeOverrideOn ("Time Override--{reference_property:_GlitchEffectLargeOverride}", Float) = 0
[HideInInspector]_GlitchEffectLargeOverride ("", Range(0,1)) = 0

[HideInInspector] s_start_GlitchEffectHueShift ("Hue Shift--{reference_property:_GlitchEffectLargeHueShiftEnabled,persistent_expand:true,default_expand:true}", Float) = 0
[HideInInspector][ThryToggle(POI_GLITCH_EFFECT_LARGE_HUESHIFT,true)]_GlitchEffectLargeHueShiftEnabled ("Enabled", Float) = 0
[ThryWideEnum(OKLab, 0, HSV, 1)] _GlitchEffectLargeHueShiftColorSpace ("Color Space", Int) = 0
_GlitchEffectHueShiftRight ("Hue Shift Right", Range(0,1)) = 0
_GlitchEffectHueShiftRightAlpha ("Coverage", Range(0,1)) = 0.5
_GlitchEffectHueShiftLeft ("Hue Shift Left", Range(0,1)) = 0
_GlitchEffectHueShiftLeftAlpha ("Coverage", Range(0,1)) = 0.5
[HideInInspector] s_end_GlitchEffectHueShift ("Hue Shift", Float) = 0

[HideInInspector] s_end_GlitchEffectLarge ("Main Glitch Effect", Float) = 0

[HideInInspector] s_start_GlitchEffectSmall ("Small Glitch Effect--{reference_property:_GlitchEffectSmallEnabled,persistent_expand:true,default_expand:true}", Float) = 0
[HideInInspector][ThryToggle(POI_GLITCH_EFFECT_SMALL, true)]_GlitchEffectSmallEnabled ("Enabled", Float) = 0
_GlitchEffectSmallInterval ("Glitch Interval", Float) = 1
_GlitchEffectSmallSpeed ("Glitch Speed", Range(0.1,3)) = 1
_GlitchEffectSmallStrength ("Glitch Strength", Range(0, 2)) = 0.5
_GlitchEffectSmallSize ("Glitch Size", Range(0,0.25)) = 0.1
[ThryToggle]_GlitchEffectSmallOverrideOn ("Time Override--{reference_property:_GlitchEffectSmallOverride}", Float) = 0
[HideInInspector]_GlitchEffectSmallOverride ("", Range(0,1)) = 0
[HideInInspector] s_end_GlitchEffectSmall ("Small Glitch Effect", Float) = 0


[HideInInspector] s_start_GlitchEffectMirror ("Mirror--{reference_property:_GlitchEffectMirrorEnable,persistent_expand:true}", Float) = 0
[HideInInspector][ThryToggleUI(true)]_GlitchEffectMirrorEnable ("Mirror", Float) = 0
[ThryWideEnum(Show In Both, 0, Show Only In Mirror, 1, Dont Show In Mirror, 2)] _GlitchEffectMirror ("Show in mirror", Int) = 0
[HideInInspector] s_end_GlitchEffectMirror ("Mirror", Float) = 0

[HideInInspector] m_end_glitchEffect ("Glitch Effect", Float) = 0
//endex

#T#PoiGlitchEffectKeywords
//ifex _GlitchEffectEnabled==0
#pragma shader_feature_local POI_GLITCH_EFFECT
#pragma shader_feature_local POI_GLITCH_EFFECT_LARGE
#pragma shader_feature_local POI_GLITCH_EFFECT_LARGE_HUESHIFT
#pragma shader_feature_local POI_GLITCH_EFFECT_SMALL
//endex

#T#PoiGlitchEffectVariables
//ifex _GlitchEffectEnabled==0
#ifdef POI_GLITCH_EFFECT
    float3 _GlitchEffectDirection;

	float _GlitchEffectMirrorEnable;
	float _GlitchEffectMirror;

	float _GlitchEffectLargeEnabled;
	float _GlitchEffectLargeHueShiftEnabled;
	float _GlitchEffectSmallEnabled;

	#if defined(POI_GLITCH_EFFECT_LARGE)
		float _GlitchEffectLargeInterval;
		float _GlitchEffectWindowFalloff;
		float _GlitchEffectLargeStrength;
		float _GlitchEffectLargeDensity;
    	float _GlitchEffectLargeHardness;
    	float _GlitchEffectLargeSpeed;
    	float _GlitchEffectLargeActiveSinusPeriods;
		float _GlitchEffectLargeOverrideOn;
		float _GlitchEffectLargeOverride;
		#if defined(POI_GLITCH_EFFECT_LARGE_HUESHIFT)
			int _GlitchEffectLargeHueShiftColorSpace;
			float _GlitchEffectHueShiftRight;
			float _GlitchEffectHueShiftRightAlpha;
			float _GlitchEffectHueShiftLeft;
			float _GlitchEffectHueShiftLeftAlpha;
		#endif
	#endif

	#if defined(POI_GLITCH_EFFECT_SMALL)
		float _GlitchEffectSmallInterval;
		float _GlitchEffectSmallSpeed;
		float _GlitchEffectSmallStrength;
		float _GlitchEffectSmallSize;
		float _GlitchEffectSmallOverrideOn;
		float _GlitchEffectSmallOverride;
	#endif

#endif
//endex

#T#PoiGlitchEffectVertFunctionCalls
//ifex _GlitchEffectEnabled==0
#if defined(POI_GLITCH_EFFECT)

	bool canGlitch = true;
	if (_GlitchEffectMirrorEnable && _GlitchEffectMirror > 0)
	{
		bool inMirror = IsInMirror();
		if (_GlitchEffectMirror == 1 && !inMirror)	canGlitch = false;
		if (_GlitchEffectMirror == 2 && inMirror)	canGlitch = false;
	}
	if (canGlitch)
	{
		float3 effectDirectionNorm = normalize(mul(unity_ObjectToWorld,float4(1000*_GlitchEffectDirection,1)).xyz);
		
		float3 toCamera = normalize(getCameraPosition() - mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz);
		float3 glitchDirection = normalize(cross(toCamera, effectDirectionNorm));
		
		float3 worldVertToFarAwayVec = 1000*effectDirectionNorm - (o.worldPos.xyz + worldOffset.xyz);

		float positionFarAwayAlongDirection = dot(worldVertToFarAwayVec, effectDirectionNorm);

		#if defined(POI_GLITCH_EFFECT_SMALL)
			float3 shiftDirection = (o.worldPos.xyz + worldOffset.xyz) - mul(unity_ObjectToWorld, float4(0,0,0,1)).xyz;;
			if(length(shiftDirection) > 0.01)
			{
				shiftDirection -= effectDirectionNorm * dot(shiftDirection, effectDirectionNorm);

				float intervalElapsedPerc = lerp(frac(_Time.y / _GlitchEffectSmallInterval), _GlitchEffectSmallOverride, step(0.1,_GlitchEffectSmallOverrideOn));

				float distancePerPeak = _GlitchEffectSmallSpeed * _GlitchEffectSmallInterval;

				float fractionalDistance = frac((positionFarAwayAlongDirection + distancePerPeak * intervalElapsedPerc) / distancePerPeak);

				float strength = (smoothstep(1-_GlitchEffectSmallSize,1,fractionalDistance) + smoothstep(-_GlitchEffectSmallSize,0,-fractionalDistance)) * _GlitchEffectSmallStrength * 0.1 * length(shiftDirection);

				shiftDirection = normalize(shiftDirection);
				shiftDirection *= strength;

				worldOffset += shiftDirection;
				localOffset += mul(unity_WorldToObject, 1000*shiftDirection)/1000;
			}
		#endif

		#if defined(POI_GLITCH_EFFECT_LARGE)
			float sinTimeMultiplicator = (2 + _GlitchEffectLargeSpeed * 5);

			//Pi and not 2*Pi, since we use _Time.z which is time in seconds*2
			float sinPeriodTimeInSec = PI/sinTimeMultiplicator;
			float sinPeriodWorldDistance = 2*PI/_GlitchEffectLargeDensity;
			int sinFullPeriodsPerGlitchInterval = floor(_GlitchEffectLargeInterval/sinPeriodTimeInSec);
			float sinFullPeriodsPerGlitchIntervalWorldDistance = sinFullPeriodsPerGlitchInterval * sinPeriodWorldDistance;
			float adjustedGlitchInterval = sinFullPeriodsPerGlitchInterval * sinPeriodTimeInSec;

			float glitchAmount = clamp(sin(_Time.z * sinTimeMultiplicator + positionFarAwayAlongDirection * _GlitchEffectLargeDensity) * _GlitchEffectLargeHardness, -1, 1)
								* (1 + 4 * step(0.9, sin((_Time.y * sinTimeMultiplicator - positionFarAwayAlongDirection * _GlitchEffectLargeDensity)/3)));
			
			float adjustedIntervalElapsedPerc = lerp(frac(_Time.y / adjustedGlitchInterval),_GlitchEffectLargeOverride, step(0.1,_GlitchEffectLargeOverrideOn));

			float modDistance = (positionFarAwayAlongDirection + adjustedIntervalElapsedPerc * sinFullPeriodsPerGlitchIntervalWorldDistance) % sinFullPeriodsPerGlitchIntervalWorldDistance;
			float activeWorldSizeFromEnd = sinFullPeriodsPerGlitchIntervalWorldDistance - _GlitchEffectLargeActiveSinusPeriods*sinPeriodWorldDistance;
			float falloffWorldDist = _GlitchEffectWindowFalloff * 0.25 * sinFullPeriodsPerGlitchIntervalWorldDistance;
			float glitchActiveModifier = saturate(
											smoothstep(activeWorldSizeFromEnd, activeWorldSizeFromEnd + falloffWorldDist, modDistance)
											+ smoothstep(-sinFullPeriodsPerGlitchIntervalWorldDistance, -sinFullPeriodsPerGlitchIntervalWorldDistance + falloffWorldDist, - modDistance)
											- 1);

			float3 glitchOffset = glitchAmount * glitchDirection * (_GlitchEffectLargeStrength * .01) * glitchActiveModifier;

			
			localOffset += mul(unity_WorldToObject, 1000*glitchOffset)/1000;
			worldOffset += glitchOffset;
		#endif
	}
#endif
//endex

#T#PoiGlitchEffectFragFunctionCalls
//ifex _GlitchEffectEnabled==0 || _GlitchEffectLargeHueShiftEnabled==0 || _GlitchEffectLargeEnabled==0
#if defined(POI_GLITCH_EFFECT) && defined(POI_GLITCH_EFFECT_LARGE) && defined(POI_GLITCH_EFFECT_LARGE_HUESHIFT)
	//need to recalcuate glitch, since we don't know about result of calculation in vertex shader
	bool canGlitch = true;
	if (_GlitchEffectMirrorEnable && _GlitchEffectMirror > 0)
	{
		bool inMirror = IsInMirror();
		if (_GlitchEffectMirror == 1 && !inMirror)	canGlitch = false;
		if (_GlitchEffectMirror == 2 && inMirror)	canGlitch = false;
	}
	if (canGlitch)
	{
		float3 effectDirectionNorm = normalize(mul(unity_ObjectToWorld,float4(1000*_GlitchEffectDirection,1)).xyz);
				
		float3 worldVertToFarAwayVec = 1000*effectDirectionNorm - mul(unity_ObjectToWorld,float4(i.localPos.xyz,1)).xyz;

		float positionFarAwayAlongDirection = dot(worldVertToFarAwayVec, effectDirectionNorm);

		float sinTimeMultiplicator = (2 + _GlitchEffectLargeSpeed * 5);

		//Pi and not 2*Pi, since we use _Time.z which is time in seconds*2
		float sinPeriodTimeInSec = PI/sinTimeMultiplicator;
		float sinPeriodWorldDistance = 2*PI/_GlitchEffectLargeDensity;
		int sinFullPeriodsPerGlitchInterval = floor(_GlitchEffectLargeInterval/sinPeriodTimeInSec);
		float sinFullPeriodsPerGlitchIntervalWorldDistance = sinFullPeriodsPerGlitchInterval * sinPeriodWorldDistance;
		float adjustedGlitchInterval = sinFullPeriodsPerGlitchInterval * sinPeriodTimeInSec;

		float glitchAmount = clamp(sin(_Time.z * sinTimeMultiplicator + positionFarAwayAlongDirection * _GlitchEffectLargeDensity) * _GlitchEffectLargeHardness, -1, 1)
								* (1 + 4 * step(0.9, sin((_Time.y * sinTimeMultiplicator - positionFarAwayAlongDirection * _GlitchEffectLargeDensity)/3)));
		
		float adjustedIntervalElapsedPerc = lerp(frac(_Time.y / adjustedGlitchInterval),_GlitchEffectLargeOverride, step(0.1,_GlitchEffectLargeOverrideOn));

		float modDistance = (positionFarAwayAlongDirection + adjustedIntervalElapsedPerc * sinFullPeriodsPerGlitchIntervalWorldDistance) % sinFullPeriodsPerGlitchIntervalWorldDistance;
		float activeWorldSizeFromEnd = sinFullPeriodsPerGlitchIntervalWorldDistance - _GlitchEffectLargeActiveSinusPeriods*sinPeriodWorldDistance;
		float falloffWorldDist = _GlitchEffectWindowFalloff * 0.125 * sinFullPeriodsPerGlitchIntervalWorldDistance;
		float glitchActiveModifier = saturate(
										smoothstep(activeWorldSizeFromEnd, activeWorldSizeFromEnd + falloffWorldDist, modDistance)
										+ smoothstep(-sinFullPeriodsPerGlitchIntervalWorldDistance, -sinFullPeriodsPerGlitchIntervalWorldDistance + falloffWorldDist, - modDistance)
										- 1);
		
		poiFragData.baseColor = lerp(poiFragData.baseColor ,hueShift(poiFragData.baseColor, frac(lerp(_GlitchEffectHueShiftLeft, _GlitchEffectHueShiftRight,step(0,glitchAmount))), _GlitchEffectLargeHueShiftColorSpace), glitchActiveModifier * lerp(_GlitchEffectHueShiftLeftAlpha, _GlitchEffectHueShiftRightAlpha,step(0,glitchAmount)));
	}
#endif
//endex