/*
  Copyright(C) 2018-2023, tetraface Inc. All rights reserved.
*/
/*
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/
*/
#include "world.inc"
#include "texture.inc"
#include "light.inc"
#include "model.inc"
#if OIT
#include "oit.inc"
#endif

cbuffer ConstantBufferMaterial : register( b2 )
{
	int DoubleSided;
	float4 MapTransform;
	float4 MapTranslate;
	float Alpha;
	float4 BaseColor;
	int AlphaMode;
	float AlphaCutOff;
	int TransparentWithZWrite;
	int RenderQueueOffsetNumber;
	float4 ShadeColorFactor;
	float ShadingShiftFactor;
	float ShadingToonyFactor;
	float GiEqualizationFactor;
	float4 Emissive;
	float RimLightingMixFactor;
	float4 ParametricRimColorFactor;
	float ParametricRimFresnelPowerFactor;
	float ParametricRimLiftFactor;
	int OutlineWidthMode;
	float OutlineWidthFactor;
	float4 OutlineColorFactor;
	float OutlineLightingMixFactor;
	float UvAnimationScrollXSpeedFactor;
	float UvAnimationScrollYSpeedFactor;
	float UvAnimationRotationSpeedFactor;
	float NormalScale;
	int HasEmissiveMap;
	int HasShadeMultiplyMap;
	int HasShadingShiftMap;
	float ShadingShiftScale;
	int HasMatcapMap;
	float4 MatcapFactor;
	int HasRimMultiplyMap;
	int HasOutlineWidthMultiplyMap;
	int HasUvAnimationMaskMap;
}

#ifndef USE_TANGENT
#define USE_TANGENT NORMALMAP
#endif

#if TEXTURE
Texture2D ColorMap : register( t0 );
#endif
SamplerState ColorMapSampler : register( s0 );
//#if ALPHAMAP
//Texture2D AlphaMap : register( t1 );
//SamplerState AlphaMapSampler : register( s1 );
//#endif
#if NORMALMAP
Texture2D NormalMap : register( t2 );
SamplerState NormalMapSampler : register( s2 );
#endif
#if SHADOW
Texture2D ShadowMap : register( t3 );
SamplerState ShadowMapSampler : register( s3 );
#endif
Texture2D EmissiveMap : register( t4 );
Texture2D ShadeMultiplyMap : register( t5 );
Texture2D ShadingShiftMap : register( t6 );
Texture2D MatcapMap : register( t7 );
Texture2D RimMultiplyMap : register( t8 );
Texture2D OutlineWidthMultiplyMap : register( t9 );
Texture2D UvAnimationMaskMap : register( t10 );

struct VS_INPUT
{
	float4 Pos : POSITION;
	float3 Normal : NORMAL;
#if 1 //always //TEXTURE || ALPHAMAP || USE_TANGENT
	float2 TexCoord : TEXCOORD0;
#if MULTIUV >= 1
	float2 TexCoord1 : TEXCOORD1;
#endif
#if MULTIUV >= 2
	float2 TexCoord2 : TEXCOORD2;
#endif
#if MULTIUV >= 3
	float2 TexCoord3 : TEXCOORD3;
#endif
#endif
#if VERTEXCOLOR
	float4 Col : COLOR0;
#endif
#if USE_TANGENT
	float4 Tangent : TANGENT;
#endif
};

struct VS_OUTPUT
{
	float4 Pos : SV_POSITION;
	float4 Col : COLOR;
	float3 Normal : NORMAL;
	float2 TexCoord : TEXCOORD0;
#if MULTIUV >= 1
	float2 TexCoord1 : TEXCOORD1;
#endif
#if MULTIUV >= 2
	float2 TexCoord2 : TEXCOORD2;
#endif
#if MULTIUV >= 3
	float2 TexCoord3 : TEXCOORD3;
#endif
#if USE_TANGENT
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
#endif
	float4 WorldPos : TEXCOORD4;
#if SHADOW
	float4 SMPos : TEXCOORD5;
#endif
};

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 Col : COLOR;
	float3 Normal : NORMAL;
	float2 TexCoord : TEXCOORD0;
#if MULTIUV >= 1
	float2 TexCoord1 : TEXCOORD1;
#endif
#if MULTIUV >= 2
	float2 TexCoord2 : TEXCOORD2;
#endif
#if MULTIUV >= 3
	float2 TexCoord3 : TEXCOORD3;
#endif
#if USE_TANGENT
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
#endif
	float4 WorldPos : TEXCOORD4;
#if SHADOW
	float4 SMPos : TEXCOORD5;
#endif
	bool IsBack : SV_IsFrontFace; // Why inverted?
#if MSAA
    uint Coverage : SV_COVERAGE;
#endif
};

struct PS_OUTPUT
{
	float4 Color    : SV_Target0;
#if RENDER_NORMAL
	float4 Normal   : SV_Target1;
#endif
};

#include "oit_store.inc"


float2 TransformUV(float2 uv, float4 transform, float4 translate)
{
	float2x2 tm = {transform.x, transform.y, transform.z, transform.w};
	return mul(uv, tm) + float2(translate.x, translate.y);
}

// Vertex shader
VS_OUTPUT VS(const VS_INPUT In)
{
	VS_OUTPUT Out;
	Out.Pos = mul(In.Pos, WorldViewProj);
	Out.Col = BaseColor;
#if VERTEXCOLOR
	Out.Col *= In.Col;
#endif
	Out.Normal = In.Normal;
	Out.TexCoord = TransformUV(In.TexCoord, MapTransform, MapTranslate);
#if MULTIUV >= 1
	Out.TexCoord1 = TransformUV(In.TexCoord1, MapTransform, MapTranslate);
#endif
#if MULTIUV >= 2
	Out.TexCoord2 = TransformUV(In.TexCoord2, MapTransform, MapTranslate);
#endif
#if MULTIUV >= 3
	Out.TexCoord3 = TransformUV(In.TexCoord3, MapTransform, MapTranslate);
#endif
#if USE_TANGENT
	if(length(In.Tangent.xyz) > 0){
		Out.Tangent = In.Tangent.xyz;
		Out.Binormal = normalize(cross(In.Tangent.xyz, In.Normal)) * In.Tangent.w;
	}else{
		if(abs(dot(In.Normal,float3(0,1,0))) < abs(dot(In.Normal,float3(0,0,1))))
			Out.Tangent = normalize(cross(float3(0,1,0),In.Normal));
		else
			Out.Tangent = normalize(cross(float3(0,0,1),In.Normal));
		Out.Binormal = normalize(cross(Out.Tangent, In.Normal));
	}
#endif
	Out.WorldPos = In.Pos;
#if SHADOW
	Out.SMPos = mul(In.Pos, ShadowMapProj);
#endif
	return Out;
}


float4 GetOutlinePos(VS_OUTPUT input)
{
	float width = OutlineWidthFactor;
	//if(HasOutlineWidthMultiplyMap)
	//	width *= OutlineWidthMultiplyMap.Sample(ColorMapSampler, GetTexCoord(input,HasOutlineWidthMultiplyMap)).g; // GS not support sample.
	if(OutlineWidthMode == 2){
		if(input.Pos.z <= 0){
			return input.Pos;
		}else{
			float4 axisX = float4(WorldView[0][0], WorldView[1][0], WorldView[2][0], 0);
			float4 pos = mul(input.WorldPos + axisX, WorldViewProj);
			float2 p1 = pos.xy / pos.w;
			float2 p0 = input.Pos.xy / input.Pos.w;
			float w = 1.0 / Resolution.x * (Resolution.y / 1000.0) * 2;
			float scale = width * w / length(p1 - p0);
			return mul(input.WorldPos + float4(input.Normal,0) * scale, WorldViewProj);
		}
	}else{
		return mul(input.WorldPos + float4(input.Normal,0) * width, WorldViewProj);
	}
}

// Geometry shader
[maxvertexcount(6)]
void GS(triangle VS_OUTPUT input[3], inout TriangleStream<VS_OUTPUT> stream)
{
	VS_OUTPUT output;
	output.Pos = input[0].Pos;
	output.Col = input[0].Col;
	output.Normal = input[0].Normal;
	output.TexCoord = input[0].TexCoord;
#if MULTIUV >= 1
	output.TexCoord1 = input[0].TexCoord1;
#endif
#if MULTIUV >= 2
	output.TexCoord2 = input[0].TexCoord2;
#endif
#if MULTIUV >= 3
	output.TexCoord3 = input[0].TexCoord3;
#endif
#if USE_TANGENT
	output.Tangent = input[0].Tangent;
	output.Binormal = input[0].Binormal;
#endif
	output.WorldPos = float4(input[0].WorldPos.xyz, 1);
#if SHADOW
	output.SMPos = input[0].SMPos;
#endif
	stream.Append(output);

	output.Pos = input[1].Pos;
	output.Col = input[1].Col;
	output.Normal = input[1].Normal;
	output.TexCoord = input[1].TexCoord;
#if MULTIUV >= 1
	output.TexCoord1 = input[1].TexCoord1;
#endif
#if MULTIUV >= 2
	output.TexCoord2 = input[1].TexCoord2;
#endif
#if MULTIUV >= 3
	output.TexCoord3 = input[1].TexCoord3;
#endif
#if USE_TANGENT
	output.Tangent = input[1].Tangent;
	output.Binormal = input[1].Binormal;
#endif
	output.WorldPos = float4(input[1].WorldPos.xyz, 1);
#if SHADOW
	output.SMPos = input[1].SMPos;
#endif
	stream.Append(output);

	output.Pos = input[2].Pos;
	output.Col = input[2].Col;
	output.Normal = input[2].Normal;
	output.TexCoord = input[2].TexCoord;
#if MULTIUV >= 1
	output.TexCoord1 = input[2].TexCoord1;
#endif
#if MULTIUV >= 2
	output.TexCoord2 = input[2].TexCoord2;
#endif
#if MULTIUV >= 3
	output.TexCoord3 = input[2].TexCoord3;
#endif
#if USE_TANGENT
	output.Tangent = input[2].Tangent;
	output.Binormal = input[2].Binormal;
#endif
	output.WorldPos = float4(input[2].WorldPos.xyz, 1);
#if SHADOW
	output.SMPos = input[2].SMPos;
#endif
	stream.Append(output);

	stream.RestartStrip();
	
	if(OutlineWidthMode != 0 && OutlineWidthFactor > 0){
		output.Pos = GetOutlinePos(input[0]);
		output.Col = input[0].Col;
		output.Normal = input[0].Normal;
		output.TexCoord = input[0].TexCoord;
#if MULTIUV >= 1
		output.TexCoord1 = input[0].TexCoord1;
#endif
#if MULTIUV >= 2
		output.TexCoord2 = input[0].TexCoord2;
#endif
#if MULTIUV >= 3
		output.TexCoord3 = input[0].TexCoord3;
#endif
#if USE_TANGENT
		output.Tangent = input[0].Tangent;
		output.Binormal = input[0].Binormal;
#endif
		output.WorldPos = float4(input[0].WorldPos.xyz, 0);
#if SHADOW
		output.SMPos = input[0].SMPos;
#endif
		stream.Append(output);

		output.Pos = GetOutlinePos(input[1]);
		output.Col = input[1].Col;
		output.Normal = input[1].Normal;
		output.TexCoord = input[1].TexCoord;
#if MULTIUV >= 1
		output.TexCoord1 = input[1].TexCoord1;
#endif
#if MULTIUV >= 2
		output.TexCoord2 = input[1].TexCoord2;
#endif
#if MULTIUV >= 3
		output.TexCoord3 = input[1].TexCoord3;
#endif
#if USE_TANGENT
		output.Tangent = input[1].Tangent;
		output.Binormal = input[1].Binormal;
#endif
		output.WorldPos = float4(input[1].WorldPos.xyz, 0);
#if SHADOW
		output.SMPos = input[1].SMPos;
#endif
		stream.Append(output);

		output.Pos = GetOutlinePos(input[2]);
		output.Col = input[2].Col;
		output.Normal = input[2].Normal;
		output.TexCoord = input[2].TexCoord;
#if MULTIUV >= 1
		output.TexCoord1 = input[2].TexCoord1;
#endif
#if MULTIUV >= 2
		output.TexCoord2 = input[2].TexCoord2;
#endif
#if MULTIUV >= 3
		output.TexCoord3 = input[2].TexCoord3;
#endif
#if USE_TANGENT
		output.Tangent = input[2].Tangent;
		output.Binormal = input[2].Binormal;
#endif
		output.WorldPos = float4(input[2].WorldPos.xyz, 0);
#if SHADOW
		output.SMPos = input[2].SMPos;
#endif
		stream.Append(output);

		stream.RestartStrip();
	}
}

// Geometry shader
//   Convert LineAdjacent (with 4 vertices) to TriangleStrip(with 3 or 4 vertices).
[maxvertexcount(8)]
void GSpatch(lineadj VS_OUTPUT input[4], inout TriangleStream<VS_OUTPUT> stream)
{
	VS_OUTPUT output;

	output.Pos = input[1].Pos;
	output.Col = input[1].Col;
	output.Normal = input[1].Normal;
	output.TexCoord = input[1].TexCoord;
#if MULTIUV >= 1
	output.TexCoord1 = input[1].TexCoord1;
#endif
#if MULTIUV >= 2
	output.TexCoord2 = input[1].TexCoord2;
#endif
#if MULTIUV >= 3
	output.TexCoord3 = input[1].TexCoord3;
#endif
#if USE_TANGENT
	output.Tangent = input[1].Tangent;
	output.Binormal = input[1].Binormal;
#endif
	output.WorldPos = float4(input[1].WorldPos.xyz, 1);
#if SHADOW
	output.SMPos = input[1].SMPos;
#endif
	stream.Append(output);

	output.Pos = input[0].Pos;
	output.Col = input[0].Col;
	output.Normal = input[0].Normal;
	output.TexCoord = input[0].TexCoord;
#if MULTIUV >= 1
	output.TexCoord1 = input[0].TexCoord1;
#endif
#if MULTIUV >= 2
	output.TexCoord2 = input[0].TexCoord2;
#endif
#if MULTIUV >= 3
	output.TexCoord3 = input[0].TexCoord3;
#endif
#if USE_TANGENT
	output.Tangent = input[0].Tangent;
	output.Binormal = input[0].Binormal;
#endif
	output.WorldPos = float4(input[0].WorldPos.xyz, 1);
#if SHADOW
	output.SMPos = input[0].SMPos;
#endif
	stream.Append(output);

	output.Pos = input[2].Pos;
	output.Col = input[2].Col;
	output.Normal = input[2].Normal;
	output.TexCoord = input[2].TexCoord;
#if MULTIUV >= 1
	output.TexCoord1 = input[2].TexCoord1;
#endif
#if MULTIUV >= 2
	output.TexCoord2 = input[2].TexCoord2;
#endif
#if MULTIUV >= 3
	output.TexCoord3 = input[2].TexCoord3;
#endif
#if USE_TANGENT
	output.Tangent = input[2].Tangent;
	output.Binormal = input[2].Binormal;
#endif
	output.WorldPos = float4(input[2].WorldPos.xyz, 1);
#if SHADOW
	output.SMPos = input[2].SMPos;
#endif
	stream.Append(output);

	if(length(input[3].Normal) > 0.0){
		output.Pos = input[3].Pos;
		output.Col = input[3].Col;
		output.Normal = input[3].Normal;
		output.TexCoord = input[3].TexCoord;
#if MULTIUV >= 1
		output.TexCoord1 = input[3].TexCoord1;
#endif
#if MULTIUV >= 2
		output.TexCoord2 = input[3].TexCoord2;
#endif
#if MULTIUV >= 3
		output.TexCoord3 = input[3].TexCoord3;
#endif
#if USE_TANGENT
		output.Tangent = input[3].Tangent;
		output.Binormal = input[3].Binormal;
#endif
		output.WorldPos = float4(input[3].WorldPos.xyz, 1);
#if SHADOW
		output.SMPos = input[3].SMPos;
#endif
		stream.Append(output);
	}

	stream.RestartStrip();
	
	if(OutlineWidthMode != 0 && OutlineWidthFactor > 0){
		if(length(input[3].Normal) > 0.0){
			output.Pos = GetOutlinePos(input[3]);
			output.Col = input[3].Col;
			output.Normal = input[3].Normal;
			output.TexCoord = input[3].TexCoord;
#if MULTIUV >= 1
			output.TexCoord1 = input[3].TexCoord1;
#endif
#if MULTIUV >= 2
			output.TexCoord2 = input[3].TexCoord2;
#endif
#if MULTIUV >= 3
			output.TexCoord3 = input[3].TexCoord3;
#endif
#if USE_TANGENT
			output.Tangent = input[3].Tangent;
			output.Binormal = input[3].Binormal;
#endif
			output.WorldPos = float4(input[3].WorldPos.xyz, 0);
#if SHADOW
			output.SMPos = input[3].SMPos;
#endif
			stream.Append(output);
		}

		output.Pos = GetOutlinePos(input[2]);
		output.Col = input[2].Col;
		output.Normal = input[2].Normal;
		output.TexCoord = input[2].TexCoord;
#if MULTIUV >= 1
		output.TexCoord1 = input[2].TexCoord1;
#endif
#if MULTIUV >= 2
		output.TexCoord2 = input[2].TexCoord2;
#endif
#if MULTIUV >= 3
		output.TexCoord3 = input[2].TexCoord3;
#endif
#if USE_TANGENT
		output.Tangent = input[2].Tangent;
		output.Binormal = input[2].Binormal;
#endif
		output.WorldPos = float4(input[2].WorldPos.xyz, 0);
#if SHADOW
		output.SMPos = input[2].SMPos;
#endif
		stream.Append(output);

		output.Pos = GetOutlinePos(input[0]);
		output.Col = input[0].Col;
		output.Normal = input[0].Normal;
		output.TexCoord = input[0].TexCoord;
#if MULTIUV >= 1
		output.TexCoord1 = input[0].TexCoord1;
#endif
#if MULTIUV >= 2
		output.TexCoord2 = input[0].TexCoord2;
#endif
#if MULTIUV >= 3
		output.TexCoord3 = input[0].TexCoord3;
#endif
#if USE_TANGENT
		output.Tangent = input[0].Tangent;
		output.Binormal = input[0].Binormal;
#endif
		output.WorldPos = float4(input[0].WorldPos.xyz, 0);
#if SHADOW
		output.SMPos = input[0].SMPos;
#endif
		stream.Append(output);

		output.Pos = GetOutlinePos(input[1]);
		output.Col = input[1].Col;
		output.Normal = input[1].Normal;
		output.TexCoord = input[1].TexCoord;
#if MULTIUV >= 1
		output.TexCoord1 = input[1].TexCoord1;
#endif
#if MULTIUV >= 2
		output.TexCoord2 = input[1].TexCoord2;
#endif
#if MULTIUV >= 3
		output.TexCoord3 = input[1].TexCoord3;
#endif
#if USE_TANGENT
		output.Tangent = input[1].Tangent;
		output.Binormal = input[1].Binormal;
#endif
		output.WorldPos = float4(input[1].WorldPos.xyz, 0);
#if SHADOW
		output.SMPos = input[1].SMPos;
#endif
		stream.Append(output);

		stream.RestartStrip();
	}
}

float2 GetTexCoord(PS_INPUT In, int channel)
{
#if MULTIUV >= 1
	if((channel & 0x30) == 0x10) return In.TexCoord1;
#endif
#if MULTIUV >= 2
	if((channel & 0x30) == 0x20) return In.TexCoord2;
#endif
#if MULTIUV >= 3
	if((channel & 0x30) == 0x30) return In.TexCoord3;
#endif
	return In.TexCoord;
}

float linearstep(float a, float b, float t)
{
	return saturate( ( t - a ) / ( b - a ) );
}

float GetShadow(PS_INPUT In)
{
#if SHADOW
	float2 smt = float2((In.SMPos.x+1)*0.5, 1.0-(In.SMPos.y+1)*0.5);
	float smz = ShadowMap.Sample(ShadowMapSampler, smt.xy).r;
	float sm_coef = (In.SMPos.z < smz+0.005) ? 1.0 : 0.5;
	return sm_coef;
#else
	return 1.0;
#endif
}

float4 ColorCorrect(float4 col, int type)
{
	if(ColorSpace != 0) // VRM 1.0
		return SRGBtoLINEAR(col, (type&3) == 1);
	else // VRM 0.x
		return LINEARtoSRGB(col, (type&3) == 2);
}

float4 GetBaseColor(PS_INPUT In)
{
	float4 col = In.Col;
#if TEXTURE
	col *= ColorCorrect(ColorMap.Sample(ColorMapSampler, GetTexCoord(In,HasTextureMap)), HasTextureMap);
#endif
	//col.a *= Alpha;

	// Cancel to write if the color is almost transparent.
	if(AlphaMode < 2)
		col.a = 1;
	else if(AlphaMode == 2){
		clip(col.a - AlphaCutOff);
		col.a = 1;
	}else
		clip(col.a - 1.0/255.0);
	return col;
}

// Pixel shader
#if OIT
[earlydepthstencil]
#endif
PS_OUTPUT PS(PS_INPUT In)
{
	PS_OUTPUT output;
	
	if(IsArbClipped(In.WorldPos.xyz))
		discard;

	if(In.WorldPos.w == 0 && !In.IsBack)
		discard;
	
	float3 V = normalize(CameraPos - In.WorldPos.xyz);
	float4 base_color = GetBaseColor(In);
	float shadow = GetShadow(In);
	
#if NORMALMAP
	float3 normal_col = NormalMap.Sample(NormalMapSampler, GetTexCoord(In,HasBumpMap)).xyz * 2.0 - 1.0;
	normal_col *= float3(NormalScale, NormalScale, 1.0);
	normal_col *= NormalMapFlip;

	float3x3 mtxn = {In.Tangent, In.Binormal, In.Normal};
	float3 N = normalize(mul(normal_col, mtxn));
#else
	float3 N = normalize(In.Normal);
#endif
	if(In.IsBack && In.WorldPos.w != 0){
		if(BackFaceColor.w == 0 && DoubleSided == 0)
			discard;
		N = -N;
		base_color.xyz *= BackFaceColor.xyz;
	}
	
	float3 color = float3(0,0,0);
#if MULTILIGHT
	for(int i=0; i<1/*LIGHT_MAX*/ && i<LightNum; i++)
#endif
	{
#if MULTILIGHT
		float3 L;
		if(LightPos[i].w == 0){
			L = normalize(LightPos[i].xyz - In.WorldPos.xyz); // point light
		}else{
			L = LightPos[i].xyz; // directional light
		}
		float3 litcol = LightCol[i];
#else
		float3 L = LightDir;
		float3 litcol = float3(1,1,1);
#endif

		float shading = dot(N, L);
		shading += ShadingShiftFactor;
		if(HasShadingShiftMap)
			shading += ColorCorrect(ShadingShiftMap.Sample(ColorMapSampler, GetTexCoord(In,HasShadingShiftMap)), HasShadingShiftMap).r * ShadingShiftScale;
		shading = linearstep(-1.0 + ShadingToonyFactor, 1.0 - ShadingToonyFactor, shading);

		float3 shadeColorTerm = ShadeColorFactor.xyz;
		if(HasShadeMultiplyMap)
			shadeColorTerm *= ColorCorrect(ShadeMultiplyMap.Sample(ColorMapSampler, GetTexCoord(In,HasShadeMultiplyMap)), HasShadeMultiplyMap).xyz;

		color = lerp(shadeColorTerm, base_color.xyz, shading);
		color = color * litcol;
		
		// Rim lighting
		{
			float3 rim = float3(0,0,0);
			if(HasMatcapMap){
				float3 x = normalize( float3( V.z, 0.0, -V.x ) );
				float3 y = -cross( V, x );
				float2 matcapUv = float2( dot( x, N ), dot( y, N ) ) * 0.495 + 0.5;
				rim = MatcapFactor.xyz * ColorCorrect(MatcapMap.Sample(ColorMapSampler, matcapUv), HasMatcapMap).xyz;
			}

			float epsilon = 0.00001;
			float parametricRim = saturate( 1.0 - dot( N, V ) + ParametricRimLiftFactor );
			parametricRim = pow( parametricRim, max( ParametricRimFresnelPowerFactor, epsilon ) );
			rim += parametricRim * ParametricRimColorFactor.xyz;

			if(HasRimMultiplyMap)
				rim *= ColorCorrect(RimMultiplyMap.Sample(ColorMapSampler, GetTexCoord(In,HasRimMultiplyMap)), HasRimMultiplyMap).xyz;

			rim *= lerp( float3(1,1,1), litcol, RimLightingMixFactor);

			// color already has the direct lighting factor + global illumination factor
			color += rim;
		}
	}
	
	float3 emissive = Emissive.xyz;
	if(HasEmissiveMap)
		emissive *= ColorCorrect(EmissiveMap.Sample(ColorMapSampler, GetTexCoord(In,HasEmissiveMap)), HasEmissiveMap).xyz;
	color += emissive;
	if(In.WorldPos.w == 0 && OutlineWidthMode != 0){
		float3 outline = OutlineColorFactor.xyz;
		color.xyz = lerp(outline, color.xyz, OutlineLightingMixFactor);
	}
	color = LINEARtoSRGB(color, ColorSpace != 0);
	output.Color.xyz = saturate(color);
	output.Color.w = base_color.w;

#if OIT
    StoreOIT(In, output.Color);
    output.Color = float4(0,0,0,0);	// This does not affect anything because RenderTargetWriteMask is 0.
#endif

#if RENDER_NORMAL
	output.Normal = float4(mul(In.Normal.xyz, (float3x3)WorldView), 1);
#endif

	return output;
}

