From 48ef38f9df109428f13f86e350671b64379704ff Mon Sep 17 00:00:00 2001 From: tomas7770 <77364520+tomas7770@users.noreply.github.com> Date: Thu, 1 Feb 2024 23:17:26 +0000 Subject: [PATCH] feat(gizmos): integrate screen picker with gizmos --- CHANGELOG.md | 1 + engine/include/cubos/engine/gizmos/gizmos.hpp | 4 +- engine/include/cubos/engine/gizmos/plugin.hpp | 3 + engine/src/cubos/engine/gizmos/gizmos.cpp | 8 ++ engine/src/cubos/engine/gizmos/plugin.cpp | 89 ++++++++----------- engine/src/cubos/engine/gizmos/renderer.cpp | 36 +------- engine/src/cubos/engine/gizmos/renderer.hpp | 12 +-- .../engine/screen_picker/screen_picker.cpp | 5 ++ 8 files changed, 58 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b10f38092..be3a23689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Switch to new system syntax (#896). - Bump `glad` from `d08b1aa` to `73eaae0`. - Bump `json` from `v3.11.2` to `v3.11.3`. +- Change Gizmo plugin to use the Screen picker plugin (#870). ### Deprecated diff --git a/engine/include/cubos/engine/gizmos/gizmos.hpp b/engine/include/cubos/engine/gizmos/gizmos.hpp index 26886a420..79d838127 100644 --- a/engine/include/cubos/engine/gizmos/gizmos.hpp +++ b/engine/include/cubos/engine/gizmos/gizmos.hpp @@ -168,13 +168,15 @@ namespace cubos::engine std::vector> viewGizmos; ///< Queued gizmos to be drawn in viewport space. std::vector> screenGizmos; ///< Queued gizmos to be drawn in screen space. + bool mLocking; ///< Whether the mouse has just now been pressed. + private: /// @brief Adds a gizmo into the corresponding vector. /// @param gizmo Gizmo to be added. /// @param space Space in which the gizmo will be drawn. void push(const std::shared_ptr& gizmo, const Space& space); - std::hash mHasher; ///< Hash function to convert string ids into integers. + static uint32_t mHasher(const std::string& id); ///< Hash function to convert string ids into integers. glm::vec3 mColor; ///< Currently set color. diff --git a/engine/include/cubos/engine/gizmos/plugin.hpp b/engine/include/cubos/engine/gizmos/plugin.hpp index b048f24a0..c1801124d 100644 --- a/engine/include/cubos/engine/gizmos/plugin.hpp +++ b/engine/include/cubos/engine/gizmos/plugin.hpp @@ -27,8 +27,11 @@ namespace cubos::engine /// before `cubos.gizmos.draw`. /// - `cubos.gizmos.draw` - queued gizmos are rendered to the window, after `cubos.renderer.draw` and /// before `cubos.window.render`. + /// - `cubos.gizmos.pick` - the ScreenPicker resource is accessed to detect gizmos at mouse coordinates, after + /// `cubos.gizmos.draw` /// /// ## Dependencies + /// - @ref screen-picker-plugin /// - @ref window-plugin /// @brief Plugin entry function. diff --git a/engine/src/cubos/engine/gizmos/gizmos.cpp b/engine/src/cubos/engine/gizmos/gizmos.cpp index 1061c3a48..c6c6e5213 100644 --- a/engine/src/cubos/engine/gizmos/gizmos.cpp +++ b/engine/src/cubos/engine/gizmos/gizmos.cpp @@ -83,6 +83,14 @@ void Gizmos::push(const std::shared_ptr& gizmo, const Space& space) } } +uint32_t Gizmos::mHasher(const std::string& id) +{ + uint32_t hash = static_cast(std::hash{}(id)); + // Set 32nd bit to distinguish from entities + hash |= static_cast(1 << 31); + return hash; +} + void Gizmos::drawLine(const std::string& id, glm::vec3 from, glm::vec3 to, float lifespan, Space space) { push(std::make_shared((uint32_t)mHasher(id), from, to, mColor, lifespan), space); diff --git a/engine/src/cubos/engine/gizmos/plugin.cpp b/engine/src/cubos/engine/gizmos/plugin.cpp index bdf7b3272..960864298 100644 --- a/engine/src/cubos/engine/gizmos/plugin.cpp +++ b/engine/src/cubos/engine/gizmos/plugin.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -23,7 +24,7 @@ using namespace cubos::engine; static void iterateGizmos(std::vector>& gizmosVector, const std::vector>& cameras, - GizmosRenderer& gizmosRenderer, const DeltaTime& deltaTime) + GizmosRenderer& gizmosRenderer, ScreenPicker& screenPicker, const DeltaTime& deltaTime) { std::vector toRemove; @@ -42,7 +43,7 @@ static void iterateGizmos(std::vector>& gizmosVec // Id gizmosRenderer.renderDevice->setShaderPipeline(gizmosRenderer.idPipeline); - gizmosRenderer.renderDevice->setFramebuffer(gizmosRenderer.idFramebuffer); + gizmosRenderer.renderDevice->setFramebuffer(screenPicker.framebuffer()); gizmosRenderer.idPipeline->getBindingPoint("gizmo")->setConstant(gizmo.id); @@ -186,6 +187,7 @@ static std::vector> getScreenInfo(c void cubos::engine::gizmosPlugin(Cubos& cubos) { + cubos.addPlugin(cubos::engine::screenPickerPlugin); cubos.addPlugin(cubos::engine::windowPlugin); cubos.addResource(); @@ -194,16 +196,15 @@ void cubos::engine::gizmosPlugin(Cubos& cubos) cubos.startupSystem("initialize GizmosRenderer") .tagged("cubos.gizmos.init") .after("cubos.window.init") - .call([](GizmosRenderer& gizmosRenderer, const Window& window) { - gizmosRenderer.init(&window->renderDevice(), window->framebufferSize()); - }); + .call( + [](GizmosRenderer& gizmosRenderer, const Window& window) { gizmosRenderer.init(&window->renderDevice()); }); cubos.system("process gizmos input") .tagged("cubos.gizmos.input") .after("cubos.window.poll") .before("cubos.gizmos.draw") .call([](GizmosRenderer& gizmosRenderer, Gizmos& gizmos, EventReader windowEvent) { - bool locking = false; + gizmos.mLocking = false; for (const auto& event : windowEvent) { if (std::holds_alternative(event)) @@ -221,74 +222,56 @@ void cubos::engine::gizmosPlugin(Cubos& cubos) } else { - locking = true; + gizmos.mLocking = true; } } } - else if (std::holds_alternative(event)) - { - gizmosRenderer.resizeTexture(std::get(event).size); - } - } - - auto* texBuffer = new uint16_t[(std::size_t)gizmosRenderer.textureSize.x * - (std::size_t)gizmosRenderer.textureSize.y * 2U]; - - gizmosRenderer.idTexture->read(texBuffer); - - int mouseX = gizmosRenderer.lastMousePosition.x; - int mouseY = gizmosRenderer.textureSize.y - gizmosRenderer.lastMousePosition.y - 1; - - if (mouseX >= gizmosRenderer.textureSize.x || mouseX < 0) - { - delete[] texBuffer; - return; - } - if (mouseY >= gizmosRenderer.textureSize.y || mouseY < 0) - { - delete[] texBuffer; - return; } - - uint16_t r = texBuffer[(ptrdiff_t)(mouseY * gizmosRenderer.textureSize.x + mouseX) * 2U]; - uint16_t g = texBuffer[(ptrdiff_t)(mouseY * gizmosRenderer.textureSize.x + mouseX) * 2U + 1U]; - - uint32_t id = (static_cast(r) << 16U) | g; - - gizmos.handleInput(id, gizmosRenderer.mousePressed); - - if (locking) - { - gizmos.setLocked(id); - } - - delete[] texBuffer; }); cubos.system("draw gizmos") .tagged("cubos.gizmos.draw") .after("cubos.renderer.draw") .before("cubos.window.render") - .call([](Gizmos& gizmos, GizmosRenderer& gizmosRenderer, const ActiveCameras& activeCameras, - const Window& window, const DeltaTime& deltaTime, Query query) { + .call([](Gizmos& gizmos, GizmosRenderer& gizmosRenderer, ScreenPicker& screenPicker, + const ActiveCameras& activeCameras, const Window& window, const DeltaTime& deltaTime, + Query query) { auto screenSize = window->framebufferSize(); gizmosRenderer.renderDevice->setShaderPipeline(gizmosRenderer.drawPipeline); gizmosRenderer.renderDevice->setDepthStencilState(gizmosRenderer.doDepthCheckStencilState); gizmosRenderer.renderDevice->clearDepth(1.0F); - gizmosRenderer.renderDevice->setFramebuffer(gizmosRenderer.idFramebuffer); - gizmosRenderer.renderDevice->clearColor(0, 0, 0, 0); - gizmosRenderer.renderDevice->clearDepth(1.0F); - auto worldInfo = getWorldInfo(query, activeCameras, screenSize); - iterateGizmos(gizmos.worldGizmos, worldInfo, gizmosRenderer, deltaTime); + iterateGizmos(gizmos.worldGizmos, worldInfo, gizmosRenderer, screenPicker, deltaTime); gizmosRenderer.renderDevice->setDepthStencilState(gizmosRenderer.noDepthCheckStencilState); auto viewInfo = getViewInfo(activeCameras, screenSize); - iterateGizmos(gizmos.viewGizmos, viewInfo, gizmosRenderer, deltaTime); + iterateGizmos(gizmos.viewGizmos, viewInfo, gizmosRenderer, screenPicker, deltaTime); auto screenInfo = getScreenInfo(screenSize); - iterateGizmos(gizmos.screenGizmos, screenInfo, gizmosRenderer, deltaTime); + iterateGizmos(gizmos.screenGizmos, screenInfo, gizmosRenderer, screenPicker, deltaTime); + }); + + cubos.system("do gizmos screen picking") + .tagged("cubos.gizmos.pick") + .after("cubos.gizmos.draw") + .call([](GizmosRenderer& gizmosRenderer, Gizmos& gizmos, const ScreenPicker& screenPicker) { + int mouseX = gizmosRenderer.lastMousePosition.x; + int mouseY = gizmosRenderer.lastMousePosition.y; + + uint32_t id = screenPicker.at(mouseX, mouseY); + if (id < static_cast(1 << 31)) + { + // Not a gizmo, treat it like empty space + id = UINT32_MAX; + } + + gizmos.handleInput(id, gizmosRenderer.mousePressed); + + if (gizmos.mLocking) + { + gizmos.setLocked(id); + } }); } diff --git a/engine/src/cubos/engine/gizmos/renderer.cpp b/engine/src/cubos/engine/gizmos/renderer.cpp index 1d3192b89..fded053a0 100644 --- a/engine/src/cubos/engine/gizmos/renderer.cpp +++ b/engine/src/cubos/engine/gizmos/renderer.cpp @@ -5,33 +5,6 @@ using cubos::engine::GizmosRenderer; using namespace cubos::core::gl; -void GizmosRenderer::initIdTexture(glm::ivec2 size) -{ - Texture2DDesc texDesc; - texDesc.width = (std::size_t)size.x; - texDesc.height = (std::size_t)size.y; - texDesc.usage = Usage::Dynamic; - texDesc.format = TextureFormat::RG16UInt; - - idTexture = renderDevice->createTexture2D(texDesc); - - texDesc.format = TextureFormat::Depth16; - mDepthTexture = renderDevice->createTexture2D(texDesc); - - FramebufferDesc frameDesc; - frameDesc.targetCount = 1; - - FramebufferDesc::FramebufferTarget target; - target.setTexture2DTarget(idTexture); - - frameDesc.targets[0] = target; - frameDesc.depthStencil.setTexture2DTarget(mDepthTexture); - - idFramebuffer = renderDevice->createFramebuffer(frameDesc); - - textureSize = size; -} - void GizmosRenderer::initDrawPipeline() { auto vs = renderDevice->createShaderStage(Stage::Vertex, R"( @@ -101,7 +74,7 @@ void GizmosRenderer::initIdPipeline() idPipeline = renderDevice->createShaderPipeline(vs, ps); } -void GizmosRenderer::init(RenderDevice* currentRenderDevice, glm::ivec2 size) +void GizmosRenderer::init(RenderDevice* currentRenderDevice) { renderDevice = currentRenderDevice; @@ -113,8 +86,6 @@ void GizmosRenderer::init(RenderDevice* currentRenderDevice, glm::ivec2 size) dss.depth.writeEnabled = false; noDepthCheckStencilState = renderDevice->createDepthStencilState(dss); - initIdTexture(size); - initDrawPipeline(); initIdPipeline(); @@ -142,11 +113,6 @@ void GizmosRenderer::initLinePrimitive() linePrimitive.va = renderDevice->createVertexArray(linePrimitive.vaDesc); } -void GizmosRenderer::resizeTexture(glm::ivec2 size) -{ - initIdTexture(size); -} - void GizmosRenderer::initBoxPrimitive() { boxPrimitive.vaDesc.elementCount = 1; diff --git a/engine/src/cubos/engine/gizmos/renderer.hpp b/engine/src/cubos/engine/gizmos/renderer.hpp index 139559b0f..0996985d8 100644 --- a/engine/src/cubos/engine/gizmos/renderer.hpp +++ b/engine/src/cubos/engine/gizmos/renderer.hpp @@ -31,20 +31,12 @@ namespace cubos::engine Primitive cutConePrimitive; ///< GL cut cone information. Primitive ringPrimitive; ///< GL ring information. - glm::ivec2 textureSize; ///< Size of the id texture. - cubos::core::gl::Texture2D idTexture; ///< Texture holding the ids of the gizmo that was drawn to each pixel. - cubos::core::gl::Framebuffer idFramebuffer; ///< Buffer holding the id texture. - cubos::core::gl::DepthStencilState doDepthCheckStencilState; ///< Stencil State that performs depth checks. cubos::core::gl::DepthStencilState noDepthCheckStencilState; ///< Stencil State that ignores depth checks. /// @brief Sets up the render device to be used. /// @param renderDevice the current Render device being used. - void init(cubos::core::gl::RenderDevice* currentRenderDevice, glm::ivec2 size); - - /// @brief Resizes the id texture. - /// @param size New size of the texture. - void resizeTexture(glm::ivec2 size); + void init(cubos::core::gl::RenderDevice* currentRenderDevice); glm::ivec2 lastMousePosition; ///< Cursor position. bool mousePressed; ///< Whether or not the mouse left button is pressed. @@ -52,8 +44,6 @@ namespace cubos::engine private: cubos::core::gl::Texture2D mDepthTexture; - void initIdTexture(glm::ivec2 size); - void initIdPipeline(); void initDrawPipeline(); diff --git a/engine/src/cubos/engine/screen_picker/screen_picker.cpp b/engine/src/cubos/engine/screen_picker/screen_picker.cpp index 4d58b4c11..9cc063f86 100644 --- a/engine/src/cubos/engine/screen_picker/screen_picker.cpp +++ b/engine/src/cubos/engine/screen_picker/screen_picker.cpp @@ -38,6 +38,11 @@ Framebuffer ScreenPicker::framebuffer() uint32_t ScreenPicker::at(int x, int y) const { y = mTextureSize.y - y - 1; + if (x >= mTextureSize.x || x < 0 || y >= mTextureSize.y || y < 0) + { + return UINT32_MAX; + } + auto* texBuffer = new uint16_t[(std::size_t)mTextureSize.x * (std::size_t)mTextureSize.y * 2U]; mIdTexture->read(texBuffer);