diff --git a/interface/resources/images/reticleLink.png b/interface/resources/images/reticleLink.png new file mode 100644 index 0000000000..b36ee79d00 Binary files /dev/null and b/interface/resources/images/reticleLink.png differ diff --git a/interface/resources/images/reticleWhite.png b/interface/resources/images/reticleWhite.png new file mode 100644 index 0000000000..4c35a186b2 Binary files /dev/null and b/interface/resources/images/reticleWhite.png differ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1763623fa6..5f17fd0510 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -57,6 +57,7 @@ #include #include +#include #include #include #include @@ -1229,9 +1230,20 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; - case Qt::Key_Apostrophe: - resetSensors(); + case Qt::Key_Apostrophe: { + if (isMeta) { + auto cursor = Cursor::Manager::instance().getCursor(); + auto curIcon = cursor->getIcon(); + if (curIcon == Cursor::Icon::DEFAULT) { + cursor->setIcon(Cursor::Icon::LINK); + } else { + cursor->setIcon(Cursor::Icon::DEFAULT); + } + } else { + resetSensors(); + } break; + } case Qt::Key_A: if (isShifted) { @@ -1355,12 +1367,27 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Slash: Menu::getInstance()->triggerOption(MenuOption::Stats); break; - case Qt::Key_Plus: - _myAvatar->increaseSize(); + + case Qt::Key_Plus: { + if (isMeta && event->modifiers().testFlag(Qt::KeypadModifier)) { + auto& cursorManager = Cursor::Manager::instance(); + cursorManager.setScale(cursorManager.getScale() * 1.1f); + } else { + _myAvatar->increaseSize(); + } break; - case Qt::Key_Minus: - _myAvatar->decreaseSize(); + } + + case Qt::Key_Minus: { + if (isMeta && event->modifiers().testFlag(Qt::KeypadModifier)) { + auto& cursorManager = Cursor::Manager::instance(); + cursorManager.setScale(cursorManager.getScale() / 1.1f); + } else { + _myAvatar->decreaseSize(); + } break; + } + case Qt::Key_Equal: _myAvatar->resetSize(); break; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index bc8047fc98..7895232f8a 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "AudioClient.h" #include "audio/AudioIOStatsRenderer.h" @@ -143,7 +144,6 @@ ApplicationOverlay::ApplicationOverlay() : _alpha(1.0f), _oculusUIRadius(1.0f), _trailingAudioLoudness(0.0f), - _crosshairTexture(0), _previousBorderWidth(-1), _previousBorderHeight(-1), _previousMagnifierBottomLeft(), @@ -257,6 +257,18 @@ void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) { glDisable(GL_TEXTURE_2D); } +void ApplicationOverlay::bindCursorTexture(uint8_t cursorIndex) { + auto& cursorManager = Cursor::Manager::instance(); + auto cursor = cursorManager.getCursor(cursorIndex); + auto iconId = cursor->getIcon(); + if (!_cursors.count(iconId)) { + auto iconPath = cursorManager.getIconImage(cursor->getIcon()); + _cursors[iconId] = DependencyManager::get()-> + getImageTexture(iconPath); + } + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_cursors[iconId])); +} + // Draws the FBO texture for the screen void ApplicationOverlay::displayOverlayTexture() { if (_alpha == 0.0f) { @@ -282,14 +294,10 @@ void ApplicationOverlay::displayOverlayTexture() { glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); }); - if (!_crosshairTexture) { - _crosshairTexture = DependencyManager::get()-> - getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png"); - } - + //draw the mouse pointer glm::vec2 canvasSize = qApp->getCanvasSize(); - glm::vec2 mouseSize = 32.0f / canvasSize; + glm::vec2 mouseSize = 32.0f / canvasSize * Cursor::Manager::instance().getScale(); auto mouseTopLeft = topLeft * mouseSize; auto mouseBottomRight = bottomRight * mouseSize; vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY()); @@ -300,7 +308,7 @@ void ApplicationOverlay::displayOverlayTexture() { glEnable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); + bindCursorTexture(); glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; DependencyManager::get()->renderQuad( mouseTopLeft + mousePosition, mouseBottomRight + mousePosition, @@ -450,18 +458,14 @@ void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float overlayColor); }); - if (!_crosshairTexture) { - _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + - "images/sixense-reticle.png"); - } - //draw the mouse pointer glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); + bindCursorTexture(); glm::vec2 canvasSize = qApp->getCanvasSize(); - const float reticleSize = 40.0f / canvasSize.x * quadWidth; + const float reticleSize = 40.0f / canvasSize.x * quadWidth * + Cursor::Manager::instance().getScale(); x -= reticleSize / 2.0f; y += reticleSize / 2.0f; const float mouseX = (qApp->getMouseX() / (float)canvasSize.x) * quadWidth; @@ -583,16 +587,12 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, //Renders optional pointers void ApplicationOverlay::renderPointers() { - //lazily load crosshair texture - if (_crosshairTexture == 0) { - _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png"); - } glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); + bindCursorTexture(); if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) { //If we are in oculus, render reticle later @@ -757,7 +757,7 @@ void ApplicationOverlay::renderPointersOculus() { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); + bindCursorTexture(); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index ee82c9274a..0e8206547a 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -108,6 +108,7 @@ private: void renderCameraToggle(); void renderStatsAndLogs(); void renderDomainConnectionStatusBorder(); + void bindCursorTexture(uint8_t cursorId = 0); TexturedHemisphere _overlays; @@ -127,7 +128,8 @@ private: float _trailingAudioLoudness; - gpu::TexturePointer _crosshairTexture; + QMap _cursors; + GLuint _newUiTexture{ 0 }; int _reticleQuad; diff --git a/libraries/ui/src/CursorManager.cpp b/libraries/ui/src/CursorManager.cpp index 8b318d549a..efadd09142 100644 --- a/libraries/ui/src/CursorManager.cpp +++ b/libraries/ui/src/CursorManager.cpp @@ -8,25 +8,85 @@ #include "CursorManager.h" +#include +#include +#include + +#include + namespace Cursor { - enum class Source { - MOUSE, - LEFT_HAND, - RIGHT_HAND, - UNKNOWN, + + void Instance::setIcon(uint16_t icon) { + _icon = icon; + } + + uint16_t Instance::getIcon() const { + return _icon; + } + + + class MouseInstance : public Instance { + Source getType() const { + return Source::MOUSE; + } + + ivec2 getScreenPosition() const { + return toGlm(QCursor::pos()); + } + + ivec2 getWindowPosition(QWidget* widget) const { + return toGlm(widget->mapFromGlobal(QCursor::pos())); + } + + vec2 getRelativePosition(QWidget* widget) const { + vec2 pos = getWindowPosition(widget); + pos /= vec2(toGlm(widget->size())); + return pos; + } }; - class Instance { - Source type; - }; + static QMap ICONS; + static uint16_t _customIconId = Icon::USER_BASE; - class Manager { - public: - static Manager& instance(); + Manager::Manager() { + ICONS[Icon::DEFAULT] = PathUtils::resourcesPath() + "images/sixense-reticle.png"; + ICONS[Icon::LINK] = PathUtils::resourcesPath() + "images/reticleLink.png"; + } - uint8_t getCount(); - Instance - }; -} + Manager& Manager::instance() { + static Manager instance; + return instance; + } + uint8_t Manager::getCount() { + return 1; + } + Instance* Manager::getCursor(uint8_t index) { + Q_ASSERT(index < getCount()); + static MouseInstance mouseInstance; + if (index == 0) { + return &mouseInstance; + } + return nullptr; + } + + uint16_t Manager::registerIcon(const QString& path) { + ICONS[_customIconId] = path; + return _customIconId++; + } + + const QString& Manager::getIconImage(uint16_t icon) { + Q_ASSERT(ICONS.count(icon)); + return ICONS[icon]; + } + + float Manager::getScale() { + return _scale; + } + + void Manager::setScale(float scale) { + _scale = scale; + } + +} \ No newline at end of file diff --git a/libraries/ui/src/CursorManager.h b/libraries/ui/src/CursorManager.h index a2d26efc58..c5810caf58 100644 --- a/libraries/ui/src/CursorManager.h +++ b/libraries/ui/src/CursorManager.h @@ -7,6 +7,9 @@ // #pragma once +#include + +#include namespace Cursor { enum class Source { @@ -16,16 +19,42 @@ namespace Cursor { UNKNOWN, }; + enum Icon { + DEFAULT, + LINK, + GRAB, + + // Add new system cursors here + + // User cursors will have ids over this value + USER_BASE = 0xFF, + }; + class Instance { - Source type; + public: + virtual Source getType() const = 0; + virtual ivec2 getWindowPosition(QWidget* widget) const = 0; + virtual vec2 getRelativePosition(QWidget* widget) const = 0; + virtual ivec2 getScreenPosition() const = 0; + virtual void setIcon(uint16_t icon); + virtual uint16_t getIcon() const; + private: + uint16_t _icon; }; class Manager { + Manager(); + Manager(const Manager& other) = delete; public: static Manager& instance(); - uint8_t getCount(); - Instance + float getScale(); + void setScale(float scale); + Instance* getCursor(uint8_t index = 0); + uint16_t registerIcon(const QString& path); + const QString& getIconImage(uint16_t icon); + private: + float _scale{ 1.0f }; }; }