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);