#ifndef X2M_LWRP_PARTICLE_COMMON_INCLUDED
#define X2M_LWRP_PARTICLE_COMMON_INCLUDED

#include "X2M-Common.hlsl"

#define _X2M_PARTICLE_KILL_NAN_ON;

float Get2DClipping(in float2 position, in float4 clipRect)
{
	float2 inside = step(clipRect.xy, position.xy) * step(position.xy, clipRect.zw);
	return inside.x * inside.y;
}
// NaN checker
// /Gic isn't enabled on fxc so we can't rely on isnan() anymore
bool IsNAN(float x)
{
	// For some reason the following tests outputs "internal compiler error" randomly on desktop
	// so we'll use a safer but slightly slower version instead :/
	//return (x <= 0.0 || 0.0 <= x) ? false : true;
	return !(x < 0.0 || x > 0.0 || x == 0.0);
}
bool IsNAN(float2 v)
{
	return IsNAN(v.x) || IsNAN(v.y);
}
bool IsNAN(float3 v)
{
	return IsNAN(v.x) || IsNAN(v.y) || IsNAN(v.z);
}
bool IsNAN(float4 v)
{
	return IsNAN(v.x) || IsNAN(v.y) || IsNAN(v.z) || IsNAN(v.w);
}
bool IsNAN(half x)
{
	return !(x < 0.0 || x > 0.0 || x == 0.0);
}
bool IsNAN(half2 v)
{
	return IsNAN(v.x) || IsNAN(v.y);
}
bool IsNAN(half3 v)
{
	return IsNAN(v.x) || IsNAN(v.y) || IsNAN(v.z);
}
bool IsNAN(half4 v)
{
	return IsNAN(v.x) || IsNAN(v.y) || IsNAN(v.z) || IsNAN(v.w);
}
#if defined(_X2M_PARTICLE_KILL_NAN_ON)

float2 KillNAN(float2 v)
{
	return IsNAN(v) ? (0.0).xx : v;
}
float3 KillNAN(float3 v)
{
	return IsNAN(v) ? (0.0).xxx : v;
}
float4 KillNAN(float4 v)
{
	return IsNAN(v) ? (0.0).xxxx : v;
}
half2 KillNAN(half2 v)
{
	return IsNAN(v) ? (0.0).xx : v;
}
half3 KillNAN(half3 v)
{
	return IsNAN(v) ? (0.0).xxx : v;
}
half4 KillNAN(half4 v)
{
	return IsNAN(v) ? (0.0).xxxx : v;
}
#else
#define KillNAN(v) (v)
#endif

//////////////////////////////////
//		距离淡出
//////////////////////////////////
#if defined(_X2M_PARTICLE_DISTANCE_FADE_ON)

CBUFFER_START(ParticlePerMaterial_DistanceFade)
	half _FadeCenter;
	half _FadeDistance;
CBUFFER_END

half CalcFadeFactor(float zDistance)
{
	return saturate(1 - (zDistance - _FadeCenter) / (_FadeDistance + 0.00001));
}

#endif

//////////////////////////////////
//		关键帧动画
//////////////////////////////////

#if defined(_UVANIMATION)

X2M_DECLARE_TEX2D(_MotionVectorTex);

CBUFFER_START(ParticlePerMaterial_UVAnimation)
	float4 _MotionVectorTex_ST;
	float  _FramePerSec;
	float  _cycleNum;
	float  _Distortion;
	float  _StartTime;
	float  _ElapsedTime;
CBUFFER_END

float4 SampleUVAnimatedColor(X2M_TEX2D_PARAM(_Tex), float2 uv)
{
	//纹理坐标v取反
	float2 texcoord = float2(uv.x, 1 - uv.y);

	//计算当前帧
	float frame = _ElapsedTime >= 0 ? _ElapsedTime : (_Time.y - _StartTime) * _FramePerSec;
	float4 interval = frac(frame);			//两帧间隔
	interval.zw = 1 - interval.xy;	//下一个关键帧的vector方向是反向的
	float frameCount = _MotionVectorTex_ST.x * _MotionVectorTex_ST.y;
	//frame = _cycleNum == 0 ? frame : min(frame, frameCount * _cycleNum - 1);
	if (_cycleNum > 0 && frame > frameCount * _cycleNum - 1)
	{
		return float4(0, 0, 0, 0);
	}
	frame = floor(fmod(frame, frameCount));

	//计算当前帧uv
	float VFrame = floor(frame / _MotionVectorTex_ST.x);
	float2 UVFrame = float2(frame - VFrame * _MotionVectorTex_ST.x, VFrame);

	float4 texUV = 0;
#define curUV texUV.xy
#define nxtUV texUV.zw 

	float2 UVPerTile = float2(1 / _MotionVectorTex_ST.x, -1.0f / _MotionVectorTex_ST.y);
	curUV = (UVFrame.xy + texcoord.xy) * UVPerTile.xy + float2(0, 1.0f);

	//计算下一帧UV
	float fBound = step(_MotionVectorTex_ST.x - 1, UVFrame.x);
	float2 nxtUVOffset = (1 - fBound) * UVPerTile * float2(1, 0) + fBound * float2(-UVFrame.x, 1) * UVPerTile.xy;
	nxtUV = curUV + nxtUVOffset;

	////采样motino vertor纹理
	float4 motionVector = 0;
	motionVector.xy = X2M_SAMPLE_TEX2D(_MotionVectorTex, curUV).xy;
	motionVector.zw = X2M_SAMPLE_TEX2D(_MotionVectorTex, nxtUV).xy;	//xy 当前帧， zw 下一帧

	//uv [0,1] --> [-1, 1]， 原始计算方式如下：
	//motionVector = motionVector * 2 - 1;
	motionVector = motionVector * float4(-2, -2, 2, 2) + float4(1, 1, -1, -1);	//当前帧uv将会减去motionVector值，提前这个减操作方便4个分量一起计算
	motionVector = motionVector * interval * _Distortion;						//乘以_Distortion=0.0037是什么意思？

	//根据motionVector得到坐标值,原始计算方式如下：
	//curUV = curUV - motionVector.xy;
	//nxtUV = nxtUV + motionVector.zw;
	texUV = texUV + motionVector;

	//采样颜色纹理
	float4 curFrameCol = X2M_SAMPLE_TEX2D(_Tex,  curUV);
	float4 nxtFrameCol = X2M_SAMPLE_TEX2D(_Tex,  nxtUV);

	//根据时间进行插值
	return lerp(curFrameCol, nxtFrameCol, interval.x);
}
#define X2M_PARTICLE_UVANIMATED_COLOR(_Tex,uv) SampleUVAnimatedColor(X2M_TEX2D_ARGS(_Tex), uv)
#else
#define X2M_PARTICLE_UVANIMATED_COLOR(_Tex,uv) X2M_SAMPLE_TEX2D(_Tex, uv)
#endif

#if defined(_X2M_PARTICLE_UVROTATION_ON)

CBUFFER_START(ParticlePerMaterial_UVRotation)
	float _UVRotationOri;// 朝向(Degree)
	float _UVRotationPivotU;
	float _UVRotationPivotV;
	float _UVRotationSpeed;//角速度(Degree)
CBUFFER_END

#define X2M_PARTICLE_ROTATE_UV(uv)\
{\
    const float TO_RADIAN = 0.0174532925199433f;\
	float cosx = cos((_UVRotationOri + _UVRotationSpeed * _Time.y) * TO_RADIAN);\
	float sinx = sin((_UVRotationOri + _UVRotationSpeed * _Time.y) * TO_RADIAN);\
	float2x2 rot = { cosx,-sinx,sinx,cosx};\
    float2 pivot = float2(_UVRotationPivotU,_UVRotationPivotV);\
    uv = (mul(rot,uv - pivot) + pivot);\
}
#else
#define X2M_PARTICLE_ROTATE_UV(uv) 
#endif

#if defined(_X2M_PARTICLE_UVSCROLL_ON)
CBUFFER_START(ParticlePerMaterial_UVScroll)
	float _UVScrollSpeedU;
	float _UVScrollSpeedV;
CBUFFER_END
#define X2M_PARTICLE_SCROLL_UV(uv) \
{\
	/*使用frac避免游戏运行时间非常长导致的精度问题,因为_Time.y是游戏启动到目前的时间*/ \
   uv.xy += frac(_Time.y * float2(_UVScrollSpeedU,_UVScrollSpeedV));\
}
#else
#define X2M_PARTICLE_SCROLL_UV(uv) 
#endif

#define X2M_PARTICLE_SCROLL_ROTATE_UV(uv) X2M_PARTICLE_ROTATE_UV(uv); X2M_PARTICLE_SCROLL_UV(uv)

//////////////////////////////////
//		Mask效果
//////////////////////////////////
#if defined(_X2M_PARTICLE_MASK_TEXTURE_ON)
X2M_DECLARE_TEX2D(_MaskTex);
CBUFFER_START(ParticlePerMaterial_MaskTexture)

	float4 _MaskTex_ST;

#if defined(_X2M_PARTICLE_MASK_UVSCROLL_ON)
	float  _MaskUVScrollSpeedU;
	float  _MaskUVScrollSpeedV;
#endif
#if defined(_X2M_PARTICLE_MASK_UVROTATION_ON)
	float _MaskUVRotationOri;// 朝向(Degree)
	float _MaskUVRotationPivotU;
	float _MaskUVRotationPivotV;
	float _MaskUVRotationSpeed;//角速度(Degree)
#endif

CBUFFER_END

#if defined(_X2M_PARTICLE_MASK_UVSCROLL_ON)
/*使用frac避免游戏运行时间非常长导致的精度问题,因为_Time.y是游戏启动到目前的时间*/
#define X2M_PARTICLE_MASK_SCROLL_UV(uv) uv.xy += frac(_Time.y * float2(_MaskUVScrollSpeedU,_MaskUVScrollSpeedV));
#else
#define X2M_PARTICLE_MASK_SCROLL_UV(uv) 
#endif
#if defined(_X2M_PARTICLE_MASK_UVROTATION_ON)
#define X2M_PARTICLE_MASK_ROTATE_UV(uv)\
{\
    const float TO_RADIAN = 0.0174532925199433f;\
	float cosx = cos((_MaskUVRotationOri + _MaskUVRotationSpeed * _Time.y) * TO_RADIAN);\
	float sinx = sin((_MaskUVRotationOri + _MaskUVRotationSpeed * _Time.y) * TO_RADIAN);\
	float2x2 rot = { cosx,-sinx,sinx,cosx};\
    float2 pivot = float2(_MaskUVRotationPivotU,_MaskUVRotationPivotV);\
    uv = (mul(rot,uv - pivot) + pivot);\
}
#else
#define X2M_PARTICLE_MASK_ROTATE_UV(uv) 
#endif
#define X2M_PARTICLE_MASK_SCROLL_ROTATE_UV(uv) X2M_PARTICLE_MASK_ROTATE_UV(uv); X2M_PARTICLE_MASK_SCROLL_UV(uv)

#define X2M_PARTICLE_MASK_UV(idx)                   float2 maskUV : TEXCOORD##idx;
#define X2M_PARTICLE_MASK_TRANSFER_UV(uv,output)    output.maskUV = TRANSFORM_TEX(uv, _MaskTex); X2M_PARTICLE_MASK_SCROLL_ROTATE_UV(output.maskUV);
#define X2M_PARTICLE_MASK_APPLY(color,input)        color.rgba *=  X2M_SAMPLE_TEX2D(_MaskTex,input.maskUV).rgba;
#else
#define X2M_PARTICLE_MASK_UV(idx) 
#define X2M_PARTICLE_MASK_TRANSFER_UV(uv,output) 
#define X2M_PARTICLE_MASK_APPLY(color,input) 
#endif


//////////////////////////////////
//		billboard
/////////////////////////////////
float4 BillBoardTrans(float4 vPos)
{
	float4 ori = mul(UNITY_MATRIX_MV, float4(0, 0, 0, 1));
	//计算scale
	float3 scale;
	scale.x = length(UNITY_MATRIX_T_MV[0].xyz);
	scale.y = length(UNITY_MATRIX_T_MV[1].xyz);
	scale.z = 1;

	float4 vt = vPos;
	vt.xyz = vt.xyz * scale + ori.xyz;
	float4 oPos;
	oPos = mul(UNITY_MATRIX_P, vt);
	return oPos;
}

///////////////////////////////
//	Emissive
//////////////////////////////
//sampler2D _EmissiveTex;
//fixed EmissiveIntensity;
//fixed3 BlendEmissiveColor(fixed3 TexColor, fixed3 blendColor, float2 uv)
//{
//	fixed3 emissive = X2M_SAMPLE_TEX2D(_EmissiveTex, uv).r * EmissiveIntensity;
//	fixed3 emissiveColor = (TexColor * emissive);
//	blendColor += emissiveColor;
//	return blendColor;
//}

////////////////////////////
//	noise
///////////////////////////
float2 rand_1(float2 uv)
{
	float2 noise = (frac(sin(dot(uv, float2(12.9898, 78.233)*2.0)) * 43758.5453));
	return noise;
}
//////////////////////////////////////////////////////
//Rim Effect
//////////////////////////////////////////////////////
#ifdef _X2M_PARTICLE_RIM_ON
CBUFFER_START(ParticlePerMaterial_Rim)
	float4 _RimColor;
	float  _RimPower;
CBUFFER_END
float  _CalcRimFactor(half3 viewDir, half3 normal)
{
	float rim = 1.0 - abs(dot(viewDir, normal));
	rim = pow(max(0.0,rim), _RimPower);
	return rim;
}
#define X2M_PARTICLE_RIM_FACTOR(input)       (_CalcRimFactor(-input.viewDirWS, input.normalWS))
#define X2M_PARTICLE_RIM_VALUE(val,input)    (val*X2M_PARTICLE_RIM_FACTOR(input))
#define X2M_PARTICLE_RIM_COLOR(input)        (X2M_PARTICLE_RIM_VALUE(_RimColor.rgb,input))
#define X2M_PARTICLE_RIM_APPLY(color, input) color.rgb += X2M_PARTICLE_RIM_COLOR(input);
#else 
#define X2M_PARTICLE_RIM_FACTOR(input)       1.0f
#define X2M_PARTICLE_RIM_VALUE(val,input)    val
#define X2M_PARTICLE_RIM_COLOR(input)        0.0f
#define X2M_PARTICLE_RIM_APPLY(color, input)
#endif
//////////////////////////////////////////////////////
//Holo Effect
//////////////////////////////////////////////////////
#ifdef _X2M_PARTICLE_HOLO_ON
CBUFFER_START(ParticlePerMaterial_Holo)
	float4 _HoloColor;
	float  _HoloThreshold;
CBUFFER_END

float _CalcHoloFactor(half3 viewDir, half3 normal)
{
	float border = 1.0 - abs(dot(viewDir, normal));     //这个值越大，说明越靠近边缘
	return border * (1.0 - _HoloThreshold) + _HoloThreshold; //最边缘的alpha=1,最内部的alpha=_HoloThreshold, border为差值因子
}
#define X2M_PARTICLE_HOLO_APPLY(color, viewdirWS, normalWS) \
	{ \
		float factor = _CalcHoloFactor(-viewdirWS, normalWS); \
		color.a *= factor * _HoloColor.a; \
		color.rgb += factor * _HoloColor.rgb;\
	}
#else 
#define X2M_PARTICLE_HOLO_APPLY(color, viewdirWS, normalWS) 
#endif

//////////////////////////////////////////////////////
//Flow Effect
//////////////////////////////////////////////////////
#if defined(_X2M_PARTICLE_FLOW_ON)
X2M_DECLARE_TEX2D(_FlowTex);
CBUFFER_START(ParticlePerMaterial_Flow)
	float4    _FlowColor;
	float4    _FlowFactor;
	float     _FlowStrength;
CBUFFER_END

float4 _CalcFlowEffect(float2 worldpos)
{
	float2 uv = worldpos * _FlowFactor.zw/*scaling*/ + _FlowFactor.xy/*Speed*/ * _Time.y;
	return X2M_SAMPLE_TEX2D(_FlowTex, uv) * _FlowColor * _FlowStrength;
}
#define X2M_PARTICLE_FLOW_WORLDPOS(input) input.positionWS
// Horizontal Flow & Vertical　Flow
#define X2M_PARTICLE_HFLOW_APPLY(color,worldpos)  color += _CalcFlowEffect(worldpos.xz);
#define X2M_PARTICLE_VFLOW_APPLY(color,worldpos)  color += _CalcFlowEffect(worldpos.xy);
#define X2M_PARTICLE_VFLOW_RIM_APPLY(color,input) color += X2M_PARTICLE_RIM_VALUE(_CalcFlowEffect(input.positionWS.xy),input);
#define X2M_PARTICLE_HFLOW_RIM_APPLY(color,input) color += X2M_PARTICLE_RIM_VALUE(_CalcFlowEffect(input.positionWS.xz),input);

//alpha不受flow影响
#define X2M_PARTICLE_HFLOW_NOALPHA_APPLY(color,worldpos)  color.rgb += _CalcFlowEffect(worldpos.xz).rgb;
#define X2M_PARTICLE_VFLOW_NOALPHA_APPLY(color,worldpos)  color.rgb += _CalcFlowEffect(worldpos.xy).rgb;
#define X2M_PARTICLE_VFLOW_RIM_NOALPHA_APPLY(color,input) color.rgb += X2M_PARTICLE_RIM_VALUE(_CalcFlowEffect(input.positionWS.xy),input).rgb;
#define X2M_PARTICLE_HFLOW_RIM_NOALPHA_APPLY(color,input) color.rgb += X2M_PARTICLE_RIM_VALUE(_CalcFlowEffect(input.positionWS.xz),input).rgb;

#else
// Horizontal Flow & Vertical　Flow
#define X2M_PARTICLE_VFLOW_APPLY(color,worldpos)
#define X2M_PARTICLE_HFLOW_APPLY(color,worldpos)
#define X2M_PARTICLE_VFLOW_RIM_APPLY(color,input)
#define X2M_PARTICLE_HFLOW_RIM_APPLY(color,input)
//alpha不受flow影响
#define X2M_PARTICLE_VFLOW_NOALPHA_APPLY(color,worldpos)
#define X2M_PARTICLE_HFLOW_NOALPHA_APPLY_NOALPHA(color,worldpos)
#define X2M_PARTICLE_VFLOW_RIM_NOALPHA_APPLY(color,input)
#define X2M_PARTICLE_HFLOW_RIM_NOALPHA_APPLY(color,input)
#endif

//////////////////////////////////////////////////////
//Flow Progress Effect
//////////////////////////////////////////////////////
#if defined(_X2M_PARTICLE_FLOW_PROGRESS_ON)
X2M_DECLARE_TEX2D(_FlowTex);
CBUFFER_START(ParticlePerMaterial_FlowProgress)
	float4 _FlowTex_ST;
	half4 _FlowColor;
	half _ScrollX;
	half _ScrollY;
	half _Progress;
	half _FlowSpeed;
CBUFFER_END

#define X2M_PARTICLE_FLOW_PROGRESS_UV(idx)         float2 flowProgressUV : TEXCOORD##idx;
#define X2M_PARTICLE_FLOW_PROGRESS_TRANSFER_UV(uv,output) output.flowProgressUV = TRANSFORM_TEX(uv, _FlowTex) + half2(_ScrollX, _ScrollY) * (_Progress + _FlowSpeed * _Time.y);

#define X2M_PARTICLE_APPLY_FLOW_PROGRESS(color,input) color.rgb += (_FlowColor * X2M_SAMPLE_TEX2D(_FlowTex,input.flowProgressUV)).rgb;
#define X2M_PARTICLE_APPLY_FLOW_PROGRESS_WITH_ALPHA(color,input) \
				fixed4 flowCol = _FlowColor * X2M_SAMPLE_TEX2D(_FlowTex,input.flowProgressUV);\
				color.rgb += flowCol.rgb;\
				color.a   *= flowCol.a;
#else
#define X2M_PARTICLE_APPLY_FLOW_PROGRESS(color,input) 
#define X2M_PARTICLE_APPLY_FLOW_PROGRESS_WITH_ALPHA(color,input)
#define X2M_PARTICLE_FLOW_PROGRESS_TRANSFER_UV(uv,output)
#define X2M_PARTICLE_FLOW_PROGRESS_UV(idx)
#endif

#if defined(_X2M_PARTICLE_MAIN_TEXTURE_ON)
X2M_DECLARE_TEX2D(_MainTex);
CBUFFER_START(ParticlePerMaterial_MainTexture)
	float4    _MainTex_ST;
	half4     _TintColor;
CBUFFER_END

#define X2M_PARTICLE_MAIN_TEXTURE_UV(idx)         float2 texcoord : TEXCOORD##idx;
#define X2M_PARTICLE_TRANSFER_MAIN_TEXTURE_UV(uv,output) output.texcoord = TRANSFORM_TEX(uv, _MainTex); X2M_PARTICLE_SCROLL_ROTATE_UV(output.texcoord);
#define X2M_PARTICLE_APPLY_MAIN_TEXTURE_ADD(col,input) float4 texcolor = X2M_SAMPLE_TEX2D(_MainTex,input.texcoord);col.rgb += input.color.rgb * _TintColor.rgb * texcolor.rgb; col.a = texcolor.a;
#define X2M_PARTICLE_APPLY_MAIN_TEXTURE_MUL(col,input) float4 texcolor = X2M_SAMPLE_TEX2D(_MainTex,input.texcoord);col.rgb *= input.color.rgb * _TintColor.rgb * texcolor.rgb; col.a = texcolor.a;
#else
#define X2M_PARTICLE_MAIN_TEXTURE_UV(idx) 
#define X2M_PARTICLE_TRANSFER_MAIN_TEXTURE_UV(uv,output) 
#define X2M_PARTICLE_APPLY_MAIN_TEXTURE_ADD(col,input)
#define X2M_PARTICLE_APPLY_MAIN_TEXTURE_MUL(col,input)
#endif

///////////////////////////////////////////////////////////////////////////////
//Noise 
///////////////////////////////////////////////////////////////////////////////
float2 X2MParticleRotateUV(float2 uv, float speed, float ori, float2 pivot)
{
    const float TO_RADIAN = 0.0174532925199433f;
	float cosx = cos((ori + speed * _Time.y) * TO_RADIAN);
	float sinx = sin((ori + speed * _Time.y) * TO_RADIAN);
	float2x2 rot = { cosx,-sinx,sinx,cosx};
    return mul(rot,uv - pivot) + pivot;
}
#if defined(_X2M_PARTICLE_NOISE_TEXTURE_ON)
X2M_DECLARE_TEX2D(_NoiseTex);
CBUFFER_START(ParticlePerMaterial_NoiseTexture)
	//float4 _MainTex_ST;
    float4 _NoiseTex_ST;
    float  _NoiseStrength;
	half4  _TintColor;
#if defined(_X2M_PARTICLE_NOISE_UVSCROLL_ON)
	float  _NoiseUVScrollSpeedU;
	float  _NoiseUVScrollSpeedV;
#endif
#if defined(_X2M_PARTICLE_NOISE_UVROTATION_ON)
	float  _NoiseUVRotationOri;// 朝向(Degree)
	float  _NoiseUVRotationPivotU;
	float  _NoiseUVRotationPivotV;
	float  _NoiseUVRotationSpeed;//角速度(Degree)
#endif
CBUFFER_END

#if defined(_X2M_PARTICLE_NOISE_UVSCROLL_ON)
/*使用frac避免游戏运行时间非常长导致的精度问题,因为_Time.y是游戏启动到目前的时间*/
#define X2M_PARTICLE_NOISE_SCROLL_UV(uv)  uv.xy += frac(_Time.y * float2(_NoiseUVScrollSpeedU,_NoiseUVScrollSpeedV));
#else
#define X2M_PARTICLE_NOISE_SCROLL_UV(uv) 
#endif

#if defined(_X2M_PARTICLE_NOISE_UVROTATION_ON)
#define X2M_PARTICLE_NOISE_ROTATE_UV(uv) uv = X2MParticleRotateUV(uv,_NoiseUVRotationSpeed,_NoiseUVRotationOri,float2(_NoiseUVRotationPivotU,_NoiseUVRotationPivotV));
#else
#define X2M_PARTICLE_NOISE_ROTATE_UV(uv) 
#endif

#define X2M_PARTICLE_NOISE_SCROLL_ROTATE_UV(uv) X2M_PARTICLE_NOISE_ROTATE_UV(uv); X2M_PARTICLE_NOISE_SCROLL_UV(uv)

float2 _X2MParticleNoiseTransformUV(float2 uv)
{
	uv = TRANSFORM_TEX(uv, _NoiseTex);
	X2M_PARTICLE_NOISE_SCROLL_ROTATE_UV(uv);
	return uv;
}
float _X2MParticleNoiseValue(float2 uv)
{
	float3 value;
	{
	    value.x = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(uv + frac(_Time.y) * float2( 0.119,  0.1091),  0, 0)).x;
	    value.y = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(uv + frac(_Time.y) * float2(-0.102,  0.01),    0, 0)).x;
	    value.z = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(X2MParticleRotateUV(uv,1.1,0,float2(0.5,0.5)), 0, 0)).x;
	}
	return (value.x + value.y) * value.z * _NoiseStrength;
}
float _X2MParticleNoiseValue2(float2 uv)
{
	float3 value;
	{
		value.x = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(uv + frac(_Time.y) * float2(0.05,  0.03), 0, 0)).x;
		value.y = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(X2MParticleRotateUV(uv, 0.03, 0, float2(0.5, 0.5)), 0, 0)).x;
		value.z = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(X2MParticleRotateUV(uv, 0.03, 0, float2(0.5, 0.5)), 0, 0)).x;
	}
	return (value.x * value.y) * value.z * _NoiseStrength;
}
float _X2MParticleNoiseValue3(float2 uv)
{
	float3 value;
	{
		value.x = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(uv + frac(_Time.y) * float2( 0.05, 0.03), 0, 0)).x;
		value.y = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(uv + frac(_Time.y) * float2( 0.03, -0.05), 0, 0)).x;
		value.z = X2M_SAMPLE_TEX2D_LOD(_NoiseTex, float4(X2MParticleRotateUV(uv, 0.03, 0, float2(0.5, 0.5)), 0, 0)).x;
	}
	return (value.x + value.y) * value.z * _NoiseStrength;
}
#define X2M_PARTICLE_NOISE_UV(idx)  float2 noiseUV : TEXCOORD##idx;
#define X2M_PARTICLE_NOISE_TRANSFER_UV(uv,output) output.noiseUV  = _X2MParticleNoiseTransformUV(uv);
#define X2M_PARTICLE_NOISE_TRANSFORM_UV(uv) _X2MParticleNoiseTransformUV(uv)
#define X2M_PARTICLE_NOISE_VALUE(uv)        _X2MParticleNoiseValue3(uv)
#define X2M_PARTICLE_NOISE_APPLY_UV(input)  input.texcoord += X2M_PARTICLE_NOISE_VALUE(input.noiseUV);
#else
#define X2M_PARTICLE_NOISE_UV(idx)  
#define X2M_PARTICLE_NOISE_TRANSFER_UV(uv,output)
#define X2M_PARTICLE_NOISE_TRANSFORM_UV(uv) uv
#define X2M_PARTICLE_NOISE_VALUE(uv) 0
#define X2M_PARTICLE_NOISE_APPLY_UV(input)
#endif
//////////////////////////////////////////////////////
//World Offset Effect
//////////////////////////////////////////////////////
float4 X2MParticleWorldToClipPos(float4 vertex, float3 normal, float rimpower,float strength,float noise)
{
	float3 normalWS   = UnityObjectToWorldNormal(normal);
	float3 positionWS = mul(unity_ObjectToWorld, vertex).xyz;
	float3 viewDir    = normalize(positionWS - _WorldSpaceCameraPos);

	float rim = 1.0 - abs(dot(viewDir, normalWS));
	rim = pow(max(0.0,rim), rimpower);
	positionWS += rim*normalWS*noise*strength;
	return TransformWorldToHClip(positionWS);
}
#ifdef _X2M_PARTICLE_WORLDOFFSET_ON
CBUFFER_START(ParticlePerMaterial_WorldOffset)
	float   _WorldOffsetRim;
	float   _WorldOffsetStrength;
CBUFFER_END
#define X2M_PARTICLE_WORLDOFFSET_CLIP_POS_NOISE(input,noise) X2MParticleWorldToClipPos(input.vertex,input.normal,_WorldOffsetRim,_WorldOffsetStrength,noise)
#define X2M_PARTICLE_WORLDOFFSET_CLIP_POS(input) X2M_PARTICLE_WORLDOFFSET_CLIP_POS_NOISE(input,X2M_PARTICLE_NOISE_VALUE(X2M_PARTICLE_NOISE_TRANSFORM_UV(input.texcoord)))
#else 
#define X2M_PARTICLE_WORLDOFFSET_CLIP_POS_NOISE(input,noise) UnityObjectToClipPos(input.vertex);
#define X2M_PARTICLE_WORLDOFFSET_CLIP_POS(input)  X2M_PARTICLE_WORLDOFFSET_CLIP_POS_NOISE(input,0)
#endif

//////////////////////////////////////////////////////
//Grab Refraction Effect
//////////////////////////////////////////////////////
#ifdef _X2M_PARTICLE_REFRACTION_ON
CBUFFER_START(ParticlePerMaterial_Refraction)
	float   _RefractionStrength;
CBUFFER_END
#define X2M_PARTICLE_REFRACTION_UV(idx)               float4 screenpos: TEXCOORD##idx;
#define X2M_PARTICLE_REFRACTION_CALC_UV(output,noise) output.screenpos = ComputeScreenPos(output.pos) + noise;
#define X2M_PARTICLE_REFRACTION_APPLY(color,input)    color.rgb += X2M_SAMPLE_TEX2DPROJ_BACKGROUND(input.screenpos).rgb * _RefractionStrength;
#else 
#define X2M_PARTICLE_REFRACTION_UV(idx)
#define X2M_PARTICLE_REFRACTION_CALC_UV(output,noise)
#define X2M_PARTICLE_REFRACTION_APPLY(color,input)
#endif
float2 X2MParticleTransformUV(float2 uv, float noise)
{
	 X2M_PARTICLE_SCROLL_ROTATE_UV(uv);
	 return uv + noise;
}
#define X2M_PARTICLE_TRANSFORM_UV(uv,tex,noise) X2MParticleTransformUV(TRANSFORM_TEX(uv, tex),noise)
//////////////////////////////////////////////////////
//Disovling Effect
//////////////////////////////////////////////////////
#if defined(_X2M_PARTICLE_DISSOLVE_ON) && defined(_X2M_PARTICLE_DISSOLVE_PER_PARTICLE_ON)
#define X2MParticleUV float4 //.z: AgePercent, .w: InverseStartLifeTime
#else 
#define X2MParticleUV float2
#endif

#if defined(_X2M_PARTICLE_DISSOLVE_ON)
X2M_DECLARE_TEX2D(_DissolveTex);
CBUFFER_START(ParticlePerMaterial_Dissolving)
	half4     _DissolveTex_ST;
	half      _DissolveThreshold; //在Per Particle情况下为Initial Threshold
	half      _DissolveEdgeSize;
	half4     _DissolveColor1;
#if defined(_X2M_PARTICLE_DISSOLVE_PER_PARTICLE_ON)
	half _DissolveDelayTime;
	half _DissolveDuration;
#endif
#if defined(_X2M_PARTICLE_DISSOLVE_DIRECTIONAL_ON)
	half3 _DissolveDirection;
#endif
CBUFFER_END

half3 DissolveTexture(half3 col, float2 uv, half threshold)
{
	half dissolvingAlpha = X2M_SAMPLE_TEX2D(_DissolveTex, uv).a;
	clip(dissolvingAlpha - threshold + _DissolveEdgeSize*threshold);
	half dissolvingFactor = step(threshold, dissolvingAlpha);
	return col * dissolvingFactor + _DissolveColor1.rgb * (1 - dissolvingFactor);
}

#if defined(_X2M_PARTICLE_DISSOLVE_PER_PARTICLE_ON)
half CalcDissolveThreshold(half agePercent, half invLifetime)
{
	half lifetime = 1.0f/invLifetime;
	half duration = min(_DissolveDuration, lifetime);
	if(duration == 0.0f)
		return 1.0f;
	half time      = agePercent * lifetime;
	half threshold = _DissolveThreshold;
	if(_DissolveDelayTime <= time)
	{
		half speed =  (1.0f - _DissolveThreshold)/duration;
		threshold += speed * (time - _DissolveDelayTime);
	}
	return saturate(threshold);
}
#define _DISSOLVE_THRESHOLD(uv)          CalcDissolveThreshold(uv.z,uv.w)
#define _DISSOLVE_TRANSFORM_TEX(dst,uv)  dst.xy = TRANSFORM_TEX(uv, _DissolveTex); dst.zw = uv.zw;
#else
#define _DISSOLVE_THRESHOLD(uv)          _DissolveThreshold
#define _DISSOLVE_TRANSFORM_TEX(dst,uv)  dst = TRANSFORM_TEX(uv, _DissolveTex);
#endif

#if defined(_X2M_PARTICLE_DISSOLVE_DIRECTIONAL_ON)
half3 DissolveDirection(half3 col, float3 pos)
{
	float3 delta = pos.xyz - _DissolveDirection.xyz;
	clip(delta);
	half3 factor = step(_DissolveEdgeSize, delta);

	col =  col * factor.x + _DissolveColor1.rgb * (1 - factor.x);
	col =  col * factor.y + _DissolveColor1.rgb * (1 - factor.y);
	col =  col * factor.z + _DissolveColor1.rgb * (1 - factor.z);

	return col;
}
#define _DISSOLVE_DIRECTION(col,pos)  DissolveDirection(col,pos.xyz)
#else 
#define _DISSOLVE_DIRECTION(col,pos)  col.rgb
#endif

#define X2M_PARTICLE_DISSOLVE_UV(idx)            X2MParticleUV dissolveUV: TEXCOORD##idx;
#define X2M_PARTICLE_DISSOLVE_TRANSFER_UV(o,uv)  _DISSOLVE_TRANSFORM_TEX(o.dissolveUV,uv)

#define X2M_PARTICLE_DISSOLVE_POSITION(idx)  float4 dissolvePos: TEXCOORD##idx;
#define X2M_PARTICLE_DISSOLVE_TRANSFER_POSITION(o,pos)  o.dissolvePos = pos;

// 第二个参数为uv
#define X2M_PARTICLE_DISSOLVE_APPLY_UV(col,uv)   col.rgb = DissolveTexture(col.rgb,uv,_DISSOLVE_THRESHOLD(uv));
// 第二个参数为pos
#define X2M_PARTICLE_DISSOLVE_APPLY_POS(col,pos) col.rgb =_DISSOLVE_DIRECTION(col,pos);
// 第二个参数为input
#define X2M_PARTICLE_DISSOLVE_APPLY(col,input)  X2M_PARTICLE_DISSOLVE_APPLY_UV(col,input.dissolveUV); X2M_PARTICLE_DISSOLVE_APPLY_POS(col,input.dissolvePos);
#define X2M_PARTICLE_DISSOLVE_TRANSFORM_TEX(uv)  TRANSFORM_TEX(uv, _DissolveTex)
#else
#define X2M_PARTICLE_DISSOLVE_POSITION(idx) 
#define X2M_PARTICLE_DISSOLVE_TRANSFER_POSITION(o,pos) 

#define X2M_PARTICLE_DISSOLVE_UV(idx)           
#define X2M_PARTICLE_DISSOLVE_TRANSFER_UV(o,uv) 

#define X2M_PARTICLE_DISSOLVE_APPLY_UV(col,uv)
#define X2M_PARTICLE_DISSOLVE_APPLY_POS(col,pos)
#define X2M_PARTICLE_DISSOLVE_APPLY(col,input)
#define X2M_PARTICLE_DISSOLVE_TRANSFORM_TEX(uv)  uv
#endif


#endif //X2M_LWRP_PARTICLE_COMMON_INCLUDED