From 2e2d03c58b502d4731a8bb850b224d1033d05fe6 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 26 Jun 2014 16:53:19 -0700 Subject: [PATCH 01/29] added ESC to restore to original camera in concertCamera.js --- examples/concertCamera.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/concertCamera.js b/examples/concertCamera.js index 7280958bc6..96218e697f 100644 --- a/examples/concertCamera.js +++ b/examples/concertCamera.js @@ -56,6 +56,11 @@ function keyPressEvent(event) { Camera.setPosition(cameraLocations[choice - 1]); Camera.keepLookingAt(cameraLookAts[choice - 1]); } + if (event.text == "ESC") { + cameraNumber = 0; + freeCamera = false; + restoreCameraState(); + } if (event.text == "0") { // Show camera location in log var cameraLocation = Camera.getPosition(); From f072c04b4cf6ca211b47d4c8e7906055aecd0471 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 27 Jun 2014 09:30:51 -0700 Subject: [PATCH 02/29] hair is a separate class --- interface/src/Hair.cpp | 35 +++++++++++++++++++++++++++++++ interface/src/Hair.h | 35 +++++++++++++++++++++++++++++++ interface/src/avatar/Avatar.cpp | 8 +++++++ interface/src/avatar/Avatar.h | 2 ++ interface/src/avatar/MyAvatar.cpp | 6 ++++++ 5 files changed, 86 insertions(+) create mode 100644 interface/src/Hair.cpp create mode 100644 interface/src/Hair.h diff --git a/interface/src/Hair.cpp b/interface/src/Hair.cpp new file mode 100644 index 0000000000..a23312eba1 --- /dev/null +++ b/interface/src/Hair.cpp @@ -0,0 +1,35 @@ +// +// Hair.cpp +// interface/src +// +// Created by Philip on June 26, 2014 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Creates single flexible vertlet-integrated strands that can be used for hair/fur/grass + +#include "Hair.h" + +#include "Util.h" +#include "world.h" + + +Hair::Hair() { + qDebug() << "Creating Hair"; + } + +void Hair::simulate(float deltaTime) { +} + +void Hair::render() { + // + // Before calling this function, translate/rotate to the origin of the owning object + glPushMatrix(); + glColor3f(1.0f, 1.0f, 0.0f); + glutSolidSphere(1.0f, 15, 15); + glPopMatrix(); +} + + diff --git a/interface/src/Hair.h b/interface/src/Hair.h new file mode 100644 index 0000000000..e4dc3778c3 --- /dev/null +++ b/interface/src/Hair.h @@ -0,0 +1,35 @@ +// +// Hair.h +// interface/src +// +// Created by Philip on June 26, 2014 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_Hair_h +#define hifi_Hair_h + +#include + +#include +#include + +#include "GeometryUtil.h" +#include "InterfaceConfig.h" +#include "Util.h" + + +class Hair { +public: + Hair(); + void simulate(float deltaTime); + void render(); + +private: + + }; + +#endif // hifi_Hair_h diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5a294bb2a5..769d0398a2 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -143,6 +143,11 @@ void Avatar::simulate(float deltaTime) { if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) { simulateHair(deltaTime); } + + foreach (Hair* hair, _hairs) { + hair->simulate(deltaTime); + } + } // update position by velocity, and subtract the change added earlier for gravity @@ -380,6 +385,9 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { getHead()->render(1.0f, modelRenderMode); if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) { renderHair(); + foreach (Hair* hair, _hairs) { + hair->render(); + } } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index f20db1019d..369cd7e688 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -19,6 +19,7 @@ #include +#include "Hair.h" #include "Hand.h" #include "Head.h" #include "InterfaceConfig.h" @@ -159,6 +160,7 @@ signals: void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision); protected: + QVector _hairs; SkeletonModel _skeletonModel; QVector _attachmentModels; float _bodyYawDelta; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7367f64d73..cfdf7e057a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -199,6 +199,9 @@ void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("MyAvatar::simulate/hair Simulate"); if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) { simulateHair(deltaTime); + foreach (Hair* hair, _hairs) { + hair->simulate(deltaTime); + } } } @@ -860,6 +863,9 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { getHead()->render(1.0f, modelRenderMode); if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) { renderHair(); + foreach (Hair* hair, _hairs) { + hair->render(); + } } } getHand()->render(true, modelRenderMode); From 370540cc339423a176c2bc8597910641954b22d7 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Sat, 28 Jun 2014 13:00:51 -0700 Subject: [PATCH 03/29] squeezeHands uses different animation on clench/release --- examples/squeezeHands.js | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/examples/squeezeHands.js b/examples/squeezeHands.js index da720734e1..f920692a3b 100644 --- a/examples/squeezeHands.js +++ b/examples/squeezeHands.js @@ -18,13 +18,16 @@ var RIGHT = 1; var lastLeftFrame = 0; var lastRightFrame = 0; -var LAST_FRAME = 11.0; // What is the number of the last frame we want to use in the animation? -var SMOOTH_FACTOR = 0.80; +var leftDirection = true; +var rightDirection = true; +var LAST_FRAME = 15.0; // What is the number of the last frame we want to use in the animation? +var SMOOTH_FACTOR = 0.0; +var MAX_FRAMES = 30.0; Script.update.connect(function(deltaTime) { - var leftTriggerValue = Math.sqrt(Controller.getTriggerValue(LEFT)); - var rightTriggerValue = Math.sqrt(Controller.getTriggerValue(RIGHT)); + var leftTriggerValue = Controller.getTriggerValue(LEFT); + var rightTriggerValue = Controller.getTriggerValue(RIGHT); var leftFrame, rightFrame; @@ -32,10 +35,31 @@ Script.update.connect(function(deltaTime) { leftFrame = (leftTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastLeftFrame * SMOOTH_FACTOR; rightFrame = (rightTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastRightFrame * SMOOTH_FACTOR; - + if (!leftDirection) { + leftFrame = MAX_FRAMES - leftFrame; + } + if (!rightDirection) { + rightFrame = MAX_FRAMES - rightFrame; + } + + if ((leftTriggerValue == 1.0) && (leftDirection == true)) { + leftDirection = false; + lastLeftFrame = MAX_FRAMES - leftFrame; + } else if ((leftTriggerValue == 0.0) && (leftDirection == false)) { + leftDirection = true; + lastLeftFrame = leftFrame; + } + if ((rightTriggerValue == 1.0) && (rightDirection == true)) { + rightDirection = false; + lastRightFrame = MAX_FRAMES - rightFrame; + } else if ((rightTriggerValue == 0.0) && (rightDirection == false)) { + rightDirection = true; + lastRightFrame = rightFrame; + } + if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){ MyAvatar.stopAnimation(leftHandAnimation); - MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, leftFrame, leftFrame); + MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, leftFrame, leftFrame); } if ((rightFrame != lastRightFrame) && rightHandAnimation.length) { MyAvatar.stopAnimation(rightHandAnimation); From 8b04a9c8b600d3c3eb8c81f21af4d7419b9bc391 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Jul 2014 16:19:05 -0700 Subject: [PATCH 04/29] Add toggle for user interface display - "/" toggles UI (incl. stats if displayed); menu View > User Interface - "%" = toggle status; menu View > Stats - Acts on normal, 3DTV, and Oculus display. --- interface/src/Application.cpp | 22 ++++++++++------------ interface/src/Menu.cpp | 6 ++---- interface/src/Menu.h | 2 +- interface/src/devices/OculusManager.cpp | 2 +- interface/src/devices/TV3DManager.cpp | 9 +++++++-- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9b2ed7b63d..0c469102cc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -683,16 +683,11 @@ void Application::paintGL() { _rearMirrorTools->render(true); } - { - PerformanceTimer perfTimer("paintGL/renderOverlay"); - //If alpha is 1, we can render directly to the screen. - if (_applicationOverlay.getAlpha() == 1.0f) { - _applicationOverlay.renderOverlay(); - } else { - //Render to to texture so we can fade it - _applicationOverlay.renderOverlay(true); - _applicationOverlay.displayOverlayTexture(); - } + PerformanceTimer perfTimer("paintGL/renderOverlay"); + // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() + _applicationOverlay.renderOverlay(true); + if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { + _applicationOverlay.displayOverlayTexture(); } } @@ -1012,6 +1007,9 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror); } break; + case Qt::Key_Slash: + Menu::getInstance()->triggerOption(MenuOption::UserInterface); + break; case Qt::Key_F: if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::DisplayFrustum); @@ -1031,7 +1029,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; break; - case Qt::Key_Slash: + case Qt::Key_Percent: Menu::getInstance()->triggerOption(MenuOption::Stats); break; case Qt::Key_Plus: @@ -2793,7 +2791,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { if (!selfAvatarOnly) { // Render the world box - if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats) && Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { PerformanceTimer perfTimer("paintGL/displaySide/renderWorldBox"); renderWorldBox(); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index dba5feca9e..7b80b0b529 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -276,6 +276,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, appInstance, SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0, false, @@ -326,7 +327,7 @@ Menu::Menu() : addDisabledActionAndSeparator(viewMenu, "Stats"); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Percent); addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); @@ -407,9 +408,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::GlowWhenSpeaking, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); - QMenu* oculusOptionsMenu = developerMenu->addMenu("Oculus Options"); - addCheckableActionToQMenuAndActionHash(oculusOptionsMenu, MenuOption::DisplayOculusOverlays, 0, true); - QMenu* sixenseOptionsMenu = developerMenu->addMenu("Sixense Options"); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 06b5c5c9f4..2d13a81b1f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -349,7 +349,6 @@ namespace MenuOption { const QString DisplayModelBounds = "Display Model Bounds"; const QString DisplayModelElementProxy = "Display Model Element Bounds"; const QString DisplayModelElementChildProxies = "Display Model Element Children"; - const QString DisplayOculusOverlays = "Display Oculus Overlays"; const QString DisplayTimingDetails = "Display Timing Details"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString EchoLocalAudio = "Echo Local Audio"; @@ -438,6 +437,7 @@ namespace MenuOption { const QString UploadAttachment = "Upload Attachment Model"; const QString UploadHead = "Upload Head Model"; const QString UploadSkeleton = "Upload Skeleton Model"; + const QString UserInterface = "UserInterface"; const QString Visage = "Visage"; const QString VoxelMode = "Cycle Voxel Mode"; const QString Voxels = "Voxels"; diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 199c313119..1260dc7036 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -269,7 +269,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() applicationOverlay.renderOverlay(true); - const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::DisplayOculusOverlays); + const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::UserInterface); //Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index 25d3ff892a..3b42c03f2d 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -100,6 +100,7 @@ void TV3DManager::display(Camera& whichCamera) { // We only need to render the overlays to a texture once, then we just render the texture as a quad // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() applicationOverlay.renderOverlay(true); + const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::UserInterface); if (glowEnabled) { Application::getInstance()->getGlowEffect()->prepare(); @@ -128,7 +129,9 @@ void TV3DManager::display(Camera& whichCamera) { glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); - applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); + if (displayOverlays) { + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); + } } glPopMatrix(); glDisable(GL_SCISSOR_TEST); @@ -154,7 +157,9 @@ void TV3DManager::display(Camera& whichCamera) { glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); - applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); + if (displayOverlays) { + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); + } } glPopMatrix(); glDisable(GL_SCISSOR_TEST); From 97ca6d70fa73e87cfb6497012bf2496bee1f976e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Jul 2014 17:15:46 -0700 Subject: [PATCH 05/29] Fixed performance timer scope --- interface/src/Application.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0c469102cc..96fee69bda 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -683,11 +683,13 @@ void Application::paintGL() { _rearMirrorTools->render(true); } - PerformanceTimer perfTimer("paintGL/renderOverlay"); - // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() - _applicationOverlay.renderOverlay(true); - if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { - _applicationOverlay.displayOverlayTexture(); + { + PerformanceTimer perfTimer("paintGL/renderOverlay"); + // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() + _applicationOverlay.renderOverlay(true); + if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { + _applicationOverlay.displayOverlayTexture(); + } } } From 2ad2b6cd1ce6cd6b49d68d2c71275ab76c212718 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Jul 2014 18:23:37 -0700 Subject: [PATCH 06/29] Resize the overlay framebuffer when the application window is resized --- interface/src/Application.cpp | 1 + interface/src/ui/ApplicationOverlay.cpp | 6 ++++++ interface/src/ui/ApplicationOverlay.h | 1 + 3 files changed, 8 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 96fee69bda..ab31eb09cd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -712,6 +712,7 @@ void Application::resizeGL(int width, int height) { resetCamerasOnResizeGL(_myCamera, width, height); glViewport(0, 0, width, height); // shouldn't this account for the menu??? + _applicationOverlay.resize(); updateProjectionMatrix(); glLoadIdentity(); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 4c445958ec..879c7cda32 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -998,6 +998,12 @@ void ApplicationOverlay::renderTexturedHemisphere() { } +void ApplicationOverlay::resize() { + delete _framebufferObject; + _framebufferObject = NULL; + // _framebufferObject is recreated at the correct size the next time it is accessed via getFramebufferObject(). +} + QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() { if (!_framebufferObject) { _framebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size()); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 7c1f87d575..5e8d06ab89 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -32,6 +32,7 @@ public: void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov); void computeOculusPickRay(float x, float y, glm::vec3& direction) const; void getClickLocation(int &x, int &y) const; + void resize(); // Getters QOpenGLFramebufferObject* getFramebufferObject(); From d1cddb4f2854c844579f9031a2a800abc022a22d Mon Sep 17 00:00:00 2001 From: mpursley Date: Mon, 7 Jul 2014 01:02:04 -0700 Subject: [PATCH 07/29] adding "export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake" for qt5.2.1 --- BUILD.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BUILD.md b/BUILD.md index 674f0d24cc..e1935bd1c5 100644 --- a/BUILD.md +++ b/BUILD.md @@ -25,6 +25,8 @@ In order for CMake to find the Qt5 find modules, you will need to set an ENV var For example, a Qt5 5.2.0 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment). export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.2.0/clang_64/lib/cmake/ + ... or ... + export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake The path it needs to be set to will depend on where and how Qt5 was installed. From f13c7634ad8af64fc2369fd897fd24f76f61200a Mon Sep 17 00:00:00 2001 From: mpursley Date: Mon, 7 Jul 2014 01:08:11 -0700 Subject: [PATCH 08/29] adding "export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.2.1/lib/cmake" for qt5.2.1 --- BUILD.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index e1935bd1c5..93aafcc3e0 100644 --- a/BUILD.md +++ b/BUILD.md @@ -24,11 +24,12 @@ In order for CMake to find the Qt5 find modules, you will need to set an ENV var For example, a Qt5 5.2.0 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment). +The path it needs to be set to will depend on where and how Qt5 was installed. e.g. + export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.2.0/clang_64/lib/cmake/ - ... or ... + export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.2.1/lib/cmake export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake -The path it needs to be set to will depend on where and how Qt5 was installed. ####Generating build files Create a build directory in the root of your checkout and then run the CMake build from there. This will keep the rest of the directory clean. From db1a9fa09b40c36ef0e751323db066880211b2df Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Jul 2014 10:14:41 -0700 Subject: [PATCH 09/29] Fix for streaming error. --- libraries/metavoxels/src/MetavoxelClientManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index e69794917f..f16b6c2396 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -143,6 +143,9 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); _reliableDeltaLOD = getLastAcknowledgedSendRecord()->getLOD(); + PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); + _remoteDataLOD = receiveRecord->getLOD(); + _remoteData = receiveRecord->getData(); } } else { Endpoint::handleMessage(message, in); From 2e73ac8bc116b23ba42e841c1d1d39b3a24f330d Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 8 Jul 2014 11:16:39 -0700 Subject: [PATCH 10/29] changed Audio.cpp to not overflow _audioOutput buffer, and 2 other things added _consecutiveNotMixedCount to prevent premature injector stream deletion; made silent-frame drop only occur in dynamic jitter buffer mode --- .../src/audio/AudioMixerClientData.cpp | 5 ++++- interface/src/Audio.cpp | 20 ++++++++++--------- .../audio/src/PositionalAudioRingBuffer.cpp | 10 +++++++--- .../audio/src/PositionalAudioRingBuffer.h | 6 +++--- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index f6437f9c97..d3883501d6 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -138,11 +138,14 @@ void AudioMixerClientData::pushBuffersAfterFrameSend() { // this was a used buffer, push the output pointer forwards PositionalAudioRingBuffer* audioBuffer = *i; + const int INJECTOR_CONSECUTIVE_NOT_MIXED_THRESHOLD = 100; + if (audioBuffer->willBeAddedToMix()) { audioBuffer->shiftReadPosition(audioBuffer->getSamplesPerFrame()); audioBuffer->setWillBeAddedToMix(false); } else if (audioBuffer->getType() == PositionalAudioRingBuffer::Injector - && audioBuffer->hasStarted() && audioBuffer->isStarved()) { + && audioBuffer->hasStarted() && audioBuffer->isStarved() + && audioBuffer->getConsecutiveNotMixedCount() > INJECTOR_CONSECUTIVE_NOT_MIXED_THRESHOLD) { // this is an empty audio buffer that has starved, safe to delete // also delete its sequence number stats QUuid streamIdentifier = ((InjectedAudioRingBuffer*)audioBuffer)->getStreamIdentifier(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6bbd769d25..c604040bc8 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -67,7 +67,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _proceduralAudioOutput(NULL), _proceduralOutputDevice(NULL), _inputRingBuffer(0), - _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO), + _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, false, 100), _isStereoInput(false), _averagedLatency(0.0), _measuredJitter(0), @@ -869,14 +869,11 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { _numFramesDisplayStarve = 10; } - // if there is anything in the ring buffer, decide what to do - if (_ringBuffer.samplesAvailable() > 0) { - - int numNetworkOutputSamples = _ringBuffer.samplesAvailable(); - int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; - - QByteArray outputBuffer; - outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); + int numSamplesAudioOutputRoomFor = _audioOutput->bytesFree() / sizeof(int16_t); + int numNetworkOutputSamples = std::min(_ringBuffer.samplesAvailable(), (int)(numSamplesAudioOutputRoomFor * networkOutputToOutputRatio)); + + // if there is data in the ring buffer and room in the audio output, decide what to do + if (numNetworkOutputSamples > 0) { int numSamplesNeededToStartPlayback = std::min(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2), _ringBuffer.getSampleCapacity()); @@ -885,6 +882,11 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { // We are still waiting for enough samples to begin playback // qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback; } else { + int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; + + QByteArray outputBuffer; + outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); + // We are either already playing back, or we have enough audio to start playing back. //qDebug() << "pushing " << numNetworkOutputSamples; _ringBuffer.setIsStarved(false); diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 0fe75f1239..6b3a1eb94f 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -99,7 +99,8 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer:: _listenerUnattenuatedZone(NULL), _desiredJitterBufferFrames(1), _currentJitterBufferFrames(-1), - _dynamicJitterBuffers(dynamicJitterBuffers) + _dynamicJitterBuffers(dynamicJitterBuffers), + _consecutiveNotMixedCount(0) { } @@ -129,7 +130,7 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { numSilentSamples = getSamplesPerFrame(); if (numSilentSamples > 0) { - if (_currentJitterBufferFrames > _desiredJitterBufferFrames) { + if (_dynamicJitterBuffers && _currentJitterBufferFrames > _desiredJitterBufferFrames) { // our current jitter buffer size exceeds its desired value, so ignore some silent // frames to get that size as close to desired as possible int samplesPerFrame = getSamplesPerFrame(); @@ -206,11 +207,12 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { if (!isNotStarvedOrHasMinimumSamples(samplesPerFrame + desiredJitterBufferSamples)) { // if the buffer was starved, allow it to accrue at least the desired number of // jitter buffer frames before we start taking frames from it for mixing - + if (_shouldOutputStarveDebug) { _shouldOutputStarveDebug = false; } + _consecutiveNotMixedCount++; return false; } else if (samplesAvailable() < samplesPerFrame) { // if the buffer doesn't have a full frame of samples to take for mixing, it is starved @@ -222,6 +224,7 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { // reset our _shouldOutputStarveDebug to true so the next is printed _shouldOutputStarveDebug = true; + _consecutiveNotMixedCount++; return false; } @@ -231,6 +234,7 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { // minus one (since a frame will be read immediately after this) is the length of the jitter buffer _currentJitterBufferFrames = samplesAvailable() / samplesPerFrame - 1; _isStarved = false; + _consecutiveNotMixedCount = 0; } // since we've read data from ring buffer at least once - we've started diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index 0322afb47b..31b0524b3b 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -83,6 +83,8 @@ public: int getDesiredJitterBufferFrames() const { return _desiredJitterBufferFrames; } int getCurrentJitterBufferFrames() const { return _currentJitterBufferFrames; } + int getConsecutiveNotMixedCount() const { return _consecutiveNotMixedCount; } + protected: // disallow copying of PositionalAudioRingBuffer objects PositionalAudioRingBuffer(const PositionalAudioRingBuffer&); @@ -107,9 +109,7 @@ protected: bool _dynamicJitterBuffers; // extra stats - int _starveCount; - int _silentFramesDropped; - + int _consecutiveNotMixedCount; }; #endif // hifi_PositionalAudioRingBuffer_h From 0e117966f703e51e505eff1c25a27b6fc50d5030 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 8 Jul 2014 11:43:06 -0700 Subject: [PATCH 11/29] better clapping --- examples/clap.js | 153 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 44 deletions(-) diff --git a/examples/clap.js b/examples/clap.js index 9da36ba094..7a2a77afc4 100644 --- a/examples/clap.js +++ b/examples/clap.js @@ -10,27 +10,34 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -function length(v) { - return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); -} +var clapAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/ClapAnimations/ClapHands_Standing.fbx"; +var startEndFrames = []; +startEndFrames.push({ start: 0, end: 8}); +startEndFrames.push({ start: 10, end: 20}); +startEndFrames.push({ start: 20, end: 28}); +startEndFrames.push({ start: 30, end: 37}); +startEndFrames.push({ start: 41, end: 46}); +startEndFrames.push({ start: 53, end: 58}); +var lastClapFrame = 0; +var lastAnimFrame = 0; -function printVector(v) { - print(v.x + ", " + v.y + ", " + v.z + "\n"); -} +var claps = []; +claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap1Reverb.wav")); +claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap2Reverb.wav")); +claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap3Reverb.wav")); +claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap4Reverb.wav")); +claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap5Reverb.wav")); +claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap6Reverb.wav")); +var numberOfSounds = claps.length; -function vMinus(a, b) { - var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }; - return rval; -} +var clappingNow = false; +var collectedClicks = 0; -// First, load the clap sound from a URL -var clap1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap1.raw"); -var clap2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap2.raw"); -var clap3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap3.raw"); -var clap4 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap4.raw"); -var clap5 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap5.raw"); -var clap6 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/clap6.raw"); +var clickClappingNow = false; +var CLAP_START_RATE = 15.0; +var clapRate = CLAP_START_RATE; +var startedTimer = false; var clapping = new Array(); clapping[0] = false; @@ -38,36 +45,94 @@ clapping[1] = false; function maybePlaySound(deltaTime) { // Set the location and other info for the sound to play - var palm1Position = Controller.getSpatialControlPosition(0); - var palm2Position = Controller.getSpatialControlPosition(2); - var distanceBetween = length(vMinus(palm1Position, palm2Position)); - for (var palm = 0; palm < 2; palm++) { - var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1); - var speed = length(palmVelocity); - - const CLAP_SPEED = 0.2; - const CLAP_DISTANCE = 0.2; + var animationDetails = MyAvatar.getAnimationDetails(clapAnimation); - if (!clapping[palm] && (distanceBetween < CLAP_DISTANCE) && (speed > CLAP_SPEED)) { - var options = new AudioInjectionOptions(); - options.position = palm1Position; - options.volume = speed / 2.0; - if (options.volume > 1.0) options.volume = 1.0; - which = Math.floor((Math.random() * 6) + 1); - if (which == 1) { Audio.playSound(clap1, options); } - else if (which == 2) { Audio.playSound(clap2, options); } - else if (which == 3) { Audio.playSound(clap3, options); } - else if (which == 4) { Audio.playSound(clap4, options); } - else if (which == 5) { Audio.playSound(clap5, options); } - else { Audio.playSound(clap6, options); } - Audio.playSound(clap, options); - clapping[palm] = true; - } else if (clapping[palm] && (speed < (CLAP_SPEED / 4.0))) { - clapping[palm] = false; - } + var frame = Math.floor(animationDetails.frameIndex); + + if (frame != lastAnimFrame) { + print("frame " + frame); + lastAnimFrame = frame; + } + for (var i = 0; i < startEndFrames.length; i++) { + if (frame == startEndFrames[i].start && (frame != lastClapFrame)) { + playClap(1.0, Camera.getPosition()); + lastClapFrame = frame; + } + } + + var palm1Position = MyAvatar.getLeftPalmPosition(); + var palm2Position = MyAvatar.getRightPalmPosition(); + var distanceBetween = Vec3.length(Vec3.subtract(palm1Position, palm2Position)); + + var palm1Velocity = Controller.getSpatialControlVelocity(1); + var palm2Velocity = Controller.getSpatialControlVelocity(3); + var closingVelocity = Vec3.length(Vec3.subtract(palm1Velocity, palm2Velocity)); + + const CLAP_SPEED = 0.7; + const CLAP_DISTANCE = 0.15; + + if ((closingVelocity > CLAP_SPEED) && (distanceBetween < CLAP_DISTANCE) && !clappingNow) { + var volume = closingVelocity / 2.0; + if (volume > 1.0) volume = 1.0; + playClap(volume, palm1Position); + clappingNow = true; + } else if (clappingNow && (distanceBetween > CLAP_DISTANCE * 1.2)) { + clappingNow = false; } } +function playClap(volume, position) { + var options = new AudioInjectionOptions(); + options.position = position; + options.volume = 1.0; + var clip = Math.floor(Math.random() * numberOfSounds); + Audio.playSound(claps[clip], options); +} + +function keepClapping() { + playClap(1.0, Camera.getPosition()); +} + +Controller.keyPressEvent.connect(function(event) { + if(event.text == "SHIFT") { + if (!clickClappingNow) { + playClap(1.0, Camera.getPosition()); + var whichClip = Math.floor(Math.random() * startEndFrames.length); + lastClapFrame = 0; + MyAvatar.startAnimation(clapAnimation, clapRate, 1.0, true, false); + clickClappingNow = true; + } else { + clapRate *= 1.25; + MyAvatar.stopAnimation(clapAnimation); + MyAvatar.startAnimation(clapAnimation, clapRate, 1.0, true, false); + collectedClicks = collectedClicks + 1; + } + } +}); + +var CLAP_END_WAIT_MSECS = 500; +Controller.keyReleaseEvent.connect(function(event) { + if (event.text == "SHIFT") { + if (!startedTimer) { + startedTimer = true; + collectedClicks = 0; + Script.setTimeout(stopClapping, CLAP_END_WAIT_MSECS); + } + } +}); + +function stopClapping() { + if (collectedClicks == 0) { + startedTimer = false; + MyAvatar.stopAnimation(clapAnimation); + clapRate = CLAP_START_RATE; + clickClappingNow = false; + } else { + startedTimer = false; + } +} + // Connect a call back that happens every frame -Script.update.connect(maybePlaySound); \ No newline at end of file +Script.update.connect(maybePlaySound); +//Controller.keyPressEvent.connect(keyPressEvent); \ No newline at end of file From 84aa4b9cda859f73751b3a3f8573bfb379d2cb60 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Jul 2014 11:59:10 -0700 Subject: [PATCH 12/29] use compiler default C++ Standard Library on OS X --- CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2451ab240a..b8566dd050 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,14 +32,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) -if (APPLE) - exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION) - string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION}) - if (DARWIN_VERSION GREATER 12) - set(CMAKE_CXX_FLAGS "-stdlib=libstdc++") - endif (DARWIN_VERSION GREATER 12) -endif (APPLE) - # targets not supported on windows if (NOT WIN32) add_subdirectory(animation-server) From d1afe127c3e47db8d754ce2afc92900391de702d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Jul 2014 12:06:43 -0700 Subject: [PATCH 13/29] updates to RtMidi find module to look for static or dynamic lib --- cmake/modules/FindRtMidi.cmake | 4 ++-- interface/CMakeLists.txt | 28 +++++++++++++--------------- interface/external/rtmidi/readme.txt | 4 +++- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cmake/modules/FindRtMidi.cmake b/cmake/modules/FindRtMidi.cmake index a54cc483e1..ad1167c5d6 100644 --- a/cmake/modules/FindRtMidi.cmake +++ b/cmake/modules/FindRtMidi.cmake @@ -26,8 +26,8 @@ else () set(RTMIDI_SEARCH_DIRS "${RTMIDI_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/rtmidi") find_path(RTMIDI_INCLUDE_DIR RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS}) - find_file(RTMIDI_CPP NAMES RtMidi.cpp PATH_SUFFIXES src HINTS ${RTMIDI_SEARCH_DIRS}) + find_library(RTMIDI_LIBRARY NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS}) include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_CPP) + find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_LIBRARY) endif () \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 68ba2761aa..49a6da7438 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -111,16 +111,6 @@ if (APPLE) SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/interface.icns") endif() -# RtMidi for scripted MIDI control -find_package(RtMidi) - -if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI) - add_definitions(-DHAVE_RTMIDI) - include_directories(SYSTEM ${RTMIDI_INCLUDE_DIR}) - - set(INTERFACE_SRCS ${INTERFACE_SRCS} "${RTMIDI_CPP}") -endif () - # create the executable, make it a bundle on OS X add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) @@ -151,6 +141,7 @@ find_package(Sixense) find_package(Visage) find_package(ZLIB) find_package(Qxmpp) +find_package(RtMidi) # include the Sixense library for Razer Hydra if available if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE) @@ -223,11 +214,18 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP) target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}") endif (QXMPP_FOUND AND NOT DISABLE_QXMPP) -# link CoreMIDI if we're using RtMidi -if (RTMIDI_FOUND AND APPLE) - find_library(CoreMIDI CoreMIDI) - add_definitions(-D__MACOSX_CORE__) - target_link_libraries(${TARGET_NAME} ${CoreMIDI}) +# and with RtMidi for RtMidi control +if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI) + + add_definitions(-DHAVE_RTMIDI) + include_directories(SYSTEM ${RTMIDI_INCLUDE_DIR}) + target_link_libraries(${TARGET_NAME} "${RTMIDI_LIBRARY}") + + if (APPLE) + find_library(CoreMIDI CoreMIDI) + add_definitions(-D__MACOSX_CORE__) + target_link_libraries(${TARGET_NAME} ${CoreMIDI}) + endif() endif() # include headers for interface and InterfaceConfig. diff --git a/interface/external/rtmidi/readme.txt b/interface/external/rtmidi/readme.txt index d83d0c293e..d0480fce4a 100644 --- a/interface/external/rtmidi/readme.txt +++ b/interface/external/rtmidi/readme.txt @@ -7,7 +7,9 @@ Stephen Birarda, June 30, 2014 2. Copy RtMidi.h to externals/rtmidi/include. -3. Copy RtMidi.cpp to externals/rtmidi/src +3. Compile the RtMidi library. + +3. Copy either librtmidi.dylib (dynamic) or librtmidi.a (static) to externals/rtmidi/lib 4. Delete your build directory, run cmake and build, and you should be all set. From 6ee52e97c80c584c0e0c959cb587dfc8620b4a16 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 8 Jul 2014 12:23:43 -0700 Subject: [PATCH 14/29] added dev menu option to disable _audioOutput overflow check --- interface/src/Audio.cpp | 11 ++++++++--- interface/src/Menu.cpp | 4 ++++ interface/src/Menu.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index c604040bc8..cc455c5544 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -869,9 +869,14 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { _numFramesDisplayStarve = 10; } - int numSamplesAudioOutputRoomFor = _audioOutput->bytesFree() / sizeof(int16_t); - int numNetworkOutputSamples = std::min(_ringBuffer.samplesAvailable(), (int)(numSamplesAudioOutputRoomFor * networkOutputToOutputRatio)); - + int numNetworkOutputSamples; + if (Menu::getInstance()->isOptionChecked(MenuOption::DisableQAudioOutputOverflowCheck)) { + numNetworkOutputSamples = _ringBuffer.samplesAvailable(); + } else { + int numSamplesAudioOutputRoomFor = _audioOutput->bytesFree() / sizeof(int16_t); + numNetworkOutputSamples = std::min(_ringBuffer.samplesAvailable(), (int)(numSamplesAudioOutputRoomFor * networkOutputToOutputRatio)); + } + // if there is data in the ring buffer and room in the audio output, decide what to do if (numNetworkOutputSamples > 0) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6b32eb5770..69d95b34db 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -428,6 +428,10 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); + QMenu* audioOptionsMenu = developerMenu->addMenu("Audio Options"); + + addCheckableActionToQMenuAndActionHash(audioOptionsMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 06b5c5c9f4..e8146f8038 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -343,6 +343,7 @@ namespace MenuOption { const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; const QString DisableNackPackets = "Disable NACK Packets"; + const QString DisableQAudioOutputOverflowCheck = "Disable QAudioOutput Overflow Check"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; From df1b4107fd92a88bc443312c4c234b05ed18e081 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 8 Jul 2014 13:01:05 -0700 Subject: [PATCH 15/29] moved qAudioOutput buffer overflow debug option to existing audio menu --- interface/src/Menu.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 69d95b34db..c0c25bb00d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -428,10 +428,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); - QMenu* audioOptionsMenu = developerMenu->addMenu("Audio Options"); - - addCheckableActionToQMenuAndActionHash(audioOptionsMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false); - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); @@ -579,6 +575,8 @@ Menu::Menu() : Qt::CTRL | Qt::SHIFT | Qt::Key_U, false); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false); + addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, Qt::CTRL | Qt::SHIFT | Qt::Key_V, this, From 02cf1f006e14a4f2fde6db2e85ea159934778d8f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Jul 2014 13:41:42 -0700 Subject: [PATCH 16/29] Change tests to reflect transmission changes and fixed issue with reprocessing already-handled reliable delta. --- .../src/metavoxels/MetavoxelServer.cpp | 9 ++++--- .../src/metavoxels/MetavoxelServer.h | 1 + .../metavoxels/src/MetavoxelClientManager.cpp | 8 ++++-- .../metavoxels/src/MetavoxelClientManager.h | 1 + libraries/metavoxels/src/MetavoxelMessages.h | 4 +++ tests/metavoxels/src/MetavoxelTests.cpp | 27 +++++++++++++------ tests/metavoxels/src/MetavoxelTests.h | 3 +++ 7 files changed, 40 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index c601478f70..b0cf93fb3a 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -93,7 +93,8 @@ void MetavoxelServer::sendDeltas() { MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server) : Endpoint(node, new PacketRecord(), NULL), _server(server), - _reliableDeltaChannel(NULL) { + _reliableDeltaChannel(NULL), + _reliableDeltaID(0) { connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleMessage(const QVariant&))); connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(checkReliableDeltaReceived())); @@ -109,7 +110,8 @@ void MetavoxelSession::update() { // if we're sending a reliable delta, wait until it's acknowledged if (_reliableDeltaChannel) { Bitstream& out = _sequencer.startPacket(); - out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); + MetavoxelDeltaPendingMessage msg = { _reliableDeltaID }; + out << QVariant::fromValue(msg); _sequencer.endPacket(); return; } @@ -134,7 +136,8 @@ void MetavoxelSession::update() { // go back to the beginning with the current packet and note that there's a delta pending _sequencer.getOutputStream().getUnderlying().device()->seek(start); - out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); + MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID }; + out << QVariant::fromValue(msg); _sequencer.endPacket(); } else { diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index f2769f26f2..0e8db55587 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -83,6 +83,7 @@ private: MetavoxelData _reliableDeltaData; MetavoxelLOD _reliableDeltaLOD; Bitstream::WriteMappings _reliableDeltaWriteMappings; + int _reliableDeltaID; }; #endif // hifi_MetavoxelServer_h diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index f16b6c2396..f3ea1ae8c5 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -87,7 +87,8 @@ void MetavoxelClientManager::updateClient(MetavoxelClient* client) { MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager) : Endpoint(node, new PacketRecord(), new PacketRecord()), _manager(manager), - _reliableDeltaChannel(NULL) { + _reliableDeltaChannel(NULL), + _reliableDeltaID(0) { connect(_sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX), SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&))); @@ -139,7 +140,10 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } } } else if (userType == MetavoxelDeltaPendingMessage::Type) { - if (!_reliableDeltaChannel) { + // check the id to make sure this is not a delta we've already processed + int id = message.value().id; + if (id > _reliableDeltaID) { + _reliableDeltaID = id; _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); _reliableDeltaLOD = getLastAcknowledgedSendRecord()->getLOD(); diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 1f37b15c18..ad6c86c8fc 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -74,6 +74,7 @@ private: ReliableChannel* _reliableDeltaChannel; MetavoxelLOD _reliableDeltaLOD; + int _reliableDeltaID; }; #endif // hifi_MetavoxelClientManager_h diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index b822f1c561..91d73c08a9 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -64,6 +64,10 @@ DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaMessage) /// A message indicating that metavoxel delta information is being sent on a reliable channel. class MetavoxelDeltaPendingMessage { STREAMABLE + +public: + + STREAM int id; }; DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaPendingMessage) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 4132270620..49808fe080 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -647,7 +647,8 @@ TestEndpoint::TestEndpoint(Mode mode) : _mode(mode), _highPriorityMessagesToSend(0.0f), _reliableMessagesToSend(0.0f), - _reliableDeltaChannel(NULL) { + _reliableDeltaChannel(NULL), + _reliableDeltaID(0) { connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); @@ -908,7 +909,8 @@ bool TestEndpoint::simulate(int iterationNumber) { // if we're sending a reliable delta, wait until it's acknowledged if (_reliableDeltaChannel) { Bitstream& out = _sequencer.startPacket(); - out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); + MetavoxelDeltaPendingMessage msg = { _reliableDeltaID }; + out << QVariant::fromValue(msg); _sequencer.endPacket(); return false; } @@ -932,7 +934,8 @@ bool TestEndpoint::simulate(int iterationNumber) { _reliableDeltaLOD = _lod; _sequencer.getOutputStream().getUnderlying().device()->seek(start); - out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); + MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID }; + out << QVariant::fromValue(msg); _sequencer.endPacket(); } else { @@ -1081,15 +1084,22 @@ void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) { } else if (userType == MetavoxelDeltaMessage::Type) { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); - _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, - _dataLOD = getLastAcknowledgedSendRecord()->getLOD()); + _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, + _remoteDataLOD = getLastAcknowledgedSendRecord()->getLOD()); + in.reset(); + _data = _remoteData; compareMetavoxelData(); } else if (userType == MetavoxelDeltaPendingMessage::Type) { - if (!_reliableDeltaChannel) { + int id = message.value().id; + if (id > _reliableDeltaID) { + _reliableDeltaID = id; _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); _reliableDeltaLOD = getLastAcknowledgedSendRecord()->getLOD(); + PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); + _remoteDataLOD = receiveRecord->getLOD(); + _remoteData = receiveRecord->getData(); } } else if (userType == QMetaType::QVariantList) { foreach (const QVariant& element, message.toList()) { @@ -1107,7 +1117,7 @@ PacketRecord* TestEndpoint::maybeCreateSendRecord() const { } PacketRecord* TestEndpoint::maybeCreateReceiveRecord() const { - return new TestReceiveRecord(_dataLOD, (_mode == METAVOXEL_SERVER_MODE) ? MetavoxelData() : _data, _remoteState); + return new TestReceiveRecord(_remoteDataLOD, _remoteData, _remoteState); } void TestEndpoint::handleHighPriorityMessage(const QVariant& message) { @@ -1127,9 +1137,10 @@ void TestEndpoint::handleHighPriorityMessage(const QVariant& message) { void TestEndpoint::handleReliableMessage(const QVariant& message, Bitstream& in) { if (message.userType() == MetavoxelDeltaMessage::Type) { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); - _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _dataLOD = _reliableDeltaLOD); + _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _remoteDataLOD = _reliableDeltaLOD); _sequencer.getInputStream().persistReadMappings(in.getAndResetReadMappings()); in.clearPersistentMappings(); + _data = _remoteData; compareMetavoxelData(); _reliableDeltaChannel = NULL; return; diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 5d719ccfdf..ce357fbb90 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -79,6 +79,8 @@ private: MetavoxelData _data; MetavoxelLOD _dataLOD; + MetavoxelData _remoteData; + MetavoxelLOD _remoteDataLOD; MetavoxelLOD _lod; SharedObjectPointer _sphere; @@ -104,6 +106,7 @@ private: MetavoxelData _reliableDeltaData; MetavoxelLOD _reliableDeltaLOD; Bitstream::WriteMappings _reliableDeltaWriteMappings; + int _reliableDeltaID; }; /// A simple shared object. From 56361718369be6d464cbfd8bba02083675a4c67e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Jul 2014 14:41:16 -0700 Subject: [PATCH 17/29] Timing fix. --- assignment-client/src/metavoxels/MetavoxelServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index b0cf93fb3a..63776de7fa 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -87,7 +87,7 @@ void MetavoxelServer::sendDeltas() { int elapsed = now - _lastSend; _lastSend = now; - _sendTimer.start(qMax(0, 2 * SEND_INTERVAL - elapsed)); + _sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL))); } MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server) : From 40ad03dbf52ffcffb0498c73652d90a76e324e79 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 8 Jul 2014 14:53:41 -0700 Subject: [PATCH 18/29] Another improvement to clapping to match animation pace with keystrokes --- examples/clap.js | 54 +++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/examples/clap.js b/examples/clap.js index 7a2a77afc4..35c344165f 100644 --- a/examples/clap.js +++ b/examples/clap.js @@ -1,23 +1,26 @@ // -// cameraExample.js +// clap.js // examples // // Copyright 2014 High Fidelity, Inc. // -// This sample script watches your hydra hands and makes clapping sound when they come close together fast +// This sample script watches your hydra hands and makes clapping sound when they come close together fast, +// and also watches for the 'shift' key and claps when that key is pressed. Clapping multiple times by pressing +// the shift key again makes the animation and sound match your pace of clapping. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // var clapAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/ClapAnimations/ClapHands_Standing.fbx"; +var ANIMATION_FRAMES_PER_CLAP = 10.0; var startEndFrames = []; -startEndFrames.push({ start: 0, end: 8}); +startEndFrames.push({ start: 0, end: 10}); startEndFrames.push({ start: 10, end: 20}); -startEndFrames.push({ start: 20, end: 28}); -startEndFrames.push({ start: 30, end: 37}); -startEndFrames.push({ start: 41, end: 46}); -startEndFrames.push({ start: 53, end: 58}); +startEndFrames.push({ start: 20, end: 30}); +startEndFrames.push({ start: 30, end: 40}); +startEndFrames.push({ start: 41, end: 51}); +startEndFrames.push({ start: 53, end: 0}); var lastClapFrame = 0; var lastAnimFrame = 0; @@ -34,15 +37,12 @@ var numberOfSounds = claps.length; var clappingNow = false; var collectedClicks = 0; +var clickStartTime, clickEndTime; var clickClappingNow = false; var CLAP_START_RATE = 15.0; var clapRate = CLAP_START_RATE; var startedTimer = false; -var clapping = new Array(); -clapping[0] = false; -clapping[1] = false; - function maybePlaySound(deltaTime) { // Set the location and other info for the sound to play @@ -51,9 +51,9 @@ function maybePlaySound(deltaTime) { var frame = Math.floor(animationDetails.frameIndex); if (frame != lastAnimFrame) { - print("frame " + frame); lastAnimFrame = frame; } + for (var i = 0; i < startEndFrames.length; i++) { if (frame == startEndFrames[i].start && (frame != lastClapFrame)) { playClap(1.0, Camera.getPosition()); @@ -90,34 +90,41 @@ function playClap(volume, position) { Audio.playSound(claps[clip], options); } -function keepClapping() { - playClap(1.0, Camera.getPosition()); -} +var FASTEST_CLAP_INTERVAL = 100.0; +var SLOWEST_CLAP_INTERVAL = 2000.0; Controller.keyPressEvent.connect(function(event) { if(event.text == "SHIFT") { if (!clickClappingNow) { + clickClappingNow = true; + clickStartTime = new Date(); playClap(1.0, Camera.getPosition()); - var whichClip = Math.floor(Math.random() * startEndFrames.length); lastClapFrame = 0; MyAvatar.startAnimation(clapAnimation, clapRate, 1.0, true, false); - clickClappingNow = true; } else { - clapRate *= 1.25; - MyAvatar.stopAnimation(clapAnimation); - MyAvatar.startAnimation(clapAnimation, clapRate, 1.0, true, false); + // Adjust animation speed for measured clicking interval + clickEndTime = new Date(); + var milliseconds = clickEndTime - clickStartTime; + clickStartTime = new Date(); + if ((milliseconds < SLOWEST_CLAP_INTERVAL) && (milliseconds > FASTEST_CLAP_INTERVAL)) { + clapRate = ANIMATION_FRAMES_PER_CLAP * (1000.0 / milliseconds); + playClap(1.0, Camera.getPosition()); + MyAvatar.stopAnimation(clapAnimation); + MyAvatar.startAnimation(clapAnimation, clapRate, 1.0, true, false); + } collectedClicks = collectedClicks + 1; } } }); -var CLAP_END_WAIT_MSECS = 500; +var CLAP_END_WAIT_MSECS = 300; Controller.keyReleaseEvent.connect(function(event) { if (event.text == "SHIFT") { + collectedClicks = 0; if (!startedTimer) { - startedTimer = true; collectedClicks = 0; Script.setTimeout(stopClapping, CLAP_END_WAIT_MSECS); + startedTimer = true; } } }); @@ -134,5 +141,4 @@ function stopClapping() { } // Connect a call back that happens every frame -Script.update.connect(maybePlaySound); -//Controller.keyPressEvent.connect(keyPressEvent); \ No newline at end of file +Script.update.connect(maybePlaySound); \ No newline at end of file From b6570dc4ee83971e4cd8b480cf7eafaa5854a609 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Jul 2014 15:10:05 -0700 Subject: [PATCH 19/29] Use congestion control on server. --- .../src/metavoxels/MetavoxelServer.cpp | 22 +++++++++++++++---- .../src/metavoxels/MetavoxelServer.h | 2 ++ .../metavoxels/src/DatagramSequencer.cpp | 2 +- libraries/metavoxels/src/DatagramSequencer.h | 4 ++-- tests/metavoxels/src/MetavoxelTests.cpp | 2 +- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 63776de7fa..14765e2ddc 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -109,10 +109,7 @@ void MetavoxelSession::update() { } // if we're sending a reliable delta, wait until it's acknowledged if (_reliableDeltaChannel) { - Bitstream& out = _sequencer.startPacket(); - MetavoxelDeltaPendingMessage msg = { _reliableDeltaID }; - out << QVariant::fromValue(msg); - _sequencer.endPacket(); + sendPacketGroup(); return; } Bitstream& out = _sequencer.startPacket(); @@ -143,6 +140,9 @@ void MetavoxelSession::update() { } else { _sequencer.endPacket(); } + + // perhaps send additional packets to fill out the group + sendPacketGroup(1); } void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) { @@ -179,3 +179,17 @@ void MetavoxelSession::checkReliableDeltaReceived() { _reliableDeltaData = MetavoxelData(); _reliableDeltaChannel = NULL; } + +void MetavoxelSession::sendPacketGroup(int alreadySent) { + int additionalPackets = _sequencer.notePacketGroup() - alreadySent; + for (int i = 0; i < additionalPackets; i++) { + Bitstream& out = _sequencer.startPacket(); + if (_reliableDeltaChannel) { + MetavoxelDeltaPendingMessage msg = { _reliableDeltaID }; + out << QVariant::fromValue(msg); + } else { + out << QVariant(); + } + _sequencer.endPacket(); + } +} diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index 0e8db55587..6df769227c 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -74,6 +74,8 @@ private slots: private: + void sendPacketGroup(int alreadySent = 0); + MetavoxelServer* _server; MetavoxelLOD _lod; diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index 2c594fc1ca..536cfc9dfb 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -79,7 +79,7 @@ ReliableChannel* DatagramSequencer::getReliableInputChannel(int index) { return channel; } -int DatagramSequencer::startPacketGroup(int desiredPackets) { +int DatagramSequencer::notePacketGroup(int desiredPackets) { // figure out how much data we have enqueued and increase the number of packets desired int totalAvailable = 0; foreach (ReliableChannel* channel, _reliableOutputChannels) { diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index b85916b561..b6dce464f7 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -108,10 +108,10 @@ public: /// Returns the intput channel at the specified index, creating it if necessary. ReliableChannel* getReliableInputChannel(int index = 0); - /// Starts a packet group. + /// Notes that we're sending a group of packets. /// \param desiredPackets the number of packets we'd like to write in the group /// \return the number of packets to write in the group - int startPacketGroup(int desiredPackets = 1); + int notePacketGroup(int desiredPackets = 1); /// Starts a new packet for transmission. /// \return a reference to the Bitstream to use for writing to the packet diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 49808fe080..0a6a5de96d 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -859,7 +859,7 @@ bool TestEndpoint::simulate(int iterationNumber) { bytesReceived += datagram.size(); _remainingPipelineCapacity += datagram.size(); } - int packetCount = _sequencer.startPacketGroup(); + int packetCount = _sequencer.notePacketGroup(); groupsSent++; maxPacketsPerGroup = qMax(maxPacketsPerGroup, packetCount); for (int i = 0; i < packetCount; i++) { From 1b890a9e48ea88f27ff154db0851ee50c08d7754 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Jul 2014 15:37:59 -0700 Subject: [PATCH 20/29] Use congestion control for client sends, too. --- libraries/metavoxels/src/Endpoint.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/metavoxels/src/Endpoint.cpp b/libraries/metavoxels/src/Endpoint.cpp index 666ffe52d9..420a52ef95 100644 --- a/libraries/metavoxels/src/Endpoint.cpp +++ b/libraries/metavoxels/src/Endpoint.cpp @@ -39,9 +39,12 @@ Endpoint::~Endpoint() { } void Endpoint::update() { - Bitstream& out = _sequencer.startPacket(); - writeUpdateMessage(out); - _sequencer.endPacket(); + int packetsToSend = _sequencer.notePacketGroup(); + for (int i = 0; i < packetsToSend; i++) { + Bitstream& out = _sequencer.startPacket(); + writeUpdateMessage(out); + _sequencer.endPacket(); + } } int Endpoint::parseData(const QByteArray& packet) { From bc785115a938c36763e418e8707c88475270c1c7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 8 Jul 2014 16:33:31 -0700 Subject: [PATCH 21/29] Fix script errors not being reported Script.update event needs to be emitted after reporting any script errors. --- libraries/script-engine/src/ScriptEngine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e93a7125b9..f5f15331ac 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -515,8 +515,6 @@ void ScriptEngine::run() { qint64 now = usecTimestampNow(); float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; - emit update(deltaTime); - lastUpdate = now; if (_engine.hasUncaughtException()) { int line = _engine.uncaughtExceptionLineNumber(); @@ -524,6 +522,9 @@ void ScriptEngine::run() { emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + _engine.uncaughtException().toString()); _engine.clearExceptions(); } + + emit update(deltaTime); + lastUpdate = now; } emit scriptEnding(); From b2912552f68e4acb394708ee2630442a9f090b59 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 8 Jul 2014 21:00:02 -0700 Subject: [PATCH 22/29] switched to better sounds for clapping --- examples/clap.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/clap.js b/examples/clap.js index 35c344165f..28835c1f00 100644 --- a/examples/clap.js +++ b/examples/clap.js @@ -26,12 +26,16 @@ var lastClapFrame = 0; var lastAnimFrame = 0; var claps = []; -claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap1Reverb.wav")); -claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap2Reverb.wav")); -claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap3Reverb.wav")); -claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap4Reverb.wav")); -claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap5Reverb.wav")); -claps.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/claps/Clap6Reverb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap1Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap2Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap3Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap4Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap5Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap6Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap7Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap8Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap9Rvb.wav")); +claps.push(new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/claps/BClap10Rvb.wav")); var numberOfSounds = claps.length; var clappingNow = false; From 1e7a18e62535e1f200158da3cb5360f4555535f3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 8 Jul 2014 21:02:32 -0700 Subject: [PATCH 23/29] Guard _framebufferObject deletion --- interface/src/ui/ApplicationOverlay.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 879c7cda32..302494852a 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -999,8 +999,10 @@ void ApplicationOverlay::renderTexturedHemisphere() { } void ApplicationOverlay::resize() { - delete _framebufferObject; - _framebufferObject = NULL; + if (_framebufferObject != NULL) { + delete _framebufferObject; + _framebufferObject = NULL; + } // _framebufferObject is recreated at the correct size the next time it is accessed via getFramebufferObject(). } From 51f7e8904d70325c11b2e4a144a9334e33fc2de5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 8 Jul 2014 21:04:30 -0700 Subject: [PATCH 24/29] Integrate UI toggling menu item and Hydra UI toggling They work together and both fade the UI in / out. --- interface/src/ui/ApplicationOverlay.cpp | 11 ++++++----- interface/src/ui/ApplicationOverlay.h | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 302494852a..b7e18df0b4 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -40,7 +40,6 @@ ApplicationOverlay::ApplicationOverlay() : _framebufferObject(NULL), _textureFov(DEFAULT_OCULUS_UI_ANGULAR_SIZE * RADIANS_PER_DEGREE), _alpha(1.0f), - _active(true), _crosshairTexture(0) { memset(_reticleActive, 0, sizeof(_reticleActive)); @@ -70,8 +69,8 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { QGLWidget* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); - //Handle fadeing and deactivation/activation of UI - if (_active) { + //Handle fading and deactivation/activation of UI + if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { _alpha += FADE_SPEED; if (_alpha > 1.0f) { _alpha = 1.0f; @@ -485,7 +484,8 @@ void ApplicationOverlay::renderControllerPointers() { if (palmData->getTrigger() == 1.0f) { if (!triggerPressed[index]) { if (bumperPressed[index]) { - _active = !_active; + Menu::getInstance()->setIsOptionChecked(MenuOption::UserInterface, + !Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)); } triggerPressed[index] = true; } @@ -495,7 +495,8 @@ void ApplicationOverlay::renderControllerPointers() { if ((controllerButtons & BUTTON_FWD)) { if (!bumperPressed[index]) { if (triggerPressed[index]) { - _active = !_active; + Menu::getInstance()->setIsOptionChecked(MenuOption::UserInterface, + !Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)); } bumperPressed[index] = true; } diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 5e8d06ab89..e2ffb506d4 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -69,7 +69,6 @@ private: float _magSizeMult[NUMBER_OF_MAGNIFIERS]; float _alpha; - bool _active; GLuint _crosshairTexture; }; From c50d9ae3e4333e6519ed9b16fddc259439c25480 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 8 Jul 2014 22:22:27 -0700 Subject: [PATCH 25/29] Hand low velocity filter as a menu option --- interface/src/Application.cpp | 7 +++++++ interface/src/Application.h | 1 + interface/src/Menu.cpp | 7 +++++++ interface/src/Menu.h | 1 + interface/src/devices/SixenseManager.cpp | 19 ++++++++++++------- interface/src/devices/SixenseManager.h | 3 +++ 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ace265ad4f..f900ea18c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -354,6 +354,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // Set the sixense filtering _sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense)); + + // Set hand controller velocity filtering + _sixenseManager.setLowVelocityFilter(Menu::getInstance()->isOptionChecked(MenuOption::LowVelocityFilter)); checkVersion(); @@ -1426,6 +1429,10 @@ void Application::setRenderVoxels(bool voxelRender) { } } +void Application::setLowVelocityFilter(bool lowVelocityFilter) { + getSixenseManager()->setLowVelocityFilter(lowVelocityFilter); +} + void Application::doKillLocalVoxels() { _wantToKillLocalVoxels = true; } diff --git a/interface/src/Application.h b/interface/src/Application.h index 11f406abf0..321a43d548 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -317,6 +317,7 @@ public slots: void nudgeVoxelsByVector(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); void setRenderVoxels(bool renderVoxels); + void setLowVelocityFilter(bool lowVelocityFilter); void doKillLocalVoxels(); void loadDialog(); void loadScriptURLDialog(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c0c25bb00d..b1f83c47cb 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -421,6 +421,13 @@ Menu::Menu() : true, appInstance->getSixenseManager(), SLOT(setFilter(bool))); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, + MenuOption::LowVelocityFilter, + 0, + true, + appInstance, + SLOT(setLowVelocityFilter(bool))); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e8146f8038..4fa02b802f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -368,6 +368,7 @@ namespace MenuOption { const QString Faceplus = "Faceplus"; const QString Faceshift = "Faceshift"; const QString FilterSixense = "Smooth Sixense Movement"; + const QString LowVelocityFilter = "Low Velocity Filter"; const QString FirstPerson = "First Person"; const QString FrameTimer = "Show Timer"; const QString FrustumRenderMode = "Render Mode"; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index c50fc887d6..15d9da43b0 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -32,6 +32,7 @@ SixenseManager::SixenseManager() { #ifdef HAVE_SIXENSE _lastMovement = 0; _amountMoved = glm::vec3(0.0f); + _lowVelocityFilter = false; _calibrationState = CALIBRATION_STATE_IDLE; // By default we assume the _neckBase (in orb frame) is as high above the orb @@ -160,17 +161,21 @@ void SixenseManager::update(float deltaTime) { } palm->setRawVelocity(rawVelocity); // meters/sec - // Use a velocity sensitive filter to damp small motions and preserve large ones with - // no latency. - float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f); - palm->setRawPosition(palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter)); - // adjustment for hydra controllers fit into hands float sign = (i == 0) ? -1.0f : 1.0f; rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); - palm->setRawRotation(safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter)); - + if (_lowVelocityFilter) { + // Use a velocity sensitive filter to damp small motions and preserve large ones with + // no latency. + float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f); + palm->setRawPosition(palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter)); + palm->setRawRotation(safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter)); + } else { + palm->setRawPosition(position); + palm->setRawRotation(rotation); + } + // use the velocity to determine whether there's any movement (if the hand isn't new) const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f; _amountMoved += rawVelocity * deltaTime; diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 8ca27ef77c..bae9e1c6d6 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -47,6 +47,7 @@ public: public slots: void setFilter(bool filter); + void setLowVelocityFilter(bool lowVelocityFilter) { _lowVelocityFilter = lowVelocityFilter; }; private: #ifdef HAVE_SIXENSE @@ -80,6 +81,8 @@ private: bool _bumperPressed[2]; int _oldX[2]; int _oldY[2]; + + bool _lowVelocityFilter; }; #endif // hifi_SixenseManager_h From f8185dec75035cb581f8128fc5464e41b86fe0a7 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 8 Jul 2014 22:26:11 -0700 Subject: [PATCH 26/29] removed some debug logs --- interface/src/avatar/Avatar.cpp | 1 - interface/src/devices/SixenseManager.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9bb54efe20..758c903b5c 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -611,7 +611,6 @@ void Avatar::initializeHair() { } } - qDebug() << "Initialize Hair"; } bool Avatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const { diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 15d9da43b0..026c1d3eb4 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -61,10 +61,8 @@ SixenseManager::~SixenseManager() { void SixenseManager::setFilter(bool filter) { #ifdef HAVE_SIXENSE if (filter) { - qDebug("Sixense Filter ON"); sixenseSetFilterEnabled(1); } else { - qDebug("Sixense Filter OFF"); sixenseSetFilterEnabled(0); } #endif From 603ca02ef97f3018fb5e2e8d89ba74a66d17d0e5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 9 Jul 2014 11:21:16 -0700 Subject: [PATCH 27/29] Default UI to "on" --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 70faec4057..2c9f7b9c28 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -276,7 +276,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, appInstance, SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0, false, From 862f31130682519e478584bbb81af8e425cb584d Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 9 Jul 2014 11:29:33 -0700 Subject: [PATCH 28/29] Fixed full screen mirror mode for non oculus --- interface/src/Application.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7eb66bafd4..bf464f98aa 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -604,9 +604,19 @@ void Application::paintGL() { } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness(0.0f); - _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); - _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); + //Only behave like a true mirror when in the OR + if (OculusManager::isConnected()) { + _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); + _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); + } else { + _myCamera.setTightness(0.0f); + glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); + float headHeight = eyePosition.y - _myAvatar->getPosition().y; + _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); + _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); + } } // Update camera position From 527f6b2a3f4d18f285a26aeff083174cb5ac2912 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 9 Jul 2014 11:32:38 -0700 Subject: [PATCH 29/29] Fix User Interface menu item string --- interface/src/Menu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 98c6af0be9..a2e1dd0c20 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -439,7 +439,7 @@ namespace MenuOption { const QString UploadAttachment = "Upload Attachment Model"; const QString UploadHead = "Upload Head Model"; const QString UploadSkeleton = "Upload Skeleton Model"; - const QString UserInterface = "UserInterface"; + const QString UserInterface = "User Interface"; const QString Visage = "Visage"; const QString VoxelMode = "Cycle Voxel Mode"; const QString Voxels = "Voxels";