From fe1c840c25493cace24ef27e14aeab21d6f71fb4 Mon Sep 17 00:00:00 2001 From: pradeep Date: Wed, 28 Apr 2021 13:39:35 +0530 Subject: [PATCH] Fix per grid rotation arcball hint in grid layout Viewport call was not suitable for grid layout rendering. Hence implemented custom logic based on cursor position to figure out viewport from it. (cherry picked from commit b9b4a980ad4744feb7d520cf93f109b53c072b9b) --- src/backend/common/defines.hpp | 1 + src/backend/opengl/glfw/window.cpp | 103 ++++++++++++++++++----------- src/backend/opengl/glfw/window.hpp | 21 +++--- src/backend/opengl/sdl/window.cpp | 97 ++++++++++++++++----------- src/backend/opengl/sdl/window.hpp | 19 +++--- src/backend/opengl/window_impl.cpp | 21 ++++++ 6 files changed, 168 insertions(+), 94 deletions(-) diff --git a/src/backend/common/defines.hpp b/src/backend/common/defines.hpp index b0ca4d6..652bf90 100644 --- a/src/backend/common/defines.hpp +++ b/src/backend/common/defines.hpp @@ -13,6 +13,7 @@ #include #include +#include namespace forge { namespace common { diff --git a/src/backend/opengl/glfw/window.cpp b/src/backend/opengl/glfw/window.cpp index 19045d6..ce0f9ad 100644 --- a/src/backend/opengl/glfw/window.cpp +++ b/src/backend/opengl/glfw/window.cpp @@ -17,6 +17,7 @@ #include #include +#include using glm::epsilonNotEqual; using glm::make_vec4; @@ -26,6 +27,11 @@ using glm::scale; using glm::translate; using glm::vec2; using glm::vec3; +using glm::vec4; +using std::floor; +using std::get; +using std::make_tuple; +using std::tuple; using namespace forge::common; @@ -43,60 +49,74 @@ void initWindowToolkit() { void destroyWindowToolkit() { glfwTerminate(); } -const mat4 Widget::findTransform(const MatrixHashMap& pMap, const float pX, - const float pY) { +tuple getCellCoordsDims(const vec2& pos, const CellIndex& idx, + const vec2& dims) { + const int rows = get<0>(idx); + const int cols = get<1>(idx); + const int cw = dims[0] / cols; + const int ch = dims[1] / rows; + const int x = static_cast(floor(pos[0] / static_cast(cw))); + const int y = static_cast(floor(pos[1] / static_cast(ch))); + return make_tuple(vec3(x * cw, y * ch, x + y * cols), vec2(cw, ch)); +} + +const vec4 Widget::getCellViewport(const vec2& pos) { + // Either of the transformation matrix maps are fine for figuring + // out the viewport corresponding to the current mouse position + // Here I am using mOrientMatrices map + vec4 retVal(0, 0, mWidth, mHeight); + for (auto& it : mOrientMatrices) { + const CellIndex& idx = it.first; + auto coordsAndDims = getCellCoordsDims(pos, idx, vec2(mWidth, mHeight)); + if (get<0>(coordsAndDims)[2] == std::get<2>(idx)) { + retVal = vec4(get<0>(coordsAndDims)[0], get<0>(coordsAndDims)[1], + get<1>(coordsAndDims)); + break; + } + } + return retVal; +} + +const mat4 Widget::findTransform(const MatrixHashMap& pMap, const double pX, + const double pY) { for (auto it : pMap) { const CellIndex& idx = it.first; const mat4& mat = it.second; - - const int rows = std::get<0>(idx); - const int cols = std::get<1>(idx); - - const int cellWidth = mWidth / cols; - const int cellHeight = mHeight / rows; - - const int x = int(pX) / cellWidth; - const int y = int(pY) / cellHeight; - const int i = x + y * cols; - if (i == std::get<2>(idx)) { return mat; } + auto coordsAndDims = + getCellCoordsDims(vec2(pX, pY), idx, vec2(mWidth, mHeight)); + if (get<0>(coordsAndDims)[2] == std::get<2>(idx)) { return mat; } } - return IDENTITY; } -const mat4 Widget::getCellViewMatrix(const float pXPos, const float pYPos) { +const mat4 Widget::getCellViewMatrix(const double pXPos, const double pYPos) { return findTransform(mViewMatrices, pXPos, pYPos); } -const mat4 Widget::getCellOrientationMatrix(const float pXPos, - const float pYPos) { +const mat4 Widget::getCellOrientationMatrix(const double pXPos, + const double pYPos) { return findTransform(mOrientMatrices, pXPos, pYPos); } -void Widget::setTransform(MatrixHashMap& pMap, const float pX, const float pY, +void Widget::setTransform(MatrixHashMap& pMap, const double pX, const double pY, const mat4& pMat) { for (auto it : pMap) { const CellIndex& idx = it.first; - - const int rows = std::get<0>(idx); - const int cols = std::get<1>(idx); - - const int cellWidth = mWidth / cols; - const int cellHeight = mHeight / rows; - - const int x = int(pX) / cellWidth; - const int y = int(pY) / cellHeight; - const int i = x + y * cols; - if (i == std::get<2>(idx)) { pMap[idx] = pMat; } + auto coordsAndDims = + getCellCoordsDims(vec2(pX, pY), idx, vec2(mWidth, mHeight)); + if (get<0>(coordsAndDims)[2] == std::get<2>(idx)) { + pMap[idx] = pMat; + return; + } } } -void Widget::setCellViewMatrix(const float pXPos, const float pYPos, +void Widget::setCellViewMatrix(const double pXPos, const double pYPos, const mat4& pMatrix) { return setTransform(mViewMatrices, pXPos, pYPos, pMatrix); } -void Widget::setCellOrientationMatrix(const float pXPos, const float pYPos, +void Widget::setCellOrientationMatrix(const double pXPos, const double pYPos, const mat4& pMatrix) { return setTransform(mOrientMatrices, pXPos, pYPos, pMatrix); } @@ -169,7 +189,7 @@ Widget::Widget(int pWidth, int pHeight, const char* pTitle, auto cursorCallback = [](GLFWwindow* w, double xpos, double ypos) { static_cast(glfwGetWindowUserPointer(w)) - ->cursorHandler(float(xpos), float(ypos)); + ->cursorHandler(xpos, ypos); }; auto mouseButtonCallback = [](GLFWwindow* w, int button, int action, @@ -250,7 +270,7 @@ void Widget::keyboardHandler(int pKey, int pScancode, int pAction, int pMods) { if (pKey == GLFW_KEY_ESCAPE && pAction == GLFW_PRESS) { hide(); } } -void Widget::cursorHandler(const float pXPos, const float pYPos) { +void Widget::cursorHandler(const double pXPos, const double pYPos) { constexpr auto ZOOM_ENABLER = GLFW_MOUSE_BUTTON_LEFT + 10 * GLFW_MOD_CONTROL; @@ -268,7 +288,7 @@ void Widget::cursorHandler(const float pXPos, const float pYPos) { setCellViewMatrix(pXPos, pYPos, vMat); } else if (mButton == ZOOM_ENABLER) { // Zoom - float dy = delta[1]; + double dy = delta[1]; if (!(std::abs(dy) < EPSILON)) { if (dy < 0.0f) { dy = -1.0f / dy; } mat4 vMat = scale(viewMat, vec3(pow(dy, ZOOM_SPEED))); @@ -279,12 +299,9 @@ void Widget::cursorHandler(const float pXPos, const float pYPos) { auto compCmp = epsilonNotEqual(mLastPos, currPos, vec2(EPSILON)); if (compCmp[0] || compCmp[1]) { const mat4 oMat = getCellOrientationMatrix(pXPos, pYPos); - - int view[4]; - glGetIntegerv(GL_VIEWPORT, view); - + const vec4 vprt = getCellViewport(currPos); auto rotParams = - calcRotationFromArcBall(mLastPos, currPos, make_vec4(view)); + calcRotationFromArcBall(mLastPos, currPos, vprt); setCellOrientationMatrix( pXPos, pYPos, @@ -303,7 +320,7 @@ void Widget::mouseButtonHandler(int pButton, int pAction, int pMods) { double x, y; glfwGetCursorPos(mWindow, &x, &y); - auto pos = vec2(float(x), float(y)); + auto pos = vec2(x, y); if (mButtonAction == GLFW_PRESS) { if (mButton == GLFW_MOUSE_BUTTON_RIGHT) { @@ -345,5 +362,11 @@ const mat4 Widget::getOrientationMatrix(const CellIndex& pIndex) { return mOrientMatrices[pIndex]; } +glm::vec2 Widget::getCursorPos() const { + double xp, yp; + glfwGetCursorPos(mWindow, &xp, &yp); + return {xp, yp}; +} + } // namespace wtk } // namespace forge diff --git a/src/backend/opengl/glfw/window.hpp b/src/backend/opengl/glfw/window.hpp index 47398b4..de04875 100644 --- a/src/backend/opengl/glfw/window.hpp +++ b/src/backend/opengl/glfw/window.hpp @@ -42,16 +42,17 @@ class Widget { Widget(); + const glm::vec4 getCellViewport(const glm::vec2& pos); const glm::mat4 findTransform(const forge::common::MatrixHashMap& pMap, - const float pX, const float pY); - const glm::mat4 getCellViewMatrix(const float pXPos, const float pYPos); - const glm::mat4 getCellOrientationMatrix(const float pXPos, - const float pYPos); - void setTransform(forge::common::MatrixHashMap& pMap, const float pX, - const float pY, const glm::mat4& pMat); - void setCellViewMatrix(const float pXPos, const float pYPos, + const double pX, const double pY); + const glm::mat4 getCellViewMatrix(const double pXPos, const double pYPos); + const glm::mat4 getCellOrientationMatrix(const double pXPos, + const double pYPos); + void setTransform(forge::common::MatrixHashMap& pMap, const double pX, + const double pY, const glm::mat4& pMat); + void setCellViewMatrix(const double pXPos, const double pYPos, const glm::mat4& pMatrix); - void setCellOrientationMatrix(const float pXPos, const float pYPos, + void setCellOrientationMatrix(const double pXPos, const double pYPos, const glm::mat4& pMatrix); public: @@ -95,7 +96,7 @@ class Widget { void keyboardHandler(int pKey, int pScancode, int pAction, int pMods); - void cursorHandler(float pXPos, float pYPos); + void cursorHandler(double pXPos, double pYPos); void mouseButtonHandler(int pButton, int pAction, int pMods); @@ -108,6 +109,8 @@ class Widget { void resetOrientationMatrices(); inline bool isBeingRotated() const { return mRotationFlag; } + + glm::vec2 getCursorPos() const; }; } // namespace wtk diff --git a/src/backend/opengl/sdl/window.cpp b/src/backend/opengl/sdl/window.cpp index bb08709..eb87cf4 100644 --- a/src/backend/opengl/sdl/window.cpp +++ b/src/backend/opengl/sdl/window.cpp @@ -26,6 +26,11 @@ using glm::scale; using glm::translate; using glm::vec2; using glm::vec3; +using glm::vec4; +using std::floor; +using std::get; +using std::make_tuple; +using std::tuple; using namespace forge::common; @@ -43,60 +48,74 @@ void initWindowToolkit() { void destroyWindowToolkit() { SDL_Quit(); } -const mat4 Widget::findTransform(const MatrixHashMap& pMap, const float pX, - const float pY) { +tuple getCellCoordsDims(const vec2& pos, const CellIndex& idx, + const vec2& dims) { + const int rows = get<0>(idx); + const int cols = get<1>(idx); + const int cw = dims[0] / cols; + const int ch = dims[1] / rows; + const int x = static_cast(floor(pos[0] / static_cast(cw))); + const int y = static_cast(floor(pos[1] / static_cast(ch))); + return make_tuple(vec3(x * cw, y * ch, x + y * cols), vec2(cw, ch)); +} + +const vec4 Widget::getCellViewport(const vec2& pos) { + // Either of the transformation matrix maps are fine for figuring + // out the viewport corresponding to the current mouse position + // Here I am using mOrientMatrices map + vec4 retVal(0, 0, mWidth, mHeight); + for (auto& it : mOrientMatrices) { + const CellIndex& idx = it.first; + auto coordsAndDims = getCellCoordsDims(pos, idx, vec2(mWidth, mHeight)); + if (get<0>(coordsAndDims)[2] == std::get<2>(idx)) { + retVal = vec4(get<0>(coordsAndDims)[0], get<0>(coordsAndDims)[1], + get<1>(coordsAndDims)); + break; + } + } + return retVal; +} + +const mat4 Widget::findTransform(const MatrixHashMap& pMap, const double pX, + const double pY) { for (auto it : pMap) { const CellIndex& idx = it.first; const mat4& mat = it.second; - - const int rows = std::get<0>(idx); - const int cols = std::get<1>(idx); - - const int cellWidth = mWidth / cols; - const int cellHeight = mHeight / rows; - - const int x = int(pX) / cellWidth; - const int y = int(pY) / cellHeight; - const int i = x + y * cols; - if (i == std::get<2>(idx)) { return mat; } + auto coordsAndDims = + getCellCoordsDims(vec2(pX, pY), idx, vec2(mWidth, mHeight)); + if (get<0>(coordsAndDims)[2] == std::get<2>(idx)) { return mat; } } - return IDENTITY; } -const mat4 Widget::getCellViewMatrix(const float pXPos, const float pYPos) { +const mat4 Widget::getCellViewMatrix(const double pXPos, const double pYPos) { return findTransform(mViewMatrices, pXPos, pYPos); } -const mat4 Widget::getCellOrientationMatrix(const float pXPos, - const float pYPos) { +const mat4 Widget::getCellOrientationMatrix(const double pXPos, + const double pYPos) { return findTransform(mOrientMatrices, pXPos, pYPos); } -void Widget::setTransform(MatrixHashMap& pMap, const float pX, const float pY, +void Widget::setTransform(MatrixHashMap& pMap, const double pX, const double pY, const mat4& pMat) { for (auto it : pMap) { const CellIndex& idx = it.first; - - const int rows = std::get<0>(idx); - const int cols = std::get<1>(idx); - - const int cellWidth = mWidth / cols; - const int cellHeight = mHeight / rows; - - const int x = int(pX) / cellWidth; - const int y = int(pY) / cellHeight; - const int i = x + y * cols; - if (i == std::get<2>(idx)) { pMap[idx] = pMat; } + auto coordsAndDims = + getCellCoordsDims(vec2(pX, pY), idx, vec2(mWidth, mHeight)); + if (get<0>(coordsAndDims)[2] == std::get<2>(idx)) { + pMap[idx] = pMat; + return; + } } } -void Widget::setCellViewMatrix(const float pXPos, const float pYPos, +void Widget::setCellViewMatrix(const double pXPos, const double pYPos, const mat4& pMatrix) { return setTransform(mViewMatrices, pXPos, pYPos, pMatrix); } -void Widget::setCellOrientationMatrix(const float pXPos, const float pYPos, +void Widget::setCellOrientationMatrix(const double pXPos, const double pYPos, const mat4& pMatrix) { return setTransform(mOrientMatrices, pXPos, pYPos, pMatrix); } @@ -265,7 +284,7 @@ void Widget::pollEvents() { auto delta = mLastPos - currPos; if (isCtrl) { // Zoom - float dy = delta[1]; + double dy = delta[1]; if (!(std::abs(dy) < EPSILON)) { if (dy < 0.0f) { dy = -1.0 / dy; } mat4 vMat = @@ -286,11 +305,9 @@ void Widget::pollEvents() { if (compCmp[0] || compCmp[1]) { const mat4 oMat = getCellOrientationMatrix(currPos[0], currPos[1]); - int view[4]; - glGetIntegerv(GL_VIEWPORT, view); - - auto rotParams = calcRotationFromArcBall( - mLastPos, currPos, make_vec4(view)); + const vec4 vprt = getCellViewport(currPos); + auto rotParams = + calcRotationFromArcBall(mLastPos, currPos, vprt); setCellOrientationMatrix( currPos[0], currPos[1], @@ -341,5 +358,11 @@ const mat4 Widget::getOrientationMatrix(const CellIndex& pIndex) { return mOrientMatrices[pIndex]; } +glm::vec2 Widget::getCursorPos() const { + int xp, yp; + SDL_GetMouseState(&xp, &yp); + return {xp, yp}; +} + } // namespace wtk } // namespace forge diff --git a/src/backend/opengl/sdl/window.hpp b/src/backend/opengl/sdl/window.hpp index 687888d..a3d5b48 100644 --- a/src/backend/opengl/sdl/window.hpp +++ b/src/backend/opengl/sdl/window.hpp @@ -43,16 +43,17 @@ class Widget { Widget(); + const glm::vec4 getCellViewport(const glm::vec2& pos); const glm::mat4 findTransform(const forge::common::MatrixHashMap& pMap, - const float pX, const float pY); - const glm::mat4 getCellViewMatrix(const float pXPos, const float pYPos); - const glm::mat4 getCellOrientationMatrix(const float pXPos, - const float pYPos); - void setTransform(forge::common::MatrixHashMap& pMap, const float pX, - const float pY, const glm::mat4& pMat); - void setCellViewMatrix(const float pXPos, const float pYPos, + const double pX, const double pY); + const glm::mat4 getCellViewMatrix(const double pXPos, const double pYPos); + const glm::mat4 getCellOrientationMatrix(const double pXPos, + const double pYPos); + void setTransform(forge::common::MatrixHashMap& pMap, const double pX, + const double pY, const glm::mat4& pMat); + void setCellViewMatrix(const double pXPos, const double pYPos, const glm::mat4& pMatrix); - void setCellOrientationMatrix(const float pXPos, const float pYPos, + void setCellOrientationMatrix(const double pXPos, const double pYPos, const glm::mat4& pMatrix); public: @@ -105,6 +106,8 @@ class Widget { void resetOrientationMatrices(); inline bool isBeingRotated() const { return mRotationFlag; } + + glm::vec2 getCursorPos() const; }; } // namespace wtk diff --git a/src/backend/opengl/window_impl.cpp b/src/backend/opengl/window_impl.cpp index 0d3fedf..5845aba 100644 --- a/src/backend/opengl/window_impl.cpp +++ b/src/backend/opengl/window_impl.cpp @@ -318,6 +318,27 @@ void window_impl::draw(const int pRows, const int pCols, const int pIndex, glDisable(GL_SCISSOR_TEST); glViewport(x, y, cellWidth, cellHeight); + // Render Arcball if cursor position matches current cell + glm::vec2 mpos = mWidget->getCursorPos(); + + int wcx = + static_cast(std::floor(mpos[0] / static_cast(cellWidth))); + int wcy = + static_cast(std::floor(mpos[1] / static_cast(cellHeight))); + + const bool isRotInCurrCell = + (c == wcx && wcy == r && pRenderable->isRotatable()); + if (isRotInCurrCell && mWidget->isBeingRotated()) { + // TODO FIXME Figure out a better way to + // render arc ball loops to include depth test for any + // objects inside it + glClear(GL_DEPTH_BUFFER_BIT); + mArcBallLoop0->render(mID, x, y, cellWidth, cellHeight, IDENTITY, + orientMatrix); + mArcBallLoop1->render(mID, x, y, cellWidth, cellHeight, IDENTITY, + orientMatrix); + } + float pos[2] = {0.0, 0.0}; if (pTitle != NULL) { mFont->setOthro2D(cellWidth, cellHeight);