diff --git a/openVulkanoCpp/Controller/CameraController.cpp b/openVulkanoCpp/Controller/CameraController.cpp new file mode 100644 index 0000000..81ba2e1 --- /dev/null +++ b/openVulkanoCpp/Controller/CameraController.cpp @@ -0,0 +1,40 @@ +#include "CameraController.hpp" +#include "Scene/Camera.hpp" +#include "Input/InputDeviceMouse.hpp" +#include "Input/InputDeviceController.hpp" +#include "Input/InputManager.hpp" +#include "Input/Touch/InputDeviceTouch.hpp" + + +namespace OpenVulkano +{ + CameraController::CameraController(Scene::Camera* camera) + { + m_inputManager = Input::InputManager::GetInstance(); + m_camera = camera; + m_actionCastRay = m_inputManager->GetAction("cast ray"); + m_actionCastRay->BindKey(Input::InputKey::Mouse::BUTTON_1); + // BIND FOR TOUCH + m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_X); + m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_X); + } + + void CameraController::Tick() + { + Input::InputDeviceMouse* mouse = static_cast(m_inputManager->GetDevice(Input::InputDeviceType::MOUSE)); + Input::InputDeviceTouch* touch = static_cast(m_inputManager->GetDevice(Input::InputDeviceType::TOUCH)); + if (m_camera->CanCastRay() && m_inputManager->GetButton(m_actionCastRay)) + { + if (mouse && mouse->GetButtonDown(Input::InputKey::Mouse::BUTTON_1)) + { + Math::Vector2i pos = mouse->GetMousePosition(); + mouse->onLeftButtonClick.NotifyAll(pos); + } + else if (touch) + { + Math::Vector2i pos = touch->GetTapPosition(); + touch->OnTap.NotifyAll(pos); + } + } + } +} diff --git a/openVulkanoCpp/Controller/CameraController.hpp b/openVulkanoCpp/Controller/CameraController.hpp index 80bfa2d..9650b04 100644 --- a/openVulkanoCpp/Controller/CameraController.hpp +++ b/openVulkanoCpp/Controller/CameraController.hpp @@ -11,6 +11,12 @@ namespace OpenVulkano { + namespace Input + { + class InputAction; + class InputManager; + } + namespace Scene { class Camera; @@ -18,22 +24,26 @@ namespace OpenVulkano class CameraController : public ITickable, ICloseable { - Scene::Camera* m_camera; - protected: - CameraController(Scene::Camera* camera = nullptr) - : m_camera(camera) - {} + Scene::Camera* m_camera; + Input::InputAction* m_actionCastRay; + Input::InputManager* m_inputManager; + + CameraController(Scene::Camera* camera = nullptr); public: ~CameraController() override = default; + void Tick() override; + virtual void Init(Scene::Camera* camera) { m_camera = camera; } void Close() override { m_camera = nullptr; } void SetCamera(Scene::Camera* camera) { m_camera = camera; } + Input::InputAction* GetActionCastRay() { return m_actionCastRay; } + Scene::Camera* GetCamera() { return m_camera; } virtual void SetActive() {} diff --git a/openVulkanoCpp/Controller/FreeCamCameraController.cpp b/openVulkanoCpp/Controller/FreeCamCameraController.cpp index 8f94d3e..7f0a082 100644 --- a/openVulkanoCpp/Controller/FreeCamCameraController.cpp +++ b/openVulkanoCpp/Controller/FreeCamCameraController.cpp @@ -8,6 +8,7 @@ #include "Base/FrameMetadata.hpp" #include "Scene/Camera.hpp" #include "Input/InputManager.hpp" +#include "Input/InputDeviceMouse.hpp" #include "Input/InputKey.hpp" namespace OpenVulkano @@ -39,6 +40,8 @@ namespace OpenVulkano vec *= m_boostFactor; } + CameraController::Tick(); + m_yaw -= input->GetAxis(m_actionLookSide) * timeScale / 2.0f; m_pitch -= input->GetAxis(m_actionLookUp) * timeScale / 2.0f; m_pitch = std::min(1.4f, std::max(-1.4f, m_pitch)); @@ -48,6 +51,7 @@ namespace OpenVulkano Math::Matrix4f camTransformation = Math::Utils::toMat4(rot); camTransformation[3] = Math::Vector4f(m_position, 1); GetCamera()->SetMatrix(camTransformation); + //CameraController::Tick(); CURRENT_FRAME.needsRedraw = true; } diff --git a/openVulkanoCpp/Input/InputDeviceMouse.hpp b/openVulkanoCpp/Input/InputDeviceMouse.hpp index d3a320b..29f2cf1 100644 --- a/openVulkanoCpp/Input/InputDeviceMouse.hpp +++ b/openVulkanoCpp/Input/InputDeviceMouse.hpp @@ -8,6 +8,7 @@ #include "InputDevice.hpp" #include "Math/Math.hpp" +#include "Base/Event.hpp" namespace OpenVulkano { @@ -143,6 +144,9 @@ namespace OpenVulkano { return window == lastWindow; } + + Event onLeftButtonClick; + }; } } \ No newline at end of file diff --git a/openVulkanoCpp/Input/InputManager.cpp b/openVulkanoCpp/Input/InputManager.cpp index 5e36010..af918a3 100644 --- a/openVulkanoCpp/Input/InputManager.cpp +++ b/openVulkanoCpp/Input/InputManager.cpp @@ -85,6 +85,18 @@ namespace OpenVulkano::Input return false; } + InputDevice* InputManager::GetDevice(InputDeviceType type) const + { + for (InputDevice* device: devices) + { + if (device->GetType() == type && type != InputDeviceType::UNKNOWN) + { + return device; + } + } + return nullptr; + } + void InputManager::Tick() { for(InputDevice* device : devices) diff --git a/openVulkanoCpp/Input/InputManager.hpp b/openVulkanoCpp/Input/InputManager.hpp index d2aa6dc..774b65c 100644 --- a/openVulkanoCpp/Input/InputManager.hpp +++ b/openVulkanoCpp/Input/InputManager.hpp @@ -42,6 +42,8 @@ namespace OpenVulkano::Input [[nodiscard]] bool GetButton(InputKey key) const; + [[nodiscard]] InputDevice* GetDevice(InputDeviceType type) const; + [[nodiscard]] InputDevice* GetLastActiveDevice() const { return lastActiveDevice; diff --git a/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp b/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp index 7d0dfa7..8fde139 100644 --- a/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp +++ b/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp @@ -84,5 +84,6 @@ namespace OpenVulkano::Input [[nodiscard]] bool IsMultiTouch() const { return m_multiTouch; } Event OnTouchAdded, OnTouchDown, OnTouchUp, OnTouchMoved, OnTouchRemoved; + Event OnTap; }; } diff --git a/openVulkanoCpp/Scene/Camera.cpp b/openVulkanoCpp/Scene/Camera.cpp new file mode 100644 index 0000000..6253937 --- /dev/null +++ b/openVulkanoCpp/Scene/Camera.cpp @@ -0,0 +1,68 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "Camera.hpp" +#include "Scene/Scene.hpp" +#include "Scene/SimpleDrawable.hpp" +#include "Scene/Geometry.hpp" +#include "Scene/Shader/Shader.hpp" +#include "Scene/TextDrawable.hpp" +#include "Scene/Prefabs/LabelDrawable.hpp" +#include "Scene/Ray.hpp" +#include "Scene/TextDrawable.hpp" + +namespace OpenVulkano::Scene +{ + + std::optional PerspectiveCamera::CastRay(const Math::Vector2i& xy) const + { + using namespace Math::Utils; + + auto scene = GetScene(); + + // nds + float ndsX = (2.f * xy.x) / m_width - 1.0f; + float ndsY = (2.f * xy.y) / m_height - 1.0f; + + Math::Vector4f rayClip = { ndsX, ndsY, 0, 1.f }; + + Math::Vector4f rayEye = inverse(m_projection) * rayClip; + rayEye.z = -1; + rayEye.a = 0; + + Math::Vector3f rayWorld = normalize(inverse(m_view) * rayEye); + + std::optional res; + for (Drawable* d: scene->rayHittableDrawables) + { + const auto& m = d->GetNodes()[0]->GetWorldMatrix(); + const Math::Vector3f rayLocalDir = normalize(inverse(m) * Math::Vector4f(rayWorld, 0)); + const Math::Vector4f rayLocalPos = inverse(m) * m_camPosition; + const Ray ray(rayLocalPos, rayLocalDir); + if (auto hit = d->Intersect(ray)) + { + // choose the closest one + if (!res || (hit->distance < res->distance)) + { + res = hit; + res->drawable = d; + } + } + } + if (res) + { + if (SimpleDrawable* sd = dynamic_cast(res->drawable)) + { + Logger::APP->info("Ray intersects object {}", sd->GetMesh()->name); + } + else if (LabelDrawable* sd = dynamic_cast(res->drawable)) + { + Logger::APP->info("Ray intersects label {}", sd->GetTexts().front().GetText()); + } + } + return res; + } +} diff --git a/openVulkanoCpp/Scene/Camera.hpp b/openVulkanoCpp/Scene/Camera.hpp index f755ded..2788cf6 100644 --- a/openVulkanoCpp/Scene/Camera.hpp +++ b/openVulkanoCpp/Scene/Camera.hpp @@ -9,6 +9,10 @@ #include "Node.hpp" #include "Math/Math.hpp" #include "Math/Frustum.hpp" +#include "Input/InputDeviceMouse.hpp" +#include "Input/Touch/InputDeviceTouch.hpp" +#include "Input/InputManager.hpp" +#include "Base/Logger.hpp" #include namespace OpenVulkano::Scene @@ -27,6 +31,7 @@ namespace OpenVulkano::Scene float m_contentScaleFactor = 1, m_zoom = 1; // For use with ortho camera float m_interfaceOrientation = 0; float m_padding = 0; //Unused + bool m_canCastRay = true; Camera() : m_nearPlane(0), m_farPlane(0), m_width(0), m_height(0) {} @@ -45,6 +50,20 @@ namespace OpenVulkano::Scene m_farPlane = farPlane; Node::Init(); UpdateProjectionMatrix(); + if (m_canCastRay) + { + Input::InputDeviceMouse* mouse = static_cast(Input::InputManager::GetInstance()->GetDevice(Input::InputDeviceType::MOUSE)); + Input::InputDeviceTouch* touch = static_cast(Input::InputManager::GetInstance()->GetDevice(Input::InputDeviceType::TOUCH)); + if (mouse) + { + mouse->onLeftButtonClick += EventHandler(this, &Camera::CastRay); + } + else if (touch) + { + touch->OnTap += EventHandler(this, &Camera::CastRay); + } + } + } public: @@ -66,6 +85,8 @@ namespace OpenVulkano::Scene [[nodiscard]] float FarPlane() const { return m_farPlane; } + [[nodiscard]] bool CanCastRay() const { return m_canCastRay; } + void SetContentScaleFactor(float contentScale = 1) { m_contentScaleFactor = 1.0f / contentScale; @@ -83,6 +104,8 @@ namespace OpenVulkano::Scene virtual void UpdateProjectionMatrix() = 0; + virtual std::optional CastRay(const Math::Vector2i& xy) const = 0; + void UpdateViewProjectionMatrix() { m_viewProjection = m_projection * m_view; @@ -241,6 +264,8 @@ namespace OpenVulkano::Scene SetProjectionMatrix(Math::Utils::perspectiveRH_ZO(m_fov, m_aspect, m_nearPlane, m_farPlane)); } + std::optional CastRay(const Math::Vector2i& xy) const override; + [[nodiscard]] bool IsPerspective() const override { return true; } }; @@ -254,6 +279,11 @@ namespace OpenVulkano::Scene SetProjectionMatrix(Math::Utils::orthoRH_ZO(-widthHalf, widthHalf, -heightHalf, heightHalf, m_nearPlane, m_farPlane)); } + std::optional CastRay(const Math::Vector2i& xy) const override + { + throw std::runtime_error("Not implemented yet"); + } + [[nodiscard]] bool IsOrtho() const override { return true; } }; }