From df7b11d1d25234d85a8b38074a823d215019284b Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 25 Dec 2012 12:14:57 +0100 Subject: [PATCH] Added ShaderBuilder Former-commit-id: 0eee75821b7bb4b2b69a020c8e79f3cbe18b522f --- include/Nazara/Renderer/ShaderBuilder.hpp | 28 +++ src/Nazara/Renderer/Renderer.cpp | 10 ++ src/Nazara/Renderer/ShaderBuilder.cpp | 200 ++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 include/Nazara/Renderer/ShaderBuilder.hpp create mode 100644 src/Nazara/Renderer/ShaderBuilder.cpp diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp new file mode 100644 index 000000000..238c441c3 --- /dev/null +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2012 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 + +#pragma once + +#ifndef NAZARA_SHADERBUILDER_HPP +#define NAZARA_SHADERBUILDER_HPP + +#include +#include + +class NAZARA_API NzShaderBuilder +{ + friend class NzRenderer; + + public: + NzShaderBuilder() = delete; + ~NzShaderBuilder() = delete; + + static const NzShader* Get(nzUInt32 flags); + + private: + static bool Initialize(); + static void Uninitialize(); +}; + +#endif // NAZARA_SHADER_HPP diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 14d5874b3..88270570f 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -466,6 +467,14 @@ bool NzRenderer::Initialize(bool initializeDebugDrawer) if (initializeDebugDrawer && !NzDebugDrawer::Initialize()) NazaraWarning("Failed to initialize debug drawer"); // Non-critique + if (!NzShaderBuilder::Initialize()) + { + NazaraError("Failed to initialize shader builder"); + Uninitialize(); + + return false; + } + if (!NzTextureSampler::Initialize()) { NazaraError("Failed to initialize texture sampler"); @@ -1019,6 +1028,7 @@ void NzRenderer::Uninitialize() NzLoaders_Texture_Unregister(); NzDebugDrawer::Uninitialize(); + NzShaderBuilder::Uninitialize(); NzTextureSampler::Uninitialize(); NzContext::EnsureContext(); diff --git a/src/Nazara/Renderer/ShaderBuilder.cpp b/src/Nazara/Renderer/ShaderBuilder.cpp new file mode 100644 index 000000000..824895da1 --- /dev/null +++ b/src/Nazara/Renderer/ShaderBuilder.cpp @@ -0,0 +1,200 @@ +// Copyright (C) 2012 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 +#include +#include +#include +#include +#include + +namespace +{ + std::map s_shaders; + + NzString BuildFragmentShaderSource(nzUInt32 flags) + { + bool glsl140 = (NzOpenGL::GetVersion() >= 300); + bool useMRT = (glsl140 && NzRenderer::HasCapability(nzRendererCap_MultipleRenderTargets)); + + NzString inKW = (glsl140) ? "in" : "varying"; + NzString fragmentColorKW = (glsl140) ? "RenderTarget0" : "gl_FragColor"; + + NzString sourceCode; + sourceCode.Reserve(256); // 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 & nzShaderBuilder_DiffuseMapping) == 0 || flags & nzShaderBuilder_Lighting) + sourceCode += "uniform vec3 DiffuseColor;\n"; + + if (flags & nzShaderBuilder_DiffuseMapping) + sourceCode += "uniform sampler2D DiffuseMap;\n"; + + sourceCode += '\n'; + + /********************Entrant********************/ + if (flags & nzShaderBuilder_DiffuseMapping) + { + sourceCode += inKW; + sourceCode += " vec2 vTexCoord;\n"; + } + + sourceCode += '\n'; + + /********************Sortant********************/ + if (useMRT) + sourceCode += "out vec4 RenderTarget0;\n"; + + sourceCode += '\n'; + + /********************Code********************/ + sourceCode += "void main()\n{\n"; + + sourceCode += '\t'; + sourceCode += fragmentColorKW; + if (flags & nzShaderBuilder_DiffuseMapping) + sourceCode += " = texture2D(DiffuseMap, vTexCoord);\n"; + else + sourceCode += " = vec4(DiffuseColor, 1.0);\n"; + + sourceCode += '}'; + + sourceCode += '\n'; + + return sourceCode; + } + + NzString BuildVertexShaderSource(nzUInt32 flags) + { + bool glsl140 = (NzOpenGL::GetVersion() >= 300); + + NzString inKW = (glsl140) ? "in" : "attribute"; + NzString outKW = (glsl140) ? "out" : "varying"; + + NzString sourceCode; + sourceCode.Reserve(256); // 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********************/ + sourceCode += "uniform mat4 WorldViewProjMatrix;\n"; + + sourceCode += '\n'; + + /********************Entrant********************/ + sourceCode += inKW; + sourceCode += " vec3 Position;\n"; + + if (flags & nzShaderBuilder_Lighting || flags & nzShaderBuilder_NormalMapping || flags & nzShaderBuilder_ParallaxMapping) + { + sourceCode += inKW; + sourceCode += " vec3 Normal;\n"; + } + + if (flags & nzShaderBuilder_Lighting) + { + sourceCode += inKW; + sourceCode += " vec3 Tangent;\n"; + } + + if (flags & nzShaderBuilder_DiffuseMapping || flags & nzShaderBuilder_Lighting || flags & nzShaderBuilder_NormalMapping || flags & nzShaderBuilder_ParallaxMapping) + { + sourceCode += inKW; + sourceCode += " vec2 TexCoord0;\n"; + } + + sourceCode += '\n'; + + /********************Sortant********************/ + if (flags & nzShaderBuilder_DiffuseMapping) + { + sourceCode += outKW; + sourceCode += " vec2 vTexCoord;\n"; + } + + sourceCode += '\n'; + + /********************Code********************/ + sourceCode += "void main()\n{\n"; + + sourceCode += "\tgl_Position = WorldViewProjMatrix * vec4(Position, 1.0);\n"; + + if (flags & nzShaderBuilder_DiffuseMapping) + sourceCode += "\tvTexCoord = TexCoord0;\n"; + + sourceCode += '}'; + + sourceCode += '\n'; + + return sourceCode; + } +} + +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 = new NzShader; + if (!shader->Create(nzShaderLanguage_GLSL)) + { + NazaraError("Failed to create shader"); + return nullptr; + } + + if (!shader->Load(nzShaderType_Fragment, BuildFragmentShaderSource(flags))) + { + NazaraError("Failed to load fragment shader: " + shader->GetLog()); + return nullptr; + } + + if (!shader->Load(nzShaderType_Vertex, BuildVertexShaderSource(flags))) + { + NazaraError("Failed to load vertex shader: " + shader->GetLog()); + return nullptr; + } + + if (!shader->Compile()) + { + NazaraError("Failed to compile shader: " + shader->GetLog()); + return nullptr; + } + + s_shaders[flags] = shader; + + return shader; + } + else + return it->second; +} + +bool NzShaderBuilder::Initialize() +{ + return true; +} + +void NzShaderBuilder::Uninitialize() +{ + for (auto it : s_shaders) + delete it.second; + + s_shaders.clear(); +}