Merge remote-tracking branch 'origin/master' into Resource-Update

Conflicts:
	include/Nazara/Audio/Music.hpp
	include/Nazara/Audio/SoundBuffer.hpp
	include/Nazara/Core/Resource.hpp
	include/Nazara/Core/ResourceListener.hpp
	include/Nazara/Graphics/Material.hpp
	include/Nazara/Renderer/Context.hpp
	include/Nazara/Renderer/RenderBuffer.hpp
	include/Nazara/Renderer/Shader.hpp
	include/Nazara/Renderer/Texture.hpp
	include/Nazara/Renderer/UberShader.hpp
	include/Nazara/Utility/Animation.hpp
	include/Nazara/Utility/Buffer.hpp
	include/Nazara/Utility/Image.hpp
	include/Nazara/Utility/IndexBuffer.hpp
	include/Nazara/Utility/Mesh.hpp
	include/Nazara/Utility/SkeletalMesh.hpp
	include/Nazara/Utility/Skeleton.hpp
	include/Nazara/Utility/StaticMesh.hpp
	include/Nazara/Utility/SubMesh.hpp
	include/Nazara/Utility/VertexBuffer.hpp
	include/Nazara/Utility/VertexDeclaration.hpp
	src/Nazara/Core/Resource.cpp
	src/Nazara/Core/ResourceListener.cpp
	src/Nazara/Graphics/DeferredRenderQueue.cpp
	src/Nazara/Graphics/ForwardRenderQueue.cpp
	src/Nazara/Graphics/SkinningManager.cpp
	src/Nazara/Renderer/RenderTexture.cpp
	src/Nazara/Renderer/Renderer.cpp
	src/Nazara/Utility/Mesh.cpp

Former-commit-id: 99b5ad26a19fe9c9f8118da7b5920bffe89f60f8
This commit is contained in:
Lynix
2015-01-25 19:29:55 +01:00
579 changed files with 11958 additions and 3706 deletions

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -80,6 +80,21 @@ const NzFrustumf& NzCamera::GetFrustum() const
return m_frustum;
}
NzVector3f NzCamera::GetGlobalForward() const
{
return NzVector3f::Forward();
}
NzVector3f NzCamera::GetGlobalRight() const
{
return NzVector3f::Right();
}
NzVector3f NzCamera::GetGlobalUp() const
{
return NzVector3f::Up();
}
const NzMatrix4f& NzCamera::GetProjectionMatrix() const
{
if (!m_projectionMatrixUpdated)

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -10,9 +10,9 @@
NzDeferredBloomPass::NzDeferredBloomPass() :
m_uniformUpdated(false),
m_brightLuminance(0.8),
m_brightMiddleGrey(0.5),
m_brightThreshold(0.8),
m_brightLuminance(0.8f),
m_brightMiddleGrey(0.5f),
m_brightThreshold(0.8f),
m_blurPassCount(5)
{
m_bilinearSampler.SetAnisotropyLevel(1);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -125,6 +125,7 @@ NzDeferredFogPass::NzDeferredFogPass()
m_pointSampler.SetWrapMode(nzSamplerWrap_Clamp);
m_shader = BuildFogShader();
m_shaderEyePositionLocation = m_shader->GetUniformLocation("EyePosition");
m_states.parameters[nzRendererParameter_DepthBuffer] = false;
}
@@ -138,7 +139,7 @@ bool NzDeferredFogPass::Process(const NzScene* scene, unsigned int firstWorkText
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetShader(m_shader);
m_shader->SendVector(m_shader->GetUniformLocation(nzShaderUniform_EyePosition), scene->GetViewer()->GetEyePosition());
m_shader->SendVector(m_shaderEyePositionLocation, scene->GetViewer()->GetEyePosition());
NzRenderer::SetRenderStates(m_states);
NzRenderer::SetTexture(0, m_workTextures[secondWorkTexture]);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -51,23 +51,21 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
NzRenderer::SetMatrix(nzMatrixType_View, viewer->GetViewMatrix());
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
for (auto& matIt : m_renderQueue->opaqueModels)
{
bool& used = std::get<0>(matIt.second);
if (used)
auto& matEntry = matIt.second;
if (matEntry.enabled)
{
bool& renderQueueInstancing = std::get<1>(matIt.second);
NzDeferredRenderQueue::MeshInstanceContainer& meshInstances = std::get<2>(matIt.second);
NzDeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
if (!meshInstances.empty())
{
const NzMaterial* material = matIt.first;
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches
// (Le deferred shading n'a pas ce problème)
bool useInstancing = instancingEnabled && renderQueueInstancing;
bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
// On commence par récupérer le programme du matériau
nzUInt32 flags = nzShaderFlags_Deferred;
@@ -79,10 +77,13 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
@@ -91,28 +92,29 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
for (auto& meshIt : meshInstances)
{
const NzMeshData& meshData = meshIt.first;
std::vector<NzMatrix4f>& instances = meshIt.second;
auto& meshEntry = meshIt.second;
std::vector<NzMatrix4f>& instances = meshEntry.instances;
if (!instances.empty())
{
const NzIndexBuffer* indexBuffer = meshData.indexBuffer;
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> DrawFunc;
std::function<void(unsigned int, nzPrimitiveMode, unsigned int, unsigned int)> InstancedDrawFunc;
NzRenderer::DrawCall drawFunc;
NzRenderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount;
if (indexBuffer)
{
DrawFunc = NzRenderer::DrawIndexedPrimitives;
InstancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
drawFunc = NzRenderer::DrawIndexedPrimitives;
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
indexCount = indexBuffer->GetIndexCount();
}
else
{
DrawFunc = NzRenderer::DrawPrimitives;
InstancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
drawFunc = NzRenderer::DrawPrimitives;
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
indexCount = vertexBuffer->GetVertexCount();
}
@@ -140,18 +142,18 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
instanceMatrices += renderedInstanceCount;
// Et on affiche
InstancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
}
}
else
{
// Sans instancing, on doit effectuer un drawcall pour chaque instance
// Sans instancing, on doit effectuer un draw call pour chaque instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
// À cause du temps de modification du buffer d'instancing
for (const NzMatrix4f& matrix : instances)
{
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
DrawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
}
@@ -161,8 +163,8 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
}
// Et on remet à zéro les données
renderQueueInstancing = false;
used = false;
matEntry.enabled = false;
matEntry.instancingEnabled = false;
}
}
@@ -228,7 +230,23 @@ bool NzDeferredGeometryPass::Resize(const NzVector2ui& dimensions)
}
catch (const std::exception& e)
{
NazaraError("Failed to create G-Buffer RTT");
NazaraError("Failed to create G-Buffer RTT: " + NzString(e.what()));
return false;
}
}
const NzDeferredGeometryPass::ShaderUniforms* NzDeferredGeometryPass::GetShaderUniforms(const NzShader* shader) const
{
auto it = m_shaderUniforms.find(shader);
if (it == m_shaderUniforms.end())
{
ShaderUniforms uniforms;
uniforms.eyePosition = shader->GetUniformLocation("EyePosition");
uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient");
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
it = m_shaderUniforms.emplace(shader, uniforms).first;
}
return &it->second;
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -17,6 +17,8 @@ NzDeferredPhongLightingPass::NzDeferredPhongLightingPass() :
m_lightMeshesDrawing(false)
{
m_directionalLightShader = NzShaderLibrary::Get("DeferredDirectionnalLight");
m_directionalLightShaderEyePositionLocation = m_directionalLightShader->GetUniformLocation("EyePosition");
m_directionalLightShaderSceneAmbientLocation = m_directionalLightShader->GetUniformLocation("SceneAmbient");
m_directionalLightUniforms.ubo = false;
m_directionalLightUniforms.locations.type = -1; // Type déjà connu
@@ -28,6 +30,8 @@ m_lightMeshesDrawing(false)
m_pointSpotLightShader = NzShaderLibrary::Get("DeferredPointSpotLight");
m_pointSpotLightShaderDiscardLocation = m_pointSpotLightShader->GetUniformLocation("Discard");
m_pointSpotLightShaderEyePositionLocation = m_pointSpotLightShader->GetUniformLocation("EyePosition");
m_pointSpotLightShaderSceneAmbientLocation = m_pointSpotLightShader->GetUniformLocation("SceneAmbient");
m_pointSpotLightUniforms.ubo = false;
m_pointSpotLightUniforms.locations.type = m_pointSpotLightShader->GetUniformLocation("LightType");
@@ -96,8 +100,8 @@ bool NzDeferredPhongLightingPass::Process(const NzScene* scene, unsigned int fir
{
NzRenderer::SetRenderStates(lightStates);
NzRenderer::SetShader(m_directionalLightShader);
m_directionalLightShader->SendColor(m_directionalLightShader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
m_directionalLightShader->SendVector(m_directionalLightShader->GetUniformLocation(nzShaderUniform_EyePosition), scene->GetViewer()->GetEyePosition());
m_directionalLightShader->SendColor(m_directionalLightShaderSceneAmbientLocation, scene->GetAmbientColor());
m_directionalLightShader->SendVector(m_directionalLightShaderEyePositionLocation, scene->GetViewer()->GetEyePosition());
for (const NzLight* light : m_renderQueue->directionalLights)
{
@@ -126,8 +130,8 @@ bool NzDeferredPhongLightingPass::Process(const NzScene* scene, unsigned int fir
NzRenderer::SetRenderStates(lightStates);
NzRenderer::SetShader(m_pointSpotLightShader);
m_pointSpotLightShader->SendColor(m_pointSpotLightShader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
m_pointSpotLightShader->SendVector(m_pointSpotLightShader->GetUniformLocation(nzShaderUniform_EyePosition), scene->GetViewer()->GetEyePosition());
m_pointSpotLightShader->SendColor(m_pointSpotLightShaderEyePositionLocation, scene->GetAmbientColor());
m_pointSpotLightShader->SendVector(m_pointSpotLightShaderSceneAmbientLocation, scene->GetViewer()->GetEyePosition());
NzMatrix4f lightMatrix;
lightMatrix.MakeIdentity();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,16 +1,15 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/DeferredRenderQueue.hpp>
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/ForwardRenderQueue.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Graphics/Debug.hpp>
///TODO: Rendre les billboards via Deferred Shading si possible
namespace
{
enum ObjectType
@@ -26,9 +25,49 @@ m_forwardQueue(forwardQueue)
{
}
NzDeferredRenderQueue::~NzDeferredRenderQueue()
void NzDeferredRenderQueue::AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos, const NzColor& color)
{
Clear(true);
m_forwardQueue->AddBillboard(material, position, size, sinCos, color);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
}
void NzDeferredRenderQueue::AddDrawable(const NzDrawable* drawable)
@@ -46,6 +85,7 @@ void NzDeferredRenderQueue::AddLight(const NzLight* light)
}
#endif
// On trie la lumière (elles sont traitées différement selon leur type)
switch (light->GetLightType())
{
case nzLightType_Directional:
@@ -61,71 +101,55 @@ void NzDeferredRenderQueue::AddLight(const NzLight* light)
break;
}
// On envoie également la lumière au forward-shading
///TODO: Possibilité pour une lumière de se réserver au Deferred Shading
m_forwardQueue->AddLight(light);
}
void NzDeferredRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix)
{
if (material->IsEnabled(nzRendererParameter_Blend))
// Un matériau transparent ? J'aime pas, va voir dans la forward queue si j'y suis
m_forwardQueue->AddMesh(material, meshData, meshAABB, transformMatrix);
else
{
ModelBatches::iterator it = opaqueModels.find(material);
auto it = opaqueModels.find(material);
if (it == opaqueModels.end())
{
it = opaqueModels.insert(std::make_pair(material, ModelBatches::mapped_type())).first;
material->AddObjectListener(this, ObjectType_Material);
BatchedModelEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
}
bool& used = std::get<0>(it->second);
bool& enableInstancing = std::get<1>(it->second);
MeshInstanceContainer& meshMap = std::get<2>(it->second);
BatchedModelEntry& entry = it->second;
entry.enabled = true;
used = true;
auto& meshMap = entry.meshMap;
MeshInstanceContainer::iterator it2 = meshMap.find(meshData);
auto it2 = meshMap.find(meshData);
if (it2 == meshMap.end())
{
it2 = meshMap.insert(std::make_pair(meshData, MeshInstanceContainer::mapped_type())).first;
MeshInstanceEntry instanceEntry(this, ObjectType_IndexBuffer, ObjectType_VertexBuffer);
instanceEntry.indexBufferListener = meshData.indexBuffer;
instanceEntry.vertexBufferListener = meshData.vertexBuffer;
if (meshData.indexBuffer)
meshData.indexBuffer->AddObjectListener(this, ObjectType_IndexBuffer);
meshData.vertexBuffer->AddObjectListener(this, ObjectType_VertexBuffer);
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
}
std::vector<NzMatrix4f>& instances = it2->second;
// On ajoute la matrice à la liste des instances de cet objet
std::vector<NzMatrix4f>& instances = it2->second.instances;
instances.push_back(transformMatrix);
// Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ?
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
enableInstancing = true; // Apparemment oui, activons l'instancing avec ce matériau
entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau
}
}
void NzDeferredRenderQueue::AddSprite(const NzSprite* sprite)
void NzDeferredRenderQueue::AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay)
{
#if NAZARA_GRAPHICS_SAFE
if (!sprite)
{
NazaraError("Invalid sprite");
return;
}
if (!sprite->IsDrawable())
{
NazaraError("Sprite is not drawable");
return;
}
#endif
/*NzMaterial* material = sprite->GetMaterial();
if (!material->IsLightingEnabled() || material->IsEnabled(nzRendererParameter_Blend))
m_forwardQueue->AddSprite(sprite);
else
sprites[material].push_back(sprite);*/
m_forwardQueue->AddSprite(sprite);
m_forwardQueue->AddSprites(material, vertices, spriteCount, overlay);
}
void NzDeferredRenderQueue::Clear(bool fully)
@@ -135,27 +159,7 @@ void NzDeferredRenderQueue::Clear(bool fully)
spotLights.clear();
if (fully)
{
for (auto& matIt : opaqueModels)
{
const NzMaterial* material = matIt.first;
material->RemoveObjectListener(this);
MeshInstanceContainer& instances = std::get<2>(matIt.second);
for (auto& instanceIt : instances)
{
const NzMeshData& renderData = instanceIt.first;
if (renderData.indexBuffer)
renderData.indexBuffer->RemoveObjectListener(this);
renderData.vertexBuffer->RemoveObjectListener(this);
}
}
opaqueModels.clear();
sprites.clear();
}
m_forwardQueue->Clear(fully);
}
@@ -168,7 +172,7 @@ bool NzDeferredRenderQueue::OnObjectDestroy(const NzRefCounted* object, int inde
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -182,14 +186,18 @@ bool NzDeferredRenderQueue::OnObjectDestroy(const NzRefCounted* object, int inde
}
case ObjectType_Material:
opaqueModels.erase(static_cast<const NzMaterial*>(object));
{
const NzMaterial* material = static_cast<const NzMaterial*>(object);
opaqueModels.erase(material);
break;
}
case ObjectType_VertexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -217,7 +225,7 @@ void NzDeferredRenderQueue::OnObjectReleased(const NzRefCounted* object, int ind
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -247,7 +255,7 @@ void NzDeferredRenderQueue::OnObjectReleased(const NzRefCounted* object, int ind
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -282,26 +290,6 @@ bool NzDeferredRenderQueue::BatchedModelMaterialComparator::operator()(const NzM
return mat1 < mat2;
}
bool NzDeferredRenderQueue::BatchedSpriteMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
{
const NzUberShader* uberShader1 = mat1->GetShader();
const NzUberShader* uberShader2 = mat2->GetShader();
if (uberShader1 != uberShader2)
return uberShader1 < uberShader2;
const NzShader* shader1 = mat1->GetShaderInstance(nzShaderFlags_Deferred)->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance(nzShaderFlags_Deferred)->GetShader();
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;
}
bool NzDeferredRenderQueue::MeshDataComparator::operator()(const NzMeshData& data1, const NzMeshData& data2)
{
const NzBuffer* buffer1;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -21,6 +21,7 @@
#include <Nazara/Graphics/Drawable.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/OpenGL.hpp>
@@ -35,6 +36,34 @@
namespace
{
const nzUInt8 r_fragmentSource_BloomBright[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/BloomBright.frag.h>
};
const nzUInt8 r_fragmentSource_BloomFinal[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/BloomFinal.frag.h>
};
const nzUInt8 r_fragmentSource_DirectionalLight[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/DirectionalLight.frag.h>
};
const nzUInt8 r_fragmentSource_FXAA[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/FXAA.frag.h>
};
const nzUInt8 r_fragmentSource_GBufferClear[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/GBufferClear.frag.h>
};
const nzUInt8 r_fragmentSource_GaussianBlur[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/GaussianBlur.frag.h>
};
const nzUInt8 r_fragmentSource_PointSpotLight[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/PointSpotLight.frag.h>
};
unsigned int RenderPassPriority[] =
{
6, // nzRenderPassType_AA
@@ -412,34 +441,6 @@ bool NzDeferredRenderTechnique::Resize(const NzVector2ui& dimensions) const
bool NzDeferredRenderTechnique::Initialize()
{
const nzUInt8 fragmentSource_BloomBright[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/BloomBright.frag.h>
};
const nzUInt8 fragmentSource_BloomFinal[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/BloomFinal.frag.h>
};
const nzUInt8 fragmentSource_DirectionalLight[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/DirectionalLight.frag.h>
};
const nzUInt8 fragmentSource_FXAA[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/FXAA.frag.h>
};
const nzUInt8 fragmentSource_GBufferClear[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/GBufferClear.frag.h>
};
const nzUInt8 fragmentSource_GaussianBlur[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/GaussianBlur.frag.h>
};
const nzUInt8 fragmentSource_PointSpotLight[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/PointSpotLight.frag.h>
};
const char vertexSource_Basic[] =
"#version 140\n"
@@ -497,7 +498,7 @@ bool NzDeferredRenderTechnique::Initialize()
NzShader* shader;
// Shaders critiques (Nécessaires pour le Deferred Shading minimal)
shader = RegisterDeferredShader("DeferredGBufferClear", fragmentSource_GBufferClear, sizeof(fragmentSource_GBufferClear), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredGBufferClear", r_fragmentSource_GBufferClear, sizeof(r_fragmentSource_GBufferClear), ppVertexStage, &error);
if (!shader)
{
NazaraError("Failed to register critical shader: " + error);
@@ -505,7 +506,7 @@ bool NzDeferredRenderTechnique::Initialize()
}
shader = RegisterDeferredShader("DeferredDirectionnalLight", fragmentSource_DirectionalLight, sizeof(fragmentSource_DirectionalLight), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredDirectionnalLight", r_fragmentSource_DirectionalLight, sizeof(r_fragmentSource_DirectionalLight), ppVertexStage, &error);
if (!shader)
{
NazaraError("Failed to register critical shader: " + error);
@@ -517,7 +518,7 @@ bool NzDeferredRenderTechnique::Initialize()
shader->SendInteger(shader->GetUniformLocation("GBuffer2"), 2);
shader = RegisterDeferredShader("DeferredPointSpotLight", fragmentSource_PointSpotLight, sizeof(fragmentSource_PointSpotLight), basicVertexStage, &error);
shader = RegisterDeferredShader("DeferredPointSpotLight", r_fragmentSource_PointSpotLight, sizeof(r_fragmentSource_PointSpotLight), basicVertexStage, &error);
if (!shader)
{
NazaraError("Failed to register critical shader: " + error);
@@ -530,7 +531,7 @@ bool NzDeferredRenderTechnique::Initialize()
// Shaders optionnels (S'ils ne sont pas présents, le rendu minimal sera quand même assuré)
shader = RegisterDeferredShader("DeferredBloomBright", fragmentSource_BloomBright, sizeof(fragmentSource_BloomBright), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredBloomBright", r_fragmentSource_BloomBright, sizeof(r_fragmentSource_BloomBright), ppVertexStage, &error);
if (shader)
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
else
@@ -539,7 +540,7 @@ bool NzDeferredRenderTechnique::Initialize()
}
shader = RegisterDeferredShader("DeferredBloomFinal", fragmentSource_BloomFinal, sizeof(fragmentSource_BloomFinal), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredBloomFinal", r_fragmentSource_BloomFinal, sizeof(r_fragmentSource_BloomFinal), ppVertexStage, &error);
if (shader)
{
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
@@ -551,7 +552,7 @@ bool NzDeferredRenderTechnique::Initialize()
}
shader = RegisterDeferredShader("DeferredFXAA", fragmentSource_FXAA, sizeof(fragmentSource_FXAA), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredFXAA", r_fragmentSource_FXAA, sizeof(r_fragmentSource_FXAA), ppVertexStage, &error);
if (shader)
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
else
@@ -560,7 +561,7 @@ bool NzDeferredRenderTechnique::Initialize()
}
shader = RegisterDeferredShader("DeferredGaussianBlur", fragmentSource_GaussianBlur, sizeof(fragmentSource_GaussianBlur), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredGaussianBlur", r_fragmentSource_GaussianBlur, sizeof(r_fragmentSource_GaussianBlur), ppVertexStage, &error);
if (shader)
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
else

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,30 +1,360 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ForwardRenderQueue.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Utility/SkeletalMesh.hpp>
#include <Nazara/Utility/StaticMesh.hpp>
#include <Nazara/Graphics/Debug.hpp>
///TODO: Remplacer les sinus/cosinus par une lookup table (va booster les perfs d'un bon x10)
namespace
{
enum ResourceType
enum ObjectType
{
ResourceType_IndexBuffer,
ResourceType_Material,
ResourceType_VertexBuffer
ObjectType_IndexBuffer,
ObjectType_Material,
ObjectType_Texture,
ObjectType_VertexBuffer
};
}
NzForwardRenderQueue::~NzForwardRenderQueue()
void NzForwardRenderQueue::AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos, const NzColor& color)
{
Clear(true);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
billboardVector.push_back(BillboardData{color, position, size, sinCos});
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos = *sinCosPtr++;
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
float defaultAlpha = 1.f;
if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = NzColor(255, 255, 255, static_cast<nzUInt8>(255.f * (*alphaPtr++)));
billboardData->sinCos = *sinCosPtr++;
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f;
if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
float sin = std::sin(NzToRadians(*anglePtr));
float cos = std::cos(NzToRadians(*anglePtr));
anglePtr++;
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos.Set(sin, cos);
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f;
if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
float defaultAlpha = 1.f;
if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
float sin = std::sin(NzToRadians(*anglePtr));
float cos = std::cos(NzToRadians(*anglePtr));
anglePtr++;
billboardData->center = *positionPtr++;
billboardData->color = NzColor(255, 255, 255, static_cast<nzUInt8>(255.f * (*alphaPtr++)));
billboardData->sinCos.Set(sin, cos);
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos = *sinCosPtr++;
billboardData->size.Set(*sizePtr++);
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
float defaultAlpha = 1.f;
if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = NzColor(255, 255, 255, static_cast<nzUInt8>(255.f * (*alphaPtr++)));
billboardData->sinCos = *sinCosPtr++;
billboardData->size.Set(*sizePtr++);
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f;
if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
float sin = std::sin(NzToRadians(*anglePtr));
float cos = std::cos(NzToRadians(*anglePtr));
anglePtr++;
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos.Set(sin, cos);
billboardData->size.Set(*sizePtr++);
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f;
if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
float defaultAlpha = 1.f;
if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
float sin = std::sin(NzToRadians(*anglePtr));
float cos = std::cos(NzToRadians(*anglePtr));
anglePtr++;
billboardData->center = *positionPtr++;
billboardData->color = NzColor(255, 255, 255, static_cast<nzUInt8>(255.f * (*alphaPtr++)));
billboardData->sinCos.Set(sin, cos);
billboardData->size.Set(*sizePtr++);
billboardData++;
}
}
void NzForwardRenderQueue::AddDrawable(const NzDrawable* drawable)
@@ -72,72 +402,81 @@ void NzForwardRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData&
{
if (material->IsEnabled(nzRendererParameter_Blend))
{
// Le matériau est transparent, nous devons rendre ce mesh d'une autre façon (après le rendu des objets opaques et en les triant)
unsigned int index = transparentModelData.size();
transparentModelData.resize(index+1);
TransparentModelData& data = transparentModelData.back();
data.boundingSphere = NzSpheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
data.material = material;
data.meshData = meshData;
data.squaredBoundingSphere = NzSpheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
data.transformMatrix = transformMatrix;
transparentModels.push_back(index);
}
else
{
ModelBatches::iterator it = opaqueModels.find(material);
auto it = opaqueModels.find(material);
if (it == opaqueModels.end())
{
it = opaqueModels.insert(std::make_pair(material, ModelBatches::mapped_type())).first;
material->AddObjectListener(this, ResourceType_Material);
BatchedModelEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
}
bool& used = std::get<0>(it->second);
bool& enableInstancing = std::get<1>(it->second);
MeshInstanceContainer& meshMap = std::get<2>(it->second);
BatchedModelEntry& entry = it->second;
entry.enabled = true;
used = true;
auto& meshMap = entry.meshMap;
MeshInstanceContainer::iterator it2 = meshMap.find(meshData);
auto it2 = meshMap.find(meshData);
if (it2 == meshMap.end())
{
it2 = meshMap.insert(std::make_pair(meshData, MeshInstanceContainer::mapped_type())).first;
MeshInstanceEntry instanceEntry(this, ObjectType_IndexBuffer, ObjectType_VertexBuffer);
instanceEntry.indexBufferListener = meshData.indexBuffer;
instanceEntry.squaredBoundingSphere = meshAABB.GetSquaredBoundingSphere();
instanceEntry.vertexBufferListener = meshData.vertexBuffer;
NzSpheref& squaredBoundingSphere = it2->second.first;
squaredBoundingSphere.Set(meshAABB.GetSquaredBoundingSphere());
if (meshData.indexBuffer)
meshData.indexBuffer->AddObjectListener(this, ResourceType_IndexBuffer);
meshData.vertexBuffer->AddObjectListener(this, ResourceType_VertexBuffer);
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
}
std::vector<NzMatrix4f>& instances = it2->second.second;
std::vector<NzMatrix4f>& instances = it2->second.instances;
instances.push_back(transformMatrix);
// Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ?
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
enableInstancing = true; // Apparemment oui, activons l'instancing avec ce matériau
entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau
}
}
void NzForwardRenderQueue::AddSprite(const NzSprite* sprite)
void NzForwardRenderQueue::AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay)
{
#if NAZARA_GRAPHICS_SAFE
if (!sprite)
auto matIt = basicSprites.find(material);
if (matIt == basicSprites.end())
{
NazaraError("Invalid sprite");
return;
BatchedBasicSpriteEntry entry(this, ObjectType_Material);
entry.materialListener = material;
matIt = basicSprites.insert(std::make_pair(material, std::move(entry))).first;
}
if (!sprite->IsDrawable())
{
NazaraError("Sprite is not drawable");
return;
}
#endif
BatchedBasicSpriteEntry& entry = matIt->second;
entry.enabled = true;
sprites[sprite->GetMaterial()].push_back(sprite);
auto& overlayMap = entry.overlayMap;
auto overlayIt = overlayMap.find(overlay);
if (overlayIt == overlayMap.end())
{
BatchedSpriteEntry overlayEntry(this, ObjectType_Texture);
overlayEntry.textureListener = overlay;
overlayIt = overlayMap.insert(std::make_pair(overlay, std::move(overlayEntry))).first;
}
auto& spriteVector = overlayIt->second.spriteChains;
spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount}));
}
void NzForwardRenderQueue::Clear(bool fully)
@@ -150,53 +489,55 @@ void NzForwardRenderQueue::Clear(bool fully)
if (fully)
{
for (auto& matIt : opaqueModels)
{
const NzMaterial* material = matIt.first;
material->RemoveObjectListener(this);
MeshInstanceContainer& instances = std::get<2>(matIt.second);
for (auto& instanceIt : instances)
{
const NzMeshData& renderData = instanceIt.first;
if (renderData.indexBuffer)
renderData.indexBuffer->RemoveObjectListener(this);
renderData.vertexBuffer->RemoveObjectListener(this);
}
}
basicSprites.clear();
billboards.clear();
opaqueModels.clear();
sprites.clear();
}
}
void NzForwardRenderQueue::Sort(const NzAbstractViewer* viewer)
{
NzPlanef nearPlane = viewer->GetFrustum().GetPlane(nzFrustumPlane_Near);
NzVector3f viewerPos = viewer->GetEyePosition();
NzVector3f viewerNormal = viewer->GetForward();
std::sort(transparentModels.begin(), transparentModels.end(), [this, &nearPlane, &viewerNormal](unsigned int index1, unsigned int index2)
{
const NzSpheref& sphere1 = transparentModelData[index1].boundingSphere;
const NzSpheref& sphere2 = transparentModelData[index2].boundingSphere;
const NzSpheref& sphere1 = transparentModelData[index1].squaredBoundingSphere;
const NzSpheref& sphere2 = transparentModelData[index2].squaredBoundingSphere;
NzVector3f position1 = sphere1.GetNegativeVertex(viewerNormal);
NzVector3f position2 = sphere2.GetNegativeVertex(viewerNormal);
return nearPlane.Distance(position1) > nearPlane.Distance(position2);
});
for (auto& pair : billboards)
{
const NzMaterial* mat = pair.first;
if (mat->IsDepthSortingEnabled())
{
BatchedBillboardEntry& entry = pair.second;
auto& billboardVector = entry.billboards;
std::sort(billboardVector.begin(), billboardVector.end(), [&viewerPos](const BillboardData& data1, const BillboardData& data2)
{
return viewerPos.SquaredDistance(data1.center) > viewerPos.SquaredDistance(data2.center);
});
}
}
}
bool NzForwardRenderQueue::OnObjectDestroy(const NzRefCounted* object, int index)
{
switch (index)
{
case ResourceType_IndexBuffer:
case ObjectType_IndexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -209,15 +550,21 @@ bool NzForwardRenderQueue::OnObjectDestroy(const NzRefCounted* object, int index
break;
}
case ResourceType_Material:
opaqueModels.erase(static_cast<const NzMaterial*>(object));
break;
case ObjectType_Material:
{
const NzMaterial* material = static_cast<const NzMaterial*>(object);
case ResourceType_VertexBuffer:
basicSprites.erase(material);
billboards.erase(material);
opaqueModels.erase(material);
break;
}
case ObjectType_VertexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -241,11 +588,11 @@ void NzForwardRenderQueue::OnObjectReleased(const NzRefCounted* object, int inde
switch (index)
{
case ResourceType_IndexBuffer:
case ObjectType_IndexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -258,8 +605,26 @@ void NzForwardRenderQueue::OnObjectReleased(const NzRefCounted* object, int inde
break;
}
case ResourceType_Material:
case ObjectType_Material:
{
for (auto it = basicSprites.begin(); it != basicSprites.end(); ++it)
{
if (it->first == object)
{
basicSprites.erase(it);
break;
}
}
for (auto it = billboards.begin(); it != billboards.end(); ++it)
{
if (it->first == object)
{
billboards.erase(it);
break;
}
}
for (auto it = opaqueModels.begin(); it != opaqueModels.end(); ++it)
{
if (it->first == object)
@@ -268,14 +633,33 @@ void NzForwardRenderQueue::OnObjectReleased(const NzRefCounted* object, int inde
break;
}
}
break;
}
case ResourceType_VertexBuffer:
case ObjectType_Texture:
{
for (auto matIt = basicSprites.begin(); matIt != basicSprites.end(); ++matIt)
{
auto& overlayMap = matIt->second.overlayMap;
for (auto overlayIt = overlayMap.begin(); overlayIt != overlayMap.end(); ++overlayIt)
{
if (overlayIt->first == object)
{
overlayMap.erase(overlayIt);
break;
}
}
}
break;
}
case ObjectType_VertexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -290,6 +674,26 @@ void NzForwardRenderQueue::OnObjectReleased(const NzRefCounted* object, int inde
}
}
bool NzForwardRenderQueue::BatchedBillboardComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
{
const NzUberShader* uberShader1 = mat1->GetShader();
const NzUberShader* uberShader2 = mat2->GetShader();
if (uberShader1 != uberShader2)
return uberShader1 < uberShader2;
const NzShader* shader1 = mat1->GetShaderInstance(nzShaderFlags_Billboard | nzShaderFlags_VertexColor)->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance(nzShaderFlags_Billboard | nzShaderFlags_VertexColor)->GetShader();
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;
}
bool NzForwardRenderQueue::BatchedModelMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
{
const NzUberShader* uberShader1 = mat1->GetShader();
@@ -299,7 +703,6 @@ bool NzForwardRenderQueue::BatchedModelMaterialComparator::operator()(const NzMa
const NzShader* shader1 = mat1->GetShaderInstance()->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance()->GetShader();
if (shader1 != shader2)
return shader1 < shader2;
@@ -320,7 +723,6 @@ bool NzForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const NzM
const NzShader* shader1 = mat1->GetShaderInstance()->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance()->GetShader();
if (shader1 != shader2)
return shader1 < shader2;

View File

@@ -1,13 +1,16 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ForwardRenderTechnique.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/OffsetOf.hpp>
#include <Nazara/Graphics/AbstractBackground.hpp>
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/Drawable.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Renderer.hpp>
@@ -22,46 +25,29 @@
namespace
{
static NzIndexBuffer* s_indexBuffer = nullptr;
unsigned int s_maxSprites = 8192;
NzIndexBuffer* BuildIndexBuffer()
struct BillboardPoint
{
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(false, s_maxSprites*6, nzBufferStorage_Hardware, nzBufferUsage_Static));
indexBuffer->SetPersistent(false);
NzColor color;
NzVector3f position;
NzVector2f size;
NzVector2f sinCos; // doit suivre size
NzVector2f uv;
};
NzBufferMapper<NzIndexBuffer> mapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
nzUInt16* indices = static_cast<nzUInt16*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxSprites; ++i)
{
*indices++ = i*4 + 0;
*indices++ = i*4 + 2;
*indices++ = i*4 + 1;
*indices++ = i*4 + 2;
*indices++ = i*4 + 3;
*indices++ = i*4 + 1;
}
return indexBuffer.release();
}
unsigned int s_maxQuads = std::numeric_limits<nzUInt16>::max()/6;
unsigned int s_vertexBufferSize = 4*1024*1024; // 4 MiB
}
NzForwardRenderTechnique::NzForwardRenderTechnique() :
m_spriteBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ_UV), s_maxSprites*4, nzBufferStorage_Hardware, nzBufferUsage_Dynamic),
m_vertexBuffer(nzBufferType_Vertex),
m_maxLightPassPerObject(3)
{
if (!s_indexBuffer)
s_indexBuffer = BuildIndexBuffer();
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
m_indexBuffer = s_indexBuffer;
}
m_vertexBuffer.Create(s_vertexBufferSize, nzDataStorage_Hardware, nzBufferUsage_Dynamic);
NzForwardRenderTechnique::~NzForwardRenderTechnique()
{
if (m_indexBuffer.Reset())
s_indexBuffer = nullptr;
m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer);
m_spriteBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Color_UV), &m_vertexBuffer);
}
void NzForwardRenderTechnique::Clear(const NzScene* scene) const
@@ -87,59 +73,17 @@ bool NzForwardRenderTechnique::Draw(const NzScene* scene) const
if (!m_renderQueue.transparentModels.empty())
DrawTransparentModels(scene);
if (!m_renderQueue.sprites.empty())
DrawSprites(scene);
if (!m_renderQueue.basicSprites.empty())
DrawBasicSprites(scene);
if (!m_renderQueue.billboards.empty())
DrawBillboards(scene);
// Les autres drawables (Exemple: Terrain)
for (const NzDrawable* drawable : m_renderQueue.otherDrawables)
drawable->Draw();
return true;
// 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();
}
}*/
}
unsigned int NzForwardRenderTechnique::GetMaxLightPassPerObject() const
@@ -162,19 +106,329 @@ void NzForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int passCount)
m_maxLightPassPerObject = passCount;
}
void NzForwardRenderTechnique::DrawBasicSprites(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
NzRenderer::SetIndexBuffer(&s_quadIndexBuffer);
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
NzRenderer::SetVertexBuffer(&m_spriteBuffer);
for (auto& matIt : m_renderQueue.basicSprites)
{
const NzMaterial* material = matIt.first;
auto& matEntry = matIt.second;
if (matEntry.enabled)
{
auto& overlayMap = matEntry.overlayMap;
for (auto& overlayIt : overlayMap)
{
const NzTexture* overlay = overlayIt.first;
auto& spriteChainVector = overlayIt.second.spriteChains;
unsigned int spriteChainCount = spriteChainVector.size();
if (spriteChainCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
nzUInt32 flags = nzShaderFlags_VertexColor;
if (overlay)
flags |= nzShaderFlags_TextureOverlay;
nzUInt8 overlayUnit;
const NzShader* shader = material->Apply(flags, 0, &overlayUnit);
if (overlay)
{
overlayUnit++;
NzRenderer::SetTexture(overlayUnit, overlay);
NzRenderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
}
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Overlay
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous
unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés
do
{
// On ouvre le buffer en écriture
NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite);
NzVertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
unsigned int spriteCount = 0;
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount()/4);
do
{
NzForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(NzVertexStruct_XYZ_Color_UV));
vertices += count*4;
spriteCount += count;
spriteChainOffset += count;
// Avons-nous traité la chaîne entière ?
if (spriteChainOffset == currentChain.spriteCount)
{
spriteChain++;
spriteChainOffset = 0;
}
}
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, spriteCount*6);
}
while (spriteChain < spriteChainCount);
spriteChainVector.clear();
}
}
// On remet à zéro
matEntry.enabled = false;
}
}
}
bool NzForwardRenderTechnique::Initialize()
{
try
{
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
s_quadIndexBuffer.Reset(false, s_maxQuads*6, nzDataStorage_Hardware, nzBufferUsage_Static);
NzBufferMapper<NzIndexBuffer> mapper(s_quadIndexBuffer, nzBufferAccess_WriteOnly);
nzUInt16* indices = static_cast<nzUInt16*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxQuads; ++i)
{
*indices++ = i*4 + 0;
*indices++ = i*4 + 2;
*indices++ = i*4 + 1;
*indices++ = i*4 + 2;
*indices++ = i*4 + 3;
*indices++ = i*4 + 1;
}
mapper.Unmap(); // Inutile de garder le buffer ouvert plus longtemps
// Quad buffer (utilisé pour l'instancing de billboard et de sprites)
//Note: Les UV sont calculés dans le shader
s_quadVertexBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XY), 4, nzDataStorage_Hardware, nzBufferUsage_Static);
float vertices[2*4] = {
-0.5f, -0.5f,
0.5f, -0.5f,
-0.5f, 0.5f,
0.5f, 0.5f,
};
s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices));
// Déclaration lors du rendu des billboards par sommet
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(BillboardPoint, color));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(BillboardPoint, position));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_TexCoord, nzComponentType_Float2, NzOffsetOf(BillboardPoint, uv));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Userdata0, nzComponentType_Float4, NzOffsetOf(BillboardPoint, size)); // Englobe sincos
// Declaration utilisée lors du rendu des billboards par instancing
// L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData0, nzComponentType_Float3, NzOffsetOf(NzForwardRenderQueue::BillboardData, center));
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData1, nzComponentType_Float4, NzOffsetOf(NzForwardRenderQueue::BillboardData, size)); // Englobe sincos
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData2, nzComponentType_Color, NzOffsetOf(NzForwardRenderQueue::BillboardData, color));
}
catch (const std::exception& e)
{
NazaraError("Failed to initialise: " + NzString(e.what()));
return false;
}
return true;
}
void NzForwardRenderTechnique::Uninitialize()
{
s_quadIndexBuffer.Reset();
s_quadVertexBuffer.Reset();
}
void NzForwardRenderTechnique::DrawBillboards(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
if (NzRenderer::HasCapability(nzRendererCap_Instancing))
{
NzVertexBuffer* instanceBuffer = NzRenderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration);
NzRenderer::SetVertexBuffer(&s_quadVertexBuffer);
for (auto& matIt : m_renderQueue.billboards)
{
const NzMaterial* material = matIt.first;
auto& entry = matIt.second;
auto& billboardVector = entry.billboards;
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply(nzShaderFlags_Billboard | nzShaderFlags_Instancing | nzShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
const NzForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
do
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
data += renderedBillboardCount;
NzRenderer::DrawPrimitivesInstanced(renderedBillboardCount, nzPrimitiveMode_TriangleStrip, 0, 4);
}
while (billboardCount > 0);
billboardVector.clear();
}
}
}
else
{
NzRenderer::SetIndexBuffer(&s_quadIndexBuffer);
NzRenderer::SetVertexBuffer(&m_billboardPointBuffer);
for (auto& matIt : m_renderQueue.billboards)
{
const NzMaterial* material = matIt.first;
auto& entry = matIt.second;
auto& billboardVector = entry.billboards;
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply(nzShaderFlags_Billboard | nzShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
const NzForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount()/4);
do
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
NzBufferMapper<NzVertexBuffer> vertexMapper(m_billboardPointBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4);
BillboardPoint* vertices = reinterpret_cast<BillboardPoint*>(vertexMapper.GetPointer());
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
{
const NzForwardRenderQueue::BillboardData& billboard = *data++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(0.f, 1.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(1.f, 1.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(0.f, 0.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(1.f, 0.f);
vertices++;
}
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedBillboardCount*6);
}
while (billboardCount > 0);
billboardVector.clear();
}
}
}
}
void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const LightUniforms* lightUniforms = nullptr;
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
for (auto& matIt : m_renderQueue.opaqueModels)
{
bool& used = std::get<0>(matIt.second);
if (used)
auto& matEntry = matIt.second;
if (matEntry.enabled)
{
bool& renderQueueInstancing = std::get<1>(matIt.second);
NzForwardRenderQueue::MeshInstanceContainer& meshInstances = std::get<2>(matIt.second);
NzForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
if (!meshInstances.empty())
{
@@ -183,7 +437,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches
// (Le deferred shading n'a pas ce problème)
bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || m_lights.IsEmpty()) && renderQueueInstancing;
bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || m_lights.IsEmpty()) && matEntry.instancingEnabled;
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply((instancing) ? nzShaderFlags_Instancing : 0);
@@ -191,23 +445,25 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Index des uniformes d'éclairage dans le shader
lightUniforms = GetLightUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
// Meshes
for (auto& subMeshIt : meshInstances)
for (auto& meshIt : meshInstances)
{
const NzMeshData& meshData = subMeshIt.first;
const NzSpheref& boundingSphere = subMeshIt.second.first;
std::vector<NzMatrix4f>& instances = subMeshIt.second.second;
const NzMeshData& meshData = meshIt.first;
auto& meshEntry = meshIt.second;
const NzSpheref& squaredBoundingSphere = meshEntry.squaredBoundingSphere;
std::vector<NzMatrix4f>& instances = meshEntry.instances;
if (!instances.empty())
{
@@ -215,20 +471,20 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> DrawFunc;
std::function<void(unsigned int, nzPrimitiveMode, unsigned int, unsigned int)> InstancedDrawFunc;
NzRenderer::DrawCall drawFunc;
NzRenderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount;
if (indexBuffer)
{
DrawFunc = NzRenderer::DrawIndexedPrimitives;
InstancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
drawFunc = NzRenderer::DrawIndexedPrimitives;
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
indexCount = indexBuffer->GetIndexCount();
}
else
{
DrawFunc = NzRenderer::DrawPrimitives;
InstancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
drawFunc = NzRenderer::DrawPrimitives;
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
indexCount = vertexBuffer->GetVertexCount();
}
@@ -250,7 +506,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
for (unsigned int pass = 0; pass < passCount; ++pass)
{
if (lightUniforms->exists)
if (shaderUniforms->hasLightUniforms)
{
unsigned int renderedLightCount = std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
lightCount -= renderedLightCount;
@@ -267,15 +523,15 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
}
for (unsigned int i = 0; i < renderedLightCount; ++i)
m_directionalLights.GetLight(lightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
m_directionalLights.GetLight(lightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
for (unsigned int i = renderedLightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
}
const NzMatrix4f* instanceMatrices = &instances[0];
unsigned int instanceCount = instances.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing)
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre maximum d'instances en une fois
while (instanceCount > 0)
{
@@ -288,7 +544,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
instanceMatrices += renderedInstanceCount;
// Et on affiche
InstancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
}
}
@@ -298,12 +554,12 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
}
else
{
if (lightUniforms->exists)
if (shaderUniforms->hasLightUniforms)
{
for (const NzMatrix4f& matrix : instances)
{
unsigned int directionalLightCount = m_directionalLights.GetLightCount();
unsigned int otherLightCount = m_lights.ComputeClosestLights(matrix.GetTranslation() + boundingSphere.GetPosition(), boundingSphere.radius, m_maxLightPassPerObject*NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - directionalLightCount);
unsigned int otherLightCount = m_lights.ComputeClosestLights(matrix.GetTranslation() + squaredBoundingSphere.GetPosition(), squaredBoundingSphere.radius, m_maxLightPassPerObject*NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - directionalLightCount);
unsigned int lightCount = directionalLightCount + otherLightCount;
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
@@ -332,17 +588,17 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
for (unsigned int i = 0; i < renderedLightCount; ++i)
{
if (directionalLightIndex >= directionalLightCount)
m_lights.GetResult(otherLightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
m_lights.GetResult(otherLightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
else
m_directionalLights.GetLight(directionalLightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
m_directionalLights.GetLight(directionalLightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
}
// On désactive l'éventuel surplus
for (unsigned int i = renderedLightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
// Et on passe à l'affichage
DrawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
NzRenderer::Enable(nzRendererParameter_Blend, false);
@@ -351,13 +607,13 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
}
else
{
// Sans instancing, on doit effectuer un drawcall pour chaque instance
// Sans instancing, on doit effectuer un draw call pour chaque instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
// À cause du temps de modification du buffer d'instancing
for (const NzMatrix4f& matrix : instances)
{
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
DrawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
}
}
@@ -367,84 +623,8 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
}
// Et on remet à zéro les données
renderQueueInstancing = false;
used = false;
}
}
}
void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShader* lastShader = nullptr;
NzRenderer::SetIndexBuffer(m_indexBuffer);
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
NzRenderer::SetVertexBuffer(&m_spriteBuffer);
for (auto& matIt : m_renderQueue.sprites)
{
const NzMaterial* material = matIt.first;
auto& spriteVector = matIt.second;
unsigned int spriteCount = spriteVector.size();
if (spriteCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply();
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
lastShader = shader;
}
const NzSprite** spritePtr = &spriteVector[0];
do
{
unsigned int renderedSpriteCount = std::min(spriteCount, 64U);
spriteCount -= renderedSpriteCount;
NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedSpriteCount*4);
NzVertexStruct_XYZ_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_UV*>(vertexMapper.GetPointer());
for (unsigned int i = 0; i < renderedSpriteCount; ++i)
{
const NzSprite* sprite = *spritePtr++;
const NzRectf& textureCoords = sprite->GetTextureCoords();
const NzVector2f& halfSize = sprite->GetSize()*0.5f;
NzVector3f center = sprite->GetPosition();
NzQuaternionf rotation = sprite->GetRotation();
vertices->position = center + rotation * NzVector3f(-halfSize.x, -halfSize.y, 0.f);
vertices->uv.Set(textureCoords.x, textureCoords.y + textureCoords.height);
vertices++;
vertices->position = center + rotation * NzVector3f(halfSize.x, -halfSize.y, 0.f);
vertices->uv.Set(textureCoords.width, textureCoords.y + textureCoords.height);
vertices++;
vertices->position = center + rotation * NzVector3f(-halfSize.x, halfSize.y, 0.f);
vertices->uv.Set(textureCoords.x, textureCoords.y);
vertices++;
vertices->position = center + rotation * NzVector3f(halfSize.x, halfSize.y, 0.f);
vertices->uv.Set(textureCoords.width, textureCoords.y);
vertices++;
}
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedSpriteCount*6);
}
while (spriteCount > 0);
spriteVector.clear();
matEntry.enabled = false;
matEntry.instancingEnabled = false;
}
}
}
@@ -452,8 +632,8 @@ void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const
void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const LightUniforms* lightUniforms = nullptr;
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
unsigned int lightCount = 0;
for (unsigned int index : m_renderQueue.transparentModels)
@@ -469,18 +649,18 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Index des uniformes d'éclairage dans le shader
lightUniforms = GetLightUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
lightCount = std::min(m_directionalLights.GetLightCount(), NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
for (unsigned int i = 0; i < lightCount; ++i)
m_directionalLights.GetLight(i)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
m_directionalLights.GetLight(i)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
lastShader = shader;
}
@@ -493,17 +673,17 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> DrawFunc;
NzRenderer::DrawCall drawFunc;
unsigned int indexCount;
if (indexBuffer)
{
DrawFunc = NzRenderer::DrawIndexedPrimitives;
drawFunc = NzRenderer::DrawIndexedPrimitives;
indexCount = indexBuffer->GetIndexCount();
}
else
{
DrawFunc = NzRenderer::DrawPrimitives;
drawFunc = NzRenderer::DrawPrimitives;
indexCount = vertexBuffer->GetVertexCount();
}
@@ -513,47 +693,58 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
// Calcul des lumières les plus proches
if (lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS && !m_lights.IsEmpty())
{
unsigned int count = std::min(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - lightCount, m_lights.ComputeClosestLights(matrix.GetTranslation() + modelData.boundingSphere.GetPosition(), modelData.boundingSphere.radius, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS));
NzVector3f position = matrix.GetTranslation() + modelData.squaredBoundingSphere.GetPosition();
float radius = modelData.squaredBoundingSphere.radius;
unsigned int closestLightCount = m_lights.ComputeClosestLights(position, radius, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS);
unsigned int count = std::min(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - lightCount, closestLightCount);
for (unsigned int i = 0; i < count; ++i)
m_lights.GetResult(i)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*(lightCount++));
m_lights.GetResult(i)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*(lightCount++));
}
for (unsigned int i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
DrawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
}
const NzForwardRenderTechnique::LightUniforms* NzForwardRenderTechnique::GetLightUniforms(const NzShader* shader) const
const NzForwardRenderTechnique::ShaderUniforms* NzForwardRenderTechnique::GetShaderUniforms(const NzShader* shader) const
{
auto it = m_lightUniforms.find(shader);
if (it != m_lightUniforms.end())
return &(it->second);
else
auto it = m_shaderUniforms.find(shader);
if (it == m_shaderUniforms.end())
{
ShaderUniforms uniforms;
uniforms.eyePosition = shader->GetUniformLocation("EyePosition");
uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient");
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
int type0Location = shader->GetUniformLocation("Lights[0].type");
int type1Location = shader->GetUniformLocation("Lights[1].type");
LightUniforms lightUniforms;
if (type0Location > 0 && type1Location > 0)
{
lightUniforms.exists = true;
lightUniforms.offset = type1Location - type0Location;
lightUniforms.uniforms.ubo = false;
lightUniforms.uniforms.locations.type = type0Location;
lightUniforms.uniforms.locations.color = shader->GetUniformLocation("Lights[0].color");
lightUniforms.uniforms.locations.factors = shader->GetUniformLocation("Lights[0].factors");
lightUniforms.uniforms.locations.parameters1 = shader->GetUniformLocation("Lights[0].parameters1");
lightUniforms.uniforms.locations.parameters2 = shader->GetUniformLocation("Lights[0].parameters2");
lightUniforms.uniforms.locations.parameters3 = shader->GetUniformLocation("Lights[0].parameters3");
uniforms.hasLightUniforms = true;
uniforms.lightOffset = type1Location - type0Location;
uniforms.lightUniforms.ubo = false;
uniforms.lightUniforms.locations.type = type0Location;
uniforms.lightUniforms.locations.color = shader->GetUniformLocation("Lights[0].color");
uniforms.lightUniforms.locations.factors = shader->GetUniformLocation("Lights[0].factors");
uniforms.lightUniforms.locations.parameters1 = shader->GetUniformLocation("Lights[0].parameters1");
uniforms.lightUniforms.locations.parameters2 = shader->GetUniformLocation("Lights[0].parameters2");
uniforms.lightUniforms.locations.parameters3 = shader->GetUniformLocation("Lights[0].parameters3");
}
else
lightUniforms.exists = false;
uniforms.hasLightUniforms = false;
auto pair = m_lightUniforms.emplace(shader, lightUniforms);
return &(pair.first->second);
it = m_shaderUniforms.emplace(shader, uniforms).first;
}
return &it->second;
}
NzIndexBuffer NzForwardRenderTechnique::s_quadIndexBuffer;
NzVertexBuffer NzForwardRenderTechnique::s_quadVertexBuffer;
NzVertexDeclaration NzForwardRenderTechnique::s_billboardInstanceDeclaration;
NzVertexDeclaration NzForwardRenderTechnique::s_billboardVertexDeclaration;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -9,13 +9,16 @@
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/DeferredRenderTechnique.hpp>
#include <Nazara/Graphics/ForwardRenderTechnique.hpp>
#include <Nazara/Graphics/GuillotineTextureAtlas.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/ParticleDeclaration.hpp>
#include <Nazara/Graphics/RenderTechniques.hpp>
#include <Nazara/Graphics/SkinningManager.hpp>
#include <Nazara/Graphics/Loaders/Mesh.hpp>
#include <Nazara/Graphics/Loaders/OBJ.hpp>
#include <Nazara/Graphics/Loaders/Texture.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Utility/Font.hpp>
#include <Nazara/Graphics/Debug.hpp>
bool NzGraphics::Initialize()
@@ -44,6 +47,12 @@ bool NzGraphics::Initialize()
return false;
}
if (!NzParticleDeclaration::Initialize())
{
NazaraError("Failed to initialize particle declarations");
return false;
}
if (!NzSkinningManager::Initialize())
{
NazaraError("Failed to initialize skinning manager");
@@ -58,14 +67,26 @@ bool NzGraphics::Initialize()
NzLoaders_Texture_Register();
// RenderTechniques
if (!NzForwardRenderTechnique::Initialize())
{
NazaraError("Failed to initialize Forward Rendering");
return false;
}
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_BasicForward), 0, []() -> NzAbstractRenderTechnique* { return new NzForwardRenderTechnique; });
if (NzDeferredRenderTechnique::IsSupported())
{
NzDeferredRenderTechnique::Initialize();
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_DeferredShading), 20, []() -> NzAbstractRenderTechnique* { return new NzDeferredRenderTechnique; });
if (NzDeferredRenderTechnique::Initialize())
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_DeferredShading), 20, []() -> NzAbstractRenderTechnique* { return new NzDeferredRenderTechnique; });
else
{
NazaraWarning("Failed to initialize Deferred Rendering");
}
}
NzFont::SetDefaultAtlas(std::make_shared<NzGuillotineTextureAtlas>());
onExit.Reset();
NazaraNotice("Initialized: Graphics module");
@@ -91,13 +112,40 @@ void NzGraphics::Uninitialize()
// Libération du module
s_moduleReferenceCounter = 0;
// Libération de l'atlas s'il vient de nous
std::shared_ptr<NzAbstractAtlas> defaultAtlas = NzFont::GetDefaultAtlas();
if (defaultAtlas && defaultAtlas->GetStorage() & nzDataStorage_Hardware)
{
NzFont::SetDefaultAtlas(nullptr);
// La police par défaut peut faire vivre un atlas hardware après la libération du module (ce qui va être problématique)
// du coup, si la police par défaut utilise un atlas hardware, on lui enlève.
// Je n'aime pas cette solution mais je n'en ai pas de meilleure sous la main pour l'instant
if (!defaultAtlas.unique())
{
// Encore au moins une police utilise l'atlas
NzFont* defaultFont = NzFont::GetDefault();
defaultFont->SetAtlas(nullptr);
if (!defaultAtlas.unique())
{
// Toujours pas seuls propriétaires ? Ah ben zut.
NazaraWarning("Default font atlas uses hardware storage and is still used");
}
}
}
defaultAtlas.reset();
// Loaders
NzLoaders_Mesh_Unregister();
NzLoaders_OBJ_Unregister();
NzLoaders_Texture_Unregister();
NzDeferredRenderTechnique::Uninitialize();
NzForwardRenderTechnique::Uninitialize();
NzMaterial::Uninitialize();
NzParticleDeclaration::Uninitialize();
NzSkinningManager::Uninitialize();
NazaraNotice("Uninitialized: Graphics module");

View File

@@ -0,0 +1,48 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/GuillotineTextureAtlas.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Graphics/Debug.hpp>
nzUInt32 NzGuillotineTextureAtlas::GetStorage() const
{
return nzDataStorage_Hardware;
}
NzAbstractImage* NzGuillotineTextureAtlas::ResizeImage(NzAbstractImage* oldImage, const NzVector2ui& size) const
{
std::unique_ptr<NzTexture> newTexture(new NzTexture);
if (newTexture->Create(nzImageType_2D, nzPixelFormat_A8, size.x, size.y, 1, 0xFF))
{
if (oldImage)
{
NzTexture* oldTexture = static_cast<NzTexture*>(oldImage);
// Copie des anciennes données
///TODO: Copie de texture à texture
NzImage image;
if (!oldTexture->Download(&image))
{
NazaraError("Failed to download old texture");
return nullptr;
}
if (!newTexture->Update(image, NzRectui(0, 0, image.GetWidth(), image.GetHeight())))
{
NazaraError("Failed to update texture");
return nullptr;
}
}
return newTexture.release();
}
else
{
// Si on arrive ici c'est que la taille demandée est trop grande pour la carte graphique
// ou que nous manquons de mémoire
return nullptr;
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -6,7 +6,7 @@
#include <Nazara/Core/Error.hpp>
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Math/Basic.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <Nazara/Math/Sphere.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Shader.hpp>
@@ -14,11 +14,11 @@
#include <Nazara/Graphics/Debug.hpp>
///TODO: Utilisation des UBOs
///TODO: Scale ?
NzLight::NzLight(nzLightType type) :
m_type(type),
m_color(NzColor::White),
m_boundingVolumeUpdated(false),
m_ambientFactor((type == nzLightType_Directional) ? 0.2f : 0.f),
m_attenuation(0.9f),
m_diffuseFactor(1.f),
@@ -31,9 +31,7 @@ m_radius(5.f)
NzLight::NzLight(const NzLight& light) :
NzSceneNode(light),
m_type(light.m_type),
m_boundingVolume(light.m_boundingVolume),
m_color(light.m_color),
m_boundingVolumeUpdated(light.m_boundingVolumeUpdated),
m_ambientFactor(light.m_ambientFactor),
m_attenuation(light.m_attenuation),
m_diffuseFactor(light.m_diffuseFactor),
@@ -41,7 +39,7 @@ m_innerAngle(light.m_innerAngle),
m_outerAngle(light.m_outerAngle),
m_radius(light.m_radius)
{
SetParent(light);
SetParent(light.GetParent());
}
void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
@@ -49,6 +47,16 @@ void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
renderQueue->AddLight(this);
}
NzLight* NzLight::Clone() const
{
return new NzLight(*this);
}
NzLight* NzLight::Create() const
{
return new NzLight;
}
void NzLight::Enable(const NzShader* shader, const NzLightUniforms& uniforms, int offset) const
{
/*
@@ -112,14 +120,6 @@ float NzLight::GetAttenuation() const
return m_attenuation;
}
const NzBoundingVolumef& NzLight::GetBoundingVolume() const
{
if (!m_boundingVolumeUpdated)
UpdateBoundingVolume();
return m_boundingVolume;
}
NzColor NzLight::GetColor() const
{
return m_color;
@@ -251,11 +251,45 @@ bool NzLight::FrustumCull(const NzFrustumf& frustum) const
return false;
}
void NzLight::InvalidateNode()
void NzLight::MakeBoundingVolume() const
{
NzSceneNode::InvalidateNode();
switch (m_type)
{
case nzLightType_Directional:
m_boundingVolume.MakeInfinite();
break;
m_boundingVolumeUpdated = false;
case nzLightType_Point:
{
NzVector3f radius(m_radius);
m_boundingVolume.Set(-radius, radius);
break;
}
case nzLightType_Spot:
{
// On forme une boite sur l'origine
NzBoxf box(NzVector3f::Zero());
// On calcule le reste des points
NzVector3f base(NzVector3f::Forward()*m_radius);
// Il nous faut maintenant le rayon du cercle projeté à cette distance
// Tangente = Opposé/Adjaçent <=> Opposé = Adjaçent*Tangente
float radius = m_radius*std::tan(NzDegreeToRadian(m_outerAngle));
NzVector3f lExtend = NzVector3f::Left()*radius;
NzVector3f uExtend = NzVector3f::Up()*radius;
// Et on ajoute ensuite les quatres extrémités de la pyramide
box.ExtendTo(base + lExtend + uExtend);
box.ExtendTo(base + lExtend - uExtend);
box.ExtendTo(base - lExtend + uExtend);
box.ExtendTo(base - lExtend - uExtend);
m_boundingVolume.Set(box);
break;
}
}
}
void NzLight::Register()
@@ -269,46 +303,7 @@ void NzLight::Unregister()
void NzLight::UpdateBoundingVolume() const
{
if (m_boundingVolume.IsNull())
{
switch (m_type)
{
case nzLightType_Directional:
m_boundingVolume.MakeInfinite();
m_boundingVolumeUpdated = true;
return; // Rien d'autre à faire
case nzLightType_Point:
{
NzVector3f radius(m_radius);
m_boundingVolume.Set(-radius, radius);
break;
}
case nzLightType_Spot:
{
// On forme une boite sur l'origine
NzBoxf box(NzVector3f::Zero());
// On calcule le reste des points
NzVector3f base(NzVector3f::Forward()*m_radius);
// Il nous faut maintenant le rayon du cercle projeté à cette distance
// Tangente = Opposé/Adjaçent <=> Opposé = Adjaçent*Tangente
float radius = m_radius*std::tan(NzDegreeToRadian(m_outerAngle));
NzVector3f lExtend = NzVector3f::Left()*radius;
NzVector3f uExtend = NzVector3f::Up()*radius;
// Et on ajoute ensuite les quatres extrémités de la pyramide
box.ExtendTo(base + lExtend + uExtend);
box.ExtendTo(base + lExtend - uExtend);
box.ExtendTo(base - lExtend + uExtend);
box.ExtendTo(base - lExtend - uExtend);
m_boundingVolume.Set(box);
break;
}
}
}
MakeBoundingVolume();
switch (m_type)
{

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -37,10 +37,10 @@ unsigned int NzLightManager::ComputeClosestLights(const NzVector3f& position, fl
light.score = std::numeric_limits<unsigned int>::max(); // Nous jouons au Golf
}
for (unsigned int i = 0; i < m_lights.size(); ++i)
for (auto it = m_lights.begin(); it != m_lights.end(); ++it)
{
const NzLight** lights = m_lights[i].first;
unsigned int lightCount = m_lights[i].second;
const NzLight** lights = it->first;
unsigned int lightCount = it->second;
for (unsigned int j = 0; j < lightCount; ++j)
{

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,10 +1,11 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Loaders/Mesh.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/SkeletalModel.hpp>
#include <Nazara/Utility/Mesh.hpp>
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
@@ -32,11 +33,71 @@ namespace
}
if (mesh->IsAnimable())
{
NazaraError("Can't load animated mesh into static model");
return false;
}
// Nous ne pouvons plus avoir recours au smart pointeur à partir d'ici si nous voulons être exception-safe
NzMesh* meshPtr = mesh.get();
model->Reset();
model->SetMesh(meshPtr);
mesh.release();
if (parameters.loadMaterials)
{
unsigned int matCount = model->GetMaterialCount();
for (unsigned int i = 0; i < matCount; ++i)
{
NzString mat = meshPtr->GetMaterial(i);
if (!mat.IsEmpty())
{
std::unique_ptr<NzMaterial> material(new NzMaterial);
material->SetPersistent(false);
if (material->LoadFromFile(mat, parameters.material))
{
model->SetMaterial(i, material.get());
material.release();
}
else
NazaraWarning("Failed to load material #" + NzString::Number(i));
}
}
}
return true;
}
nzTernary CheckAnimated(NzInputStream& stream, const NzSkeletalModelParameters& parameters)
{
NazaraUnused(stream);
NazaraUnused(parameters);
return nzTernary_Unknown;
}
bool LoadAnimated(NzSkeletalModel* model, NzInputStream& stream, const NzSkeletalModelParameters& parameters)
{
NazaraUnused(parameters);
std::unique_ptr<NzMesh> mesh(new NzMesh);
mesh->SetPersistent(false);
if (!mesh->LoadFromStream(stream, parameters.mesh))
{
NazaraError("Failed to load model mesh");
return false;
}
if (!mesh->IsAnimable())
{
NazaraError("Can't load static mesh into animated model");
return false;
}
// Nous ne pouvons plus avoir recours au smart pointeur à partir d'ici si nous voulons être exception-safe
NzMesh* meshPtr = mesh.get();
@@ -74,9 +135,11 @@ namespace
void NzLoaders_Mesh_Register()
{
NzModelLoader::RegisterLoader(NzMeshLoader::IsExtensionSupported, CheckStatic, LoadStatic);
NzSkeletalModelLoader::RegisterLoader(NzMeshLoader::IsExtensionSupported, CheckAnimated, LoadAnimated);
}
void NzLoaders_Mesh_Unregister()
{
NzModelLoader::UnregisterLoader(NzMeshLoader::IsExtensionSupported, CheckStatic, LoadStatic);
NzSkeletalModelLoader::UnregisterLoader(NzMeshLoader::IsExtensionSupported, CheckAnimated, LoadAnimated);
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -61,6 +61,8 @@ namespace
for (unsigned int i = 0; i < meshCount; ++i)
{
unsigned int faceCount = meshes[i].faces.size();
if (faceCount == 0)
continue;
std::vector<unsigned int> indices;
indices.reserve(faceCount*3); // Pire cas si les faces sont des triangles
@@ -97,6 +99,7 @@ namespace
}
}
// Création des buffers
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(vertexCount > std::numeric_limits<nzUInt16>::max(), indices.size(), parameters.mesh.storage, nzBufferUsage_Static));
indexBuffer->SetPersistent(false);
@@ -108,7 +111,7 @@ namespace
for (unsigned int j = 0; j < indices.size(); ++j)
indexMapper.Set(j, indices[j]);
indexMapper.Unmap();
indexMapper.Unmap(); // Pour laisser les autres tâches affecter l'index buffer
// Remplissage des vertices
bool hasNormals = true;
@@ -139,7 +142,7 @@ namespace
if (index >= 0)
{
const NzVector3f& uvw = texCoords[index];
vertex.uv.Set(uvw.x, uvw.y);
vertex.uv.Set(uvw.x, (parameters.mesh.flipUVs) ? 1.f - uvw.y : uvw.y); // Inversion des UVs si demandé
}
else
hasTexCoords = false;
@@ -167,9 +170,7 @@ namespace
subMesh->SetMaterialIndex(meshes[i].material);
subMesh->SetPrimitiveMode(nzPrimitiveMode_TriangleList);
if (parameters.mesh.center)
subMesh->Center();
// Ce que nous pouvons générer dépend des données à disposition (par exemple les tangentes nécessitent des coordonnées de texture)
if (hasNormals && hasTexCoords)
subMesh->GenerateTangents();
else if (hasTexCoords)
@@ -181,6 +182,18 @@ namespace
subMesh.release();
}
if (parameters.mesh.center)
{
unsigned int subMeshCount = mesh->GetSubMeshCount();
for (unsigned int i = 0; i < subMeshCount; ++i)
{
NzStaticMesh* subMesh = static_cast<NzStaticMesh*>(mesh->GetSubMesh(i));
subMesh->Center();
}
mesh->InvalidateAABB();
}
mesh->SetMaterialCount(parser.GetMaterialCount());
model->SetMesh(mesh.get());

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -27,7 +27,7 @@ NzOBJParser::~NzOBJParser()
const NzString* NzOBJParser::GetMaterials() const
{
return &m_materials[0];
return m_materials.data();
}
unsigned int NzOBJParser::GetMaterialCount() const
@@ -37,7 +37,7 @@ unsigned int NzOBJParser::GetMaterialCount() const
const NzOBJParser::Mesh* NzOBJParser::GetMeshes() const
{
return &m_meshes[0];
return m_meshes.data();
}
unsigned int NzOBJParser::GetMeshCount() const
@@ -52,7 +52,7 @@ const NzString& NzOBJParser::GetMtlLib() const
const NzVector3f* NzOBJParser::GetNormals() const
{
return &m_normals[0];
return m_normals.data();
}
unsigned int NzOBJParser::GetNormalCount() const
@@ -62,7 +62,7 @@ unsigned int NzOBJParser::GetNormalCount() const
const NzVector4f* NzOBJParser::GetPositions() const
{
return &m_positions[0];
return m_positions.data();
}
unsigned int NzOBJParser::GetPositionCount() const
@@ -72,7 +72,7 @@ unsigned int NzOBJParser::GetPositionCount() const
const NzVector3f* NzOBJParser::GetTexCoords() const
{
return &m_texCoords[0];
return m_texCoords.data();
}
unsigned int NzOBJParser::GetTexCoordCount() const
@@ -93,13 +93,15 @@ bool NzOBJParser::Parse()
m_positions.clear();
m_texCoords.clear();
// Beaucoup de meshs font plus de 100 sommets, on prépare le terrain
// Beaucoup de meshs font plus de 100 sommets, préparons le terrain
m_normals.reserve(100);
m_positions.reserve(100);
m_texCoords.reserve(100);
// On va regrouper les meshs par nom et par matériau
std::unordered_map<NzString, std::unordered_map<NzString, std::vector<Face>>> meshes;
// On prépare le mesh par défaut
std::vector<Face>* currentMesh = &meshes[meshName][matName];
while (Advance(false))
@@ -265,8 +267,8 @@ bool NzOBJParser::Parse()
break;
}
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
case 's':
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
if (m_currentLine.GetSize() <= 2 || m_currentLine[1] == ' ')
{
NzString param = m_currentLine.SubString(2);
@@ -275,8 +277,8 @@ bool NzOBJParser::Parse()
}
else
UnrecognizedLine();
#endif
break;
#endif
case 'u':
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -15,6 +15,25 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
namespace
{
const nzUInt8 r_coreFragmentShader[] = {
#include <Nazara/Graphics/Resources/Shaders/Basic/core.frag.h>
};
const nzUInt8 r_coreVertexShader[] = {
#include <Nazara/Graphics/Resources/Shaders/Basic/core.vert.h>
};
const nzUInt8 r_compatibilityFragmentShader[] = {
#include <Nazara/Graphics/Resources/Shaders/Basic/compatibility.frag.h>
};
const nzUInt8 r_compatibilityVertexShader[] = {
#include <Nazara/Graphics/Resources/Shaders/Basic/compatibility.vert.h>
};
}
bool NzMaterialParams::IsValid() const
{
if (!NzUberShaderLibrary::Has(shaderName))
@@ -30,25 +49,11 @@ NzMaterial::NzMaterial()
NzMaterial::NzMaterial(const NzMaterial& material) :
NzRefCounted(),
NzResource()
NzResource(material)
{
Copy(material);
}
NzMaterial::NzMaterial(NzMaterial&& material)
{
Copy(material);
// Nous "volons" la référence du matériau
material.m_alphaMap.Reset();
material.m_diffuseMap.Reset();
material.m_emissiveMap.Reset();
material.m_heightMap.Reset();
material.m_normalMap.Reset();
material.m_specularMap.Reset();
material.m_uberShader.Reset();
}
NzMaterial::~NzMaterial()
{
NotifyDestroy();
@@ -153,6 +158,11 @@ void NzMaterial::EnableAlphaTest(bool alphaTest)
InvalidateShaders();
}
void NzMaterial::EnableDepthSorting(bool depthSorting)
{
m_depthSortingEnabled = depthSorting;
}
void NzMaterial::EnableLighting(bool lighting)
{
m_lightingEnabled = lighting;
@@ -249,10 +259,11 @@ const NzUberShader* NzMaterial::GetShader() const
const NzUberShaderInstance* NzMaterial::GetShaderInstance(nzUInt32 flags) const
{
if (!m_shaders[flags].uberInstance)
const ShaderInstance& instance = m_shaders[flags];
if (!instance.uberInstance)
GenerateShader(flags);
return m_shaders[flags].uberInstance;
return instance.uberInstance;
}
float NzMaterial::GetShininess() const
@@ -320,6 +331,11 @@ bool NzMaterial::IsAlphaTestEnabled() const
return m_alphaTestEnabled;
}
bool NzMaterial::IsDepthSortingEnabled() const
{
return m_depthSortingEnabled;
}
bool NzMaterial::IsEnabled(nzRendererParameter parameter) const
{
#ifdef NAZARA_DEBUG
@@ -376,6 +392,7 @@ void NzMaterial::Reset()
m_alphaThreshold = 0.2f;
m_alphaTestEnabled = false;
m_ambientColor = NzColor(128, 128, 128);
m_depthSortingEnabled = false;
m_diffuseColor = NzColor::White;
m_diffuseSampler = NzTextureSampler();
m_lightingEnabled = true;
@@ -618,27 +635,13 @@ void NzMaterial::SetSrcBlend(nzBlendFunc func)
NzMaterial& NzMaterial::operator=(const NzMaterial& material)
{
NzResource::operator=(material);
Copy(material);
return *this;
}
NzMaterial& NzMaterial::operator=(NzMaterial&& material)
{
Copy(material);
// Comme ça nous volons la référence du matériau
material.m_alphaMap.Reset();
material.m_diffuseMap.Reset();
material.m_emissiveMap.Reset();
material.m_heightMap.Reset();
material.m_normalMap.Reset();
material.m_specularMap.Reset();
material.m_uberShader.Reset();
return *this;
}
NzMaterial* NzMaterial::GetDefault()
{
return s_defaultMaterial;
@@ -646,33 +649,33 @@ NzMaterial* NzMaterial::GetDefault()
void NzMaterial::Copy(const NzMaterial& material)
{
// On relache les références proprement
m_alphaMap.Reset();
m_diffuseMap.Reset();
m_emissiveMap.Reset();
m_heightMap.Reset();
m_normalMap.Reset();
m_specularMap.Reset();
m_uberShader.Reset();
// Copie des états de base
m_alphaTestEnabled = material.m_alphaTestEnabled;
m_alphaThreshold = material.m_alphaThreshold;
m_ambientColor = material.m_ambientColor;
m_depthSortingEnabled = material.m_depthSortingEnabled;
m_diffuseColor = material.m_diffuseColor;
m_diffuseSampler = material.m_diffuseSampler;
m_lightingEnabled = material.m_lightingEnabled;
m_shininess = material.m_shininess;
m_specularColor = material.m_specularColor;
m_specularSampler = material.m_specularSampler;
m_states = material.m_states;
m_transformEnabled = material.m_transformEnabled;
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_diffuseMap.Release();
m_emissiveMap.Release();
m_heightMap.Release();
m_normalMap.Release();
m_specularMap.Release();
m_uberShader.Release();
m_alphaMap = material.m_alphaMap;
m_diffuseMap = material.m_diffuseMap;
// Copie des références de texture
m_alphaMap = material.m_alphaMap;
m_diffuseMap = material.m_diffuseMap;
m_emissiveMap = material.m_emissiveMap;
m_heightMap = material.m_heightMap;
m_normalMap = material.m_normalMap;
m_heightMap = material.m_heightMap;
m_normalMap = material.m_normalMap;
m_specularMap = material.m_specularMap;
// Copie de la référence vers l'Über-Shader
m_uberShader = material.m_uberShader;
// On copie les instances de shader par la même occasion
std::memcpy(&m_shaders[0], &material.m_shaders[0], (nzShaderFlags_Max+1)*sizeof(ShaderInstance));
}
void NzMaterial::GenerateShader(nzUInt32 flags) const
@@ -688,11 +691,15 @@ void NzMaterial::GenerateShader(nzUInt32 flags) const
list.SetParameter("PARALLAX_MAPPING", m_heightMap.IsValid());
list.SetParameter("SPECULAR_MAPPING", m_specularMap.IsValid());
list.SetParameter("TEXTURE_MAPPING", m_alphaMap.IsValid() || m_diffuseMap.IsValid() || m_emissiveMap.IsValid() ||
m_normalMap.IsValid() || m_heightMap.IsValid() || m_specularMap.IsValid());
m_normalMap.IsValid() || m_heightMap.IsValid() || m_specularMap.IsValid() ||
flags & nzShaderFlags_TextureOverlay);
list.SetParameter("TRANSFORM", m_transformEnabled);
list.SetParameter("FLAG_DEFERRED", static_cast<bool>(flags & nzShaderFlags_Deferred));
list.SetParameter("FLAG_INSTANCING", static_cast<bool>(flags & nzShaderFlags_Instancing));
list.SetParameter("FLAG_BILLBOARD", static_cast<bool>(flags & nzShaderFlags_Billboard));
list.SetParameter("FLAG_DEFERRED", static_cast<bool>((flags & nzShaderFlags_Deferred) != 0));
list.SetParameter("FLAG_INSTANCING", static_cast<bool>((flags & nzShaderFlags_Instancing) != 0));
list.SetParameter("FLAG_TEXTUREOVERLAY", static_cast<bool>((flags & nzShaderFlags_TextureOverlay) != 0));
list.SetParameter("FLAG_VERTEXCOLOR", static_cast<bool>((flags & nzShaderFlags_VertexColor) != 0));
ShaderInstance& instance = m_shaders[flags];
instance.uberInstance = m_uberShader->Get(list);
@@ -734,33 +741,17 @@ bool NzMaterial::Initialize()
NzString vertexShader;
if (glsl140)
{
const nzUInt8 coreFragmentShader[] = {
#include <Nazara/Graphics/Resources/Shaders/Basic/core.frag.h>
};
const nzUInt8 coreVertexShader[] = {
#include <Nazara/Graphics/Resources/Shaders/Basic/core.vert.h>
};
fragmentShader.Set(reinterpret_cast<const char*>(coreFragmentShader), sizeof(coreFragmentShader));
vertexShader.Set(reinterpret_cast<const char*>(coreVertexShader), sizeof(coreVertexShader));
fragmentShader.Set(reinterpret_cast<const char*>(r_coreFragmentShader), sizeof(r_coreFragmentShader));
vertexShader.Set(reinterpret_cast<const char*>(r_coreVertexShader), sizeof(r_coreVertexShader));
}
else
{
const nzUInt8 compatibilityFragmentShader[] = {
#include <Nazara/Graphics/Resources/Shaders/Basic/compatibility.frag.h>
};
const nzUInt8 compatibilityVertexShader[] = {
#include <Nazara/Graphics/Resources/Shaders/Basic/compatibility.vert.h>
};
fragmentShader.Set(reinterpret_cast<const char*>(compatibilityFragmentShader), sizeof(compatibilityFragmentShader));
vertexShader.Set(reinterpret_cast<const char*>(compatibilityVertexShader), sizeof(compatibilityVertexShader));
fragmentShader.Set(reinterpret_cast<const char*>(r_compatibilityFragmentShader), sizeof(r_compatibilityFragmentShader));
vertexShader.Set(reinterpret_cast<const char*>(r_compatibilityVertexShader), sizeof(r_compatibilityVertexShader));
}
uberShader->SetShader(nzShaderStage_Fragment, fragmentShader, "ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING");
uberShader->SetShader(nzShaderStage_Vertex, vertexShader, "FLAG_INSTANCING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
uberShader->SetShader(nzShaderStage_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING");
uberShader->SetShader(nzShaderStage_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_INSTANCING FLAG_VERTEXCOLOR TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
NzUberShaderLibrary::Register("Basic", uberShader.get());
uberShader.release();
@@ -800,8 +791,8 @@ bool NzMaterial::Initialize()
vertexShader.Set(reinterpret_cast<const char*>(compatibilityVertexShader), sizeof(compatibilityVertexShader));
}
uberShader->SetShader(nzShaderStage_Fragment, fragmentShader, "FLAG_DEFERRED ALPHA_MAPPING ALPHA_TEST DIFFUSE_MAPPING EMISSIVE_MAPPING LIGHTING NORMAL_MAPPING PARALLAX_MAPPING SPECULAR_MAPPING");
uberShader->SetShader(nzShaderStage_Vertex, vertexShader, "FLAG_DEFERRED FLAG_INSTANCING COMPUTE_TBNMATRIX LIGHTING PARALLAX_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
uberShader->SetShader(nzShaderStage_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING EMISSIVE_MAPPING LIGHTING NORMAL_MAPPING PARALLAX_MAPPING SPECULAR_MAPPING");
uberShader->SetShader(nzShaderStage_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_DEFERRED FLAG_INSTANCING FLAG_VERTEXCOLOR COMPUTE_TBNMATRIX LIGHTING PARALLAX_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
NzUberShaderLibrary::Register("PhongLighting", uberShader.get());
uberShader.release();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -25,7 +25,6 @@ bool NzModelParameters::IsValid() const
}
NzModel::NzModel() :
m_boundingVolumeUpdated(true),
m_matCount(0),
m_skin(0),
m_skinCount(1)
@@ -33,22 +32,15 @@ m_skinCount(1)
}
NzModel::NzModel(const NzModel& model) :
NzResource(model),
NzSceneNode(model),
m_materials(model.m_materials),
m_boundingVolume(model.m_boundingVolume),
m_boundingVolumeUpdated(model.m_boundingVolumeUpdated),
m_mesh(model.m_mesh),
m_matCount(model.m_matCount),
m_skin(model.m_skin),
m_skinCount(model.m_skinCount)
{
if (model.m_mesh)
{
// Nous n'avons des matériaux que si nous avons un mesh
m_mesh = model.m_mesh;
m_materials = model.m_materials;
}
SetParent(model);
SetParent(model.GetParent());
}
NzModel::~NzModel()
@@ -75,22 +67,14 @@ void NzModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
}
}
const NzBoundingVolumef& NzModel::GetBoundingVolume() const
NzModel* NzModel::Clone() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_mesh)
{
NazaraError("Model has no mesh");
return new NzModel(*this);
}
static NzBoundingVolumef dummy(nzExtend_Null);
return dummy;
}
#endif
if (!m_boundingVolumeUpdated)
UpdateBoundingVolume();
return m_boundingVolume;
NzModel* NzModel::Create() const
{
return new NzModel;
}
NzMaterial* NzModel::GetMaterial(const NzString& subMeshName) const
@@ -396,7 +380,7 @@ void NzModel::SetSkinCount(unsigned int skinCount)
#if NAZARA_GRAPHICS_SAFE
if (skinCount == 0)
{
NazaraError("Skin count must be over 0");
NazaraError("Skin count must be over zero");
return;
}
#endif
@@ -407,6 +391,7 @@ void NzModel::SetSkinCount(unsigned int skinCount)
NzModel& NzModel::operator=(const NzModel& node)
{
NzResource::operator=(node);
NzSceneNode::operator=(node);
m_boundingVolume = node.m_boundingVolume;
@@ -420,41 +405,12 @@ NzModel& NzModel::operator=(const NzModel& node)
return *this;
}
NzModel& NzModel::operator=(NzModel&& node)
void NzModel::MakeBoundingVolume() const
{
NzSceneNode::operator=(node);
// Ressources
m_mesh = std::move(node.m_mesh);
m_materials = std::move(node.m_materials);
// Paramètres
m_boundingVolume = node.m_boundingVolume;
m_boundingVolumeUpdated = node.m_boundingVolumeUpdated;
m_matCount = node.m_matCount;
m_skin = node.m_skin;
m_skinCount = node.m_skinCount;
return *this;
}
void NzModel::InvalidateNode()
{
NzSceneNode::InvalidateNode();
m_boundingVolumeUpdated = false;
}
void NzModel::UpdateBoundingVolume() const
{
if (m_boundingVolume.IsNull())
if (m_mesh)
m_boundingVolume.Set(m_mesh->GetAABB());
if (!m_transformMatrixUpdated)
UpdateTransformMatrix();
m_boundingVolume.Update(m_transformMatrix);
m_boundingVolumeUpdated = true;
else
m_boundingVolume.MakeNull();
}
NzModelLoader::LoaderList NzModel::s_loaders;

View File

@@ -0,0 +1,14 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ParticleController.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzParticleController::NzParticleController(const NzParticleController& controller) :
NzRefCounted()
{
NazaraUnused(controller);
}
NzParticleController::~NzParticleController() = default;

View File

@@ -0,0 +1,231 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ParticleDeclaration.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/OffsetOf.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/ParticleStruct.hpp>
#include <Nazara/Utility/Utility.hpp>
#include <cstring>
#include <Nazara/Graphics/Debug.hpp>
NzParticleDeclaration::NzParticleDeclaration() :
m_stride(0)
{
}
NzParticleDeclaration::NzParticleDeclaration(const NzParticleDeclaration& declaration) :
NzRefCounted(),
m_stride(declaration.m_stride)
{
std::memcpy(m_components, declaration.m_components, sizeof(Component)*(nzParticleComponent_Max+1));
}
NzParticleDeclaration::~NzParticleDeclaration()
{
NotifyDestroy();
}
void NzParticleDeclaration::DisableComponent(nzParticleComponent component)
{
#ifdef NAZARA_DEBUG
if (component > nzParticleComponent_Max)
{
NazaraError("Vertex component out of enum");
return;
}
#endif
#if NAZARA_GRAPHICS_SAFE
if (component == nzParticleComponent_Unused)
{
NazaraError("Cannot disable \"unused\" component");
return;
}
#endif
Component& vertexComponent = m_components[component];
if (vertexComponent.enabled)
{
vertexComponent.enabled = false;
m_stride -= NzUtility::ComponentStride[vertexComponent.type];
}
}
void NzParticleDeclaration::EnableComponent(nzParticleComponent component, nzComponentType type, unsigned int offset)
{
#ifdef NAZARA_DEBUG
if (component > nzParticleComponent_Max)
{
NazaraError("Vertex component out of enum");
return;
}
#endif
#if NAZARA_GRAPHICS_SAFE
if (!IsTypeSupported(type))
{
NazaraError("Component type 0x" + NzString::Number(type, 16) + " is not supported by particle declarations");
return;
}
#endif
if (component != nzParticleComponent_Unused)
{
Component& particleComponent = m_components[component];
if (particleComponent.enabled)
m_stride -= NzUtility::ComponentStride[particleComponent.type];
else
particleComponent.enabled = true;
particleComponent.offset = offset;
particleComponent.type = type;
}
m_stride += NzUtility::ComponentStride[type];
}
void NzParticleDeclaration::GetComponent(nzParticleComponent component, bool* enabled, nzComponentType* type, unsigned int* offset) const
{
#ifdef NAZARA_DEBUG
if (component > nzParticleComponent_Max)
{
NazaraError("Particle component out of enum");
return;
}
#endif
#if NAZARA_GRAPHICS_SAFE
if (component == nzParticleComponent_Unused)
{
NazaraError("Cannot get \"unused\" component");
return;
}
#endif
const Component& particleComponent = m_components[component];
if (enabled)
*enabled = particleComponent.enabled;
if (type)
*type = particleComponent.type;
if (offset)
*offset = particleComponent.offset;
}
unsigned int NzParticleDeclaration::GetStride() const
{
return m_stride;
}
void NzParticleDeclaration::SetStride(unsigned int stride)
{
m_stride = stride;
}
NzParticleDeclaration& NzParticleDeclaration::operator=(const NzParticleDeclaration& declaration)
{
std::memcpy(m_components, declaration.m_components, sizeof(Component)*(nzParticleComponent_Max+1));
m_stride = declaration.m_stride;
return *this;
}
NzParticleDeclaration* NzParticleDeclaration::Get(nzParticleLayout layout)
{
#ifdef NAZARA_DEBUG
if (layout > nzParticleLayout_Max)
{
NazaraError("Particle layout out of enum");
return nullptr;
}
#endif
return &s_declarations[layout];
}
bool NzParticleDeclaration::IsTypeSupported(nzComponentType type)
{
switch (type)
{
case nzComponentType_Color:
case nzComponentType_Double1:
case nzComponentType_Double2:
case nzComponentType_Double3:
case nzComponentType_Double4:
case nzComponentType_Float1:
case nzComponentType_Float2:
case nzComponentType_Float3:
case nzComponentType_Float4:
case nzComponentType_Int1:
case nzComponentType_Int2:
case nzComponentType_Int3:
case nzComponentType_Int4:
case nzComponentType_Quaternion:
return true;
}
NazaraError("Component type not handled (0x" + NzString::Number(type, 16) + ')');
return false;
}
bool NzParticleDeclaration::Initialize()
{
try
{
NzErrorFlags flags(nzErrorFlag_Silent | nzErrorFlag_ThrowException);
// Layout : Type
NzParticleDeclaration* declaration;
// nzParticleLayout_Billboard : NzParticleStruct_Billboard
declaration = &s_declarations[nzParticleLayout_Billboard];
declaration->EnableComponent(nzParticleComponent_Color, nzComponentType_Color, NzOffsetOf(NzParticleStruct_Billboard, color));
declaration->EnableComponent(nzParticleComponent_Life, nzComponentType_Int1, NzOffsetOf(NzParticleStruct_Billboard, life));
declaration->EnableComponent(nzParticleComponent_Normal, nzComponentType_Float3, NzOffsetOf(NzParticleStruct_Billboard, normal));
declaration->EnableComponent(nzParticleComponent_Position, nzComponentType_Float3, NzOffsetOf(NzParticleStruct_Billboard, position));
declaration->EnableComponent(nzParticleComponent_Rotation, nzComponentType_Float1, NzOffsetOf(NzParticleStruct_Billboard, rotation));
declaration->EnableComponent(nzParticleComponent_Velocity, nzComponentType_Float3, NzOffsetOf(NzParticleStruct_Billboard, velocity));
NazaraAssert(declaration->GetStride() == sizeof(NzParticleStruct_Billboard), "Invalid stride for declaration nzParticleLayout_Billboard");
// nzParticleLayout_Model : NzParticleStruct_Model
declaration = &s_declarations[nzParticleLayout_Model];
declaration->EnableComponent(nzParticleComponent_Life, nzComponentType_Int1, NzOffsetOf(NzParticleStruct_Model, life));
declaration->EnableComponent(nzParticleComponent_Position, nzComponentType_Float3, NzOffsetOf(NzParticleStruct_Model, position));
declaration->EnableComponent(nzParticleComponent_Rotation, nzComponentType_Quaternion, NzOffsetOf(NzParticleStruct_Model, rotation));
declaration->EnableComponent(nzParticleComponent_Velocity, nzComponentType_Float3, NzOffsetOf(NzParticleStruct_Model, velocity));
NazaraAssert(declaration->GetStride() == sizeof(NzParticleStruct_Model), "Invalid stride for declaration nzParticleLayout_Model");
// nzParticleLayout_Sprite : NzParticleStruct_Sprite
declaration = &s_declarations[nzParticleLayout_Sprite];
declaration->EnableComponent(nzParticleComponent_Color, nzComponentType_Color, NzOffsetOf(NzParticleStruct_Sprite, color));
declaration->EnableComponent(nzParticleComponent_Life, nzComponentType_Int1, NzOffsetOf(NzParticleStruct_Sprite, life));
declaration->EnableComponent(nzParticleComponent_Position, nzComponentType_Float2, NzOffsetOf(NzParticleStruct_Sprite, position));
declaration->EnableComponent(nzParticleComponent_Rotation, nzComponentType_Float1, NzOffsetOf(NzParticleStruct_Sprite, rotation));
declaration->EnableComponent(nzParticleComponent_Velocity, nzComponentType_Float2, NzOffsetOf(NzParticleStruct_Sprite, velocity));
NazaraAssert(declaration->GetStride() == sizeof(NzParticleStruct_Sprite), "Invalid stride for declaration nzParticleLayout_Sprite");
}
catch (const std::exception& e)
{
NazaraError("Failed to initialize particle declarations: " + NzString(e.what()));
return false;
}
return true;
}
void NzParticleDeclaration::Uninitialize()
{
// Rien à faire
}
NzParticleDeclaration NzParticleDeclaration::s_declarations[nzParticleLayout_Max+1];

View File

@@ -0,0 +1,92 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ParticleEmitter.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <Nazara/Graphics/ParticleMapper.hpp>
#include <Nazara/Graphics/ParticleSystem.hpp>
#include <cstdlib>
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
NzParticleEmitter::NzParticleEmitter() :
m_lagCompensationEnabled(false),
m_emissionAccumulator(0.f),
m_emissionRate(0.f),
m_emissionCount(1)
{
}
NzParticleEmitter::~NzParticleEmitter() = default;
void NzParticleEmitter::Emit(NzParticleSystem& system, float elapsedTime) const
{
if (m_emissionRate > 0.f)
{
// On accumule la partie réelle (pour éviter qu'un taux d'update élevé empêche des particules de se former)
m_emissionAccumulator += elapsedTime*m_emissionRate;
float emissionCount = std::floor(m_emissionAccumulator); // Le nombre d'émissions de cette mise à jour
m_emissionAccumulator -= emissionCount; // On enlève la partie entière
if (emissionCount >= 1.f)
{
// On calcule le nombre maximum de particules pouvant être émises cette fois-ci
unsigned int emissionCountInt = static_cast<unsigned int>(emissionCount);
unsigned int maxParticleCount = emissionCountInt*m_emissionCount;
// On récupère le nombre de particules qu'il est possible de créer selon l'espace libre
unsigned int particleCount = std::min(maxParticleCount, system.GetMaxParticleCount() - system.GetParticleCount());
if (particleCount == 0)
return;
// Et on émet nos particules
void* particles = system.GenerateParticles(particleCount);
NzParticleMapper mapper(particles, system.GetDeclaration());
SetupParticles(mapper, particleCount);
if (m_lagCompensationEnabled)
{
// On va maintenant appliquer les contrôleurs
float accumulator = 0.f;
float invEmissionRate = 1.f/m_emissionRate;
for (unsigned int i = 1; i <= emissionCountInt; ++i)
system.ApplyControllers(mapper, std::min(m_emissionCount*i, particleCount), 20*invEmissionRate, accumulator);
}
}
}
}
void NzParticleEmitter::EnableLagCompensation(bool enable)
{
m_lagCompensationEnabled = enable;
}
unsigned int NzParticleEmitter::GetEmissionCount() const
{
return m_emissionCount;
}
float NzParticleEmitter::GetEmissionRate() const
{
return m_emissionRate;
}
bool NzParticleEmitter::IsLagCompensationEnabled() const
{
return m_lagCompensationEnabled;
}
void NzParticleEmitter::SetEmissionCount(unsigned int count)
{
m_emissionCount = count;
}
void NzParticleEmitter::SetEmissionRate(float rate)
{
m_emissionRate = rate;
}

View File

@@ -0,0 +1,14 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ParticleGenerator.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzParticleGenerator::NzParticleGenerator(const NzParticleGenerator& generator) :
NzRefCounted()
{
NazaraUnused(generator);
}
NzParticleGenerator::~NzParticleGenerator() = default;

View File

@@ -0,0 +1,15 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ParticleMapper.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzParticleMapper::NzParticleMapper(void* buffer, const NzParticleDeclaration* declaration) :
m_declaration(declaration),
m_ptr(static_cast<nzUInt8*>(buffer))
{
}
NzParticleMapper::~NzParticleMapper() = default;

View File

@@ -0,0 +1,14 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ParticleRenderer.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzParticleRenderer::NzParticleRenderer(const NzParticleRenderer& renderer) :
NzRefCounted()
{
NazaraUnused(renderer);
}
NzParticleRenderer::~NzParticleRenderer() = default;

View File

@@ -0,0 +1,346 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ParticleSystem.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <Nazara/Graphics/ParticleMapper.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <cstdlib>
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
NzParticleSystem::NzParticleSystem(unsigned int maxParticleCount, nzParticleLayout layout) :
NzParticleSystem(maxParticleCount, NzParticleDeclaration::Get(layout))
{
}
NzParticleSystem::NzParticleSystem(unsigned int maxParticleCount, const NzParticleDeclaration* declaration) :
m_declaration(declaration),
m_fixedStepEnabled(false),
m_processing(false),
m_stepAccumulator(0.f),
m_stepSize(1.f/60.f),
m_maxParticleCount(maxParticleCount),
m_particleCount(0)
{
// En cas d'erreur, un constructeur ne peut que lancer une exception
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
m_particleSize = m_declaration->GetStride(); // La taille de chaque particule
ResizeBuffer();
}
NzParticleSystem::NzParticleSystem(const NzParticleSystem& system) :
NzSceneNode(system),
m_controllers(system.m_controllers),
m_generators(system.m_generators),
m_declaration(system.m_declaration),
m_renderer(system.m_renderer),
m_fixedStepEnabled(system.m_fixedStepEnabled),
m_processing(false),
m_stepAccumulator(0.f),
m_stepSize(system.m_stepSize),
m_maxParticleCount(system.m_maxParticleCount),
m_particleCount(system.m_particleCount),
m_particleSize(system.m_particleSize)
{
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
ResizeBuffer();
// On ne copie que les particules vivantes
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize);
}
NzParticleSystem::~NzParticleSystem() = default;
void NzParticleSystem::AddController(NzParticleController* controller)
{
m_controllers.emplace_back(controller);
}
void NzParticleSystem::AddEmitter(NzParticleEmitter* emitter)
{
m_emitters.emplace_back(emitter);
}
void NzParticleSystem::AddGenerator(NzParticleGenerator* generator)
{
m_generators.emplace_back(generator);
}
void NzParticleSystem::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
{
///FIXME: Vérifier le renderer
if (m_particleCount > 0)
{
NzParticleMapper mapper(m_buffer.data(), m_declaration);
m_renderer->Render(*this, mapper, 0, m_particleCount-1, renderQueue);
}
}
void* NzParticleSystem::CreateParticle()
{
return CreateParticles(1);
}
void* NzParticleSystem::CreateParticles(unsigned int count)
{
if (count == 0)
return nullptr;
if (m_particleCount+count > m_maxParticleCount)
return nullptr;
unsigned int particlesIndex = m_particleCount;
m_particleCount += count;
return &m_buffer[particlesIndex*m_particleSize];
}
void NzParticleSystem::EnableFixedStep(bool fixedStep)
{
// On teste pour empêcher que cette méthode ne remette systématiquement le step accumulator à zéro
if (m_fixedStepEnabled != fixedStep)
{
m_fixedStepEnabled = fixedStep;
m_stepAccumulator = 0.f;
}
}
void* NzParticleSystem::GenerateParticle()
{
return GenerateParticles(1);
}
void* NzParticleSystem::GenerateParticles(unsigned int count)
{
void* ptr = CreateParticles(count);
if (!ptr)
return nullptr;
NzParticleMapper mapper(ptr, m_declaration);
for (NzParticleGenerator* generator : m_generators)
generator->Generate(*this, mapper, 0, count-1);
return ptr;
}
const NzParticleDeclaration* NzParticleSystem::GetDeclaration() const
{
return m_declaration;
}
float NzParticleSystem::GetFixedStepSize() const
{
return m_stepSize;
}
unsigned int NzParticleSystem::GetMaxParticleCount() const
{
return m_maxParticleCount;
}
unsigned int NzParticleSystem::GetParticleCount() const
{
return m_particleCount;
}
unsigned int NzParticleSystem::GetParticleSize() const
{
return m_particleSize;
}
nzSceneNodeType NzParticleSystem::GetSceneNodeType() const
{
return nzSceneNodeType_ParticleEmitter;
}
bool NzParticleSystem::IsDrawable() const
{
return true;
}
bool NzParticleSystem::IsFixedStepEnabled() const
{
return m_fixedStepEnabled;
}
void NzParticleSystem::KillParticle(unsigned int index)
{
///FIXME: Vérifier index
if (m_processing)
{
// Le buffer est en train d'être modifié, nous ne pouvons pas réduire sa taille, on place alors la particule dans une liste d'attente
m_dyingParticles.insert(index);
return;
}
// On déplace la dernière particule vivante à la place de celle-ci
if (--m_particleCount > 0)
std::memcpy(&m_buffer[index*m_particleSize], &m_buffer[m_particleCount*m_particleSize], m_particleSize);
}
void NzParticleSystem::KillParticles()
{
m_particleCount = 0;
}
void NzParticleSystem::RemoveController(NzParticleController* controller)
{
auto it = std::find(m_controllers.begin(), m_controllers.end(), controller);
if (it != m_controllers.end())
m_controllers.erase(it);
}
void NzParticleSystem::RemoveEmitter(NzParticleEmitter* emitter)
{
auto it = std::find(m_emitters.begin(), m_emitters.end(), emitter);
if (it != m_emitters.end())
m_emitters.erase(it);
}
void NzParticleSystem::RemoveGenerator(NzParticleGenerator* generator)
{
auto it = std::find(m_generators.begin(), m_generators.end(), generator);
if (it != m_generators.end())
m_generators.erase(it);
}
void NzParticleSystem::SetFixedStepSize(float stepSize)
{
m_stepSize = stepSize;
}
void NzParticleSystem::SetRenderer(NzParticleRenderer* renderer)
{
m_renderer = renderer;
}
NzParticleSystem& NzParticleSystem::operator=(const NzParticleSystem& system)
{
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
NzSceneNode::operator=(system);
m_controllers = system.m_controllers;
m_declaration = system.m_declaration;
m_fixedStepEnabled = system.m_fixedStepEnabled;
m_generators = system.m_generators;
m_maxParticleCount = system.m_maxParticleCount;
m_particleCount = system.m_particleCount;
m_particleSize = system.m_particleSize;
m_renderer = system.m_renderer;
m_stepSize = system.m_stepSize;
// La copie ne peut pas (ou plutôt ne devrait pas) avoir lieu pendant une mise à jour, inutile de copier
m_dyingParticles.clear();
m_processing = false;
m_stepAccumulator = 0.f;
m_buffer.clear(); // Pour éviter une recopie lors du resize() qui ne servira pas à grand chose
ResizeBuffer();
// On ne copie que les particules vivantes
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize);
return *this;
}
void NzParticleSystem::ApplyControllers(NzParticleMapper& mapper, unsigned int particleCount, float elapsedTime, float& stepAccumulator)
{
m_processing = true;
// Pour éviter un verrouillage en cas d'exception
NzCallOnExit onExit([this]()
{
m_processing = false;
});
if (m_fixedStepEnabled)
{
stepAccumulator += elapsedTime;
while (stepAccumulator >= m_stepSize)
{
for (NzParticleController* controller : m_controllers)
controller->Apply(*this, mapper, 0, particleCount-1, m_stepSize);
stepAccumulator -= m_stepSize;
}
}
else
{
for (NzParticleController* controller : m_controllers)
controller->Apply(*this, mapper, 0, particleCount-1, elapsedTime);
}
onExit.CallAndReset();
// On tue maintenant les particules mortes durant la mise à jour
if (m_dyingParticles.size() < m_particleCount)
{
// On tue les particules depuis la dernière vers la première (en terme de place), le std::set étant trié via std::greater
// La raison est simple, étant donné que la mort d'une particule signifie le déplacement de la dernière particule du buffer,
// sans cette solution certaines particules pourraient échapper à la mort
for (unsigned int index : m_dyingParticles)
KillParticle(index);
}
else
KillParticles(); // Toutes les particules sont mortes, ceci est beaucoup plus rapide
m_dyingParticles.clear();
}
void NzParticleSystem::MakeBoundingVolume() const
{
///TODO: Calculer l'AABB (prendre la taille des particules en compte s'il y a)
m_boundingVolume.MakeInfinite();
}
void NzParticleSystem::Register()
{
m_scene->RegisterForUpdate(this);
}
void NzParticleSystem::ResizeBuffer()
{
// Histoire de décrire un peu mieux l'erreur en cas d'échec
try
{
m_buffer.resize(m_maxParticleCount*m_particleSize);
}
catch (const std::exception& e)
{
NzStringStream stream;
stream << "Failed to allocate particle buffer (" << e.what() << ") for " << m_maxParticleCount << " particles of size " << m_particleSize;
NazaraError(stream.ToString());
}
}
void NzParticleSystem::Unregister()
{
m_scene->UnregisterForUpdate(this);
}
void NzParticleSystem::Update()
{
float elapsedTime = m_scene->GetUpdateTime();
// Émission
for (NzParticleEmitter* emitter : m_emitters)
emitter->Emit(*this, elapsedTime);
// Mise à jour
if (m_particleCount > 0)
{
///TODO: Mettre à jour en utilisant des threads
NzParticleMapper mapper(m_buffer.data(), m_declaration);
ApplyControllers(mapper, m_particleCount, elapsedTime, m_stepAccumulator);
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,22 +1,31 @@
/********************Entrant********************/
varying vec2 vTexCoord;
varying vec4 vColor;
/********************Uniformes********************/
uniform sampler2D MaterialAlphaMap;
uniform float MaterialAlphaThreshold;
uniform vec4 MaterialDiffuse;
uniform sampler2D MaterialDiffuseMap;
uniform vec2 InvTargetSize;
/********************Fonctions********************/
void main()
{
vec4 fragmentColor = MaterialDiffuse;
vec4 fragmentColor = MaterialDiffuse; * vColor;
#if AUTO_TEXCOORDS
vec2 texCoord = gl_FragCoord.xy * InvTargetSize;
#else
vec2 texCoord = vTexCoord;
#endif
#if DIFFUSE_MAPPING
fragmentColor *= texture2D(MaterialDiffuseMap, vTexCoord);
fragmentColor *= texture2D(MaterialDiffuseMap, texCoord);
#endif
#if ALPHA_MAPPING
fragmentColor.a *= texture2D(MaterialAlphaMap, vTexCoord).r;
fragmentColor.a *= texture2D(MaterialAlphaMap, texCoord).r;
#endif
#if ALPHA_TEST

View File

@@ -1 +1 @@
47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,97,114,121,105,110,103,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,50,68,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,118,84,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,50,68,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,118,84,101,120,67,111,111,114,100,41,46,114,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,105,102,32,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,9,103,108,95,70,114,97,103,67,111,108,111,114,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,13,10,125,
47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,97,114,121,105,110,103,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,118,97,114,121,105,110,103,32,118,101,99,52,32,118,67,111,108,111,114,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,118,101,99,50,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,32,42,32,118,67,111,108,111,114,59,13,10,13,10,35,105,102,32,65,85,84,79,95,84,69,88,67,79,79,82,68,83,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,103,108,95,70,114,97,103,67,111,111,114,100,46,120,121,32,42,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,35,101,108,115,101,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,50,68,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,50,68,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,105,102,32,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,9,103,108,95,70,114,97,103,67,111,108,111,114,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,13,10,125,

View File

@@ -1,10 +1,19 @@
/********************Entrant********************/
#if FLAG_BILLBOARD
varying vec3 InstanceData0; // center
varying vec4 InstanceData1; // size | sin cos
varying vec4 InstanceData2; // color
#else
varying mat4 InstanceData0;
#endif
varying vec4 VertexColor;
varying vec3 VertexPosition;
varying vec2 VertexTexCoord;
/********************Sortant********************/
varying vec2 vTexCoord;
varying vec4 vColor;
/********************Uniformes********************/
uniform float VertexDepth;
@@ -14,29 +23,77 @@ uniform mat4 WorldViewProjMatrix;
/********************Fonctions********************/
void main()
{
#if FLAG_INSTANCING
#if TRANSFORM
gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);
#if FLAG_VERTEXCOLOR
vec4 color = VertexColor;
#else
vec4 color = vec4(1.0);
#endif
vec2 texCoords;
#if FLAG_BILLBOARD
#if FLAG_INSTANCING
vec3 billboardCenter = InstanceData0;
vec2 billboardSize = InstanceData1.xy;
vec2 billboardSinCos = InstanceData1.zw;
vec4 billboardColor = InstanceData2;
vec2 rotatedPosition;
rotatedPosition.x = VertexPosition.x*billboardSinCos.y - VertexPosition.y*billboardSinCos.x;
rotatedPosition.y = VertexPosition.y*billboardSinCos.y + VertexPosition.x*billboardSinCos.x;
rotatedPosition *= billboardSize;
vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
vec3 vertexPos = billboardCenter + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y;
gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0);
color = billboardColor;
texCoords = VertexPosition.xy + vec2(0.5, 0.5);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = InstanceData0 * vec4(VertexPosition, 1.0);
#endif
vec2 billboardCorner = VertexTexCoord - vec2(0.5, 0.5);
vec2 billboardSize = VertexUserdata0.xy;
vec2 billboardSinCos = VertexUserdata0.zw;
vec2 rotatedPosition;
rotatedPosition.x = billboardCorner.x*billboardSinCos.y - billboardCorner.y*billboardSinCos.x;
rotatedPosition.y = billboardCorner.y*billboardSinCos.y + billboardCorner.x*billboardSinCos.x;
rotatedPosition *= billboardSize;
vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
vec3 vertexPos = VertexPosition + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y;
gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0);
texCoords = VertexTexCoord;
#endif
#else
#if TRANSFORM
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0);
#if FLAG_INSTANCING
#if TRANSFORM
gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);
#else
gl_Position = vec4(VertexPosition, 1.0);
#if UNIFORM_VERTEX_DEPTH
gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = InstanceData0 * vec4(VertexPosition, 1.0);
#endif
#endif
#else
#if TRANSFORM
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = vec4(VertexPosition, 1.0);
#endif
#endif
#endif
texCoords = VertexTexCoord;
#endif
vColor = color;
#if TEXTURE_MAPPING
vTexCoord = vec2(VertexTexCoord);
vTexCoord = vec2(texCoords);
#endif
}

File diff suppressed because one or more lines are too long

View File

@@ -3,22 +3,24 @@ layout(early_fragment_tests) in;
#endif
/********************Entrant********************/
in vec4 vColor;
in vec2 vTexCoord;
/********************Sortant********************/
out vec4 RenderTarget0;
/********************Uniformes********************/
uniform vec2 InvTargetSize;
uniform sampler2D MaterialAlphaMap;
uniform float MaterialAlphaThreshold;
uniform vec4 MaterialDiffuse;
uniform sampler2D MaterialDiffuseMap;
uniform vec2 InvTargetSize;
uniform sampler2D TextureOverlay;
/********************Fonctions********************/
void main()
{
vec4 fragmentColor = MaterialDiffuse;
vec4 fragmentColor = MaterialDiffuse * vColor;
#if AUTO_TEXCOORDS
vec2 texCoord = gl_FragCoord.xy * InvTargetSize;
@@ -34,6 +36,10 @@ void main()
fragmentColor.a *= texture(MaterialAlphaMap, texCoord).r;
#endif
#if FLAG_TEXTUREOVERLAY
fragmentColor *= texture(TextureOverlay, texCoord);
#endif
#if ALPHA_TEST
if (fragmentColor.a < MaterialAlphaThreshold)
discard;

View File

@@ -1 +1 @@
35,105,102,32,69,65,82,76,89,95,70,82,65,71,77,69,78,84,95,84,69,83,84,83,32,38,38,32,33,65,76,80,72,65,95,84,69,83,84,13,10,108,97,121,111,117,116,40,101,97,114,108,121,95,102,114,97,103,109,101,110,116,95,116,101,115,116,115,41,32,105,110,59,13,10,35,101,110,100,105,102,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,118,101,99,50,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,13,10,35,105,102,32,65,85,84,79,95,84,69,88,67,79,79,82,68,83,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,103,108,95,70,114,97,103,67,111,111,114,100,46,120,121,32,42,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,35,101,108,115,101,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,105,102,32,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,13,10,125,
35,105,102,32,69,65,82,76,89,95,70,82,65,71,77,69,78,84,95,84,69,83,84,83,32,38,38,32,33,65,76,80,72,65,95,84,69,83,84,13,10,108,97,121,111,117,116,40,101,97,114,108,121,95,102,114,97,103,109,101,110,116,95,116,101,115,116,115,41,32,105,110,59,13,10,35,101,110,100,105,102,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,118,101,99,52,32,118,67,111,108,111,114,59,13,10,105,110,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,118,101,99,50,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,84,101,120,116,117,114,101,79,118,101,114,108,97,121,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,32,42,32,118,67,111,108,111,114,59,13,10,13,10,35,105,102,32,65,85,84,79,95,84,69,88,67,79,79,82,68,83,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,103,108,95,70,114,97,103,67,111,111,114,100,46,120,121,32,42,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,35,101,108,115,101,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,70,76,65,71,95,84,69,88,84,85,82,69,79,86,69,82,76,65,89,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,84,101,120,116,117,114,101,79,118,101,114,108,97,121,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,105,102,32,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,13,10,125,

View File

@@ -1,42 +1,102 @@
/********************Entrant********************/
#if FLAG_BILLBOARD
in vec3 InstanceData0; // center
in vec4 InstanceData1; // size | sin cos
in vec4 InstanceData2; // color
#else
in mat4 InstanceData0;
#endif
in vec4 VertexColor;
in vec3 VertexPosition;
in vec2 VertexTexCoord;
in vec4 VertexUserdata0;
/********************Sortant********************/
out vec4 vColor;
out vec2 vTexCoord;
/********************Uniformes********************/
uniform float VertexDepth;
uniform mat4 ViewMatrix;
uniform mat4 ViewProjMatrix;
uniform mat4 WorldViewProjMatrix;
/********************Fonctions********************/
void main()
{
#if FLAG_INSTANCING
#if TRANSFORM
gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = InstanceData0 * vec4(VertexPosition, 1.0);
#endif
#endif
#if FLAG_VERTEXCOLOR
vec4 color = VertexColor;
#else
#if TRANSFORM
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = vec4(VertexPosition, 1.0);
#endif
#endif
vec4 color = vec4(1.0);
#endif
vec2 texCoords;
#if FLAG_BILLBOARD
#if FLAG_INSTANCING
vec3 billboardCenter = InstanceData0;
vec2 billboardSize = InstanceData1.xy;
vec2 billboardSinCos = InstanceData1.zw;
vec4 billboardColor = InstanceData2;
vec2 rotatedPosition;
rotatedPosition.x = VertexPosition.x*billboardSinCos.y - VertexPosition.y*billboardSinCos.x;
rotatedPosition.y = VertexPosition.y*billboardSinCos.y + VertexPosition.x*billboardSinCos.x;
rotatedPosition *= billboardSize;
vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
vec3 vertexPos = billboardCenter + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y;
gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0);
color = billboardColor;
texCoords = VertexPosition.xy + 0.5;
#else
vec2 billboardCorner = VertexTexCoord - 0.5;
vec2 billboardSize = VertexUserdata0.xy;
vec2 billboardSinCos = VertexUserdata0.zw;
vec2 rotatedPosition;
rotatedPosition.x = billboardCorner.x*billboardSinCos.y - billboardCorner.y*billboardSinCos.x;
rotatedPosition.y = billboardCorner.y*billboardSinCos.y + billboardCorner.x*billboardSinCos.x;
rotatedPosition *= billboardSize;
vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
vec3 vertexPos = VertexPosition + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y;
gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0);
texCoords = VertexTexCoord;
#endif
#else
#if FLAG_INSTANCING
#if TRANSFORM
gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = InstanceData0 * vec4(VertexPosition, 1.0);
#endif
#endif
#else
#if TRANSFORM
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = vec4(VertexPosition, 1.0);
#endif
#endif
#endif
texCoords = VertexTexCoord;
#endif
vColor = color;
#if TEXTURE_MAPPING
vTexCoord = vec2(VertexTexCoord);
vTexCoord = vec2(texCoords);
#endif
}

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
#if FLAG_DEFERRED
#error Deferred Shading needs core profile
#error Deferred Shading is not supported by compatibility shaders
#endif
#define LIGHT_DIRECTIONAL 0
@@ -11,6 +11,7 @@ varying mat3 vLightToWorld;
varying vec3 vNormal;
varying vec2 vTexCoord;
varying vec3 vWorldPos;
varying vec4 vColor;
/********************Uniformes********************/
struct Light
@@ -24,9 +25,10 @@ struct Light
vec2 parameters3;
};
uniform vec3 EyePosition;
// Lumières
uniform Light Lights[3];
// Matériau
uniform sampler2D MaterialAlphaMap;
uniform float MaterialAlphaThreshold;
uniform vec4 MaterialAmbient;
@@ -38,18 +40,27 @@ uniform float MaterialShininess;
uniform vec4 MaterialSpecular;
uniform sampler2D MaterialSpecularMap;
// Autres
uniform vec3 EyePosition;
uniform vec4 SceneAmbient;
/********************Fonctions********************/
void main()
{
vec4 diffuseColor = MaterialDiffuse;
vec4 diffuseColor = MaterialDiffuse * vColor;
#if AUTO_TEXCOORDS
vec2 texCoord = gl_FragCoord.xy * InvTargetSize;
#else
vec2 texCoord = vTexCoord;
#endif
#if DIFFUSE_MAPPING
diffuseColor *= texture(MaterialDiffuseMap, vTexCoord);
diffuseColor *= texture(MaterialDiffuseMap, texCoord);
#endif
#if ALPHA_MAPPING
diffuseColor.a *= texture(MaterialAlphaMap, vTexCoord).r;
diffuseColor.a *= texture(MaterialAlphaMap, texCoord).r;
#endif
#if ALPHA_TEST
@@ -63,7 +74,7 @@ void main()
vec3 lightSpecular = vec3(0.0);
#if NORMAL_MAPPING
vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture(MaterialNormalMap, vTexCoord)) - 1.0));
vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture(MaterialNormalMap, texCoord)) - 1.0));
#else
vec3 normal = normalize(vNormal);
#endif
@@ -206,7 +217,7 @@ void main()
lightSpecular *= MaterialSpecular.rgb;
#if SPECULAR_MAPPING
lightSpecular *= texture(MaterialSpecularMap, vTexCoord).rgb; // Utiliser l'alpha de MaterialSpecular n'aurait aucun sens
lightSpecular *= texture(MaterialSpecularMap, texCoord).rgb; // Utiliser l'alpha de MaterialSpecular n'aurait aucun sens
#endif
vec3 lightColor = (lightAmbient + lightDiffuse + lightSpecular);
@@ -215,7 +226,7 @@ void main()
#if EMISSIVE_MAPPING
float lightIntensity = dot(lightColor, vec3(0.3, 0.59, 0.11));
vec3 emissionColor = MaterialDiffuse.rgb * texture(MaterialEmissiveMap, vTexCoord).rgb;
vec3 emissionColor = MaterialDiffuse.rgb * texture(MaterialEmissiveMap, texCoord).rgb;
RenderTarget0 = vec4(mix(fragmentColor.rgb, emissionColor, clamp(1.0 - 3.0*lightIntensity, 0.0, 1.0)), fragmentColor.a);
#else
RenderTarget0 = fragmentColor;

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,12 @@
/********************Entrant********************/
#if FLAG_BILLBOARD
varying vec3 InstanceData0; // center
varying vec4 InstanceData1; // size | sin cos
varying vec4 InstanceData2; // color
#else
varying mat4 InstanceData0;
#endif
varying vec3 VertexPosition;
varying vec3 VertexNormal;
varying vec3 VertexTangent;
@@ -10,6 +17,7 @@ varying mat3 vLightToWorld;
varying vec3 vNormal;
varying vec2 vTexCoord;
varying vec3 vWorldPos;
varying vec4 vColor;
/********************Uniformes********************/
uniform float VertexDepth;
@@ -20,28 +28,76 @@ uniform mat4 WorldViewProjMatrix;
/********************Fonctions********************/
void main()
{
#if FLAG_INSTANCING
#if TRANSFORM
gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);
#if FLAG_VERTEXCOLOR
vec4 color = VertexColor;
#else
vec4 color = vec4(1.0);
#endif
vec2 texCoords;
#if FLAG_BILLBOARD
#if FLAG_INSTANCING
vec3 billboardCenter = InstanceData0;
vec2 billboardSize = InstanceData1.xy;
vec2 billboardSinCos = InstanceData1.zw;
vec4 billboardColor = InstanceData2;
vec2 rotatedPosition;
rotatedPosition.x = VertexPosition.x*billboardSinCos.y - VertexPosition.y*billboardSinCos.x;
rotatedPosition.y = VertexPosition.y*billboardSinCos.y + VertexPosition.x*billboardSinCos.x;
rotatedPosition *= billboardSize;
vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
vec3 vertexPos = billboardCenter + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y;
gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0);
color = billboardColor;
texCoords = VertexPosition.xy + vec2(0.5, 0.5);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = InstanceData0 * vec4(VertexPosition, 1.0);
#endif
vec2 billboardCorner = VertexTexCoord - vec2(0.5, 0.5);
vec2 billboardSize = VertexUserdata0.xy;
vec2 billboardSinCos = VertexUserdata0.zw;
vec2 rotatedPosition;
rotatedPosition.x = billboardCorner.x*billboardSinCos.y - billboardCorner.y*billboardSinCos.x;
rotatedPosition.y = billboardCorner.y*billboardSinCos.y + billboardCorner.x*billboardSinCos.x;
rotatedPosition *= billboardSize;
vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
vec3 vertexPos = VertexPosition + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y;
gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0);
texCoords = VertexTexCoord;
#endif
#else
#if TRANSFORM
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0);
#if FLAG_INSTANCING
#if TRANSFORM
gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);
#else
gl_Position = vec4(VertexPosition, 1.0);
#if UNIFORM_VERTEX_DEPTH
gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = InstanceData0 * vec4(VertexPosition, 1.0);
#endif
#endif
#else
#if TRANSFORM
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = vec4(VertexPosition, 1.0);
#endif
#endif
#endif
texCoords = VertexTexCoord;
#endif
vColor = color;
#if LIGHTING
#if FLAG_INSTANCING
@@ -61,11 +117,7 @@ void main()
#endif
#if TEXTURE_MAPPING
/* #if FLAG_FLIP_UVS
vTexCoord = vec2(VertexTexCoord.x, 1.0 - VertexTexCoord.y);
#else*/
vTexCoord = VertexTexCoord;
#endif
vTexCoord = vec2(texCoords);
#endif
#if LIGHTING && PARALLAX_MAPPING

File diff suppressed because one or more lines are too long

View File

@@ -7,6 +7,7 @@ layout(early_fragment_tests) in;
#define LIGHT_SPOT 2
/********************Entrant********************/
in vec4 vColor;
in mat3 vLightToWorld;
in vec3 vNormal;
in vec2 vTexCoord;
@@ -30,9 +31,10 @@ struct Light
vec2 parameters3;
};
uniform vec3 EyePosition;
// Lumières
uniform Light Lights[3];
// Matériau
uniform sampler2D MaterialAlphaMap;
uniform float MaterialAlphaThreshold;
uniform vec4 MaterialAmbient;
@@ -45,10 +47,15 @@ uniform float MaterialShininess;
uniform vec4 MaterialSpecular;
uniform sampler2D MaterialSpecularMap;
// Autres
uniform float ParallaxBias = -0.03;
uniform float ParallaxScale = 0.02;
uniform vec2 InvTargetSize;
uniform vec3 EyePosition;
uniform vec4 SceneAmbient;
uniform sampler2D TextureOverlay;
/********************Fonctions********************/
vec3 FloatToColor(float f)
{
@@ -76,8 +83,14 @@ vec4 EncodeNormal(in vec3 normal)
void main()
{
vec4 diffuseColor = MaterialDiffuse;
vec4 diffuseColor = MaterialDiffuse * vColor;
#if AUTO_TEXCOORDS
vec2 texCoord = gl_FragCoord.xy * InvTargetSize;
#else
vec2 texCoord = vTexCoord;
#endif
#if LIGHTING && PARALLAX_MAPPING
float height = texture(MaterialHeightMap, texCoord).r;
float v = height*ParallaxScale + ParallaxBias;
@@ -90,9 +103,14 @@ void main()
diffuseColor *= texture(MaterialDiffuseMap, texCoord);
#endif
#if FLAG_TEXTUREOVERLAY
diffuseColor *= texture(TextureOverlay, texCoord);
#endif
#if FLAG_DEFERRED
#if ALPHA_TEST
#if ALPHA_MAPPING // Inutile de faire de l'alpha-mapping sans alpha-test en Deferred (l'alpha n'est pas sauvegardé)
// Inutile de faire de l'alpha-mapping sans alpha-test en Deferred (l'alpha n'est pas sauvegardé dans le G-Buffer)
#if ALPHA_MAPPING
diffuseColor.a *= texture(MaterialAlphaMap, texCoord).r;
#endif

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +1,20 @@
/********************Entrant********************/
#if FLAG_BILLBOARD
in vec3 InstanceData0; // center
in vec4 InstanceData1; // size | sin cos
in vec4 InstanceData2; // color
#else
in mat4 InstanceData0;
#endif
in vec4 VertexColor;
in vec3 VertexPosition;
in vec3 VertexNormal;
in vec3 VertexTangent;
in vec2 VertexTexCoord;
/********************Sortant********************/
out vec4 vColor;
out mat3 vLightToWorld;
out vec3 vNormal;
out vec2 vTexCoord;
@@ -22,29 +31,79 @@ uniform mat4 WorldViewProjMatrix;
/********************Fonctions********************/
void main()
{
#if FLAG_INSTANCING
#if TRANSFORM
gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = InstanceData0 * vec4(VertexPosition, 1.0);
#endif
#endif
#if FLAG_VERTEXCOLOR
vec4 color = VertexColor;
#else
#if TRANSFORM
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = vec4(VertexPosition, 1.0);
#endif
#endif
vec4 color = vec4(1.0);
#endif
//#if LIGHTING
vec2 texCoords;
#if FLAG_BILLBOARD
#if FLAG_INSTANCING
vec3 billboardCenter = InstanceData0;
vec2 billboardSize = InstanceData1.xy;
vec2 billboardSinCos = InstanceData1.zw;
vec4 billboardColor = InstanceData2;
vec2 rotatedPosition;
rotatedPosition.x = VertexPosition.x*billboardSinCos.y - VertexPosition.y*billboardSinCos.x;
rotatedPosition.y = VertexPosition.y*billboardSinCos.y + VertexPosition.x*billboardSinCos.x;
rotatedPosition *= billboardSize;
vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
vec3 vertexPos = billboardCenter + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y;
gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0);
color = billboardColor;
texCoords = VertexPosition.xy + 0.5;
#else
vec2 billboardCorner = VertexTexCoord - 0.5;
vec2 billboardSize = VertexUserdata0.xy;
vec2 billboardSinCos = VertexUserdata0.zw;
vec2 rotatedPosition;
rotatedPosition.x = billboardCorner.x*billboardSinCos.y - billboardCorner.y*billboardSinCos.x;
rotatedPosition.y = billboardCorner.y*billboardSinCos.y + billboardCorner.x*billboardSinCos.x;
rotatedPosition *= billboardSize;
vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
vec3 vertexPos = VertexPosition + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y;
gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0);
texCoords = VertexTexCoord;
#endif
#else
#if FLAG_INSTANCING
#if TRANSFORM
gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = InstanceData0 * vec4(VertexPosition, 1.0);
#endif
#endif
#else
#if TRANSFORM
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
#else
#if UNIFORM_VERTEX_DEPTH
gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0);
#else
gl_Position = vec4(VertexPosition, 1.0);
#endif
#endif
#endif
texCoords = VertexTexCoord;
#endif
vColor = color;
#if LIGHTING
#if FLAG_INSTANCING
mat3 rotationMatrix = mat3(InstanceData0);
#else
@@ -59,14 +118,10 @@ void main()
#else
vNormal = normalize(rotationMatrix * VertexNormal);
#endif
//#endif
#endif
#if TEXTURE_MAPPING
/* #if FLAG_FLIP_UVS
vTexCoord = vec2(VertexTexCoord.x, 1.0 - VertexTexCoord.y);
#else*/
vTexCoord = VertexTexCoord;
// #endif
#endif
#if LIGHTING && PARALLAX_MAPPING

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -9,57 +9,36 @@
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/ColorBackground.hpp>
#include <Nazara/Graphics/RenderTechniques.hpp>
#include <Nazara/Graphics/SceneRoot.hpp>
#include <Nazara/Graphics/SkinningManager.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <functional>
#include <memory>
#include <set>
#include <vector>
#include <Nazara/Graphics/Debug.hpp>
struct NzSceneImpl
NzScene::NzScene() :
m_ambientColor(25, 25, 25),
m_root(this),
m_viewer(nullptr),
m_backgroundEnabled(true),
m_update(false),
m_updatePerSecond(60)
{
NzSceneImpl(NzScene* scene) :
root(scene)
{
}
std::unique_ptr<NzAbstractBackground> background;
std::unique_ptr<NzAbstractRenderTechnique> renderTechnique;
std::vector<NzUpdatable*> updateList;
std::vector<NzUpdatable*> visibleUpdateList;
NzClock updateClock;
NzColor ambientColor = NzColor(25,25,25);
NzSceneRoot root;
NzAbstractViewer* viewer = nullptr;
bool backgroundEnabled = true;
bool update = false;
float frameTime;
float updateTime;
int renderTechniqueRanking;
unsigned int updatePerSecond = 60;
};
NzScene::NzScene()
{
m_impl = new NzSceneImpl(this);
}
NzScene::~NzScene()
{
delete m_impl;
}
void NzScene::AddToVisibilityList(NzUpdatable* object)
{
m_impl->visibleUpdateList.push_back(object);
m_visibleUpdateList.push_back(object);
}
void NzScene::Clear()
{
m_nodeMap.clear();
m_nodes.clear();
}
void NzScene::Cull()
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return;
@@ -69,42 +48,40 @@ void NzScene::Cull()
NzAbstractRenderQueue* renderQueue = GetRenderTechnique()->GetRenderQueue();
renderQueue->Clear(false);
m_impl->visibleUpdateList.clear();
m_visibleUpdateList.clear();
// Frustum culling
RecursiveFrustumCull(renderQueue, m_impl->viewer->GetFrustum(), &m_impl->root);
RecursiveFrustumCull(renderQueue, m_viewer->GetFrustum(), &m_root);
///TODO: Occlusion culling
///TODO: Light culling
}
void NzScene::Draw()
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return;
}
#endif
m_impl->viewer->ApplyView();
m_viewer->ApplyView();
try
{
NzErrorFlags errFlags(nzErrorFlag_ThrowException);
m_impl->renderTechnique->Clear(this);
m_impl->renderTechnique->Draw(this);
NzErrorFlags errFlags(nzErrorFlag_ThrowException, true);
m_renderTechnique->Clear(this);
m_renderTechnique->Draw(this);
}
catch (const std::exception& e)
{
NzString oldName = m_impl->renderTechnique->GetName();
NzString oldName = m_renderTechnique->GetName();
if (m_impl->renderTechniqueRanking > 0)
if (m_renderTechniqueRanking > 0)
{
m_impl->renderTechnique.reset(NzRenderTechniques::GetByRanking(m_impl->renderTechniqueRanking-1, &m_impl->renderTechniqueRanking));
NazaraError("Render technique \"" + oldName + "\" failed, fallback to \"" + m_impl->renderTechnique->GetName() + '"');
m_renderTechnique.reset(NzRenderTechniques::GetByRanking(m_renderTechniqueRanking-1, &m_renderTechniqueRanking));
NazaraError("Render technique \"" + oldName + "\" failed, falling back to \"" + m_renderTechnique->GetName() + '"');
}
else
{
@@ -118,53 +95,154 @@ void NzScene::Draw()
void NzScene::EnableBackground(bool enable)
{
m_impl->backgroundEnabled = enable;
m_backgroundEnabled = enable;
}
NzSceneNode* NzScene::FindNode(const NzString& name)
{
auto it = m_nodeMap.find(name);
if (it == m_nodeMap.end())
return nullptr;
return it->second;
}
const NzSceneNode* NzScene::FindNode(const NzString& name) const
{
auto it = m_nodeMap.find(name);
if (it == m_nodeMap.end())
return nullptr;
return it->second;
}
NzColor NzScene::GetAmbientColor() const
{
return m_impl->ambientColor;
return m_ambientColor;
}
NzAbstractBackground* NzScene::GetBackground() const
{
if (!m_impl->background)
m_impl->background.reset(new NzColorBackground);
if (!m_background)
m_background.reset(new NzColorBackground);
return m_impl->background.get();
return m_background.get();
}
NzVector3f NzScene::GetBackward() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Backward();
}
#endif
return -m_viewer->GetGlobalForward();
}
NzVector3f NzScene::GetDown() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Down();
}
#endif
return -m_viewer->GetGlobalUp();
}
NzVector3f NzScene::GetForward() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Forward();
}
#endif
return m_viewer->GetGlobalForward();
}
NzVector3f NzScene::GetLeft() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Left();
}
#endif
return -m_viewer->GetGlobalRight();
}
NzAbstractRenderTechnique* NzScene::GetRenderTechnique() const
{
if (!m_impl->renderTechnique)
m_impl->renderTechnique.reset(NzRenderTechniques::GetByRanking(-1, &m_impl->renderTechniqueRanking));
if (!m_renderTechnique)
m_renderTechnique.reset(NzRenderTechniques::GetByRanking(-1, &m_renderTechniqueRanking));
return m_impl->renderTechnique.get();
return m_renderTechnique.get();
}
NzSceneNode& NzScene::GetRoot() const
NzVector3f NzScene::GetRight() const
{
return m_impl->root;
#if NAZARA_GRAPHICS_SAFE
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Right();
}
#endif
return m_viewer->GetGlobalRight();
}
NzSceneNode& NzScene::GetRoot()
{
return m_root;
}
const NzSceneNode& NzScene::GetRoot() const
{
return m_root;
}
NzAbstractViewer* NzScene::GetViewer() const
{
return m_impl->viewer;
return m_viewer;
}
NzVector3f NzScene::GetUp() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Up();
}
#endif
return m_viewer->GetGlobalUp();
}
float NzScene::GetUpdateTime() const
{
return m_impl->updateTime;
return m_updateTime;
}
unsigned int NzScene::GetUpdatePerSecond() const
{
return m_impl->updatePerSecond;
return m_updatePerSecond;
}
bool NzScene::IsBackgroundEnabled() const
{
return m_impl->backgroundEnabled;
return m_backgroundEnabled;
}
void NzScene::RegisterForUpdate(NzUpdatable* object)
@@ -177,27 +255,77 @@ void NzScene::RegisterForUpdate(NzUpdatable* object)
}
#endif
m_impl->updateList.push_back(object);
m_updateList.push_back(object);
}
void NzScene::RemoveNode(NzSceneNode* node)
{
if (!node)
return;
// C'est moche mais je n'ai pas d'autre choix que d'utiliser un std::unique_ptr pour utiliser std::find
std::unique_ptr<NzSceneNode> ptr(node);
auto it = std::find(m_nodes.begin(), m_nodes.end(), ptr);
ptr.release();
if (it == m_nodes.end())
{
NazaraError("This scene node doesn't belong to this scene");
return;
}
NzString nodeName = node->GetName();
if (!nodeName.IsEmpty())
m_nodeMap.erase(nodeName);
m_nodes.erase(it);
}
void NzScene::RemoveNode(const NzString& name)
{
RemoveNode(FindNode(name));
}
void NzScene::RenderFrame()
{
try
{
NzErrorFlags errFlags(nzErrorFlag_ThrowException, true);
Update();
Cull();
UpdateVisible();
Draw();
}
catch (const std::exception& e)
{
NazaraError("Failed to render frame: " + NzString(e.what()));
}
}
void NzScene::SetAmbientColor(const NzColor& color)
{
m_impl->ambientColor = color;
m_ambientColor = color;
}
void NzScene::SetBackground(NzAbstractBackground* background)
{
m_impl->background.reset(background);
m_background.reset(background);
}
void NzScene::SetRenderTechnique(NzAbstractRenderTechnique* renderTechnique)
{
m_impl->renderTechnique.reset(renderTechnique);
m_renderTechnique.reset(renderTechnique);
}
void NzScene::SetViewer(NzAbstractViewer* viewer)
{
m_impl->viewer = viewer;
if (m_viewer != viewer)
{
m_viewer = viewer;
// Invalidation de tous les nodes de la scène (utile pour la régénération des sommets dépendant du viewer)
m_root.InvalidateNode();
}
}
void NzScene::SetViewer(NzAbstractViewer& viewer)
@@ -207,7 +335,7 @@ void NzScene::SetViewer(NzAbstractViewer& viewer)
void NzScene::SetUpdatePerSecond(unsigned int updatePerSecond)
{
m_impl->updatePerSecond = updatePerSecond;
m_updatePerSecond = updatePerSecond;
}
void NzScene::UnregisterForUpdate(NzUpdatable* object)
@@ -220,20 +348,20 @@ void NzScene::UnregisterForUpdate(NzUpdatable* object)
}
#endif
auto it = std::find(m_impl->updateList.begin(), m_impl->updateList.end(), object);
if (it != m_impl->updateList.end())
m_impl->updateList.erase(it);
auto it = std::find(m_updateList.begin(), m_updateList.end(), object);
if (it != m_updateList.end())
m_updateList.erase(it);
}
void NzScene::Update()
{
m_impl->update = (m_impl->updatePerSecond == 0 || m_impl->updateClock.GetMilliseconds() > 1000/m_impl->updatePerSecond);
if (m_impl->update)
m_update = (m_updatePerSecond == 0 || m_updateClock.GetMilliseconds() > 1000/m_updatePerSecond);
if (m_update)
{
m_impl->updateTime = m_impl->updateClock.GetSeconds();
m_impl->updateClock.Restart();
m_updateTime = m_updateClock.GetSeconds();
m_updateClock.Restart();
for (NzUpdatable* updatable : m_impl->updateList)
for (NzUpdatable* updatable : m_updateList)
///TODO: Multihreading
updatable->Update();
}
@@ -243,16 +371,68 @@ void NzScene::UpdateVisible()
{
NzSkinningManager::Skin();
if (m_impl->update)
if (m_update)
{
for (NzUpdatable* node : m_impl->visibleUpdateList)
for (NzUpdatable* node : m_visibleUpdateList)
node->Update();
}
}
NzScene::operator const NzSceneNode&() const
{
return m_impl->root;
return m_root;
}
bool NzScene::ChangeNodeName(NzSceneNode* node, const NzString& newName)
{
#ifdef NAZARA_DEBUG
std::unique_ptr<NzSceneNode> ptr(node);
auto it = std::find(m_nodes.begin(), m_nodes.end(), ptr);
ptr.release();
if (it == m_nodes.end())
{
NazaraInternalError("Node isn't part of the scene");
return false;
}
#endif
if (!newName.IsEmpty())
{
auto pair = m_nodeMap.insert(std::make_pair(newName, node));
if (!pair.second)
{
NazaraError("Name \"" + newName + "\" is already in use");
return false;
}
}
NzString oldName = node->GetName();
if (!oldName.IsEmpty())
m_nodeMap.erase(oldName);
node->SetNameInternal(newName);
return true;
}
bool NzScene::RegisterSceneNode(const NzString& name, NzSceneNode* node)
{
if (!name.IsEmpty())
{
if (m_nodeMap.find(name) != m_nodeMap.end())
{
NazaraError("Node " + name + " is already registred");
return false;
}
m_nodeMap[name] = node;
}
node->SetNameInternal(name);
node->SetParent(m_root, true);
m_nodes.emplace_back(node);
return true;
}
void NzScene::RecursiveFrustumCull(NzAbstractRenderQueue* renderQueue, const NzFrustumf& frustum, NzNode* node)

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -11,6 +11,7 @@
NzSceneNode::NzSceneNode() :
m_scene(nullptr),
m_boundingVolumeUpdated(false),
m_drawingEnabled(true),
m_visible(false)
{
@@ -19,6 +20,7 @@ m_visible(false)
NzSceneNode::NzSceneNode(const NzSceneNode& sceneNode) :
NzNode(sceneNode),
m_scene(nullptr),
m_boundingVolumeUpdated(false),
m_drawingEnabled(sceneNode.m_drawingEnabled),
m_visible(false)
{
@@ -31,16 +33,107 @@ void NzSceneNode::EnableDrawing(bool drawingEnabled)
m_drawingEnabled = drawingEnabled;
}
NzVector3f NzSceneNode::GetBackward() const
{
if (m_scene)
{
if (!m_derivedUpdated)
UpdateDerived();
return m_derivedRotation * m_scene->GetBackward();
}
else
return NzNode::GetBackward();
}
const NzBoundingVolumef& NzSceneNode::GetBoundingVolume() const
{
if (!m_boundingVolumeUpdated)
UpdateBoundingVolume();
return m_boundingVolume;
}
NzVector3f NzSceneNode::GetDown() const
{
if (m_scene)
{
if (!m_derivedUpdated)
UpdateDerived();
return m_derivedRotation * m_scene->GetDown();
}
else
return NzNode::GetDown();
}
NzVector3f NzSceneNode::GetForward() const
{
if (m_scene)
{
if (!m_derivedUpdated)
UpdateDerived();
return m_derivedRotation * m_scene->GetForward();
}
else
return NzNode::GetForward();
}
NzVector3f NzSceneNode::GetLeft() const
{
if (m_scene)
{
if (!m_derivedUpdated)
UpdateDerived();
return m_derivedRotation * m_scene->GetLeft();
}
else
return NzNode::GetLeft();
}
const NzString& NzSceneNode::GetName() const
{
return m_name;
}
nzNodeType NzSceneNode::GetNodeType() const
{
return nzNodeType_Scene;
}
NzVector3f NzSceneNode::GetRight() const
{
if (m_scene)
{
if (!m_derivedUpdated)
UpdateDerived();
return m_derivedRotation * m_scene->GetRight();
}
else
return NzNode::GetRight();
}
NzScene* NzSceneNode::GetScene() const
{
return m_scene;
}
NzVector3f NzSceneNode::GetUp() const
{
if (m_scene)
{
if (!m_derivedUpdated)
UpdateDerived();
return m_derivedRotation * m_scene->GetUp();
}
else
return NzNode::GetUp();
}
bool NzSceneNode::IsDrawingEnabled() const
{
return m_drawingEnabled;
@@ -51,6 +144,19 @@ bool NzSceneNode::IsVisible() const
return m_visible;
}
bool NzSceneNode::SetName(const NzString& name)
{
if (m_scene)
// On demande à la scène de changer notre nom
return m_scene->ChangeNodeName(this, name);
else
{
// Pas de scène ? Changeons notre nom nous-même
SetNameInternal(name);
return true;
}
}
NzSceneNode& NzSceneNode::operator=(const NzSceneNode& sceneNode)
{
NzNode::operator=(sceneNode);
@@ -62,26 +168,23 @@ NzSceneNode& NzSceneNode::operator=(const NzSceneNode& sceneNode)
return *this;
}
NzSceneNode& NzSceneNode::operator=(NzSceneNode&& sceneNode)
{
NzNode::operator=(sceneNode);
// La scène est affectée via le parenting du node
m_drawingEnabled = sceneNode.m_drawingEnabled;
m_visible = sceneNode.m_visible;
return *this;
}
bool NzSceneNode::FrustumCull(const NzFrustumf& frustum) const
{
return frustum.Contains(GetBoundingVolume());
}
void NzSceneNode::InvalidateNode()
{
NzNode::InvalidateNode();
m_boundingVolumeUpdated = false;
}
void NzSceneNode::OnParenting(const NzNode* parent)
{
if (parent)
{
///FIXME: Remonter jusqu'au premier parent de type SceneNode plutôt que de s'arrêter au premier venu
if (parent->GetNodeType() == nzNodeType_Scene)
SetScene(static_cast<const NzSceneNode*>(parent)->m_scene);
}
@@ -116,6 +219,11 @@ void NzSceneNode::Register()
{
}
void NzSceneNode::SetNameInternal(const NzString& name)
{
m_name = name;
}
void NzSceneNode::SetScene(NzScene* scene)
{
if (m_scene != scene)
@@ -139,6 +247,18 @@ void NzSceneNode::Update()
{
}
void NzSceneNode::UpdateBoundingVolume() const
{
if (m_boundingVolume.IsNull())
MakeBoundingVolume();
if (!m_transformMatrixUpdated)
UpdateTransformMatrix();
m_boundingVolume.Update(m_transformMatrix);
m_boundingVolumeUpdated = true;
}
void NzSceneNode::UpdateVisibility(const NzFrustumf& frustum)
{
bool wasVisible = m_visible;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -20,12 +20,6 @@ void NzSceneRoot::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
NazaraInternalError("SceneNode::AddToRenderQueue() called on SceneRoot");
}
const NzBoundingVolumef& NzSceneRoot::GetBoundingVolume() const
{
static NzBoundingVolumef infinite(nzExtend_Infinite);
return infinite;
}
nzSceneNodeType NzSceneRoot::GetSceneNodeType() const
{
return nzSceneNodeType_Root;
@@ -36,6 +30,23 @@ bool NzSceneRoot::IsDrawable() const
return true;
}
NzSceneRoot* NzSceneRoot::Clone() const
{
NazaraInternalError("SceneNode::Clone() called on SceneRoot");
return nullptr;
}
NzSceneRoot* NzSceneRoot::Create() const
{
NazaraInternalError("SceneNode::Create() called on SceneRoot");
return nullptr;
}
void NzSceneRoot::MakeBoundingVolume() const
{
m_boundingVolume.MakeInfinite();
}
void NzSceneRoot::Register()
{
NazaraInternalError("SceneNode::Register() called on SceneRoot");

View File

@@ -0,0 +1,352 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/SkeletalModel.hpp>
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/SkinningManager.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/MeshData.hpp>
#include <Nazara/Utility/SkeletalMesh.hpp>
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
bool NzSkeletalModelParameters::IsValid() const
{
if (!NzModelParameters::IsValid())
return false;
if (loadAnimation && !animation.IsValid())
return false;
return true;
}
NzSkeletalModel::NzSkeletalModel() :
m_currentSequence(nullptr),
m_animationEnabled(true)
{
}
NzSkeletalModel::NzSkeletalModel(const NzSkeletalModel& model) :
NzModel(model),
m_skeleton(model.m_skeleton),
m_currentSequence(model.m_currentSequence),
m_animationEnabled(model.m_animationEnabled),
m_interpolation(model.m_interpolation),
m_currentFrame(model.m_currentFrame),
m_nextFrame(model.m_nextFrame)
{
}
NzSkeletalModel::~NzSkeletalModel()
{
m_scene->UnregisterForUpdate(this);
}
void NzSkeletalModel::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
{
const NzMatrix4f& transformMatrix = GetTransformMatrix();
unsigned int submeshCount = m_mesh->GetSubMeshCount();
for (unsigned int i = 0; i < submeshCount; ++i)
{
const NzSkeletalMesh* mesh = static_cast<const NzSkeletalMesh*>(m_mesh->GetSubMesh(i));
const NzMaterial* material = m_materials[mesh->GetMaterialIndex()];
NzMeshData meshData;
meshData.indexBuffer = mesh->GetIndexBuffer();
meshData.primitiveMode = mesh->GetPrimitiveMode();
meshData.vertexBuffer = NzSkinningManager::GetBuffer(mesh, &m_skeleton);
renderQueue->AddMesh(material, meshData, m_skeleton.GetAABB(), transformMatrix);
}
}
void NzSkeletalModel::AdvanceAnimation(float elapsedTime)
{
#if NAZARA_GRAPHICS_SAFE
if (!m_animation)
{
NazaraError("Model has no animation");
return;
}
#endif
m_interpolation += m_currentSequence->frameRate * elapsedTime;
while (m_interpolation > 1.f)
{
m_interpolation -= 1.f;
unsigned lastFrame = m_currentSequence->firstFrame + m_currentSequence->frameCount - 1;
if (m_nextFrame+1 > lastFrame)
{
if (m_animation->IsLoopPointInterpolationEnabled())
{
m_currentFrame = m_nextFrame;
m_nextFrame = m_currentSequence->firstFrame;
}
else
{
m_currentFrame = m_currentSequence->firstFrame;
m_nextFrame = m_currentFrame+1;
}
}
else
{
m_currentFrame = m_nextFrame;
m_nextFrame++;
}
}
m_animation->AnimateSkeleton(&m_skeleton, m_currentFrame, m_nextFrame, m_interpolation);
InvalidateBoundingVolume();
}
NzSkeletalModel* NzSkeletalModel::Clone() const
{
return new NzSkeletalModel(*this);
}
NzSkeletalModel* NzSkeletalModel::Create() const
{
return new NzSkeletalModel;
}
void NzSkeletalModel::EnableAnimation(bool animation)
{
m_animationEnabled = animation;
}
NzAnimation* NzSkeletalModel::GetAnimation() const
{
return m_animation;
}
NzSkeleton* NzSkeletalModel::GetSkeleton()
{
InvalidateBoundingVolume();
return &m_skeleton;
}
const NzSkeleton* NzSkeletalModel::GetSkeleton() const
{
return &m_skeleton;
}
bool NzSkeletalModel::HasAnimation() const
{
return m_animation != nullptr;
}
bool NzSkeletalModel::IsAnimated() const
{
return true;
}
bool NzSkeletalModel::IsAnimationEnabled() const
{
return m_animationEnabled;
}
bool NzSkeletalModel::IsDrawable() const
{
return m_mesh != nullptr && m_mesh->GetSubMeshCount() >= 1;
}
bool NzSkeletalModel::LoadFromFile(const NzString& filePath, const NzSkeletalModelParameters& params)
{
return NzSkeletalModelLoader::LoadFromFile(this, filePath, params);
}
bool NzSkeletalModel::LoadFromMemory(const void* data, std::size_t size, const NzSkeletalModelParameters& params)
{
return NzSkeletalModelLoader::LoadFromMemory(this, data, size, params);
}
bool NzSkeletalModel::LoadFromStream(NzInputStream& stream, const NzSkeletalModelParameters& params)
{
return NzSkeletalModelLoader::LoadFromStream(this, stream, params);
}
void NzSkeletalModel::Reset()
{
NzModel::Reset();
m_skeleton.Destroy();
}
bool NzSkeletalModel::SetAnimation(NzAnimation* animation)
{
#if NAZARA_GRAPHICS_SAFE
if (!m_mesh)
{
NazaraError("Model has no mesh");
return false;
}
if (animation)
{
if (!animation->IsValid())
{
NazaraError("Invalid animation");
return false;
}
if (animation->GetType() != m_mesh->GetAnimationType())
{
NazaraError("Animation type must match mesh animation type");
return false;
}
if (animation->GetJointCount() != m_mesh->GetJointCount())
{
NazaraError("Animation joint count must match mesh joint count");
return false;
}
}
#endif
m_animation = animation;
if (m_animation)
{
m_currentFrame = 0;
m_interpolation = 0.f;
SetSequence(0);
}
return true;
}
void NzSkeletalModel::SetMesh(NzMesh* mesh)
{
#if NAZARA_GRAPHICS_SAFE
if (mesh && mesh->GetAnimationType() != nzAnimationType_Skeletal)
{
NazaraError("Mesh animation type must be skeletal");
return;
}
#endif
NzModel::SetMesh(mesh);
if (m_mesh)
{
if (m_animation && m_animation->GetJointCount() != m_mesh->GetJointCount())
{
NazaraWarning("Animation joint count is not matching new mesh joint count, disabling animation...");
SetAnimation(nullptr);
}
m_skeleton = *m_mesh->GetSkeleton(); // Copie du squelette template
}
}
bool NzSkeletalModel::SetSequence(const NzString& sequenceName)
{
///TODO: Rendre cette erreur "safe" avec le nouveau système de gestions d'erreur (No-log)
#if NAZARA_GRAPHICS_SAFE
if (!m_animation)
{
NazaraError("Model has no animation");
return false;
}
#endif
const NzSequence* currentSequence = m_animation->GetSequence(sequenceName);
if (!currentSequence)
{
NazaraError("Sequence not found");
return false;
}
m_currentSequence = currentSequence;
m_nextFrame = m_currentSequence->firstFrame;
return true;
}
void NzSkeletalModel::SetSequence(unsigned int sequenceIndex)
{
#if NAZARA_GRAPHICS_SAFE
if (!m_animation)
{
NazaraError("Model has no animation");
return;
}
#endif
const NzSequence* currentSequence = m_animation->GetSequence(sequenceIndex);
#if NAZARA_GRAPHICS_SAFE
if (!currentSequence)
{
NazaraError("Sequence not found");
return;
}
#endif
m_currentSequence = currentSequence;
m_nextFrame = m_currentSequence->firstFrame;
}
NzSkeletalModel& NzSkeletalModel::operator=(const NzSkeletalModel& node)
{
NzSkeletalModel::operator=(node);
m_animation = node.m_animation;
m_animationEnabled = node.m_animationEnabled;
m_currentFrame = node.m_currentFrame;
m_currentSequence = node.m_currentSequence;
m_interpolation = node.m_interpolation;
m_nextFrame = node.m_nextFrame;
m_skeleton = node.m_skeleton;
return *this;
}
NzSkeletalModel& NzSkeletalModel::operator=(NzSkeletalModel&& node)
{
NzModel::operator=(node);
// Ressources
m_animation = std::move(node.m_animation);
m_skeleton = std::move(node.m_skeleton);
// Paramètres
m_animationEnabled = node.m_animationEnabled;
m_currentFrame = node.m_currentFrame;
m_currentSequence = node.m_currentSequence;
m_interpolation = node.m_interpolation;
m_nextFrame = node.m_nextFrame;
return *this;
}
void NzSkeletalModel::MakeBoundingVolume() const
{
m_boundingVolume.Set(m_skeleton.GetAABB());
}
void NzSkeletalModel::Register()
{
m_scene->RegisterForUpdate(this);
}
void NzSkeletalModel::Unregister()
{
m_scene->UnregisterForUpdate(this);
}
void NzSkeletalModel::Update()
{
if (m_animationEnabled && m_animation)
AdvanceAnimation(m_scene->GetUpdateTime());
}
NzSkeletalModelLoader::LoaderList NzSkeletalModel::s_loaders;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -35,8 +35,8 @@ namespace
NzVertexBuffer* buffer;
};
using MeshMap = std::unordered_map<const NzSkeletalMesh*, BufferData>;
using SkeletonMap = std::unordered_map<const NzSkeleton*, MeshMap>;
using MeshMap = std::unordered_map<const NzSkeletalMesh*, std::pair<NzSkeletalMeshConstListener, BufferData>>;
using SkeletonMap = std::unordered_map<const NzSkeleton*, std::pair<NzSkeletonConstListener, MeshMap>>;
SkeletonMap s_cache;
std::vector<SkinningData> s_skinningQueue;
@@ -51,7 +51,7 @@ namespace
{
for (auto& pair : s_cache)
{
MeshMap& meshMap = pair.second;
MeshMap& meshMap = pair.second.second;
meshMap.erase(static_cast<const NzSkeletalMesh*>(object));
}
break;
@@ -75,17 +75,20 @@ namespace
{
for (auto& pair : s_cache)
{
MeshMap& meshMap = pair.second;
MeshMap& meshMap = pair.second.second;
for (auto& pair2 : meshMap)
pair2.second.updated = false;
pair2.second.second.updated = false;
}
break;
}
case ObjectType_Skeleton:
{
for (auto& pair : s_cache.at(static_cast<const NzSkeleton*>(object)))
pair.second.updated = false;
const NzSkeleton* skeleton = static_cast<const NzSkeleton*>(object);
for (auto& pair : s_cache.at(skeleton).second)
pair.second.second.updated = false;
break;
break;
}
}
@@ -161,25 +164,20 @@ NzVertexBuffer* NzSkinningManager::GetBuffer(const NzSkeletalMesh* mesh, const N
SkeletonMap::iterator it = s_cache.find(skeleton);
if (it == s_cache.end())
{
it = s_cache.insert(std::make_pair(skeleton, SkeletonMap::mapped_type())).first;
skeleton->AddObjectListener(&listener, ObjectType_Skeleton);
}
it = s_cache.insert(std::make_pair(skeleton, std::make_pair(NzSkeletonConstListener(&listener, ObjectType_Skeleton, skeleton), MeshMap{}))).first;
NzVertexBuffer* buffer;
MeshMap& meshMap = it->second;
MeshMap& meshMap = it->second.second;
MeshMap::iterator it2 = meshMap.find(mesh);
if (it2 == meshMap.end())
{
std::unique_ptr<NzVertexBuffer> vertexBuffer(new NzVertexBuffer);
vertexBuffer->SetPersistent(false);
vertexBuffer->Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent), mesh->GetVertexCount(), nzBufferStorage_Hardware, nzBufferUsage_Dynamic);
vertexBuffer->Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent), mesh->GetVertexCount(), nzDataStorage_Hardware, nzBufferUsage_Dynamic);
BufferData data({vertexBuffer.get(), true});
meshMap.insert(std::make_pair(mesh, data));
mesh->AddObjectListener(&listener, ObjectType_SkeletalMesh);
meshMap.insert(std::make_pair(mesh, std::make_pair(NzSkeletalMeshConstListener(&listener, ObjectType_SkeletalMesh, mesh), data)));
s_skinningQueue.push_back(SkinningData{mesh, skeleton, vertexBuffer.get()});
@@ -187,7 +185,7 @@ NzVertexBuffer* NzSkinningManager::GetBuffer(const NzSkeletalMesh* mesh, const N
}
else
{
BufferData& data = it2->second;
BufferData& data = it2->second.second;
if (!data.updated)
{
s_skinningQueue.push_back(SkinningData{mesh, skeleton, data.buffer});
@@ -221,13 +219,6 @@ bool NzSkinningManager::Initialize()
void NzSkinningManager::Uninitialize()
{
for (auto& pair : s_cache)
{
pair.first->RemoveObjectListener(&listener);
MeshMap& meshMap = pair.second;
for (auto& pair2 : meshMap)
pair2.first->RemoveObjectListener(&listener);
}
s_cache.clear();
s_skinningQueue.clear();
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -21,7 +21,7 @@ namespace
{
NzIndexBuffer* BuildIndexBuffer()
{
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(false, 36, nzBufferStorage_Hardware, nzBufferUsage_Static));
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(false, 36, nzDataStorage_Hardware, nzBufferUsage_Static));
indexBuffer->SetPersistent(false);
nzUInt16 indices[6*6] =
@@ -87,7 +87,7 @@ namespace
"void main()\n"
"{\n"
" gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);\n"
" vTexCoord = vec3(VertexPosition.x, -VertexPosition.y, -VertexPosition.z);\n"
" vTexCoord = vec3(VertexPosition.x, VertexPosition.y, -VertexPosition.z);\n"
"}\n";
const char* vertexSource140 =
@@ -102,7 +102,7 @@ namespace
"void main()\n"
"{\n"
" gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);\n"
" vTexCoord = vec3(VertexPosition.x, -VertexPosition.y, -VertexPosition.z);\n"
" vTexCoord = vec3(VertexPosition.x, VertexPosition.y, -VertexPosition.z);\n"
"}\n";
///TODO: Remplacer ça par des ShaderNode
@@ -155,7 +155,7 @@ namespace
NzVertexBuffer* BuildVertexBuffer()
{
std::unique_ptr<NzVertexBuffer> vertexBuffer(new NzVertexBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ), 8, nzBufferStorage_Hardware, nzBufferUsage_Static));
std::unique_ptr<NzVertexBuffer> vertexBuffer(new NzVertexBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ), 8, nzDataStorage_Hardware, nzBufferUsage_Static));
vertexBuffer->SetPersistent(false);
float vertices[8*(sizeof(float)*3)] =

View File

@@ -1,75 +1,66 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <cstring>
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
NzSprite::NzSprite() :
m_boundingVolume(NzBoundingVolumef::Null()),
m_color(NzColor::White),
m_textureCoords(0.f, 0.f, 1.f, 1.f),
m_size(64.f, 64.f),
m_boundingVolumeUpdated(true)
m_verticesUpdated(false)
{
SetDefaultMaterial();
}
NzSprite::NzSprite(NzTexture* texture) :
m_boundingVolume(NzBoundingVolumef::Null()),
m_textureCoords(0.f, 0.f, 1.f, 1.f)
m_color(NzColor::White),
m_textureCoords(0.f, 0.f, 1.f, 1.f),
m_size(64.f, 64.f),
m_verticesUpdated(false)
{
if (texture)
{
m_material = new NzMaterial;
m_material->SetPersistent(false);
m_material->SetDiffuseMap(texture);
if (texture->IsValid())
m_size.Set(texture->GetWidth(), texture->GetHeight());
else
m_size.Set(64.f, 64.f);
m_boundingVolumeUpdated = false;
}
else
{
m_size.Set(64.f, 64.f);
m_boundingVolumeUpdated = true;
}
SetTexture(texture, true);
}
NzSprite::NzSprite(const NzSprite& sprite) :
NzSceneNode(sprite),
m_boundingVolume(sprite.m_boundingVolume),
m_color(sprite.m_color),
m_material(sprite.m_material),
m_textureCoords(sprite.m_textureCoords),
m_size(sprite.m_size),
m_boundingVolumeUpdated(sprite.m_boundingVolumeUpdated)
m_vertices(sprite.m_vertices),
m_verticesUpdated(sprite.m_verticesUpdated)
{
SetParent(sprite);
SetParent(sprite.GetParent());
}
NzSprite::NzSprite(NzSprite&& sprite) :
NzSceneNode(sprite),
m_boundingVolume(sprite.m_boundingVolume),
m_material(std::move(sprite.m_material)),
m_textureCoords(sprite.m_textureCoords),
m_size(sprite.m_size),
m_boundingVolumeUpdated(sprite.m_boundingVolumeUpdated)
{
}
NzSprite::~NzSprite() = default;
void NzSprite::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
{
renderQueue->AddSprite(this);
if (!m_verticesUpdated)
UpdateVertices();
renderQueue->AddSprites(m_material, m_vertices, 1);
}
const NzBoundingVolumef& NzSprite::GetBoundingVolume() const
NzSprite* NzSprite::Clone() const
{
static NzBoundingVolumef infinity(NzBoundingVolumef::Infinite());
return infinity;
return new NzSprite(*this);
}
NzSprite* NzSprite::Create() const
{
return new NzSprite;
}
const NzColor& NzSprite::GetColor() const
{
return m_color;
}
NzMaterial* NzSprite::GetMaterial() const
@@ -97,38 +88,69 @@ bool NzSprite::IsDrawable() const
return m_material != nullptr;
}
void NzSprite::SetColor(const NzColor& color)
{
m_color = color;
m_verticesUpdated = false;
}
void NzSprite::SetDefaultMaterial()
{
std::unique_ptr<NzMaterial> material(new NzMaterial);
material->Enable(nzRendererParameter_FaceCulling, false);
material->EnableLighting(false);
SetMaterial(material.get());
material->SetPersistent(false);
material.release();
}
void NzSprite::SetMaterial(NzMaterial* material, bool resizeSprite)
{
m_material = material;
NzTexture* diffuseMap = m_material->GetDiffuseMap();
if (resizeSprite && diffuseMap && diffuseMap->IsValid())
SetSize(NzVector2f(diffuseMap->GetSize()));
if (m_material && resizeSprite)
{
NzTexture* diffuseMap = m_material->GetDiffuseMap();
if (diffuseMap && diffuseMap->IsValid())
SetSize(NzVector2f(NzVector2ui(diffuseMap->GetSize())));
}
}
void NzSprite::SetSize(const NzVector2f& size)
{
m_size = size;
// On invalide la bounding box
m_boundingVolume.MakeNull();
m_boundingVolumeUpdated = false;
m_verticesUpdated = false;
}
void NzSprite::SetSize(float sizeX, float sizeY)
{
SetSize(NzVector2f(sizeX, sizeY));
}
void NzSprite::SetTexture(NzTexture* texture, bool resizeSprite)
{
std::unique_ptr<NzMaterial> material(new NzMaterial);
material->SetPersistent(false);
if (!m_material)
SetDefaultMaterial();
else if (m_material->GetReferenceCount() > 1)
{
m_material = new NzMaterial(*m_material);
m_material->SetPersistent(false);
}
material->Enable(nzRendererParameter_FaceCulling, false);
material->EnableLighting(false);
material->SetDiffuseMap(texture);
SetMaterial(material.get(), resizeSprite);
material.release();
m_material->SetDiffuseMap(texture);
if (resizeSprite && texture && texture->IsValid())
SetSize(NzVector2f(NzVector2ui(texture->GetSize())));
}
void NzSprite::SetTextureCoords(const NzRectf& coords)
{
m_textureCoords = coords;
m_verticesUpdated = false;
}
void NzSprite::SetTextureRect(const NzRectui& rect)
@@ -155,29 +177,69 @@ void NzSprite::SetTextureRect(const NzRectui& rect)
SetTextureCoords(NzRectf(invWidth*rect.x, invHeight*rect.y, invWidth*rect.width, invHeight*rect.height));
}
NzSprite& NzSprite::operator=(const NzSprite& sprite)
{
NzSceneNode::operator=(sprite);
m_color = sprite.m_color;
m_material = sprite.m_material;
m_textureCoords = sprite.m_textureCoords;
m_size = sprite.m_size;
// On ne copie pas les sommets finaux car il est très probable que nos paramètres soient modifiés et qu'ils doivent être régénérés de toute façon
m_verticesUpdated = false;
return *this;
}
void NzSprite::InvalidateNode()
{
NzSceneNode::InvalidateNode();
m_boundingVolumeUpdated = false;
m_verticesUpdated = false;
}
void NzSprite::Register()
{
// Le changement de scène peut affecter les sommets
m_verticesUpdated = false;
}
void NzSprite::Unregister()
{
}
void NzSprite::UpdateBoundingVolume() const
void NzSprite::MakeBoundingVolume() const
{
if (m_boundingVolume.IsNull())
m_boundingVolume.Set(-m_size.x*0.5f, -m_size.y*0.5f, 0.f, m_size.x, m_size.y, 0.f);
NzVector3f down = (m_scene) ? m_scene->GetDown() : NzVector3f::Down();
NzVector3f right = (m_scene) ? m_scene->GetRight() : NzVector3f::Right();
m_boundingVolume.Set(NzVector3f(0.f), m_size.x*right + m_size.y*down);
}
void NzSprite::UpdateVertices() const
{
if (!m_transformMatrixUpdated)
UpdateTransformMatrix();
m_boundingVolume.Update(m_transformMatrix);
m_boundingVolumeUpdated = true;
NzVector3f down = (m_scene) ? m_scene->GetDown() : NzVector3f::Down();
NzVector3f right = (m_scene) ? m_scene->GetRight() : NzVector3f::Right();
m_vertices[0].color = m_color;
m_vertices[0].position = m_transformMatrix.Transform(NzVector3f(0.f));
m_vertices[0].uv.Set(m_textureCoords.GetCorner(nzRectCorner_LeftTop));
m_vertices[1].color = m_color;
m_vertices[1].position = m_transformMatrix.Transform(m_size.x*right);
m_vertices[1].uv.Set(m_textureCoords.GetCorner(nzRectCorner_RightTop));
m_vertices[2].color = m_color;
m_vertices[2].position = m_transformMatrix.Transform(m_size.y*down);
m_vertices[2].uv.Set(m_textureCoords.GetCorner(nzRectCorner_LeftBottom));
m_vertices[3].color = m_color;
m_vertices[3].position = m_transformMatrix.Transform(m_size.x*right + m_size.y*down);
m_vertices[3].uv.Set(m_textureCoords.GetCorner(nzRectCorner_RightBottom));
m_verticesUpdated = true;
}

View File

@@ -0,0 +1,418 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/TextSprite.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/SparsePtr.hpp>
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <memory>
#include <Nazara/Utility/Font.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzTextSprite::NzTextSprite() :
m_color(NzColor::White),
m_verticesUpdated(false)
{
SetDefaultMaterial();
}
NzTextSprite::NzTextSprite(const NzTextSprite& sprite) :
NzSceneNode(sprite),
m_atlases(sprite.m_atlases),
m_renderInfos(sprite.m_renderInfos),
m_localVertices(sprite.m_localVertices),
m_vertices(sprite.m_vertices),
m_color(sprite.m_color),
m_material(sprite.m_material),
m_localBounds(sprite.m_localBounds),
m_verticesUpdated(sprite.m_verticesUpdated)
{
SetParent(sprite.GetParent());
for (const NzAbstractAtlas* atlas : m_atlases)
atlas->AddListener(this);
}
NzTextSprite::~NzTextSprite()
{
ClearAtlases();
}
void NzTextSprite::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
{
if (!m_verticesUpdated)
UpdateVertices();
for (auto& pair : m_renderInfos)
{
NzTexture* overlay = pair.first;
RenderIndices& indices = pair.second;
if (indices.count > 0)
renderQueue->AddSprites(m_material, &m_vertices[indices.first*4], indices.count, overlay);
}
}
void NzTextSprite::Clear()
{
ClearAtlases();
m_boundingVolume.MakeNull();
m_localVertices.clear();
m_renderInfos.clear();
m_vertices.clear();
}
NzTextSprite* NzTextSprite::Clone() const
{
return new NzTextSprite(*this);
}
NzTextSprite* NzTextSprite::Create() const
{
return new NzTextSprite;
}
const NzColor& NzTextSprite::GetColor() const
{
return m_color;
}
NzMaterial* NzTextSprite::GetMaterial() const
{
return m_material;
}
nzSceneNodeType NzTextSprite::GetSceneNodeType() const
{
return nzSceneNodeType_TextSprite;
}
void NzTextSprite::InvalidateVertices()
{
m_verticesUpdated = false;
}
bool NzTextSprite::IsDrawable() const
{
return m_material != nullptr;
}
void NzTextSprite::SetColor(const NzColor& color)
{
m_color = color;
m_verticesUpdated = false;
}
void NzTextSprite::SetDefaultMaterial()
{
std::unique_ptr<NzMaterial> material(new NzMaterial);
material->Enable(nzRendererParameter_Blend, true);
material->Enable(nzRendererParameter_DepthWrite, false);
material->Enable(nzRendererParameter_FaceCulling, false);
material->EnableLighting(false);
material->SetDstBlend(nzBlendFunc_InvSrcAlpha);
material->SetSrcBlend(nzBlendFunc_SrcAlpha);
SetMaterial(material.get());
material->SetPersistent(false);
material.release();
}
void NzTextSprite::SetMaterial(NzMaterial* material)
{
m_material = material;
}
void NzTextSprite::Update(const NzAbstractTextDrawer& drawer)
{
ClearAtlases();
NzCallOnExit clearOnFail([this]()
{
Clear();
});
unsigned int fontCount = drawer.GetFontCount();
for (unsigned int i = 0; i < fontCount; ++i)
{
NzFont* font = drawer.GetFont(i);
const NzAbstractAtlas* atlas = font->GetAtlas().get();
#if NAZARA_GRAPHICS_SAFE
if ((atlas->GetStorage() & nzDataStorage_Hardware) == 0)
{
// Cet atlas ne nous donnera pas de texture, nous ne pouvons pas l'utiliser
NazaraError("Font " + NzString::Pointer(font) + " uses a non-hardware atlas which cannot be used by text sprites");
return;
}
#endif
if (m_atlases.insert(atlas).second)
atlas->AddListener(this);
}
unsigned int glyphCount = drawer.GetGlyphCount();
m_localVertices.resize(glyphCount * 4);
m_vertices.resize(glyphCount * 4);
NzTexture* lastTexture = nullptr;
unsigned int* count = nullptr;
for (unsigned int i = 0; i < glyphCount; ++i)
{
const NzAbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i);
NzTexture* texture = static_cast<NzTexture*>(glyph.atlas);
if (lastTexture != texture)
{
auto pair = m_renderInfos.insert(std::make_pair(texture, RenderIndices{0U, 0U}));
count = &pair.first->second.count;
lastTexture = texture;
}
(*count)++;
}
// Attribution des indices
unsigned int index = 0;
for (auto& pair : m_renderInfos)
{
RenderIndices& indices = pair.second;
indices.first = index;
index += indices.count;
indices.count = 0; // On réinitialise count à zéro (on va s'en servir pour compteur dans la boucle suivante)
}
NzSparsePtr<NzVector2f> texCoordPtr(&m_vertices[0].uv, sizeof(NzVertexStruct_XYZ_Color_UV));
lastTexture = nullptr;
RenderIndices* indices = nullptr;
for (unsigned int i = 0; i < glyphCount; ++i)
{
const NzAbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i);
NzTexture* texture = static_cast<NzTexture*>(glyph.atlas);
if (lastTexture != texture)
{
indices = &m_renderInfos[texture]; // On a changé de texture, on ajuste le pointeur
lastTexture = texture;
}
// Affectation des positions et couleurs (locaux)
for (unsigned int j = 0; j < 4; ++j)
{
m_localVertices[i*4 + j].color = glyph.color;
m_localVertices[i*4 + j].position.Set(glyph.corners[j]);
}
// Calcul des coordonnées de texture (globaux)
// On commence par transformer les coordonnées entières en flottantes:
NzVector2ui size(texture->GetSize());
float invWidth = 1.f/size.x;
float invHeight = 1.f/size.y;
NzRectf uvRect(glyph.atlasRect);
uvRect.x *= invWidth;
uvRect.y *= invHeight;
uvRect.width *= invWidth;
uvRect.height *= invHeight;
// Extraction des quatre coins et attribution
NzSparsePtr<NzVector2f> texCoord = texCoordPtr + indices->first*4 + indices->count*4;
if (!glyph.flipped)
{
// Le glyphe n'est pas retourné, l'ordre des UV suit celui des sommets
*texCoord++ = uvRect.GetCorner(nzRectCorner_LeftTop);
*texCoord++ = uvRect.GetCorner(nzRectCorner_RightTop);
*texCoord++ = uvRect.GetCorner(nzRectCorner_LeftBottom);
*texCoord++ = uvRect.GetCorner(nzRectCorner_RightBottom);
}
else
{
// Le glyphe a subit une rotation de 90° (sens antihoraire), on adapte les UV en conséquence
*texCoord++ = uvRect.GetCorner(nzRectCorner_LeftBottom);
*texCoord++ = uvRect.GetCorner(nzRectCorner_LeftTop);
*texCoord++ = uvRect.GetCorner(nzRectCorner_RightBottom);
*texCoord++ = uvRect.GetCorner(nzRectCorner_RightTop);
}
// Et on passe au prochain
indices->count++;
}
m_localBounds = drawer.GetBounds();
m_boundingVolume.MakeNull();
m_boundingVolumeUpdated = false;
m_verticesUpdated = false;
clearOnFail.Reset();
}
NzTextSprite& NzTextSprite::operator=(const NzTextSprite& text)
{
NzSceneNode::operator=(text);
m_atlases = text.m_atlases;
m_color = text.m_color;
m_material = text.m_material;
m_renderInfos = text.m_renderInfos;
m_localBounds = text.m_localBounds;
m_localVertices = text.m_localVertices;
// On ne copie pas les sommets finaux car il est très probable que nos paramètres soient modifiés et qu'ils doivent être régénérés de toute façon
m_verticesUpdated = false;
return *this;
}
void NzTextSprite::ClearAtlases()
{
for (const NzAbstractAtlas* atlas : m_atlases)
atlas->RemoveListener(this);
m_atlases.clear();
}
void NzTextSprite::InvalidateNode()
{
NzSceneNode::InvalidateNode();
m_verticesUpdated = false;
}
void NzTextSprite::MakeBoundingVolume() const
{
NzVector3f down = (m_scene) ? m_scene->GetDown() : NzVector3f::Down();
NzVector3f right = (m_scene) ? m_scene->GetRight() : NzVector3f::Right();
NzRectf bounds(m_localBounds);
NzVector2f max = bounds.GetMaximum();
NzVector2f min = bounds.GetMinimum();
m_boundingVolume.Set(min.x*right + min.y*down, max.x*right + max.y*down);
}
bool NzTextSprite::OnAtlasCleared(const NzAbstractAtlas* atlas, void* userdata)
{
NazaraUnused(userdata);
#ifdef NAZARA_DEBUG
if (m_atlases.find(atlas) == m_atlases.end())
{
NazaraInternalError("Not listening to " + NzString::Pointer(atlas));
return false;
}
#endif
NazaraWarning("TextSprite " + NzString::Pointer(this) + " has been cleared because atlas " + NzString::Pointer(atlas) + " that was under use has been cleared");
Clear();
return false;
}
bool NzTextSprite::OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer, void* userdata)
{
NazaraUnused(atlas);
NazaraUnused(userdata);
#ifdef NAZARA_DEBUG
if (m_atlases.find(atlas) == m_atlases.end())
{
NazaraInternalError("Not listening to " + NzString::Pointer(atlas));
return false;
}
#endif
NzTexture* oldTexture = static_cast<NzTexture*>(oldLayer);
NzTexture* newTexture = static_cast<NzTexture*>(newLayer);
auto it = m_renderInfos.find(oldTexture);
if (it != m_renderInfos.end())
{
// Nous utilisons bien cette texture, nous devons mettre à jour les coordonnées de texture
RenderIndices indices = std::move(it->second);
NzVector2ui oldSize(oldTexture->GetSize());
NzVector2ui newSize(newTexture->GetSize());
NzVector2f scale = NzVector2f(oldSize)/NzVector2f(newSize);
NzSparsePtr<NzVector2f> texCoordPtr(&m_vertices[indices.first].uv, sizeof(NzVertexStruct_XYZ_Color_UV));
for (unsigned int i = 0; i < indices.count; ++i)
{
for (unsigned int j = 0; j < 4; ++j)
texCoordPtr[i*4 + j] *= scale;
}
// Nous enlevons l'ancienne texture et rajoutons la nouvelle à sa place (pour les mêmes indices)
m_renderInfos.erase(it);
m_renderInfos.insert(std::make_pair(newTexture, std::move(indices)));
}
return true;
}
void NzTextSprite::OnAtlasReleased(const NzAbstractAtlas* atlas, void* userdata)
{
NazaraUnused(userdata);
#ifdef NAZARA_DEBUG
if (m_atlases.find(atlas) == m_atlases.end())
{
NazaraInternalError("Not listening to " + NzString::Pointer(atlas));
return;
}
#endif
NazaraWarning("TextSprite " + NzString::Pointer(this) + " has been cleared because atlas " + NzString::Pointer(atlas) + " that was under use has been released");
Clear();
}
void NzTextSprite::Register()
{
// Le changement de scène peut affecter les sommets
m_verticesUpdated = false;
}
void NzTextSprite::Unregister()
{
}
void NzTextSprite::UpdateVertices() const
{
if (!m_transformMatrixUpdated)
UpdateTransformMatrix();
NzVector3f down = (m_scene) ? m_scene->GetDown() : NzVector3f::Down();
NzVector3f right = (m_scene) ? m_scene->GetRight() : NzVector3f::Right();
NzSparsePtr<NzColor> colorPtr(&m_vertices[0].color, sizeof(NzVertexStruct_XYZ_Color_UV));
NzSparsePtr<NzVector3f> posPtr(&m_vertices[0].position, sizeof(NzVertexStruct_XYZ_Color_UV));
for (auto& pair : m_renderInfos)
{
RenderIndices& indices = pair.second;
NzSparsePtr<NzColor> color = colorPtr + indices.first*4;
NzSparsePtr<NzVector3f> pos = posPtr + indices.first*4;
NzVertexStruct_XY_Color* localVertex = &m_localVertices[indices.first*4];
for (unsigned int i = 0; i < indices.count; ++i)
{
for (unsigned int j = 0; j < 4; ++j)
{
*pos++ = m_transformMatrix.Transform(localVertex->position.x*right + localVertex->position.y*down);
*color++ = m_color * localVertex->color;
localVertex++;
}
}
}
m_verticesUpdated = true;
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -10,6 +10,7 @@
NzView::NzView() :
m_targetRegion(0.f, 0.f, 1.f, 1.f),
m_size(0.f),
m_target(nullptr),
m_frustumUpdated(false),
m_projectionMatrixUpdated(false),
@@ -20,6 +21,12 @@ m_zNear(-1.f)
{
}
NzView::NzView(const NzVector2f& size) :
NzView() // On délègue
{
SetSize(size);
}
NzView::~NzView()
{
if (m_target)
@@ -73,6 +80,21 @@ const NzFrustumf& NzView::GetFrustum() const
return m_frustum;
}
NzVector3f NzView::GetGlobalForward() const
{
return NzVector3f::UnitZ();
}
NzVector3f NzView::GetGlobalRight() const
{
return NzVector3f::UnitX();
}
NzVector3f NzView::GetGlobalUp() const
{
return -NzVector3f::UnitY();
}
const NzMatrix4f& NzView::GetProjectionMatrix() const
{
if (!m_projectionMatrixUpdated)
@@ -125,6 +147,17 @@ float NzView::GetZNear() const
return m_zNear;
}
void NzView::SetSize(const NzVector2f& size)
{
SetSize(size.x, size.y);
}
void NzView::SetSize(float width, float height)
{
m_size.Set(width, height);
m_projectionMatrixUpdated = false;
}
void NzView::SetTarget(const NzRenderTarget* renderTarget)
{
if (m_target)
@@ -256,10 +289,16 @@ void NzView::UpdateFrustum() const
void NzView::UpdateProjectionMatrix() const
{
if (!m_viewportUpdated)
UpdateViewport();
if (m_size.x <= 0.f || m_size.y <= 0.f) // Si la taille est nulle, on prendra la taille du viewport
{
if (!m_viewportUpdated)
UpdateViewport();
m_projectionMatrix.MakeOrtho(0.f, m_viewport.width, 0.f, m_viewport.height, m_zNear, m_zFar);
}
else
m_projectionMatrix.MakeOrtho(0.f, m_size.x, 0.f, m_size.y, m_zNear, m_zFar);
m_projectionMatrix.MakeOrtho(m_viewport.x, m_viewport.x + m_viewport.width, m_viewport.y, m_viewport.y + m_viewport.height, m_zNear, m_zFar);
m_projectionMatrixUpdated = true;
}