//////////////////////////////////////////////////////
// MK Toon ShadowCaster Program			       		//
//					                                //
// Created by Michael Kremmel                       //
// www.michaelkremmel.de                            //
// Copyright © 2021 All rights reserved.            //
//////////////////////////////////////////////////////

#ifndef MK_TOON_SHADOWCASTER
	#define MK_TOON_SHADOWCASTER

	#include "../Core.hlsl"

	#if defined(MK_URP)
		#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
		#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
	#elif defined(MK_LWRP)
		#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
		#include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Shadows.hlsl"
	#endif

	#include "../Surface.hlsl"
	#include "Data.hlsl"

	//This should be excluded from the CBuffer
	uniform float3 _LightDirection;

	/////////////////////////////////////////////////////////////////////////////////////////////
	// VERTEX SHADER
	/////////////////////////////////////////////////////////////////////////////////////////////
	void ShadowCasterVert 
	(
		VertexInputShadowCaster VERTEX_INPUT,
		out VertexOutputShadowCaster vertexOutput
		,out float4 svPositionClip : SV_POSITION
	)
	{
		UNITY_SETUP_INSTANCE_ID(VERTEX_INPUT);
		INITIALIZE_STRUCT(VertexOutputShadowCaster, vertexOutput);
		UNITY_TRANSFER_INSTANCE_ID(VERTEX_INPUT, vertexOutput);
		UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(vertexOutput);

		#ifdef MK_VERTEX_ANIMATION
			VERTEX_INPUT.vertex.xyz = VertexAnimation(PASS_VERTEX_ANIMATION_ARG(_VertexAnimationMap, PASS_VERTEX_ANIMATION_UV(VERTEX_INPUT.texcoord0.xy), _VertexAnimationIntensity, _VertexAnimationFrequency.xyz, VERTEX_INPUT.vertex.xyz, VERTEX_INPUT.normal));
		#endif

		#if defined(MK_VERTCLR) || defined(MK_POLYBRUSH)
			vertexOutput.color = VERTEX_INPUT.color;
		#endif

		#if defined(MK_TCM)
			vertexOutput.uv = VERTEX_INPUT.texcoord0.xy * _AlbedoMap_ST.xy + _AlbedoMap_ST.zw;
		#endif

		#if defined(MK_URP) || defined(MK_LWRP)
			half3 normalWorld = ComputeNormalWorld(VERTEX_INPUT.normal);
		#endif
		#ifdef MK_PARALLAX
			half3 viewTangent = ComputeViewTangent(ComputeViewObject(VERTEX_INPUT.vertex.xyz), VERTEX_INPUT.normal, VERTEX_INPUT.tangent, cross(VERTEX_INPUT.normal, VERTEX_INPUT.tangent.xyz) * VERTEX_INPUT.tangent.w * unity_WorldTransformParams.w);
		#endif

		#if defined(MK_URP)
			float3 positionWorld = mul(MATRIX_M, float4(VERTEX_INPUT.vertex.xyz, 1.0)).xyz;
			svPositionClip = mul(MATRIX_VP, float4(ApplyShadowBias(positionWorld, normalWorld, _LightDirection), 1.0));
			#if UNITY_REVERSED_Z
				svPositionClip.z = min(svPositionClip.z, svPositionClip.w * UNITY_NEAR_CLIP_VALUE);
			#else
				svPositionClip.z = max(svPositionClip.z, svPositionClip.w * UNITY_NEAR_CLIP_VALUE);
			#endif
		#elif defined(MK_LWRP)
			float3 positionWorld = mul(MATRIX_M, float4(VERTEX_INPUT.vertex.xyz, 1.0)).xyz;
			float invNdotL = 1.0 - saturate(dot(_LightDirection, normalWorld));
			float scale = invNdotL * _ShadowBias.y;

			positionWorld = _LightDirection * _ShadowBias.xxx + positionWorld;
			positionWorld = normalWorld * scale.xxx + positionWorld;
			svPositionClip = mul(MATRIX_VP, float4(positionWorld, 1));
			#if UNITY_REVERSED_Z
				svPositionClip.z = min(svPositionClip.z, svPositionClip.w * UNITY_NEAR_CLIP_VALUE);
			#else
				svPositionClip.z = max(svPositionClip.z, svPositionClip.w * UNITY_NEAR_CLIP_VALUE);
			#endif
		#else
			TRANSFER_SHADOW_CASTER_NOPOS(vertexOutput, svPositionClip)
		#endif
	}

	/////////////////////////////////////////////////////////////////////////////////////////////
	// FRAGMENT SHADER
	/////////////////////////////////////////////////////////////////////////////////////////////
	half4 ShadowCasterFrag 
		(
			VertexOutputShadowCaster vertexOutput
			#ifdef MK_LEGACY_RP
				#if UNITY_VERSION >= 20171
					,UNITY_POSITION(vpos)
				#else
					,UNITY_VPOS_TYPE vpos : VPOS
				#endif
			#endif
		) : SV_Target
	{	
		UNITY_SETUP_INSTANCE_ID(vertexOutput);
		UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(vertexOutput);
		
		MKSurfaceData surfaceData = ComputeSurfaceData
		(
			PASS_POSITION_WORLD_ARG(0)
			PASS_FOG_FACTOR_WORLD_ARG(0)
			PASS_BASE_UV_ARG(float4(vertexOutput.uv.xy, 0, 0))
			PASS_LIGHTMAP_UV_ARG(0)
			PASS_VERTEX_COLOR_ARG(vertexOutput.color)
			PASS_NORMAL_WORLD_ARG(1)
			PASS_VERTEX_LIGHTING_ARG(0)
			PASS_TANGENT_WORLD_ARG(1)
			PASS_VIEW_TANGENT_ARG(vertexOutput.viewTangent)
			PASS_BITANGENT_WORLD_ARG(1)
			PASS_POSITION_CLIP_ARG(0)
			PASS_NULL_CLIP_ARG(0)
			PASS_FLIPBOOK_UV_ARG(0)
		);
		Surface surface = InitSurface(surfaceData, PASS_TEXTURE_2D(_AlbedoMap, SAMPLER_REPEAT_MAIN), _AlbedoColor);
		
		#if defined(MK_URP) || defined(MK_LWRP)
			return 0;
		#else
			#ifdef MK_SURFACE_TYPE_TRANSPARENT
				#ifdef MK_TOON_DITHER_MASK
					/*
					#ifdef LOD_FADE_CROSSFADE
						#define _LOD_FADE_ON_ALPHA
						alpha *= unity_LODFade.y;
					#endif
					*/
					
					// dither mask alpha blending
					half alphaRef = tex3D(_DitherMaskLOD, float3(vpos.xy*0.25,surface.alpha*0.9375)).a;
					Clip0(alphaRef);
				#else
					Clip0(surface.alpha - 0.5);
				#endif

				/*
				//Disabled for now
				#ifdef LOD_FADE_CROSSFADE
					#ifdef _LOD_FADE_ON_ALPHA
						#undef _LOD_FADE_ON_ALPHA
					#else
						UnityApplyDitherCrossFade(vpos.xy);
					#endif
				#endif
				*/
			#endif
			SHADOW_CASTER_FRAGMENT(vertexOutput)
		#endif
	}			
#endif