From e4a0275f57fdc2455bdc4880e37a5e828dcd21ce Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 10:53:11 -0700 Subject: [PATCH 01/25] Exposed sixense and mouse options and oculus UI angle to preferences --- interface/src/Menu.cpp | 6 +- interface/src/Menu.h | 10 +- interface/src/devices/OculusManager.h | 2 + interface/src/devices/SixenseManager.cpp | 4 +- interface/src/devices/SixenseManager.h | 3 + interface/src/ui/ApplicationOverlay.cpp | 8 +- interface/src/ui/ApplicationOverlay.h | 5 +- interface/src/ui/PreferencesDialog.cpp | 13 + interface/ui/preferencesDialog.ui | 331 ++++++++++++++++++++++- 9 files changed, 367 insertions(+), 15 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3015a638f6..644b08f03d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -45,6 +45,7 @@ #include "ui/ModelsBrowser.h" #include "ui/LoginDialog.h" #include "ui/NodeBounds.h" +#include "devices/OculusManager.h" Menu* Menu::_instance = NULL; @@ -83,6 +84,7 @@ Menu::Menu() : _audioJitterBufferSamples(0), _bandwidthDialog(NULL), _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), + _realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), _faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION), _frustumDrawMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET), @@ -91,6 +93,9 @@ Menu::Menu() : _lodToolsDialog(NULL), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), + _oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE), + _sixenseReticleMoveSpeed(DEFAULT_SIXENSE_RETICLE_MOVE_SPEED), + _invertSixenseButtons(DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS), _automaticAvatarLOD(true), _avatarLODDecreaseFPS(DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS), _avatarLODIncreaseFPS(ADJUST_LOD_UP_FPS), @@ -387,7 +392,6 @@ Menu::Menu() : QMenu* sixenseOptionsMenu = developerMenu->addMenu("Sixense Options"); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); - addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseInvertInputButtons, 0, false); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 41f0b41498..4d2174a448 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -90,6 +90,12 @@ public: void setFieldOfView(float fieldOfView) { _fieldOfView = fieldOfView; } float getRealWorldFieldOfView() const { return _realWorldFieldOfView; } void setRealWorldFieldOfView(float realWorldFieldOfView) { _realWorldFieldOfView = realWorldFieldOfView; } + float getOculusUIAngularSize() const { return _oculusUIAngularSize; } + void setOculusUIAngularSize(float oculusUIAngularSize) { _oculusUIAngularSize = oculusUIAngularSize; } + float getSixenseReticleMoveSpeed() const { return _sixenseReticleMoveSpeed; } + void setSixenseReticleMoveSpeed(float sixenseReticleMoveSpeed) { _sixenseReticleMoveSpeed = sixenseReticleMoveSpeed; } + bool getInvertSixenseButtons() const { return _invertSixenseButtons; } + void setInvertSixenseButtons(bool invertSixenseButtons) { _invertSixenseButtons = invertSixenseButtons; } float getFaceshiftEyeDeflection() const { return _faceshiftEyeDeflection; } void setFaceshiftEyeDeflection(float faceshiftEyeDeflection) { _faceshiftEyeDeflection = faceshiftEyeDeflection; } @@ -255,6 +261,9 @@ private: LodToolsDialog* _lodToolsDialog; int _maxVoxels; float _voxelSizeScale; + float _oculusUIAngularSize; + float _sixenseReticleMoveSpeed; + bool _invertSixenseButtons; bool _automaticAvatarLOD; float _avatarLODDecreaseFPS; float _avatarLODIncreaseFPS; @@ -400,7 +409,6 @@ namespace MenuOption { const QString SettingsExport = "Export Settings"; const QString SettingsImport = "Import Settings"; const QString SimpleShadows = "Simple"; - const QString SixenseInvertInputButtons = "Invert Sixense Mouse Input Buttons"; const QString SixenseMouseInput = "Enable Sixense Mouse Input"; const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowBordersModelNodes = "Show Model Nodes"; diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index caff38a6b0..21b9d67f4d 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -20,6 +20,8 @@ #include "renderer/ProgramObject.h" +const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; + class Camera; /// Handles interaction with the Oculus Rift. diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index fa902be46f..5257a777e0 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -339,7 +339,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { Qt::MouseButton bumperButton; Qt::MouseButton triggerButton; - if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseInvertInputButtons)) { + if (Menu::getInstance()->getInvertSixenseButtons()) { bumperButton = Qt::LeftButton; triggerButton = Qt::RightButton; } else { @@ -351,7 +351,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { float xAngle = (atan2(direction.z, direction.x) + M_PI_2) + 0.5f; float yAngle = 1.0f - ((atan2(direction.z, direction.y) + M_PI_2) + 0.5f); - float cursorRange = widget->width(); + float cursorRange = widget->width() * (1.0f - Menu::getInstance()->getSixenseReticleMoveSpeed() * 0.01f) * 2.0f; pos.setX(cursorRange * xAngle); pos.setY(cursorRange * yAngle); diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index f3c5633f90..71511cd06b 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -30,6 +30,9 @@ const unsigned int BUTTON_FWD = 1U << 7; // Event type that represents moving the controller const unsigned int CONTROLLER_MOVE_EVENT = 1500U; +const float DEFAULT_SIXENSE_RETICLE_MOVE_SPEED = 1.0f; +const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = true; + /// Handles interaction with the Sixense SDK (e.g., Razer Hydra). class SixenseManager : public QObject { Q_OBJECT diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 95ac803e37..a45e42dc0b 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -33,7 +33,7 @@ ApplicationOverlay::ApplicationOverlay() : _framebufferObject(NULL), _oculusAngle(65.0f * RADIANS_PER_DEGREE), _distance(0.5f), - _textureFov(PI / 2.5f), + _textureFov(DEFAULT_OCULUS_UI_ANGULAR_SIZE * RADIANS_PER_DEGREE), _uiType(HEMISPHERE) { } @@ -50,6 +50,8 @@ const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; void ApplicationOverlay::renderOverlay(bool renderToTexture) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); + _textureFov = Menu::getInstance()->getOculusUIAngularSize() * RADIANS_PER_DEGREE; + Application* application = Application::getInstance(); Overlays& overlays = application->getOverlays(); @@ -154,8 +156,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { MyAvatar* myAvatar = application->getAvatar(); const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); - - // Get vertical FoV of the displayed overlay texture const float halfVerticalAngle = _oculusAngle / 2.0f; const float overlayAspectRatio = glWidget->width() / (float)glWidget->height(); @@ -338,7 +338,7 @@ void ApplicationOverlay::renderControllerPointer() { float xAngle = (atan2(direction.z, direction.x) + M_PI_2) + 0.5f; float yAngle = 1.0f - ((atan2(direction.z, direction.y) + M_PI_2) + 0.5f); - float cursorRange = glWidget->width(); + float cursorRange = glWidget->width() * (1.0f - Menu::getInstance()->getSixenseReticleMoveSpeed() * 0.01f) * 2.0f; int mouseX = cursorRange * xAngle; int mouseY = cursorRange * yAngle; diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 03a323cd5d..b6066099fa 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -31,10 +31,7 @@ public: // Getters QOpenGLFramebufferObject* getFramebufferObject(); - float getOculusAngle() const { return _oculusAngle; } - - // Setters - void setOculusAngle(float oculusAngle) { _oculusAngle = oculusAngle; } + void setUIType(UIType uiType) { _uiType = uiType; } private: diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index d5c6079d4b..5e6c6984eb 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -137,6 +137,13 @@ void PreferencesDialog::loadPreferences() { ui.maxVoxelsSpin->setValue(menuInstance->getMaxVoxels()); ui.maxVoxelsPPSSpin->setValue(menuInstance->getMaxVoxelPacketsPerSecond()); + + ui.oculusUIAngularSizeSpin->setValue(menuInstance->getOculusUIAngularSize()); + + ui.sixenseReticleMoveSpeedSpin->setValue(menuInstance->getSixenseReticleMoveSpeed()); + + ui.invertSixenseButtonsCheckBox->setChecked(menuInstance->getInvertSixenseButtons()); + } void PreferencesDialog::savePreferences() { @@ -189,6 +196,12 @@ void PreferencesDialog::savePreferences() { (float)ui.faceshiftEyeDeflectionSider->maximum()); Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value()); + Menu::getInstance()->setOculusUIAngularSize(ui.oculusUIAngularSizeSpin->value()); + + Menu::getInstance()->setSixenseReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value()); + + Menu::getInstance()->setInvertSixenseButtons(ui.invertSixenseButtonsCheckBox->isChecked()); + Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value()); Application::getInstance()->getAudio()->setJitterBufferSamples(ui.audioJitterSpin->value()); diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index a1c2073ab6..f00d7c4788 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -154,9 +154,9 @@ color: #0e7077 0 - -204 - 494 - 1091 + -1002 + 477 + 1386 @@ -1605,6 +1605,331 @@ padding: 10px;margin-top:10px + + + + + 0 + 0 + + + + + 0 + 40 + + + + + Arial + 20 + 50 + false + + + + color: #0e7077 + + + Oculus Rift + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + User Interface Angular Size + + + 15 + + + maxVoxelsSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 125 + 36 + + + + + Arial + + + + 30 + + + 160 + + + 1 + + + 72 + + + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + Arial + 20 + 50 + false + + + + color: #0e7077 + + + Sixense Controllers + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Invert Mouse Buttons + + + 15 + + + maxVoxelsSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 32 + 0 + + + + + 0 + 0 + + + + + + + + 32 + 32 + + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Reticle Movement Speed + + + 15 + + + maxVoxelsSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 125 + 36 + + + + + Arial + + + + 100 + + + 1 + + + 50 + + + + + From 4a1307fa382ff92a25877f21474c57c42a55825d Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 10:54:50 -0700 Subject: [PATCH 02/25] Killed two warnings --- interface/src/ui/ApplicationOverlay.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index a45e42dc0b..f6afc15223 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -316,7 +316,6 @@ void ApplicationOverlay::renderControllerPointer() { MyAvatar* myAvatar = application->getAvatar(); const HandData* handData = Application::getInstance()->getAvatar()->getHandData(); - int numberOfPalms = handData->getNumPalms(); for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) { const PalmData* palmData = NULL; @@ -431,8 +430,6 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY) magnifyHeight = widgetHeight - mouseY; } - const float halfMagnifyHeight = magnifyHeight / 2.0f; - float newWidth = magnifyWidth * magnification; float newHeight = magnifyHeight * magnification; From 422db14812a20a63cb7c3a987733832253c7e883 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 11:34:57 -0700 Subject: [PATCH 03/25] Fixed some improper logic and used better defaults --- interface/src/devices/SixenseManager.cpp | 17 +++++++++++------ interface/src/devices/SixenseManager.h | 5 +++-- interface/src/ui/ApplicationOverlay.cpp | 13 ++++++------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 5257a777e0..ed55dc4c66 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -185,6 +185,11 @@ void SixenseManager::update(float deltaTime) { #endif // HAVE_SIXENSE } +float SixenseManager::getCursorPixelRangeMultiplier() const { + //scales (0,100) to (0.4,2.0) + return ((Menu::getInstance()->getSixenseReticleMoveSpeed()) * 0.008f + 0.2f) * 2.0f; +} + #ifdef HAVE_SIXENSE // the calibration sequence is: @@ -347,14 +352,14 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { triggerButton = Qt::LeftButton; } - // Get the angles, scaled between 0-1 - float xAngle = (atan2(direction.z, direction.x) + M_PI_2) + 0.5f; - float yAngle = 1.0f - ((atan2(direction.z, direction.y) + M_PI_2) + 0.5f); + // Get the angles, scaled between (-0.5,0.5) + float xAngle = (atan2(direction.z, direction.x) + M_PI_2); + float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); - float cursorRange = widget->width() * (1.0f - Menu::getInstance()->getSixenseReticleMoveSpeed() * 0.01f) * 2.0f; + float cursorRange = widget->width() * getCursorPixelRangeMultiplier(); - pos.setX(cursorRange * xAngle); - pos.setY(cursorRange * yAngle); + pos.setX(widget->width() / 2.0f + cursorRange * xAngle); + pos.setY(widget->height() / 2.0f + cursorRange * yAngle); //If we are off screen then we should stop processing, and if a trigger or bumper is pressed, //we should unpress them. diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 71511cd06b..41e061a25b 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -30,8 +30,8 @@ const unsigned int BUTTON_FWD = 1U << 7; // Event type that represents moving the controller const unsigned int CONTROLLER_MOVE_EVENT = 1500U; -const float DEFAULT_SIXENSE_RETICLE_MOVE_SPEED = 1.0f; -const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = true; +const float DEFAULT_SIXENSE_RETICLE_MOVE_SPEED = 37.5f; +const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false; /// Handles interaction with the Sixense SDK (e.g., Razer Hydra). class SixenseManager : public QObject { @@ -42,6 +42,7 @@ public: ~SixenseManager(); void update(float deltaTime); + float getCursorPixelRangeMultiplier() const; public slots: diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index f6afc15223..8ba0b42910 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -333,14 +333,14 @@ void ApplicationOverlay::renderControllerPointer() { // Get directon relative to avatar orientation glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection(); - // Get the angles, scaled between 0-1 - float xAngle = (atan2(direction.z, direction.x) + M_PI_2) + 0.5f; - float yAngle = 1.0f - ((atan2(direction.z, direction.y) + M_PI_2) + 0.5f); + // Get the angles, scaled between (-0.5,0.5) + float xAngle = (atan2(direction.z, direction.x) + M_PI_2) ; + float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); - float cursorRange = glWidget->width() * (1.0f - Menu::getInstance()->getSixenseReticleMoveSpeed() * 0.01f) * 2.0f; + float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMultiplier(); - int mouseX = cursorRange * xAngle; - int mouseY = cursorRange * yAngle; + int mouseX = glWidget->width() / 2.0f + cursorRange * xAngle; + int mouseY = glWidget->height() / 2.0f + cursorRange * yAngle; //If the cursor is out of the screen then don't render it if (mouseX < 0 || mouseX >= glWidget->width() || mouseY < 0 || mouseY >= glWidget->height()) { @@ -409,7 +409,6 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY) const float horizontalAngle = halfVerticalAngle * 2.0f * overlayAspectRatio; const float halfHorizontalAngle = horizontalAngle / 2; - float magnifyWidth = 80.0f; float magnifyHeight = 60.0f; From 3747a5eeae79bee2b14b6bd43db226ac37316808 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 13:38:28 -0700 Subject: [PATCH 04/25] update hemisphere VBO on ui size change --- interface/src/ui/ApplicationOverlay.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 8ba0b42910..e228e39976 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -692,8 +692,11 @@ void ApplicationOverlay::renderTexturedHemisphere() { static VerticesIndices vbo(0, 0); int vertices = slices * (stacks - 1) + 1; int indices = slices * 2 * 3 * (stacks - 2) + slices * 3; - //We only generate the VBO once - if (vbo.first == 0) { + + static float oldTextureFOV = _textureFov; + //We only generate the VBO when the _textureFov changes + if (vbo.first == 0 || oldTextureFOV != _textureFov) { + oldTextureFOV = _textureFov; TextureVertex* vertexData = new TextureVertex[vertices]; TextureVertex* vertex = vertexData; for (int i = 0; i < stacks - 1; i++) { @@ -718,7 +721,9 @@ void ApplicationOverlay::renderTexturedHemisphere() { vertex->uv.y = 0.5f; vertex++; - glGenBuffers(1, &vbo.first); + if (vbo.first == 0){ + glGenBuffers(1, &vbo.first); + } glBindBuffer(GL_ARRAY_BUFFER, vbo.first); const int BYTES_PER_VERTEX = sizeof(TextureVertex); glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); From 230af7f5a7820ddf632c28bf2258f279440fd537 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 13:49:35 -0700 Subject: [PATCH 05/25] Stopped clamping the magnification --- interface/src/ui/ApplicationOverlay.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index e228e39976..830a3f843b 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -415,20 +415,6 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY) mouseX -= magnifyWidth / 2; mouseY -= magnifyHeight / 2; - //clamp the magnification - if (mouseX < 0) { - magnifyWidth += mouseX; - mouseX = 0; - } else if (mouseX + magnifyWidth > widgetWidth) { - magnifyWidth = widgetWidth - mouseX; - } - if (mouseY < 0) { - magnifyHeight += mouseY; - mouseY = 0; - } else if (mouseY + magnifyHeight > widgetHeight) { - magnifyHeight = widgetHeight - mouseY; - } - float newWidth = magnifyWidth * magnification; float newHeight = magnifyHeight * magnification; From c593117ac5bccd39d09625298d54c596846bf411 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 15:03:09 -0700 Subject: [PATCH 06/25] New reticle for sixense and oculus mouse movement --- .../resources/images/sixense-reticle.png | Bin 0 -> 26350 bytes interface/src/ui/ApplicationOverlay.cpp | 62 ++++++++++-------- interface/src/ui/ApplicationOverlay.h | 2 + 3 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 interface/resources/images/sixense-reticle.png diff --git a/interface/resources/images/sixense-reticle.png b/interface/resources/images/sixense-reticle.png new file mode 100644 index 0000000000000000000000000000000000000000..b168b25106b99693112c3b2f3a351b4a49733325 GIT binary patch literal 26350 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 int mouseY = application->getMouseY(); + + //lazily load crosshair texture + if (_crosshairTexture == 0) { + _crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png")); + } + glEnable(GL_TEXTURE_2D); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, _crosshairTexture); + + + + if (OculusManager::isConnected() && application->getLastMouseMoveType() == QEvent::MouseMove) { const float pointerWidth = 10; const float pointerHeight = 10; - const float crossPad = 4; _numMagnifiers = 1; _mouseX[0] = application->getMouseX(); @@ -289,25 +304,22 @@ void ApplicationOverlay::renderPointers() { glBegin(GL_QUADS); - glColor3f(1, 0, 0); + glColor3f(0.0f, 198.0f / 255.0f, 244.0f / 255.0f); //Horizontal crosshair - glVertex2i(mouseX, mouseY - crossPad); - glVertex2i(mouseX + pointerWidth, mouseY - crossPad); - glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight + crossPad); - glVertex2i(mouseX, mouseY - pointerHeight + crossPad); - - //Vertical crosshair - glVertex2i(mouseX + crossPad, mouseY); - glVertex2i(mouseX + pointerWidth - crossPad, mouseY); - glVertex2i(mouseX + pointerWidth - crossPad, mouseY - pointerHeight); - glVertex2i(mouseX + crossPad, mouseY - pointerHeight); + glTexCoord2d(0.0f, 0.0f); glVertex2i(mouseX, mouseY); + glTexCoord2d(1.0f, 0.0f); glVertex2i(mouseX + pointerWidth, mouseY); + glTexCoord2d(1.0f, 1.0f); glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight); + glTexCoord2d(0.0f, 1.0f); glVertex2i(mouseX, mouseY - pointerHeight); glEnd(); } else if (application->getLastMouseMoveType() == CONTROLLER_MOVE_EVENT && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { //only render controller pointer if we aren't already rendering a mouse pointer renderControllerPointer(); } + + glDisable(GL_TEXTURE_2D); + } void ApplicationOverlay::renderControllerPointer() { @@ -349,13 +361,12 @@ void ApplicationOverlay::renderControllerPointer() { float pointerWidth = 40; float pointerHeight = 40; - float crossPad = 16; + //if we have the oculus, we should make the cursor smaller since it will be //magnified if (OculusManager::isConnected()) { - pointerWidth /= 4; - pointerHeight /= 4; - crossPad /= 4; + pointerWidth /= 2; + pointerHeight /= 2; _mouseX[_numMagnifiers] = mouseX; _mouseY[_numMagnifiers] = mouseY; @@ -368,19 +379,12 @@ void ApplicationOverlay::renderControllerPointer() { glBegin(GL_QUADS); - glColor3f(0.0f, 0.0f, 1.0f); + glColor3f(0.0f, 198.0f/255.0f, 244.0f/255.0f); - //Horizontal crosshair - glVertex2i(mouseX, mouseY - crossPad); - glVertex2i(mouseX + pointerWidth, mouseY - crossPad); - glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight + crossPad); - glVertex2i(mouseX, mouseY - pointerHeight + crossPad); - - //Vertical crosshair - glVertex2i(mouseX + crossPad, mouseY); - glVertex2i(mouseX + pointerWidth - crossPad, mouseY); - glVertex2i(mouseX + pointerWidth - crossPad, mouseY - pointerHeight); - glVertex2i(mouseX + crossPad, mouseY - pointerHeight); + glTexCoord2d(0.0f, 0.0f); glVertex2i(mouseX, mouseY); + glTexCoord2d(1.0f, 0.0f); glVertex2i(mouseX + pointerWidth, mouseY); + glTexCoord2d(1.0f, 1.0f); glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight); + glTexCoord2d(0.0f, 1.0f); glVertex2i(mouseX, mouseY - pointerHeight); glEnd(); } diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index b6066099fa..dc1d3d641f 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -59,6 +59,8 @@ private: int _mouseX[2]; int _mouseY[2]; int _numMagnifiers; + + GLuint _crosshairTexture; }; #endif // hifi_ApplicationOverlay_h \ No newline at end of file From cb1669653d771c510667caef7ee899d4640a148f Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 15:05:23 -0700 Subject: [PATCH 07/25] Mouse reticle bigger in oculus --- interface/src/ui/ApplicationOverlay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 2b98360b02..9222cb092d 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -292,8 +292,8 @@ void ApplicationOverlay::renderPointers() { if (OculusManager::isConnected() && application->getLastMouseMoveType() == QEvent::MouseMove) { - const float pointerWidth = 10; - const float pointerHeight = 10; + const float pointerWidth = 20; + const float pointerHeight = 20; _numMagnifiers = 1; _mouseX[0] = application->getMouseX(); From 587c0e5a9d1ca50b661b8ee310b8186a895d082c Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 16:01:59 -0700 Subject: [PATCH 08/25] Render Oculus pointers separate from texture for better quality --- interface/src/ui/ApplicationOverlay.cpp | 108 +++++++++++++++++++----- interface/src/ui/ApplicationOverlay.h | 3 +- 2 files changed, 88 insertions(+), 23 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 9222cb092d..fe6baadf66 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -37,8 +37,6 @@ ApplicationOverlay::ApplicationOverlay() : _uiType(HEMISPHERE), _crosshairTexture(0) { - - } ApplicationOverlay::~ApplicationOverlay() { @@ -259,6 +257,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glEnd(); } + renderControllerPointersOculus(); + glPopMatrix(); glDepthMask(GL_TRUE); @@ -289,8 +289,6 @@ void ApplicationOverlay::renderPointers() { glBindTexture(GL_TEXTURE_2D, _crosshairTexture); - - if (OculusManager::isConnected() && application->getLastMouseMoveType() == QEvent::MouseMove) { const float pointerWidth = 20; const float pointerHeight = 20; @@ -299,30 +297,36 @@ void ApplicationOverlay::renderPointers() { _mouseX[0] = application->getMouseX(); _mouseY[0] = application->getMouseY(); - mouseX -= pointerWidth / 2.0f; - mouseY += pointerHeight / 2.0f; + //If we are in oculus, render reticle later - glBegin(GL_QUADS); - glColor3f(0.0f, 198.0f / 255.0f, 244.0f / 255.0f); + if (!OculusManager::isConnected()) { - //Horizontal crosshair - glTexCoord2d(0.0f, 0.0f); glVertex2i(mouseX, mouseY); - glTexCoord2d(1.0f, 0.0f); glVertex2i(mouseX + pointerWidth, mouseY); - glTexCoord2d(1.0f, 1.0f); glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight); - glTexCoord2d(0.0f, 1.0f); glVertex2i(mouseX, mouseY - pointerHeight); + mouseX -= pointerWidth / 2.0f; + mouseY += pointerHeight / 2.0f; - glEnd(); + glBegin(GL_QUADS); + + glColor3f(0.0f, 198.0f / 255.0f, 244.0f / 255.0f); + + //Horizontal crosshair + glTexCoord2d(0.0f, 0.0f); glVertex2i(mouseX, mouseY); + glTexCoord2d(1.0f, 0.0f); glVertex2i(mouseX + pointerWidth, mouseY); + glTexCoord2d(1.0f, 1.0f); glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight); + glTexCoord2d(0.0f, 1.0f); glVertex2i(mouseX, mouseY - pointerHeight); + + glEnd(); + } } else if (application->getLastMouseMoveType() == CONTROLLER_MOVE_EVENT && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { //only render controller pointer if we aren't already rendering a mouse pointer - renderControllerPointer(); + renderControllerPointers(); } - + glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } -void ApplicationOverlay::renderControllerPointer() { +void ApplicationOverlay::renderControllerPointers() { Application* application = Application::getInstance(); QGLWidget* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); @@ -365,13 +369,12 @@ void ApplicationOverlay::renderControllerPointer() { //if we have the oculus, we should make the cursor smaller since it will be //magnified if (OculusManager::isConnected()) { - pointerWidth /= 2; - pointerHeight /= 2; _mouseX[_numMagnifiers] = mouseX; _mouseY[_numMagnifiers] = mouseY; _numMagnifiers++; - + //If oculus is enabled, we draw the crosshairs later + continue; } mouseX -= pointerWidth / 2.0f; @@ -390,13 +393,74 @@ void ApplicationOverlay::renderControllerPointer() { } } +void ApplicationOverlay::renderControllerPointersOculus() { + Application* application = Application::getInstance(); + QGLWidget* glWidget = application->getGLWidget(); + + const int widgetWidth = glWidget->width(); + const int widgetHeight = glWidget->height(); + + const float reticleSize = 50.0f; + + glBindTexture(GL_TEXTURE_2D, _crosshairTexture); + glDisable(GL_DEPTH_TEST); + + for (int i = 0; i < _numMagnifiers; i++) { + + float mouseX = (float)_mouseX[i]; + float mouseY = (float)_mouseY[i]; + mouseX -= reticleSize / 2; + mouseY += reticleSize / 2; + + // Get position on hemisphere using angle + if (_uiType == HEMISPHERE) { + + //Get new UV coordinates from our magnification window + float newULeft = mouseX / widgetWidth; + float newURight = (mouseX + reticleSize) / widgetWidth; + float newVBottom = 1.0 - mouseY / widgetHeight; + float newVTop = 1.0 - (mouseY - reticleSize) / widgetHeight; + + // Project our position onto the hemisphere using the UV coordinates + float lX = sin((newULeft - 0.5f) * _textureFov); + float rX = sin((newURight - 0.5f) * _textureFov); + float bY = sin((newVBottom - 0.5f) * _textureFov); + float tY = sin((newVTop - 0.5f) * _textureFov); + + float dist; + //Bottom Left + dist = sqrt(lX * lX + bY * bY); + float blZ = sqrt(1.0f - dist * dist); + //Top Left + dist = sqrt(lX * lX + tY * tY); + float tlZ = sqrt(1.0f - dist * dist); + //Bottom Right + dist = sqrt(rX * rX + bY * bY); + float brZ = sqrt(1.0f - dist * dist); + //Top Right + dist = sqrt(rX * rX + tY * tY); + float trZ = sqrt(1.0f - dist * dist); + + glBegin(GL_QUADS); + + glColor3f(0.0f, 198.0f / 255.0f, 244.0f / 255.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(lX, tY, -tlZ); + glTexCoord2f(1.0f, 0.0f); glVertex3f(rX, tY, -trZ); + glTexCoord2f(1.0f, 1.0f); glVertex3f(rX, bY, -brZ); + glTexCoord2f(0.0f, 1.0f); glVertex3f(lX, bY, -blZ); + + glEnd(); + } + } + glEnable(GL_DEPTH_TEST); +} + //Renders a small magnification of the currently bound texture at the coordinates void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY) { Application* application = Application::getInstance(); QGLWidget* glWidget = application->getGLWidget(); - MyAvatar* myAvatar = application->getAvatar(); - const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); float leftX, rightX, leftZ, rightZ, topZ, bottomZ; diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index dc1d3d641f..71f78d606d 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -44,7 +44,8 @@ private: typedef QPair VerticesIndices; void renderPointers(); - void renderControllerPointer(); + void renderControllerPointers(); + void renderControllerPointersOculus(); void renderMagnifier(int mouseX, int mouseY); void renderAudioMeter(); void renderStatsAndLogs(); From 53d4cc795a62b767f27c975267ba37de596afe7f Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 16:09:45 -0700 Subject: [PATCH 09/25] Removed unused UI types that clutter code --- interface/src/ui/ApplicationOverlay.cpp | 272 ++++++++---------------- interface/src/ui/ApplicationOverlay.h | 7 +- 2 files changed, 85 insertions(+), 194 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index fe6baadf66..2ef5665bee 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -34,7 +34,6 @@ ApplicationOverlay::ApplicationOverlay() : _oculusAngle(65.0f * RADIANS_PER_DEGREE), _distance(0.5f), _textureFov(DEFAULT_OCULUS_UI_ANGULAR_SIZE * RADIANS_PER_DEGREE), - _uiType(HEMISPHERE), _crosshairTexture(0) { } @@ -157,25 +156,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { MyAvatar* myAvatar = application->getAvatar(); const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); - // Get vertical FoV of the displayed overlay texture - const float halfVerticalAngle = _oculusAngle / 2.0f; - const float overlayAspectRatio = glWidget->width() / (float)glWidget->height(); - const float halfOverlayHeight = _distance * tan(halfVerticalAngle); - const float overlayHeight = halfOverlayHeight * 2.0f; - - // The more vertices, the better the curve - const int numHorizontalVertices = 20; - const int numVerticalVertices = 20; - // U texture coordinate width at each quad - const float quadTexWidth = 1.0f / (numHorizontalVertices - 1); - const float quadTexHeight = 1.0f / (numVerticalVertices - 1); - - // Get horizontal angle and angle increment from vertical angle and aspect ratio - const float horizontalAngle = halfVerticalAngle * 2.0f * overlayAspectRatio; - const float angleIncrement = horizontalAngle / (numHorizontalVertices - 1); - const float halfHorizontalAngle = horizontalAngle / 2; - - const float verticalAngleIncrement = _oculusAngle / (numVerticalVertices - 1); glActiveTexture(GL_TEXTURE0); @@ -211,8 +191,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.01f); - float leftX, rightX, leftZ, rightZ, topZ, bottomZ; - //Draw the magnifiers for (int i = 0; i < _numMagnifiers; i++) { renderMagnifier(_mouseX[i], _mouseY[i]); @@ -221,42 +199,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glDepthMask(GL_FALSE); glDisable(GL_ALPHA_TEST); - //TODO: Remove immediate mode in favor of VBO - if (_uiType == HEMISPHERE) { - renderTexturedHemisphere(); - } else{ - glBegin(GL_QUADS); - // Place the vertices in a semicircle curve around the camera - for (int i = 0; i < numHorizontalVertices - 1; i++) { - for (int j = 0; j < numVerticalVertices - 1; j++) { - - // Calculate the X and Z coordinates from the angles and radius from camera - leftX = sin(angleIncrement * i - halfHorizontalAngle) * _distance; - rightX = sin(angleIncrement * (i + 1) - halfHorizontalAngle) * _distance; - leftZ = -cos(angleIncrement * i - halfHorizontalAngle) * _distance; - rightZ = -cos(angleIncrement * (i + 1) - halfHorizontalAngle) * _distance; - if (_uiType == 2) { - topZ = -cos((verticalAngleIncrement * (j + 1) - halfVerticalAngle) * overlayAspectRatio) * _distance; - bottomZ = -cos((verticalAngleIncrement * j - halfVerticalAngle) * overlayAspectRatio) * _distance; - } else { - topZ = -99999; - bottomZ = -99999; - } - - glTexCoord2f(quadTexWidth * i, (j + 1) * quadTexHeight); - glVertex3f(leftX, (j + 1) * quadTexHeight * overlayHeight - halfOverlayHeight, max(topZ, leftZ)); - glTexCoord2f(quadTexWidth * (i + 1), (j + 1) * quadTexHeight); - glVertex3f(rightX, (j + 1) * quadTexHeight * overlayHeight - halfOverlayHeight, max(topZ, rightZ)); - glTexCoord2f(quadTexWidth * (i + 1), j * quadTexHeight); - glVertex3f(rightX, j * quadTexHeight * overlayHeight - halfOverlayHeight, max(bottomZ, rightZ)); - glTexCoord2f(quadTexWidth * i, j * quadTexHeight); - glVertex3f(leftX, j * quadTexHeight * overlayHeight - halfOverlayHeight, max(bottomZ, leftZ)); - } - } - - glEnd(); - } - + renderTexturedHemisphere(); + renderControllerPointersOculus(); glPopMatrix(); @@ -411,106 +355,12 @@ void ApplicationOverlay::renderControllerPointersOculus() { float mouseY = (float)_mouseY[i]; mouseX -= reticleSize / 2; mouseY += reticleSize / 2; - - // Get position on hemisphere using angle - if (_uiType == HEMISPHERE) { - - //Get new UV coordinates from our magnification window - float newULeft = mouseX / widgetWidth; - float newURight = (mouseX + reticleSize) / widgetWidth; - float newVBottom = 1.0 - mouseY / widgetHeight; - float newVTop = 1.0 - (mouseY - reticleSize) / widgetHeight; - - // Project our position onto the hemisphere using the UV coordinates - float lX = sin((newULeft - 0.5f) * _textureFov); - float rX = sin((newURight - 0.5f) * _textureFov); - float bY = sin((newVBottom - 0.5f) * _textureFov); - float tY = sin((newVTop - 0.5f) * _textureFov); - - float dist; - //Bottom Left - dist = sqrt(lX * lX + bY * bY); - float blZ = sqrt(1.0f - dist * dist); - //Top Left - dist = sqrt(lX * lX + tY * tY); - float tlZ = sqrt(1.0f - dist * dist); - //Bottom Right - dist = sqrt(rX * rX + bY * bY); - float brZ = sqrt(1.0f - dist * dist); - //Top Right - dist = sqrt(rX * rX + tY * tY); - float trZ = sqrt(1.0f - dist * dist); - - glBegin(GL_QUADS); - - glColor3f(0.0f, 198.0f / 255.0f, 244.0f / 255.0f); - - glTexCoord2f(0.0f, 0.0f); glVertex3f(lX, tY, -tlZ); - glTexCoord2f(1.0f, 0.0f); glVertex3f(rX, tY, -trZ); - glTexCoord2f(1.0f, 1.0f); glVertex3f(rX, bY, -brZ); - glTexCoord2f(0.0f, 1.0f); glVertex3f(lX, bY, -blZ); - - glEnd(); - } - } - glEnable(GL_DEPTH_TEST); -} - -//Renders a small magnification of the currently bound texture at the coordinates -void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY) -{ - Application* application = Application::getInstance(); - QGLWidget* glWidget = application->getGLWidget(); - - float leftX, rightX, leftZ, rightZ, topZ, bottomZ; - - const int widgetWidth = glWidget->width(); - const int widgetHeight = glWidget->height(); - const float magnification = 4.0f; - - // Get vertical FoV of the displayed overlay texture - const float halfVerticalAngle = _oculusAngle / 2.0f; - const float overlayAspectRatio = glWidget->width() / (float)glWidget->height(); - const float halfOverlayHeight = _distance * tan(halfVerticalAngle); - - // Get horizontal angle and angle increment from vertical angle and aspect ratio - const float horizontalAngle = halfVerticalAngle * 2.0f * overlayAspectRatio; - const float halfHorizontalAngle = horizontalAngle / 2; - - float magnifyWidth = 80.0f; - float magnifyHeight = 60.0f; - - mouseX -= magnifyWidth / 2; - mouseY -= magnifyHeight / 2; - - float newWidth = magnifyWidth * magnification; - float newHeight = magnifyHeight * magnification; - - // Magnification Texture Coordinates - float magnifyULeft = mouseX / (float)widgetWidth; - float magnifyURight = (mouseX + magnifyWidth) / (float)widgetWidth; - float magnifyVBottom = 1.0f - mouseY / (float)widgetHeight; - float magnifyVTop = 1.0f - (mouseY + magnifyHeight) / (float)widgetHeight; - - // Coordinates of magnification overlay - float newMouseX = (mouseX + magnifyWidth / 2) - newWidth / 2.0f; - float newMouseY = (mouseY + magnifyHeight / 2) + newHeight / 2.0f; - - // Get angle on the UI - float leftAngle = (newMouseX / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle; - float rightAngle = ((newMouseX + newWidth) / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle; - - float bottomAngle = (newMouseY / (float)widgetHeight) * _oculusAngle - halfVerticalAngle; - float topAngle = ((newMouseY - newHeight) / (float)widgetHeight) * _oculusAngle - halfVerticalAngle; - - // Get position on hemisphere using angle - if (_uiType == HEMISPHERE) { - + //Get new UV coordinates from our magnification window - float newULeft = newMouseX / widgetWidth; - float newURight = (newMouseX + newWidth) / widgetWidth; - float newVBottom = 1.0 - newMouseY / widgetHeight; - float newVTop = 1.0 - (newMouseY - newHeight) / widgetHeight; + float newULeft = mouseX / widgetWidth; + float newURight = (mouseX + reticleSize) / widgetWidth; + float newVBottom = 1.0 - mouseY / widgetHeight; + float newVTop = 1.0 - (mouseY - reticleSize) / widgetHeight; // Project our position onto the hemisphere using the UV coordinates float lX = sin((newULeft - 0.5f) * _textureFov); @@ -534,40 +384,86 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY) glBegin(GL_QUADS); - glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(lX, tY, -tlZ); - glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rX, tY, -trZ); - glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rX, bY, -brZ); - glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(lX, bY, -blZ); - - glEnd(); - - } else { - leftX = sin(leftAngle) * _distance; - rightX = sin(rightAngle) * _distance; - leftZ = -cos(leftAngle) * _distance; - rightZ = -cos(rightAngle) * _distance; - if (_uiType == CURVED_SEMICIRCLE) { - topZ = -cos(topAngle * overlayAspectRatio) * _distance; - bottomZ = -cos(bottomAngle * overlayAspectRatio) * _distance; - } else { - // Dont want to use topZ or bottomZ for SEMICIRCLE - topZ = -99999; - bottomZ = -99999; - } - - float bottomY = (1.0 - newMouseY / (float)widgetHeight) * halfOverlayHeight * 2.0f - halfOverlayHeight; - float topY = bottomY + (newHeight / widgetHeight) * halfOverlayHeight * 2; - - //TODO: Remove immediate mode in favor of VBO - glBegin(GL_QUADS); - - glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(leftX, topY, max(topZ, leftZ)); - glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rightX, topY, max(topZ, rightZ)); - glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rightX, bottomY, max(bottomZ, rightZ)); - glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(leftX, bottomY, max(bottomZ, leftZ)); + glColor3f(0.0f, 198.0f / 255.0f, 244.0f / 255.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(lX, tY, -tlZ); + glTexCoord2f(1.0f, 0.0f); glVertex3f(rX, tY, -trZ); + glTexCoord2f(1.0f, 1.0f); glVertex3f(rX, bY, -brZ); + glTexCoord2f(0.0f, 1.0f); glVertex3f(lX, bY, -blZ); glEnd(); + } + glEnable(GL_DEPTH_TEST); +} + +//Renders a small magnification of the currently bound texture at the coordinates +void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY) +{ + Application* application = Application::getInstance(); + QGLWidget* glWidget = application->getGLWidget(); + + + const int widgetWidth = glWidget->width(); + const int widgetHeight = glWidget->height(); + const float magnification = 4.0f; + + float magnifyWidth = 80.0f; + float magnifyHeight = 60.0f; + + mouseX -= magnifyWidth / 2; + mouseY -= magnifyHeight / 2; + + float newWidth = magnifyWidth * magnification; + float newHeight = magnifyHeight * magnification; + + // Magnification Texture Coordinates + float magnifyULeft = mouseX / (float)widgetWidth; + float magnifyURight = (mouseX + magnifyWidth) / (float)widgetWidth; + float magnifyVBottom = 1.0f - mouseY / (float)widgetHeight; + float magnifyVTop = 1.0f - (mouseY + magnifyHeight) / (float)widgetHeight; + + // Coordinates of magnification overlay + float newMouseX = (mouseX + magnifyWidth / 2) - newWidth / 2.0f; + float newMouseY = (mouseY + magnifyHeight / 2) + newHeight / 2.0f; + + // Get position on hemisphere using angle + + //Get new UV coordinates from our magnification window + float newULeft = newMouseX / widgetWidth; + float newURight = (newMouseX + newWidth) / widgetWidth; + float newVBottom = 1.0 - newMouseY / widgetHeight; + float newVTop = 1.0 - (newMouseY - newHeight) / widgetHeight; + + // Project our position onto the hemisphere using the UV coordinates + float lX = sin((newULeft - 0.5f) * _textureFov); + float rX = sin((newURight - 0.5f) * _textureFov); + float bY = sin((newVBottom - 0.5f) * _textureFov); + float tY = sin((newVTop - 0.5f) * _textureFov); + + float dist; + //Bottom Left + dist = sqrt(lX * lX + bY * bY); + float blZ = sqrt(1.0f - dist * dist); + //Top Left + dist = sqrt(lX * lX + tY * tY); + float tlZ = sqrt(1.0f - dist * dist); + //Bottom Right + dist = sqrt(rX * rX + bY * bY); + float brZ = sqrt(1.0f - dist * dist); + //Top Right + dist = sqrt(rX * rX + tY * tY); + float trZ = sqrt(1.0f - dist * dist); + + glBegin(GL_QUADS); + + glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(lX, tY, -tlZ); + glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rX, tY, -trZ); + glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rX, bY, -brZ); + glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(lX, bY, -blZ); + + glEnd(); + } void ApplicationOverlay::renderAudioMeter() { diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 71f78d606d..53a0125dae 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -19,8 +19,6 @@ class QOpenGLFramebufferObject; class ApplicationOverlay { public: - enum UIType { HEMISPHERE, SEMICIRCLE, CURVED_SEMICIRCLE }; - ApplicationOverlay(); ~ApplicationOverlay(); @@ -31,9 +29,7 @@ public: // Getters QOpenGLFramebufferObject* getFramebufferObject(); - - void setUIType(UIType uiType) { _uiType = uiType; } - + private: // Interleaved vertex data struct TextureVertex { @@ -56,7 +52,6 @@ private: float _oculusAngle; float _distance; float _textureFov; - UIType _uiType; int _mouseX[2]; int _mouseY[2]; int _numMagnifiers; From bef625d237a14dd12bf36c79d61518ab919bc515 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 13 Jun 2014 16:13:43 -0700 Subject: [PATCH 10/25] Removed pointless Code --- interface/src/ui/ApplicationOverlay.cpp | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 2ef5665bee..13630290fd 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -234,33 +234,10 @@ void ApplicationOverlay::renderPointers() { if (OculusManager::isConnected() && application->getLastMouseMoveType() == QEvent::MouseMove) { - const float pointerWidth = 20; - const float pointerHeight = 20; - + //If we are in oculus, render reticle later _numMagnifiers = 1; _mouseX[0] = application->getMouseX(); _mouseY[0] = application->getMouseY(); - - //If we are in oculus, render reticle later - - - if (!OculusManager::isConnected()) { - - mouseX -= pointerWidth / 2.0f; - mouseY += pointerHeight / 2.0f; - - glBegin(GL_QUADS); - - glColor3f(0.0f, 198.0f / 255.0f, 244.0f / 255.0f); - - //Horizontal crosshair - glTexCoord2d(0.0f, 0.0f); glVertex2i(mouseX, mouseY); - glTexCoord2d(1.0f, 0.0f); glVertex2i(mouseX + pointerWidth, mouseY); - glTexCoord2d(1.0f, 1.0f); glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight); - glTexCoord2d(0.0f, 1.0f); glVertex2i(mouseX, mouseY - pointerHeight); - - glEnd(); - } } else if (application->getLastMouseMoveType() == CONTROLLER_MOVE_EVENT && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { //only render controller pointer if we aren't already rendering a mouse pointer renderControllerPointers(); From 3fbde70f96694979d62a5ae22ae0f8bf17f147f1 Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Sun, 15 Jun 2014 21:05:23 +0200 Subject: [PATCH 11/25] Added functions to test usleep, msleep and sleep for accuracy. --- libraries/shared/src/SharedUtil.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index f29e8e3345..06a5ab8137 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "OctalCode.h" #include "SharedUtil.h" @@ -415,13 +416,16 @@ void printVoxelCode(unsigned char* voxelCode) { #ifdef _WIN32 void usleep(int waitTime) { - __int64 time1 = 0, time2 = 0, sysFreq = 0; - - QueryPerformanceCounter((LARGE_INTEGER *)&time1); - QueryPerformanceFrequency((LARGE_INTEGER *)&sysFreq); - do { - QueryPerformanceCounter((LARGE_INTEGER *)&time2); - } while( (time2 - time1) < waitTime); + quint64 compTime = waitTime + usecTimestampNow(); + quint64 compTimeSleep = compTime - 2000; + while (true) { + if (usecTimestampNow() < compTimeSleep) { + QThread::msleep(1); + } + if (usecTimestampNow() >= compTime) { + break; + } + } } #endif From 05900420a56ee37087f88a72fa84ee955850a5ae Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Sun, 15 Jun 2014 21:07:03 +0200 Subject: [PATCH 12/25] Replaced windows usleep version with a non busy waiting high accuracy version. This fixes the high CPU load for the windows servers too! --- interface/src/Util.cpp | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 07ca65b286..5ce1435bd6 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -21,6 +21,8 @@ #include +#include + #include "InterfaceConfig.h" #include "ui/TextRenderer.h" #include "VoxelConstants.h" @@ -409,8 +411,44 @@ void runTimingTests() { float NSEC_TO_USEC = 1.0f / 1000.0f; elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; - qDebug("QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs / (float) numTests); + qDebug("QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs); + // Test sleep functions for accuracy + startTime.start(); + QThread::msleep(1); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("QThread::msleep(1) ms: %f", elapsedUsecs / 1000.0f); + + startTime.start(); + QThread::sleep(1); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("QThread::sleep(1) ms: %f", elapsedUsecs / 1000.0f); + + startTime.start(); + usleep(1); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("usleep(1) ms: %f", elapsedUsecs / 1000.0f); + + startTime.start(); + usleep(10); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("usleep(10) ms: %f", elapsedUsecs / 1000.0f); + + startTime.start(); + usleep(100); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("usleep(100) ms: %f", elapsedUsecs / 1000.0f); + + startTime.start(); + usleep(1000); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("usleep(1000) ms: %f", elapsedUsecs / 1000.0f); + + startTime.start(); + usleep(15000); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("usleep(15000) ms: %f", elapsedUsecs / 1000.0f); + // Random number generation startTime.start(); for (int i = 0; i < numTests; i++) { From 8c700d43f34ef26bc389ad2f2374b9e57b2c1289 Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Sun, 15 Jun 2014 21:08:14 +0200 Subject: [PATCH 13/25] Modified CALLBACK_ACCELERATOR_RATIO for windows because some systems need larger input buffer to work fine. --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 2cbe3a062f..271bcd5279 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1419,7 +1419,7 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) // proportional to the accelerator ratio. #ifdef Q_OS_WIN -const float Audio::CALLBACK_ACCELERATOR_RATIO = 0.4f; +const float Audio::CALLBACK_ACCELERATOR_RATIO = 0.1f; #endif #ifdef Q_OS_MAC From 94e58e9559bff84fd60233acdf3aaa3f9b4d314f Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Mon, 16 Jun 2014 10:04:56 -0700 Subject: [PATCH 14/25] Fixed coding standard and made getCursorPixelRangeMultiplier more clear --- interface/src/devices/SixenseManager.cpp | 10 ++++++++-- interface/src/ui/ApplicationOverlay.cpp | 8 +++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index ed55dc4c66..43dadaef1c 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -185,9 +185,14 @@ void SixenseManager::update(float deltaTime) { #endif // HAVE_SIXENSE } +const float MAXIMUM_PIXEL_RANGE_MULT = 2.0f; +const float MINIMUM_PIXEL_RANGE_MULT = 0.4f; +const float RANGE_MULT = (MAXIMUM_PIXEL_RANGE_MULT - MINIMUM_PIXEL_RANGE_MULT) * 0.01; + +//Returns a multiplier to be applied to the cursor range for the controllers float SixenseManager::getCursorPixelRangeMultiplier() const { - //scales (0,100) to (0.4,2.0) - return ((Menu::getInstance()->getSixenseReticleMoveSpeed()) * 0.008f + 0.2f) * 2.0f; + //scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT) + return Menu::getInstance()->getSixenseReticleMoveSpeed() * RANGE_MULT + MINIMUM_PIXEL_RANGE_MULT; } #ifdef HAVE_SIXENSE @@ -356,6 +361,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { float xAngle = (atan2(direction.z, direction.x) + M_PI_2); float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); + // Get the pixel range over which the xAngle and yAngle are scaled float cursorRange = widget->width() * getCursorPixelRangeMultiplier(); pos.setX(widget->width() / 2.0f + cursorRange * xAngle); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 13630290fd..aedc81facc 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -46,6 +46,8 @@ ApplicationOverlay::~ApplicationOverlay() { const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; +const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; + // Renders the overlays either to a texture or to the screen void ApplicationOverlay::renderOverlay(bool renderToTexture) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); @@ -222,7 +224,6 @@ void ApplicationOverlay::renderPointers() { int mouseX = application->getMouseX(); int mouseY = application->getMouseY(); - //lazily load crosshair texture if (_crosshairTexture == 0) { _crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png")); @@ -274,6 +275,7 @@ void ApplicationOverlay::renderControllerPointers() { float xAngle = (atan2(direction.z, direction.x) + M_PI_2) ; float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); + // Get the pixel range over which the xAngle and yAngle are scaled float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMultiplier(); int mouseX = glWidget->width() / 2.0f + cursorRange * xAngle; @@ -303,7 +305,7 @@ void ApplicationOverlay::renderControllerPointers() { glBegin(GL_QUADS); - glColor3f(0.0f, 198.0f/255.0f, 244.0f/255.0f); + glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]); glTexCoord2d(0.0f, 0.0f); glVertex2i(mouseX, mouseY); glTexCoord2d(1.0f, 0.0f); glVertex2i(mouseX + pointerWidth, mouseY); @@ -361,7 +363,7 @@ void ApplicationOverlay::renderControllerPointersOculus() { glBegin(GL_QUADS); - glColor3f(0.0f, 198.0f / 255.0f, 244.0f / 255.0f); + glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]); glTexCoord2f(0.0f, 0.0f); glVertex3f(lX, tY, -tlZ); glTexCoord2f(1.0f, 0.0f); glVertex3f(rX, tY, -trZ); From 031fe323ea5e98b5d37167da3c983ce7960d45b8 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Mon, 16 Jun 2014 10:12:09 -0700 Subject: [PATCH 15/25] Got rid of some verbosity --- interface/src/devices/SixenseManager.cpp | 13 +++++++------ interface/src/devices/SixenseManager.h | 2 +- interface/src/ui/ApplicationOverlay.cpp | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 43dadaef1c..2c62a58800 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -185,14 +185,15 @@ void SixenseManager::update(float deltaTime) { #endif // HAVE_SIXENSE } -const float MAXIMUM_PIXEL_RANGE_MULT = 2.0f; -const float MINIMUM_PIXEL_RANGE_MULT = 0.4f; -const float RANGE_MULT = (MAXIMUM_PIXEL_RANGE_MULT - MINIMUM_PIXEL_RANGE_MULT) * 0.01; +//Constants for getCursorPixelRangeMultiplier() +const float MIN_PIXEL_RANGE_MULT = 0.4f; +const float MAX_PIXEL_RANGE_MULT = 2.0f; +const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01; //Returns a multiplier to be applied to the cursor range for the controllers -float SixenseManager::getCursorPixelRangeMultiplier() const { +float SixenseManager::getCursorPixelRangeMult() const { //scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT) - return Menu::getInstance()->getSixenseReticleMoveSpeed() * RANGE_MULT + MINIMUM_PIXEL_RANGE_MULT; + return Menu::getInstance()->getSixenseReticleMoveSpeed() * RANGE_MULT + MIN_PIXEL_RANGE_MULT; } #ifdef HAVE_SIXENSE @@ -362,7 +363,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); // Get the pixel range over which the xAngle and yAngle are scaled - float cursorRange = widget->width() * getCursorPixelRangeMultiplier(); + float cursorRange = widget->width() * getCursorPixelRangeMult(); pos.setX(widget->width() / 2.0f + cursorRange * xAngle); pos.setY(widget->height() / 2.0f + cursorRange * yAngle); diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 41e061a25b..8803c2c006 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -42,7 +42,7 @@ public: ~SixenseManager(); void update(float deltaTime); - float getCursorPixelRangeMultiplier() const; + float getCursorPixelRangeMult() const; public slots: diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index aedc81facc..471ff20d66 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -276,7 +276,7 @@ void ApplicationOverlay::renderControllerPointers() { float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); // Get the pixel range over which the xAngle and yAngle are scaled - float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMultiplier(); + float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMult(); int mouseX = glWidget->width() / 2.0f + cursorRange * xAngle; int mouseY = glWidget->height() / 2.0f + cursorRange * yAngle; From af3b2a9d0f6c4f8e332e5a766915d53d309afad0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 16 Jun 2014 10:43:13 -0700 Subject: [PATCH 16/25] Update LocationManager::goTo to use new addresses API The new API address is now used for goTo when # or @ isn't present Fixed the multiple locations popup to show when multiple locations are found --- interface/src/Menu.cpp | 8 ++- interface/src/avatar/MyAvatar.cpp | 64 +++++++++++----------- interface/src/avatar/MyAvatar.h | 1 + interface/src/location/LocationManager.cpp | 57 ++++++------------- interface/src/location/LocationManager.h | 7 +-- 5 files changed, 58 insertions(+), 79 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0c6a3efa24..46b2bfc806 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1002,7 +1002,9 @@ bool Menu::goToDestination(QString destination) { } void Menu::goTo(QString destination) { - LocationManager::getInstance().goTo(destination); + LocationManager* manager = &LocationManager::getInstance(); + manager->goTo(destination); + connect(manager, &LocationManager::multipleDestinationsFound, getInstance(), &Menu::multipleDestinationsDecision); } void Menu::goTo() { @@ -1091,9 +1093,9 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson int userResponse = msgBox.exec(); if (userResponse == QMessageBox::Ok) { - Application::getInstance()->getAvatar()->goToLocationFromResponse(userData); + Application::getInstance()->getAvatar()->goToLocationFromAddress(userData["address"].toObject()); } else if (userResponse == QMessageBox::Open) { - Application::getInstance()->getAvatar()->goToLocationFromResponse(userData); + Application::getInstance()->getAvatar()->goToLocationFromAddress(placeData["address"].toObject()); } LocationManager* manager = reinterpret_cast(sender()); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a14152aa04..54ed641d72 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1626,44 +1626,46 @@ void MyAvatar::resetSize() { } void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) { - if (jsonObject["status"].toString() == "success") { - - // send a node kill request, indicating to other clients that they should play the "disappeared" effect - sendKillAvatar(); - QJsonObject locationObject = jsonObject["data"].toObject()["address"].toObject(); - QString positionString = locationObject["position"].toString(); - QString orientationString = locationObject["orientation"].toString(); - QString domainHostnameString = locationObject["domain"].toString(); - - qDebug() << "Changing domain to" << domainHostnameString << - ", position to" << positionString << - ", and orientation to" << orientationString; - - QStringList coordinateItems = positionString.split(','); - QStringList orientationItems = orientationString.split(','); - - NodeList::getInstance()->getDomainHandler().setHostname(domainHostnameString); - - // orient the user to face the target - glm::quat newOrientation = glm::quat(glm::radians(glm::vec3(orientationItems[0].toFloat(), - orientationItems[1].toFloat(), - orientationItems[2].toFloat()))) - * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - setOrientation(newOrientation); - - // move the user a couple units away - const float DISTANCE_TO_USER = 2.0f; - glm::vec3 newPosition = glm::vec3(coordinateItems[0].toFloat(), coordinateItems[1].toFloat(), - coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; - setPosition(newPosition); - emit transformChanged(); + goToLocationFromAddress(locationObject); } else { QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found."); } } +void MyAvatar::goToLocationFromAddress(const QJsonObject& locationObject) { + // send a node kill request, indicating to other clients that they should play the "disappeared" effect + sendKillAvatar(); + + QString positionString = locationObject["position"].toString(); + QString orientationString = locationObject["orientation"].toString(); + QString domainHostnameString = locationObject["domain"].toString(); + + qDebug() << "Changing domain to" << domainHostnameString << + ", position to" << positionString << + ", and orientation to" << orientationString; + + QStringList coordinateItems = positionString.split(','); + QStringList orientationItems = orientationString.split(','); + + NodeList::getInstance()->getDomainHandler().setHostname(domainHostnameString); + + // orient the user to face the target + glm::quat newOrientation = glm::quat(glm::radians(glm::vec3(orientationItems[0].toFloat(), + orientationItems[1].toFloat(), + orientationItems[2].toFloat()))) + * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + setOrientation(newOrientation); + + // move the user a couple units away + const float DISTANCE_TO_USER = 2.0f; + glm::vec3 newPosition = glm::vec3(coordinateItems[0].toFloat(), coordinateItems[1].toFloat(), + coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; + setPosition(newPosition); + emit transformChanged(); +} + void MyAvatar::updateMotionBehaviorsFromMenu() { Menu* menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::ObeyEnvironmentalGravity)) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d99102c356..2fbc488feb 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -129,6 +129,7 @@ public slots: void resetSize(); void goToLocationFromResponse(const QJsonObject& jsonObject); + void goToLocationFromAddress(const QJsonObject& jsonObject); // Set/Get update the thrust that will move the avatar around void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index f80c331df4..f1fd5e71f1 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -16,10 +16,11 @@ const QString GET_USER_ADDRESS = "/api/v1/users/%1/address"; const QString GET_PLACE_ADDRESS = "/api/v1/places/%1/address"; +const QString GET_ADDRESSES = "/api/v1/addresses/%1"; const QString POST_PLACE_CREATE = "/api/v1/places/"; -LocationManager::LocationManager() : _userData(), _placeData() { +LocationManager::LocationManager() { }; @@ -74,59 +75,37 @@ void LocationManager::goTo(QString destination) { // go to coordinate destination or to Username if (!goToDestination(destination)) { - // reset data on local variables - _userData = QJsonObject(); - _placeData = QJsonObject(); - destination = QString(QUrl::toPercentEncoding(destination)); JSONCallbackParameters callbackParams; callbackParams.jsonCallbackReceiver = this; - callbackParams.jsonCallbackMethod = "goToUserFromResponse"; - AccountManager::getInstance().authenticatedRequest(GET_USER_ADDRESS.arg(destination), - QNetworkAccessManager::GetOperation, - callbackParams); - - callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; - AccountManager::getInstance().authenticatedRequest(GET_PLACE_ADDRESS.arg(destination), + callbackParams.jsonCallbackMethod = "goToAddressFromResponse"; + AccountManager::getInstance().authenticatedRequest(GET_ADDRESSES.arg(destination), QNetworkAccessManager::GetOperation, callbackParams); } } -void LocationManager::goToUserFromResponse(const QJsonObject& jsonObject) { - _userData = jsonObject; - checkForMultipleDestinations(); -} +void LocationManager::goToAddressFromResponse(const QJsonObject& responseData) { + QJsonValue status = responseData["status"]; + qDebug() << responseData; + if (!status.isUndefined() && status.toString() == "success") { + const QJsonObject& data = responseData["data"].toObject(); + const QJsonValue& userObject = data["user"]; + const QJsonValue& placeObject = data["place"]; -void LocationManager::goToLocationFromResponse(const QJsonObject& jsonObject) { - _placeData = jsonObject; - checkForMultipleDestinations(); -} - -void LocationManager::checkForMultipleDestinations() { - if (!_userData.isEmpty() && !_placeData.isEmpty()) { - if (_userData.contains("status") && _userData["status"].toString() == "success" && - _placeData.contains("status") && _placeData["status"].toString() == "success") { - emit multipleDestinationsFound(_userData, _placeData); - return; + if (!placeObject.isUndefined() && !userObject.isUndefined()) { + emit multipleDestinationsFound(userObject.toObject(), placeObject.toObject()); + } else if (placeObject.isUndefined()) { + Application::getInstance()->getAvatar()->goToLocationFromAddress(userObject.toObject()["address"].toObject()); + } else { + Application::getInstance()->getAvatar()->goToLocationFromAddress(placeObject.toObject()["address"].toObject()); } - - if (_userData.contains("status") && _userData["status"].toString() == "success") { - Application::getInstance()->getAvatar()->goToLocationFromResponse(_userData); - return; - } - - if (_placeData.contains("status") && _placeData["status"].toString() == "success") { - Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData); - return; - } - + } else { QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found."); } } void LocationManager::goToUser(QString userName) { - JSONCallbackParameters callbackParams; callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; diff --git a/interface/src/location/LocationManager.h b/interface/src/location/LocationManager.h index ac66b3d08b..b781f3f54e 100644 --- a/interface/src/location/LocationManager.h +++ b/interface/src/location/LocationManager.h @@ -39,11 +39,7 @@ public: bool goToDestination(QString destination); private: - QJsonObject _userData; - QJsonObject _placeData; - void replaceLastOccurrence(const QChar search, const QChar replace, QString& string); - void checkForMultipleDestinations(); signals: void creationCompleted(LocationManager::NamedLocationCreateResponse response); @@ -52,8 +48,7 @@ signals: private slots: void namedLocationDataReceived(const QJsonObject& data); void errorDataReceived(QNetworkReply::NetworkError error, const QString& message); - void goToLocationFromResponse(const QJsonObject& jsonObject); - void goToUserFromResponse(const QJsonObject& jsonObject); + void goToAddressFromResponse(const QJsonObject& jsonObject); }; From d5aa12db7d9bb99d634f9e08796a2141baca57b2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 16 Jun 2014 10:55:05 -0700 Subject: [PATCH 17/25] Added models support to inspect.js --- examples/inspect.js | 49 ++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/examples/inspect.js b/examples/inspect.js index 28db1e7735..af63957ec3 100644 --- a/examples/inspect.js +++ b/examples/inspect.js @@ -177,30 +177,45 @@ function keyReleaseEvent(event) { function mousePressEvent(event) { if (alt && !isActive) { - isActive = true; mouseLastX = event.x; mouseLastY = event.y; // Compute trajectories related values var pickRay = Camera.computePickRay(mouseLastX, mouseLastY); - var intersection = Voxels.findRayIntersection(pickRay); + var voxelIntersection = Voxels.findRayIntersection(pickRay); + var modelIntersection = Models.findRayIntersection(pickRay); position = Camera.getPosition(); - avatarTarget = MyAvatar.getTargetAvatarPosition(); - voxelTarget = intersection.intersection; - if (Vec3.length(Vec3.subtract(avatarTarget, position)) < Vec3.length(Vec3.subtract(voxelTarget, position))) { - if (avatarTarget.x != 0 || avatarTarget.y != 0 || avatarTarget.z != 0) { - center = avatarTarget; - } else { - center = voxelTarget; - } - } else { - if (voxelTarget.x != 0 || voxelTarget.y != 0 || voxelTarget.z != 0) { - center = voxelTarget; - } else { - center = avatarTarget; - } + var avatarTarget = MyAvatar.getTargetAvatarPosition(); + var voxelTarget = voxelIntersection.intersection; + + + var distance = -1; + var string; + + if (modelIntersection.intersects && modelIntersection.accurate) { + distance = modelIntersection.distance; + center = modelIntersection.modelProperties.position; + string = "Inspecting model"; + } + + if ((distance == -1 || Vec3.length(Vec3.subtract(avatarTarget, position)) < distance) && + (avatarTarget.x != 0 || avatarTarget.y != 0 || avatarTarget.z != 0)) { + distance = Vec3.length(Vec3.subtract(avatarTarget, position)); + center = avatarTarget; + string = "Inspecting avatar"; + } + + if ((distance == -1 || Vec3.length(Vec3.subtract(voxelTarget, position)) < distance) && + (voxelTarget.x != 0 || voxelTarget.y != 0 || voxelTarget.z != 0)) { + distance = Vec3.length(Vec3.subtract(voxelTarget, position)); + center = voxelTarget; + string = "Inspecting voxel"; + } + + if (distance == -1) { + return; } vector = Vec3.subtract(position, center); @@ -209,6 +224,8 @@ function mousePressEvent(event) { altitude = Math.asin(vector.y / Vec3.length(vector)); Camera.keepLookingAt(center); + print(string); + isActive = true; } } From b3b3a72946202da452d1846879fa5f271047c899 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 16 Jun 2014 10:55:34 -0700 Subject: [PATCH 18/25] Disable editModels.js mouse events when ALT is pressed. (no conflict with inspect.js) --- examples/editModels.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/examples/editModels.js b/examples/editModels.js index 93a34b9a3a..53633d3c0c 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -691,6 +691,10 @@ function rayPlaneIntersection(pickRay, point, normal) { } function mousePressEvent(event) { + if (altIsPressed) { + return; + } + mouseLastPosition = { x: event.x, y: event.y }; modelSelected = false; var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); @@ -790,6 +794,10 @@ var oldModifier = 0; var modifier = 0; var wasShifted = false; function mouseMoveEvent(event) { + if (altIsPressed) { + return; + } + var pickRay = Camera.computePickRay(event.x, event.y); if (!modelSelected) { @@ -894,6 +902,10 @@ function mouseMoveEvent(event) { } function mouseReleaseEvent(event) { + if (altIsPressed) { + return; + } + modelSelected = false; glowedModelID.id = -1; @@ -962,4 +974,16 @@ Menu.menuItemEvent.connect(function(menuItem){ } }); +// handling of inspect.js concurrence +altIsPressed = false; +Controller.keyPressEvent.connect(function(event) { + if (event.text == "ALT") { + altIsPressed = true; + } +}); +Controller.keyReleaseEvent.connect(function(event) { + if (event.text == "ALT") { + altIsPressed = false; + } +}); From 978b7521dba30fb90e5eb39a2a5075dcd9fcd1ff Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 16 Jun 2014 11:30:47 -0700 Subject: [PATCH 19/25] Move connect call for multiple destinations to constructor --- interface/src/Menu.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 46b2bfc806..8f023e607f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -165,6 +165,8 @@ Menu::Menu() : Qt::Key_At, this, SLOT(goTo())); + connect(&LocationManager::getInstance(), &LocationManager::multipleDestinationsFound, + this, &Menu::multipleDestinationsDecision); addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model"); addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead())); @@ -1002,9 +1004,7 @@ bool Menu::goToDestination(QString destination) { } void Menu::goTo(QString destination) { - LocationManager* manager = &LocationManager::getInstance(); - manager->goTo(destination); - connect(manager, &LocationManager::multipleDestinationsFound, getInstance(), &Menu::multipleDestinationsDecision); + LocationManager::getInstance().goTo(destination); } void Menu::goTo() { From 9faf9d7749d4f50d4a03d6b44cbb43314ad86b36 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 16 Jun 2014 11:43:04 -0700 Subject: [PATCH 20/25] Remove extra connect and disconnect for multipleDestinationsDecision --- interface/src/Menu.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f2f68a3594..f4fb8a363f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1074,9 +1074,7 @@ bool Menu::goToURL(QString location) { } void Menu::goToUser(const QString& user) { - LocationManager* manager = &LocationManager::getInstance(); - manager->goTo(user); - connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); + LocationManager::getInstance().goTo(user); } /// Open a url, shortcutting any "hifi" scheme URLs to the local application. @@ -1104,7 +1102,6 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson } LocationManager* manager = reinterpret_cast(sender()); - disconnect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); } void Menu::muteEnvironment() { From d08b63b2476244721ae1d601ad47d681bae28ea3 Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Mon, 16 Jun 2014 23:30:28 +0200 Subject: [PATCH 21/25] changed 2000 into a constant defined inline --- libraries/shared/src/SharedUtil.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 06a5ab8137..e4d2e1c835 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -416,8 +416,9 @@ void printVoxelCode(unsigned char* voxelCode) { #ifdef _WIN32 void usleep(int waitTime) { + const quint64 BUSY_LOOP_USECS = 2000; quint64 compTime = waitTime + usecTimestampNow(); - quint64 compTimeSleep = compTime - 2000; + quint64 compTimeSleep = compTime - BUSY_LOOP_USECS; while (true) { if (usecTimestampNow() < compTimeSleep) { QThread::msleep(1); From f367e1840d20e9c758c5b41a9e01d65da6b22cbd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 17 Jun 2014 10:37:35 -0700 Subject: [PATCH 22/25] Added a detached mode by default in inpect.js --- examples/inspect.js | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/examples/inspect.js b/examples/inspect.js index af63957ec3..b292d5f609 100644 --- a/examples/inspect.js +++ b/examples/inspect.js @@ -34,6 +34,7 @@ var noMode = 0; var orbitMode = 1; var radialMode = 2; var panningMode = 3; +var detachedMode = 4; var mode = noMode; @@ -48,6 +49,9 @@ var radius = 0.0; var azimuth = 0.0; var altitude = 0.0; +var avatarPosition; +var avatarOrientation; + function handleRadialMode(dx, dy) { azimuth += dx / AZIMUTH_RATE; @@ -108,7 +112,7 @@ function restoreCameraState() { } function handleModes() { - var newMode = noMode; + var newMode = (mode == noMode) ? noMode : detachedMode; if (alt) { if (control) { if (shift) { @@ -121,6 +125,22 @@ function handleModes() { } } + // if entering detachMode + if (newMode == detachedMode && mode != detachedMode) { + avatarPosition = MyAvatar.position; + avatarOrientation = MyAvatar.orientation; + } + // if leaving detachMode + if (mode == detachedMode && newMode == detachedMode && + (avatarPosition.x != MyAvatar.position.x || + avatarPosition.y != MyAvatar.position.y || + avatarPosition.z != MyAvatar.position.z || + avatarOrientation.x != MyAvatar.orientation.x || + avatarOrientation.y != MyAvatar.orientation.y || + avatarOrientation.z != MyAvatar.orientation.z || + avatarOrientation.w != MyAvatar.orientation.w)) { + newMode = noMode; + } // if leaving noMode if (mode == noMode && newMode != noMode) { saveCameraState(); @@ -252,6 +272,10 @@ function mouseMoveEvent(event) { } } +function update() { + handleModes(); +} + function scriptEnding() { if (mode != noMode) { restoreCameraState(); @@ -265,4 +289,5 @@ Controller.mousePressEvent.connect(mousePressEvent); Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Controller.mouseMoveEvent.connect(mouseMoveEvent); +Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From b37b9fb09745f6468904c22df80ae97b14bb3f76 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 17 Jun 2014 11:59:26 -0700 Subject: [PATCH 23/25] remove warnings about unused variables --- interface/src/Menu.cpp | 2 -- interface/src/ui/ApplicationOverlay.cpp | 3 --- 2 files changed, 5 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0dccf6256b..5c8c2e97aa 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1104,8 +1104,6 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson } else if (userResponse == QMessageBox::Open) { Application::getInstance()->getAvatar()->goToLocationFromAddress(placeData["address"].toObject()); } - - LocationManager* manager = reinterpret_cast(sender()); } void Menu::muteEnvironment() { diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 471ff20d66..af4648244f 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -154,7 +154,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { Application* application = Application::getInstance(); - QGLWidget* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); @@ -221,8 +220,6 @@ void ApplicationOverlay::renderPointers() { Application* application = Application::getInstance(); // Render a crosshair over the mouse when in Oculus _numMagnifiers = 0; - int mouseX = application->getMouseX(); - int mouseY = application->getMouseY(); //lazily load crosshair texture if (_crosshairTexture == 0) { From 3f3632564254fc5c1a164cfe04eb02a74aed739d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 17 Jun 2014 11:59:37 -0700 Subject: [PATCH 24/25] remove warnings about signed/unsigned comparison --- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/audio/AudioMixerClientData.cpp | 10 +++++----- domain-server/src/DomainServer.cpp | 2 +- libraries/audio/src/Sound.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index b3909660e2..d96fce450a 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -335,7 +335,7 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData(); // enumerate the ARBs attached to the otherNode and add all that should be added to mix - for (unsigned int i = 0; i < otherNodeClientData->getRingBuffers().size(); i++) { + for (int i = 0; i < otherNodeClientData->getRingBuffers().size(); i++) { PositionalAudioRingBuffer* otherNodeBuffer = otherNodeClientData->getRingBuffers()[i]; if ((*otherNode != *node diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 7fb2a7dcab..9494e927a9 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -25,14 +25,14 @@ AudioMixerClientData::AudioMixerClientData() : } AudioMixerClientData::~AudioMixerClientData() { - for (unsigned int i = 0; i < _ringBuffers.size(); i++) { + for (int i = 0; i < _ringBuffers.size(); i++) { // delete this attached PositionalAudioRingBuffer delete _ringBuffers[i]; } } AvatarAudioRingBuffer* AudioMixerClientData::getAvatarAudioRingBuffer() const { - for (unsigned int i = 0; i < _ringBuffers.size(); i++) { + for (int i = 0; i < _ringBuffers.size(); i++) { if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Microphone) { return (AvatarAudioRingBuffer*) _ringBuffers[i]; } @@ -79,7 +79,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { InjectedAudioRingBuffer* matchingInjectedRingBuffer = NULL; - for (unsigned int i = 0; i < _ringBuffers.size(); i++) { + for (int i = 0; i < _ringBuffers.size(); i++) { if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Injector && ((InjectedAudioRingBuffer*) _ringBuffers[i])->getStreamIdentifier() == streamIdentifier) { matchingInjectedRingBuffer = (InjectedAudioRingBuffer*) _ringBuffers[i]; @@ -99,7 +99,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { } void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples) { - for (unsigned int i = 0; i < _ringBuffers.size(); i++) { + for (int i = 0; i < _ringBuffers.size(); i++) { if (_ringBuffers[i]->shouldBeAddedToMix(jitterBufferLengthSamples)) { // this is a ring buffer that is ready to go // set its flag so we know to push its buffer when all is said and done @@ -113,7 +113,7 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSam } void AudioMixerClientData::pushBuffersAfterFrameSend() { - for (unsigned int i = 0; i < _ringBuffers.size(); i++) { + for (int i = 0; i < _ringBuffers.size(); i++) { // this was a used buffer, push the output pointer forwards PositionalAudioRingBuffer* audioBuffer = _ringBuffers[i]; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index f7185063a9..d55a9b52ca 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -659,7 +659,7 @@ void DomainServer::readAvailableDatagrams() { wasNoisyTimerStarted = true; } - const quint64 NOISY_MESSAGE_INTERVAL_MSECS = 5 * 1000; + const qint64 NOISY_MESSAGE_INTERVAL_MSECS = 5 * 1000; if (requestAssignment.getType() != Assignment::AgentType || noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) { diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 9bc78f2303..7ef3afdf29 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -258,7 +258,7 @@ void Sound::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& ou // Now pull out the data quint32 outputAudioByteArraySize = qFromLittleEndian(dataHeader.descriptor.size); outputAudioByteArray.resize(outputAudioByteArraySize); - if (waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize) != outputAudioByteArraySize) { + if (waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize) != (int)outputAudioByteArraySize) { qDebug() << "Error reading WAV file"; } From 9a3f8508cfaf3e7662a131f3d647a97b67ea5de2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 17 Jun 2014 12:12:53 -0700 Subject: [PATCH 25/25] add support for inside out ray intersection on AACube and AABox --- libraries/octree/src/AABox.cpp | 37 ++++++++++++++++++++++++++++++++ libraries/octree/src/AACube.cpp | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/libraries/octree/src/AABox.cpp b/libraries/octree/src/AABox.cpp index 7aa4d76134..409b362b24 100644 --- a/libraries/octree/src/AABox.cpp +++ b/libraries/octree/src/AABox.cpp @@ -180,6 +180,18 @@ static bool findIntersection(float origin, float direction, float corner, float return false; } +// finds the intersection between a ray and the inside facing plane on one axis +static bool findInsideOutIntersection(float origin, float direction, float corner, float size, float& distance) { + if (direction > EPSILON) { + distance = -1.0f * (origin - (corner + size)) / direction; + return true; + } else if (direction < -EPSILON) { + distance = -1.0f * (origin - corner) / direction; + return true; + } + return false; +} + bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const { // handle the trivial cases where the expanded box contains the start or end if (expandedContains(start, expansion) || expandedContains(end, expansion)) { @@ -207,9 +219,34 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { // handle the trivial case where the box contains the origin if (contains(origin)) { + // We still want to calculate the distance from the origin to the inside out plane + float axisDistance; + if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) { + distance = axisDistance; + face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE; + return true; + } + if ((findInsideOutIntersection(origin.y, direction.y, _corner.y, _scale.y, axisDistance) && axisDistance >= 0 && + isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x) && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) { + distance = axisDistance; + face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE; + return true; + } + if ((findInsideOutIntersection(origin.z, direction.z, _corner.z, _scale.z, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) && + isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { + distance = axisDistance; + face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; + return true; + } + // This case is unexpected, but mimics the previous behavior for inside out intersections distance = 0; return true; } + // check each axis float axisDistance; if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 && diff --git a/libraries/octree/src/AACube.cpp b/libraries/octree/src/AACube.cpp index 443d725a38..5a8839db4e 100644 --- a/libraries/octree/src/AACube.cpp +++ b/libraries/octree/src/AACube.cpp @@ -169,6 +169,18 @@ static bool findIntersection(float origin, float direction, float corner, float return false; } +// finds the intersection between a ray and the inside facing plane on one axis +static bool findInsideOutIntersection(float origin, float direction, float corner, float size, float& distance) { + if (direction > EPSILON) { + distance = -1.0f * (origin - (corner + size)) / direction; + return true; + } else if (direction < -EPSILON) { + distance = -1.0f * (origin - corner) / direction; + return true; + } + return false; +} + bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const { // handle the trivial cases where the expanded box contains the start or end if (expandedContains(start, expansion) || expandedContains(end, expansion)) { @@ -196,9 +208,35 @@ bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { // handle the trivial case where the box contains the origin if (contains(origin)) { + + // We still want to calculate the distance from the origin to the inside out plane + float axisDistance; + if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) { + distance = axisDistance; + face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE; + return true; + } + if ((findInsideOutIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 && + isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale) && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) { + distance = axisDistance; + face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE; + return true; + } + if ((findInsideOutIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && + isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { + distance = axisDistance; + face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; + return true; + } + // This case is unexpected, but mimics the previous behavior for inside out intersections distance = 0; return true; } + // check each axis float axisDistance; if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&