Skip to content

Commit

Permalink
feat(gizmos): integrate screen picker with gizmos
Browse files Browse the repository at this point in the history
  • Loading branch information
tomas7770 committed Feb 2, 2024
1 parent 68c00d8 commit d4cbd61
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 100 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 3 additions & 1 deletion engine/include/cubos/engine/gizmos/gizmos.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,15 @@ namespace cubos::engine
std::vector<std::shared_ptr<Gizmo>> viewGizmos; ///< Queued gizmos to be drawn in viewport space.
std::vector<std::shared_ptr<Gizmo>> 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>& gizmo, const Space& space);

std::hash<std::string> 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.

Expand Down
3 changes: 3 additions & 0 deletions engine/include/cubos/engine/gizmos/plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions engine/src/cubos/engine/gizmos/gizmos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ void Gizmos::push(const std::shared_ptr<Gizmo>& gizmo, const Space& space)
}
}

uint32_t Gizmos::mHasher(const std::string& id)
{
uint32_t hash = static_cast<uint32_t>(std::hash<std::string>{}(id));
// Set 32nd bit to distinguish from entities
hash |= static_cast<uint32_t>(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<LineGizmo>((uint32_t)mHasher(id), from, to, mColor, lifespan), space);
Expand Down
89 changes: 36 additions & 53 deletions engine/src/cubos/engine/gizmos/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <cubos/engine/gizmos/plugin.hpp>
#include <cubos/engine/renderer/plugin.hpp>
#include <cubos/engine/screen_picker/plugin.hpp>
#include <cubos/engine/transform/plugin.hpp>
#include <cubos/engine/window/plugin.hpp>

Expand All @@ -23,7 +24,7 @@ using namespace cubos::engine;

static void iterateGizmos(std::vector<std::shared_ptr<Gizmos::Gizmo>>& gizmosVector,
const std::vector<std::pair<glm::mat4, BaseRenderer::Viewport>>& cameras,
GizmosRenderer& gizmosRenderer, const DeltaTime& deltaTime)
GizmosRenderer& gizmosRenderer, ScreenPicker& screenPicker, const DeltaTime& deltaTime)
{
std::vector<std::size_t> toRemove;

Expand All @@ -42,7 +43,7 @@ static void iterateGizmos(std::vector<std::shared_ptr<Gizmos::Gizmo>>& gizmosVec

// Id
gizmosRenderer.renderDevice->setShaderPipeline(gizmosRenderer.idPipeline);
gizmosRenderer.renderDevice->setFramebuffer(gizmosRenderer.idFramebuffer);
gizmosRenderer.renderDevice->setFramebuffer(screenPicker.framebuffer());

gizmosRenderer.idPipeline->getBindingPoint("gizmo")->setConstant(gizmo.id);

Expand Down Expand Up @@ -186,6 +187,7 @@ static std::vector<std::pair<glm::mat4, BaseRenderer::Viewport>> getScreenInfo(c

void cubos::engine::gizmosPlugin(Cubos& cubos)
{
cubos.addPlugin(cubos::engine::screenPickerPlugin);
cubos.addPlugin(cubos::engine::windowPlugin);

cubos.addResource<Gizmos>();
Expand All @@ -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> windowEvent) {
bool locking = false;
gizmos.mLocking = false;
for (const auto& event : windowEvent)
{
if (std::holds_alternative<MouseMoveEvent>(event))
Expand All @@ -221,74 +222,56 @@ void cubos::engine::gizmosPlugin(Cubos& cubos)
}
else
{
locking = true;
gizmos.mLocking = true;
}
}
}
else if (std::holds_alternative<ResizeEvent>(event))
{
gizmosRenderer.resizeTexture(std::get<ResizeEvent>(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<uint32_t>(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<const LocalToWorld&, const Camera&> query) {
.call([](Gizmos& gizmos, GizmosRenderer& gizmosRenderer, ScreenPicker& screenPicker,
const ActiveCameras& activeCameras, const Window& window, const DeltaTime& deltaTime,
Query<const LocalToWorld&, const Camera&> 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<uint32_t>(1 << 31))
{
// Not a gizmo, treat it like empty space
id = UINT32_MAX;
}

gizmos.handleInput(id, gizmosRenderer.mousePressed);

if (gizmos.mLocking)
{
gizmos.setLocked(id);
}
});
}
36 changes: 1 addition & 35 deletions engine/src/cubos/engine/gizmos/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"(
Expand Down Expand Up @@ -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;

Expand All @@ -113,8 +86,6 @@ void GizmosRenderer::init(RenderDevice* currentRenderDevice, glm::ivec2 size)
dss.depth.writeEnabled = false;
noDepthCheckStencilState = renderDevice->createDepthStencilState(dss);

initIdTexture(size);

initDrawPipeline();
initIdPipeline();

Expand Down Expand Up @@ -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;
Expand Down
12 changes: 1 addition & 11 deletions engine/src/cubos/engine/gizmos/renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,29 +31,19 @@ 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.

private:
cubos::core::gl::Texture2D mDepthTexture;

void initIdTexture(glm::ivec2 size);

void initIdPipeline();
void initDrawPipeline();

Expand Down
5 changes: 5 additions & 0 deletions engine/src/cubos/engine/screen_picker/screen_picker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit d4cbd61

Please sign in to comment.