<commit_before>// Copyright (C) 2013 <NAME>
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/ShaderBuilder.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Shader.hpp>
#include <memory>
#include <unordered_map>
#include <Nazara/Renderer/Debug.hpp>

namespace
{
	std::unordered_map<nzUInt32, NzResourceRef<NzShader>> s_shaders;

	NzString BuildFragmentShaderSource(nzUInt32 flags)
	{
		bool glsl140 = (NzOpenGL::GetVersion() >= 310);
		//bool useMRT = (glsl140 && NzRenderer::HasCapability(nzRendererCap_MultipleRenderTargets));

		NzString inKW = (glsl140) ? "in" : "varying";
		NzString fragmentColorKW = (glsl140) ? "RenderTarget0" : "gl_FragColor";

		NzString sourceCode;
		sourceCode.Reserve(1024); // Le shader peut faire plus, mais cela évite déjà beaucoup de petites allocations

		/********************Préprocesseur********************/
		sourceCode = "#version ";
		if (glsl140)
			sourceCode += "140\n";
		else
			sourceCode += "110\n";

		sourceCode += '\n';

		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += "#define LIGHT_DIRECTIONAL 0\n"
			              "#define LIGHT_POINT 1\n"
			              "#define LIGHT_SPOT 2\n"
			              "#define MAX_LIGHTS 8\n"
			              "\n";
		}

		sourceCode += '\n';

		/********************Uniformes********************/
		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += "struct Light\n"
			              "{\n"
			              "int type;\n"
			              "vec4 ambient;\n"
			              "vec4 diffuse;\n"
			              "vec4 specular;\n"
			              "\n"
			              "vec4 parameters1;\n"
			              "vec4 parameters2;\n"
			              "vec2 parameters3;\n"
			              "};\n"
			              "\n";
		}

		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += "uniform vec3 CameraPosition;\n"
			              "uniform int LightCount;\n"
			              "uniform Light Lights[MAX_LIGHTS];\n"
			              "uniform vec4 MaterialAmbient;\n";
		}

		if ((flags & nzShaderFlags_DiffuseMapping) == 0 || flags & nzShaderFlags_Lighting)
			sourceCode += "uniform vec4 MaterialDiffuse;\n";

		if (flags & nzShaderFlags_DiffuseMapping)
			sourceCode += "uniform sampler2D MaterialDiffuseMap;\n";

		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_NormalMapping)
				sourceCode += "uniform sampler2D MaterialNormalMap;\n";

			sourceCode += "uniform float MaterialShininess;\n"
			              "uniform vec4 MaterialSpecular;\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "uniform sampler2D MaterialSpecularMap;\n";

			sourceCode += "uniform vec4 SceneAmbient;\n";
		}

		sourceCode += '\n';

		/********************Entrant********************/
		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_NormalMapping)
				sourceCode += inKW + " mat3 vLightToWorld;\n";
			else
				sourceCode += inKW + " vec3 vNormal;\n";
		}

		if (flags & nzShaderFlags_DiffuseMapping || flags & nzShaderFlags_NormalMapping)
			sourceCode += inKW + " vec2 vTexCoord;\n";

		if (flags & nzShaderFlags_Lighting)
			sourceCode += inKW + " vec3 vWorldPos;\n";

		sourceCode += '\n';

		/********************Sortant********************/
		if (glsl140)
			sourceCode += "out vec4 RenderTarget0;\n";

		sourceCode += '\n';

		/********************Fonctions********************/
		sourceCode += "void main()\n"
		              "{\n";

		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += "vec3 light = vec3(0.0, 0.0, 0.0);\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "vec3 si = vec3(0.0, 0.0, 0.0);\n";

			if (flags & nzShaderFlags_NormalMapping)
				sourceCode += "vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture2D(MaterialNormalMap, vTexCoord)) - 1.0));\n";
			else
				sourceCode += "vec3 normal = normalize(vNormal);\n";

			sourceCode += "\n"
			              "for (int i = 0; i < LightCount; ++i)\n"
			              "{\n";

			if (glsl140)
			{
				sourceCode += "switch (Lights[i].type)\n"
				              "{\n"
				              "case LIGHT_DIRECTIONAL:\n";
			}
			else // Le GLSL 110 n'a pas d'instruction switch
				sourceCode += "if (Lights[i].type == LIGHT_DIRECTIONAL)\n";

			// Directional Light
			sourceCode += "{\n"
			              "vec3 lightDir = normalize(-Lights[i].parameters1.xyz);\n"
			              "light += Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);\n"
			              "\n"
			              "float lambert = max(dot(normal, lightDir), 0.0);\n"
			              "light += lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;\n"
			              "\n"
			              "if (MaterialShininess > 0.0)\n"
			              "{\n"
			              "vec3 eyeVec = normalize(CameraPosition - vWorldPos);\n"
			              "vec3 reflection = reflect(-lightDir, normal);\n"
			              "\n"
			              "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "si";
			else
				sourceCode += "light";

			sourceCode += " += specular * Lights[i].specular.rgb * MaterialSpecular.rgb;\n"
			              "}\n";

			if (glsl140)
			{
				sourceCode += "break;\n"
				              "}\n"
				              "\n"
				              "case LIGHT_POINT:\n";
			}
			else
				sourceCode += "}\n"
				              "else if (Lights[i].type == LIGHT_POINT)\n";

			// Point Light
			sourceCode += "{\n"
			              "vec3 lightDir = Lights[i].parameters1.xyz - vWorldPos;\n"
			              "\n"
			              "float att = max(Lights[i].parameters1.w - Lights[i].parameters2.x*length(lightDir), 0.0);\n"
			              "light += att * Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);\n"
			              "\n"
			              "lightDir = normalize(lightDir);\n"
			              "float lambert = max(dot(normal, lightDir), 0.0);\n"
			              "light += att * lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;\n"
			              "\n"
			              "if (MaterialShininess > 0.0)\n"
			              "{\n"
			              "vec3 eyeVec = normalize(CameraPosition - vWorldPos);\n"
			              "vec3 reflection = reflect(-lightDir, normal);\n"
			              "\n"
			              "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "si";
			else
				sourceCode += "light";

			sourceCode += " += att * specular * Lights[i].specular.rgb * MaterialSpecular.rgb;\n"
			              "}\n";

			if (glsl140)
			{
				sourceCode += "break;\n"
				              "}\n"
				              "\n"
				              "case LIGHT_SPOT:\n";
			}
			else
			{
				sourceCode += "}\n"
				              "else if (Lights[i].type == LIGHT_SPOT)\n";
			}

			// Spot Light
			sourceCode += "{\n"
			              "vec3 lightDir = Lights[i].parameters1.xyz - vWorldPos;\n"
			              "\n"
			              "float att = max(Lights[i].parameters1.w - Lights[i].parameters2.w*length(lightDir), 0.0);\n"
			              "light += att * Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);\n"
			              "\n"
			              "lightDir = normalize(lightDir);\n"
			              "\n"
			              "float curAngle = dot(Lights[i].parameters2.xyz, -lightDir);\n"
			              "float outerAngle = Lights[i].parameters3.y;\n"
			              "float innerMinusOuterAngle = Lights[i].parameters3.x - outerAngle;\n"
			              "float lambert = max(dot(normal, lightDir), 0.0);\n"
			              "att *= max((curAngle - outerAngle) / innerMinusOuterAngle, 0.0);\n"
			              "light += att * lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;\n"
			              "\n"
			              "if (MaterialShininess > 0.0)\n"
			              "{\n"
			              "vec3 eyeVec = normalize(CameraPosition - vWorldPos);\n"
			              "vec3 reflection = reflect(-lightDir, normal);\n"
			              "\n"
			              "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "si";
			else
				sourceCode += "light";

			sourceCode += " += att * specular * Lights[i].specular.rgb * MaterialSpecular.rgb;\n"
			              "}\n";

			if (glsl140)
			{
				sourceCode += "break;\n"
				              "}\n"
				              "default:\n"
				              "break;\n"
				              "}\n";
			}
			else
				sourceCode += "}\n";

			sourceCode += "}\n"
			              "\n";

			sourceCode += fragmentColorKW + " = vec4(light, MaterialDiffuse.a)";

			if (flags & nzShaderFlags_DiffuseMapping)
				sourceCode += "*texture2D(MaterialDiffuseMap, vTexCoord)";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += " + vec4(si, MaterialDiffuse.a)*texture2D(MaterialSpecularMap, vTexCoord)"; // Utiliser l'alpha de MaterialSpecular n'aurait aucun sens

			sourceCode += ";\n";
		}
		else if (flags & nzShaderFlags_DiffuseMapping)
			sourceCode += fragmentColorKW + " = texture2D(MaterialDiffuseMap, vTexCoord);\n";
		else
			sourceCode += fragmentColorKW + " = MaterialDiffuse;\n";

		sourceCode += "}\n";

		return sourceCode;
	}

	NzString BuildVertexShaderSource(nzUInt32 flags)
	{
		bool glsl140 = (NzOpenGL::GetVersion() >= 310);

		NzString inKW = (glsl140) ? "in" : "attribute";
		NzString outKW = (glsl140) ? "out" : "varying";

		NzString sourceCode;
		sourceCode.Reserve(512); // Le shader peut faire plus, mais cela évite déjà beaucoup de petites allocations

		/********************Version de GLSL********************/
		sourceCode = "#version ";
		if (glsl140)
			sourceCode += "140\n";
		else
			sourceCode += "110\n";

		sourceCode += '\n';

		/********************Uniformes********************/
		if (flags & nzShaderFlags_Instancing)
			sourceCode += "uniform mat4 ViewProjMatrix;\n";
		else
		{
			if (flags & nzShaderFlags_Lighting)
				sourceCode += "uniform mat4 WorldMatrix;\n";

			sourceCode += "uniform mat4 WorldViewProjMatrix;\n";
		}

		sourceCode += '\n';

		/********************Entrant********************/
		if (flags & nzShaderFlags_Instancing)
			sourceCode += inKW + " mat4 InstanceMatrix;\n";

		sourceCode += inKW + " vec3 VertexPosition;\n";

		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += inKW + " vec3 VertexNormal;\n";
			sourceCode += inKW + " vec3 VertexTangent;\n";
		}

		if (flags & nzShaderFlags_DiffuseMapping)
			sourceCode += inKW + " vec2 VertexTexCoord0;\n";

		sourceCode += '\n';

		/********************Sortant********************/
		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_NormalMapping)
				sourceCode += outKW + " mat3 vLightToWorld;\n";
			else
				sourceCode += outKW + " vec3 vNormal;\n";
		}

		if (flags & nzShaderFlags_DiffuseMapping || flags & nzShaderFlags_NormalMapping)
			sourceCode += outKW + " vec2 vTexCoord;\n";

		if (flags & nzShaderFlags_Lighting)
			sourceCode += outKW + " vec3 vWorldPos;\n";

		sourceCode += '\n';

		/********************Code********************/
		sourceCode += "void main()\n"
		              "{\n";

		if (flags & nzShaderFlags_Instancing)
			sourceCode += "gl_Position = ViewProjMatrix * InstanceMatrix * vec4(VertexPosition, 1.0);\n";
		else
			sourceCode += "gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);\n";

		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_Instancing)
			{
				if (glsl140)
					sourceCode += "mat3 rotationMatrix = mat3(InstanceMatrix);\n";
				else
					sourceCode += "mat3 rotationMatrix = mat3(InstanceMatrix[0].xyz, InstanceMatrix[1].xyz, InstanceMatrix[2].xyz);\n";
			}
			else
			{
				if (glsl140)
					sourceCode += "mat3 rotationMatrix = mat3(WorldMatrix);\n";
				else
					sourceCode += "mat3 rotationMatrix = mat3(WorldMatrix[0].xyz, WorldMatrix[1].xyz, WorldMatrix[2].xyz);\n";
			}

			if (flags & nzShaderFlags_NormalMapping)
			{
				sourceCode += "\n"
				              "vec3 binormal = cross(VertexNormal, VertexTangent);\n"
				              "vLightToWorld[0] = normalize(rotationMatrix * VertexTangent);\n"
				              "vLightToWorld[1] = normalize(rotationMatrix * binormal);\n"
				              "vLightToWorld[2] = normalize(rotationMatrix * VertexNormal);\n"
				              "\n";
			}
			else
				sourceCode += "vNormal = normalize(rotationMatrix * VertexNormal);\n";
		}

		if (flags & nzShaderFlags_DiffuseMapping || flags & nzShaderFlags_NormalMapping || flags & nzShaderFlags_SpecularMapping)
		{
			if (flags & nzShaderFlags_FlipUVs)
				sourceCode += "vTexCoord = vec2(VertexTexCoord0.x, 1.0 - VertexTexCoord0.y);\n";
			else
				sourceCode += "vTexCoord = VertexTexCoord0;\n";
		}

		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_Instancing)
				sourceCode += "vWorldPos = vec3(InstanceMatrix * vec4(VertexPosition, 1.0));\n";
			else
				sourceCode += "vWorldPos = vec3(WorldMatrix * vec4(VertexPosition, 1.0));\n";
		}

		sourceCode += "}\n";

		return sourceCode;
	}

	NzShader* BuildShader(nzUInt32 flags)
	{
		std::unique_ptr<NzShader> shader(new NzShader);<commit_msg>Fixed some shader flags not compiling<commit_after>// Copyright (C) 2013 <NAME>
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/ShaderBuilder.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Shader.hpp>
#include <memory>
#include <unordered_map>
#include <Nazara/Renderer/Debug.hpp>

namespace
{
	std::unordered_map<nzUInt32, NzResourceRef<NzShader>> s_shaders;

	NzString BuildFragmentShaderSource(nzUInt32 flags)
	{
		bool glsl140 = (NzOpenGL::GetVersion() >= 310);
		//bool useMRT = (glsl140 && NzRenderer::HasCapability(nzRendererCap_MultipleRenderTargets));
		bool uvMapping = (flags & nzShaderFlags_DiffuseMapping || flags & nzShaderFlags_NormalMapping || flags & nzShaderFlags_SpecularMapping);

		NzString inKW = (glsl140) ? "in" : "varying";
		NzString fragmentColorKW = (glsl140) ? "RenderTarget0" : "gl_FragColor";

		NzString sourceCode;
		sourceCode.Reserve(1024); // Le shader peut faire plus, mais cela évite déjà beaucoup de petites allocations

		/********************Préprocesseur********************/
		sourceCode = "#version ";
		if (glsl140)
			sourceCode += "140\n";
		else
			sourceCode += "110\n";

		sourceCode += '\n';

		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += "#define LIGHT_DIRECTIONAL 0\n"
			              "#define LIGHT_POINT 1\n"
			              "#define LIGHT_SPOT 2\n"
			              "#define MAX_LIGHTS 8\n"
			              "\n";
		}

		sourceCode += '\n';

		/********************Uniformes********************/
		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += "struct Light\n"
			              "{\n"
			              "int type;\n"
			              "vec4 ambient;\n"
			              "vec4 diffuse;\n"
			              "vec4 specular;\n"
			              "\n"
			              "vec4 parameters1;\n"
			              "vec4 parameters2;\n"
			              "vec2 parameters3;\n"
			              "};\n"
			              "\n";
		}

		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += "uniform vec3 CameraPosition;\n"
			              "uniform int LightCount;\n"
			              "uniform Light Lights[MAX_LIGHTS];\n"
			              "uniform vec4 MaterialAmbient;\n";
		}

		if ((flags & nzShaderFlags_DiffuseMapping) == 0 || flags & nzShaderFlags_Lighting)
			sourceCode += "uniform vec4 MaterialDiffuse;\n";

		if (flags & nzShaderFlags_DiffuseMapping)
			sourceCode += "uniform sampler2D MaterialDiffuseMap;\n";

		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_NormalMapping)
				sourceCode += "uniform sampler2D MaterialNormalMap;\n";

			sourceCode += "uniform float MaterialShininess;\n"
			              "uniform vec4 MaterialSpecular;\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "uniform sampler2D MaterialSpecularMap;\n";

			sourceCode += "uniform vec4 SceneAmbient;\n";
		}

		sourceCode += '\n';

		/********************Entrant********************/
		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_NormalMapping)
				sourceCode += inKW + " mat3 vLightToWorld;\n";
			else
				sourceCode += inKW + " vec3 vNormal;\n";
		}

		if (uvMapping)
			sourceCode += inKW + " vec2 vTexCoord;\n";

		if (flags & nzShaderFlags_Lighting)
			sourceCode += inKW + " vec3 vWorldPos;\n";

		sourceCode += '\n';

		/********************Sortant********************/
		if (glsl140)
			sourceCode += "out vec4 RenderTarget0;\n";

		sourceCode += '\n';

		/********************Fonctions********************/
		sourceCode += "void main()\n"
		              "{\n";

		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += "vec3 light = vec3(0.0, 0.0, 0.0);\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "vec3 si = vec3(0.0, 0.0, 0.0);\n";

			if (flags & nzShaderFlags_NormalMapping)
				sourceCode += "vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture2D(MaterialNormalMap, vTexCoord)) - 1.0));\n";
			else
				sourceCode += "vec3 normal = normalize(vNormal);\n";

			sourceCode += "\n"
			              "for (int i = 0; i < LightCount; ++i)\n"
			              "{\n";

			if (glsl140)
			{
				sourceCode += "switch (Lights[i].type)\n"
				              "{\n"
				              "case LIGHT_DIRECTIONAL:\n";
			}
			else // Le GLSL 110 n'a pas d'instruction switch
				sourceCode += "if (Lights[i].type == LIGHT_DIRECTIONAL)\n";

			// Directional Light
			sourceCode += "{\n"
			              "vec3 lightDir = normalize(-Lights[i].parameters1.xyz);\n"
			              "light += Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);\n"
			              "\n"
			              "float lambert = max(dot(normal, lightDir), 0.0);\n"
			              "light += lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;\n"
			              "\n"
			              "if (MaterialShininess > 0.0)\n"
			              "{\n"
			              "vec3 eyeVec = normalize(CameraPosition - vWorldPos);\n"
			              "vec3 reflection = reflect(-lightDir, normal);\n"
			              "\n"
			              "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "si";
			else
				sourceCode += "light";

			sourceCode += " += specular * Lights[i].specular.rgb * MaterialSpecular.rgb;\n"
			              "}\n";

			if (glsl140)
			{
				sourceCode += "break;\n"
				              "}\n"
				              "\n"
				              "case LIGHT_POINT:\n";
			}
			else
				sourceCode += "}\n"
				              "else if (Lights[i].type == LIGHT_POINT)\n";

			// Point Light
			sourceCode += "{\n"
			              "vec3 lightDir = Lights[i].parameters1.xyz - vWorldPos;\n"
			              "\n"
			              "float att = max(Lights[i].parameters1.w - Lights[i].parameters2.x*length(lightDir), 0.0);\n"
			              "light += att * Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);\n"
			              "\n"
			              "lightDir = normalize(lightDir);\n"
			              "float lambert = max(dot(normal, lightDir), 0.0);\n"
			              "light += att * lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;\n"
			              "\n"
			              "if (MaterialShininess > 0.0)\n"
			              "{\n"
			              "vec3 eyeVec = normalize(CameraPosition - vWorldPos);\n"
			              "vec3 reflection = reflect(-lightDir, normal);\n"
			              "\n"
			              "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "si";
			else
				sourceCode += "light";

			sourceCode += " += att * specular * Lights[i].specular.rgb * MaterialSpecular.rgb;\n"
			              "}\n";

			if (glsl140)
			{
				sourceCode += "break;\n"
				              "}\n"
				              "\n"
				              "case LIGHT_SPOT:\n";
			}
			else
			{
				sourceCode += "}\n"
				              "else if (Lights[i].type == LIGHT_SPOT)\n";
			}

			// Spot Light
			sourceCode += "{\n"
			              "vec3 lightDir = Lights[i].parameters1.xyz - vWorldPos;\n"
			              "\n"
			              "float att = max(Lights[i].parameters1.w - Lights[i].parameters2.w*length(lightDir), 0.0);\n"
			              "light += att * Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);\n"
			              "\n"
			              "lightDir = normalize(lightDir);\n"
			              "\n"
			              "float curAngle = dot(Lights[i].parameters2.xyz, -lightDir);\n"
			              "float outerAngle = Lights[i].parameters3.y;\n"
			              "float innerMinusOuterAngle = Lights[i].parameters3.x - outerAngle;\n"
			              "float lambert = max(dot(normal, lightDir), 0.0);\n"
			              "att *= max((curAngle - outerAngle) / innerMinusOuterAngle, 0.0);\n"
			              "light += att * lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;\n"
			              "\n"
			              "if (MaterialShininess > 0.0)\n"
			              "{\n"
			              "vec3 eyeVec = normalize(CameraPosition - vWorldPos);\n"
			              "vec3 reflection = reflect(-lightDir, normal);\n"
			              "\n"
			              "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);\n";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += "si";
			else
				sourceCode += "light";

			sourceCode += " += att * specular * Lights[i].specular.rgb * MaterialSpecular.rgb;\n"
			              "}\n";

			if (glsl140)
			{
				sourceCode += "break;\n"
				              "}\n"
				              "default:\n"
				              "break;\n"
				              "}\n";
			}
			else
				sourceCode += "}\n";

			sourceCode += "}\n"
			              "\n";

			sourceCode += fragmentColorKW + " = vec4(light, MaterialDiffuse.a)";

			if (flags & nzShaderFlags_DiffuseMapping)
				sourceCode += "*texture2D(MaterialDiffuseMap, vTexCoord)";

			if (flags & nzShaderFlags_SpecularMapping)
				sourceCode += " + vec4(si, MaterialDiffuse.a)*texture2D(MaterialSpecularMap, vTexCoord)"; // Utiliser l'alpha de MaterialSpecular n'aurait aucun sens

			sourceCode += ";\n";
		}
		else if (flags & nzShaderFlags_DiffuseMapping)
			sourceCode += fragmentColorKW + " = texture2D(MaterialDiffuseMap, vTexCoord);\n";
		else
			sourceCode += fragmentColorKW + " = MaterialDiffuse;\n";

		sourceCode += "}\n";

		return sourceCode;
	}

	NzString BuildVertexShaderSource(nzUInt32 flags)
	{
		bool glsl140 = (NzOpenGL::GetVersion() >= 310);
		bool uvMapping = (flags & nzShaderFlags_DiffuseMapping || flags & nzShaderFlags_NormalMapping || flags & nzShaderFlags_SpecularMapping);

		NzString inKW = (glsl140) ? "in" : "attribute";
		NzString outKW = (glsl140) ? "out" : "varying";

		NzString sourceCode;
		sourceCode.Reserve(512); // Le shader peut faire plus, mais cela évite déjà beaucoup de petites allocations

		/********************Version de GLSL********************/
		sourceCode = "#version ";
		if (glsl140)
			sourceCode += "140\n";
		else
			sourceCode += "110\n";

		sourceCode += '\n';

		/********************Uniformes********************/
		if (flags & nzShaderFlags_Instancing)
			sourceCode += "uniform mat4 ViewProjMatrix;\n";
		else
		{
			if (flags & nzShaderFlags_Lighting)
				sourceCode += "uniform mat4 WorldMatrix;\n";

			sourceCode += "uniform mat4 WorldViewProjMatrix;\n";
		}

		sourceCode += '\n';

		/********************Entrant********************/
		if (flags & nzShaderFlags_Instancing)
			sourceCode += inKW + " mat4 InstanceMatrix;\n";

		sourceCode += inKW + " vec3 VertexPosition;\n";

		if (flags & nzShaderFlags_Lighting)
		{
			sourceCode += inKW + " vec3 VertexNormal;\n";
			sourceCode += inKW + " vec3 VertexTangent;\n";
		}

		if (uvMapping)
			sourceCode += inKW + " vec2 VertexTexCoord0;\n";

		sourceCode += '\n';

		/********************Sortant********************/
		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_NormalMapping)
				sourceCode += outKW + " mat3 vLightToWorld;\n";
			else
				sourceCode += outKW + " vec3 vNormal;\n";
		}

		if (uvMapping)
			sourceCode += outKW + " vec2 vTexCoord;\n";

		if (flags & nzShaderFlags_Lighting)
			sourceCode += outKW + " vec3 vWorldPos;\n";

		sourceCode += '\n';

		/********************Code********************/
		sourceCode += "void main()\n"
		              "{\n";

		if (flags & nzShaderFlags_Instancing)
			sourceCode += "gl_Position = ViewProjMatrix * InstanceMatrix * vec4(VertexPosition, 1.0);\n";
		else
			sourceCode += "gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);\n";

		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_Instancing)
			{
				if (glsl140)
					sourceCode += "mat3 rotationMatrix = mat3(InstanceMatrix);\n";
				else
					sourceCode += "mat3 rotationMatrix = mat3(InstanceMatrix[0].xyz, InstanceMatrix[1].xyz, InstanceMatrix[2].xyz);\n";
			}
			else
			{
				if (glsl140)
					sourceCode += "mat3 rotationMatrix = mat3(WorldMatrix);\n";
				else
					sourceCode += "mat3 rotationMatrix = mat3(WorldMatrix[0].xyz, WorldMatrix[1].xyz, WorldMatrix[2].xyz);\n";
			}

			if (flags & nzShaderFlags_NormalMapping)
			{
				sourceCode += "\n"
				              "vec3 binormal = cross(VertexNormal, VertexTangent);\n"
				              "vLightToWorld[0] = normalize(rotationMatrix * VertexTangent);\n"
				              "vLightToWorld[1] = normalize(rotationMatrix * binormal);\n"
				              "vLightToWorld[2] = normalize(rotationMatrix * VertexNormal);\n"
				              "\n";
			}
			else
				sourceCode += "vNormal = normalize(rotationMatrix * VertexNormal);\n";
		}

		if (uvMapping)
		{
			if (flags & nzShaderFlags_FlipUVs)
				sourceCode += "vTexCoord = vec2(VertexTexCoord0.x, 1.0 - VertexTexCoord0.y);\n";
			else
				sourceCode += "vTexCoord = VertexTexCoord0;\n";
		}

		if (flags & nzShaderFlags_Lighting)
		{
			if (flags & nzShaderFlags_Instancing)
				sourceCode += "vWorldPos = vec3(InstanceMatrix * vec4(VertexPosition, 1.0));\n";
			else
				sourceCode += "vWorldPos = vec3(WorldMatrix * vec4(VertexPosition, 1.0));\n";
		}

		sourceCode += "}\n";

		return sourceCode;
	}

	NzShader* BuildShader(nzUInt32 flags)
	{
		std::unique_ptr<NzShader> shader(new NzShader);
{'fraction_non_alphanumeric': 0.1668413958364535, 'fraction_numerical': 0.018047027107982627, 'mean_word_length': 2.4489927685950414, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3816013', 'n_tokens_mistral': 10469, 'n_tokens_neox': 8538, 'n_words': 1730}