#ifndef ALLIN13DSHADER_COMMON_STRUCTS
#define ALLIN13DSHADER_COMMON_STRUCTS

#define T_SPACE_PROPERTIES(n1, n2, n3) float3 tspace0 : TEXCOORD##n1; float3 tspace1 : TEXCOORD##n2; float3 tspace2 : TEXCOORD##n3;
#define INIT_T_SPACE(normalWS) \
	o.tspace0 = float3(tangentWS.x, bitangentWS.x, normalWS.x); \
	o.tspace1 = float3(tangentWS.y, bitangentWS.y, normalWS.y); \
	o.tspace2 = float3(tangentWS.z, bitangentWS.z, normalWS.z);


#define INIT_DECAL_DATA(decalData) \
	decalData.baseColor = float4(0, 0, 0, 1); \
	decalData.normalTS = float4(0, 0, 0, 0); \
	decalData.emissive = 0; \
	decalData.mask = 0; \
	decalData.unpackedNormal = float3(0, 0, 0); \
	decalData.smoothness = 0; \
	decalData.metallic = 0; \
	decalData.MAOSAlpha = 1;
	
#define INIT_EFFECTS_DATA(data) \
	data.mainUV = float2(0, 0); \
	data.rawMainUV = float2(0, 0); \
	data.normalizedScreenSpaceUV = float2(0, 0); \
	data.vertexColor = float4(1, 1, 1, 1); \
	data.vertexColorLuminosity = 1.0; \
	data.vertexOS = float3(0, 0, 0); \
	data.vertexWS = float3(0, 0, 0); \
	data.vertexVS = float3(0, 0, 0); \
	data.normalOS = float3(0, 1, 0); \
	data.normalWS = float3(0, 1, 0); \
	data.viewDirWS = float3(0, 0, -1); \
	data.tangentWS = float3(1, 0, 0); \
	data.bitangentWS = float3(0, 1, 0); \
	data.projPos = float4(0, 0, 0, 0); \
	data.pos = float4(0, 0, 0, 0); \
	data.lightColor = float3(1, 1, 1); \
	data.lightDir = float3(0, -1, 1); \
	data.sceneDepthDiff = 1.0; \
	data.normalizedDepth = 0; \
	data.camDistance = 0; \
	data.camDistanceViewSpace = 0; \
	data.shaderTime = float3(0, 0, 0); \
	data.uv_dist = float2(0, 0); \
	data.uvMatrix = 0; \
	data.uv_matrix_normalMap = 0; \
	data.uv_normalMap = 0; \
	data.uvDiff = 0; \
	data._ShadowCoord = 0; \
	data.metallic = 0; \
	data.smoothness = 1;

#define INIT_GI(gi) \
	gi.diffuse = float3(0, 0, 0); \
	gi.shadowMask = float4(0, 0, 0, 0); \
	gi.uvLightmap = float2(0, 0);


#define UV_FRONT(data) data.uvMatrix._m00_m01
#define UV_FRONT_WEIGHT(data) data.uvMatrix._m02

#define UV_SIDE(data) data.uvMatrix._m10_m11
#define UV_SIDE_WEIGHT(data) data.uvMatrix._m12

#define UV_TOP(data) data.uvMatrix._m20_m21
#define UV_TOP_WEIGHT(data) data.uvMatrix._m22

#define UV_DOWN(data) data.uvMatrix._m30_m31
#define UV_DOWN_WEIGHT(data) data.uvMatrix._m32

#define MAIN_UV(data) data.uvMatrix._m00_m01

//Main UV
#define SCALED_MAIN_UV(input)	input.mainUV.xy
#define RAW_MAIN_UV(input)		input.mainUV.zw

//Tangent WS
#define TANGENT_WS(input) float3(input.tspace0.x, input.tspace1.x, input.tspace2.x)

//Interpolator 01
#define UV_LIGHTMAP(input) input.interpolator_01.xy
#define UV_DIFF(input) input.interpolator_01.zw

//Interpolator 02
#define UV_NORMAL_MAP(input) input.interpolator_02.xy
#define UV_EMISSION_MAP(input) input.interpolator_02.zw

//Interpolator 03
#define SHADER_TIME(input) input.interpolator_03.xyz
#define FOGCOORD(input) input.interpolator_03.w

//Interpolator 04
#define NORMAL_OS(input) input.interpolator_04.xyz
#define VERTEX_COLOR_R(input) input.interpolator_04.w

//Interpolator 05
#define POSITION_OS(input) input.interpolator_05.xyz
#define VERTEX_COLOR_G(input) input.interpolator_05.w

//Interpolator 06
#define POSITION_WS(input) input.interpolator_06.xyz
#define VERTEX_COLOR_B(input) input.interpolator_06.w

//Interpolator 07
#define VIEWDIR_WS(input) input.interpolator_07.xyz
#define VERTEX_COLOR_A(input) input.interpolator_07.w


#ifdef _NORMAL_MAP_ON
	#define NORMAL_UV_FRONT(data) data.uv_matrix_normalMap._m00_m01
	#define NORMAL_UV_SIDE(data) data.uv_matrix_normalMap._m10_m11
	#define NORMAL_UV_TOP(data) data.uv_matrix_normalMap._m20_m21

	#define MAIN_NORMAL_UV(data) data.uv_matrix_normalMap._m00_m01
#endif


#ifdef _NORMAL_MAP_ON
	#ifdef _TRIPLANAR_MAPPING_ON
		#define DISPLACE_ALL_UVS(data, displacementAmount) \
			UV_FRONT(data) += displacementAmount; \
			UV_SIDE(data) += displacementAmount; \
			UV_TOP(data) += displacementAmount; \
			UV_DOWN(data) += displacementAmount; \
			NORMAL_UV_FRONT(data) += displacementAmount; \
			NORMAL_UV_SIDE(data) += displacementAmount; \
			NORMAL_UV_TOP(data) += displacementAmount; \
			data.rawMainUV += displacementAmount;
			
		#define QUANTIZE_ALL_UVS(data, quantizeFactor) \
			UV_FRONT(data)	= floor(UV_FRONT(data)	* quantizeFactor) / quantizeFactor; \
			UV_SIDE(data)	= floor(UV_SIDE(data)	* quantizeFactor) / quantizeFactor; \
			UV_TOP(data)	= floor(UV_TOP(data)	* quantizeFactor) / quantizeFactor; \
			UV_DOWN(data)	= floor(UV_DOWN(data)	* quantizeFactor) / quantizeFactor; \
			NORMAL_UV_FRONT(data)	= floor(NORMAL_UV_FRONT(data)	* quantizeFactor) / quantizeFactor; \
			NORMAL_UV_SIDE(data)	= floor(NORMAL_UV_SIDE(data)	* quantizeFactor) / quantizeFactor; \
			NORMAL_UV_TOP(data)		= floor(NORMAL_UV_TOP(data)		* quantizeFactor) / quantizeFactor; \
			data.rawMainUV = floor(data.rawMainUV * quantizeFactor) / quantizeFactor;
		
		#define FLOOR_ALL_UVS(data) \
			UV_FRONT(data)	= floor(UV_FRONT(data)); \
			UV_SIDE(data)	= floor(UV_SIDE(data)); \
			UV_TOP(data)	= floor(UV_TOP(data)); \
			UV_DOWN(data)	= floor(UV_DOWN(data)); \
			NORMAL_UV_FRONT(data)	= floor(NORMAL_UV_FRONT(data)); \
			NORMAL_UV_SIDE(data)	= floor(NORMAL_UV_SIDE(data)); \
			NORMAL_UV_TOP(data)		= floor(NORMAL_UV_TOP(data)); \
			data.rawMainUV = floor(data.rawMainUV);
	#else
		#define QUANTIZE_ALL_UVS(data, quantizeFactor) \
			MAIN_UV(data) = floor(MAIN_UV(data) * quantizeFactor) / quantizeFactor; \
			MAIN_NORMAL_UV(data) = floor(MAIN_NORMAL_UV(data) * quantizeFactor) / quantizeFactor; \
			data.rawMainUV = floor(data.rawMainUV * quantizeFactor) / quantizeFactor;
			
		#define DISPLACE_ALL_UVS(data, displacementAmount) \
			MAIN_UV(data) += displacementAmount; \
			MAIN_NORMAL_UV(data) += displacementAmount; \
			data.rawMainUV += displacementAmount;
	#endif
#else
	#ifdef _TRIPLANAR_MAPPING_ON
		#define DISPLACE_ALL_UVS(data, displacementAmount) \
			data.uvMatrix._m00_m01 += displacementAmount; \
			data.uvMatrix._m10_m11 += displacementAmount; \
			data.uvMatrix._m20_m21 += displacementAmount; \
			data.uvMatrix._m30_m31 += displacementAmount; \
			data.rawMainUV += displacementAmount;
			
		#define QUANTIZE_ALL_UVS(data, quantizeFactor) \
			data.uvMatrix._m00_m01 = floor(data.uvMatrix._m00_m01 * quantizeFactor) / quantizeFactor; \
			data.uvMatrix._m10_m11 = floor(data.uvMatrix._m10_m11 * quantizeFactor) / quantizeFactor; \
			data.uvMatrix._m20_m21 = floor(data.uvMatrix._m20_m21 * quantizeFactor) / quantizeFactor; \
			data.uvMatrix._m30_m31 = floor(data.uvMatrix._m30_m31 * quantizeFactor) / quantizeFactor; \
			data.rawMainUV = floor(data.rawMainUV * quantizeFactor) / quantizeFactor;
	#else
		#define DISPLACE_ALL_UVS(data, displacementAmount) \
			MAIN_UV(data)	+= displacementAmount; \
			data.rawMainUV	+= displacementAmount;
			
		#define QUANTIZE_ALL_UVS(data, quantizeFactor) \
			MAIN_UV(data) = floor(MAIN_UV(data) * quantizeFactor) / quantizeFactor; \
			data.rawMainUV = floor(data.rawMainUV * quantizeFactor) / quantizeFactor;
	#endif
#endif

#define RECALCULATE_NORMAL_OFFSET 0.01

struct AllIn1LightData
{
	float3 lightColor;
	float3 lightDir;
	float realtimeShadow;
	float4 shadowColor;
	float distanceAttenuation;
	uint layerMask;
};

struct AllIn1DecalData
{
	float4 baseColor;
	float4 normalTS;
	float3 emissive;
	float mask;
	float3 unpackedNormal;
	float smoothness;
	float metallic;
	float MAOSAlpha;
};

struct ShadowCoordStruct
{
	float4 _ShadowCoord : TEXCOORD0;
	float4 pos : TEXCOORD1;
};

struct FogStruct
{
	float fogCoord : TEXCOORD0;
};

struct VertexData
{
	float4 vertex		: POSITION; 
	float2 uv			: TEXCOORD0;
	float2 uvLightmap	: TEXCOORD1;
	float3 normal		: NORMAL;
	float4 tangent		: TANGENT;
	float4 vertexColor	: COLOR;

	UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct FragmentDataOutline
{
	float4 pos	: SV_POSITION;
	float2 mainUV	: TEXCOORD0;
	float3 normalWS : TEXCOORD1;
	
	float4 interpolator_01 : TEXCOORD2;
	float4 interpolator_02 : TEXCOORD3;
	float4 interpolator_03 : TEXCOORD4;

	float3 positionWS : TEXCOORD5;

	UNITY_VERTEX_INPUT_INSTANCE_ID
	UNITY_VERTEX_OUTPUT_STEREO
};

struct FragmentData
{
	float4 pos	: SV_POSITION;
	float4 mainUV	: TEXCOORD0;
	
	float3 normalWS : TEXCOORD1;

	float4 interpolator_01 : TEXCOORD2;
	float4 interpolator_02 : TEXCOORD3;
	float4 interpolator_03 : TEXCOORD4;
	float4 interpolator_04 : TEXCOORD5;
	float4 interpolator_05 : TEXCOORD6;
	float4 interpolator_06 : TEXCOORD7;
	float4 interpolator_07 : TEXCOORD8;

#ifdef REQUIRE_TANGENT_WS
	T_SPACE_PROPERTIES(9, 10, 11)
#endif

#if defined(REQUIRE_SCENE_DEPTH) || defined(LOD_FADE_CROSSFADE)
	float4 projPos : TEXCOORD12;
#endif
	
	float4 _ShadowCoord : TEXCOORD13;

	UNITY_VERTEX_INPUT_INSTANCE_ID
	UNITY_VERTEX_OUTPUT_STEREO
};

struct FragmentDataShadowCaster
{
	float4 pos	: SV_POSITION;
	float4 positionOS : TEXCOORD1;
	float2 mainUV : TEXCOORD2;
	float3 positionWS : TEXCOORD3;
	float2 uv2 : TEXCOORD4;
	float3 shaderTime : TEXCOORD5;
	float3 normalOS : TEXCOORD6;
	float3 normalWS : TEXCOORD7;
	
	UNITY_VERTEX_INPUT_INSTANCE_ID	
	UNITY_VERTEX_OUTPUT_STEREO 
};

struct TriplanarData
{
	float2 uv_triplanar_front;
	float2 uv_triplanar_side;
	float2 uv_triplanar_top;
};

struct AllIn1GI
{
	float3 diffuse;
	float4 shadowMask;
	float2 uvLightmap;
};

//<AllIn1Struct name=EffectsData>
struct EffectsData
{
	float2 mainUV;
	float2 rawMainUV;

	float2 normalizedScreenSpaceUV;

	float4 vertexColor;
	float vertexColorLuminosity;

	float3 vertexOS;
	float3 vertexWS;
	float3 vertexVS;
	float3 normalOS;
	float3 normalWS;
	float3 viewDirWS;

	float3 tangentWS;
	float3 bitangentWS;

	float4 projPos;
	float4 pos; //Patch to fix the error when UNITY_LIGHT_ATTENUATION is expanded
	
	float3 lightColor;
	float3 lightDir;
	
	float sceneDepthDiff;
	float normalizedDepth;
	float camDistance;
	float camDistanceViewSpace;
	float3 shaderTime;

	float2 uv_dist;
	
	float4x3 uvMatrix;
	float4x3 uv_matrix_normalMap;
	float2 uv_normalMap;

	float2 uvDiff;

	float4 _ShadowCoord;

	float metallic;
	float smoothness;
};
//</AllIn1Struct>

#ifdef _TRIPLANAR_MAPPING_ON
float3 GetTriplanarWeights(float3 normal, float2 uv)
{
	float3 weights = abs(normal);

	float transition = 0.0;
#ifdef _TRIPLANAR_NOISE_TRANSITION_ON
	float2 scaleUV = ACCESS_PROP_FLOAT4(_TriplanarNoiseTex_ST).xy;
	transition = SAMPLE_TEX2D(_TriplanarNoiseTex, uv * scaleUV).r;
	transition = (transition - 0.5) * 2.0;
	transition *= ACCESS_PROP_FLOAT(_TriplanarTransitionPower);
	
	normal.xz = lerp(float2(-0.5, -0.5), float2(0.5, 0.5), transition);
	
	normal = normalize(normal);
	weights = abs(normal);
#endif
	
	weights = pow(weights, ACCESS_PROP_FLOAT(_TriplanarSharpness));
	weights = weights / (weights.x + weights.y + weights.z);
	
	return weights;
}
#endif

#endif