From 6e7d1e0e711bdafcbc77c3a4958b5b840e313a5a Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sun, 26 Apr 2020 16:37:49 -0500 Subject: [PATCH] VideoCommon: Add Free Look camera with separate modes --- Source/Core/VideoCommon/CMakeLists.txt | 2 + Source/Core/VideoCommon/FreeLookCamera.cpp | 272 ++++++++++++++++++++ Source/Core/VideoCommon/FreeLookCamera.h | 66 +++++ Source/Core/VideoCommon/VideoCommon.vcxproj | 2 + Source/Core/VideoCommon/VideoConfig.h | 8 + 5 files changed, 350 insertions(+) create mode 100644 Source/Core/VideoCommon/FreeLookCamera.cpp create mode 100644 Source/Core/VideoCommon/FreeLookCamera.h diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index d8993e19d4..8e957f4a8d 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -33,6 +33,8 @@ add_library(videocommon FramebufferManager.h FramebufferShaderGen.cpp FramebufferShaderGen.h + FreeLookCamera.cpp + FreeLookCamera.h GeometryShaderGen.cpp GeometryShaderGen.h GeometryShaderManager.cpp diff --git a/Source/Core/VideoCommon/FreeLookCamera.cpp b/Source/Core/VideoCommon/FreeLookCamera.cpp new file mode 100644 index 0000000000..45ceb775b1 --- /dev/null +++ b/Source/Core/VideoCommon/FreeLookCamera.cpp @@ -0,0 +1,272 @@ +// Copyright 2020 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "VideoCommon/FreeLookCamera.h" + +#include +#include + +#include + +#include "Common/MathUtil.h" + +#include "Common/ChunkFile.h" +#include "Core/Config/GraphicsSettings.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "VideoCommon/VideoCommon.h" +#include "VideoCommon/VideoConfig.h" + +FreeLookCamera g_freelook_camera; + +namespace +{ +std::string to_string(FreelookControlType type) +{ + switch (type) + { + case FreelookControlType::SixAxis: + return "Six Axis"; + case FreelookControlType::FPS: + return "First Person"; + case FreelookControlType::Orbital: + return "Orbital"; + } + + return ""; +} + +class SixAxisController : public CameraController +{ +public: + SixAxisController() = default; + + Common::Matrix44 GetView() override { return m_mat; } + + void MoveVertical(float amt) override + { + m_mat = Common::Matrix44::Translate(Common::Vec3{0, amt, 0}) * m_mat; + } + + void MoveHorizontal(float amt) override + { + m_mat = Common::Matrix44::Translate(Common::Vec3{amt, 0, 0}) * m_mat; + } + + void Zoom(float amt) override + { + m_mat = Common::Matrix44::Translate(Common::Vec3{0, 0, amt}) * m_mat; + } + + void Rotate(const Common::Vec3& amt) override + { + using Common::Matrix33; + m_mat = Common::Matrix44::FromMatrix33(Matrix33::RotateX(amt.x) * Matrix33::RotateY(amt.y) * + Matrix33::RotateZ(amt.z)) * + m_mat; + } + + void Reset() override { m_mat = Common::Matrix44::Identity(); } + + void DoState(PointerWrap& p) { p.Do(m_mat); } + +private: + Common::Matrix44 m_mat = Common::Matrix44::Identity(); +}; + +constexpr double HalfPI = MathUtil::PI / 2; + +class FPSController : public CameraController +{ +public: + Common::Matrix44 GetView() override + { + return m_rotate_mat * Common::Matrix44::Translate(m_position); + } + + void MoveVertical(float amt) override + { + Common::Vec3 up{m_rotate_mat.data[4], m_rotate_mat.data[5], m_rotate_mat.data[6]}; + m_position += up * amt; + } + + void MoveHorizontal(float amt) override + { + Common::Vec3 right{m_rotate_mat.data[0], m_rotate_mat.data[1], m_rotate_mat.data[2]}; + m_position += right * amt; + } + + void Zoom(float amt) override + { + Common::Vec3 forward{m_rotate_mat.data[8], m_rotate_mat.data[9], m_rotate_mat.data[10]}; + m_position += forward * amt; + } + + void Rotate(const Common::Vec3& amt) override + { + m_rotation += amt; + + using Common::Matrix33; + using Common::Matrix44; + m_rotate_mat = + Matrix44::FromMatrix33(Matrix33::RotateX(m_rotation.x) * Matrix33::RotateY(m_rotation.y)); + } + + void Reset() override + { + m_position = Common::Vec3{}; + m_rotation = Common::Vec3{}; + m_rotate_mat = Common::Matrix44::Identity(); + } + + void DoState(PointerWrap& p) + { + p.Do(m_rotation); + p.Do(m_rotate_mat); + p.Do(m_position); + } + +private: + Common::Vec3 m_rotation = Common::Vec3{}; + Common::Matrix44 m_rotate_mat = Common::Matrix44::Identity(); + Common::Vec3 m_position = Common::Vec3{}; +}; + +class OrbitalController : public CameraController +{ +public: + Common::Matrix44 GetView() override + { + Common::Matrix44 result = Common::Matrix44::Identity(); + result *= Common::Matrix44::Translate(Common::Vec3{0, 0, -m_distance}); + result *= Common::Matrix44::FromMatrix33(Common::Matrix33::RotateX(m_rotation.x)); + result *= Common::Matrix44::FromMatrix33(Common::Matrix33::RotateY(m_rotation.y)); + + return result; + } + + void MoveVertical(float) override {} + + void MoveHorizontal(float) override {} + + void Zoom(float amt) override + { + m_distance += -1 * amt; + m_distance = std::clamp(m_distance, 0.0f, m_distance); + } + + void Rotate(const Common::Vec3& amt) override { m_rotation += amt; } + + void Reset() override + { + m_rotation = Common::Vec3{}; + m_distance = 0; + } + + void DoState(PointerWrap& p) + { + p.Do(m_rotation); + p.Do(m_distance); + } + +private: + float m_distance = 0; + Common::Vec3 m_rotation = Common::Vec3{}; +}; +} // namespace + +void FreeLookCamera::SetControlType(FreelookControlType type) +{ + if (m_current_type && *m_current_type == type) + { + return; + } + + if (type == FreelookControlType::SixAxis) + { + m_camera_controller = std::make_unique(); + } + else if (type == FreelookControlType::Orbital) + { + m_camera_controller = std::make_unique(); + } + else + { + m_camera_controller = std::make_unique(); + } + + m_current_type = type; +} + +Common::Matrix44 FreeLookCamera::GetView() +{ + return m_camera_controller->GetView(); +} + +void FreeLookCamera::MoveVertical(float amt) +{ + m_camera_controller->MoveVertical(amt); + m_dirty = true; +} + +void FreeLookCamera::MoveHorizontal(float amt) +{ + m_camera_controller->MoveHorizontal(amt); + m_dirty = true; +} + +void FreeLookCamera::Zoom(float amt) +{ + m_camera_controller->Zoom(amt); + m_dirty = true; +} + +void FreeLookCamera::Rotate(const Common::Vec3& amt) +{ + m_camera_controller->Rotate(amt); + m_dirty = true; +} + +void FreeLookCamera::Reset() +{ + m_camera_controller->Reset(); + m_dirty = true; +} + +void FreeLookCamera::DoState(PointerWrap& p) +{ + if (p.mode == PointerWrap::MODE_WRITE || p.mode == PointerWrap::MODE_MEASURE) + { + p.Do(m_current_type); + if (m_camera_controller) + { + m_camera_controller->DoState(p); + } + } + else + { + const auto old_type = m_current_type; + p.Do(m_current_type); + if (old_type == m_current_type) + { + m_camera_controller->DoState(p); + } + else if (p.GetMode() == PointerWrap::MODE_READ) + { + const std::string old_type_name = old_type ? to_string(*old_type) : ""; + const std::string loaded_type_name = m_current_type ? to_string(*m_current_type) : ""; + const std::string message = + fmt::format("State needs same free look camera type. Settings value '{}', loaded value " + "'{}'. Aborting load state", + old_type_name, loaded_type_name); + Core::DisplayMessage(message, 5000); + p.SetMode(PointerWrap::MODE_VERIFY); + } + } +} + +bool FreeLookCamera::IsDirty() const +{ + return m_dirty; +} diff --git a/Source/Core/VideoCommon/FreeLookCamera.h b/Source/Core/VideoCommon/FreeLookCamera.h new file mode 100644 index 0000000000..0fe27d5e58 --- /dev/null +++ b/Source/Core/VideoCommon/FreeLookCamera.h @@ -0,0 +1,66 @@ +// Copyright 2020 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Common/Matrix.h" +#include "VideoCommon/VideoConfig.h" + +class PointerWrap; + +class CameraController +{ +public: + CameraController() = default; + virtual ~CameraController() = default; + + CameraController(const CameraController&) = delete; + CameraController& operator=(const CameraController&) = delete; + + CameraController(CameraController&&) = delete; + CameraController& operator=(CameraController&&) = delete; + + virtual Common::Matrix44 GetView() = 0; + + virtual void MoveVertical(float amt) = 0; + virtual void MoveHorizontal(float amt) = 0; + + virtual void Zoom(float amt) = 0; + + virtual void Rotate(const Common::Vec3& amt) = 0; + + virtual void Reset() = 0; + + virtual void DoState(PointerWrap& p) = 0; +}; + +class FreeLookCamera +{ +public: + void SetControlType(FreelookControlType type); + Common::Matrix44 GetView(); + + void MoveVertical(float amt); + void MoveHorizontal(float amt); + + void Zoom(float amt); + + void Rotate(const Common::Vec3& amt); + + void Reset(); + + void DoState(PointerWrap& p); + + bool IsDirty() const; + +private: + bool m_dirty = false; + std::optional m_current_type; + std::unique_ptr m_camera_controller; +}; + +extern FreeLookCamera g_freelook_camera; diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index dec1ffb34b..75c215a3ab 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -63,6 +63,7 @@ + @@ -141,6 +142,7 @@ + diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 3f18f458a0..41dc891e8a 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -51,6 +51,13 @@ enum class ShaderCompilationMode : int AsynchronousSkipRendering }; +enum class FreelookControlType : int +{ + SixAxis, + FPS, + Orbital +}; + // NEVER inherit from this class. struct VideoConfig final { @@ -107,6 +114,7 @@ struct VideoConfig final std::string sDumpPath; bool bInternalResolutionFrameDumps; bool bFreeLook; + FreelookControlType iFreelookControlType; bool bBorderlessFullscreen; bool bEnableGPUTextureDecoding; int iBitrateKbps;