diff --git a/include/Nazara/Graphics/Camera.hpp b/include/Nazara/Graphics/Camera.hpp index 790097835..9d182fdb4 100644 --- a/include/Nazara/Graphics/Camera.hpp +++ b/include/Nazara/Graphics/Camera.hpp @@ -13,10 +13,9 @@ #include #include #include +#include -class NzRenderTarget; - -class NAZARA_API NzCamera : public NzSceneNode +class NAZARA_API NzCamera : public NzSceneNode, NzRenderTarget::Listener { public: NzCamera(); @@ -35,36 +34,47 @@ class NAZARA_API NzCamera : public NzSceneNode const NzMatrix4f& GetProjectionMatrix() const; nzSceneNodeType GetSceneNodeType() const override; const NzRenderTarget* GetTarget() const; + const NzRectf& GetTargetRegion() const; const NzMatrix4f& GetViewMatrix() const; - const NzRectf& GetViewport() const; + const NzRectui& GetViewport() const; float GetZFar() const; float GetZNear() const; void SetFOV(float fov); void SetTarget(const NzRenderTarget* renderTarget); void SetTarget(const NzRenderTarget& renderTarget); - void SetViewport(const NzRectf& viewport); + void SetTargetRegion(const NzRectf& region); + void SetViewport(const NzRectui& viewport); void SetZFar(float zFar); void SetZNear(float zNear); private: void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override; void Invalidate(); - void Register(); - void Unregister(); + + void OnRenderTargetReleased(const NzRenderTarget* renderTarget, void* userdata) override; + bool OnRenderTargetSizeChange(const NzRenderTarget* renderTarget, void* userdata) override; + + void Register() override; + void Unregister() override; + void UpdateFrustum() const; void UpdateProjectionMatrix() const; void UpdateViewMatrix() const; + void UpdateViewport() const; + bool VisibilityTest(const NzFrustumf& frustum) override; mutable NzFrustumf m_frustum; mutable NzMatrix4f m_projectionMatrix; mutable NzMatrix4f m_viewMatrix; - NzRectf m_viewport; + NzRectf m_targetRegion; + mutable NzRectui m_viewport; const NzRenderTarget* m_target; mutable bool m_frustumUpdated; mutable bool m_projectionMatrixUpdated; mutable bool m_viewMatrixUpdated; + mutable bool m_viewportUpdated; mutable float m_aspectRatio; float m_fov; float m_zFar; diff --git a/include/Nazara/Renderer/RenderTarget.hpp b/include/Nazara/Renderer/RenderTarget.hpp index b466b8f87..8c5eb16a7 100644 --- a/include/Nazara/Renderer/RenderTarget.hpp +++ b/include/Nazara/Renderer/RenderTarget.hpp @@ -10,6 +10,7 @@ #include #include #include +#include class NzRenderer; @@ -18,9 +19,13 @@ class NAZARA_API NzRenderTarget friend class NzRenderer; public: - NzRenderTarget() = default; + class Listener; + + NzRenderTarget(); virtual ~NzRenderTarget(); + void AddListener(Listener* listener, void* userdata = nullptr) const; + virtual unsigned int GetHeight() const = 0; virtual NzRenderTargetParameters GetParameters() const = 0; virtual unsigned int GetWidth() const = 0; @@ -28,14 +33,34 @@ class NAZARA_API NzRenderTarget bool IsActive() const; virtual bool IsRenderable() const = 0; + void RemoveListener(Listener* listener) const; + bool SetActive(bool active); // Fonctions OpenGL virtual bool HasContext() const = 0; + class Listener + { + public: + Listener() = default; + ~Listener(); + + virtual bool OnRenderTargetParametersChange(const NzRenderTarget* renderTarget, void* userdata); + virtual void OnRenderTargetReleased(const NzRenderTarget* renderTarget, void* userdata); + virtual bool OnRenderTargetSizeChange(const NzRenderTarget* renderTarget, void* userdata); + }; + protected: virtual bool Activate() const = 0; virtual void Desactivate() const; + + void NotifyParametersChange(); + void NotifySizeChange(); + + private: + mutable std::unordered_map m_listeners; + bool m_listenersLocked; }; #endif // NAZARA_RENDERTARGET_HPP diff --git a/src/Nazara/Graphics/Camera.cpp b/src/Nazara/Graphics/Camera.cpp index 88466aad2..ba67735f3 100644 --- a/src/Nazara/Graphics/Camera.cpp +++ b/src/Nazara/Graphics/Camera.cpp @@ -10,9 +10,11 @@ NzCamera::NzCamera() : m_viewport(0.f, 0.f, 1.f, 1.f), +m_target(nullptr), m_frustumUpdated(false), m_projectionMatrixUpdated(false), m_viewMatrixUpdated(false), +m_viewportUpdated(false), m_aspectRatio(0.f), m_fov(70.f), m_zFar(100.f), @@ -20,50 +22,27 @@ m_zNear(1.f) { } -NzCamera::~NzCamera() = default; +NzCamera::~NzCamera() +{ + if (m_target) + m_target->RemoveListener(this); +} void NzCamera::Activate() { #ifdef NAZARA_GRAPHICS_SAFE if (!m_target) { - NazaraError("No render target !"); + NazaraError("Camera has no render target"); return; } #endif + if (!m_viewportUpdated) + UpdateViewport(); + NzRenderer::SetTarget(m_target); - - unsigned int width = m_target->GetWidth(); - unsigned int height = std::max(m_target->GetHeight(), 1U); - - float vWidth = width * m_viewport.width; - float vHeight = height * m_viewport.height; - - NzRectui viewport; - viewport.x = width * m_viewport.x; - viewport.y = height * m_viewport.x; - viewport.width = vWidth; - viewport.height = height * m_viewport.height; - NzRenderer::SetViewport(viewport); - - float aspectRatio = vWidth/vHeight; - - if (!NzNumberEquals(m_aspectRatio, aspectRatio)) - { - m_aspectRatio = aspectRatio; - m_frustumUpdated = false; - m_projectionMatrixUpdated = false; - } - - if (!m_projectionMatrixUpdated) - UpdateProjectionMatrix(); - - if (!m_viewMatrixUpdated) - UpdateViewMatrix(); - - NzRenderer::SetMatrix(nzMatrixType_Projection, m_projectionMatrix); - NzRenderer::SetMatrix(nzMatrixType_View, m_viewMatrix); + NzRenderer::SetViewport(m_viewport); if (m_scene) m_scene->SetActiveCamera(this); @@ -130,6 +109,11 @@ const NzRenderTarget* NzCamera::GetTarget() const return m_target; } +const NzRectf& NzCamera::GetTargetRegion() const +{ + return m_targetRegion; +} + const NzMatrix4f& NzCamera::GetViewMatrix() const { if (!m_viewMatrixUpdated) @@ -138,8 +122,19 @@ const NzMatrix4f& NzCamera::GetViewMatrix() const return m_viewMatrix; } -const NzRectf& NzCamera::GetViewport() const +const NzRectui& NzCamera::GetViewport() const { + #if NAZARA_GRAPHICS_SAFE + if (!m_target) + { + NazaraError("Camera has no render target"); + return m_viewport; + } + #endif + + if (!m_viewportUpdated) + UpdateViewport(); + return m_viewport; } @@ -158,12 +153,18 @@ void NzCamera::SetFOV(float fov) m_fov = fov; m_frustumUpdated = false; - m_projectionMatrixUpdated= false; + m_projectionMatrixUpdated = false; } void NzCamera::SetTarget(const NzRenderTarget* renderTarget) { + NazaraError(NzString::Pointer(m_target)); + if (m_target) + m_target->RemoveListener(this); + m_target = renderTarget; + if (m_target) + m_target->AddListener(this); } void NzCamera::SetTarget(const NzRenderTarget& renderTarget) @@ -171,9 +172,27 @@ void NzCamera::SetTarget(const NzRenderTarget& renderTarget) SetTarget(&renderTarget); } -void NzCamera::SetViewport(const NzRectf& viewport) +void NzCamera::SetTargetRegion(const NzRectf& region) { - m_viewport = viewport; + m_targetRegion = region; + m_viewportUpdated = false; +} + +void NzCamera::SetViewport(const NzRectui& viewport) +{ + #if NAZARA_GRAPHICS_SAFE + if (!m_target) + { + NazaraError("Camera has no render target"); + return; + } + #endif + + // On calcule la région nécessaire pour produire ce viewport avec la taille actuelle de la cible + float invWidth = 1.f/m_target->GetWidth(); + float invHeight = 1.f/m_target->GetHeight(); + + SetTargetRegion(NzRectf(invWidth * viewport.x, invHeight * viewport.y, invWidth * viewport.width, invHeight * viewport.height)); } void NzCamera::SetZFar(float zFar) @@ -196,17 +215,40 @@ void NzCamera::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const { NazaraUnused(renderQueue); - NazaraInternalError("SceneNode::AddToRenderQueue() called on SceneRoot"); + NazaraInternalError("SceneNode::AddToRenderQueue() called on Camera"); } void NzCamera::Invalidate() { NzSceneNode::Invalidate(); + // Le frustum et la view matrix dépendent des paramètres du node, invalidons-les m_frustumUpdated = false; m_viewMatrixUpdated = false; } +void NzCamera::OnRenderTargetReleased(const NzRenderTarget* renderTarget, void* userdata) +{ + NazaraUnused(userdata); + + if (renderTarget == m_target) + m_target = nullptr; + else + NazaraInternalError("Not listening to " + NzString::Pointer(renderTarget)); +} + +bool NzCamera::OnRenderTargetSizeChange(const NzRenderTarget* renderTarget, void* userdata) +{ + NazaraUnused(userdata); + + if (renderTarget == m_target) + m_viewportUpdated = false; + else + NazaraInternalError("Not listening to " + NzString::Pointer(renderTarget)); + + return true; +} + void NzCamera::Register() { } @@ -242,6 +284,29 @@ void NzCamera::UpdateViewMatrix() const m_viewMatrixUpdated = true; } +void NzCamera::UpdateViewport() const +{ + unsigned int width = m_target->GetWidth(); + unsigned int height = std::max(m_target->GetHeight(), 1U); + + float vWidth = width * m_viewport.width; + float vHeight = height * m_viewport.height; + float aspectRatio = vWidth/vHeight; + + if (!NzNumberEquals(m_aspectRatio, aspectRatio, 0.001f)) + { + m_aspectRatio = aspectRatio; + m_frustumUpdated = false; + m_projectionMatrixUpdated = false; + } + + m_viewport.x = width * m_targetRegion.x; + m_viewport.y = height * m_targetRegion.y; + m_viewport.width = vWidth; + m_viewport.height = vHeight; + m_viewportUpdated = true; +} + bool NzCamera::VisibilityTest(const NzFrustumf& frustum) { NazaraUnused(frustum); diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index 5db7c2aa9..8a54c5bf1 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -140,6 +140,9 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene) const NzCamera* camera = scene->GetActiveCamera(); const NzShaderProgram* lastProgram = nullptr; + NzRenderer::SetMatrix(nzMatrixType_Projection, camera->GetProjectionMatrix()); + NzRenderer::SetMatrix(nzMatrixType_View, camera->GetViewMatrix()); + // Rendu des modèles opaques for (auto& matIt : m_renderQueue.opaqueModels) { diff --git a/src/Nazara/Graphics/SkyboxBackground.cpp b/src/Nazara/Graphics/SkyboxBackground.cpp index 625609cf7..0403d617b 100644 --- a/src/Nazara/Graphics/SkyboxBackground.cpp +++ b/src/Nazara/Graphics/SkyboxBackground.cpp @@ -198,13 +198,14 @@ void NzSkyboxBackground::Draw(const NzScene* scene) const s_program->SendInteger(s_skyboxLocation, 0); - const NzMatrix4f& viewMatrix = NzRenderer::GetMatrix(nzMatrixType_View); - NzMatrix4f skyboxMatrix(viewMatrix); + NzCamera* camera = scene->GetActiveCamera(); + + NzMatrix4f skyboxMatrix(camera->GetViewMatrix()); skyboxMatrix.SetTranslation(NzVector3f::Zero()); NzRenderer::SetIndexBuffer(m_indexBuffer); NzRenderer::SetMatrix(nzMatrixType_View, skyboxMatrix); - NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Scale(NzVector3f(scene->GetActiveCamera()->GetZNear()))); + NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Scale(NzVector3f(camera->GetZNear()))); NzRenderer::SetRenderStates(states); NzRenderer::SetShaderProgram(s_program); NzRenderer::SetTexture(0, m_texture); @@ -212,8 +213,6 @@ void NzSkyboxBackground::Draw(const NzScene* scene) const NzRenderer::SetVertexBuffer(m_vertexBuffer); NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, 36); - - NzRenderer::SetMatrix(nzMatrixType_View, viewMatrix); } nzBackgroundType NzSkyboxBackground::GetBackgroundType() const diff --git a/src/Nazara/Renderer/RenderTarget.cpp b/src/Nazara/Renderer/RenderTarget.cpp index 401ae8627..e2e45552d 100644 --- a/src/Nazara/Renderer/RenderTarget.cpp +++ b/src/Nazara/Renderer/RenderTarget.cpp @@ -6,13 +6,37 @@ #include #include -NzRenderTarget::~NzRenderTarget() = default; +NzRenderTarget::NzRenderTarget() : +m_listenersLocked(false) +{ +} + +NzRenderTarget::~NzRenderTarget() +{ + m_listenersLocked = true; + for (auto& pair : m_listeners) + pair.first->OnRenderTargetReleased(this, pair.second); +} + +void NzRenderTarget::AddListener(Listener* listener, void* userdata) const +{ + NazaraError("What the"); + if (!m_listenersLocked) + m_listeners.insert(std::make_pair(listener, userdata)); + NazaraError("What the"); +} bool NzRenderTarget::IsActive() const { return NzRenderer::GetTarget() == this; } +void NzRenderTarget::RemoveListener(Listener* listener) const +{ + if (!m_listenersLocked) + m_listeners.erase(listener); +} + bool NzRenderTarget::SetActive(bool active) { if (active) @@ -27,3 +51,59 @@ void NzRenderTarget::Desactivate() const { // Seuls les target sans contextes (ex: NzRenderTexture) nécessitent une désactivation } + +void NzRenderTarget::NotifyParametersChange() +{ + m_listenersLocked = true; + + auto it = m_listeners.begin(); + while (it != m_listeners.end()) + { + if (!it->first->OnRenderTargetParametersChange(this, it->second)) + m_listeners.erase(it++); + else + ++it; + } + + m_listenersLocked = false; +} + +void NzRenderTarget::NotifySizeChange() +{ + m_listenersLocked = true; + + auto it = m_listeners.begin(); + while (it != m_listeners.end()) + { + if (!it->first->OnRenderTargetSizeChange(this, it->second)) + m_listeners.erase(it++); + else + ++it; + } + + m_listenersLocked = false; +} + +NzRenderTarget::Listener::~Listener() = default; + +bool NzRenderTarget::Listener::OnRenderTargetParametersChange(const NzRenderTarget* renderTarget, void* userdata) +{ + NazaraUnused(renderTarget); + NazaraUnused(userdata); + + return true; +} + +void NzRenderTarget::Listener::OnRenderTargetReleased(const NzRenderTarget* renderTarget, void* userdata) +{ + NazaraUnused(renderTarget); + NazaraUnused(userdata); +} + +bool NzRenderTarget::Listener::OnRenderTargetSizeChange(const NzRenderTarget* renderTarget, void* userdata) +{ + NazaraUnused(renderTarget); + NazaraUnused(userdata); + + return true; +} diff --git a/src/Nazara/Renderer/RenderTexture.cpp b/src/Nazara/Renderer/RenderTexture.cpp index 696f3eb28..0b53de42d 100644 --- a/src/Nazara/Renderer/RenderTexture.cpp +++ b/src/Nazara/Renderer/RenderTexture.cpp @@ -317,6 +317,9 @@ bool NzRenderTexture::Create(unsigned int width, unsigned int height, bool lock) return false; } + NotifyParametersChange(); + NotifySizeChange(); + return true; } @@ -435,6 +438,7 @@ NzRenderTargetParameters NzRenderTexture::GetParameters() const } #endif + ///TODO return NzRenderTargetParameters(); } diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index a1bfdc2a3..37a30a8af 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -294,6 +294,9 @@ bool NzRenderWindow::OnWindowCreated() if (!SetActive(true)) // Les fenêtres s'activent à la création NazaraWarning("Failed to activate window"); + NotifyParametersChange(); + NotifySizeChange(); + m_clock.Restart(); return true;