From 13a50a87dd11101c208fb8c7975e6f0b801e49ab Mon Sep 17 00:00:00 2001 From: SweetId <2630750+SweetId@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:59:23 +0530 Subject: [PATCH] Add EditorCameraComponent and EditorCameraSystem --- .../Core/Components/CameraComponent.hpp | 39 ++++++++ .../Core/Systems/CameraSystem.hpp | 37 ++++++++ .../Core/Components/CameraComponent.cpp | 95 +++++++++++++++++++ .../Core/Systems/CameraSystem.cpp | 39 ++++++++ 4 files changed, 210 insertions(+) create mode 100644 include/NazaraEditor/Core/Components/CameraComponent.hpp create mode 100644 include/NazaraEditor/Core/Systems/CameraSystem.hpp create mode 100644 src/NazaraEditor/Core/Components/CameraComponent.cpp create mode 100644 src/NazaraEditor/Core/Systems/CameraSystem.cpp diff --git a/include/NazaraEditor/Core/Components/CameraComponent.hpp b/include/NazaraEditor/Core/Components/CameraComponent.hpp new file mode 100644 index 0000000..6a14166 --- /dev/null +++ b/include/NazaraEditor/Core/Components/CameraComponent.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include + +namespace Nz +{ + class NodeComponent; + class WindowEventHandler; + + class NAZARAEDITOR_CORE_API EditorCameraComponent + { + public: + EditorCameraComponent(); + EditorCameraComponent(const EditorCameraComponent&) = delete; + + EditorCameraComponent(EditorCameraComponent&&); + ~EditorCameraComponent(); + + void Update(Time elapsedTime, NodeComponent& node); + + inline void SetPosition(const Nz::Vector3f& position) { m_targetPosition = position; } + inline void SetRotation(const Nz::Quaternionf& rotation) { m_targetAngles = rotation.ToEulerAngles(); } + + inline const Nz::Vector3f& GetPosition() const { return m_targetPosition; } + inline const Nz::EulerAnglesf& GetOrientation() const { return m_targetAngles; } + + private: + NazaraSlot(Nz::WindowEventHandler, OnMouseMoved, m_onMouseMoved); + + Nz::EulerAnglesf m_targetAngles; + Nz::Vector3f m_targetPosition; + Nz::Vector3f m_currentVelocity; + + float m_moveSpeed; + float m_smoothSpeed; + }; +} \ No newline at end of file diff --git a/include/NazaraEditor/Core/Systems/CameraSystem.hpp b/include/NazaraEditor/Core/Systems/CameraSystem.hpp new file mode 100644 index 0000000..92b844a --- /dev/null +++ b/include/NazaraEditor/Core/Systems/CameraSystem.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include +#include + +namespace Nz +{ + class NAZARAEDITOR_CORE_API EditorCameraSystem + { + public: + static constexpr bool AllowConcurrent = false; + static constexpr Int64 ExecutionOrder = 1'001; + + EditorCameraSystem(entt::registry& registry); + ~EditorCameraSystem(); + + EditorCameraSystem(const EditorCameraSystem&) = delete; + EditorCameraSystem& operator=(const EditorCameraSystem&) = delete; + + EditorCameraSystem(EditorCameraSystem&&) = delete; + EditorCameraSystem& operator=(EditorCameraSystem&&) = delete; + + void Update(Time elapsedTime); + + private: + void OnCameraDestroy(entt::registry& registry, entt::entity entity); + + entt::registry& m_registry; + + entt::observer m_cameraConstructObserver; + entt::scoped_connection m_cameraDestroyConnection; + + std::unordered_set m_cameraEntities; + }; +} \ No newline at end of file diff --git a/src/NazaraEditor/Core/Components/CameraComponent.cpp b/src/NazaraEditor/Core/Components/CameraComponent.cpp new file mode 100644 index 0000000..a233c5e --- /dev/null +++ b/src/NazaraEditor/Core/Components/CameraComponent.cpp @@ -0,0 +1,95 @@ +#include + +#include + +namespace +{ + // Unity SmoothDamp function + template + T SmoothDamp(T current, T target, T& currentVelocity, float smoothTime, Nz::Time deltaTime) + { + if (current.SquaredDistance(target) < 0.0001f) + return target; + + // Based on Game Programming Gems 4 Chapter 1.10 + smoothTime = std::max(0.0001f, smoothTime); + float omega = 2.f / smoothTime; + + float x = omega * deltaTime.AsSeconds(); + float exp = 1.f / (1.f + x + 0.48f * x * x + 0.235f * x * x * x); + T change = current - target; + T originalTo = target; + + // Clamp maximum speed + float maxChange = smoothTime; + float dist = change.GetLength(); + dist = Nz::Clamp(dist, -maxChange, maxChange); + target = current - change.Normalize() * dist; + + T temp = (currentVelocity + omega * change) * deltaTime.AsSeconds(); + currentVelocity = (currentVelocity - omega * temp) * exp; + T output = target + (change + temp) * exp; + + // Prevent overshooting + if (current.SquaredDistance(target) <= current.SquaredDistance(output)) + { + output = originalTo; + currentVelocity = (output - originalTo) / deltaTime.AsSeconds(); + } + + return output; + } +} + +namespace Nz +{ + EditorCameraComponent::EditorCameraComponent() + : m_moveSpeed(3.f) + , m_smoothSpeed(0.3f) + { + auto& handler = EditorBaseApplication::Instance()->GetWindow()->GetEventHandler(); + + m_onMouseMoved.Connect(handler.OnMouseMoved, [&](const Nz::WindowEventHandler*, const Nz::WindowEvent::MouseMoveEvent& event) + { + // Gestion de la caméra free-fly (Rotation) + float sensitivity = 0.3f; // Sensibilité de la souris + + // On modifie l'angle de la caméra grâce au déplacement relatif sur X de la souris + m_targetAngles.yaw = m_targetAngles.yaw - event.deltaX * sensitivity; + m_targetAngles.yaw.Normalize(); + + // Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles + m_targetAngles.pitch = Nz::Clamp(m_targetAngles.pitch - event.deltaY * sensitivity, -89.f, 89.f); + }); + } + + EditorCameraComponent::~EditorCameraComponent() + { + m_onMouseMoved.Disconnect(); + } + + void EditorCameraComponent::Update(Time elapsedTime, NodeComponent& node) + { + // todo use action mapping + Nz::Vector3f delta; + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::W)) + delta += Nz::Vector3f::Forward(); + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::S)) + delta += Nz::Vector3f::Backward(); + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::A)) + delta += Nz::Vector3f::Left(); + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::D)) + delta += Nz::Vector3f::Right(); + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Q)) + delta += Nz::Vector3f::Up(); + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::E)) + delta += Nz::Vector3f::Down(); + + auto currentRotation = m_targetAngles.ToQuaternion(); + m_targetPosition += (currentRotation * delta) * elapsedTime.AsSeconds() * m_moveSpeed; + + auto currentPosition = SmoothDamp(node.GetPosition(), m_targetPosition, m_currentVelocity, m_smoothSpeed, elapsedTime); + node.SetPosition(currentPosition); + node.SetRotation(currentRotation); + } +} \ No newline at end of file diff --git a/src/NazaraEditor/Core/Systems/CameraSystem.cpp b/src/NazaraEditor/Core/Systems/CameraSystem.cpp new file mode 100644 index 0000000..8adf71d --- /dev/null +++ b/src/NazaraEditor/Core/Systems/CameraSystem.cpp @@ -0,0 +1,39 @@ +#include +#include + +#include + +namespace Nz +{ + EditorCameraSystem::EditorCameraSystem(entt::registry& registry) + : m_registry(registry) + , m_cameraConstructObserver(registry, entt::collector.group()) + { + m_cameraDestroyConnection = registry.on_destroy().connect<&EditorCameraSystem::OnCameraDestroy>(this); + } + + EditorCameraSystem::~EditorCameraSystem() + { + m_cameraConstructObserver.disconnect(); + } + + void EditorCameraSystem::Update(Time elapsedTime) + { + m_cameraConstructObserver.each([&](entt::entity entity) { + m_cameraEntities.insert(entity); + }); + + for (auto entity : m_cameraEntities) + { + EditorCameraComponent& camera = m_registry.get(entity); + NodeComponent& transform = m_registry.get(entity); + + camera.Update(elapsedTime, transform); + } + } + + void EditorCameraSystem::OnCameraDestroy(entt::registry& registry, entt::entity entity) + { + m_cameraEntities.erase(entity); + } +} \ No newline at end of file