diff --git a/examples/demo-app/demo_app.cpp b/examples/demo-app/demo_app.cpp index a8be07cb..1dc196ad 100644 --- a/examples/demo-app/demo_app.cpp +++ b/examples/demo-app/demo_app.cpp @@ -769,15 +769,17 @@ void callback() { ImGuiIO& io = ImGui::GetIO(); if (io.MouseClicked[0]) { glm::vec2 screenCoords{io.MousePos.x, io.MousePos.y}; + int xInd, yInd; + std::tie(xInd, yInd) = polyscope::view::screenCoordsToBufferInds(screenCoords); glm::vec3 worldRay = polyscope::view::screenCoordsToWorldRay(screenCoords); glm::vec3 worldPos = polyscope::view::screenCoordsToWorldPosition(screenCoords); - std::pair pickPair = - polyscope::pick::evaluatePickQuery(screenCoords.x, screenCoords.y); + std::pair pickPair = polyscope::pick::pickAtScreenCoords(screenCoords); std::cout << "Polyscope scene test click " << std::endl; std::cout << " io.MousePos.x: " << io.MousePos.x << " io.MousePos.y: " << io.MousePos.y << std::endl; std::cout << " screenCoords.x: " << screenCoords.x << " screenCoords.y: " << screenCoords.y << std::endl; + std::cout << " bufferInd.x: " << xInd << " bufferInd.y: " << yInd << std::endl; std::cout << " worldRay: "; polyscope::operator<<(std::cout, worldRay) << std::endl; std::cout << " worldPos: "; diff --git a/include/polyscope/pick.h b/include/polyscope/pick.h index 82e45d41..2facd906 100644 --- a/include/polyscope/pick.h +++ b/include/polyscope/pick.h @@ -20,7 +20,9 @@ size_t requestPickBufferRange(Structure* requestingStructure, size_t count); // == Main query // Get the structure which was clicked on (nullptr if none), and the pick ID in local indices for that structure (such // that 0 is the first index as returned from requestPickBufferRange()) -std::pair evaluatePickQuery(int xPos, int yPos); +std::pair pickAtScreenCoords(glm::vec2 screenCoords); // takes screen coordinates +std::pair pickAtBufferCoords(int xPos, int yPos); // takes indices into the buffer +std::pair evaluatePickQuery(int xPos, int yPos); // old, badly named. takes buffer coordinates. // == Stateful picking: track and update a current selection diff --git a/include/polyscope/view.h b/include/polyscope/view.h index 6090fbd8..06c0f2d3 100644 --- a/include/polyscope/view.h +++ b/include/polyscope/view.h @@ -4,6 +4,7 @@ #include #include +#include #include "polyscope/camera_parameters.h" #include "polyscope/types.h" @@ -111,7 +112,7 @@ void getCameraFrame(glm::vec3& lookDir, glm::vec3& upDir, glm::vec3& rightDir); // Get world geometry corresponding to a screen pixel (e.g. from a mouse click) glm::vec3 screenCoordsToWorldRay(glm::vec2 screenCoords); -glm::vec3 bufferCoordsToWorldRay(glm::vec2 screenCoords); +glm::vec3 bufferCoordsToWorldRay(int xPos, int yPos); glm::vec3 screenCoordsToWorldPosition(glm::vec2 screenCoords); // queries the depth buffer to get full position // Flight-related @@ -129,6 +130,7 @@ void setCameraFromJson(std::string jsonData, bool flyTo); // Other helpers std::string to_string(ProjectionMode mode); std::string to_string(NavigateStyle style); +std::tuple screenCoordsToBufferInds(glm::vec2 screenCoords); // Internal helpers. Should probably not be called in user code. void buildViewGui(); diff --git a/src/pick.cpp b/src/pick.cpp index e8800fcd..2e45eed7 100644 --- a/src/pick.cpp +++ b/src/pick.cpp @@ -118,6 +118,13 @@ size_t localIndexToGlobal(std::pair localPick) { return rangeStart + localPick.second; } +std::pair pickAtScreenCoords(glm::vec2 screenCoords) { + int xInd, yInd; + std::tie(xInd, yInd) = view::screenCoordsToBufferInds(screenCoords); + return pickAtBufferCoords(xInd, yInd); +} + +std::pair pickAtBufferCoords(int xPos, int yPos) { return evaluatePickQuery(xPos, yPos); } std::pair evaluatePickQuery(int xPos, int yPos) { diff --git a/src/polyscope.cpp b/src/polyscope.cpp index f4ccf927..6cf2ead7 100644 --- a/src/polyscope.cpp +++ b/src/polyscope.cpp @@ -376,8 +376,7 @@ void processInputEvents() { // Don't pick at the end of a long drag if (dragDistSinceLastRelease < dragIgnoreThreshold) { ImVec2 p = ImGui::GetMousePos(); - std::pair pickResult = - pick::evaluatePickQuery(io.DisplayFramebufferScale.x * p.x, io.DisplayFramebufferScale.y * p.y); + std::pair pickResult = pick::pickAtScreenCoords(glm::vec2{p.x, p.y}); pick::setSelection(pickResult); } diff --git a/src/surface_mesh.cpp b/src/surface_mesh.cpp index 08b7d23f..577465f0 100644 --- a/src/surface_mesh.cpp +++ b/src/surface_mesh.cpp @@ -1392,8 +1392,7 @@ long long int SurfaceMesh::selectVertex() { // API is a giant mess.. size_t pickInd; ImVec2 p = ImGui::GetMousePos(); - std::pair pickVal = - pick::evaluatePickQuery(io.DisplayFramebufferScale.x * p.x, io.DisplayFramebufferScale.y * p.y); + std::pair pickVal = pick::pickAtScreenCoords(glm::vec2{p.x, p.y}); if (pickVal.first == this) { diff --git a/src/view.cpp b/src/view.cpp index f313594b..2ced6796 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -83,6 +83,19 @@ std::string to_string(NavigateStyle style) { return ""; // unreachable } + +std::tuple screenCoordsToBufferInds(glm::vec2 screenCoords) { + + int xPos = (screenCoords.x * view::bufferWidth) / view::windowWidth; + int yPos = (screenCoords.y * view::bufferHeight) / view::windowHeight; + + // clamp to lie in [0,width),[0,height) + xPos = std::max(std::min(xPos, view::bufferWidth - 1), 0); + yPos = std::max(std::min(yPos, view::bufferHeight - 1), 0); + + return std::tuple(xPos, yPos); +} + void processRotate(glm::vec2 startP, glm::vec2 endP) { if (startP == endP) { @@ -489,13 +502,13 @@ glm::vec3 screenCoordsToWorldRay(glm::vec2 screenCoords) { return worldRayDir; } -glm::vec3 bufferCoordsToWorldRay(glm::vec2 screenCoords) { +glm::vec3 bufferCoordsToWorldRay(glm::vec2 bufferCoords) { glm::mat4 view = getCameraViewMatrix(); glm::mat4 proj = getCameraPerspectiveMatrix(); glm::vec4 viewport = {0., 0., view::bufferWidth, view::bufferHeight}; - glm::vec3 screenPos3{screenCoords.x, view::bufferHeight - screenCoords.y, 0.}; + glm::vec3 screenPos3{bufferCoords.x, view::bufferHeight - bufferCoords.y, 0.}; glm::vec3 worldPos = glm::unProject(screenPos3, view, proj, viewport); glm::vec3 worldRayDir = glm::normalize(glm::vec3(worldPos) - getCameraWorldPosition()); @@ -505,9 +518,8 @@ glm::vec3 bufferCoordsToWorldRay(glm::vec2 screenCoords) { glm::vec3 screenCoordsToWorldPosition(glm::vec2 screenCoords) { - glm::vec2 bufferCoords{screenCoords.x * static_cast(view::bufferWidth) / static_cast(view::windowWidth), - screenCoords.y * static_cast(view::bufferHeight) / - static_cast(view::windowHeight)}; + int xInd, yInd; + std::tie(xInd, yInd) = screenCoordsToBufferInds(screenCoords); glm::mat4 view = getCameraViewMatrix(); glm::mat4 viewInv = glm::inverse(view); @@ -517,7 +529,7 @@ glm::vec3 screenCoordsToWorldPosition(glm::vec2 screenCoords) { // query the depth buffer to get depth render::FrameBuffer* sceneFramebuffer = render::engine->sceneBuffer.get(); - float depth = sceneFramebuffer->readDepth(bufferCoords.x, view::bufferHeight - bufferCoords.y); + float depth = sceneFramebuffer->readDepth(xInd, view::bufferHeight - yInd); if (depth == 1.) { // if we didn't hit anything in the depth buffer, just return infinity float inf = std::numeric_limits::infinity();