From 7cab0363a929fb86e7f13b9f552488d1acb856c4 Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 5 Jun 2017 15:13:56 -0400 Subject: [PATCH 001/174] standalone 21180 branch with just the C++ changes --- interface/resources/images/cursor-none.png | Bin 0 -> 133 bytes interface/src/Application.cpp | 38 ++++++++++-------- interface/src/Application.h | 5 ++- interface/src/Menu.cpp | 5 +++ interface/src/Menu.h | 1 + interface/src/avatar/MyAvatar.cpp | 30 +++++++++++--- interface/src/avatar/MyAvatar.h | 5 +++ .../src/avatars-renderer/Avatar.cpp | 4 +- libraries/avatars/src/AvatarData.cpp | 34 +++++++++++----- libraries/avatars/src/AvatarData.h | 7 ++++ libraries/avatars/src/ScriptAvatarData.cpp | 8 ++++ libraries/avatars/src/ScriptAvatarData.h | 3 ++ .../src/display-plugins/CompositorHelper.cpp | 12 +++++- .../src/display-plugins/CompositorHelper.h | 4 ++ libraries/ui/src/CursorManager.cpp | 1 + libraries/ui/src/CursorManager.h | 1 + 16 files changed, 123 insertions(+), 35 deletions(-) create mode 100644 interface/resources/images/cursor-none.png diff --git a/interface/resources/images/cursor-none.png b/interface/resources/images/cursor-none.png new file mode 100644 index 0000000000000000000000000000000000000000..0b3f499242563a99230b69da0b8483ed8305f9e5 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7BeuosDLn|L;8^r1_lQ95>H=O_J^$8Le|V%OcrM`Ffa&tx;TbdoK8-VU|pOb e(!<2Tz`!EFz}RZPs)&Jsfx*+&&t;ucLK6Uz(jKb- literal 0 HcmV?d00001 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5e3e09e778..ed9b76d070 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -882,14 +882,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _glWidget->setFocusPolicy(Qt::StrongFocus); _glWidget->setFocus(); -#ifdef Q_OS_MAC - auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget -#else - // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the - // window menu, which is a pain, so only hide it for the GL surface - auto cursorTarget = _glWidget; -#endif - cursorTarget->setCursor(Qt::BlankCursor); + bool useSystemCursor = cmdOptionExists(argc, constArgv, "--system-cursor"); + showCursor(useSystemCursor ? Cursor::Icon::SYSTEM : Cursor::Icon::DEFAULT); // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); @@ -1547,9 +1541,16 @@ void Application::checkChangeCursor() { } } -void Application::showCursor(const QCursor& cursor) { +void Application::showCursor(const Cursor::Icon& cursor) { QMutexLocker locker(&_changeCursorLock); - _desiredCursor = cursor; + + auto managedCursor = Cursor::Manager::instance().getCursor(); + auto curIcon = managedCursor->getIcon(); + if (curIcon != cursor) { + managedCursor->setIcon(cursor); + curIcon = cursor; + } + _desiredCursor = cursor == Cursor::Icon::SYSTEM ? Qt::ArrowCursor : Qt::BlankCursor; _cursorNeedsChanging = true; } @@ -1958,9 +1959,9 @@ void Application::initializeUi() { _window->setMenuBar(new Menu()); auto compositorHelper = DependencyManager::get(); - connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] { + connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] { if (isHMDMode()) { - showCursor(compositorHelper->getAllowMouseCapture() ? Qt::BlankCursor : Qt::ArrowCursor); + showCursor(compositorHelper->getAllowMouseCapture() ? Cursor::Icon::DEFAULT : Cursor::Icon::SYSTEM); } }); @@ -2784,9 +2785,11 @@ void Application::keyPressEvent(QKeyEvent* event) { auto cursor = Cursor::Manager::instance().getCursor(); auto curIcon = cursor->getIcon(); if (curIcon == Cursor::Icon::DEFAULT) { - cursor->setIcon(Cursor::Icon::LINK); + showCursor(Cursor::Icon::SYSTEM); + } else if (curIcon == Cursor::Icon::SYSTEM) { + showCursor(Cursor::Icon::LINK); } else { - cursor->setIcon(Cursor::Icon::DEFAULT); + showCursor(Cursor::Icon::DEFAULT); } } else { resetSensors(true); @@ -3958,10 +3961,13 @@ void Application::updateMyAvatarLookAtPosition() { } } else { AvatarSharedPointer lookingAt = myAvatar->getLookAtTargetAvatar().lock(); - if (lookingAt && myAvatar.get() != lookingAt.get()) { + bool haveLookAtCandidate = lookingAt && myAvatar.get() != lookingAt.get(); + auto avatar = static_pointer_cast(lookingAt); + bool mutualLookAtSnappingEnabled = avatar && avatar->getLookAtSnappingEnabled() && myAvatar->getLookAtSnappingEnabled(); + if (haveLookAtCandidate && mutualLookAtSnappingEnabled) { // If I am looking at someone else, look directly at one of their eyes isLookingAtSomeone = true; - auto lookingAtHead = static_pointer_cast(lookingAt)->getHead(); + auto lookingAtHead = avatar->getHead(); const float MAXIMUM_FACE_ANGLE = 65.0f * RADIANS_PER_DEGREE; glm::vec3 lookingAtFaceOrientation = lookingAtHead->getFinalOrientationInWorldFrame() * IDENTITY_FORWARD; diff --git a/interface/src/Application.h b/interface/src/Application.h index e8507c39e8..2d2278c904 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -54,6 +54,7 @@ #include "BandwidthRecorder.h" #include "FancyCamera.h" #include "ConnectionMonitor.h" +#include "CursorManager.h" #include "gpu/Context.h" #include "Menu.h" #include "octree/OctreePacketProcessor.h" @@ -163,7 +164,7 @@ public: QSize getDeviceSize() const; bool hasFocus() const; - void showCursor(const QCursor& cursor); + void showCursor(const Cursor::Icon& cursor); bool isThrottleRendering() const; @@ -639,7 +640,7 @@ private: void checkChangeCursor(); mutable QMutex _changeCursorLock { QMutex::Recursive }; - QCursor _desiredCursor{ Qt::BlankCursor }; + Qt::CursorShape _desiredCursor{ Qt::BlankCursor }; bool _cursorNeedsChanging { false }; QThread* _deadlockWatchdogThread; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4138798484..98560acd57 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -504,6 +504,11 @@ Menu::Menu() { action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowOtherLookAtVectors, 0, false); connect(action, &QAction::triggered, [this]{ Avatar::setShowOtherLookAtVectors(isOptionChecked(MenuOption::ShowOtherLookAtVectors)); }); + action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableLookAtSnapping, 0, true); + connect(action, &QAction::triggered, [this, avatar]{ + avatar->setProperty("lookAtSnappingEnabled", isOptionChecked(MenuOption::EnableLookAtSnapping)); + }); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawDefaultPose, 0, false, avatar.get(), SLOT(setEnableDebugDrawDefaultPose(bool))); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b6d72f5446..676340a894 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -177,6 +177,7 @@ namespace MenuOption { const QString ShowDSConnectTable = "Show Domain Connection Timing"; const QString ShowMyLookAtVectors = "Show My Eye Vectors"; const QString ShowOtherLookAtVectors = "Show Other Eye Vectors"; + const QString EnableLookAtSnapping = "Enable LookAt Snapping"; const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats"; const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; const QString SimulateEyeTracking = "Simulate"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9996df2afc..7b5fefb2d0 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -834,6 +834,9 @@ void MyAvatar::saveData() { settings.setValue("scale", _targetScale); + settings.setValue("yawSpeed", _yawSpeed); + settings.setValue("pitchSpeed", _pitchSpeed); + settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ? "" : @@ -974,6 +977,9 @@ void MyAvatar::loadData() { getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f)); + _yawSpeed = loadSetting(settings, "yawSpeed", _yawSpeed); + _pitchSpeed = loadSetting(settings, "pitchSpeed", _pitchSpeed); + _targetScale = loadSetting(settings, "scale", 1.0f); setScale(glm::vec3(_targetScale)); @@ -1099,6 +1105,15 @@ int MyAvatar::parseDataFromBuffer(const QByteArray& buffer) { return buffer.size(); } +ScriptAvatarData* MyAvatar::getTargetAvatar() const { + auto avatar = std::static_pointer_cast(_lookAtTargetAvatar.lock()); + if (avatar) { + return new ScriptAvatar(avatar); + } else { + return nullptr; + } +} + void MyAvatar::updateLookAtTargetAvatar() { // // Look at the avatar whose eyes are closest to the ray in direction of my avatar's head @@ -1127,9 +1142,8 @@ void MyAvatar::updateLookAtTargetAvatar() { if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { _lookAtTargetAvatar = avatarPointer; _targetAvatarPosition = avatarPointer->getPosition(); - smallestAngleTo = angleTo; } - if (isLookingAtMe(avatar)) { + if (_lookAtSnappingEnabled && avatar->getLookAtSnappingEnabled() && isLookingAtMe(avatar)) { // Alter their gaze to look directly at my camera; this looks more natural than looking at my avatar's face. glm::vec3 lookAtPosition = avatar->getHead()->getLookAtPosition(); // A position, in world space, on my avatar. @@ -1146,14 +1160,19 @@ void MyAvatar::updateLookAtTargetAvatar() { ViewFrustum viewFrustum; qApp->copyViewFrustum(viewFrustum); + glm::vec3 viewPosition = viewFrustum.getPosition(); + glm::quat viewOrientation = viewFrustum.getOrientation(); +#if DEBUG_ALWAYS_LOOKAT_EYES_NOT_CAMERA + viewPosition = (avatarLeftEye + avatarRightEye) / 2.0f; +#endif // scale gazeOffset by IPD, if wearing an HMD. if (qApp->isHMDMode()) { glm::mat4 leftEye = qApp->getEyeOffset(Eye::Left); glm::mat4 rightEye = qApp->getEyeOffset(Eye::Right); glm::vec3 leftEyeHeadLocal = glm::vec3(leftEye[3]); glm::vec3 rightEyeHeadLocal = glm::vec3(rightEye[3]); - glm::vec3 humanLeftEye = viewFrustum.getPosition() + (viewFrustum.getOrientation() * leftEyeHeadLocal); - glm::vec3 humanRightEye = viewFrustum.getPosition() + (viewFrustum.getOrientation() * rightEyeHeadLocal); + glm::vec3 humanLeftEye = + (viewOrientation * leftEyeHeadLocal); + glm::vec3 humanRightEye = viewPosition + (viewOrientation * rightEyeHeadLocal); auto hmdInterface = DependencyManager::get(); float ipdScale = hmdInterface->getIPDScale(); @@ -1167,7 +1186,7 @@ void MyAvatar::updateLookAtTargetAvatar() { } // And now we can finally add that offset to the camera. - glm::vec3 corrected = viewFrustum.getPosition() + gazeOffset; + glm::vec3 corrected = viewPosition + gazeOffset; avatar->getHead()->setCorrectedLookAtPosition(corrected); @@ -2199,6 +2218,7 @@ void MyAvatar::updateMotionBehaviorFromMenu() { _motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; } setCollisionsEnabled(menu->isOptionChecked(MenuOption::EnableAvatarCollisions)); + setProperty("lookAtSnappingEnabled", menu->isOptionChecked(MenuOption::EnableLookAtSnapping)); } void MyAvatar::setCollisionsEnabled(bool enabled) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fde350a43e..2f5be25a4b 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "AtRestDetector.h" #include "MyCharacterController.h" @@ -132,6 +133,9 @@ class MyAvatar : public Avatar { Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled) Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls) + Q_PROPERTY(float yawSpeed MEMBER _yawSpeed) + Q_PROPERTY(float pitchSpeed MEMBER _pitchSpeed) + public: enum DriveKeys { TRANSLATE_X = 0, @@ -368,6 +372,7 @@ public: Q_INVOKABLE glm::vec3 getEyePosition() const { return getHead()->getEyePosition(); } Q_INVOKABLE glm::vec3 getTargetAvatarPosition() const { return _targetAvatarPosition; } + Q_INVOKABLE ScriptAvatarData* getTargetAvatar() const; Q_INVOKABLE glm::vec3 getLeftHandPosition() const; Q_INVOKABLE glm::vec3 getRightHandPosition() const; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index d78287a0e7..4575adc762 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -506,8 +506,8 @@ void Avatar::postUpdate(float deltaTime) { if (isMyAvatar() ? showMyLookAtVectors : showOtherLookAtVectors) { const float EYE_RAY_LENGTH = 10.0; - const glm::vec4 BLUE(0.0f, 0.0f, 1.0f, 1.0f); - const glm::vec4 RED(1.0f, 0.0f, 0.0f, 1.0f); + const glm::vec4 BLUE(0.0f, 0.0f, _lookAtSnappingEnabled ? 1.0f : 0.25f, 1.0f); + const glm::vec4 RED(_lookAtSnappingEnabled ? 1.0f : 0.25f, 0.0f, 0.0f, 1.0f); int leftEyeJoint = getJointIndex("LeftEye"); glm::vec3 leftEyePosition; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d82068b8ac..ee46da42f8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -85,6 +85,8 @@ AvatarData::AvatarData() : ASSERT(sizeof(AvatarDataPacket::AdditionalFlags) == AvatarDataPacket::ADDITIONAL_FLAGS_SIZE); ASSERT(sizeof(AvatarDataPacket::ParentInfo) == AvatarDataPacket::PARENT_INFO_SIZE); ASSERT(sizeof(AvatarDataPacket::FaceTrackerInfo) == AvatarDataPacket::FACE_TRACKER_INFO_SIZE); + + connect(this, &AvatarData::lookAtSnappingChanged, this, &AvatarData::markIdentityDataChanged); } AvatarData::~AvatarData() { @@ -1479,14 +1481,18 @@ void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& ide >> identityOut.displayName >> identityOut.sessionDisplayName >> identityOut.avatarEntityData - >> identityOut.sequenceId; + >> identityOut.sequenceId + >> identityOut.lookAtSnappingEnabled + ; #ifdef WANT_DEBUG qCDebug(avatars) << __FUNCTION__ << "identityOut.uuid:" << identityOut.uuid << "identityOut.skeletonModelURL:" << identityOut.skeletonModelURL << "identityOut.displayName:" << identityOut.displayName - << "identityOut.sessionDisplayName:" << identityOut.sessionDisplayName; + << "identityOut.sessionDisplayName:" << identityOut.sessionDisplayName + << "identityOut.lookAtSnappingEnabled:" << identityOut.lookAtSnappingEnabled + ; #endif } @@ -1541,6 +1547,13 @@ void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityC identityChanged = true; } + if (_lookAtSnappingEnabled != identity.lookAtSnappingEnabled) { +#ifdef DEBUG_LOOKAT_SNAPPING + qCDebug(avatars) << __FUNCTION__ << identity.sessionDisplayName << "_lookAtSnappingEnabled" << _lookAtSnappingEnabled << "->" << identity.lookAtSnappingEnabled; +#endif + setProperty("lookAtSnappingEnabled", identity.lookAtSnappingEnabled); + identityChanged = true; + } } QByteArray AvatarData::identityByteArray() const { @@ -1549,13 +1562,16 @@ QByteArray AvatarData::identityByteArray() const { const QUrl& urlToSend = cannonicalSkeletonModelURL(emptyURL); // depends on _skeletonModelURL _avatarEntitiesLock.withReadLock([&] { - identityStream << getSessionUUID() - << urlToSend - << _attachmentData - << _displayName - << getSessionDisplayNameForTransport() // depends on _sessionDisplayName - << _avatarEntityData - << _identitySequenceId; + identityStream + << getSessionUUID() + << urlToSend + << _attachmentData + << _displayName + << getSessionDisplayNameForTransport() // depends on _sessionDisplayName + << _avatarEntityData + << _identitySequenceId + << _lookAtSnappingEnabled + ; }); return identityData; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 4104615cfe..6f29b6af22 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -323,6 +323,7 @@ class AvatarData : public QObject, public SpatiallyNestable { Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) Q_PROPERTY(float scale READ getTargetScale WRITE setTargetScale) + Q_PROPERTY(float density READ getDensity) Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition) Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw) Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch) @@ -344,6 +345,7 @@ class AvatarData : public QObject, public SpatiallyNestable { // sessionDisplayName is sanitized, defaulted version displayName that is defined by the AvatarMixer rather than by Interface clients. // The result is unique among all avatars present at the time. Q_PROPERTY(QString sessionDisplayName READ getSessionDisplayName WRITE setSessionDisplayName) + Q_PROPERTY(bool lookAtSnappingEnabled MEMBER _lookAtSnappingEnabled NOTIFY lookAtSnappingChanged) Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript) Q_PROPERTY(QVector attachmentData READ getAttachmentData WRITE setAttachmentData) @@ -532,6 +534,7 @@ public: QString sessionDisplayName; AvatarEntityMap avatarEntityData; quint64 sequenceId; + bool lookAtSnappingEnabled; }; static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut); @@ -545,6 +548,8 @@ public: const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; } const QString& getDisplayName() const { return _displayName; } const QString& getSessionDisplayName() const { return _sessionDisplayName; } + bool getLookAtSnappingEnabled() const { return _lookAtSnappingEnabled; } + virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setDisplayName(const QString& displayName); @@ -633,6 +638,7 @@ public: signals: void displayNameChanged(); + void lookAtSnappingChanged(bool enabled); public slots: void sendAvatarDataPacket(); @@ -697,6 +703,7 @@ protected: QVector _attachmentData; QString _displayName; QString _sessionDisplayName { }; + bool _lookAtSnappingEnabled { true }; QUrl cannonicalSkeletonModelURL(const QUrl& empty) const; QHash _jointIndices; ///< 1-based, since zero is returned for missing keys diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index 01d7f293d8..49e53952d4 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -15,6 +15,7 @@ ScriptAvatarData::ScriptAvatarData(AvatarSharedPointer avatarData) : _avatarData(avatarData) { QObject::connect(avatarData.get(), &AvatarData::displayNameChanged, this, &ScriptAvatarData::displayNameChanged); + QObject::connect(avatarData.get(), &AvatarData::lookAtSnappingChanged, this, &ScriptAvatarData::lookAtSnappingChanged); } // @@ -152,6 +153,13 @@ QString ScriptAvatarData::getSessionDisplayName() const { return QString(); } } +bool ScriptAvatarData::getLookAtSnappingEnabled() const { + if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) { + return sharedAvatarData->getLookAtSnappingEnabled(); + } else { + return false; + } +} // // IDENTIFIER PROPERTIES // END diff --git a/libraries/avatars/src/ScriptAvatarData.h b/libraries/avatars/src/ScriptAvatarData.h index d763b6e97a..4a95333402 100644 --- a/libraries/avatars/src/ScriptAvatarData.h +++ b/libraries/avatars/src/ScriptAvatarData.h @@ -45,6 +45,7 @@ class ScriptAvatarData : public QObject { Q_PROPERTY(QUuid sessionUUID READ getSessionUUID) Q_PROPERTY(QString displayName READ getDisplayName NOTIFY displayNameChanged) Q_PROPERTY(QString sessionDisplayName READ getSessionDisplayName) + Q_PROPERTY(bool lookAtSnappingEnabled READ getLookAtSnappingEnabled NOTIFY lookAtSnappingChanged) // // ATTACHMENT AND JOINT PROPERTIES @@ -95,6 +96,7 @@ public: QUuid getSessionUUID() const; QString getDisplayName() const; QString getSessionDisplayName() const; + bool getLookAtSnappingEnabled() const; // // ATTACHMENT AND JOINT PROPERTIES @@ -127,6 +129,7 @@ public: signals: void displayNameChanged(); + void lookAtSnappingChanged(bool enabled); public slots: glm::quat getAbsoluteJointRotationInObjectFrame(int index) const; diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp index d8e0c59da7..00e49b78db 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp @@ -436,7 +436,7 @@ glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const mousePosition -= 1.0; mousePosition.y *= -1.0f; - vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; + vec2 mouseSize = CURSOR_PIXEL_SIZE * Cursor::Manager::instance().getScale() / canvasSize; result = glm::scale(glm::translate(glm::mat4(), vec3(mousePosition, 0.0f)), vec3(mouseSize, 1.0f)); } return result; @@ -450,3 +450,13 @@ QVariant ReticleInterface::getPosition() const { void ReticleInterface::setPosition(QVariant position) { _compositor->setReticlePosition(vec2FromVariant(position)); } + +float ReticleInterface::getScale() const { + auto& cursorManager = Cursor::Manager::instance(); + return cursorManager.getScale(); +} + +void ReticleInterface::setScale(float scale) { + auto& cursorManager = Cursor::Manager::instance(); + cursorManager.setScale(scale); +} diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h index 5be2d68cf9..73e010fdd4 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h @@ -179,6 +179,7 @@ class ReticleInterface : public QObject { Q_PROPERTY(QVariant position READ getPosition WRITE setPosition) Q_PROPERTY(bool visible READ getVisible WRITE setVisible) Q_PROPERTY(float depth READ getDepth WRITE setDepth) + Q_PROPERTY(float scale READ getScale WRITE setScale) Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition) Q_PROPERTY(bool mouseCaptured READ isMouseCaptured) Q_PROPERTY(bool allowMouseCapture READ getAllowMouseCapture WRITE setAllowMouseCapture) @@ -200,6 +201,9 @@ public: Q_INVOKABLE float getDepth() { return _compositor->getReticleDepth(); } Q_INVOKABLE void setDepth(float depth) { _compositor->setReticleDepth(depth); } + Q_INVOKABLE float getScale() const; + Q_INVOKABLE void setScale(float scale); + Q_INVOKABLE QVariant getPosition() const; Q_INVOKABLE void setPosition(QVariant position); diff --git a/libraries/ui/src/CursorManager.cpp b/libraries/ui/src/CursorManager.cpp index f768b5f227..28b84efb32 100644 --- a/libraries/ui/src/CursorManager.cpp +++ b/libraries/ui/src/CursorManager.cpp @@ -35,6 +35,7 @@ namespace Cursor { static uint16_t _customIconId = Icon::USER_BASE; Manager::Manager() { + ICONS[Icon::SYSTEM] = PathUtils::resourcesPath() + "images/cursor-none.png"; ICONS[Icon::DEFAULT] = PathUtils::resourcesPath() + "images/arrow.png"; ICONS[Icon::LINK] = PathUtils::resourcesPath() + "images/link.png"; } diff --git a/libraries/ui/src/CursorManager.h b/libraries/ui/src/CursorManager.h index 99d5ccdc77..6c0bf162b3 100644 --- a/libraries/ui/src/CursorManager.h +++ b/libraries/ui/src/CursorManager.h @@ -18,6 +18,7 @@ namespace Cursor { }; enum Icon { + SYSTEM, DEFAULT, LINK, GRAB, From d3127ba97557551b76847a314d9d6d1e76905f6a Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 19 Jun 2017 20:18:39 -0400 Subject: [PATCH 002/174] remove unintended merge line --- libraries/avatars/src/AvatarData.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7f02de8a29..affd5af147 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -370,7 +370,6 @@ public: virtual ~AvatarData(); static const QUrl& defaultFullAvatarModelUrl(); - QUrl cannonicalSkeletonModelURL(const QUrl& empty) const; virtual bool isMyAvatar() const { return false; } From fbeaa01f7db70dec523c76c649603d8c4c7f5529 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 20 Jun 2017 01:51:33 -0400 Subject: [PATCH 003/174] remerge master / remove debug block --- libraries/avatars/src/AvatarData.cpp | 3 --- libraries/avatars/src/AvatarData.h | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b0423f4272..29907d6a3e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1552,9 +1552,6 @@ void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityC } if (_lookAtSnappingEnabled != identity.lookAtSnappingEnabled) { -#ifdef DEBUG_LOOKAT_SNAPPING - qCDebug(avatars) << __FUNCTION__ << identity.sessionDisplayName << "_lookAtSnappingEnabled" << _lookAtSnappingEnabled << "->" << identity.lookAtSnappingEnabled; -#endif setProperty("lookAtSnappingEnabled", identity.lookAtSnappingEnabled); identityChanged = true; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index affd5af147..fafe878027 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -370,6 +370,7 @@ public: virtual ~AvatarData(); static const QUrl& defaultFullAvatarModelUrl(); + QUrl cannonicalSkeletonModelURL(const QUrl& empty) const; virtual bool isMyAvatar() const { return false; } @@ -548,7 +549,6 @@ public: const QString& getDisplayName() const { return _displayName; } const QString& getSessionDisplayName() const { return _sessionDisplayName; } bool getLookAtSnappingEnabled() const { return _lookAtSnappingEnabled; } - virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setDisplayName(const QString& displayName); @@ -703,7 +703,6 @@ protected: QString _displayName; QString _sessionDisplayName { }; bool _lookAtSnappingEnabled { true }; - QUrl cannonicalSkeletonModelURL(const QUrl& empty) const; QHash _jointIndices; ///< 1-based, since zero is returned for missing keys QStringList _jointNames; ///< in order of depth-first traversal From b46219241ce428b82e0252081b00af69969308be Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 26 Jun 2017 22:44:31 -0400 Subject: [PATCH 004/174] add peakValueListChanged scaffolding --- libraries/audio-client/src/AudioClient.cpp | 12 +++++++++--- libraries/audio-client/src/AudioClient.h | 10 +++++++++- libraries/audio-client/src/AudioPeakValues.cpp | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 libraries/audio-client/src/AudioPeakValues.cpp diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index fc54a04a5e..7a1d8edccd 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -224,13 +224,18 @@ AudioClient::AudioClient() : // start a thread to detect any device changes _checkDevicesTimer = new QTimer(this); connect(_checkDevicesTimer, &QTimer::timeout, [this] { - QtConcurrent::run(QThreadPool::globalInstance(), [this] { - checkDevices(); - }); + QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkDevices(); }); }); const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000; _checkDevicesTimer->start(DEVICE_CHECK_INTERVAL_MSECS); + // start a thread to detect peak value changes + _checkPeakValuesTimer = new QTimer(this); + connect(_checkPeakValuesTimer, &QTimer::timeout, [this] { + QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkPeakValues(); }); + }); + const unsigned long PEAK_VALUES_CHECK_INTERVAL_SECS = 50; + configureReverb(); @@ -262,6 +267,7 @@ void AudioClient::cleanupBeforeQuit() { stop(); _checkDevicesTimer->stop(); + _checkPeakValuesTimer->stop(); } void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 54ce3aa6c2..79e82526c6 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -148,6 +148,8 @@ public: QAudioDeviceInfo getActiveAudioDevice(QAudio::Mode mode) const; QList getAudioDevices(QAudio::Mode mode) const; + void enablePeakValues(bool enable) { _enablePeakValues = enable; } + static const float CALLBACK_ACCELERATOR_RATIO; bool getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QString& deviceName); @@ -220,6 +222,7 @@ signals: void deviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device); void devicesChanged(QAudio::Mode mode, const QList& devices); + void peakValueListChanged(const QList peakValueList); void receivedFirstPacket(); void disconnected(); @@ -238,9 +241,12 @@ private: friend class CheckDevicesThread; friend class LocalInjectorsThread; + // background tasks + void checkDevices(); + void checkPeakValues(); + void outputFormatChanged(); void handleAudioInput(QByteArray& audioBuffer); - void checkDevices(); void prepareLocalAudioInjectors(std::unique_ptr localAudioLock = nullptr); bool mixLocalAudioInjectors(float* mixBuffer); float azimuthForSource(const glm::vec3& relativePosition); @@ -293,6 +299,7 @@ private: std::atomic _localInjectorsAvailable { false }; MixedProcessedAudioStream _receivedAudioStream; bool _isStereoInput; + std::atomic _enablePeakValues { false }; quint64 _outputStarveDetectionStartTimeMsec; int _outputStarveDetectionCount; @@ -391,6 +398,7 @@ private: RateCounter<> _audioInbound; QTimer* _checkDevicesTimer { nullptr }; + QTimer* _checkPeakValuesTimer { nullptr }; }; diff --git a/libraries/audio-client/src/AudioPeakValues.cpp b/libraries/audio-client/src/AudioPeakValues.cpp new file mode 100644 index 0000000000..021f23b907 --- /dev/null +++ b/libraries/audio-client/src/AudioPeakValues.cpp @@ -0,0 +1,16 @@ +// +// AudioPeakValues.cpp +// interface/src +// +// Created by Zach Pomerantz on 6/26/2017 +// Copyright 2013 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 +// + +#include "AudioClient.h" + +void AudioClient::checkPeakValues() { + // TODO +} From 3f57e5eb4d9cc145915948b2c91860c994cac344 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 27 Jun 2017 14:04:52 -0400 Subject: [PATCH 005/174] implement peakValueListChanged --- libraries/audio-client/src/AudioClient.cpp | 10 +- libraries/audio-client/src/AudioClient.h | 1 + .../audio-client/src/AudioPeakValues.cpp | 164 +++++++++++++++++- 3 files changed, 169 insertions(+), 6 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 7a1d8edccd..7f872443be 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -77,7 +77,7 @@ Setting::Handle staticJitterBufferFrames("staticJitterBufferFrames", // protect the Qt internal device list using Mutex = std::mutex; using Lock = std::unique_lock; -static Mutex _deviceMutex; +Mutex _deviceMutex; // thread-safe QList getAvailableDevices(QAudio::Mode mode) { @@ -235,7 +235,7 @@ AudioClient::AudioClient() : QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkPeakValues(); }); }); const unsigned long PEAK_VALUES_CHECK_INTERVAL_SECS = 50; - + _checkPeakValuesTimer->start(PEAK_VALUES_CHECK_INTERVAL_SECS); configureReverb(); @@ -308,8 +308,6 @@ QString getWinDeviceName(IMMDevice* pEndpoint) { QString deviceName; IPropertyStore* pPropertyStore; pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); - pEndpoint->Release(); - pEndpoint = nullptr; PROPVARIANT pv; PropVariantInit(&pv); HRESULT hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); @@ -338,6 +336,8 @@ QString AudioClient::getWinDeviceName(wchar_t* guid) { deviceName = QString("NONE"); } else { deviceName = ::getWinDeviceName(pEndpoint); + pEndpoint->Release(); + pEndpoint = nullptr; } pMMDeviceEnumerator->Release(); pMMDeviceEnumerator = nullptr; @@ -421,6 +421,8 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { deviceName = QString("NONE"); } else { deviceName = getWinDeviceName(pEndpoint); + pEndpoint->Release(); + pEndpoint = nullptr; } pMMDeviceEnumerator->Release(); pMMDeviceEnumerator = NULL; diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 79e82526c6..63b1398d09 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -149,6 +149,7 @@ public: QList getAudioDevices(QAudio::Mode mode) const; void enablePeakValues(bool enable) { _enablePeakValues = enable; } + bool peakValuesAvailable() const; static const float CALLBACK_ACCELERATOR_RATIO; diff --git a/libraries/audio-client/src/AudioPeakValues.cpp b/libraries/audio-client/src/AudioPeakValues.cpp index 021f23b907..3df469b830 100644 --- a/libraries/audio-client/src/AudioPeakValues.cpp +++ b/libraries/audio-client/src/AudioPeakValues.cpp @@ -11,6 +11,166 @@ #include "AudioClient.h" -void AudioClient::checkPeakValues() { - // TODO +#ifdef Q_OS_WIN + +#include +#include +#include +#include + +#include + +#define RETURN_ON_FAIL(result) if (FAILED(result)) { return; } +#define CONTINUE_ON_FAIL(result) if (FAILED(result)) { continue; } + +extern QString getWinDeviceName(IMMDevice* pEndpoint); +extern std::mutex _deviceMutex; + +std::map> activeClients; + +template +void release(T* t) { + t->Release(); } + +template <> +void release(IAudioClient* audioClient) { + audioClient->Stop(); + audioClient->Release(); +} + +void AudioClient::checkPeakValues() { + // prepare the windows environment + CoInitialize(NULL); + + // if disabled, clean up active clients + if (!_enablePeakValues) { + activeClients.clear(); + return; + } + + // lock the devices so the _inputDevices list is static + std::unique_lock lock(_deviceMutex); + HRESULT result; + + // initialize the payload + QList peakValueList; + for (int i = 0; i < _inputDevices.size(); ++i) { + peakValueList.push_back(0.0f); + } + + std::shared_ptr enumerator; + { + IMMDeviceEnumerator* pEnumerator; + result = CoCreateInstance( + __uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, + __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator); + RETURN_ON_FAIL(result); + enumerator = std::shared_ptr(pEnumerator, &release); + } + + std::shared_ptr endpoints; + { + IMMDeviceCollection* pEndpoints; + result = enumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &pEndpoints); + RETURN_ON_FAIL(result); + endpoints = std::shared_ptr(pEndpoints, &release); + } + + UINT count; + { + result = endpoints->GetCount(&count); + RETURN_ON_FAIL(result); + } + + IMMDevice* pDevice; + std::shared_ptr device; + IAudioMeterInformation* pMeterInfo; + std::shared_ptr meterInfo; + IAudioClient* pAudioClient; + std::shared_ptr audioClient; + DWORD hardwareSupport; + LPWSTR pDeviceId = NULL; + LPWAVEFORMATEX format; + float peakValue; + QString deviceName; + int deviceIndex; + for (UINT i = 0; i < count; ++i) { + result = endpoints->Item(i, &pDevice); + CONTINUE_ON_FAIL(result); + device = std::shared_ptr(pDevice, &release); + + // if the device isn't listed through Qt, skip it + deviceName = ::getWinDeviceName(pDevice); + deviceIndex = 0; + for (; deviceIndex < _inputDevices.size(); ++deviceIndex) { + if (deviceName == _inputDevices[deviceIndex].deviceName()) { + break; + } + } + if (deviceIndex >= _inputDevices.size()) { + continue; + } + + //continue; + + result = device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_ALL, NULL, (void**)&pMeterInfo); + CONTINUE_ON_FAIL(result); + meterInfo = std::shared_ptr(pMeterInfo, &release); + + //continue; + + hardwareSupport; + result = meterInfo->QueryHardwareSupport(&hardwareSupport); + CONTINUE_ON_FAIL(result); + + //continue; + + // if the device has no hardware support (USB)... + if (!(hardwareSupport & ENDPOINT_HARDWARE_SUPPORT_METER)) { + result = device->GetId(&pDeviceId); + CONTINUE_ON_FAIL(result); + std::wstring deviceId(pDeviceId); + CoTaskMemFree(pDeviceId); + + //continue; + + // ...and no active client... + if (activeClients.find(deviceId) == activeClients.end()) { + result = device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient); + CONTINUE_ON_FAIL(result); + audioClient = std::shared_ptr(pAudioClient, &release); + + //continue; + + // ...activate a client + audioClient->GetMixFormat(&format); + audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, format, NULL); + audioClient->Start(); + + //continue; + + activeClients[deviceId] = audioClient; + } + } + + // get the peak value and put it in the payload + meterInfo->GetPeakValue(&peakValue); + peakValueList[deviceIndex] = peakValue; + } + + emit peakValueListChanged(peakValueList); +} + +bool AudioClient::peakValuesAvailable() const { + return true; +} + +#else +void AudioClient::checkPeakValues() { +} + +bool AudioClient::peakValuesAvailable() const { + return false; +} +#endif \ No newline at end of file From 5353437f5915b9c88ab276a81dfdd95276a8df8d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 27 Jun 2017 17:37:13 -0400 Subject: [PATCH 006/174] add peakValues to scripting API --- interface/src/scripting/AudioDevices.cpp | 82 ++++++++++++++++++------ interface/src/scripting/AudioDevices.h | 63 +++++++++++++++--- 2 files changed, 118 insertions(+), 27 deletions(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index b0ea8226e8..1c31d7aa5a 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -34,28 +34,44 @@ Setting::Handle& getSetting(bool contextIsHMD, QAudio::Mode mode) { } } -QHash AudioDeviceList::_roles { - { Qt::DisplayRole, "display" }, - { Qt::CheckStateRole, "selected" } +enum AudioDeviceRole { + DisplayRole = Qt::DisplayRole, + CheckStateRole = Qt::CheckStateRole, + PeakRole = Qt::UserRole }; + +QHash AudioDeviceList::_roles { + { DisplayRole, "display" }, + { CheckStateRole, "selected" }, + { PeakRole, "peak" } +}; + Qt::ItemFlags AudioDeviceList::_flags { Qt::ItemIsSelectable | Qt::ItemIsEnabled }; QVariant AudioDeviceList::data(const QModelIndex& index, int role) const { - if (!index.isValid() || index.row() >= _devices.size()) { + if (!index.isValid() || index.row() >= rowCount()) { return QVariant(); } - if (role == Qt::DisplayRole) { - return _devices.at(index.row()).display; - } else if (role == Qt::CheckStateRole) { - return _devices.at(index.row()).selected; + if (role == DisplayRole) { + return _devices.at(index.row())->display; + } else if (role == CheckStateRole) { + return _devices.at(index.row())->selected; } else { return QVariant(); } } +QVariant AudioInputDeviceList::data(const QModelIndex& index, int role) const { + if (index.isValid() && index.row() < rowCount() && role == PeakRole) { + return std::static_pointer_cast(_devices.at(index.row()))->peak; + } else { + return AudioDeviceList::data(index, role); + } +} + bool AudioDeviceList::setData(const QModelIndex& index, const QVariant& value, int role) { - if (!index.isValid() || index.row() >= _devices.size() || role != Qt::CheckStateRole) { + if (!index.isValid() || index.row() >= rowCount() || role != CheckStateRole) { return false; } @@ -73,19 +89,19 @@ bool AudioDeviceList::setDevice(int row, bool fromUser) { auto& device = _devices[row]; // skip if already selected - if (!device.selected) { + if (!device->selected) { auto client = DependencyManager::get(); QMetaObject::invokeMethod(client.data(), "switchAudioDevice", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, success), Q_ARG(QAudio::Mode, _mode), - Q_ARG(const QAudioDeviceInfo&, device.info)); + Q_ARG(const QAudioDeviceInfo&, device->info)); if (success) { - device.selected = true; + device->selected = true; if (fromUser) { - emit deviceSelected(device.info, _selectedDevice); + emit deviceSelected(device->info, _selectedDevice); } - emit deviceChanged(device.info); + emit deviceChanged(device->info); } } @@ -100,7 +116,7 @@ void AudioDeviceList::resetDevice(bool contextIsHMD, const QString& device) { if (!device.isNull()) { auto i = 0; for (; i < rowCount(); ++i) { - if (device == _devices[i].info.deviceName()) { + if (device == _devices[i]->info.deviceName()) { break; } } @@ -138,8 +154,8 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device) { _selectedDevice = device; QModelIndex index; - for (auto i = 0; i < _devices.size(); ++i) { - AudioDevice& device = _devices[i]; + for (auto i = 0; i < rowCount(); ++i) { + AudioDevice& device = *_devices[i]; if (device.selected && device.info != _selectedDevice) { device.selected = false; @@ -166,17 +182,47 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { .remove("Device") .replace(" )", ")"); device.selected = (device.info == _selectedDevice); - _devices.push_back(device); + _devices.push_back(newDevice(device)); } endResetModel(); } +bool AudioInputDeviceList::peakValuesAvailable() { + std::call_once(_peakFlag, [&] { + _peakValuesAvailable = DependencyManager::get()->peakValuesAvailable(); + }); + return _peakValuesAvailable; +} + +void AudioInputDeviceList::setPeakValuesEnabled(bool enable) { + if (peakValuesAvailable() && (enable != _peakValuesEnabled)) { + DependencyManager::get()->enablePeakValues(enable); + _peakValuesEnabled = enable; + emit peakValuesEnabledChanged(_peakValuesEnabled); + } +} + +void AudioInputDeviceList::onPeakValueListChanged(const QList& peakValueList) { + assert(_mode == QAudio::AudioInput); + + if (peakValueList.length() != rowCount()) { + qWarning() << "AudioDeviceList" << __FUNCTION__ << "length mismatch"; + } + + for (auto i = 0; i < rowCount(); ++i) { + std::static_pointer_cast(_devices[i])->peak = peakValueList[i]; + } + + emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0), { PeakRole }); +} + AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) { auto client = DependencyManager::get(); connect(client.data(), &AudioClient::deviceChanged, this, &AudioDevices::onDeviceChanged, Qt::QueuedConnection); connect(client.data(), &AudioClient::devicesChanged, this, &AudioDevices::onDevicesChanged, Qt::QueuedConnection); + connect(client.data(), &AudioClient::peakValueListChanged, &_inputs, &AudioInputDeviceList::onPeakValueListChanged, Qt::QueuedConnection); // connections are made after client is initialized, so we must also fetch the devices _inputs.onDeviceChanged(client->getActiveAudioDevice(QAudio::AudioInput)); diff --git a/interface/src/scripting/AudioDevices.h b/interface/src/scripting/AudioDevices.h index cd47ab4191..bdf03820f4 100644 --- a/interface/src/scripting/AudioDevices.h +++ b/interface/src/scripting/AudioDevices.h @@ -12,6 +12,9 @@ #ifndef hifi_scripting_AudioDevices_h #define hifi_scripting_AudioDevices_h +#include +#include + #include #include #include @@ -29,7 +32,11 @@ class AudioDeviceList : public QAbstractListModel { Q_OBJECT public: - AudioDeviceList(QAudio::Mode mode) : _mode(mode) {} + AudioDeviceList(QAudio::Mode mode = QAudio::AudioOutput) : _mode(mode) {} + ~AudioDeviceList() = default; + + virtual std::shared_ptr newDevice(const AudioDevice& device) + { return std::make_shared(device); } int rowCount(const QModelIndex& parent = QModelIndex()) const override { Q_UNUSED(parent); return _devices.size(); } QHash roleNames() const override { return _roles; } @@ -47,11 +54,11 @@ signals: const QAudioDeviceInfo& previousDevice = QAudioDeviceInfo()); void deviceChanged(const QAudioDeviceInfo& device); -private slots: +protected slots: void onDeviceChanged(const QAudioDeviceInfo& device); void onDevicesChanged(const QList& devices); -private: +protected: friend class AudioDevices; bool setDevice(int index, bool fromUser); @@ -59,16 +66,54 @@ private: static QHash _roles; static Qt::ItemFlags _flags; - QAudio::Mode _mode; + QAudio::Mode _mode { QAudio::AudioOutput }; QAudioDeviceInfo _selectedDevice; - QList _devices; + QList> _devices; +}; + +class AudioInputDevice : public AudioDevice { +public: + AudioInputDevice(const AudioDevice& device) : AudioDevice(device) {} + float peak { 0.0f }; +}; + +class AudioInputDeviceList : public AudioDeviceList { + Q_OBJECT + Q_PROPERTY(bool peakValuesAvailable READ peakValuesAvailable) + Q_PROPERTY(bool peakValuesEnabled READ peakValuesEnabled WRITE setPeakValuesEnabled NOTIFY peakValuesEnabledChanged) + +public: + AudioInputDeviceList() : AudioDeviceList(QAudio::AudioInput) {} + virtual ~AudioInputDeviceList() = default; + + virtual std::shared_ptr newDevice(const AudioDevice& device) + { return std::make_shared(device); } + + QVariant data(const QModelIndex& index, int role) const override; + +signals: + void peakValuesEnabledChanged(bool enabled); + +protected slots: + void onPeakValueListChanged(const QList& peakValueList); + +protected: + friend class AudioDevices; + + bool peakValuesAvailable(); + std::once_flag _peakFlag; + bool _peakValuesAvailable; + + bool peakValuesEnabled() const { return _peakValuesEnabled; } + void setPeakValuesEnabled(bool enable); + bool _peakValuesEnabled { false }; }; class Audio; class AudioDevices : public QObject { Q_OBJECT - Q_PROPERTY(AudioDeviceList* input READ getInputList NOTIFY nop) + Q_PROPERTY(AudioInputDeviceList* input READ getInputList NOTIFY nop) Q_PROPERTY(AudioDeviceList* output READ getOutputList NOTIFY nop) public: @@ -86,11 +131,11 @@ private slots: private: friend class Audio; - AudioDeviceList* getInputList() { return &_inputs; } + AudioInputDeviceList* getInputList() { return &_inputs; } AudioDeviceList* getOutputList() { return &_outputs; } - AudioDeviceList _inputs { QAudio::AudioInput }; - AudioDeviceList _outputs { QAudio::AudioOutput }; + AudioInputDeviceList _inputs; + AudioDeviceList _outputs; bool& _contextIsHMD; }; From 9b72ab96ff5a019d20b7a030a48c20af1bf84023 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 27 Jun 2017 17:37:24 -0400 Subject: [PATCH 007/174] add peak values to qml --- interface/resources/qml/hifi/audio/Audio.qml | 26 ++++++++++++++++--- .../audio/{InputLevel.qml => InputPeak.qml} | 6 ++--- 2 files changed, 25 insertions(+), 7 deletions(-) rename interface/resources/qml/hifi/audio/{InputLevel.qml => InputPeak.qml} (95%) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index c13bd3281a..9ebde8b61f 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -36,6 +36,23 @@ Rectangle { return root.parent.objectName == "loader"; } + property bool showPeaks: true; + function enablePeakValues() { + Audio.devices.input.peakValuesEnabled = true; + Audio.devices.input.peakValuesEnabledChanged.connect(function(enabled) { + if (!enabled && root.showPeaks) { + Audio.devices.input.peakValuesEnabled = true; + } + }); + } + function disablePeakValues() { + root.showPeaks = false; + Audio.devices.input.peakValuesEnabled = false; + } + + Component.onCompleted: enablePeakValues(); + Component.onDestruction: disablePeakValues(); + Column { y: 16; // padding does not work spacing: 16; @@ -122,7 +139,7 @@ Rectangle { width: parent.width; AudioControls.CheckBox { - Layout.maximumWidth: parent.width - level.width - 40; + Layout.maximumWidth: parent.width - inputPeak.width - 40; text: display; wrap: false; checked: selected; @@ -131,11 +148,12 @@ Rectangle { checked = Qt.binding(function() { return selected; }); // restore binding } } - InputLevel { - id: level; + InputPeak { + id: inputPeak; + visible: Audio.devices.input.peakValuesAvailable; + peak: model.peak; Layout.alignment: Qt.AlignRight; Layout.rightMargin: 30; - visible: selected; } } } diff --git a/interface/resources/qml/hifi/audio/InputLevel.qml b/interface/resources/qml/hifi/audio/InputPeak.qml similarity index 95% rename from interface/resources/qml/hifi/audio/InputLevel.qml rename to interface/resources/qml/hifi/audio/InputPeak.qml index 58ce3a1ec7..4ff49091b1 100644 --- a/interface/resources/qml/hifi/audio/InputLevel.qml +++ b/interface/resources/qml/hifi/audio/InputPeak.qml @@ -1,5 +1,5 @@ // -// InputLevel.qml +// InputPeak.qml // qml/hifi/audio // // Created by Zach Pomerantz on 6/20/2017 @@ -15,7 +15,7 @@ import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 Rectangle { - readonly property var level: Audio.inputLevel; + property var peak; width: 70; height: 8; @@ -65,7 +65,7 @@ Rectangle { Rectangle { // mask id: mask; - width: parent.width * level; + width: parent.width * peak; radius: 5; anchors { bottom: parent.bottom; From ed49f80322377e7d5e40f4229889eed13345504f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 29 Jun 2017 17:32:52 -0400 Subject: [PATCH 008/174] fix peak check secs->msecs --- libraries/audio-client/src/AudioClient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 7f872443be..88f34d60f1 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -234,8 +234,8 @@ AudioClient::AudioClient() : connect(_checkPeakValuesTimer, &QTimer::timeout, [this] { QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkPeakValues(); }); }); - const unsigned long PEAK_VALUES_CHECK_INTERVAL_SECS = 50; - _checkPeakValuesTimer->start(PEAK_VALUES_CHECK_INTERVAL_SECS); + const unsigned long PEAK_VALUES_CHECK_INTERVAL_MSECS = 50; + _checkPeakValuesTimer->start(PEAK_VALUES_CHECK_INTERVAL_MSECS); configureReverb(); From 631e5a7b0433c100b457428a6e53bc0cf9ac575a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 29 Jun 2017 17:34:01 -0400 Subject: [PATCH 009/174] add override to AudioInputDeviceList::newDevice --- interface/src/scripting/AudioDevices.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AudioDevices.h b/interface/src/scripting/AudioDevices.h index bdf03820f4..60d547f58f 100644 --- a/interface/src/scripting/AudioDevices.h +++ b/interface/src/scripting/AudioDevices.h @@ -86,7 +86,7 @@ public: AudioInputDeviceList() : AudioDeviceList(QAudio::AudioInput) {} virtual ~AudioInputDeviceList() = default; - virtual std::shared_ptr newDevice(const AudioDevice& device) + virtual std::shared_ptr newDevice(const AudioDevice& device) override { return std::make_shared(device); } QVariant data(const QModelIndex& index, int role) const override; From 9053531bda7d157b46e95c7070d5c65bdf907537 Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 3 Jul 2017 12:03:46 -0400 Subject: [PATCH 010/174] fix missing viewPosition + offset --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ab1e644420..db841e1bdf 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1271,7 +1271,7 @@ void MyAvatar::updateLookAtTargetAvatar() { glm::mat4 rightEye = qApp->getEyeOffset(Eye::Right); glm::vec3 leftEyeHeadLocal = glm::vec3(leftEye[3]); glm::vec3 rightEyeHeadLocal = glm::vec3(rightEye[3]); - glm::vec3 humanLeftEye = + (viewOrientation * leftEyeHeadLocal); + glm::vec3 humanLeftEye = viewPosition + (viewOrientation * leftEyeHeadLocal); glm::vec3 humanRightEye = viewPosition + (viewOrientation * rightEyeHeadLocal); auto hmdInterface = DependencyManager::get(); From 0da19af6f32c274f42a0fc08b18a6bb2cb220280 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 11 Jul 2017 10:06:38 -0700 Subject: [PATCH 011/174] Stop all capture devices when Audio.qml is not visible. Otherwise, Windows will continue to capture audio from all attached devices (possibly causing mic audio glitches) until Interface shutdown. --- interface/resources/qml/hifi/audio/Audio.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index aea0f0501d..4e0b4cebe2 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -52,6 +52,7 @@ Rectangle { Component.onCompleted: enablePeakValues(); Component.onDestruction: disablePeakValues(); + onVisibleChanged: visible ? enablePeakValues() : disablePeakValues(); Column { y: 16; // padding does not work From 50deee1d38fd9f66d94bd8b3731f29342e43b411 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 12 Jul 2017 12:29:25 -0700 Subject: [PATCH 012/174] Replace tabs with spaces --- interface/src/scripting/AudioDevices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index 574ec00ad6..c3958f2ad9 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -73,7 +73,7 @@ QVariant AudioInputDeviceList::data(const QModelIndex& index, int role) const { } bool AudioDeviceList::setData(const QModelIndex& index, const QVariant& value, int role) { - if (!index.isValid() || index.row() >= rowCount() || role != CheckStateRole) { + if (!index.isValid() || index.row() >= rowCount() || role != CheckStateRole) { return false; } From cf6c1ae4a54391d4d096c5e76805534fbfc60f31 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 12 Jul 2017 12:30:02 -0700 Subject: [PATCH 013/174] Replace tabs with spaces --- assignment-client/src/audio/AudioMixerSlave.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index ed63bbc298..a131e266d2 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -558,7 +558,7 @@ float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const Positio // produce an oriented angle about the y-axis glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2)); - float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward" + float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward" return (direction.x < 0.0f) ? -angle : angle; } else { From 190e1ac7d9307049cd04d73cd800fd62d432a1b7 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 18 Jul 2017 17:22:16 -0400 Subject: [PATCH 014/174] move/scope viewOrientation into the related code block --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index db841e1bdf..d2d15ea708 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1261,12 +1261,12 @@ void MyAvatar::updateLookAtTargetAvatar() { qApp->copyViewFrustum(viewFrustum); glm::vec3 viewPosition = viewFrustum.getPosition(); - glm::quat viewOrientation = viewFrustum.getOrientation(); #if DEBUG_ALWAYS_LOOKAT_EYES_NOT_CAMERA viewPosition = (avatarLeftEye + avatarRightEye) / 2.0f; #endif // scale gazeOffset by IPD, if wearing an HMD. if (qApp->isHMDMode()) { + glm::quat viewOrientation = viewFrustum.getOrientation(); glm::mat4 leftEye = qApp->getEyeOffset(Eye::Left); glm::mat4 rightEye = qApp->getEyeOffset(Eye::Right); glm::vec3 leftEyeHeadLocal = glm::vec3(leftEye[3]); From d9de0a8687d9ef70aa42fb9605395fc2e8ee3e13 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 18 Jul 2017 17:46:59 -0400 Subject: [PATCH 015/174] bump AvatarMixer protocol version --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 240697d890..1c357818e1 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -69,7 +69,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::AvatarData: case PacketType::BulkAvatarData: case PacketType::KillAvatar: - return static_cast(AvatarMixerPacketVersion::IsReplicatedInAvatarIdentity); + return static_cast(AvatarMixerPacketVersion::AvatarIdentityLookAtSnapping); case PacketType::MessagesData: return static_cast(MessageDataVersion::TextOrBinaryData); case PacketType::ICEServerHeartbeat: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 848bfd97cf..b7d3aa1eac 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -247,7 +247,8 @@ enum class AvatarMixerPacketVersion : PacketVersion { AvatarIdentitySequenceId, MannequinDefaultAvatar, AvatarIdentitySequenceFront, - IsReplicatedInAvatarIdentity + IsReplicatedInAvatarIdentity, + AvatarIdentityLookAtSnapping, }; enum class DomainConnectRequestVersion : PacketVersion { From 93ad1b6cbf8c1f3fe1a979ef21d8419b5a634f08 Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Thu, 3 Aug 2017 01:53:26 +0530 Subject: [PATCH 016/174] Add link in help page to report a problem --- interface/resources/html/tabletHelp.html | 27 +++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index cbd7ffcfe7..a6588be083 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -6,7 +6,14 @@ Welcome to Interface