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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
48
src/Nazara/Graphics/GuillotineTextureAtlas.cpp
Normal file
48
src/Nazara/Graphics/GuillotineTextureAtlas.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
14
src/Nazara/Graphics/ParticleController.cpp
Normal file
14
src/Nazara/Graphics/ParticleController.cpp
Normal 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;
|
||||
231
src/Nazara/Graphics/ParticleDeclaration.cpp
Normal file
231
src/Nazara/Graphics/ParticleDeclaration.cpp
Normal 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];
|
||||
92
src/Nazara/Graphics/ParticleEmitter.cpp
Normal file
92
src/Nazara/Graphics/ParticleEmitter.cpp
Normal 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;
|
||||
}
|
||||
14
src/Nazara/Graphics/ParticleGenerator.cpp
Normal file
14
src/Nazara/Graphics/ParticleGenerator.cpp
Normal 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;
|
||||
15
src/Nazara/Graphics/ParticleMapper.cpp
Normal file
15
src/Nazara/Graphics/ParticleMapper.cpp
Normal 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;
|
||||
14
src/Nazara/Graphics/ParticleRenderer.cpp
Normal file
14
src/Nazara/Graphics/ParticleRenderer.cpp
Normal 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;
|
||||
346
src/Nazara/Graphics/ParticleSystem.cpp
Normal file
346
src/Nazara/Graphics/ParticleSystem.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
352
src/Nazara/Graphics/SkeletalModel.cpp
Normal file
352
src/Nazara/Graphics/SkeletalModel.cpp
Normal 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;
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)] =
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
418
src/Nazara/Graphics/TextSprite.cpp
Normal file
418
src/Nazara/Graphics/TextSprite.cpp
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user