Shader "PleasureArcade/ParticleShader"
{
    Properties
    {
		_MainTex ("Particle", 2D) = "white" {}
		_DepthAdjust ("Depth Adjust", Float) = 0
		[Toggle(FADE_BY_COLOR)] _FadeByColor ("Fade By Color", Int) = 0
		[Toggle(FADE_BY_SIZE)] _FadeBySize ("Fade By Size", Int) = 0
		_MinParticleFadeSize ("Min Particle Fade Size", Float) = 0.5

		[Toggle(SOFT_PARTICLES)] _SoftParticles("Soft Particles", Int) = 0
		_SoftParticleFade ("Soft Particle Fade", Float) = 0.25
		
		_GlobalPositionOffset ("Global Position Offset", Vector) = (0, 0, 0, 0)

		_StencilLayer ("Stencil Layer", Int) = 69
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Transparent+11" "VRCFallback"="Hidden"}
        LOD 100

        Pass
        {
			Blend OneMinusDstColor One
			Cull Off Lighting Off ZWrite Off
			ColorMask A
			ZTest Always

			Stencil
            {
                Ref [_StencilLayer]
                Comp Always
                Pass Replace
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
			#pragma shader_feature SOFT_PARTICLES
			#pragma shader_feature FADE_BY_COLOR
			#pragma shader_feature FADE_BY_SIZE

			#include "UnityCG.cginc"

            struct appdata
            {
				float4 vertex : POSITION;
				fixed4 color : COLOR;
                float4 uv : TEXCOORD0;		// .xy = uv ; .zw = particle size
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
				fixed alpha : COLOR;
				float4 cameraSpace : TEXCOORD1;
            };

			// built-in
			sampler2D _CameraDepthTexture;
			half4 _CameraDepthTexture_ST;

            sampler2D _MainTex;
			float _DepthAdjust;
			float _SoftParticleFade;
			fixed _MinParticleFadeSize;
			
			float4 _GlobalPositionOffset;

            v2f vert (appdata v)
            {
                v2f o;
				float4 worldSpace = mul(unity_ObjectToWorld, v.vertex);
				worldSpace += _GlobalPositionOffset;
                o.vertex = UnityWorldToClipPos(worldSpace.xyz);
				o.cameraSpace = ComputeGrabScreenPos(o.vertex);
				o.cameraSpace.z = UnityObjectToViewPos(v.vertex).z * _ProjectionParams.w * -1.;
                o.uv = v.uv.xy;
				o.alpha = 1;
				#ifdef FADE_BY_COLOR
				o.alpha *= v.color.r;
				#endif
				#ifdef FADE_BY_SIZE
				o.alpha *= smoothstep(0, _MinParticleFadeSize, (v.uv.z + v.uv.w) * 0.5);
				#endif
                return o;
            }

			bool IsMirrorClone()
			{
				return unity_CameraProjection[2][0] != 0.f || unity_CameraProjection[2][1] != 0.f;
			}

            fixed4 frag (v2f i) : SV_Target
            {
				clip(IsMirrorClone() ? -1 : 1);
				
				fixed col = tex2D(_MainTex, i.uv).r;

				// Trim out square edges
				clip(col - 0.001);

				// screen space UVs: _ProjectionParams.x = -1 if projection is flipped (DirectX render)
				float2 ssUV = i.cameraSpace.xy/i.cameraSpace.w;
				ssUV.y = -1 * ssUV.y * _ProjectionParams.x + step(0, _ProjectionParams.x);
				ssUV = UnityStereoScreenSpaceUVAdjust(ssUV, _CameraDepthTexture_ST);
				float bufferDepth = Linear01Depth(tex2D(_CameraDepthTexture, ssUV)).r - _DepthAdjust * _ProjectionParams.w;

				#ifndef SOFT_PARTICLES
				clip(bufferDepth - i.cameraSpace.z);
				#endif

				#ifdef SOFT_PARTICLES
                // sample the texture
				col *= smoothstep(0, _ProjectionParams.w * (float)_SoftParticleFade, bufferDepth - i.cameraSpace.z);
				#endif

                return fixed4(col, col, col, col * i.alpha);
            }
            ENDCG
        }
    }
}
