
// zlib open source license
//
// Copyright (c) 2010 to 2013 David Forsgren Piuva
// 
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// 
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 
//    1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
// 
//    2. Altered source versions must be plainly marked as such, and must not be
//    misrepresented as being the original software.
// 
//    3. This notice may not be removed or altered from any source
//    distribution.

struct PrecompiledShaderHeaderType {
	char filetype[4]; // "DPS1"
	UINT64 checksum;
	unsigned long size; // The content's length in bytes stored in the ByteArray object
};

static char* CommonPostEffectVertexShader = \
	"VS_to_PS VS( VS_structure input ) {\n" \
	"	VS_to_PS output = (VS_to_PS)0;\n" \
	"	output.Pos = input.Pos;\n" \
	"	return output;\n" \
	"}\n";

static char* CommonDrawVertexShader = \
	"VS_to_PS VS( VS_structure input ) {\n" \
	"	VS_to_PS output = (VS_to_PS)0;\n" \
	"	output.Pos = float4((XAxis * input.Pos.x) + (YAxis * input.Pos.y) + Center,0.5f,1.0f);\n" \
	"	output.Pos_ObjectSpace = input.Pos.xy;\n" \
	"	output.Tex.xy = lerp(SrcRectUV1.xz,SrcRectUV1.yw,(input.Pos.xy + 1.0f) * 0.5f);\n" \
	"	output.Tex.zw = lerp(SrcRectUV2.xz,SrcRectUV2.yw,(input.Pos.xy + 1.0f) * 0.5f);\n" \
	"	return output;\n" \
	"}\n";

static char* ShaderHeaders[NumberOfShaderTypes] = {
	"Texture2D tex_0 : register( t0 );\n" \
	"Texture2D tex_1 : register( t1 );\n" \
	"Texture2D tex_2 : register( t2 );\n" \
	"Texture2D tex_3 : register( t3 );\n" \
	"Texture2D tex_4 : register( t4 );\n" \
	"Texture2D tex_5 : register( t5 );\n" \
	"Texture2D tex_6 : register( t6 );\n" \
	"Texture2D tex_7 : register( t7 );\n" \
	"Texture2D tex_8 : register( t8 );\n" \
	"Texture2D tex_9 : register( t9 );\n" \
	"Texture2D tex_10 : register( t10 );\n" \
	"Texture2D tex_11 : register( t11 );\n" \
	"Texture2D tex_12 : register( t12 );\n" \
	"Texture2D tex_13 : register( t13 );\n" \
	"Texture2D tex_14 : register( t14 );\n" \
	"Texture2D tex_15 : register( t15 );\n" \
	"Texture2D tex_lightAtlas : register( t16 );\n" \
	"Texture2D tex_depthAtlas : register( t17 );\n" \
	"Texture2D tex_depthBufferCopy : register( t18 );\n" \
	"SamplerState samConstant : register( s0 );\n" \
	"SamplerState samSharp : register( s1 );\n" \
	"SamplerState samClampedConstant : register( s2 );\n" \
	"SamplerState samClampedSharp : register( s3 );\n" \
	"SamplerState samAnisotropicMipmap : register( s4 );\n" \
	"SamplerState samMipmap : register( s5 );\n" \
	"SamplerComparisonState samShadow : register( s6 );\n" \
	"#define OutsideIntensity ZWCorrection.x\n" \
	"#define FadeSize ZWCorrection.y\n" \
	"#define MaxNumberOfLights 64\n" \
	"struct LightSource {\n" \
	"	int Type; float3 Pos;\n" \
	"	float Radius; float3 Color;\n" \
	"	float3 XAxis; float WidthSlope;\n" \
	"	float3 YAxis; float HeightSlope;\n" \
	"	float3 ZAxis; float NearClip;\n" \
	"	float4 TextureAtlasRect;\n" \
	"	float4 DepthAtlasRect;\n" \
	"	float2 ZWCorrection; float ShadowOffset; float ShadowTransparency;\n" \
	"};\n" \
	"cbuffer cbEveryRender : register( b0 ) {\n" \
	"	float4x4 WorldToCamera_NoRefraction;\n" \
	"	float4x4 WorldToCamera;\n" \
	"	float4x4 CameraToImage;\n" \
	"	float4x4 WorldToImage;\n" \
	"	float3 CameraPos_WorldSpace; float EnableCuttingPlane;\n" \
	"	float4 CuttingPlane;\n" \
	"	float4 FogColor;\n" \
	"	float4 SceneSettingsA;\n" \
	"	float3 AmbientLight; int NumberOfLights;\n" \
	"	LightSource Lights[MaxNumberOfLights];\n" \
	"	float2 Dimensions; float GlobalTime; float Padding_EveryRender;\n" \
	"};\n" \
	"cbuffer cbEveryObject : register( b1 ) {\n" \
	"	float4x4 ObjectToWorld;\n" \
	"	float4 InstanceColor;\n" \
	"	int BoneBuffer; float DetailLevel; float2 Padding_EveryObject;\n" \
	"};\n" \
	"struct SingleBone {\n" \
	"	float4 Start;\n" \
	"	float4 YAxis;\n" \
	"	float4 ZAxis;\n" \
	"};\n" \
	"cbuffer cbBoneBuffer_8 : register( b2 ) {\n" \
	"	SingleBone Bone_8[8];\n" \
	"};\n" \
	"cbuffer cbBoneBuffer_16 : register( b3 ) {\n" \
	"	SingleBone Bone_16[16];\n" \
	"};\n" \
	"cbuffer cbBoneBuffer_32 : register( b4 ) {\n" \
	"	SingleBone Bone_32[32];\n" \
	"};\n" \
	"cbuffer cbBoneBuffer_64 : register( b5 ) {\n" \
	"	SingleBone Bone_64[64];\n" \
	"};\n" \
	"cbuffer cbArgBuffer : register( b6 ) {\n" \
	"	float4 Arg[16];\n" \
	"};\n" \
	"struct VS_structure {\n" \
	"	float4 Pos : POSITION;\n" \
	"	float4 Tex : TEXCOORD;\n" \
	"	float4 Color : COLOR;\n" \
	"	float3 Normal : NORMAL;\n" \
	"	float Selected : PSIZE;\n" \
	"	float4 A : BINORMAL;\n" \
	"	float4 B : TANGENT;\n" \
	"	float4 BoneData : TEXTURE;\n" \
	"};\n" \
	"#define FogDistance SceneSettingsA.x\n" \
	"#define MaxFogIntensity SceneSettingsA.y\n" \
	"#define NearClipPlane SceneSettingsA.z\n" \
	"#define FarClipPlane SceneSettingsA.x\n" \
	"#define CameraXScale CameraToImage._11\n" \
	"#define CameraYScale CameraToImage._22\n" \
	"#define UseCuttingPlane(WORLD_SPACE_POS) if (EnableCuttingPlane > 0.5f) { clip(dot(WORLD_SPACE_POS.xyz,CuttingPlane.xyz) - CuttingPlane.w); }\n" \
	"void Engine_LightAux ( in float3 Pos_WorldSpace, in float3 Normal_WorldSpace, in float SpecularSharpness, in int Directed, out float3 SumOfDiffuseLight, out float3 SumOfSpecularLight ) {\n" \
	"	int i;\n" \
	"	float3 Direction;\n" \
	"	float Dist;\n" \
	"	float Intensity;\n" \
	"	float SpecularLevel;\n" \
	"	float3 ProjectedPos;\n" \
	"	float3 UndirectedLight;\n" \
	"	float3 ProjectionIntensity;\n" \
	"	float2 ConeProjection;\n" \
	"	float ConeDist;\n" \
	"	float2 UV;\n" \
	"	float LightSpaceDepth;\n" \
	"	float Lit;\n" \
	"	float Depth;\n" \
	"	float ShadowMultiplier;\n" \
	"	float3 ReflectedViewDirection;\n" \
	"	ReflectedViewDirection = reflect(normalize(Pos_WorldSpace - CameraPos_WorldSpace), Normal_WorldSpace);\n" \
	"	SumOfDiffuseLight = AmbientLight;\n" \
	"	SumOfSpecularLight = float3(0.0f, 0.0f, 0.0f);\n" \
	"	for(i = 0; i < NumberOfLights && i < MaxNumberOfLights; i++) {\n" \
	"		switch(Lights[i].Type) {\n" \
	"		case 0:\n" \
	"			Dist = length(Pos_WorldSpace - Lights[i].Pos);\n" \
	"			if (Dist < Lights[i].Radius) {\n" \
	"				Direction = normalize(Pos_WorldSpace - Lights[i].Pos);\n" \
	"				Intensity = pow(((Lights[i].Radius - Dist) / Lights[i].Radius), 2.0f);\n" \
	"				UndirectedLight = Lights[i].Color * Intensity;\n" \
	"				if (Directed) {\n" \
	"					SumOfDiffuseLight += saturate(-dot(Direction,Normal_WorldSpace)) * UndirectedLight;\n" \
	"					SpecularLevel = saturate(-dot(Direction,ReflectedViewDirection));\n" \
	"					SumOfSpecularLight += pow(SpecularLevel, SpecularSharpness) * UndirectedLight;\n" \
	"				} else {\n" \
	"					SumOfDiffuseLight += UndirectedLight;\n" \
	"					SumOfSpecularLight += 0;\n" \
	"				}\n" \
	"			}\n" \
	"		break;\n" \
	"		case 1:\n" \
	"			UndirectedLight = Lights[i].Color;\n" \
	"			if (Directed) {\n" \
	"				SumOfDiffuseLight += saturate(-dot(Lights[i].ZAxis,Normal_WorldSpace)) * UndirectedLight;\n" \
	"				SpecularLevel = saturate(-dot(Lights[i].ZAxis,ReflectedViewDirection));\n" \
	"				SumOfSpecularLight += pow(SpecularLevel, SpecularSharpness) * UndirectedLight;\n" \
	"			} else {\n" \
	"				SumOfDiffuseLight += UndirectedLight;\n" \
	"				SumOfSpecularLight += 0;\n" \
	"			}\n" \
	"		break;\n" \
	"		case 2:\n" \
	"			Dist = length(Pos_WorldSpace - Lights[i].Pos);\n" \
	"			if (Dist < Lights[i].Radius) {\n" \
	"				ProjectedPos = mul(Pos_WorldSpace - Lights[i].Pos, transpose(float3x3(Lights[i].XAxis,Lights[i].YAxis,Lights[i].ZAxis)));\n" \
	"				ConeProjection = float2(ProjectedPos.x / (ProjectedPos.z * Lights[i].WidthSlope),ProjectedPos.y / (ProjectedPos.z * Lights[i].HeightSlope));\n" \
	"				ConeDist = length(ConeProjection);\n" \
	"				if (ConeDist < 1.0f && ProjectedPos.z > 0.0f) {\n" \
	"					Direction = normalize(Pos_WorldSpace - Lights[i].Pos);\n" \
	"					Intensity = pow(((Lights[i].Radius - Dist) / Lights[i].Radius), 2.0f);\n" \
	"					ProjectionIntensity = 1.0f - pow(ConeDist,2.0f);\n" \
	"					UndirectedLight = Lights[i].Color * ProjectionIntensity * Intensity;\n" \
	"					if (Directed) {\n" \
	"						SumOfDiffuseLight += saturate(-dot(Direction,Normal_WorldSpace)) * UndirectedLight;\n" \
	"						SpecularLevel = saturate(-dot(Direction,ReflectedViewDirection));\n" \
	"						SumOfSpecularLight += pow(SpecularLevel, SpecularSharpness) * UndirectedLight;\n" \
	"					} else {\n" \
	"						SumOfDiffuseLight += UndirectedLight;\n" \
	"						SumOfSpecularLight += 0;\n" \
	"					}\n" \
	"				}\n" \
	"			}\n" \
	"		break;\n" \
	"		case 3:\n" \
	"			Dist = length(Pos_WorldSpace - Lights[i].Pos);\n" \
	"			if (Dist < Lights[i].Radius) {\n" \
	"				ProjectedPos = mul(Pos_WorldSpace - Lights[i].Pos, transpose(float3x3(Lights[i].XAxis,Lights[i].YAxis,Lights[i].ZAxis)));\n" \
	"				ConeProjection = float2(ProjectedPos.x / (ProjectedPos.z * Lights[i].WidthSlope),ProjectedPos.y / (ProjectedPos.z * Lights[i].HeightSlope));\n" \
	"				if (ConeProjection.x > -1.0f && ConeProjection.x < 1.0f && ConeProjection.y > -1.0f && ConeProjection.y < 1.0f && ProjectedPos.z > 0.0f) {\n" \
	"					Direction = normalize(Pos_WorldSpace - Lights[i].Pos);\n" \
	"					Intensity = pow(((Lights[i].Radius - Dist) / Lights[i].Radius), 2.0f);\n" \
	"					ProjectionIntensity = tex_lightAtlas.SampleLevel( samSharp, float2(lerp(Lights[i].TextureAtlasRect.x,Lights[i].TextureAtlasRect.y,(ConeProjection.x + 1.0f) / 2.0f),lerp(Lights[i].TextureAtlasRect.z,Lights[i].TextureAtlasRect.w,(-ConeProjection.y + 1.0f) / 2.0f) ), 0 ).xyz;\n" \
	"					UndirectedLight = Lights[i].Color * ProjectionIntensity * Intensity;\n" \
	"					if (Directed) {\n" \
	"						SumOfDiffuseLight += saturate(-dot(Direction,Normal_WorldSpace)) * UndirectedLight;\n" \
	"						SpecularLevel = saturate(-dot(Direction,ReflectedViewDirection));\n" \
	"						SumOfSpecularLight += pow(SpecularLevel, SpecularSharpness) * UndirectedLight;\n" \
	"					} else {\n" \
	"						SumOfDiffuseLight += UndirectedLight;\n" \
	"						SumOfSpecularLight += 0;\n" \
	"					}\n" \
	"				}\n" \
	"			}\n" \
	"		break;\n" \
	"		case 4:\n" \
	"			Dist = length(Pos_WorldSpace - Lights[i].Pos);\n" \
	"			if (Dist < Lights[i].Radius) {\n" \
	"				ProjectedPos = mul(Pos_WorldSpace - Lights[i].Pos, transpose(float3x3(Lights[i].XAxis,Lights[i].YAxis,Lights[i].ZAxis)));\n" \
	"				ConeProjection = float2(ProjectedPos.x / (ProjectedPos.z * Lights[i].WidthSlope),ProjectedPos.y / (ProjectedPos.z * Lights[i].HeightSlope));\n" \
	"				ConeDist = length(ConeProjection);\n" \
	"				if (ConeDist < 1.0f && ProjectedPos.z > 0.0f) {\n" \
	"					UV = float2(lerp(Lights[i].DepthAtlasRect.x,Lights[i].DepthAtlasRect.y,(ConeProjection.x + 1.0f) / 2.0f),lerp(Lights[i].DepthAtlasRect.z,Lights[i].DepthAtlasRect.w,(-ConeProjection.y + 1.0f) / 2.0f));\n" \
	"					LightSpaceDepth = (Lights[i].ZWCorrection.y / (ProjectedPos.z * (1 - Lights[i].ShadowOffset))) + Lights[i].ZWCorrection.x;\n" \
	"					if ( LightSpaceDepth < tex_depthAtlas.SampleLevel( samSharp, UV, 0 ).x ) {\n" \
	"						ShadowMultiplier = 1.0f;\n" \
	"					} else {\n" \
	"						Lit = tex_depthAtlas.SampleCmpLevelZero( samShadow, UV, LightSpaceDepth);\n" \
	"						ShadowMultiplier = lerp(Lights[i].ShadowTransparency,1.0f,Lit);\n" \
	"					}\n" \
	"					Direction = normalize(Pos_WorldSpace - Lights[i].Pos);\n" \
	"					Intensity = pow(((Lights[i].Radius - Dist) / Lights[i].Radius), 2.0f);\n" \
	"					ProjectionIntensity = 1.0f - pow(ConeDist,2.0f);\n" \
	"					UndirectedLight = Lights[i].Color * ProjectionIntensity * Intensity * ShadowMultiplier;\n" \
	"					if (Directed) {\n" \
	"						SumOfDiffuseLight += saturate(-dot(Direction,Normal_WorldSpace)) * UndirectedLight;\n" \
	"						SpecularLevel = saturate(-dot(Direction,ReflectedViewDirection));\n" \
	"						SumOfSpecularLight += pow(SpecularLevel, SpecularSharpness) * UndirectedLight;\n" \
	"					} else {\n" \
	"						SumOfDiffuseLight += UndirectedLight;\n" \
	"						SumOfSpecularLight += 0;\n" \
	"					}\n" \
	"				}\n" \
	"			}\n" \
	"		break;\n" \
	"		case 5:\n" \
	"			Dist = length(Pos_WorldSpace - Lights[i].Pos);\n" \
	"			if (Dist < Lights[i].Radius) {\n" \
	"				ProjectedPos = mul(Pos_WorldSpace - Lights[i].Pos, transpose(float3x3(Lights[i].XAxis,Lights[i].YAxis,Lights[i].ZAxis)));\n" \
	"				ConeProjection = float2(ProjectedPos.x / (ProjectedPos.z * Lights[i].WidthSlope),ProjectedPos.y / (ProjectedPos.z * Lights[i].HeightSlope));\n" \
	"				if (ConeProjection.x > -1.0f && ConeProjection.x < 1.0f && ConeProjection.y > -1.0f && ConeProjection.y < 1.0f && ProjectedPos.z > 0.0f) {\n" \
	"					UV = float2(lerp(Lights[i].DepthAtlasRect.x,Lights[i].DepthAtlasRect.y,(ConeProjection.x + 1.0f) / 2.0f),lerp(Lights[i].DepthAtlasRect.z,Lights[i].DepthAtlasRect.w,(-ConeProjection.y + 1.0f) / 2.0f));\n" \
	"					LightSpaceDepth = (Lights[i].ZWCorrection.y / (ProjectedPos.z * (1 - Lights[i].ShadowOffset))) + Lights[i].ZWCorrection.x;\n" \
	"					if ( LightSpaceDepth < tex_depthAtlas.SampleLevel( samSharp, UV, 0 ).x ) {\n" \
	"						ShadowMultiplier = 1.0f;\n" \
	"					} else {\n" \
	"						Lit = tex_depthAtlas.SampleCmpLevelZero( samShadow, UV, LightSpaceDepth);\n" \
	"						ShadowMultiplier = lerp(Lights[i].ShadowTransparency,1.0f,Lit);\n" \
	"					}\n" \
	"					Direction = normalize(Pos_WorldSpace - Lights[i].Pos);\n" \
	"					Intensity = pow(((Lights[i].Radius - Dist) / Lights[i].Radius), 2.0f);\n" \
	"					ProjectionIntensity = tex_lightAtlas.SampleLevel( samSharp, float2(lerp(Lights[i].TextureAtlasRect.x,Lights[i].TextureAtlasRect.y,(ConeProjection.x + 1.0f) / 2.0f),lerp(Lights[i].TextureAtlasRect.z,Lights[i].TextureAtlasRect.w,(-ConeProjection.y + 1.0f) / 2.0f) ), 0 ).xyz;\n" \
	"					UndirectedLight = Lights[i].Color * ProjectionIntensity * Intensity * ShadowMultiplier;\n" \
	"					if (Directed) {\n" \
	"						SumOfDiffuseLight += saturate(-dot(Direction,Normal_WorldSpace)) * UndirectedLight;\n" \
	"						SpecularLevel = saturate(-dot(Direction,ReflectedViewDirection));\n" \
	"						SumOfSpecularLight += pow(SpecularLevel, SpecularSharpness) * UndirectedLight;\n" \
	"					} else {\n" \
	"						SumOfDiffuseLight += UndirectedLight;\n" \
	"						SumOfSpecularLight += 0;\n" \
	"					}\n" \
	"				}\n" \
	"			}\n" \
	"		break;\n" \
	"		case 6:\n" \
	"			ProjectedPos = mul(Pos_WorldSpace - Lights[i].Pos, transpose(float3x3(Lights[i].XAxis,Lights[i].YAxis,Lights[i].ZAxis)));\n" \
	"			ConeProjection = float2(ProjectedPos.x / Lights[i].WidthSlope,ProjectedPos.y / Lights[i].HeightSlope);\n" \
	"			ConeDist = max(abs(ConeProjection.x),abs(ConeProjection.y));\n" \
	"			if (ConeDist < 1.0f) {\n" \
	"				UV = float2(lerp(Lights[i].DepthAtlasRect.x,Lights[i].DepthAtlasRect.y,(ConeProjection.x + 1.0f) / 2.0f),lerp(Lights[i].DepthAtlasRect.z,Lights[i].DepthAtlasRect.w,(-ConeProjection.y + 1.0f) / 2.0f));\n" \
	"				LightSpaceDepth = ((ProjectedPos.z - Lights[i].ShadowOffset) - Lights[i].NearClip) / (Lights[i].Radius - Lights[i].NearClip);\n" \
	"				if (LightSpaceDepth < 0.0f || LightSpaceDepth > 1.0f) {\n" \
	"					ShadowMultiplier = Lights[i].OutsideIntensity;\n" \
	"				} else {\n" \
	"					if ( LightSpaceDepth < tex_depthAtlas.SampleLevel( samSharp, UV, 0 ).x ) {\n" \
	"						ShadowMultiplier = 1.0f;\n" \
	"					} else {\n" \
	"						Lit = tex_depthAtlas.SampleCmpLevelZero( samShadow, UV, LightSpaceDepth);\n" \
	"						ShadowMultiplier = lerp(Lights[i].ShadowTransparency,1.0f,Lit);\n" \
	"					}\n" \
	"				}\n" \
	"			} else {\n" \
	"				ShadowMultiplier = 1.0f;\n" \
	"			}\n" \
	"			ProjectionIntensity = saturate((1.0f - ConeDist) / Lights[i].FadeSize);\n" \
	"			UndirectedLight = Lights[i].Color * lerp(Lights[i].OutsideIntensity,ShadowMultiplier,ProjectionIntensity);\n" \
	"			if (Directed) {\n" \
	"				SumOfDiffuseLight += saturate(-dot(Lights[i].ZAxis,Normal_WorldSpace)) * UndirectedLight;\n" \
	"				SpecularLevel = saturate(-dot(Lights[i].ZAxis,ReflectedViewDirection));\n" \
	"				SumOfSpecularLight += pow(SpecularLevel, SpecularSharpness) * UndirectedLight;\n" \
	"			} else {\n" \
	"				SumOfDiffuseLight += UndirectedLight;\n" \
	"				SumOfSpecularLight += 0;\n" \
	"			}\n" \
	"		break;\n" \
	"		}\n" \
	"	}\n" \
	"}\n" \
	"void Engine_GetDiffuseAndSpecularLight ( in float3 Pos_WorldSpace, in float3 Normal_WorldSpace, in float SpecularSharpness, out float3 SumOfDiffuseLight, out float3 SumOfSpecularLight ) {\n" \
	"	Engine_LightAux(Pos_WorldSpace,Normal_WorldSpace,SpecularSharpness,true,SumOfDiffuseLight,SumOfSpecularLight);\n" \
	"}\n" \
	"void Engine_GetDiffuseLight ( in float3 Pos_WorldSpace, in float3 Normal_WorldSpace, out float3 SumOfDiffuseLight ) {\n" \
	"	float3 SpecularWaste;\n" \
	"	Engine_LightAux(Pos_WorldSpace,Normal_WorldSpace,10,true,SumOfDiffuseLight,SpecularWaste);\n" \
	"}\n" \
	"void Engine_GetUndirectedLight ( in float3 Pos_WorldSpace, out float3 SumOfDiffuseLight ) {\n" \
	"	float3 SpecularWaste;\n" \
	"	Engine_LightAux(Pos_WorldSpace,float3(0,0,0),10,false,SumOfDiffuseLight,SpecularWaste);\n" \
	"}\n" \
	"void Engine_GetBoneMatrix ( in int BoneIndex, out float4x4 BoneToObject ) {\n" \
	"	SingleBone Bone;\n" \
	"	switch(BoneBuffer) {\n" \
	"		case 0: Bone = Bone_8[BoneIndex]; break;\n" \
	"		case 1: Bone = Bone_16[BoneIndex]; break;\n" \
	"		case 2: Bone = Bone_32[BoneIndex]; break;\n" \
	"		default: Bone = Bone_64[BoneIndex]; break;\n" \
	"	}\n" \
	"	float3 YAxis = Bone.YAxis.xyz;\n" \
	"	float3 ZAxis = Bone.ZAxis.xyz;\n" \
	"	float3 XAxis = cross(YAxis,ZAxis);\n" \
	"	float3 Start = Bone.Start.xyz;\n" \
	"	BoneToObject._11 = XAxis.x; BoneToObject._12 = XAxis.y; BoneToObject._13 = XAxis.z; BoneToObject._14 = 0.0f;\n" \
	"	BoneToObject._21 = YAxis.x; BoneToObject._22 = YAxis.y; BoneToObject._23 = YAxis.z; BoneToObject._24 = 0.0f;\n" \
	"	BoneToObject._31 = ZAxis.x; BoneToObject._32 = ZAxis.y; BoneToObject._33 = ZAxis.z; BoneToObject._34 = 0.0f;\n" \
	"	BoneToObject._41 = Start.x; BoneToObject._42 = Start.y; BoneToObject._43 = Start.z; BoneToObject._44 = 1.0f;\n" \
	"}\n" \
	"void Engine_GetBoneUserData ( in int BoneIndex, out float3 UserData ) {\n" \
	"	SingleBone Bone;\n" \
	"	switch(BoneBuffer) {\n" \
	"		case 0: Bone = Bone_8[BoneIndex]; break;\n" \
	"		case 1: Bone = Bone_16[BoneIndex]; break;\n" \
	"		case 2: Bone = Bone_32[BoneIndex]; break;\n" \
	"		default: Bone = Bone_64[BoneIndex]; break;\n" \
	"	}\n" \
	"	UserData.x = Bone.Start.w;\n" \
	"	UserData.y = Bone.YAxis.w;\n" \
	"	UserData.z = Bone.ZAxis.w;\n" \
	"}\n" \
,
	"Texture2D tex_0 : register( t0 );\n" \
	"Texture2D tex_1 : register( t1 );\n" \
	"Texture2D tex_2 : register( t2 );\n" \
	"Texture2D tex_3 : register( t3 );\n" \
	"Texture2D tex_4 : register( t4 );\n" \
	"Texture2D tex_5 : register( t5 );\n" \
	"Texture2D tex_6 : register( t6 );\n" \
	"Texture2D tex_7 : register( t7 );\n" \
	"Texture2D tex_8 : register( t8 );\n" \
	"Texture2D tex_9 : register( t9 );\n" \
	"Texture2D tex_10 : register( t10 );\n" \
	"Texture2D tex_11 : register( t11 );\n" \
	"Texture2D tex_12 : register( t12 );\n" \
	"Texture2D tex_13 : register( t13 );\n" \
	"Texture2D tex_14 : register( t14 );\n" \
	"Texture2D tex_15 : register( t15 );\n" \
	"SamplerState samConstant : register( s0 );\n" \
	"SamplerState samLinear : register( s1 );\n" \
	"SamplerState samClampedConstant : register( s2 );\n" \
	"SamplerState samClampedLinear : register( s3 );\n" \
	"cbuffer cbEveryRender : register( b0 ) {\n" \
	"	float2 Dimensions; float GlobalTime; float PaddingA;\n" \
	"	float4 Arg[16];\n" \
	"	float2 ZWCorrection[16];\n" \
	"};\n" \
	"struct VS_structure {\n" \
	"	float4 Pos : POSITION;\n" \
	"};\n" \
	"struct VS_to_PS {\n" \
	"	float4 Pos : SV_POSITION;\n" \
	"};\n" \
	"#define PixelPos (input.Pos.xy)\n" \
,
	"Texture2D tex_0 : register( t0 );\n" \
	"Texture2D tex_1 : register( t1 );\n" \
	"Texture2D tex_2 : register( t2 );\n" \
	"Texture2D tex_3 : register( t3 );\n" \
	"Texture2D tex_4 : register( t4 );\n" \
	"Texture2D tex_5 : register( t5 );\n" \
	"Texture2D tex_6 : register( t6 );\n" \
	"Texture2D tex_7 : register( t7 );\n" \
	"Texture2D tex_8 : register( t8 );\n" \
	"Texture2D tex_9 : register( t9 );\n" \
	"Texture2D tex_10 : register( t10 );\n" \
	"Texture2D tex_11 : register( t11 );\n" \
	"Texture2D tex_12 : register( t12 );\n" \
	"Texture2D tex_13 : register( t13 );\n" \
	"Texture2D tex_14 : register( t14 );\n" \
	"Texture2D tex_15 : register( t15 );\n" \
	"SamplerState samConstant : register( s0 );\n" \
	"SamplerState samLinear : register( s1 );\n" \
	"SamplerState samClampedConstant : register( s2 );\n" \
	"SamplerState samClampedLinear : register( s3 );\n" \
	"cbuffer cbEveryRender : register( b0 ) {\n" \
	"	float4 Color;\n" \
	"	float4 SrcRectUV1;\n" \
	"	float4 SrcRectUV2;\n" \
	"	float2 Dimensions; float GlobalTime; float PaddingA;\n" \
	"	float2 XAxis; float2 YAxis;\n" \
	"	float2 Center; float2 PaddingB;\n" \
	"	float4 Arg[16];\n" \
	"};\n" \
	"struct VS_structure {\n" \
	"	float4 Pos : POSITION;\n" \
	"};\n" \
	"struct VS_to_PS {\n" \
	"	float4 Pos : SV_POSITION;\n" \
	"	float4 Tex : TEXCOORD1;\n" \
	"	float2 Pos_ObjectSpace : TEXCOORD2;\n" \
	"};\n" \
	"#define PixelPos (input.Pos.xy)\n" \
	"#define ObjectPos input.Pos_ObjectSpace\n" \
	"#define UV1 (input.Tex.xy)\n" \
	"#define UV2 (input.Tex.zw)\n" \
,
	"cbuffer cbEveryDebugRender : register( b0 ) {\n" \
	"	float4x4 WorldToImage;\n" \
	"};\n" \
	"struct VS_structure {\n" \
	"	float4 Pos : POSITION;\n" \
	"	float3 Color : COLOR;\n" \
	"};\n" \
	"struct VS_to_PS {\n" \
	"	float4 Pos : SV_POSITION;\n" \
	"	float3 Color : COLOR;\n" \
	"};\n" \
};

static char* LineVertexShader = \
	"VS_to_PS VS( VS_structure input ) {\n" \
	"	VS_to_PS output = (VS_to_PS)0;\n" \
	"	output.Pos = mul( input.Pos, WorldToImage );\n" \
	"	output.Color = input.Color;\n" \
	"	return output;\n" \
	"}\n";

static char* LinePixelShader = \
	"float4 PS( VS_to_PS input) : SV_Target {\n" \
	"	return float4(input.Color,1.0f);\n" \
	"}\n";

#define InsertChar(NEWCHAR) if (writeIndex < lenOutput) { sOutput[writeIndex] = (wchar_t)NEWCHAR; writeIndex++; }
#define InsertInt(NEWINT) sprintf(IntegerBuffer,"%i",NEWINT); i2 = 0; while(IntegerBuffer[i2] != '\0') { InsertChar(IntegerBuffer[i2]) i2++; }
#define InsertStringInterval(STRINGREF,STARTINDEX,ENDINDEX) LoopForward(STARTINDEX,i2,ENDINDEX) InsertChar(STRINGREF[i2])
#define InsertString(NEWSTRING) i2 = 0; while(NEWSTRING[i2] != '\0') { InsertChar(NEWSTRING[i2]) i2++; }

bool TranslatedHLSLMessage(wchar_t* sOutput, int lenOutput, char* OriginalMessage, char* sHeader, wchar_t* filename, bool Optional) {
	//Allocate space for the worst case integer length and terminate before the end
	int i; int i2; int writeIndex; int lineStartIndex; int lineEndIndex; int readIndex; char IntegerBuffer[12]; bool firstLine;
	int NumberOfHeaderLines;

	writeIndex = 0;
	lineStartIndex = 0;
	readIndex = 0;
	firstLine = true;
	
	InsertString("Error in ")
	InsertString(filename)
	InsertString("\n")
	
	NumberOfHeaderLines = 1;
	i = 0;
	while (sHeader[i] != '\0') {
		if (sHeader[i] == (char)10) {
			NumberOfHeaderLines++;
		}
		i++;
	}
	
	while (OriginalMessage[readIndex] != '\0') {
		while (OriginalMessage[readIndex] != '\0' && OriginalMessage[readIndex] != (char)10) { readIndex++; }
		lineEndIndex = readIndex - 1;
		
		if (firstLine == false) { InsertString("\n") }
		
		bool hasLC = false;
		int LeftIndex = 0; int MiddleIndex = 0; int RightIndex = 0;
		int LineNumber = 0; int CharNumber = 0;
		i = lineStartIndex;
		if (OriginalMessage[i] == '(') {
			LeftIndex = i;
			i++;
			while (OriginalMessage[i] >= '0' && OriginalMessage[i] <= '9') i++;
			if (OriginalMessage[i] == ',') {
				MiddleIndex = i;
				i++;
				while (OriginalMessage[i] >= '0' && OriginalMessage[i] <= '9') i++;
					if (OriginalMessage[i] == ')') {
						RightIndex = i;
						hasLC = true;
					} else {
						hasLC = false;
					}
			} else {
				hasLC = false;
			}
		} else {
			hasLC = false;
		}
		
		if (hasLC) {
			LineNumber = ParseIntFromPartOfString(OriginalMessage,LeftIndex + 1,MiddleIndex - 1) - NumberOfHeaderLines;
			CharNumber = ParseIntFromPartOfString(OriginalMessage,MiddleIndex + 1,RightIndex - 1);
			InsertString("At line ")
			InsertInt(LineNumber)
			InsertString(" column ")
			InsertInt(CharNumber)
			InsertString(" ")
			InsertStringInterval(OriginalMessage,RightIndex + 1,lineEndIndex)
		} else{
			if (Optional) {
				if (CompareStrings_PartOfACaseInsensitive_Ansi(OriginalMessage,lineStartIndex,lineStartIndex + 11,"error X3501:")) {
					// Don't show messages for an optional shader that don't exist
					return false;
				}
			}
			InsertStringInterval(OriginalMessage,lineStartIndex,lineEndIndex)
		}
		
		lineStartIndex = lineEndIndex + 2;
		readIndex = lineStartIndex;
		firstLine = false;
	}
	
	// Terminate
	sOutput[writeIndex] = '\0';
	return true;
}

// Returns true if a precompiled shader is returned in ppBlobOut
// Returns false if failed to find or load the precompiled shader or if the checksum did not match
bool EngineCore::LoadPrecompiledShader(wchar_t* Filename, UINT64 CheckSum, ByteArray** BinaryShader) {
	PrecompiledShaderHeaderType Header;
	
	FILE* filePtr;
	
	// Open the file in binary.
	if(_wfopen_s(&filePtr, Filename, L"rb") != 0) {
		// We did not find a precompiled shader.
		// Tell the caller that it need to compile the shader from source code.
		return false;
	}
	
	// Read in the file header.
	if(fread(&Header, sizeof(Header), 1, filePtr) != 1) {
		// The precompiled shader is corrupted.
		// Tell the caller that it need to compile the shader from source code.
		fclose(filePtr);
		return false;
	}
	
	if (Header.filetype[0] != 'D'		// David's
	 || Header.filetype[1] != 'P'		// Precompiled
	 || Header.filetype[2] != 'S'		// Shader
	 || Header.filetype[3] != '1') {	// Version 1
		// The precompiled shader is not of the right version.
		// Tell the caller that it need to compile the shader from source code.
		fclose(filePtr);
		return false;
	}
	
	if (Header.checksum != CheckSum) {
		// The final HLSL code has been modified.
		// Tell the caller that it need to compile the shader from source code.
		fclose(filePtr);
		return false;
	}
	
	// Create the byte array holding the data
	*BinaryShader = new ByteArray((long)Header.size,MQ);
	if ((*BinaryShader) == NULL) {
		MQ->InsertMessage(L"EngineCore::LoadPrecompiledShader: Could not allocate the ByteArray class for storing the compiled shader.");
		fclose(filePtr);
		return false;
	}
	
	// Read data from file.
	if(fread((*BinaryShader)->TheData, 1, (int)Header.size, filePtr) != (int)Header.size) {
		swprintf_s( MQ->messageBuffer, L"EngineCore::LoadPrecompiledShader: Could not retrieve the content from the file \"%s\".", Filename); MQ->InsertMessage(MQ->messageBuffer);
		fclose(filePtr);
		return false;
	}
	
	// Close the file.
	if (filePtr) {
		if(fclose(filePtr) != 0) {
			swprintf_s( MQ->messageBuffer, L"EngineCore::LoadPrecompiledShader: The file \"%s\" could not be closed after reading.", Filename); MQ->InsertMessage(MQ->messageBuffer);
			return false;
		}
	}
	
	return true;
}

bool EngineCore::SavePrecompiledShader(wchar_t* Filename, UINT64 CheckSum, ByteArray** BinaryShader) {
	PrecompiledShaderHeaderType Header;
	
	Header.checksum = CheckSum;
	Header.size = (*BinaryShader)->GetSizeInBytes();
	Header.filetype[0] = 'D';
	Header.filetype[1] = 'P';
	Header.filetype[2] = 'S';
	Header.filetype[3] = '1';
	
	// Delete any previous file with that name
	_wremove(Filename);
	
	// Save to file
	FILE* filePtr;
	
	// Open the file in binary.
	if( (_wfopen_s(&filePtr, Filename, L"wb")) != 0 ) {
		swprintf_s( MQ->messageBuffer, L"EngineCore::SavePrecompiledShader: The file \"%s\" could not be opened for writing.", Filename); MQ->InsertMessage(MQ->messageBuffer);
		return false;
	}
	
	// Save the file header.
	fwrite(&Header,sizeof(PrecompiledShaderHeaderType),1,filePtr);
	
	// Write the content to the file.
	fwrite((*BinaryShader)->TheData, 1, Header.size, filePtr);
	
	// Close the file.
	if (filePtr) {
		if(fclose(filePtr) != 0) {
			swprintf_s( MQ->messageBuffer, L"EngineCore::SavePrecompiledShader: The file \"%s\" could not be closed after writing.", Filename); MQ->InsertMessage(MQ->messageBuffer);
			return false;
		}
	}
	
	//SAFE_DELETE(CompressedResult.Content)
	
	return true;
}

// The precompiled shaders can not be used without the HLSL source code because the engine may have a new header included in the code.
int EngineCore::CompileShaderFromFile( int shadertype, wchar_t* filename, wchar_t* precompiledExtension, LPCSTR szEntryPoint, LPCSTR szShaderModel, ByteArray** BinaryShader, bool Optional) {
	int lenHeader;
	int lenShader;
	char* shader;
	char* finalShader;
	wchar_t subDirFilename[260];
	wchar_t subDirPath[260];
	wchar_t precompiledFilename[260];
	int lenFinalShader;
	wchar_t* BOM;
	UINT64 CheckSum;
	
	// Load and measure the shader content
	shader = LoadTextAsANSI(filename);
	if (shader == NULL) {
		swprintf_s( MQ->messageBuffer, L"EngineCore::CompileShaderFromFile: The shader \"%s\" could not be loaded.", filename); MQ->InsertMessage(MQ->messageBuffer);
		return CompilationResult_Failed;
	} else {
		BOM = GetBOM(shader);
		if (BOM != NULL) {
			swprintf_s( MQ->messageBuffer, L"EngineCore::CompileShaderFromFile: The shader \"%s\" is not ANSI encoded. It is encoded as %s", filename, BOM); MQ->InsertMessage(MQ->messageBuffer);
			return CompilationResult_Failed;
		}
	}
	
	// Measure length of the loaded shader code
	lenShader = lengthOfString(shader);
	
	// Measure length of the header
	lenHeader = lengthOfString(ShaderHeaders[shadertype]);
	
	// Allocate enough memory
	lenFinalShader = lenHeader + lenShader + 3;
	finalShader = new char[lenFinalShader]; //Content + linebreak + content + linebreak + terminator
	// Concatunate
	sprintf(finalShader,"%s\n%s\n",ShaderHeaders[shadertype],shader);
	// Release the loaded string
	SAFE_DELETE(shader)
	
	// Make a filename for the precompiled shader
	if (!(AddSubDir(filename,subDirFilename,L"Precompiled"))) {
		swprintf_s( MQ->messageBuffer, L"EngineCore::CompileShaderFromFile: The filename \"%s\" is too long for the function AddSubDir.", filename); MQ->InsertMessage(MQ->messageBuffer);
		SAFE_DELETE_ARRAY(finalShader)
		return CompilationResult_Failed;
	}
	CopyToFixedSizePath(subDirFilename,subDirPath); OnlyPath(subDirPath);
	if (!(replaceAfterDot(subDirFilename,precompiledFilename,precompiledExtension))) {
		swprintf_s( MQ->messageBuffer, L"EngineCore::CompileShaderFromFile: The filename \"%s\" is too long for the function replaceAfterDot.", subDirFilename); MQ->InsertMessage(MQ->messageBuffer);
		SAFE_DELETE_ARRAY(finalShader)
		return CompilationResult_Failed;
	}
	
	// Get the checksum for the final shader code
	CheckSum = CheckSumFromString(finalShader);
	
	DWORD dwShaderFlags = (1<<11); //D3DCOMPILE_ENABLE_STRICTNESS
	#if defined( DEBUG ) || defined( _DEBUG )
		dwShaderFlags |= (1<<0); //D3DCOMPILE_DEBUG
	#endif
	
	if (LoadPrecompiledShader(precompiledFilename,CheckSum,BinaryShader)) {
		// The precompiled shader has been loaded to BinaryShader
		SAFE_DELETE_ARRAY(finalShader)
		return CompilationResult_Compiled;
	} else {
		// Compile a new shader
		ID3DBlob* pErrorBlob;
		ID3DBlob* pResultBlob;
		HRESULT ErrorCode = D3DX11CompileFromMemory( finalShader, lenFinalShader, NULL, NULL, NULL, szEntryPoint, szShaderModel, dwShaderFlags, 0, NULL, &pResultBlob, &pErrorBlob, NULL );
		if( FAILED(ErrorCode) ) {
			if( pErrorBlob != NULL ) {
				if (TranslatedHLSLMessage(MQ->messageBuffer,1024,(char*)pErrorBlob->GetBufferPointer(),ShaderHeaders[shadertype],filename,Optional)) {
					MQ->InsertMessage(MQ->messageBuffer);
				} else {
					// Ignore error message
					SAFE_RELEASE(pErrorBlob)
					SAFE_RELEASE(pResultBlob)
					SAFE_DELETE_ARRAY(finalShader)
					return CompilationResult_OptionalEntryNotFound;
				}
			} else {
				MQ->InsertMessage(L"EngineCore::CompileShaderFromFile: The HLSL compiler did not give any message about the error.");
			}
			SAFE_RELEASE(pErrorBlob)
			SAFE_RELEASE(pResultBlob)
			SAFE_DELETE_ARRAY(finalShader)
			return CompilationResult_Failed;
		} else {
			// Resize the byte array
			*BinaryShader = new ByteArray((long)pResultBlob->GetBufferSize(),MQ);
			if ((*BinaryShader) == NULL) {
				MQ->InsertMessage(L"EngineCore::CompileShaderFromFile: Could not allocate the ByteArray class for storing the compiled shader.");
				SAFE_RELEASE(pErrorBlob)
				SAFE_RELEASE(pResultBlob)
				SAFE_DELETE_ARRAY(finalShader)
				return CompilationResult_Failed;
			}
			
			// Copy the result to the byte array
			memcpy((*BinaryShader)->TheData,pResultBlob->GetBufferPointer(),pResultBlob->GetBufferSize());
			
			// Save the result to file with checksum
			CreateDirectory(subDirPath,NULL);
			SavePrecompiledShader(precompiledFilename,CheckSum,BinaryShader);
			
			SAFE_RELEASE(pErrorBlob)
			SAFE_RELEASE(pResultBlob)
			SAFE_DELETE_ARRAY(finalShader)
			return CompilationResult_Compiled;
		}
	}
}

int EngineCore::CompileShaderFromString( int shadertype, char* shader, LPCSTR szEntryPoint, LPCSTR szShaderModel, ByteArray** BinaryShader, bool Optional) {
	int lenHeader;
	int lenShader;
	char* finalShader;
	int lenFinalShader;
	
	// Measure length of the shader code
	lenShader = lengthOfString(shader);
	
	// Measure length of the header
	lenHeader = lengthOfString(ShaderHeaders[shadertype]);
	
	// Allocate enough memory
	lenFinalShader = lenHeader + lenShader + 3;
	finalShader = new char[lenFinalShader]; //Content + linebreak + content + linebreak + terminator
	// Concatunate
	sprintf(finalShader,"%s\n%s\n",ShaderHeaders[shadertype],shader);
	
	DWORD dwShaderFlags = (1<<11); //D3DCOMPILE_ENABLE_STRICTNESS
	#if defined( DEBUG ) || defined( _DEBUG )
		dwShaderFlags |= (1<<0); //D3DCOMPILE_DEBUG
	#endif
	
	// Compile the shader
	ID3DBlob* pErrorBlob;
	ID3DBlob* pResultBlob;
	if( FAILED(D3DX11CompileFromMemory( finalShader, lenFinalShader, NULL, NULL, NULL, szEntryPoint, szShaderModel, dwShaderFlags, 0, NULL, &pResultBlob, &pErrorBlob, NULL )) ) {
		if( pErrorBlob != NULL ) {
			if (TranslatedHLSLMessage(MQ->messageBuffer,1024,(char*)pErrorBlob->GetBufferPointer(),ShaderHeaders[shadertype],L"<No filename>",Optional)) {
				MQ->InsertMessage(MQ->messageBuffer);
			} else {
				// Ignore error message
				SAFE_RELEASE(pErrorBlob)
				SAFE_RELEASE(pResultBlob)
				SAFE_DELETE_ARRAY(finalShader)
				return CompilationResult_OptionalEntryNotFound;
			}
		} else {
			MQ->InsertMessage(L"EngineCore::CompileShaderFromString: The HLSL compiler did not give any message about the error.");
		}
		SAFE_RELEASE(pErrorBlob)
		SAFE_RELEASE(pResultBlob)
		SAFE_DELETE_ARRAY(finalShader)
		return CompilationResult_Failed;
	} else {
		// Resize the byte array
		*BinaryShader = new ByteArray((long)pResultBlob->GetBufferSize(),MQ);
		if ((*BinaryShader) == NULL) {
			MQ->InsertMessage(L"EngineCore::CompileShaderFromString: Could not allocate the ByteArray class for storing the compiled shader.");
			SAFE_RELEASE(pErrorBlob)
			SAFE_RELEASE(pResultBlob)
			SAFE_DELETE_ARRAY(finalShader)
			return CompilationResult_Failed;
		}
		
		// Copy the result to the byte array
		memcpy((*BinaryShader)->TheData,pResultBlob->GetBufferPointer(),pResultBlob->GetBufferSize());
		
		SAFE_RELEASE(pErrorBlob)
		SAFE_RELEASE(pResultBlob)
		SAFE_DELETE_ARRAY(finalShader)
		return CompilationResult_Compiled;
	}
}
