From 3ea910c6b56110eee49547328396c9edcc0fda7e Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Tue, 17 Dec 2024 20:51:08 +0100 Subject: [PATCH] create `CPlanarProjection.hpp` & `IPlanarProjection.hpp` classes, add 61_UI/cameras.json. Make a few changes to interface classes, load demo data from the json file. TODO for tomorrow: use loaded planar projections vector to interact with the application. --- 61_UI/CMakeLists.txt | 5 +- 61_UI/cameras.json | 105 +++++++ 61_UI/config.json.template | 28 -- 61_UI/include/common.hpp | 1 + 61_UI/main.cpp | 297 +++++++++++++++++++- 61_UI/pipeline.groovy | 50 ---- common/include/camera/CFPSCamera.hpp | 6 +- common/include/camera/CLinearProjection.hpp | 53 ++-- common/include/camera/CPlanarProjection.hpp | 42 +++ common/include/camera/IGimbal.hpp | 27 ++ common/include/camera/IGimbalController.hpp | 36 ++- common/include/camera/ILinearProjection.hpp | 43 +-- common/include/camera/IPlanarProjection.hpp | 116 ++++++++ common/include/camera/IProjection.hpp | 11 +- 14 files changed, 668 insertions(+), 152 deletions(-) create mode 100644 61_UI/cameras.json delete mode 100644 61_UI/config.json.template delete mode 100644 61_UI/pipeline.groovy create mode 100644 common/include/camera/CPlanarProjection.hpp create mode 100644 common/include/camera/IPlanarProjection.hpp diff --git a/61_UI/CMakeLists.txt b/61_UI/CMakeLists.txt index a34e46ce6..1930cb17f 100644 --- a/61_UI/CMakeLists.txt +++ b/61_UI/CMakeLists.txt @@ -15,4 +15,7 @@ if(NBL_BUILD_IMGUI) nbl_create_executable_project("${NBL_EXTRA_SOURCES}" "" "${NBL_INCLUDE_SERACH_DIRECTORIES}" "${NBL_LIBRARIES}" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} geometryCreatorSpirvBRD) -endif() \ No newline at end of file +endif() + +add_dependencies(${EXECUTABLE_NAME} argparse) +target_include_directories(${EXECUTABLE_NAME} PUBLIC $) \ No newline at end of file diff --git a/61_UI/cameras.json b/61_UI/cameras.json new file mode 100644 index 000000000..bd4d7aaa9 --- /dev/null +++ b/61_UI/cameras.json @@ -0,0 +1,105 @@ +{ + "cameras": [ + { + "type": "FPS", + "position": [-2.238, 1.438, -1.558], + "orientation": [0.253, 0.368, -0.105, 0.888] + }, + { + "type": "FPS", + "position": [-2.017, 0.386, 0.684], + "orientation": [0.047, 0.830, -0.072, 0.55] + } + ], + "projections": [ + { + "type": "perspective", + "fov": 60.0, + "zNear": 0.1, + "zFar": 100.0, + "leftHanded": true + }, + { + "type": "orthographic", + "orthoWidth": 10.0, + "zNear": 0.1, + "zFar": 100.0, + "leftHanded": true + } + ], + "viewports": [ + { + "camera": 0, + "planarControllerSet": [ + { + "projection": 0, + "controllers": { + "keyboard": 0, + "mouse": 0 + } + }, + { + "projection": 1, + "controllers": { + "keyboard": 1, + "mouse": 0 + } + } + ] + }, + { + "camera": 1, + "planarControllerSet": [ + { + "projection": 0, + "controllers": { + "keyboard": 0, + "mouse": 0 + } + }, + { + "projection": 1, + "controllers": { + "keyboard": 1, + "mouse": 0 + } + } + ] + } + ], + "controllers": { + "keyboard": [ + { + "mappings": { + "W": "MoveForward", + "S": "MoveBackward", + "A": "MoveLeft", + "D": "MoveRight", + "I": "TiltDown", + "K": "TiltUp", + "J": "PanLeft", + "L": "PanRight" + } + }, + { + "mappings": { + "W": "MoveUp", + "S": "MoveDown", + "A": "MoveLeft", + "D": "MoveRight" + } + } + ], + "mouse": [ + { + "mappings": { + "RELATIVE_POSITIVE_MOVEMENT_X": "PanRight", + "RELATIVE_NEGATIVE_MOVEMENT_X": "PanLeft", + "RELATIVE_POSITIVE_MOVEMENT_Y": "TiltUp", + "RELATIVE_NEGATIVE_MOVEMENT_Y": "TiltDown" + } + } + ] + } + } + \ No newline at end of file diff --git a/61_UI/config.json.template b/61_UI/config.json.template deleted file mode 100644 index f961745c1..000000000 --- a/61_UI/config.json.template +++ /dev/null @@ -1,28 +0,0 @@ -{ - "enableParallelBuild": true, - "threadsPerBuildProcess" : 2, - "isExecuted": false, - "scriptPath": "", - "cmake": { - "configurations": [ "Release", "Debug", "RelWithDebInfo" ], - "buildModes": [], - "requiredOptions": [] - }, - "profiles": [ - { - "backend": "vulkan", - "platform": "windows", - "buildModes": [], - "runConfiguration": "Release", - "gpuArchitectures": [] - } - ], - "dependencies": [], - "data": [ - { - "dependencies": [], - "command": [""], - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/61_UI/include/common.hpp b/61_UI/include/common.hpp index 0c33a5813..4033afc14 100644 --- a/61_UI/include/common.hpp +++ b/61_UI/include/common.hpp @@ -12,6 +12,7 @@ #include "camera/CCubeProjection.hpp" #include "camera/CLinearProjection.hpp" +#include "camera/CPlanarProjection.hpp" // the example's headers #include "nbl/ui/ICursorControl.h" diff --git a/61_UI/main.cpp b/61_UI/main.cpp index acc42106e..57bc61b78 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -2,11 +2,21 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h +#include "nlohmann/json.hpp" +#include "argparse/argparse.hpp" +using json = nlohmann::json; + #include "common.hpp" #include "keysmapping.hpp" #include "camera/CCubeProjection.hpp" #include "glm/glm/ext/matrix_clip_space.hpp" // TODO: TESTING +//! TODO: this could be engine class actually, temporary keepin it in the example though +class CPlanarProjectionCameraController +{ + +}; + constexpr IGPUImage::SSubresourceRange TripleBufferUsedSubresourceRange = { .aspectMask = IGPUImage::EAF_COLOR_BIT, @@ -239,6 +249,22 @@ class UISampleApp final : public examples::SimpleWindowedApplication inline bool onAppInitialized(smart_refctd_ptr&& system) override { + argparse::ArgumentParser program("Virtual camera event system demo"); + + program.add_argument("--file") + .required() + .help("Path to json file with camera inputs"); + + try + { + program.parse_args({ argv.data(), argv.data() + argv.size() }); + } + catch (const std::exception& err) + { + std::cerr << err.what() << std::endl << program; + return false; + } + // Create imput system m_inputSystem = make_smart_refctd_ptr(logger_opt_smart_ptr(smart_refctd_ptr(m_logger))); @@ -485,9 +511,261 @@ class UISampleApp final : public examples::SimpleWindowedApplication oracle.reportBeginFrameRecord(); - /* - TESTS, TODO: remove all once finished work & integrate with the example properly - */ + // json file with camera inputs + // @Yas: TODO: THIS NEEDS BETTER VALIDATION AND LOGS ON FAILURE (+ status logs would be nice)!!! + { + const auto cameraJsonFile = program.get("--file"); + + std::ifstream file(cameraJsonFile.c_str()); + if (!file.is_open()) + { + std::cerr << "Error: Cannot open input \"" << cameraJsonFile.c_str() << "\" json file."; + return false; + } + + json j; + file >> j; + + std::vector> cameras; + for (const auto& jCamera : j["cameras"]) + { + if (jCamera.contains("type")) + { + if (jCamera["type"] == "FPS") + { + if (!jCamera.contains("position")) + { + std::cerr << "Expected \"position\" keyword for camera definition!"; + return false; + } + + if (!jCamera.contains("orientation")) + { + std::cerr << "Expected \"orientation\" keyword for camera definition!"; + return false; + } + + auto position = [&]() + { + auto jret = jCamera["position"].get>(); + return float32_t3(jret[0], jret[1], jret[2]); + }(); + + auto orientation = [&]() + { + auto jret = jCamera["orientation"].get>(); + return glm::quat(jret[0], jret[1], jret[2], jret[3]); + }(); + + cameras.emplace_back() = make_smart_refctd_ptr(position, orientation); + } + else + { + std::cerr << "Unsupported camera type!"; + return false; + } + } + else + { + std::cerr << "Expected \"type\" keyword for camera definition!"; + return false; + } + } + + std::vector projections; + for (const auto& jProjection : j["projections"]) + { + if (jProjection.contains("type")) + { + float zNear, zFar; + bool leftHanded; + + if (!jProjection.contains("zNear")) + { + "Expected \"zNear\" keyword for planar projection definition!"; + return false; + } + + if (!jProjection.contains("zFar")) + { + "Expected \"zFar\" keyword for planar projection definition!"; + return false; + } + + if (!jProjection.contains("leftHanded")) + { + "Expected \"leftHanded\" keyword for planar projection definition!"; + return false; + } + + zNear = jProjection["zNear"].get(); + zFar = jProjection["zFar"].get(); + leftHanded = jProjection["leftHanded"].get(); + + if (jProjection["type"] == "perspective") + { + if (!jProjection.contains("fov")) + { + "Expected \"fov\" keyword for planar perspective projection definition!"; + return false; + } + + float fov = jProjection["fov"].get(); + projections.emplace_back(IPlanarProjection::CProjection::create(leftHanded, zNear, zFar, fov)); + + } + else if (jProjection["type"] == "orthographic") + { + if (!jProjection.contains("orthoWidth")) + { + "Expected \"orthoWidth\" keyword for planar orthographic projection definition!"; + return false; + } + + float orthoWidth = jProjection["orthoWidth"].get(); + projections.emplace_back(IPlanarProjection::CProjection::create(leftHanded, zNear, zFar, orthoWidth)); + } + else + { + std::cerr << "Unsupported projection!"; + return false; + } + } + } + + struct + { + std::vector keyboard; + std::vector mouse; + } controllers; + + if (j.contains("controllers")) + { + const auto& jControllers = j["controllers"]; + + if (jControllers.contains("keyboard")) + { + for (const auto& jKeyboard : jControllers["keyboard"]) + { + if (jKeyboard.contains("mappings")) + { + auto& controller = controllers.keyboard.emplace_back(); + for (const auto& [key, value] : jKeyboard["mappings"].items()) + { + const auto nativeCode = stringToKeyCode(key.c_str()); + + if (nativeCode == EKC_NONE) + { + std::cerr << "Invalid native key \"" << key.c_str() << "\" code mapping for keyboard controller!" << std::endl; + return false; + } + + controller[nativeCode] = CVirtualGimbalEvent::stringToVirtualEvent(value.get()); + } + } + else + { + std::cerr << "Expected \"mappings\" keyword for keyboard controller definition!" << std::endl; + return false; + } + } + } + else + { + std::cerr << "Expected \"keyboard\" keyword in controllers definition!" << std::endl; + return false; + } + + if (jControllers.contains("mouse")) + { + for (const auto& jMouse : jControllers["mouse"]) + { + if (jMouse.contains("mappings")) + { + auto& controller = controllers.mouse.emplace_back(); + for (const auto& [key, value] : jMouse["mappings"].items()) + { + const auto nativeCode = stringToMouseCode(key.c_str()); + + if (nativeCode == EMC_NONE) + { + std::cerr << "Invalid native key \"" << key.c_str() << "\" code mapping for mouse controller!" << std::endl; + return false; + } + + controller[nativeCode] = CVirtualGimbalEvent::stringToVirtualEvent(value.get()); + } + } + else + { + std::cerr << "Expected \"mappings\" keyword for mouse controller definition!" << std::endl; + return false; + } + } + } + else + { + std::cerr << "Expected \"mouse\" keyword in controllers definition!" << std::endl; + return false; + } + } + else + { + std::cerr << "Expected \"controllers\" keyword in JSON!" << std::endl; + return false; + } + + + // viewpoets here + if (j.contains("viewports")) + { + for (const auto& jViewport : j["viewports"]) + { + if (!jViewport.contains("camera")) + { + std::cerr << "Expected \"camera\" keyword in viewport definition!" << std::endl; + return false; + } + + const auto cameraIx = jViewport["camera"].get(); + auto& planars = m_planarProjections.emplace_back() = planar_projection_t::create(smart_refctd_ptr(cameras[cameraIx])); + + if (!jViewport.contains("planarControllerSet")) + { + std::cerr << "Expected \"planarControllerSet\" keyword in viewport definition!" << std::endl; + return false; + } + + for (const auto& jPlanarController : jViewport["planarControllerSet"]) + { + if (!jPlanarController.contains("projection")) + { + std::cerr << "Expected \"projection\" keyword in planarControllerSet!" << std::endl; + return false; + } + + if (!jPlanarController.contains("controllers")) + { + std::cerr << "Expected \"controllers\" keyword in planarControllerSet!" << std::endl; + return false; + } + + auto projectionIx = jPlanarController["projection"].get(); + auto keyboardControllerIx = jPlanarController["controllers"]["keyboard"].get(); + auto mouseControllerIx = jPlanarController["controllers"]["mouse"].get(); + + auto& projection = planars->getPlanarProjections().emplace_back(projections[projectionIx]); + projection.updateKeyboardMapping([&](auto& map) { map = controllers.keyboard[keyboardControllerIx]; }); + projection.updateMouseMapping([&](auto& map) { map = controllers.mouse[mouseControllerIx]; }); + } + } + } + else + { + std::cerr << "Expected \"viewports\" keyword in JSON!" << std::endl; + return false; + } + } const auto iAspectRatio = float(m_window->getWidth()) / float(m_window->getHeight()); const auto iInvAspectRatio = float(m_window->getHeight()) / float(m_window->getWidth()); @@ -880,7 +1158,11 @@ class UISampleApp final : public examples::SimpleWindowedApplication auto projectionMatrices = projections->getLinearProjections(); { - auto mutableRange = smart_refctd_ptr_static_cast(projections)->getLinearProjections(); + + /* + TODO: update it + + auto mutableRange = smart_refctd_ptr_static_cast(projections)->getLinearProjections(); for (uint32_t i = 0u; i < mutableRange.size(); ++i) { auto projection = mutableRange.begin() + i; @@ -902,6 +1184,9 @@ class UISampleApp final : public examples::SimpleWindowedApplication projection->setProjectionMatrix(buildProjectionMatrixOrthoRH(viewWidth[i], viewHeight, zNear[i], zFar[i])); } } + */ + + } /* @@ -1662,6 +1947,10 @@ class UISampleApp final : public examples::SimpleWindowedApplication std::string lastManipulatedModelIdentifier = "Geometry Creator Object"; bool firstFrame = true; + + using planar_projections_range_t = std::vector; + using planar_projection_t = CPlanarProjection; + std::vector> m_planarProjections; }; NBL_MAIN_FUNC(UISampleApp) \ No newline at end of file diff --git a/61_UI/pipeline.groovy b/61_UI/pipeline.groovy deleted file mode 100644 index 7b7c9702a..000000000 --- a/61_UI/pipeline.groovy +++ /dev/null @@ -1,50 +0,0 @@ -import org.DevshGraphicsProgramming.Agent -import org.DevshGraphicsProgramming.BuilderInfo -import org.DevshGraphicsProgramming.IBuilder - -class CUIBuilder extends IBuilder -{ - public CUIBuilder(Agent _agent, _info) - { - super(_agent, _info) - } - - @Override - public boolean prepare(Map axisMapping) - { - return true - } - - @Override - public boolean build(Map axisMapping) - { - IBuilder.CONFIGURATION config = axisMapping.get("CONFIGURATION") - IBuilder.BUILD_TYPE buildType = axisMapping.get("BUILD_TYPE") - - def nameOfBuildDirectory = getNameOfBuildDirectory(buildType) - def nameOfConfig = getNameOfConfig(config) - - agent.execute("cmake --build ${info.rootProjectPath}/${nameOfBuildDirectory}/${info.targetProjectPathRelativeToRoot} --target ${info.targetBaseName} --config ${nameOfConfig} -j12 -v") - - return true - } - - @Override - public boolean test(Map axisMapping) - { - return true - } - - @Override - public boolean install(Map axisMapping) - { - return true - } -} - -def create(Agent _agent, _info) -{ - return new CUIBuilder(_agent, _info) -} - -return this \ No newline at end of file diff --git a/common/include/camera/CFPSCamera.hpp b/common/include/camera/CFPSCamera.hpp index 8b5868566..a6d169f09 100644 --- a/common/include/camera/CFPSCamera.hpp +++ b/common/include/camera/CFPSCamera.hpp @@ -20,9 +20,9 @@ class CFPSCamera final : public ICamera : base_t(), m_gimbal({ .position = position, .orientation = orientation }) {} ~CFPSCamera() = default; - const base_t::keyboard_to_virtual_events_t& getKeyboardMappingPreset() const override { return m_keyboard_to_virtual_events_preset; } - const base_t::mouse_to_virtual_events_t& getMouseMappingPreset() const override { return m_mouse_to_virtual_events_preset; } - const base_t::imguizmo_to_virtual_events_t& getImguizmoMappingPreset() const override { return m_imguizmo_to_virtual_events_preset; } + const base_t::keyboard_to_virtual_events_t getKeyboardMappingPreset() const override { return m_keyboard_to_virtual_events_preset; } + const base_t::mouse_to_virtual_events_t getMouseMappingPreset() const override { return m_mouse_to_virtual_events_preset; } + const base_t::imguizmo_to_virtual_events_t getImguizmoMappingPreset() const override { return m_imguizmo_to_virtual_events_preset; } const typename base_t::CGimbal& getGimbal() override { diff --git a/common/include/camera/CLinearProjection.hpp b/common/include/camera/CLinearProjection.hpp index 77725125b..791e9cb1b 100644 --- a/common/include/camera/CLinearProjection.hpp +++ b/common/include/camera/CLinearProjection.hpp @@ -6,40 +6,39 @@ namespace nbl::hlsl { + template ProjectionsRange> + class CLinearProjection : public ILinearProjection + { + public: + using ILinearProjection::ILinearProjection; -template ProjectionsRange> -class CLinearProjection : public ILinearProjection -{ -public: - using ILinearProjection::ILinearProjection; - - CLinearProjection() = default; + CLinearProjection() = default; - inline static core::smart_refctd_ptr create(core::smart_refctd_ptr&& camera) - { - if (!camera) - return nullptr; + inline static core::smart_refctd_ptr create(core::smart_refctd_ptr&& camera) + { + if (!camera) + return nullptr; - return core::smart_refctd_ptr(new CLinearProjection(core::smart_refctd_ptr(camera)), core::dont_grab); - } + return core::smart_refctd_ptr(new CLinearProjection(core::smart_refctd_ptr(camera)), core::dont_grab); + } - virtual std::span getLinearProjections() const override - { - return std::span(m_projections.data(), m_projections.size()); - } + virtual std::span getLinearProjections() const override + { + return std::span(m_projections.data(), m_projections.size()); + } - inline std::span getLinearProjections() - { - return std::span(m_projections.data(), m_projections.size()); - } + inline std::span getLinearProjections() + { + return std::span(m_projections.data(), m_projections.size()); + } -private: - CLinearProjection(core::smart_refctd_ptr&& camera) - : ILinearProjection(core::smart_refctd_ptr(camera)) {} - virtual ~CLinearProjection() = default; + private: + CLinearProjection(core::smart_refctd_ptr&& camera) + : ILinearProjection(core::smart_refctd_ptr(camera)) {} + virtual ~CLinearProjection() = default; - ProjectionsRange m_projections; -}; + ProjectionsRange m_projections; + }; } // nbl::hlsl namespace diff --git a/common/include/camera/CPlanarProjection.hpp b/common/include/camera/CPlanarProjection.hpp new file mode 100644 index 000000000..f726ea959 --- /dev/null +++ b/common/include/camera/CPlanarProjection.hpp @@ -0,0 +1,42 @@ +#ifndef _NBL_C_PLANAR_PROJECTION_HPP_ +#define _NBL_C_PLANAR_PROJECTION_HPP_ + +#include "IPlanarProjection.hpp" +#include "IRange.hpp" + +namespace nbl::hlsl +{ + template ProjectionsRange> + class CPlanarProjection : public IPlanarProjection + { + public: + virtual ~CPlanarProjection() = default; + + inline static core::smart_refctd_ptr create(core::smart_refctd_ptr&& camera) + { + if (!camera) + return nullptr; + + return core::smart_refctd_ptr(new CPlanarProjection(core::smart_refctd_ptr(camera)), core::dont_grab); + } + + virtual std::span getLinearProjections() const override + { + return { reinterpret_cast(m_projections.data()), m_projections.size() }; + } + + inline ProjectionsRange& getPlanarProjections() + { + return m_projections; + } + + private: + CPlanarProjection(core::smart_refctd_ptr&& camera) + : IPlanarProjection(core::smart_refctd_ptr(camera)) {} + + ProjectionsRange m_projections; + }; + +} // nbl::hlsl namespace + +#endif // _NBL_C_PLANAR_PROJECTION_HPP_ \ No newline at end of file diff --git a/common/include/camera/IGimbal.hpp b/common/include/camera/IGimbal.hpp index 3fe98d3eb..1a94affc5 100644 --- a/common/include/camera/IGimbal.hpp +++ b/common/include/camera/IGimbal.hpp @@ -79,6 +79,33 @@ namespace nbl::hlsl } } + static constexpr VirtualEventType stringToVirtualEvent(std::string_view event) + { + if (event == "MoveForward") return MoveForward; + if (event == "MoveBackward") return MoveBackward; + if (event == "MoveLeft") return MoveLeft; + if (event == "MoveRight") return MoveRight; + if (event == "MoveUp") return MoveUp; + if (event == "MoveDown") return MoveDown; + if (event == "TiltUp") return TiltUp; + if (event == "TiltDown") return TiltDown; + if (event == "PanLeft") return PanLeft; + if (event == "PanRight") return PanRight; + if (event == "RollLeft") return RollLeft; + if (event == "RollRight") return RollRight; + if (event == "ScaleXInc") return ScaleXInc; + if (event == "ScaleXDec") return ScaleXDec; + if (event == "ScaleYInc") return ScaleYInc; + if (event == "ScaleYDec") return ScaleYDec; + if (event == "ScaleZInc") return ScaleZInc; + if (event == "ScaleZDec") return ScaleZDec; + if (event == "Translate") return Translate; + if (event == "Rotate") return Rotate; + if (event == "Scale") return Scale; + if (event == "None") return None; + return None; + } + static inline constexpr auto VirtualEventsTypeTable = []() { std::array output; diff --git a/common/include/camera/IGimbalController.hpp b/common/include/camera/IGimbalController.hpp index b6e2ec00a..c7a0c507a 100644 --- a/common/include/camera/IGimbalController.hpp +++ b/common/include/camera/IGimbalController.hpp @@ -77,13 +77,26 @@ struct IGimbalManipulateEncoder using imguizmo_to_virtual_events_t = std::unordered_map; //! default preset with encode_keyboard_code_t to gimbal_virtual_event_t map - virtual const keyboard_to_virtual_events_t& getKeyboardMappingPreset() const = 0u; + virtual const keyboard_to_virtual_events_t getKeyboardMappingPreset() const { return {}; } //! default preset with encode_keyboard_code_t to gimbal_virtual_event_t map - virtual const mouse_to_virtual_events_t& getMouseMappingPreset() const = 0u; + virtual const mouse_to_virtual_events_t getMouseMappingPreset() const { return {}; } //! default preset with encode_keyboard_code_t to gimbal_virtual_event_t map - virtual const imguizmo_to_virtual_events_t& getImguizmoMappingPreset() const = 0u; + virtual const imguizmo_to_virtual_events_t getImguizmoMappingPreset() const { return {}; } + + virtual const keyboard_to_virtual_events_t& getKeyboardVirtualEventMap() const = 0; + virtual const mouse_to_virtual_events_t& getMouseVirtualEventMap() const = 0; + virtual const imguizmo_to_virtual_events_t& getImguizmoVirtualEventMap() const = 0; + + // Binds mouse key codes to virtual events, the mapKeys lambda will be executed with controller keyboard_to_virtual_events_t table + virtual void updateKeyboardMapping(const std::function& mapKeys) = 0; + + // Binds mouse key codes to virtual events, the mapKeys lambda will be executed with controller mouse_to_virtual_events_t table + virtual void updateMouseMapping(const std::function& mapKeys) = 0; + + // Binds imguizmo key codes to virtual events, the mapKeys lambda will be executed with controller imguizmo_to_virtual_events_t table + virtual void updateImguizmoMapping(const std::function& mapKeys) = 0; }; class IGimbalController : public IGimbalManipulateEncoder @@ -115,14 +128,9 @@ class IGimbalController : public IGimbalManipulateEncoder m_lastVirtualUpTimeStamp = m_nextPresentationTimeStamp; } - // Binds mouse key codes to virtual events, the mapKeys lambda will be executed with controller keyboard_to_virtual_events_t table - void updateKeyboardMapping(const std::function& mapKeys) { mapKeys(m_keyboardVirtualEventMap); } - - // Binds mouse key codes to virtual events, the mapKeys lambda will be executed with controller mouse_to_virtual_events_t table - void updateMouseMapping(const std::function& mapKeys) { mapKeys(m_mouseVirtualEventMap); } - - // Binds imguizmo key codes to virtual events, the mapKeys lambda will be executed with controller imguizmo_to_virtual_events_t table - void updateImguizmoMapping(const std::function& mapKeys) { mapKeys(m_imguizmoVirtualEventMap); } + virtual void updateKeyboardMapping(const std::function& mapKeys) override { mapKeys(m_keyboardVirtualEventMap); } + virtual void updateMouseMapping(const std::function& mapKeys) override { mapKeys(m_mouseVirtualEventMap); } + virtual void updateImguizmoMapping(const std::function& mapKeys) override { mapKeys(m_imguizmoVirtualEventMap); } struct SUpdateParameters { @@ -175,9 +183,9 @@ class IGimbalController : public IGimbalManipulateEncoder count = vKeyboardEventsCount + vMouseEventsCount + vImguizmoEventsCount; } - inline const keyboard_to_virtual_events_t& getKeyboardVirtualEventMap() { return m_keyboardVirtualEventMap; } - inline const mouse_to_virtual_events_t& getMouseVirtualEventMap() { return m_mouseVirtualEventMap; } - inline const imguizmo_to_virtual_events_t& getImguizmoVirtualEventMap() { return m_imguizmoVirtualEventMap; } + virtual const keyboard_to_virtual_events_t& getKeyboardVirtualEventMap() const override { return m_keyboardVirtualEventMap; } + virtual const mouse_to_virtual_events_t& getMouseVirtualEventMap() const override { return m_mouseVirtualEventMap; } + virtual const imguizmo_to_virtual_events_t& getImguizmoVirtualEventMap() const override { return m_imguizmoVirtualEventMap; } private: /** diff --git a/common/include/camera/ILinearProjection.hpp b/common/include/camera/ILinearProjection.hpp index 6222a58b4..fc0115610 100644 --- a/common/include/camera/ILinearProjection.hpp +++ b/common/include/camera/ILinearProjection.hpp @@ -38,27 +38,6 @@ class ILinearProjection : virtual public core::IReferenceCounted CProjection() : CProjection(projection_matrix_t(1)) {} CProjection(const projection_matrix_t& matrix) { setProjectionMatrix(matrix); } - inline void setProjectionMatrix(const projection_matrix_t& matrix) - { - m_projectionMatrix = matrix; - const auto det = hlsl::determinant(m_projectionMatrix); - - // we will allow you to lose a dimension since such a projection itself *may* - // be valid, however then you cannot un-project because the inverse doesn't exist! - m_isProjectionSingular = not det; - - if (m_isProjectionSingular) - { - m_isProjectionLeftHanded = std::nullopt; - m_invProjectionMatrix = std::nullopt; - } - else - { - m_isProjectionLeftHanded = det < 0.0; - m_invProjectionMatrix = inverse(m_projectionMatrix); - } - } - //! Returns P (Projection matrix) inline const projection_matrix_t& getProjectionMatrix() const { return m_projectionMatrix; } @@ -84,6 +63,28 @@ class ILinearProjection : virtual public core::IReferenceCounted return true; } + protected: + inline void setProjectionMatrix(const projection_matrix_t& matrix) + { + m_projectionMatrix = matrix; + const auto det = hlsl::determinant(m_projectionMatrix); + + // we will allow you to lose a dimension since such a projection itself *may* + // be valid, however then you cannot un-project because the inverse doesn't exist! + m_isProjectionSingular = not det; + + if (m_isProjectionSingular) + { + m_isProjectionLeftHanded = std::nullopt; + m_invProjectionMatrix = std::nullopt; + } + else + { + m_isProjectionLeftHanded = det < 0.0; + m_invProjectionMatrix = inverse(m_projectionMatrix); + } + } + private: projection_matrix_t m_projectionMatrix; inv_projection_matrix_t m_invProjectionMatrix; diff --git a/common/include/camera/IPlanarProjection.hpp b/common/include/camera/IPlanarProjection.hpp new file mode 100644 index 000000000..4ca9a0475 --- /dev/null +++ b/common/include/camera/IPlanarProjection.hpp @@ -0,0 +1,116 @@ +#ifndef _NBL_I_PLANAR_PROJECTION_HPP_ +#define _NBL_I_PLANAR_PROJECTION_HPP_ + +#include "ILinearProjection.hpp" + +namespace nbl::hlsl +{ + +class IPlanarProjection : public ILinearProjection +{ +public: + struct CProjection : public ILinearProjection::CProjection, public IGimbalManipulateEncoder + { + using base_t = ILinearProjection::CProjection; + + enum ProjectionType : uint8_t + { + Perspective, + Orthographic, + + Count + }; + + template + static CProjection create(Args&&... args) + requires (T != Count) + { + CProjection output; + + if constexpr (T == Perspective) output.setPerspective(std::forward(args)...); + else if (T == Orthographic) output.setOrthographic(std::forward(args)...); + + return output; + } + + CProjection(const CProjection& other) = default; + CProjection(CProjection&& other) noexcept = default; + + struct ProjectionParameters + { + ProjectionType m_type; + + union PlanarParameters + { + struct + { + float fov; + } perspective; + + struct + { + float orthoWidth; + } orthographic; + + PlanarParameters() {} + ~PlanarParameters() {} + } m_planar; + + float m_zNear; + float m_zFar; + }; + + inline void setPerspective(bool leftHanded = true, float zNear = 0.1f, float zFar = 100.f, float fov = 60.f, float aspectRatio = 16.f / 9.f) + { + m_parameters.m_type = Perspective; + m_parameters.m_planar.perspective.fov = fov; + m_parameters.m_zNear = zNear; + m_parameters.m_zFar = zFar; + + if (leftHanded) + base_t::setProjectionMatrix(buildProjectionMatrixPerspectiveFovLH(glm::radians(fov), aspectRatio, zNear, zFar)); + else + base_t::setProjectionMatrix(buildProjectionMatrixPerspectiveFovRH(glm::radians(fov), aspectRatio, zNear, zFar)); + } + + inline void setOrthographic(bool leftHanded = true, float zNear = 0.1f, float zFar = 100.f, float orthoWidth = 10.f, float aspectRatio = 16.f / 9.f) + { + m_parameters.m_type = Orthographic; + m_parameters.m_planar.orthographic.orthoWidth = orthoWidth; + m_parameters.m_zNear = zNear; + m_parameters.m_zFar = zFar; + + const auto viewHeight = orthoWidth * core::reciprocal(aspectRatio); + + if (leftHanded) + base_t::setProjectionMatrix(buildProjectionMatrixOrthoLH(orthoWidth, viewHeight, zNear, zFar)); + else + base_t::setProjectionMatrix(buildProjectionMatrixOrthoRH(orthoWidth, viewHeight, zNear, zFar)); + } + + virtual void updateKeyboardMapping(const std::function& mapKeys) override { mapKeys(m_keyboardVirtualEventMap); } + virtual void updateMouseMapping(const std::function& mapKeys) override { mapKeys(m_mouseVirtualEventMap); } + virtual void updateImguizmoMapping(const std::function& mapKeys) override { mapKeys(m_imguizmoVirtualEventMap); } + + virtual const keyboard_to_virtual_events_t& getKeyboardVirtualEventMap() const override { return m_keyboardVirtualEventMap; } + virtual const mouse_to_virtual_events_t& getMouseVirtualEventMap() const override { return m_mouseVirtualEventMap; } + virtual const imguizmo_to_virtual_events_t& getImguizmoVirtualEventMap() const override { return m_imguizmoVirtualEventMap; } + inline const ProjectionParameters& getParameters() const { return m_parameters; } + private: + CProjection() = default; + ProjectionParameters m_parameters; + + keyboard_to_virtual_events_t m_keyboardVirtualEventMap; + mouse_to_virtual_events_t m_mouseVirtualEventMap; + imguizmo_to_virtual_events_t m_imguizmoVirtualEventMap; + }; + +protected: + IPlanarProjection(core::smart_refctd_ptr&& camera) + : ILinearProjection(core::smart_refctd_ptr(camera)) {} + virtual ~IPlanarProjection() = default; +}; + +} // nbl::hlsl namespace + +#endif // _NBL_I_PLANAR_PROJECTION_HPP_ \ No newline at end of file diff --git a/common/include/camera/IProjection.hpp b/common/include/camera/IProjection.hpp index 357adefe9..cb6facdcc 100644 --- a/common/include/camera/IProjection.hpp +++ b/common/include/camera/IProjection.hpp @@ -15,13 +15,16 @@ class IProjection enum class ProjectionType { - //! Perspective, Orthographic, Oblique, Axonometric, Shear projections or any custom linear transformation + //! Any raw linear transformation, for example it may represent Perspective, Orthographic, Oblique, Axonometric, Shear projections Linear, - //! Represents pre-transform *concatenated* with linear view-port transform, projects onto a quad - Perspective, + //! Specialized linear projection for planar projections with parameters + Planar, - //! Represents a Perspective projection onto cube consisting of 6 quad cube faces + //! Extension of planar projection represented by pre-transform & planar transform combined projecting onto R3 cave quad + CaveQuad, + + //! Specialized CaveQuad projection, represents planar projections onto cube with 6 quad cube faces Cube, Spherical,