Added ShaderManager (Experimental)

Former-commit-id: 327e373f2b932e31184e88c5f29bd5bd8fa3ba46
This commit is contained in:
Lynix 2013-07-15 00:23:04 +02:00
parent 68d5f9a8e6
commit 4352083c4b
23 changed files with 1367 additions and 955 deletions

View File

@ -115,7 +115,9 @@ enum nzStreamOptionFlags
{
nzStreamOption_None = 0x0,
nzStreamOption_Text = 0x1
nzStreamOption_Text = 0x1,
nzStreamOption_Max = nzStreamOption_Text*2-1
};
enum nzTernary

View File

@ -16,7 +16,6 @@ class NAZARA_API NzColorBackground : public NzAbstractBackground
{
public:
NzColorBackground(const NzColor& color = NzColor::Black);
~NzColorBackground();
void Draw(const NzScene* scene) const;
@ -27,7 +26,7 @@ class NAZARA_API NzColorBackground : public NzAbstractBackground
private:
NzColor m_color;
NzShaderRef m_shader;
NzShaderConstRef m_shader;
};
#endif // NAZARA_COLORBACKGROUND_HPP

View File

@ -39,7 +39,7 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
private:
void OnResourceDestroy(const NzResource* resource, int index);
struct MaterialComparator
struct ModelMaterialComparator
{
bool operator()(const NzMaterial* mat1, const NzMaterial* mat2);
};
@ -55,6 +55,12 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
bool operator()(const NzSkeletalMesh* subMesh1, const NzSkeletalMesh* subMesh2);
};
struct StaticData
{
NzBoxf aabb;
NzMatrix4f transformMatrix;
};
struct StaticMeshComparator
{
bool operator()(const NzStaticMesh* subMesh1, const NzStaticMesh* subMesh2);
@ -78,8 +84,8 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
};
typedef std::map<const NzSkeletalMesh*, std::vector<SkeletalData>, SkeletalMeshComparator> SkeletalMeshContainer;
typedef std::map<const NzStaticMesh*, std::vector<NzMatrix4f>, StaticMeshComparator> StaticMeshContainer;
typedef std::map<const NzMaterial*, std::pair<SkeletalMeshContainer, StaticMeshContainer>, MaterialComparator> MeshContainer;
typedef std::map<const NzStaticMesh*, std::vector<StaticData>, StaticMeshComparator> StaticMeshContainer;
typedef std::map<const NzMaterial*, std::pair<SkeletalMeshContainer, StaticMeshContainer>, ModelMaterialComparator> MeshContainer;
MeshContainer opaqueModels;
std::vector<std::pair<unsigned int, bool>> transparentsModels;

View File

@ -23,7 +23,7 @@ class NAZARA_API NzLight : public NzSceneNode
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override;
void Apply(const NzShader* shader, unsigned int lightUnit) const;
void Enable(const NzShader* shader, unsigned int lightUnit) const;
NzColor GetAmbientColor() const;
float GetAttenuation() const;
@ -46,6 +46,8 @@ class NAZARA_API NzLight : public NzSceneNode
NzLight& operator=(const NzLight& light);
static void Disable(const NzShader* shader, unsigned int lightUnit);
private:
void Invalidate();
void Register();

View File

@ -17,7 +17,6 @@ class NAZARA_API NzTextureBackground : public NzAbstractBackground
public:
NzTextureBackground();
NzTextureBackground(NzTexture* texture);
~NzTextureBackground();
void Draw(const NzScene* scene) const;
@ -27,7 +26,7 @@ class NAZARA_API NzTextureBackground : public NzAbstractBackground
void SetTexture(NzTexture* texture);
private:
NzShaderRef m_shader;
NzShaderConstRef m_shader;
NzTextureRef m_texture;
};

View File

@ -43,7 +43,7 @@
#include <Nazara/Renderer/RenderTexture.hpp>
#include <Nazara/Renderer/RenderWindow.hpp>
#include <Nazara/Renderer/Shader.hpp>
#include <Nazara/Renderer/ShaderBuilder.hpp>
#include <Nazara/Renderer/ShaderManager.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Renderer/TextureSampler.hpp>

View File

@ -94,9 +94,11 @@ enum nzRendererCap
enum nzRendererClearFlags
{
nzRendererClear_Color = 0x01,
nzRendererClear_Depth = 0x02,
nzRendererClear_Stencil = 0x04
nzRendererClear_Color = 0x1,
nzRendererClear_Depth = 0x2,
nzRendererClear_Stencil = 0x4,
nzRendererClear_Max = nzRendererClear_Stencil*2-1
};
enum nzRendererComparison
@ -155,17 +157,11 @@ enum nzShaderFlags
{
nzShaderFlags_None = 0,
nzShaderFlags_AlphaMapping = 0x001,
nzShaderFlags_AlphaTest = 0x002,
nzShaderFlags_Deferred = 0x004,
nzShaderFlags_DiffuseMapping = 0x008,
nzShaderFlags_EmissiveMapping = 0x010,
nzShaderFlags_FlipUVs = 0x020,
nzShaderFlags_Instancing = 0x040,
nzShaderFlags_Lighting = 0x080,
nzShaderFlags_NormalMapping = 0x100,
nzShaderFlags_ParallaxMapping = 0x200,
nzShaderFlags_SpecularMapping = 0x400
//nzShaderFlags_Deferred = 0x1,
nzShaderFlags_FlipUVs = 0x1,
nzShaderFlags_Instancing = 0x2,
nzShaderFlags_Max = nzShaderFlags_Instancing*2-1
};
enum nzShaderLanguage
@ -178,11 +174,19 @@ enum nzShaderLanguage
nzShaderLanguage_Max = nzShaderLanguage_GLSL
};
enum nzShaderTarget
{
nzShaderTarget_FullscreenQuad,
nzShaderTarget_Model,
nzShaderTarget_None,
nzShaderTarget_Max = nzShaderTarget_None
};
enum nzShaderUniform
{
nzShaderUniform_CameraPosition,
nzShaderUniform_InvTargetSize,
nzShaderUniform_LightCount,
nzShaderUniform_MaterialAlphaMap,
nzShaderUniform_MaterialAlphaThreshold,
nzShaderUniform_MaterialAmbient,

View File

@ -57,7 +57,6 @@ class NAZARA_API NzMaterial : public NzResource
NzTexture* GetAlphaMap() const;
float GetAlphaThreshold() const;
NzColor GetAmbientColor() const;
const NzShader* GetCustomShader() const;
nzRendererComparison GetDepthFunc() const;
NzColor GetDiffuseColor() const;
NzTexture* GetDiffuseMap() const;
@ -70,7 +69,7 @@ class NAZARA_API NzMaterial : public NzResource
NzTexture* GetHeightMap() const;
NzTexture* GetNormalMap() const;
const NzRenderStates& GetRenderStates() const;
nzUInt32 GetShaderFlags() const;
const NzShader* GetShader(nzShaderTarget target, nzUInt32 flags) const;
float GetShininess() const;
NzColor GetSpecularColor() const;
NzTexture* GetSpecularMap() const;
@ -78,10 +77,15 @@ class NAZARA_API NzMaterial : public NzResource
const NzTextureSampler& GetSpecularSampler() const;
nzBlendFunc GetSrcBlend() const;
bool HasCustomShader() const;
bool HasAlphaMap() const;
bool HasDiffuseMap() const;
bool HasEmissiveMap() const;
bool HasHeightMap() const;
bool HasNormalMap() const;
bool HasSpecularMap() const;
bool IsEnabled(nzRendererParameter renderParameter) const;
bool IsAlphaTestEnabled() const;
bool IsEnabled(nzRendererParameter renderParameter) const;
bool IsLightingEnabled() const;
bool LoadFromFile(const NzString& filePath, const NzMaterialParams& params = NzMaterialParams());
@ -94,7 +98,6 @@ class NAZARA_API NzMaterial : public NzResource
void SetAlphaMap(NzTexture* map);
void SetAlphaThreshold(float alphaThreshold);
void SetAmbientColor(const NzColor& ambient);
void SetCustomShader(const NzShader* shader);
void SetDepthFunc(nzRendererComparison depthFunc);
void SetDiffuseColor(const NzColor& diffuse);
bool SetDiffuseMap(const NzString& texturePath);
@ -110,6 +113,7 @@ class NAZARA_API NzMaterial : public NzResource
bool SetNormalMap(const NzString& texturePath);
void SetNormalMap(NzTexture* map);
void SetRenderStates(const NzRenderStates& states);
void SetShader(nzShaderTarget target, nzUInt32 flags, const NzShader* shader);
void SetShininess(float shininess);
void SetSpecularColor(const NzColor& specular);
bool SetSpecularMap(const NzString& texturePath);
@ -123,19 +127,26 @@ class NAZARA_API NzMaterial : public NzResource
static NzMaterial* GetDefault();
private:
struct ShaderUnit
{
NzShaderConstRef shader;
bool custom = false;
};
void Copy(const NzMaterial& material);
void GenerateShader(nzShaderTarget target, nzUInt32 flags) const;
void InvalidateShaders(nzShaderTarget target);
static bool Initialize();
static void Uninitialize();
nzUInt32 m_shaderFlags;
NzColor m_ambientColor;
NzColor m_diffuseColor;
NzColor m_specularColor;
NzRenderStates m_states;
mutable ShaderUnit m_shaders[nzShaderTarget_Max+1][nzShaderFlags_Max+1];
NzTextureSampler m_diffuseSampler;
NzTextureSampler m_specularSampler;
mutable NzShaderConstRef m_customShader;
NzTextureRef m_alphaMap;
NzTextureRef m_diffuseMap;
NzTextureRef m_emissiveMap;

View File

@ -1,28 +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
#pragma once
#ifndef NAZARA_SHADERBUILDER_HPP
#define NAZARA_SHADERBUILDER_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Renderer/Shader.hpp>
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_SHADERBUILDER_HPP

View File

@ -0,0 +1,33 @@
// 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
#pragma once
#ifndef NAZARA_SHADERMANAGER_HPP
#define NAZARA_SHADERMANAGER_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Renderer/Shader.hpp>
#include <Nazara/Renderer/ShaderManagerParams.hpp>
class NAZARA_API NzShaderManager
{
friend class NzRenderer;
public:
NzShaderManager() = delete;
~NzShaderManager() = delete;
static const NzShader* Get(const NzShaderManagerParams& params);
private:
static NzString BuildFragmentCode(const NzShaderManagerParams& params);
static NzString BuildVertexCode(const NzShaderManagerParams& params);
static NzShader* GenerateShader(const NzShaderManagerParams& params);
static bool Initialize();
static void Uninitialize();
};
#endif // NAZARA_SHADERMANAGER_HPP

View File

@ -0,0 +1,43 @@
// 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
#pragma once
#ifndef NAZARA_SHADERMANAGERPARAMS_HPP
#define NAZARA_SHADERMANAGERPARAMS_HPP
#include <Nazara/Renderer/Enums.hpp>
struct NzShaderManagerParams
{
struct FullscreenQuad
{
bool alphaMapping;
bool alphaTest;
bool diffuseMapping;
};
struct Model
{
bool alphaMapping;
bool alphaTest;
bool diffuseMapping;
bool emissiveMapping;
bool lighting;
bool normalMapping;
bool parallaxMapping;
bool specularMapping;
};
nzShaderTarget target;
nzUInt32 flags;
union
{
FullscreenQuad fullscreenQuad;
Model model;
};
};
#endif // NAZARA_SHADERMANAGERPARAMS_HPP

View File

@ -268,7 +268,8 @@ enum nzWindowStyleFlags
nzWindowStyle_Resizable = 0x4,
nzWindowStyle_Titlebar = 0x8,
nzWindowStyle_Default = nzWindowStyle_Closable | nzWindowStyle_Resizable | nzWindowStyle_Titlebar
nzWindowStyle_Default = nzWindowStyle_Closable | nzWindowStyle_Resizable | nzWindowStyle_Titlebar,
nzWindowStyle_Max = nzWindowStyle_Titlebar*2-1
};
#endif // NAZARA_ENUMS_UTILITY_HPP

View File

@ -2,101 +2,23 @@
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#ifndef NAZARA_RENDERER_OPENGL
#define NAZARA_RENDERER_OPENGL // Nécessaire pour inclure les headers OpenGL
#endif
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Graphics/ColorBackGround.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/ShaderBuilder.hpp>
#include <Nazara/Renderer/ShaderManager.hpp>
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
namespace
{
NzShader* BuildShader()
{
const char* fragmentSource110 =
"#version 110\n"
"uniform vec4 Color;\n"
"void main()\n"
"{\n"
" gl_FragColor = Color;\n"
"}\n";
const char* fragmentSource140 =
"#version 140\n"
"out vec4 RenderTarget0;\n"
"uniform vec4 Color;\n"
"void main()\n"
"{\n"
" RenderTarget0 = Color;\n"
"}\n";
const char* vertexSource110 =
"#version 110\n"
"attribute vec2 VertexPosition;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(VertexPosition, 0.0, 1.0);\n"
"}\n";
const char* vertexSource140 =
"#version 140\n"
"in vec2 VertexPosition;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(VertexPosition, 0.0, 1.0);\n"
"}\n";
///TODO: Remplacer ça par des ShaderNode
std::unique_ptr<NzShader> shader(new NzShader(nzShaderLanguage_GLSL));
shader->SetPersistent(false);
bool useGLSL140 = (NzOpenGL::GetVersion() >= 310);
if (!shader->Load(nzShaderType_Fragment, (useGLSL140) ? fragmentSource140 : fragmentSource110))
{
NazaraError("Failed to load fragment shader");
return nullptr;
}
if (!shader->Load(nzShaderType_Vertex, (useGLSL140) ? vertexSource140 : vertexSource110))
{
NazaraError("Failed to load vertex shader");
return nullptr;
}
if (!shader->Compile())
{
NazaraError("Failed to compile shader");
return nullptr;
}
return shader.release();
}
static NzShader* s_shader = nullptr;
static unsigned int s_colorLocation;
}
NzColorBackground::NzColorBackground(const NzColor& color) :
m_color(color)
{
if (!s_shader)
{
s_shader = BuildShader();
s_colorLocation = s_shader->GetUniformLocation("Color");
}
NzShaderManagerParams params;
params.target = nzShaderTarget_FullscreenQuad;
params.flags = 0;
params.fullscreenQuad.alphaMapping = false;
params.fullscreenQuad.alphaTest = false;
params.fullscreenQuad.diffuseMapping = false;
m_shader = s_shader;
}
NzColorBackground::~NzColorBackground()
{
if (m_shader.Reset())
s_shader = nullptr;
m_shader = NzShaderManager::Get(params);
}
void NzColorBackground::Draw(const NzScene* scene) const
@ -105,7 +27,7 @@ void NzColorBackground::Draw(const NzScene* scene) const
static NzRenderStates states;
m_shader->SendColor(s_colorLocation, m_color);
m_shader->SendColor(m_shader->GetUniformLocation(nzShaderUniform_MaterialDiffuse), m_color);
NzRenderer::SetRenderStates(states);
NzRenderer::SetShader(m_shader);

View File

@ -142,7 +142,14 @@ void NzForwardRenderQueue::AddModel(const NzModel* model)
if (pair2.second)
staticMesh->AddResourceListener(this, ResourceType_StaticMesh);
pair2.first->second.push_back(transformMatrix);
std::vector<StaticData>& staticDataContainer = pair2.first->second;
staticDataContainer.resize(staticDataContainer.size()+1);
StaticData& data = staticDataContainer.back();
data.aabb = staticMesh->GetAABB();
data.aabb.Transform(transformMatrix);
data.transformMatrix = transformMatrix;
}
break;
@ -257,31 +264,22 @@ bool NzForwardRenderQueue::StaticMeshComparator::operator()(const NzStaticMesh*
return buffer1 < buffer2;
}
bool NzForwardRenderQueue::MaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
bool NzForwardRenderQueue::ModelMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
{
const NzShader* shader1 = mat1->GetCustomShader();
const NzShader* shader2 = mat2->GetCustomShader();
if (shader1)
///TODO: Comparaison des shaders
for (unsigned int i = 0; i <= nzShaderFlags_Max; ++i)
{
if (shader2)
{
if (shader1 != shader2)
return shader1 < shader2;
}
else
return true;
}
else if (shader2)
return false;
else
{
nzUInt32 shaderFlags1 = mat1->GetShaderFlags();
nzUInt32 shaderFlags2 = mat2->GetShaderFlags();
const NzShader* shader1 = mat1->GetShader(nzShaderTarget_Model, i);
const NzShader* shader2 = mat2->GetShader(nzShaderTarget_Model, i);
if (shaderFlags1 != shaderFlags2)
return shaderFlags1 < shaderFlags2;
if (shader1 != shader2)
return shader1 < shader2;
}
const NzTexture* diffuseMap1 = mat1->GetDiffuseMap();
const NzTexture* diffuseMap2 = mat2->GetDiffuseMap();
if (diffuseMap1 != diffuseMap2)
return diffuseMap1 < diffuseMap2;
return mat1 < mat2;
}

View File

@ -10,20 +10,107 @@
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Material.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/ShaderBuilder.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/StaticMesh.hpp>
#include <Nazara/Utility/VertexStruct.hpp>
#include <limits>
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
namespace
{
struct LightComparator
class LightManager
{
bool operator()(const NzLight* light1, const NzLight* light2)
{
return light1->GetPosition().SquaredDistance(pos) < light2->GetPosition().SquaredDistance(pos);
}
public:
LightManager() = default;
~LightManager() = default;
NzVector3f pos;
unsigned int FindClosestLights(const NzLight** lights, unsigned int lightCount, const NzSpheref& object)
{
for (Light& light : m_lights)
{
light.light = nullptr;
light.score = std::numeric_limits<unsigned int>::max(); // Nous jouons au Golf
}
for (unsigned int i = 0; i < lightCount; ++i)
{
const NzLight* light = *lights;
unsigned int score = std::numeric_limits<unsigned int>::max();
switch (light->GetLightType())
{
case nzLightType_Directional:
score = 0; // Lumière choisie d'office
break;
case nzLightType_Point:
{
NzSpheref lightSphere(light->GetPosition(), light->GetRadius());
if (lightSphere.Intersect(object))
score = static_cast<unsigned int>(light->GetPosition().SquaredDistance(object.GetPosition())*1000.f);
break;
}
case nzLightType_Spot:
{
NzSpheref lightSphere(light->GetPosition(), light->GetRadius());
///TODO: Attribuer bonus/malus selon l'angle du spot ?
if (lightSphere.Intersect(object))
score = static_cast<unsigned int>(light->GetPosition().SquaredDistance(object.GetPosition())*1000.f);
break;
}
}
if (score < m_lights[0].score)
{
unsigned int j;
for (j = 1; j < 3; ++j) ///TODO: Constante
{
if (score > m_lights[j].score)
break;
}
j--; // Position de la nouvelle lumière
// Décalage
std::memcpy(&m_lights[0], &m_lights[1], j*sizeof(Light));
m_lights[j].light = light;
m_lights[j].score = score;
}
lights++;
}
unsigned int i;
for (i = 0; i < 3; ++i) ///TODO: Constante
{
if (m_lights[i].light)
break;
}
return 3-i; ///TODO: Constante
}
const NzLight* GetLight(unsigned int i) const
{
///TODO: Constante
return m_lights[3-i-1].light; // Les lumières sont stockées dans l'ordre inverse (De la plus éloignée à la plus proche)
}
private:
struct Light
{
const NzLight* light;
unsigned int score;
};
Light m_lights[3]; ///TODO: Constante
};
}
@ -46,15 +133,11 @@ void NzForwardRenderTechnique::Clear(const NzScene* scene)
void NzForwardRenderTechnique::Draw(const NzScene* scene)
{
///TODO: Regrouper les activations par méthode
LightComparator lightComparator;
LightManager lightManager;
const NzCamera* camera = scene->GetActiveCamera();
const NzShader* lastShader = nullptr;
// Externes à la boucle pour conserver leur valeurs si le shader ne change pas
unsigned int lightCount = 0;
int lightCountLocation = -1;
// Rendu des modèles opaques
for (auto& matIt : m_renderQueue.opaqueModels)
{
@ -66,18 +149,13 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
const NzMaterial* material = matIt.first;
// On commence par récupérer le shader du matériau
const NzShader* shader;
if (material->HasCustomShader())
shader = material->GetCustomShader();
else
shader = NzShaderBuilder::Get(material->GetShaderFlags());
const NzShader* shader = material->GetShader(nzShaderTarget_Model, 0);
unsigned int lightCount = 0;
// Les uniformes sont conservées au sein du shader, inutile de les renvoyer tant que le shader reste le même
if (shader != lastShader)
{
// On récupère l'information sur l'éclairage en même temps que la position de l'uniforme "LightCount"
lightCountLocation = shader->GetUniformLocation(nzShaderUniform_LightCount);
NzRenderer::SetShader(shader);
// Couleur ambiante de la scène
@ -85,18 +163,11 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_CameraPosition), camera->GetPosition());
lightCount = 0;
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
if (lightCountLocation != -1)
{
for (const NzLight* light : m_renderQueue.directionnalLights)
{
light->Apply(shader, lightCount++);
if (lightCount > NAZARA_RENDERER_SHADER_MAX_LIGHTCOUNT)
break; // Prévenons les bêtises des utilisateurs
}
}
lightCount = m_renderQueue.directionnalLights.size();
for (unsigned int i = 0; i < lightCount; ++i)
m_renderQueue.directionnalLights[i]->Enable(shader, i);
lastShader = shader;
}
@ -116,8 +187,9 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
for (auto& subMeshIt : staticContainer)
{
const NzStaticMesh* mesh = subMeshIt.first;
std::vector<NzMatrix4f>& matrices = subMeshIt.second;
if (!matrices.empty())
std::vector<NzForwardRenderQueue::StaticData>& staticData = subMeshIt.second;
if (!staticData.empty())
{
const NzIndexBuffer* indexBuffer = mesh->GetIndexBuffer();
const NzVertexBuffer* vertexBuffer = mesh->GetVertexBuffer();
@ -140,28 +212,25 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
NzRenderer::SetIndexBuffer(indexBuffer);
NzRenderer::SetVertexBuffer(vertexBuffer);
for (const NzMatrix4f& matrix : matrices)
for (const NzForwardRenderQueue::StaticData& data : staticData)
{
// Calcul des lumières les plus proches
///TODO: LightManager ?
if (lightCountLocation != -1)
if (lightCount < m_maxLightsPerObject && !m_renderQueue.lights.empty())
{
std::vector<const NzLight*>& lights = m_renderQueue.lights;
unsigned int count = lightManager.FindClosestLights(&m_renderQueue.lights[0], m_renderQueue.lights.size(), data.aabb.GetBoundingSphere());
count -= lightCount;
lightComparator.pos = matrix.GetTranslation();
std::sort(lights.begin(), lights.end(), lightComparator);
unsigned int max = std::min(std::min(NAZARA_RENDERER_SHADER_MAX_LIGHTCOUNT - lightCount, m_maxLightsPerObject), static_cast<unsigned int>(lights.size()));
for (unsigned int i = 0; i < max; ++i)
lights[i]->Apply(shader, lightCount++);
shader->SendInteger(lightCountLocation, lightCount);
for (unsigned int i = 0; i < count; ++i)
lightManager.GetLight(i)->Enable(shader, lightCount++);
}
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
for (unsigned int i = lightCount; i < 3; ++i) ///TODO: Constante sur le nombre maximum de lumières
NzLight::Disable(shader, i);
NzRenderer::SetMatrix(nzMatrixType_World, data.transformMatrix);
drawFunc(mesh->GetPrimitiveMode(), 0, indexCount);
}
matrices.clear();
staticData.clear();
}
}
}
@ -175,18 +244,13 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
m_renderQueue.transparentSkeletalModels[pair.first].material;
// On commence par récupérer le shader du matériau
const NzShader* shader;
if (material->HasCustomShader())
shader = material->GetCustomShader();
else
shader = NzShaderBuilder::Get(material->GetShaderFlags());
const NzShader* shader = material->GetShader(nzShaderTarget_Model, 0);
unsigned int lightCount = 0;
// Les uniformes sont conservées au sein du shader, inutile de les renvoyer tant que le shader reste le même
if (shader != lastShader)
{
// On récupère l'information sur l'éclairage en même temps que la position de l'uniforme "LightCount"
lightCountLocation = shader->GetUniformLocation(nzShaderUniform_LightCount);
NzRenderer::SetShader(shader);
// Couleur ambiante de la scène
@ -194,18 +258,11 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_CameraPosition), camera->GetPosition());
lightCount = 0;
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
if (lightCountLocation != -1)
{
for (const NzLight* light : m_renderQueue.directionnalLights)
{
light->Apply(shader, lightCount++);
if (lightCount > NAZARA_RENDERER_SHADER_MAX_LIGHTCOUNT)
break; // Prévenons les bêtises des utilisateurs
}
}
lightCount = m_renderQueue.directionnalLights.size();
for (unsigned int i = 0; i < lightCount; ++i)
m_renderQueue.directionnalLights[i]->Enable(shader, i);
lastShader = shader;
}
@ -241,21 +298,18 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
NzRenderer::SetVertexBuffer(vertexBuffer);
// Calcul des lumières les plus proches
///TODO: LightManager ?
if (lightCountLocation != -1)
if (lightCount < m_maxLightsPerObject && !m_renderQueue.lights.empty())
{
std::vector<const NzLight*>& lights = m_renderQueue.lights;
unsigned int count = lightManager.FindClosestLights(&m_renderQueue.lights[0], m_renderQueue.lights.size(), staticModel.aabb.GetBoundingSphere());
count -= lightCount;
lightComparator.pos = matrix.GetTranslation();
std::sort(lights.begin(), lights.end(), lightComparator);
unsigned int max = std::min(std::min(NAZARA_RENDERER_SHADER_MAX_LIGHTCOUNT - lightCount, m_maxLightsPerObject), static_cast<unsigned int>(lights.size()));
for (unsigned int i = 0; i < max; ++i)
lights[i]->Apply(shader, lightCount++);
shader->SendInteger(lightCountLocation, lightCount);
for (unsigned int i = 0; i < count; ++i)
lightManager.GetLight(i)->Enable(shader, lightCount++);
}
for (unsigned int i = lightCount; i < 3; ++i) ///TODO: Constante sur le nombre maximum de lumières
NzLight::Disable(shader, i);
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
drawFunc(mesh->GetPrimitiveMode(), 0, indexCount);
}
@ -265,6 +319,51 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
}
}
// Les billboards
/*if (!m_renderQueue.billboards.empty())
{
//NzRenderer::SetIndexBuffer(m_billboardIndexBuffer);
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
NzRenderer::SetShader(m_billboardShader);
NzRenderer::SetVertexBuffer(m_billboardVertexBuffer);
m_billboardShader->SendVector(s_cameraForwardLocation, camera->GetForward());
m_billboardShader->SendVector(s_cameraUpLocation, camera->GetUp());
m_billboardShader->SendVector(s_worldUpLocation, NzVector3f::Up());
// Couleur ambiante de la scène
m_billboardShader->SendColor(m_billboardShader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
m_billboardShader->SendVector(m_billboardShader->GetUniformLocation(nzShaderUniform_CameraPosition), camera->GetPosition());
lightCount = 0;
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
m_renderQueue.lights[0]->Apply(m_billboardShader, 0);
for (auto& matIt : m_renderQueue.billboards)
{
const NzMaterial* material = matIt.first;
auto& billboards = matIt.second;
material->Apply(m_billboardShader);
unsigned int billboardCount = billboards.size();
const NzForwardRenderQueue::BillboardData* data = &billboards[0];
while (billboardCount > 0)
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboards);
billboardCount -= renderedBillboardCount;
m_billboardVertexBuffer->FillVertices(data, 0, renderedBillboardCount, true);
data += renderedBillboardCount;
NzRenderer::DrawPrimitives(nzPrimitiveMode_PointList, 0, renderedBillboardCount);
}
billboards.clear();
}
}*/
// Les autres drawables (Exemple: Terrain)
for (const NzDrawable* drawable : m_renderQueue.otherDrawables)
drawable->Draw();
@ -282,5 +381,5 @@ NzAbstractRenderQueue* NzForwardRenderTechnique::GetRenderQueue()
void NzForwardRenderTechnique::SetMaxLightsPerObject(unsigned int lightCount)
{
m_maxLightsPerObject = lightCount;
m_maxLightsPerObject = lightCount; ///TODO: Vérifier par rapport à la constante
}

View File

@ -38,7 +38,7 @@ void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
renderQueue->AddLight(this);
}
void NzLight::Apply(const NzShader* shader, unsigned int lightUnit) const
void NzLight::Enable(const NzShader* shader, unsigned int lightUnit) const
{
/*
struct Light
@ -66,6 +66,7 @@ void NzLight::Apply(const NzShader* shader, unsigned int lightUnit) const
-P3: float cosInnerAngle + float cosOuterAngle
*/
///TODO: Optimiser
int typeLocation = shader->GetUniformLocation("Lights[0].type");
int ambientLocation = shader->GetUniformLocation("Lights[0].ambient");
int diffuseLocation = shader->GetUniformLocation("Lights[0].diffuse");
@ -217,6 +218,12 @@ NzLight& NzLight::operator=(const NzLight& light)
return *this;
}
void NzLight::Disable(const NzShader* shader, unsigned int lightUnit)
{
///TODO: Optimiser
shader->SendInteger(shader->GetUniformLocation("Lights[" + NzString::Number(lightUnit) + "].type"), -1);
}
void NzLight::Invalidate()
{
NzSceneNode::Invalidate();

View File

@ -2,99 +2,22 @@
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#ifndef NAZARA_RENDERER_OPENGL
#define NAZARA_RENDERER_OPENGL // Nécessaire pour inclure les headers OpenGL
#endif
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Graphics/TextureBackground.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/ShaderBuilder.hpp>
#include <Nazara/Renderer/ShaderManager.hpp>
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
namespace
{
static NzShader* s_shader = nullptr;
static int s_textureLocation;
NzShader* BuildShader()
{
const char* fragmentSource110 =
"#version 110\n"
"varying vec2 vTexCoord;\n"
"uniform sampler2D Texture;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture(Texture, vTexCoord);\n"
"}\n";
const char* fragmentSource140 =
"#version 140\n"
"in vec2 vTexCoord;\n"
"out vec4 RenderTarget0;\n"
"uniform sampler2D Texture;\n"
"void main()\n"
"{\n"
" RenderTarget0 = texture(Texture, vTexCoord);\n"
"}\n";
const char* vertexSource110 =
"#version 110\n"
"attribute vec2 VertexPosition;\n"
"varying vec2 vTexCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(VertexPosition, 0.0, 1.0);\n"
" vTexCoord = vec2((VertexPosition.x + 1.0)*0.5, (VertexPosition.y + 1.0)*0.5);\n"
"}\n";
const char* vertexSource140 =
"#version 140\n"
"in vec2 VertexPosition;\n"
"out vec2 vTexCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(VertexPosition, 0.0, 1.0);\n"
" vTexCoord = vec2((VertexPosition.x + 1.0)*0.5, (VertexPosition.y + 1.0)*0.5);\n"
"}\n";
///TODO: Remplacer ça par des ShaderNode
std::unique_ptr<NzShader> shader(new NzShader(nzShaderLanguage_GLSL));
shader->SetPersistent(false);
bool useGLSL140 = (NzOpenGL::GetVersion() >= 310);
if (!shader->Load(nzShaderType_Fragment, (useGLSL140) ? fragmentSource140 : fragmentSource110))
{
NazaraError("Failed to load fragment shader");
return nullptr;
}
if (!shader->Load(nzShaderType_Vertex, (useGLSL140) ? vertexSource140 : vertexSource110))
{
NazaraError("Failed to load vertex shader");
return nullptr;
}
if (!shader->Compile())
{
NazaraError("Failed to compile shader");
return nullptr;
}
s_textureLocation = shader->GetUniformLocation("Texture");
return shader.release();
}
}
NzTextureBackground::NzTextureBackground()
{
if (!s_shader)
s_shader = BuildShader();
NzShaderManagerParams params;
params.target = nzShaderTarget_FullscreenQuad;
params.flags = 0;
params.fullscreenQuad.alphaMapping = false;
params.fullscreenQuad.alphaTest = false;
params.fullscreenQuad.diffuseMapping = true;
m_shader = s_shader;
m_shader = NzShaderManager::Get(params);
}
NzTextureBackground::NzTextureBackground(NzTexture* texture) :
@ -103,19 +26,14 @@ NzTextureBackground()
m_texture = texture;
}
NzTextureBackground::~NzTextureBackground()
{
if (m_shader.Reset())
s_shader = nullptr;
}
void NzTextureBackground::Draw(const NzScene* scene) const
{
NazaraUnused(scene);
static NzRenderStates states;
m_shader->SendInteger(s_textureLocation, 0);
m_shader->SendColor(m_shader->GetUniformLocation(nzShaderUniform_MaterialDiffuse), NzColor::White);
m_shader->SendInteger(m_shader->GetUniformLocation(nzShaderUniform_MaterialDiffuseMap), 0);
NzRenderer::SetRenderStates(states);
NzRenderer::SetShader(m_shader);

View File

@ -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");

View File

@ -66,7 +66,6 @@ bool NzGLSLShader::Compile()
CacheUniform(CameraPosition);
CacheUniform(InvTargetSize);
CacheUniform(LightCount);
CacheUniform(MaterialAlphaMap);
CacheUniform(MaterialAlphaThreshold);
CacheUniform(MaterialAmbient);

View File

@ -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()

View File

@ -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();

View File

@ -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();
}

View 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);
}