From 793952eb672cedaeebc85faa9230cfaee3cccee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 29 Jul 2021 20:16:58 +0200 Subject: [PATCH] Graphics: Add Camera class --- include/Nazara/Graphics/Camera.hpp | 76 +++++++ include/Nazara/Graphics/Camera.inl | 202 ++++++++++++++++++ .../Graphics/Components/CameraComponent.hpp | 60 +----- .../Graphics/Components/CameraComponent.inl | 192 ----------------- src/Nazara/Graphics/Camera.cpp | 55 +++++ .../Graphics/Components/CameraComponent.cpp | 45 ---- 6 files changed, 340 insertions(+), 290 deletions(-) create mode 100644 include/Nazara/Graphics/Camera.hpp create mode 100644 include/Nazara/Graphics/Camera.inl create mode 100644 src/Nazara/Graphics/Camera.cpp diff --git a/include/Nazara/Graphics/Camera.hpp b/include/Nazara/Graphics/Camera.hpp new file mode 100644 index 000000000..99a0e1335 --- /dev/null +++ b/include/Nazara/Graphics/Camera.hpp @@ -0,0 +1,76 @@ +// Copyright (C) 2021 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 + +#pragma once + +#ifndef NAZARA_CAMERA_HPP +#define NAZARA_CAMERA_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API Camera : public AbstractViewer + { + public: + inline Camera(const RenderTarget* renderTarget, ProjectionType projectionType = ProjectionType::Perspective); + inline Camera(const Camera& camera); + inline Camera(Camera&& camera) noexcept; + ~Camera() = default; + + inline float GetAspectRatio() const; + inline DegreeAnglef GetFOV() const; + const RenderTarget& GetRenderTarget() override; + inline const Vector2f& GetSize() const; + inline const Rectf& GetTargetRegion() const; + ViewerInstance& GetViewerInstance() override; + const ViewerInstance& GetViewerInstance() const override; + const Recti& GetViewport() const override; + inline float GetZFar() const; + inline float GetZNear() const; + + inline void UpdateFOV(DegreeAnglef fov); + inline void UpdateProjectionType(ProjectionType projectionType); + inline void UpdateSize(const Vector2f& size); + void UpdateTarget(const RenderTarget* framebuffer); + inline void UpdateTargetRegion(const Rectf& targetRegion); + inline void UpdateViewport(const Recti& viewport); + inline void UpdateZFar(float zFar); + inline void UpdateZNear(float zNear); + + inline Camera& operator=(const Camera& camera); + inline Camera& operator=(Camera&& camera) noexcept; + + private: + inline void UpdateProjectionMatrix(); + inline void UpdateViewport(); + inline void UpdateViewport(Vector2ui renderTargetSize); + + NazaraSlot(RenderTarget, OnRenderTargetRelease, m_onRenderTargetRelease); + NazaraSlot(RenderTarget, OnRenderTargetSizeChange, m_onRenderTargetSizeChange); + + const RenderTarget* m_renderTarget; + DegreeAnglef m_fov; + ProjectionType m_projectionType; + Rectf m_targetRegion; + Recti m_viewport; + Vector2f m_size; + ViewerInstance m_viewerInstance; + float m_aspectRatio; + float m_zFar; + float m_zNear; + }; +} + +#include + +#endif diff --git a/include/Nazara/Graphics/Camera.inl b/include/Nazara/Graphics/Camera.inl new file mode 100644 index 000000000..1a73aef69 --- /dev/null +++ b/include/Nazara/Graphics/Camera.inl @@ -0,0 +1,202 @@ +// Copyright (C) 2021 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#include +#include + +namespace Nz +{ + inline Camera::Camera(const RenderTarget* renderTarget, ProjectionType projectionType) : + m_renderTarget(nullptr), + m_fov(70.f), + m_projectionType(projectionType), + m_targetRegion(0.f, 0.f, 1.f, 1.f), + m_viewport(0, 0, 0, 0), + m_size(-1.f, -1.f), + m_zFar(1000.f), + m_zNear(1.f) + { + UpdateTarget(renderTarget); + } + + inline Camera::Camera(const Camera& camera) : + m_renderTarget(nullptr), + m_fov(camera.m_fov), + m_projectionType(camera.m_projectionType), + m_targetRegion(camera.m_targetRegion), + m_viewport(camera.m_viewport), + m_size(camera.m_size), + m_aspectRatio(camera.m_aspectRatio), + m_zFar(camera.m_zFar), + m_zNear(camera.m_zNear) + { + UpdateTarget(camera.m_renderTarget); + } + + inline Camera::Camera(Camera&& camera) noexcept : + m_renderTarget(nullptr), + m_fov(camera.m_fov), + m_projectionType(camera.m_projectionType), + m_targetRegion(camera.m_targetRegion), + m_viewport(camera.m_viewport), + m_size(camera.m_size), + m_aspectRatio(camera.m_aspectRatio), + m_zFar(camera.m_zFar), + m_zNear(camera.m_zNear) + { + UpdateTarget(camera.m_renderTarget); + } + + inline float Camera::GetAspectRatio() const + { + return m_aspectRatio; + } + + inline DegreeAnglef Camera::GetFOV() const + { + return m_fov; + } + + inline const Vector2f& Camera::GetSize() const + { + return m_size; + } + + inline const Rectf& Camera::GetTargetRegion() const + { + return m_targetRegion; + } + + inline float Camera::GetZFar() const + { + return m_zFar; + } + + inline float Camera::GetZNear() const + { + return m_zNear; + } + + inline void Camera::UpdateFOV(DegreeAnglef fov) + { + m_fov = fov; + UpdateProjectionMatrix(); + } + + inline void Camera::UpdateZFar(float zFar) + { + m_zFar = zFar; + UpdateProjectionMatrix(); + } + + inline void Camera::UpdateZNear(float zNear) + { + NazaraAssert(!NumberEquals(zNear, 0.f), "zNear cannot be zero"); + + m_zNear = zNear; + UpdateProjectionMatrix(); + } + + inline Camera& Camera::operator=(const Camera& camera) + { + m_fov = camera.m_fov; + m_projectionType = camera.m_projectionType; + m_targetRegion = camera.m_targetRegion; + m_viewport = camera.m_viewport; + m_size = camera.m_size; + m_aspectRatio = camera.m_aspectRatio; + m_zFar = camera.m_zFar; + m_zNear = camera.m_zNear; + + UpdateTarget(camera.m_renderTarget); + + return *this; + } + + inline Camera& Camera::operator=(Camera&& camera) noexcept + { + m_fov = camera.m_fov; + m_projectionType = camera.m_projectionType; + m_targetRegion = camera.m_targetRegion; + m_viewport = camera.m_viewport; + m_size = camera.m_size; + m_aspectRatio = camera.m_aspectRatio; + m_zFar = camera.m_zFar; + m_zNear = camera.m_zNear; + + UpdateTarget(camera.m_renderTarget); + + return *this; + } + + inline void Camera::UpdateProjectionType(ProjectionType projectionType) + { + m_projectionType = projectionType; + UpdateProjectionMatrix(); + } + + inline void Camera::UpdateTargetRegion(const Rectf& targetRegion) + { + m_targetRegion = targetRegion; + UpdateViewport(); + } + + inline void Camera::UpdateViewport(const Recti& viewport) + { + NazaraAssert(m_renderTarget, "no render target"); + + // We compute the region necessary to make this view port with the actual size of the target + Vector2f invSize = 1.f / Vector2f(m_renderTarget->GetSize()); + + UpdateTargetRegion(Rectf(invSize.x * viewport.x, invSize.y * viewport.y, invSize.x * viewport.width, invSize.y * viewport.height)); + } + + inline void Camera::UpdateSize(const Vector2f& size) + { + m_size = size; + UpdateProjectionMatrix(); + } + + inline void Camera::UpdateProjectionMatrix() + { + switch (m_projectionType) + { + case ProjectionType::Orthographic: + if (m_size.x < 0.f || m_size.y < 0.f) + m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Ortho(0.f, float(m_viewport.x), 0.f, float(m_viewport.y), m_zNear, m_zFar)); + else + m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Ortho(0.f, m_size.x, 0.f, m_size.y, m_zNear, m_zFar)); + break; + + case ProjectionType::Perspective: + m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Perspective(m_fov, m_aspectRatio, m_zNear, m_zFar)); + break; + } + } + + inline void Camera::UpdateViewport() + { + NazaraAssert(m_renderTarget, "no rendertarget!"); + return UpdateViewport(m_renderTarget->GetSize()); + } + + inline void Camera::UpdateViewport(Vector2ui renderTargetSize) + { + renderTargetSize.y = std::max(renderTargetSize.y, 1U); // Let's make sure we won't divide by zero + + // Our target region is expressed as % of the viewport dimensions, let's compute it in pixels + Rectf fViewport(m_targetRegion); + fViewport.x *= renderTargetSize.x; + fViewport.y *= renderTargetSize.y; + fViewport.width *= renderTargetSize.x; + fViewport.height *= renderTargetSize.y; + + m_aspectRatio = fViewport.width / fViewport.height; + + // Convert it back to int + m_viewport.Set(fViewport); + + UpdateProjectionMatrix(); + } +} diff --git a/include/Nazara/Graphics/Components/CameraComponent.hpp b/include/Nazara/Graphics/Components/CameraComponent.hpp index 89807a6c4..705510d91 100644 --- a/include/Nazara/Graphics/Components/CameraComponent.hpp +++ b/include/Nazara/Graphics/Components/CameraComponent.hpp @@ -8,66 +8,20 @@ #define NAZARA_CAMERACOMPONENT_HPP #include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace Nz { - class NAZARA_GRAPHICS_API CameraComponent : public AbstractViewer + class NAZARA_GRAPHICS_API CameraComponent : public Camera { public: - inline CameraComponent(const RenderTarget* renderTarget, ProjectionType projectionType = ProjectionType::Perspective); - inline CameraComponent(const CameraComponent& camera); - inline CameraComponent(CameraComponent&& camera) noexcept; + using Camera::Camera; + CameraComponent(const CameraComponent& camera) = default; + CameraComponent(CameraComponent&& camera) noexcept = default; ~CameraComponent() = default; - inline float GetAspectRatio() const; - inline DegreeAnglef GetFOV() const; - const RenderTarget& GetRenderTarget() override; - inline const Vector2f& GetSize() const; - inline const Rectf& GetTargetRegion() const; - ViewerInstance& GetViewerInstance() override; - const ViewerInstance& GetViewerInstance() const override; - const Recti& GetViewport() const override; - inline float GetZFar() const; - inline float GetZNear() const; - - inline void UpdateFOV(DegreeAnglef fov); - inline void UpdateProjectionType(ProjectionType projectionType); - inline void UpdateSize(const Vector2f& size); - void UpdateTarget(const RenderTarget* framebuffer); - inline void UpdateTargetRegion(const Rectf& targetRegion); - inline void UpdateViewport(const Recti& viewport); - inline void UpdateZFar(float zFar); - inline void UpdateZNear(float zNear); - - inline CameraComponent& operator=(const CameraComponent& camera); - inline CameraComponent& operator=(CameraComponent&& camera) noexcept; - - private: - inline void UpdateProjectionMatrix(); - inline void UpdateViewport(); - inline void UpdateViewport(Vector2ui renderTargetSize); - - NazaraSlot(RenderTarget, OnRenderTargetRelease, m_onRenderTargetRelease); - NazaraSlot(RenderTarget, OnRenderTargetSizeChange, m_onRenderTargetSizeChange); - - const RenderTarget* m_renderTarget; - DegreeAnglef m_fov; - ProjectionType m_projectionType; - Rectf m_targetRegion; - Recti m_viewport; - Vector2f m_size; - ViewerInstance m_viewerInstance; - float m_aspectRatio; - float m_zFar; - float m_zNear; + CameraComponent& operator=(const CameraComponent& camera) = default; + CameraComponent& operator=(CameraComponent&& camera) noexcept = default; }; } diff --git a/include/Nazara/Graphics/Components/CameraComponent.inl b/include/Nazara/Graphics/Components/CameraComponent.inl index 55ea155b2..8b9bf0b34 100644 --- a/include/Nazara/Graphics/Components/CameraComponent.inl +++ b/include/Nazara/Graphics/Components/CameraComponent.inl @@ -7,196 +7,4 @@ namespace Nz { - inline CameraComponent::CameraComponent(const RenderTarget* renderTarget, ProjectionType projectionType) : - m_renderTarget(nullptr), - m_fov(70.f), - m_projectionType(projectionType), - m_targetRegion(0.f, 0.f, 1.f, 1.f), - m_viewport(0, 0, 0, 0), - m_size(-1.f, -1.f), - m_zFar(1000.f), - m_zNear(1.f) - { - UpdateTarget(renderTarget); - } - - inline CameraComponent::CameraComponent(const CameraComponent& camera) : - m_renderTarget(nullptr), - m_fov(camera.m_fov), - m_projectionType(camera.m_projectionType), - m_targetRegion(camera.m_targetRegion), - m_viewport(camera.m_viewport), - m_size(camera.m_size), - m_aspectRatio(camera.m_aspectRatio), - m_zFar(camera.m_zFar), - m_zNear(camera.m_zNear) - { - UpdateTarget(camera.m_renderTarget); - } - - inline CameraComponent::CameraComponent(CameraComponent&& camera) noexcept : - m_renderTarget(nullptr), - m_fov(camera.m_fov), - m_projectionType(camera.m_projectionType), - m_targetRegion(camera.m_targetRegion), - m_viewport(camera.m_viewport), - m_size(camera.m_size), - m_aspectRatio(camera.m_aspectRatio), - m_zFar(camera.m_zFar), - m_zNear(camera.m_zNear) - { - UpdateTarget(camera.m_renderTarget); - } - - inline float CameraComponent::GetAspectRatio() const - { - return m_aspectRatio; - } - - inline DegreeAnglef CameraComponent::GetFOV() const - { - return m_fov; - } - - inline const Vector2f& CameraComponent::GetSize() const - { - return m_size; - } - - inline const Rectf& CameraComponent::GetTargetRegion() const - { - return m_targetRegion; - } - - inline float CameraComponent::GetZFar() const - { - return m_zFar; - } - - inline float CameraComponent::GetZNear() const - { - return m_zNear; - } - - inline void CameraComponent::UpdateFOV(DegreeAnglef fov) - { - m_fov = fov; - UpdateProjectionMatrix(); - } - - inline void CameraComponent::UpdateZFar(float zFar) - { - m_zFar = zFar; - UpdateProjectionMatrix(); - } - - inline void CameraComponent::UpdateZNear(float zNear) - { - NazaraAssert(!NumberEquals(zNear, 0.f), "zNear cannot be zero"); - - m_zNear = zNear; - UpdateProjectionMatrix(); - } - - inline CameraComponent& CameraComponent::operator=(const CameraComponent& camera) - { - m_fov = camera.m_fov; - m_projectionType = camera.m_projectionType; - m_targetRegion = camera.m_targetRegion; - m_viewport = camera.m_viewport; - m_size = camera.m_size; - m_aspectRatio = camera.m_aspectRatio; - m_zFar = camera.m_zFar; - m_zNear = camera.m_zNear; - - UpdateTarget(camera.m_renderTarget); - - return *this; - } - - inline CameraComponent& CameraComponent::operator=(CameraComponent&& camera) noexcept - { - m_fov = camera.m_fov; - m_projectionType = camera.m_projectionType; - m_targetRegion = camera.m_targetRegion; - m_viewport = camera.m_viewport; - m_size = camera.m_size; - m_aspectRatio = camera.m_aspectRatio; - m_zFar = camera.m_zFar; - m_zNear = camera.m_zNear; - - UpdateTarget(camera.m_renderTarget); - - return *this; - } - - inline void CameraComponent::UpdateProjectionType(ProjectionType projectionType) - { - m_projectionType = projectionType; - UpdateProjectionMatrix(); - } - - inline void CameraComponent::UpdateTargetRegion(const Rectf& targetRegion) - { - m_targetRegion = targetRegion; - UpdateViewport(); - } - - inline void CameraComponent::UpdateViewport(const Recti& viewport) - { - NazaraAssert(m_renderTarget, "no render target"); - - // We compute the region necessary to make this view port with the actual size of the target - Vector2f invSize = 1.f / Vector2f(m_renderTarget->GetSize()); - - UpdateTargetRegion(Rectf(invSize.x * viewport.x, invSize.y * viewport.y, invSize.x * viewport.width, invSize.y * viewport.height)); - } - - inline void CameraComponent::UpdateSize(const Vector2f& size) - { - m_size = size; - UpdateProjectionMatrix(); - } - - inline void CameraComponent::UpdateProjectionMatrix() - { - switch (m_projectionType) - { - case ProjectionType::Orthographic: - if (m_size.x < 0.f || m_size.y < 0.f) - m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Ortho(0.f, float(m_viewport.x), 0.f, float(m_viewport.y), m_zNear, m_zFar)); - else - m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Ortho(0.f, m_size.x, 0.f, m_size.y, m_zNear, m_zFar)); - break; - - case ProjectionType::Perspective: - m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Perspective(m_fov, m_aspectRatio, m_zNear, m_zFar)); - break; - } - } - - inline void CameraComponent::UpdateViewport() - { - NazaraAssert(m_renderTarget, "no rendertarget!"); - return UpdateViewport(m_renderTarget->GetSize()); - } - - inline void CameraComponent::UpdateViewport(Vector2ui renderTargetSize) - { - renderTargetSize.y = std::max(renderTargetSize.y, 1U); // Let's make sure we won't divide by zero - - // Our target region is expressed as % of the viewport dimensions, let's compute it in pixels - Rectf fViewport(m_targetRegion); - fViewport.x *= renderTargetSize.x; - fViewport.y *= renderTargetSize.y; - fViewport.width *= renderTargetSize.x; - fViewport.height *= renderTargetSize.y; - - m_aspectRatio = fViewport.width / fViewport.height; - - // Convert it back to int - m_viewport.Set(fViewport); - - UpdateProjectionMatrix(); - } } diff --git a/src/Nazara/Graphics/Camera.cpp b/src/Nazara/Graphics/Camera.cpp new file mode 100644 index 000000000..d955324db --- /dev/null +++ b/src/Nazara/Graphics/Camera.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2021 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#include +#include +#include + +namespace Nz +{ + const RenderTarget& Camera::GetRenderTarget() + { + if (!m_renderTarget) + throw std::runtime_error("no rendertarget set"); + + return* m_renderTarget; + } + + ViewerInstance& Camera::GetViewerInstance() + { + return m_viewerInstance; + } + + const ViewerInstance& Camera::GetViewerInstance() const + { + return m_viewerInstance; + } + + const Recti& Camera::GetViewport() const + { + return m_viewport; + } + + void Camera::UpdateTarget(const RenderTarget* renderTarget) + { + m_onRenderTargetRelease.Disconnect(); + m_onRenderTargetSizeChange.Disconnect(); + + m_renderTarget = renderTarget; + if (m_renderTarget) + { + m_onRenderTargetRelease.Connect(m_renderTarget->OnRenderTargetRelease, [this](const RenderTarget*) + { + UpdateTarget(nullptr); + }); + + m_onRenderTargetSizeChange.Connect(m_renderTarget->OnRenderTargetSizeChange, [this](const RenderTarget*, const Vector2ui& newSize) + { + UpdateViewport(newSize); + }); + + UpdateViewport(); + } + } +} diff --git a/src/Nazara/Graphics/Components/CameraComponent.cpp b/src/Nazara/Graphics/Components/CameraComponent.cpp index b47892b4f..8b9bf0b34 100644 --- a/src/Nazara/Graphics/Components/CameraComponent.cpp +++ b/src/Nazara/Graphics/Components/CameraComponent.cpp @@ -3,53 +3,8 @@ // For conditions of distribution and use, see copyright notice in Prerequisites.hpp #include -#include #include namespace Nz { - const RenderTarget& CameraComponent::GetRenderTarget() - { - if (!m_renderTarget) - throw std::runtime_error("no rendertarget set"); - - return* m_renderTarget; - } - - ViewerInstance& CameraComponent::GetViewerInstance() - { - return m_viewerInstance; - } - - const ViewerInstance& CameraComponent::GetViewerInstance() const - { - return m_viewerInstance; - } - - const Recti& CameraComponent::GetViewport() const - { - return m_viewport; - } - - void CameraComponent::UpdateTarget(const RenderTarget* renderTarget) - { - m_onRenderTargetRelease.Disconnect(); - m_onRenderTargetSizeChange.Disconnect(); - - m_renderTarget = renderTarget; - if (m_renderTarget) - { - m_onRenderTargetRelease.Connect(m_renderTarget->OnRenderTargetRelease, [this](const RenderTarget*) - { - UpdateTarget(nullptr); - }); - - m_onRenderTargetSizeChange.Connect(m_renderTarget->OnRenderTargetSizeChange, [this](const RenderTarget*, const Vector2ui& newSize) - { - UpdateViewport(newSize); - }); - - UpdateViewport(); - } - } }