

#ifndef X2M_GRASS_INCLUDED
#define X2M_GRASS_INCLUDED
#define USE_LOD0 1
#include "FoliageWindField.hlsl"

struct vertex_input_compress {
	float4 vertex : POSITION;
	UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct vertex_input {
	float4 vertex;
	half3 normal;
	float2 texcoord;
	half4 texcoord1;
};

vertex_input DecodeVertexInputCompress(vertex_input_compress v)
{


	////////////// vertex, uv, normal, color covert to uint3   max bit is 30 is not 32 /////////////////////////////
	// x
	//  0                           8                               14                              20                      30
	//      vertex.x -> 256 ->8 bit     vertex.y ->64->6 bit             normal.x -> 64 ->6 bit          uv.x ->1024->10bit
	//
	// y
	// 0                            8                       14                          20                           30
	//      vertex.z ->256 ->8 bit    normal.y->64->6 bit        normal.z ->64 ->6 bit        uv.y ->1024->10 bit
	//
	// z
	// 0                                            9                                        18                                 26                                      30
	//   color.r -> 64 * 10 = 640 ->512->9 bit        color.g -> 64 * 10 = 640 ->512->9 bit      color.b -> 360 = 256 ->8 bit       color.a -> 3.0 * 10 -> 16 -> 4bit
	//////////////////////////////////////////////////////////////////////////////////////////

	vertex_input ret = (vertex_input)0;
	uint3 data = asuint(v.vertex.xyz);
	uint4 x = (data.xxxx >> uint4(0, 8, 14, 20));
	x &= uint4(255, 63, 63, 1023);
	uint4 y = (data.yyyy >> uint4(0, 8, 14, 20));
	y &= uint4(255, 63, 63, 1023);
	uint4 z = (data.zzzz >> uint4(0, 9, 18, 26));
	z &= uint4(511, 511, 255, 15);

	ret.vertex.xyzw = float4(x.xy, y.x, 1.0);
	ret.vertex.xyz *= float3(1.0 / 256.0, 1.0 / 64.0, 1.0 / 256.0);
	ret.vertex.xz -= float2(0.5, 0.5);

	ret.texcoord.xy = float2(x.w, y.w);
	ret.texcoord.xy *= (1.0 / 1024.0);
	
	ret.normal = half3(x.z, y.yz);
	ret.normal *= (1.0 / 64.0);
	ret.normal -= half3(0.5, 0.5, 0.5);
	ret.normal = normalize(ret.normal);

	ret.texcoord1 = z;
	// xy : offset [0m, 8m], z : rotate [0, 3.141592 * 2], w : scale [0, 3]
	ret.texcoord1 *= half4(8.0 / 512.0, 8.0 / 512.0, (3.141592 * 2.0) / 256.0, 3.0 / 16.0);

	// test only
	//ret.texcoord1.y *= 0;
	//ret.texcoord1.x *= 0;
	//ret.texcoord1.w *= 3.0;
	// test end

	return ret;
}

#if USE_LOD0
float2 BladeXYToForceMapUV(float2 uv)
{
	// the tile is 64 X 64
	float2 ret = uv * 255;	// [0, 63]
	ret += float2(0.5, 0.5);
	ret.xy *= _CollisionTex_TexelSize.xy;
	return ret;
}
#endif

float2 CalColorMaskUVFromWorldPos(float3 posWS)
{
	float2 uv = posWS.xz;
	uv *=  1.0f/100.0f;	//world pos -> uv  
	//uv = frac(uv);
	//uv.y = 1.0 - uv.y;
	//uv += 0.5f; //heightmap offset -256 -> uv offset 0.5
	float offset = 260.0 / 512.0; //According to: HeightMapMaskExport.Export(): Vector3 rayPos = new Vector3(ni - 260, 1000, nj - 260)
	uv += offset;

	return uv;
}


float4 CalHeigthMapUVFromWorldPos(float2 uv, float2 vOffset)
{
	vOffset.xy *= 0.875;//7.0 / 8.0;
	uv += vOffset.xy;
	uv *= _RegionHeightMap_TexelSize.xy;	//world pos -> uv
	uv = frac(uv);
	uv.xy += float2(1, 1);
	uv = frac(uv);
	uv += (_RegionHeightMap_TexelSize.xy * 0.5);
	//uv.y = 1.0 - uv.y;
	//uv += 0.5f; //heightmap offset -256 -> uv offset 0.5
	float offset = 260.0 / 512.0; //According to: HeightMapMaskExport.Export(): Vector3 rayPos = new Vector3(ni - 260, 1000, nj - 260)
	uv += offset;
	
//#if UNITY_UV_STARTS_AT_TOP
//			 DX
//			uv.y = 1.0 - uv.y;
//			 OpenGL, don't need 1.0 - y
//#endif
	return float4(uv, 0, 0);
}

half2 DecodeTemplateColor_RandomOffset(half4 color)
{
	half2 ret = half2(0, 0);
	ret.x = color.z / 6.14;
	ret.y = color.w / 3.0;
	ret.xy *= 2.0;
	ret.xy -= half2(1, 1);
	ret.xy *= 0.5;//1.0 / 8.0;//(8.0 / 64.0);

	return ret;
}

float4 CalGrassUVFromWorldPos(float2 uv2, float2 vOffset)
{
    //vOffset.xy *= 0.875; //7.0 / 8.0;
    //uv += vOffset.xy;
   
}
float GetMaskInBlade(half3 worldPos)
{
    float2 uv = float2(worldPos.x ,  worldPos.z );
    uv *= _RegionHeightMap_TexelSize; //world pos -> uv 
    uv *= _RegionHeightMap_ST;
    float offset = 260.0 / 512.0; //According to: HeightMapMaskExport.Export(): Vector3 rayPos = new Vector3(ni - 260, 1000, nj - 260)
    uv += offset;
    uv = frac(uv);
    float4 heightMapValue = SAMPLE_TEXTURE2D_LOD(_RegionHeightMap, sampler_RegionHeightMap, uv, 0).rgba;
    return heightMapValue.y;
}

float2 GetHeightInBlade(float3 localPos, float4 worldPos)
{
	float4 uv = CalHeigthMapUVFromWorldPos(worldPos.xz, localPos.xz);
    
	float4 heightMapValue1 = SAMPLE_TEXTURE2D_LOD(_RegionHeightMap, sampler_RegionHeightMap, uv.xy, uv.w).rgba;
	heightMapValue1.r *= -25.5;
	return heightMapValue1.xy;
}



half4 DecodeTemplateColor(half4 color)
{
	//half4 ret = float4(0, 0, 0, 0);
	//ret.x = color.x * 8;
	//ret.y = color.y * 8;
	//ret.z = color.z * 10.0;
	//ret.w = color.w * 10.0;

	////ret.xy += DecodeTemplateColor_RandomOffset(color);

	//return ret;
	return color * half4(8, 8, 10, 10);
}

half3 DecodeDisplacement(half2 angle)
{
	/*float s1 = sin(zenith);
	float s2 = sin(azimuth);
	float c1 = cos(zenith);
	float c2 = cos(azimuth);

	float3 ret = float3(s1 * c2,
		c1,
		s1 * s2);*/

	half2 s = sin(angle);
	half2 c = cos(angle);
	half3 ret = half3(s.x, c.x, s.x);
	ret.xz *= half2(c.y, s.y);
	ret = normalize(ret);
	return ret;

}

half3 DecodeNormal(half2 angle)
{
	/*half s1 = sin(zenith);
	half s2 = sin(azimuth);*/
	half2 s = sin(angle);
	half2 c = cos(angle);
	//half c1 = cos(zenith);
	//half c2 = cos(azimuth);

	//half3 ret = half3(s1 * c2,
	//	c1,
	//	s1 * s2);

	half3 ret = half3(s.x, c.x, s.x);
	ret.xz *= half2(c.y, s.y);
	ret = normalize(ret);
	return ret;

}


half4 DecodeIdleDisplacement(half randomSeed1, half randomSeed2, half r)
{
	half b = randomSeed1 * 6.28;
	half a = randomSeed2 * 3.14 / 2.0;//*(_Idle.y / 180.0);	//zenith
	/*float s1 = sin(a);
	float s2 = sin(b);
	float c1 = cos(a);
	float c2 = cos(b);


	float4 ret = float4(s1 * c2,
		c1,
		s1 * s2,
		0.0);

	ret = normalize(ret) * r;*/

	return half4(DecodeDisplacement(half2(a, b)) * r, 0);

}

#if USE_LOD0

half4 GetCollision(float3 worldPos)
{
	half4 ret = half4(0, 0, 0, 0);

    float2 uvDisplacement = worldPos.xz - _PlayerPos.xz;
	uvDisplacement /= 12.8;
	uvDisplacement += float2(0.5, 0.5);

	if (uvDisplacement.x >= 0 && uvDisplacement.x <= 1 && uvDisplacement.y >= 0 && uvDisplacement.y <= 1)
	{

#if UNITY_UV_STARTS_AT_TOP
		// DX
		uvDisplacement.y = 1.0 - uvDisplacement.y;
		// OpenGL, don't need 1.0 - y
#endif

		ret = SAMPLE_TEXTURE2D_LOD(_CollisionTex, sampler_CollisionTex, uvDisplacement, 0);
		ret.yw = 0;

        float d = _PlayerPos.y - worldPos.y;
		if (d >= 0)
		{
			d += 1.0;
			d = pow(d, -3);
			ret *= d;
		}

	}

	return ret;
}

half4 GetInteractive(float3 worldPos)
{
	half4 ret = half4(0, 0, 0, 0);
    float2 uv = floor(worldPos.xz * 5) - floor(_PlayerPos.xz * 5);
	uv *= _InteractiveTex_TexelSize.xy;
	uv += float2(0.5, 0.5);

#if UNITY_UV_STARTS_AT_TOP
	//DX
	uv.y = 1.0 - uv.y;
	//OpenGL, don't need 1.0 - y
#endif
	if (uv.x >= 0 && uv.x <= 1 && uv.y >= 0 && uv.y <= 1)
	{
		ret = SAMPLE_TEXTURE2D_LOD(_InteractiveTex, sampler_InteractiveTex, uv, 0);
		//ret = tex2Dlod(_CutoffGrassEncodeTex, float4(uv, 0, 0));
	}

	return ret;
}
#endif

float4 CalV1(float4 root, float4 v2)
{
	float4 v2p = v2 - root;
	return dot(float4(0, 1, 0, 0), v2p) * float4(0, 1, 0, 0) + root;
}

float3 CalBiNormal(float3 v2p, float b)
{
	float3 vUp = float3(0, 1, 0);
	if (v2p.y == 1)	//if(dot(vUp, v2p) == 1)
	{
		float s = sin(b);
		float c = cos(b);

		//float3 vOriginBiNormal = float3(1, 0, 0);
		// float3 vBiNormal = 0;	// when the grass's tip is (0, 1, 0)
		//vBiNormal.x = c * vOriginBiNormal.x + s * vOriginBiNormal.z;
		//vBiNormal.y = 0;
		//vBiNormal.z = -s * vOriginBiNormal.x + c * vOriginBiNormal.z;
		return float3(c, 0, -s);
	}
	else
	{
		float3 ret = cross(vUp, v2p);
		ret = normalize(ret);
		return ret;
	}
	
	
}

float3 CalNormal(float3 v2p, float3 vEN, float b)
{
	float s = sin(b);
	float c = cos(b);

	//float3 vNormal = float3(0, 0, 1);
	// float3 vTipNormal = 0;	// when the grass's tip is (0, 1, 0)
	//vTipNormal.x = c * vNormal.x + s * vNormal.z;
	//vTipNormal.y = 0;
	//vTipNormal.z = -s * vNormal.x + c * vNormal.z;

	float3 vTipNormal = float3(s, 0, c);

	float3 vUp = float3(0, 1, 0);
	float3 vGroundV2p = float3(v2p.x, 0, v2p.z);
	float dv = dot(vGroundV2p, vTipNormal);
	vEN *= dv;
	vEN = normalize(vEN);
	float dt = 0;
	if (dv < 0)
		dt = 1.0 + dv;
	else
		dt = 1.0 - dv;

	float3 ret = vTipNormal * dt + vEN * (1.0 - dt);
	ret = normalize(ret);

	return ret;
}



//half3 TranslucencyLeaf(half3 vLight, half3 vView, half3 vNormal, half randomValue)
//{
//	half3 transmission = 0;
//	
//	half3 SubsurfaceColor = _LightColor0.rgb * _TintColor * _TintIntensity;
//
//	half Wrap = 1.5;
//	half Macro_AO = randomValue;//1.0;
//	half NoL = dot(vNormal, vLight);
//	half VoL = dot(vView, vLight);
//	half WrapNoL = saturate((-NoL + Wrap) / sqrt(1 + Wrap)) * saturate(Macro_AO);
//	half Scatter = max(0, D_GGX(_Roughness, saturate(-VoL + _PhaseShift)));
//	transmission = (WrapNoL * Scatter) * SubsurfaceColor;
//	
//	return transmission;
//	
//}

//half3 BackLeaf(half3 vLight, half3 vEye, half3 vNormal, half randomValue)
//{
//	half3 transmission = 0;
//	half fEdotL = saturate(dot(vEye.xyz, -vLight.xyz));
//	half fPowEdotL = fEdotL * fEdotL;
//	fPowEdotL *= fPowEdotL;
//	half fLdotNBack = saturate(dot(-vNormal.xyz, vLight.xyz) * 0.6 + 0.4);
//	half3 fBackShading = lerp(fPowEdotL, fLdotNBack, _PhaseShift);
//
//	half3 SubsurfaceColor = _LightColor0.rgb * _TintColor * _TintIntensity;
//	transmission = fBackShading * SubsurfaceColor;
//
//
//	return transmission;
//
//}



#ifdef USE_LOD0

bool IsClip0(float distance, float randomValue)
{
	bool bClip = false;
	half threshold = saturate((distance - 32) / -8.0);
	bClip = step(threshold, randomValue);
	return bClip;
}

#endif

float3 RotateY(float3 localPos)
{
	float3 vCenter = float3(4, 0, 4);
	float3 vDif = localPos - vCenter;
	float3 vDifRotateY = vDif;
	//vDif = mul((float3x3)unity_ObjectToWorld, vDif);
	vDifRotateY.x = dot(vDif.xz, float2(unity_ObjectToWorld[0][0], unity_ObjectToWorld[0][2]));
	vDifRotateY.z = dot(vDif.xz, float2(unity_ObjectToWorld[2][0], unity_ObjectToWorld[2][2]));
	return vDifRotateY + vCenter;
}

#endif // X2M_GRASS_INCLUDED
