Added ShaderManager (Experimental)
Former-commit-id: 327e373f2b932e31184e88c5f29bd5bd8fa3ba46
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderStates.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
#include <Nazara/Renderer/ShaderManager.hpp>
|
||||
#include <Nazara/Utility/BufferMapper.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/Skeleton.hpp>
|
||||
@@ -529,7 +529,19 @@ bool NzDebugDrawer::Initialize()
|
||||
{
|
||||
// Shader
|
||||
{
|
||||
shader = NzShaderBuilder::Get(nzShaderFlags_None);
|
||||
NzShaderManagerParams params;
|
||||
params.target = nzShaderTarget_Model;
|
||||
params.flags = 0;
|
||||
params.model.alphaMapping = false;
|
||||
params.model.alphaTest = false;
|
||||
params.model.diffuseMapping = false;
|
||||
params.model.emissiveMapping = false;
|
||||
params.model.lighting = false;
|
||||
params.model.normalMapping = false;
|
||||
params.model.parallaxMapping = false;
|
||||
params.model.specularMapping = false;
|
||||
|
||||
shader = NzShaderManager::Get(params);
|
||||
if (!shader)
|
||||
{
|
||||
NazaraError("Failed to build debug shader");
|
||||
|
||||
@@ -66,7 +66,6 @@ bool NzGLSLShader::Compile()
|
||||
|
||||
CacheUniform(CameraPosition);
|
||||
CacheUniform(InvTargetSize);
|
||||
CacheUniform(LightCount);
|
||||
CacheUniform(MaterialAlphaMap);
|
||||
CacheUniform(MaterialAlphaThreshold);
|
||||
CacheUniform(MaterialAmbient);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <Nazara/Renderer/Material.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
#include <Nazara/Renderer/ShaderManager.hpp>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
@@ -31,13 +31,16 @@ NzMaterial::NzMaterial(NzMaterial&& material)
|
||||
Copy(material);
|
||||
|
||||
// Nous "volons" la référence du matériau
|
||||
material.m_alphaMap = nullptr;
|
||||
material.m_customShader = nullptr;
|
||||
material.m_diffuseMap = nullptr;
|
||||
material.m_emissiveMap = nullptr;
|
||||
material.m_heightMap = nullptr;
|
||||
material.m_normalMap = nullptr;
|
||||
material.m_specularMap = nullptr;
|
||||
material.m_alphaMap.Reset();
|
||||
material.m_diffuseMap.Reset();
|
||||
material.m_emissiveMap.Reset();
|
||||
material.m_heightMap.Reset();
|
||||
material.m_normalMap.Reset();
|
||||
material.m_specularMap.Reset();
|
||||
|
||||
for (unsigned int i = 0; i <= nzShaderTarget_Max; ++i)
|
||||
for (ShaderUnit& unit : material.m_shaders[i])
|
||||
unit.shader.Reset();
|
||||
}
|
||||
|
||||
void NzMaterial::Apply(const NzShader* shader) const
|
||||
@@ -160,19 +163,11 @@ void NzMaterial::Enable(nzRendererParameter renderParameter, bool enable)
|
||||
void NzMaterial::EnableAlphaTest(bool alphaTest)
|
||||
{
|
||||
m_alphaTestEnabled = alphaTest;
|
||||
if (m_alphaTestEnabled)
|
||||
m_shaderFlags |= nzShaderFlags_AlphaTest;
|
||||
else
|
||||
m_shaderFlags &= ~nzShaderFlags_AlphaTest;
|
||||
}
|
||||
|
||||
void NzMaterial::EnableLighting(bool lighting)
|
||||
{
|
||||
m_lightingEnabled = lighting;
|
||||
if (m_lightingEnabled)
|
||||
m_shaderFlags |= nzShaderFlags_Lighting;
|
||||
else
|
||||
m_shaderFlags &= ~nzShaderFlags_Lighting;
|
||||
}
|
||||
|
||||
NzTexture* NzMaterial::GetAlphaMap() const
|
||||
@@ -190,11 +185,6 @@ NzColor NzMaterial::GetAmbientColor() const
|
||||
return m_ambientColor;
|
||||
}
|
||||
|
||||
const NzShader* NzMaterial::GetCustomShader() const
|
||||
{
|
||||
return m_customShader;
|
||||
}
|
||||
|
||||
nzRendererComparison NzMaterial::GetDepthFunc() const
|
||||
{
|
||||
return m_states.depthFunc;
|
||||
@@ -255,9 +245,13 @@ const NzRenderStates& NzMaterial::GetRenderStates() const
|
||||
return m_states;
|
||||
}
|
||||
|
||||
nzUInt32 NzMaterial::GetShaderFlags() const
|
||||
const NzShader* NzMaterial::GetShader(nzShaderTarget target, nzUInt32 flags) const
|
||||
{
|
||||
return m_shaderFlags;
|
||||
const ShaderUnit& unit = m_shaders[target][flags];
|
||||
if (!unit.shader.IsValid())
|
||||
GenerateShader(target, flags);
|
||||
|
||||
return unit.shader;
|
||||
}
|
||||
|
||||
float NzMaterial::GetShininess() const
|
||||
@@ -290,9 +284,39 @@ nzBlendFunc NzMaterial::GetSrcBlend() const
|
||||
return m_states.srcBlend;
|
||||
}
|
||||
|
||||
bool NzMaterial::HasCustomShader() const
|
||||
bool NzMaterial::HasAlphaMap() const
|
||||
{
|
||||
return m_customShader != nullptr;
|
||||
return m_alphaMap.IsValid();
|
||||
}
|
||||
|
||||
bool NzMaterial::HasDiffuseMap() const
|
||||
{
|
||||
return m_diffuseMap.IsValid();
|
||||
}
|
||||
|
||||
bool NzMaterial::HasEmissiveMap() const
|
||||
{
|
||||
return m_emissiveMap.IsValid();
|
||||
}
|
||||
|
||||
bool NzMaterial::HasHeightMap() const
|
||||
{
|
||||
return m_heightMap.IsValid();
|
||||
}
|
||||
|
||||
bool NzMaterial::HasNormalMap() const
|
||||
{
|
||||
return m_normalMap.IsValid();
|
||||
}
|
||||
|
||||
bool NzMaterial::HasSpecularMap() const
|
||||
{
|
||||
return m_specularMap.IsValid();
|
||||
}
|
||||
|
||||
bool NzMaterial::IsAlphaTestEnabled() const
|
||||
{
|
||||
return m_alphaTestEnabled;
|
||||
}
|
||||
|
||||
bool NzMaterial::IsEnabled(nzRendererParameter parameter) const
|
||||
@@ -308,11 +332,6 @@ bool NzMaterial::IsEnabled(nzRendererParameter parameter) const
|
||||
return m_states.parameters[parameter];
|
||||
}
|
||||
|
||||
bool NzMaterial::IsAlphaTestEnabled() const
|
||||
{
|
||||
return m_alphaTestEnabled;
|
||||
}
|
||||
|
||||
bool NzMaterial::IsLightingEnabled() const
|
||||
{
|
||||
return m_lightingEnabled;
|
||||
@@ -336,20 +355,27 @@ bool NzMaterial::LoadFromStream(NzInputStream& stream, const NzMaterialParams& p
|
||||
void NzMaterial::Reset()
|
||||
{
|
||||
m_alphaMap.Reset();
|
||||
m_customShader.Reset();
|
||||
m_diffuseMap.Reset();
|
||||
m_emissiveMap.Reset();
|
||||
m_heightMap.Reset();
|
||||
m_normalMap.Reset();
|
||||
m_specularMap.Reset();
|
||||
|
||||
for (unsigned int i = 0; i <= nzShaderTarget_Max; ++i)
|
||||
{
|
||||
for (ShaderUnit& unit : m_shaders[i])
|
||||
{
|
||||
unit.custom = false;
|
||||
unit.shader.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
m_alphaThreshold = 0.2f;
|
||||
m_alphaTestEnabled = false;
|
||||
m_ambientColor = NzColor(128, 128, 128);
|
||||
m_diffuseColor = NzColor::White;
|
||||
m_diffuseSampler = NzTextureSampler();
|
||||
m_lightingEnabled = true;
|
||||
m_shaderFlags = nzShaderFlags_Lighting;
|
||||
m_shininess = 50.f;
|
||||
m_specularColor = NzColor::White;
|
||||
m_specularSampler = NzTextureSampler();
|
||||
@@ -378,10 +404,8 @@ bool NzMaterial::SetAlphaMap(const NzString& texturePath)
|
||||
void NzMaterial::SetAlphaMap(NzTexture* map)
|
||||
{
|
||||
m_alphaMap = map;
|
||||
if (m_alphaMap)
|
||||
m_shaderFlags |= nzShaderFlags_AlphaMapping;
|
||||
else
|
||||
m_shaderFlags &= ~nzShaderFlags_AlphaMapping;
|
||||
|
||||
InvalidateShaders(nzShaderTarget_Model);
|
||||
}
|
||||
|
||||
void NzMaterial::SetAlphaThreshold(float alphaThreshold)
|
||||
@@ -394,11 +418,6 @@ void NzMaterial::SetAmbientColor(const NzColor& ambient)
|
||||
m_ambientColor = ambient;
|
||||
}
|
||||
|
||||
void NzMaterial::SetCustomShader(const NzShader* shader)
|
||||
{
|
||||
m_customShader = shader;
|
||||
}
|
||||
|
||||
void NzMaterial::SetDepthFunc(nzRendererComparison depthFunc)
|
||||
{
|
||||
m_states.depthFunc = depthFunc;
|
||||
@@ -429,10 +448,8 @@ bool NzMaterial::SetDiffuseMap(const NzString& texturePath)
|
||||
void NzMaterial::SetDiffuseMap(NzTexture* map)
|
||||
{
|
||||
m_diffuseMap = map;
|
||||
if (m_diffuseMap)
|
||||
m_shaderFlags |= nzShaderFlags_DiffuseMapping;
|
||||
else
|
||||
m_shaderFlags &= ~nzShaderFlags_DiffuseMapping;
|
||||
|
||||
InvalidateShaders(nzShaderTarget_Model);
|
||||
}
|
||||
|
||||
void NzMaterial::SetDiffuseSampler(const NzTextureSampler& sampler)
|
||||
@@ -465,10 +482,8 @@ bool NzMaterial::SetEmissiveMap(const NzString& texturePath)
|
||||
void NzMaterial::SetEmissiveMap(NzTexture* map)
|
||||
{
|
||||
m_emissiveMap = map;
|
||||
if (m_emissiveMap)
|
||||
m_shaderFlags |= nzShaderFlags_EmissiveMapping;
|
||||
else
|
||||
m_shaderFlags &= ~nzShaderFlags_EmissiveMapping;
|
||||
|
||||
InvalidateShaders(nzShaderTarget_Model);
|
||||
}
|
||||
|
||||
void NzMaterial::SetFaceCulling(nzFaceCulling culling)
|
||||
@@ -501,6 +516,8 @@ bool NzMaterial::SetHeightMap(const NzString& texturePath)
|
||||
void NzMaterial::SetHeightMap(NzTexture* map)
|
||||
{
|
||||
m_heightMap = map;
|
||||
|
||||
InvalidateShaders(nzShaderTarget_Model);
|
||||
}
|
||||
|
||||
bool NzMaterial::SetNormalMap(const NzString& texturePath)
|
||||
@@ -523,10 +540,8 @@ bool NzMaterial::SetNormalMap(const NzString& texturePath)
|
||||
void NzMaterial::SetNormalMap(NzTexture* map)
|
||||
{
|
||||
m_normalMap = map;
|
||||
if (m_normalMap)
|
||||
m_shaderFlags |= nzShaderFlags_NormalMapping;
|
||||
else
|
||||
m_shaderFlags &= ~nzShaderFlags_NormalMapping;
|
||||
|
||||
InvalidateShaders(nzShaderTarget_Model);
|
||||
}
|
||||
|
||||
void NzMaterial::SetRenderStates(const NzRenderStates& states)
|
||||
@@ -534,6 +549,14 @@ void NzMaterial::SetRenderStates(const NzRenderStates& states)
|
||||
m_states = states;
|
||||
}
|
||||
|
||||
void NzMaterial::SetShader(nzShaderTarget target, nzUInt32 flags, const NzShader* shader)
|
||||
{
|
||||
ShaderUnit& unit = m_shaders[target][flags];
|
||||
|
||||
unit.custom = (shader != nullptr);
|
||||
unit.shader = shader;
|
||||
}
|
||||
|
||||
void NzMaterial::SetShininess(float shininess)
|
||||
{
|
||||
m_shininess = shininess;
|
||||
@@ -564,10 +587,8 @@ bool NzMaterial::SetSpecularMap(const NzString& texturePath)
|
||||
void NzMaterial::SetSpecularMap(NzTexture* map)
|
||||
{
|
||||
m_specularMap = map;
|
||||
if (m_specularMap)
|
||||
m_shaderFlags |= nzShaderFlags_SpecularMapping;
|
||||
else
|
||||
m_shaderFlags &= ~nzShaderFlags_SpecularMapping;
|
||||
|
||||
InvalidateShaders(nzShaderTarget_Model);
|
||||
}
|
||||
|
||||
void NzMaterial::SetSpecularSampler(const NzTextureSampler& sampler)
|
||||
@@ -592,13 +613,16 @@ NzMaterial& NzMaterial::operator=(NzMaterial&& material)
|
||||
Copy(material);
|
||||
|
||||
// Comme ça nous volons la référence du matériau
|
||||
material.m_alphaMap = nullptr;
|
||||
material.m_customShader = nullptr;
|
||||
material.m_diffuseMap = nullptr;
|
||||
material.m_emissiveMap = nullptr;
|
||||
material.m_heightMap = nullptr;
|
||||
material.m_normalMap = nullptr;
|
||||
material.m_specularMap = nullptr;
|
||||
material.m_alphaMap.Reset();
|
||||
material.m_diffuseMap.Reset();
|
||||
material.m_emissiveMap.Reset();
|
||||
material.m_heightMap.Reset();
|
||||
material.m_normalMap.Reset();
|
||||
material.m_specularMap.Reset();
|
||||
|
||||
for (unsigned int i = 0; i <= nzShaderTarget_Max; ++i)
|
||||
for (ShaderUnit& unit : material.m_shaders[i])
|
||||
unit.shader.Reset();
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -611,18 +635,20 @@ NzMaterial* NzMaterial::GetDefault()
|
||||
void NzMaterial::Copy(const NzMaterial& material)
|
||||
{
|
||||
m_alphaMap.Reset();
|
||||
m_customShader.Reset();
|
||||
m_diffuseMap.Reset();
|
||||
m_emissiveMap.Reset();
|
||||
m_heightMap.Reset();
|
||||
m_normalMap.Reset();
|
||||
m_specularMap.Reset();
|
||||
|
||||
for (unsigned int i = 0; i <= nzShaderTarget_Max; ++i)
|
||||
for (ShaderUnit& unit : m_shaders[i])
|
||||
unit.shader.Reset();
|
||||
|
||||
std::memcpy(this, &material, sizeof(NzMaterial)); // Autorisé dans notre cas, et bien plus rapide
|
||||
|
||||
// Ensuite une petite astuce pour récupérer correctement les références
|
||||
m_alphaMap.Release();
|
||||
m_customShader.Release();
|
||||
m_diffuseMap.Release();
|
||||
m_emissiveMap.Release();
|
||||
m_heightMap.Release();
|
||||
@@ -630,11 +656,63 @@ void NzMaterial::Copy(const NzMaterial& material)
|
||||
m_specularMap.Release();
|
||||
|
||||
m_alphaMap = material.m_alphaMap;
|
||||
m_customShader = material.m_customShader;
|
||||
m_diffuseMap = material.m_diffuseMap;
|
||||
m_emissiveMap = material.m_emissiveMap;
|
||||
m_heightMap = material.m_heightMap;
|
||||
m_normalMap = material.m_normalMap;
|
||||
m_specularMap = material.m_specularMap;
|
||||
|
||||
for (unsigned int i = 0; i <= nzShaderTarget_Max; ++i)
|
||||
{
|
||||
for (unsigned int j = 0; j <= nzShaderFlags_Max; ++j)
|
||||
{
|
||||
NzShaderConstRef& shader = m_shaders[i][j].shader;
|
||||
|
||||
shader.Release();
|
||||
shader = material.m_shaders[i][j].shader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NzMaterial::GenerateShader(nzShaderTarget target, nzUInt32 flags) const
|
||||
{
|
||||
NzShaderManagerParams params;
|
||||
params.target = target;
|
||||
params.flags = flags;
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case nzShaderTarget_FullscreenQuad:
|
||||
params.fullscreenQuad.alphaMapping = m_alphaMap.IsValid();
|
||||
params.fullscreenQuad.alphaTest = m_alphaTestEnabled;
|
||||
params.fullscreenQuad.diffuseMapping = m_diffuseMap.IsValid();
|
||||
break;
|
||||
|
||||
case nzShaderTarget_Model:
|
||||
params.model.alphaMapping = m_alphaMap.IsValid();
|
||||
params.model.alphaTest = m_alphaTestEnabled;
|
||||
params.model.diffuseMapping = m_diffuseMap.IsValid();
|
||||
params.model.emissiveMapping = m_emissiveMap.IsValid();
|
||||
params.model.lighting = m_lightingEnabled;
|
||||
params.model.normalMapping = m_normalMap.IsValid();
|
||||
params.model.parallaxMapping = m_heightMap.IsValid();
|
||||
params.model.specularMapping = m_specularMap.IsValid();
|
||||
break;
|
||||
|
||||
case nzShaderTarget_None:
|
||||
break;
|
||||
}
|
||||
|
||||
m_shaders[target][flags].shader = NzShaderManager::Get(params);
|
||||
}
|
||||
|
||||
void NzMaterial::InvalidateShaders(nzShaderTarget target)
|
||||
{
|
||||
for (ShaderUnit& unit : m_shaders[target])
|
||||
{
|
||||
if (!unit.custom)
|
||||
unit.shader.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool NzMaterial::Initialize()
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <Nazara/Renderer/Material.hpp>
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
#include <Nazara/Renderer/ShaderManager.hpp>
|
||||
#include <Nazara/Renderer/Loaders/Texture.hpp>
|
||||
#include <Nazara/Utility/AbstractBuffer.hpp>
|
||||
#include <Nazara/Utility/IndexBuffer.hpp>
|
||||
@@ -37,10 +37,10 @@ namespace
|
||||
{
|
||||
Update_None = 0,
|
||||
|
||||
Update_Matrices = 0x01,
|
||||
Update_Shader = 0x02,
|
||||
Update_Textures = 0x04,
|
||||
Update_VAO = 0x08,
|
||||
Update_Matrices = 0x1,
|
||||
Update_Shader = 0x2,
|
||||
Update_Textures = 0x4,
|
||||
Update_VAO = 0x8
|
||||
};
|
||||
|
||||
struct MatrixUnit
|
||||
@@ -500,6 +500,8 @@ bool NzRenderer::Initialize()
|
||||
if (!NzOpenGL::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize OpenGL");
|
||||
Uninitialize();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -616,9 +618,9 @@ bool NzRenderer::Initialize()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NzShaderBuilder::Initialize())
|
||||
if (!NzShaderManager::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize shader builder");
|
||||
NazaraError("Failed to initialize shader manager");
|
||||
Uninitialize();
|
||||
|
||||
return false;
|
||||
@@ -1180,7 +1182,7 @@ void NzRenderer::Uninitialize()
|
||||
NzLoaders_Texture_Unregister();
|
||||
|
||||
NzTextureSampler::Uninitialize();
|
||||
NzShaderBuilder::Uninitialize();
|
||||
NzShaderManager::Uninitialize();
|
||||
NzMaterial::Uninitialize();
|
||||
NzDebugDrawer::Uninitialize();
|
||||
|
||||
|
||||
@@ -1,536 +0,0 @@
|
||||
// Copyright (C) 2013 Jérôme Leclercq
|
||||
// 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>
|
||||
|
||||
///TODO: Remplacer par les ShaderNode
|
||||
|
||||
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 textureLookupKW = (glsl140) ? "texture" : "texture2D";
|
||||
|
||||
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"
|
||||
"\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[" NazaraStringifyMacro(NAZARA_RENDERER_SHADER_MAX_LIGHTCOUNT) "];\n"
|
||||
"uniform vec4 MaterialAmbient;\n";
|
||||
}
|
||||
|
||||
if (flags & nzShaderFlags_AlphaMapping)
|
||||
sourceCode += "uniform sampler2D MaterialAlphaMap;\n";
|
||||
|
||||
if (flags & nzShaderFlags_AlphaTest)
|
||||
sourceCode += "uniform float MaterialAlphaThreshold;\n";
|
||||
|
||||
sourceCode += "uniform vec4 MaterialDiffuse;\n";
|
||||
|
||||
if (flags & nzShaderFlags_DiffuseMapping)
|
||||
sourceCode += "uniform sampler2D MaterialDiffuseMap;\n";
|
||||
|
||||
if (flags & nzShaderFlags_EmissiveMapping)
|
||||
sourceCode += "uniform sampler2D MaterialEmissiveMap;\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";
|
||||
|
||||
sourceCode += "float alpha = MaterialDiffuse.a";
|
||||
if (flags & nzShaderFlags_AlphaMapping)
|
||||
sourceCode += '*' + textureLookupKW + "(MaterialAlphaMap, vTexCoord).r";
|
||||
|
||||
sourceCode += ";\n";
|
||||
|
||||
if (flags & nzShaderFlags_AlphaTest)
|
||||
{
|
||||
sourceCode += "if (alpha < MaterialAlphaThreshold)\n"
|
||||
"discard;\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(" + textureLookupKW + "(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 += "vec3 lighting = light";
|
||||
|
||||
if (flags & nzShaderFlags_DiffuseMapping)
|
||||
sourceCode += "*vec3(" + textureLookupKW + "(MaterialDiffuseMap, vTexCoord))";
|
||||
|
||||
if (flags & nzShaderFlags_SpecularMapping)
|
||||
sourceCode += " + si*vec3(" + textureLookupKW + "(MaterialSpecularMap, vTexCoord))"; // Utiliser l'alpha de MaterialSpecular n'aurait aucun sens
|
||||
|
||||
sourceCode += ";\n";
|
||||
|
||||
if (flags & nzShaderFlags_EmissiveMapping)
|
||||
{
|
||||
sourceCode += "float intensity = light.r*0.3 + light.g*0.59 + light.b*0.11;\n"
|
||||
"vec3 emission = vec3(" + textureLookupKW + "(MaterialEmissiveMap, vTexCoord));\n"
|
||||
+ fragmentColorKW + " = vec4(mix(lighting, emission, clamp(1.0 - 3.0*intensity, 0.0, 1.0)), alpha);\n";
|
||||
}
|
||||
else
|
||||
sourceCode += fragmentColorKW + " = vec4(lighting, alpha);\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceCode += fragmentColorKW + " = MaterialDiffuse";
|
||||
|
||||
if (flags & nzShaderFlags_DiffuseMapping)
|
||||
sourceCode += "*vec4(" + textureLookupKW + "(MaterialDiffuseMap, vTexCoord).rgb, alpha);\n";
|
||||
|
||||
sourceCode += ";\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 VertexTexCoord;\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(VertexTexCoord.x, 1.0 - VertexTexCoord.y);\n";
|
||||
else
|
||||
sourceCode += "vTexCoord = VertexTexCoord;\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);
|
||||
if (!shader->Create(nzShaderLanguage_GLSL))
|
||||
{
|
||||
NazaraError("Failed to create shader");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NzString fragmentSource = BuildFragmentShaderSource(flags);
|
||||
if (!shader->Load(nzShaderType_Fragment, fragmentSource))
|
||||
{
|
||||
NazaraError("Failed to load fragment shader: " + shader->GetLog());
|
||||
NazaraNotice("Fragment shader source: ");
|
||||
NazaraNotice(fragmentSource);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NzString vertexSource = BuildVertexShaderSource(flags);
|
||||
if (!shader->Load(nzShaderType_Vertex, vertexSource))
|
||||
{
|
||||
NazaraError("Failed to load vertex shader: " + shader->GetLog());
|
||||
NazaraNotice("Vertex shader source: ");
|
||||
NazaraNotice(vertexSource);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
NazaraNotice("Fragment shader source: ");
|
||||
NazaraNotice(fragmentSource);
|
||||
NazaraNotice("Vertex shader source: ");
|
||||
NazaraNotice(vertexSource);
|
||||
#endif
|
||||
|
||||
if (!shader->Compile())
|
||||
{
|
||||
NazaraError("Failed to compile shader: " + shader->GetLog());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shader->SetFlags(flags);
|
||||
shader->SetPersistent(false);
|
||||
|
||||
return shader.release();
|
||||
}
|
||||
}
|
||||
|
||||
const NzShader* NzShaderBuilder::Get(nzUInt32 flags)
|
||||
{
|
||||
auto it = s_shaders.find(flags);
|
||||
if (it == s_shaders.end())
|
||||
{
|
||||
// Alors nous créons le shader
|
||||
NzShader* shader = BuildShader(flags);
|
||||
if (!shader)
|
||||
{
|
||||
NazaraWarning("Failed to build shader (flags: 0x" + NzString::Number(flags, 16) + "), using default one...");
|
||||
|
||||
shader = s_shaders[0]; // Shader par défaut
|
||||
}
|
||||
|
||||
s_shaders[flags] = shader;
|
||||
|
||||
return shader;
|
||||
}
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool NzShaderBuilder::Initialize()
|
||||
{
|
||||
NzShader* shader = BuildShader(0);
|
||||
if (!shader)
|
||||
{
|
||||
NazaraInternalError("Failed to build default shader");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_shaders[0] = shader;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzShaderBuilder::Uninitialize()
|
||||
{
|
||||
s_shaders.clear();
|
||||
}
|
||||
841
src/Nazara/Renderer/ShaderManager.cpp
Normal file
841
src/Nazara/Renderer/ShaderManager.cpp
Normal file
@@ -0,0 +1,841 @@
|
||||
// Copyright (C) 2013 Jérôme Leclercq
|
||||
// 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/Core/Log.hpp>
|
||||
#include <Nazara/Renderer/ShaderManager.hpp>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ParamsHash
|
||||
{
|
||||
std::size_t operator()(const NzShaderManagerParams& params) const
|
||||
{
|
||||
static_assert(nzShaderTarget_Max < 0x4, "Maximum shader target takes more than 2 bits");
|
||||
|
||||
std::size_t h = (params.target << 0) | // 2 bits
|
||||
(params.flags << 2); // 8 bits
|
||||
|
||||
switch (params.target)
|
||||
{
|
||||
case nzShaderTarget_FullscreenQuad:
|
||||
h |= (params.fullscreenQuad.alphaMapping << 10) | // 1 bit
|
||||
(params.fullscreenQuad.alphaTest << 11) | // 1 bit
|
||||
(params.fullscreenQuad.diffuseMapping << 12); // 1 bit
|
||||
break;
|
||||
|
||||
case nzShaderTarget_Model:
|
||||
h |= (params.model.alphaMapping << 10) | // 1 bit
|
||||
(params.model.alphaTest << 11) | // 1 bit
|
||||
(params.model.diffuseMapping << 12) | // 1 bit
|
||||
(params.model.emissiveMapping << 13) | // 1 bit
|
||||
(params.model.lighting << 14) | // 1 bit
|
||||
(params.model.normalMapping << 15) | // 1 bit
|
||||
(params.model.parallaxMapping << 16) | // 1 bit
|
||||
(params.model.specularMapping << 17); // 1 bit
|
||||
break;
|
||||
|
||||
case nzShaderTarget_None:
|
||||
break;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct ParamsEquality
|
||||
{
|
||||
bool operator()(const NzShaderManagerParams& first, const NzShaderManagerParams& second) const
|
||||
{
|
||||
if (first.target != second.target || first.flags != second.flags)
|
||||
return false;
|
||||
|
||||
switch (first.target)
|
||||
{
|
||||
case nzShaderTarget_FullscreenQuad:
|
||||
return std::memcmp(&first.fullscreenQuad, &second.fullscreenQuad, sizeof(NzShaderManagerParams::FullscreenQuad)) == 0;
|
||||
|
||||
case nzShaderTarget_Model:
|
||||
return std::memcmp(&first.model, &second.model, sizeof(NzShaderManagerParams::Model)) == 0;
|
||||
|
||||
case nzShaderTarget_None:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<NzShaderManagerParams, NzShaderRef, ParamsHash, ParamsEquality> s_shaders;
|
||||
NzString s_inKW;
|
||||
NzString s_outKW;
|
||||
NzString s_fragmentColorKW;
|
||||
NzString s_textureLookupKW;
|
||||
bool s_earlyFragmentTest;
|
||||
bool s_glsl140;
|
||||
unsigned int s_glslVersion;
|
||||
}
|
||||
|
||||
const NzShader* NzShaderManager::Get(const NzShaderManagerParams& params)
|
||||
{
|
||||
auto it = s_shaders.find(params);
|
||||
if (it == s_shaders.end())
|
||||
{
|
||||
// Alors nous gébérons le shader
|
||||
NzShader* shader = GenerateShader(params);
|
||||
if (!shader)
|
||||
{
|
||||
NazaraWarning("Failed to build shader, using default one...");
|
||||
|
||||
NzShaderManagerParams defaultParams;
|
||||
defaultParams.flags = params.flags;
|
||||
defaultParams.target = nzShaderTarget_None;
|
||||
|
||||
shader = s_shaders[defaultParams]; // Shader par défaut
|
||||
}
|
||||
|
||||
s_shaders[params] = shader;
|
||||
|
||||
return shader;
|
||||
}
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
NzString NzShaderManager::BuildFragmentCode(const NzShaderManagerParams& params)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (params.target > nzShaderTarget_Max)
|
||||
{
|
||||
NazaraError("Shader target out of enum");
|
||||
return NzString();
|
||||
}
|
||||
#endif
|
||||
|
||||
NzString source;
|
||||
source.Reserve(2048); // Le shader peut faire plus, mais cela évite déjà beaucoup de petites allocations
|
||||
|
||||
/********************Header********************/
|
||||
source += "#version ";
|
||||
source += NzString::Number(s_glslVersion);
|
||||
source += "\n\n";
|
||||
|
||||
if (s_earlyFragmentTest)
|
||||
source += "layout(early_fragment_tests) in;" "\n\n";
|
||||
|
||||
switch (params.target)
|
||||
{
|
||||
case nzShaderTarget_FullscreenQuad:
|
||||
{
|
||||
/********************Entrant********************/
|
||||
if (params.fullscreenQuad.alphaMapping || params.fullscreenQuad.diffuseMapping)
|
||||
source += s_inKW + " vec2 vTexCoord;" "\n\n";
|
||||
|
||||
/********************Sortant********************/
|
||||
if (s_glsl140)
|
||||
source += "out vec4 RenderTarget0;" "\n\n";
|
||||
|
||||
/********************Uniformes********************/
|
||||
if (params.fullscreenQuad.alphaMapping)
|
||||
source += "uniform sampler2D MaterialAlphaMap;" "\n";
|
||||
|
||||
if (params.fullscreenQuad.alphaTest)
|
||||
source += "uniform float MaterialAlphaThreshold;" "\n";
|
||||
|
||||
source += "uniform vec4 MaterialDiffuse;" "\n";
|
||||
|
||||
if (params.fullscreenQuad.diffuseMapping)
|
||||
source += "uniform sampler2D MaterialDiffuseMap;" "\n";
|
||||
|
||||
source += '\n';
|
||||
|
||||
/********************Fonctions********************/
|
||||
source += "void main()" "\n"
|
||||
"{" "\n";
|
||||
|
||||
source += "\t" "vec4 fragmentColor = MaterialDiffuse";
|
||||
if (params.fullscreenQuad.diffuseMapping)
|
||||
source += '*' + s_textureLookupKW + "(MaterialDiffuseMap, vTexCoord)";
|
||||
|
||||
source += ";" "\n"
|
||||
"\t" "float fragmentAlpha = ";
|
||||
|
||||
if (params.fullscreenQuad.diffuseMapping)
|
||||
source += "fragmentColor.a";
|
||||
else
|
||||
source += "MaterialDiffuse.a";
|
||||
|
||||
if (params.fullscreenQuad.alphaMapping)
|
||||
source += '*' + s_textureLookupKW + "(MaterialAlphaMap, vTexCoord).r";
|
||||
|
||||
source += ";" "\n";
|
||||
|
||||
if (params.fullscreenQuad.alphaMapping)
|
||||
{
|
||||
source += "if (fragmentAlpha < MaterialAlphaThreshold)" "\n"
|
||||
"\t" "discard;" "\n";
|
||||
}
|
||||
|
||||
source += "\t" "RenderTarget0 = fragmentColor;" "\n"
|
||||
"}" "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case nzShaderTarget_Model:
|
||||
{
|
||||
//bool parallaxMapping = (params.model.lighting && params.model.parallaxMapping);
|
||||
bool uvMapping = (params.model.alphaMapping || params.model.diffuseMapping || params.model.normalMapping || params.model.specularMapping);
|
||||
|
||||
if (params.model.lighting)
|
||||
{
|
||||
source += "#define LIGHT_DIRECTIONAL 0" "\n"
|
||||
"#define LIGHT_POINT 1" "\n"
|
||||
"#define LIGHT_SPOT 2" "\n\n";
|
||||
}
|
||||
|
||||
/********************Entrant********************/
|
||||
if (params.model.lighting)
|
||||
{
|
||||
if (params.model.normalMapping)
|
||||
source += s_inKW + " mat3 vLightToWorld;" "\n";
|
||||
else
|
||||
source += s_inKW + " vec3 vNormal;" "\n";
|
||||
}
|
||||
|
||||
if (uvMapping)
|
||||
source += s_inKW + " vec2 vTexCoord;" "\n";
|
||||
|
||||
if (params.model.lighting)
|
||||
source += s_inKW + " vec3 vWorldPos;" "\n";
|
||||
|
||||
if (params.model.lighting || uvMapping)
|
||||
source += '\n';
|
||||
|
||||
/********************Sortant********************/
|
||||
if (s_glsl140)
|
||||
source += "out vec4 RenderTarget0;" "\n\n";
|
||||
|
||||
/********************Uniformes********************/
|
||||
if (params.model.lighting)
|
||||
{
|
||||
source += "struct Light" "\n"
|
||||
"{" "\n"
|
||||
"\t" "int type;" "\n"
|
||||
"\t" "vec4 ambient;" "\n"
|
||||
"\t" "vec4 diffuse;" "\n"
|
||||
"\t" "vec4 specular;" "\n\n"
|
||||
|
||||
"\t" "vec4 parameters1;" "\n"
|
||||
"\t" "vec4 parameters2;" "\n"
|
||||
"\t" "vec2 parameters3;" "\n"
|
||||
"};" "\n\n"
|
||||
|
||||
"uniform vec3 CameraPosition;" "\n"
|
||||
"uniform Light Lights[3];" "\n"
|
||||
"uniform vec4 MaterialAmbient;" "\n";
|
||||
}
|
||||
|
||||
if (params.model.alphaMapping)
|
||||
source += "uniform sampler2D MaterialAlphaMap;" "\n";
|
||||
|
||||
if (params.model.alphaTest)
|
||||
source += "uniform float MaterialAlphaThreshold;" "\n";
|
||||
|
||||
source += "uniform vec4 MaterialDiffuse;" "\n";
|
||||
|
||||
if (params.model.diffuseMapping)
|
||||
source += "uniform sampler2D MaterialDiffuseMap;" "\n";
|
||||
|
||||
if (params.model.emissiveMapping)
|
||||
source += "uniform sampler2D MaterialEmissiveMap;" "\n";
|
||||
|
||||
if (params.model.lighting)
|
||||
{
|
||||
if (params.model.normalMapping)
|
||||
source += "uniform sampler2D MaterialNormalMap;" "\n";
|
||||
|
||||
source += "uniform float MaterialShininess;" "\n"
|
||||
"uniform vec4 MaterialSpecular;" "\n";
|
||||
|
||||
if (params.model.specularMapping)
|
||||
source += "uniform sampler2D MaterialSpecularMap;" "\n";
|
||||
|
||||
source += "uniform vec4 SceneAmbient;" "\n";
|
||||
}
|
||||
|
||||
source += '\n';
|
||||
|
||||
/********************Fonctions********************/
|
||||
source += "void main()" "\n"
|
||||
"{" "\n";
|
||||
|
||||
/*if (!parallaxMapping)
|
||||
{*/
|
||||
source += "\t" "vec4 fragmentColor = MaterialDiffuse";
|
||||
if (params.model.diffuseMapping)
|
||||
source += '*' + s_textureLookupKW + "(MaterialDiffuseMap, vTexCoord)";
|
||||
|
||||
source += ";" "\n";
|
||||
//}
|
||||
|
||||
if (params.model.alphaMapping)
|
||||
{
|
||||
source += "\t" "fragmentColor.a *= ";
|
||||
|
||||
if (params.model.alphaMapping)
|
||||
source += s_textureLookupKW + "(MaterialAlphaMap, vTexCoord).r";
|
||||
|
||||
/*if (parallaxMapping && params.model.diffuseMapping)
|
||||
source += '*' + s_textureLookupKW + "(MaterialDiffuseMap, vTexCoord).a";*/
|
||||
|
||||
source += ";" "\n";
|
||||
}
|
||||
|
||||
if (params.model.alphaTest)
|
||||
{
|
||||
source += "if (diffuseColor.a < MaterialAlphaThreshold)" "\n"
|
||||
"\t" "discard;" "\n";
|
||||
}
|
||||
|
||||
if (params.model.lighting)
|
||||
{
|
||||
source += "\t" "vec3 lightColor = vec3(0.0);" "\n";
|
||||
|
||||
if (params.model.specularMapping)
|
||||
source += "\t" "vec3 specularColor = vec3(0.0);" "\n";
|
||||
|
||||
if (params.model.normalMapping)
|
||||
source += "\t" "vec3 normal = normalize(vLightToWorld * (2.0 * vec3(" + s_textureLookupKW + "(MaterialNormalMap, vTexCoord)) - 1.0));" "\n";
|
||||
else
|
||||
source += "\t" "vec3 normal = normalize(vNormal);" "\n";
|
||||
|
||||
source += '\n';
|
||||
|
||||
source += "\t" "if (MaterialShininess > 0.0)" "\n"
|
||||
"\t" "{" "\n"
|
||||
"\t\t" "vec3 eyeVec = normalize(CameraPosition - vWorldPos);" "\n\n"
|
||||
|
||||
"\t\t" "for (int i = 0; i < 3; ++i)" "\n"
|
||||
"\t\t" "{" "\n";
|
||||
|
||||
if (s_glsl140)
|
||||
{
|
||||
source += "\t\t\t" "switch (Lights[i].type)" "\n"
|
||||
"\t\t\t" "{" "\n"
|
||||
"\t\t\t\t" "case LIGHT_DIRECTIONAL:" "\n";
|
||||
}
|
||||
else // Le GLSL 110 n'a pas d'instruction switch
|
||||
source += "\t\t\t" "if (Lights[i].type == LIGHT_DIRECTIONAL)" "\n";
|
||||
|
||||
// Directional Light
|
||||
source += "\t\t\t\t" "{" "\n"
|
||||
"\t\t\t\t\t" "vec3 lightDir = normalize(-Lights[i].parameters1.xyz);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "float lambert = max(dot(normal, lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "vec3 reflection = reflect(-lightDir, normal);" "\n"
|
||||
"\t\t\t\t\t" "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);" "\n";
|
||||
|
||||
if (params.model.specularMapping)
|
||||
source += "\t\t\t\t\t" "specularColor";
|
||||
else
|
||||
source += "\t\t\t\t\t" "lightColor";
|
||||
|
||||
source += " += specular * Lights[i].specular.rgb * MaterialSpecular.rgb;" "\n";
|
||||
|
||||
if (s_glsl140)
|
||||
{
|
||||
source += "\t\t\t\t\t" "break;" "\n"
|
||||
"\t\t\t\t" "}" "\n\n"
|
||||
|
||||
"\t\t\t\t" "case LIGHT_POINT:" "\n";
|
||||
}
|
||||
else
|
||||
source += "\t\t\t" "}" "\n"
|
||||
"\t\t\t" "else if (Lights[i].type == LIGHT_POINT)" "\n";
|
||||
|
||||
// Point Light
|
||||
source += "\t\t\t\t" "{" "\n"
|
||||
"\t\t\t\t\t" "vec3 lightDir = Lights[i].parameters1.xyz - vWorldPos;" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "float att = max(Lights[i].parameters1.w - Lights[i].parameters2.x*length(lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += att * Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);" "\n"
|
||||
|
||||
"\t\t\t\t\t" "lightDir = normalize(lightDir);" "\n"
|
||||
"\t\t\t\t\t" "float lambert = max(dot(normal, lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += att * lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "vec3 reflection = reflect(-lightDir, normal);" "\n"
|
||||
"\t\t\t\t\t" "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);" "\n";
|
||||
|
||||
if (params.model.specularMapping)
|
||||
source += "\t\t\t\t\t" "specularColor";
|
||||
else
|
||||
source += "\t\t\t\t\t" "lightColor";
|
||||
|
||||
source += " += att * specular * Lights[i].specular.rgb * MaterialSpecular.rgb;" "\n";
|
||||
|
||||
if (s_glsl140)
|
||||
{
|
||||
source += "\t\t\t\t\t" "break;" "\n"
|
||||
"\t\t\t\t" "}" "\n\n"
|
||||
|
||||
"\t\t\t\t" "case LIGHT_SPOT:" "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
source += "\t\t\t" "}" "\n"
|
||||
"\t\t\t" "else if (Lights[i].type == LIGHT_SPOT)" "\n";
|
||||
}
|
||||
|
||||
// Spot Light
|
||||
source += "\t\t\t\t" "{" "\n"
|
||||
"\t\t\t\t\t" "vec3 lightDir = Lights[i].parameters1.xyz - vWorldPos;" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "float att = max(Lights[i].parameters1.w - Lights[i].parameters2.w*length(lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += att * Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "lightDir = normalize(lightDir);" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "float curAngle = dot(Lights[i].parameters2.xyz, -lightDir);" "\n"
|
||||
"\t\t\t\t\t" "float outerAngle = Lights[i].parameters3.y;" "\n"
|
||||
"\t\t\t\t\t" "float innerMinusOuterAngle = Lights[i].parameters3.x - outerAngle;" "\n"
|
||||
"\t\t\t\t\t" "float lambert = max(dot(normal, lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "att *= max((curAngle - outerAngle) / innerMinusOuterAngle, 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += att * lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "vec3 reflection = reflect(-lightDir, normal);" "\n"
|
||||
"\t\t\t\t\t" "float specular = pow(max(dot(reflection, eyeVec), 0.0), MaterialShininess);" "\n";
|
||||
|
||||
if (params.model.specularMapping)
|
||||
source += "\t\t\t\t\t" "specularColor";
|
||||
else
|
||||
source += "\t\t\t\t\t" "lightColor";
|
||||
|
||||
source += " += att * specular * Lights[i].specular.rgb * MaterialSpecular.rgb;\n";
|
||||
|
||||
if (s_glsl140)
|
||||
{
|
||||
source += "\t\t\t\t\t" "break;" "\n"
|
||||
"\t\t\t\t" "}" "\n\n"
|
||||
"\t\t\t\t" "default:" "\n"
|
||||
"\t\t\t\t\t" "break;" "\n"
|
||||
"\t\t\t" "}" "\n";
|
||||
}
|
||||
else
|
||||
source += "\t\t\t" "}" "\n";
|
||||
|
||||
source += "\t\t" "}" "\n"
|
||||
"\t" "}" "\n"
|
||||
"\t" "else" "\n"
|
||||
"\t" "{" "\n";
|
||||
|
||||
source += "\t\t" "for (int i = 0; i < 3; ++i)" "\n"
|
||||
"\t\t" "{" "\n";
|
||||
|
||||
if (s_glsl140)
|
||||
{
|
||||
source += "\t\t\t" "switch (Lights[i].type)" "\n"
|
||||
"\t\t\t" "{" "\n"
|
||||
"\t\t\t\t" "case LIGHT_DIRECTIONAL:" "\n";
|
||||
}
|
||||
else // Le GLSL 110 n'a pas d'instruction switch
|
||||
source += "\t\t\t" "if (Lights[i].type == LIGHT_DIRECTIONAL)" "\n";
|
||||
|
||||
// Directional Light
|
||||
source += "\t\t\t\t" "{" "\n"
|
||||
"\t\t\t\t\t" "vec3 lightDir = normalize(-Lights[i].parameters1.xyz);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "float lambert = max(dot(normal, lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;" "\n\n";
|
||||
|
||||
if (s_glsl140)
|
||||
{
|
||||
source += "\t\t\t\t\t" "break;" "\n"
|
||||
"\t\t\t\t" "}" "\n\n"
|
||||
|
||||
"\t\t\t\t" "case LIGHT_POINT:" "\n";
|
||||
}
|
||||
else
|
||||
source += "\t\t\t" "}" "\n"
|
||||
"\t\t\t" "else if (Lights[i].type == LIGHT_POINT)" "\n";
|
||||
|
||||
// Point Light
|
||||
source += "\t\t\t\t" "{" "\n"
|
||||
"\t\t\t\t\t" "vec3 lightDir = Lights[i].parameters1.xyz - vWorldPos;" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "float att = max(Lights[i].parameters1.w - Lights[i].parameters2.x*length(lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += att * Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);" "\n"
|
||||
|
||||
"\t\t\t\t\t" "lightDir = normalize(lightDir);" "\n"
|
||||
"\t\t\t\t\t" "float lambert = max(dot(normal, lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += att * lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;" "\n\n";
|
||||
|
||||
if (s_glsl140)
|
||||
{
|
||||
source += "\t\t\t\t\t" "break;" "\n"
|
||||
"\t\t\t\t" "}" "\n\n"
|
||||
|
||||
"\t\t\t\t" "case LIGHT_SPOT:" "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
source += "\t\t\t" "}" "\n"
|
||||
"\t\t\t" "else if (Lights[i].type == LIGHT_SPOT)" "\n";
|
||||
}
|
||||
|
||||
// Spot Light
|
||||
source += "\t\t\t\t" "{" "\n"
|
||||
"\t\t\t\t\t" "vec3 lightDir = Lights[i].parameters1.xyz - vWorldPos;" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "float att = max(Lights[i].parameters1.w - Lights[i].parameters2.w*length(lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += att * Lights[i].ambient.rgb * (MaterialAmbient.rgb + SceneAmbient.rgb);" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "lightDir = normalize(lightDir);" "\n\n"
|
||||
|
||||
"\t\t\t\t\t" "float curAngle = dot(Lights[i].parameters2.xyz, -lightDir);" "\n"
|
||||
"\t\t\t\t\t" "float outerAngle = Lights[i].parameters3.y;" "\n"
|
||||
"\t\t\t\t\t" "float innerMinusOuterAngle = Lights[i].parameters3.x - outerAngle;" "\n"
|
||||
"\t\t\t\t\t" "float lambert = max(dot(normal, lightDir), 0.0);" "\n"
|
||||
"\t\t\t\t\t" "att *= max((curAngle - outerAngle) / innerMinusOuterAngle, 0.0);" "\n"
|
||||
"\t\t\t\t\t" "lightColor += att * lambert * Lights[i].diffuse.rgb * MaterialDiffuse.rgb;" "\n\n";
|
||||
|
||||
if (s_glsl140)
|
||||
{
|
||||
source += "\t\t\t\t\t" "break;" "\n"
|
||||
"\t\t\t\t" "}" "\n\n"
|
||||
"\t\t\t\t" "default:" "\n"
|
||||
"\t\t\t\t\t" "break;" "\n"
|
||||
"\t\t\t" "}" "\n";
|
||||
}
|
||||
else
|
||||
source += "\t\t\t" "}" "\n";
|
||||
|
||||
source += "\t\t" "}" "\n"
|
||||
"\t" "}" "\n\n"
|
||||
|
||||
"\t" "fragmentColor *= vec4(lightColor";
|
||||
|
||||
if (params.model.specularMapping)
|
||||
source += "+ specularColor*" + s_textureLookupKW + "(MaterialSpecularMap, vTexCoord).rgb"; // Utiliser l'alpha de MaterialSpecular n'aurait aucun sens
|
||||
|
||||
source += ", 1.0);" "\n";
|
||||
|
||||
if (params.model.emissiveMapping)
|
||||
{
|
||||
if (params.model.specularMapping)
|
||||
source += "\t" "float lightIntensity = dot(lightColor + specularColor, vec3(0.3, 0.59, 0.11));" "\n";
|
||||
else
|
||||
source += "\t" "float lightIntensity = dot(lightColor, vec3(0.3, 0.59, 0.11));" "\n";
|
||||
|
||||
source += "\t" "vec3 emissionColor = MaterialDiffuse.rgb*" + s_textureLookupKW + "(MaterialEmissiveMap, vTexCoord).rgb;" "\n"
|
||||
"\t" + s_fragmentColorKW + " = vec4(mix(fragmentColor.rgb, emissionColor, clamp(1.0 - 3.0*lightIntensity, 0.0, 1.0)), fragmentColor.a);" "\n";
|
||||
}
|
||||
else
|
||||
source += '\t' + s_fragmentColorKW + " = fragmentColor;" "\n";
|
||||
}
|
||||
else
|
||||
source += '\t' + s_fragmentColorKW + " = fragmentColor;" "\n";
|
||||
|
||||
source += "}" "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case nzShaderTarget_None:
|
||||
{
|
||||
/********************Sortant********************/
|
||||
if (s_glsl140)
|
||||
source += "out vec4 RenderTarget0;" "\n\n";
|
||||
|
||||
/********************Uniformes********************/
|
||||
source += "uniform vec4 MaterialDiffuse;" "\n\n";
|
||||
|
||||
/********************Fonctions********************/
|
||||
source += "void main()" "\n"
|
||||
"{" "\n";
|
||||
source += '\t' + s_fragmentColorKW + " = MaterialDiffuse;" "\n";
|
||||
source += "}" "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
NzString NzShaderManager::BuildVertexCode(const NzShaderManagerParams& params)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (params.target > nzShaderTarget_Max)
|
||||
{
|
||||
NazaraError("Shader target out of enum");
|
||||
return NzString();
|
||||
}
|
||||
#endif
|
||||
|
||||
NzString source;
|
||||
source.Reserve(2048); // Le shader peut faire plus, mais cela évite déjà beaucoup de petites allocations
|
||||
|
||||
/********************Header********************/
|
||||
source += "#version ";
|
||||
source += NzString::Number(s_glslVersion);
|
||||
source += "\n\n";
|
||||
|
||||
switch (params.target)
|
||||
{
|
||||
case nzShaderTarget_FullscreenQuad:
|
||||
{
|
||||
bool uvMapping = (params.fullscreenQuad.alphaMapping || params.fullscreenQuad.diffuseMapping);
|
||||
|
||||
/********************Entrant********************/
|
||||
source += s_inKW + " vec2 VertexPosition;" "\n\n";
|
||||
|
||||
/********************Sortant********************/
|
||||
if (uvMapping)
|
||||
source += s_outKW + " vec2 vTexCoord;" "\n\n";
|
||||
|
||||
/********************Code********************/
|
||||
source += "void main()" "\n"
|
||||
"{" "\n"
|
||||
"\t" "gl_Position = vec4(VertexPosition, 0.0, 1.0);" "\n";
|
||||
|
||||
if (uvMapping)
|
||||
{
|
||||
if (params.flags & nzShaderFlags_FlipUVs)
|
||||
source += "\t" "vTexCoord = vec2((VertexPosition.x + 1.0)*0.5, 0.5 - VertexPosition.y*0.5;" "\n";
|
||||
else
|
||||
source += "\t" "vTexCoord = vec2((VertexPosition.x + 1.0)*0.5, (VertexPosition.y + 1.0)*0.5);" "\n";
|
||||
}
|
||||
|
||||
source += "}" "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case nzShaderTarget_Model:
|
||||
{
|
||||
bool uvMapping = (params.model.diffuseMapping || params.model.normalMapping || params.model.specularMapping);
|
||||
|
||||
/********************Entrant********************/
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += s_inKW + " mat4 InstanceData0;" "\n";
|
||||
|
||||
source += s_inKW + " vec3 VertexPosition;" "\n";
|
||||
|
||||
if (params.model.lighting)
|
||||
{
|
||||
source += s_inKW + " vec3 VertexNormal;" "\n";
|
||||
source += s_inKW + " vec3 VertexTangent;" "\n";
|
||||
}
|
||||
|
||||
if (uvMapping)
|
||||
source += s_inKW + " vec2 VertexTexCoord;" "\n";
|
||||
|
||||
source += '\n';
|
||||
|
||||
/********************Sortant********************/
|
||||
if (params.model.lighting)
|
||||
{
|
||||
if (params.model.normalMapping)
|
||||
source += s_outKW + " mat3 vLightToWorld;" "\n";
|
||||
else
|
||||
source += s_outKW + " vec3 vNormal;" "\n";
|
||||
}
|
||||
|
||||
if (uvMapping)
|
||||
source += s_outKW + " vec2 vTexCoord;" "\n";
|
||||
|
||||
if (params.model.lighting)
|
||||
source += s_outKW + " vec3 vWorldPos;" "\n";
|
||||
|
||||
if (params.model.lighting || uvMapping)
|
||||
source += '\n';
|
||||
|
||||
/********************Uniformes********************/
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += "uniform mat4 ViewProjMatrix;" "\n";
|
||||
else
|
||||
{
|
||||
if (params.model.lighting)
|
||||
source += "uniform mat4 WorldMatrix;" "\n";
|
||||
|
||||
source += "uniform mat4 WorldViewProjMatrix;" "\n";
|
||||
}
|
||||
|
||||
source += '\n';
|
||||
|
||||
/********************Code********************/
|
||||
source += "void main()" "\n"
|
||||
"{" "\n";
|
||||
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += "\t" "gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);" "\n";
|
||||
else
|
||||
source += "\t" "gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);" "\n";
|
||||
|
||||
if (params.model.lighting)
|
||||
{
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
{
|
||||
if (s_glsl140)
|
||||
source += "\t" "mat3 rotationMatrix = mat3(InstanceData0);" "\n";
|
||||
else
|
||||
source += "\t" "mat3 rotationMatrix = mat3(InstanceData0[0].xyz, InstanceData0[1].xyz, InstanceData0[2].xyz);" "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_glsl140)
|
||||
source += "\t" "mat3 rotationMatrix = mat3(WorldMatrix);" "\n";
|
||||
else
|
||||
source += "\t" "mat3 rotationMatrix = mat3(WorldMatrix[0].xyz, WorldMatrix[1].xyz, WorldMatrix[2].xyz);" "\n";
|
||||
}
|
||||
|
||||
if (params.model.normalMapping)
|
||||
{
|
||||
source += "\n"
|
||||
"\t" "vec3 binormal = cross(VertexNormal, VertexTangent);" "\n"
|
||||
"\t" "vLightToWorld[0] = normalize(rotationMatrix * VertexTangent);" "\n"
|
||||
"\t" "vLightToWorld[1] = normalize(rotationMatrix * binormal);" "\n"
|
||||
"\t" "vLightToWorld[2] = normalize(rotationMatrix * VertexNormal);" "\n\n";
|
||||
}
|
||||
else
|
||||
source += "\t" "vNormal = normalize(rotationMatrix * VertexNormal);" "\n";
|
||||
}
|
||||
|
||||
if (uvMapping)
|
||||
{
|
||||
if (params.flags & nzShaderFlags_FlipUVs)
|
||||
source += "\t" "vTexCoord = vec2(VertexTexCoord.x, 1.0 - VertexTexCoord.y);" "\n";
|
||||
else
|
||||
source += "\t" "vTexCoord = VertexTexCoord;" "\n";
|
||||
}
|
||||
|
||||
if (params.model.lighting)
|
||||
{
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += "\t" "vWorldPos = vec3(InstanceData0 * vec4(VertexPosition, 1.0));" "\n";
|
||||
else
|
||||
source += "\t" "vWorldPos = vec3(WorldMatrix * vec4(VertexPosition, 1.0));" "\n";
|
||||
}
|
||||
|
||||
source += "}" "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case nzShaderTarget_None:
|
||||
{
|
||||
/********************Entrant********************/
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += s_inKW + " mat4 InstanceData0;" "\n";
|
||||
|
||||
source += s_inKW + " vec3 VertexPosition;" "\n\n";
|
||||
|
||||
/********************Uniformes********************/
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += "uniform mat4 ViewProjMatrix;" "\n\n";
|
||||
else
|
||||
source += "uniform mat4 WorldViewProjMatrix;" "\n\n";
|
||||
|
||||
/********************Code********************/
|
||||
source += "void main()" "\n"
|
||||
"{" "\n";
|
||||
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += "\t" "gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);" "\n";
|
||||
else
|
||||
source += "\t" "gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);" "\n";
|
||||
|
||||
source += "}" "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
NzShader* NzShaderManager::GenerateShader(const NzShaderManagerParams& params)
|
||||
{
|
||||
std::unique_ptr<NzShader> shader(new NzShader);
|
||||
shader->SetPersistent(false);
|
||||
|
||||
if (!shader->Create(nzShaderLanguage_GLSL))
|
||||
{
|
||||
NazaraError("Failed to create shader");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NzString fragmentSource = BuildFragmentCode(params);
|
||||
if (!shader->Load(nzShaderType_Fragment, fragmentSource))
|
||||
{
|
||||
NazaraError("Failed to load fragment shader: " + shader->GetLog());
|
||||
NazaraNotice("Source:\n" + fragmentSource);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NzString vertexSource = BuildVertexCode(params);
|
||||
if (!shader->Load(nzShaderType_Vertex, vertexSource))
|
||||
{
|
||||
NazaraError("Failed to load vertex shader: " + shader->GetLog());
|
||||
NazaraNotice("Source:\n" + vertexSource);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
NazaraNotice("Fragment shader source:\n" + fragmentSource);
|
||||
NazaraNotice("Vertex shader source:\n" + vertexSource);
|
||||
#endif
|
||||
|
||||
if (!shader->Compile())
|
||||
{
|
||||
NazaraError("Failed to compile shader: " + shader->GetLog());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shader.release();
|
||||
}
|
||||
|
||||
bool NzShaderManager::Initialize()
|
||||
{
|
||||
s_glslVersion = NzOpenGL::GetGLSLVersion();
|
||||
s_earlyFragmentTest = (s_glslVersion >= 420 || NzOpenGL::IsSupported(nzOpenGLExtension_Shader_ImageLoadStore));
|
||||
s_glsl140 = (s_glslVersion >= 140);
|
||||
|
||||
s_fragmentColorKW = (s_glsl140) ? "RenderTarget0" : "gl_FragColor";
|
||||
s_inKW = (s_glsl140) ? "in" : "varying";
|
||||
s_outKW = (s_glsl140) ? "out" : "varying";
|
||||
s_textureLookupKW = (s_glsl140) ? "texture" : "texture2D";
|
||||
|
||||
NzShaderManagerParams params;
|
||||
params.target = nzShaderTarget_None;
|
||||
for (unsigned int i = 0; i <= nzShaderFlags_Max; ++i)
|
||||
{
|
||||
params.flags = i;
|
||||
|
||||
NzShader* shader = GenerateShader(params);
|
||||
if (!shader)
|
||||
{
|
||||
NazaraError("Failed to generate default shader (flags: 0x" + NzString::Number(i, 16) + ')');
|
||||
Uninitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
s_shaders[params] = shader;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzShaderManager::Uninitialize()
|
||||
{
|
||||
s_shaders.clear();
|
||||
s_fragmentColorKW.Clear(false);
|
||||
s_inKW.Clear(false);
|
||||
s_outKW.Clear(false);
|
||||
s_textureLookupKW.Clear(false);
|
||||
}
|
||||
Reference in New Issue
Block a user