From 4e9d162172c7c28c3d813373e1d8d4566ec164a3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 24 Feb 2019 13:23:20 +1300 Subject: [PATCH 01/21] AccountServices, HifiAbout, and WalletScriptingInterface JSDoc review --- interface/src/AboutUtil.h | 14 ++++---- interface/src/commerce/Wallet.h | 8 ++--- .../AccountServicesScriptingInterface.cpp | 4 +-- .../AccountServicesScriptingInterface.h | 32 +++++++++---------- .../src/scripting/WalletScriptingInterface.h | 22 ++++++------- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/interface/src/AboutUtil.h b/interface/src/AboutUtil.h index c06255aaa5..4a5074857d 100644 --- a/interface/src/AboutUtil.h +++ b/interface/src/AboutUtil.h @@ -16,8 +16,8 @@ #include /**jsdoc - * The HifiAbout API provides information about the version of Interface that is currently running. It also - * provides the ability to open a Web page in an Interface browser window. + * The HifiAbout API provides information about the version of Interface that is currently running. It also + * has the functionality to open a web page in an Interface browser window. * * @namespace HifiAbout * @@ -30,9 +30,9 @@ * @property {string} qtVersion - The Qt version used in Interface that is currently running. Read-only. * * @example Report build information for the version of Interface currently running. - * print("HiFi build date: " + HifiAbout.buildDate); // 11 Feb 2019 - * print("HiFi version: " + HifiAbout.buildVersion); // 0.78.0 - * print("Qt version: " + HifiAbout.qtVersion); // 5.10.1 + * print("HiFi build date: " + HifiAbout.buildDate); // Returns the build date of the version of Interface currently running on your machine. + * print("HiFi version: " + HifiAbout.buildVersion); // Returns the build version of Interface currently running on your machine. + * print("Qt version: " + HifiAbout.qtVersion); // Returns the Qt version details of the version of Interface currently running on your machine. */ class AboutUtil : public QObject { @@ -52,9 +52,9 @@ public: public slots: /**jsdoc - * Display a Web page in an Interface browser window. + * Display a web page in an Interface browser window. * @function HifiAbout.openUrl - * @param {string} url - The URL of the Web page to display. + * @param {string} url - The URL of the web page you want to view in Interface. */ void openUrl(const QString &url) const; private: diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index 5e5e6c9b4f..fdd6b5e2a6 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -62,8 +62,8 @@ public: * ValueMeaningDescription * * - * 0Not logged inThe user isn't logged in. - * 1Not set upThe user's wallet isn't set up. + * 0Not logged inThe user is not logged in. + * 1Not set upThe user's wallet has not been set up. * 2Pre-existingThere is a wallet present on the server but not one * locally. * 3ConflictingThere is a wallet present on the server plus one present locally, @@ -73,8 +73,8 @@ public: * 5ReadyThe wallet is ready for use. * * - *

Wallets used to be stored locally but now they're stored on the server, unless the computer once had a wallet stored - * locally in which case the wallet may be present in both places.

+ *

Wallets used to be stored locally but now they're only stored on the server. A wallet is present in both places if + * your computer previously stored its information locally.

* @typedef {number} WalletScriptingInterface.WalletStatus */ enum WalletStatus { diff --git a/interface/src/scripting/AccountServicesScriptingInterface.cpp b/interface/src/scripting/AccountServicesScriptingInterface.cpp index a3597886e9..5ede7c7a98 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.cpp +++ b/interface/src/scripting/AccountServicesScriptingInterface.cpp @@ -115,8 +115,8 @@ DownloadInfoResult::DownloadInfoResult() : /**jsdoc * Information on the assets currently being downloaded and pending download. * @typedef {object} AccountServices.DownloadInfoResult - * @property {number[]} downloading - The percentage complete for each asset currently being downloaded. - * @property {number} pending - The number of assets waiting to be download. + * @property {number[]} downloading - The download percentage of each asset currently downloading. + * @property {number} pending - The number of assets pending download. */ QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result) { QScriptValue object = engine->newObject(); diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index c08181d7c9..b5c4a6e0df 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -38,19 +38,19 @@ class AccountServicesScriptingInterface : public QObject { Q_OBJECT /**jsdoc - * The AccountServices API provides functions related to user connectivity, visibility, and asset download - * progress. + * The AccountServices API provides functions that give information on user connectivity, visibility, and + * asset download progress. * * @hifi-interface * @hifi-client-entity * @hifi-avatar * * @namespace AccountServices - * @property {string} username - The user name if the user is logged in, otherwise "Unknown user". - * Read-only. + * @property {string} username - The user name of the user logged in. If there is no user logged in, it is + * "Unknown user". Read-only. * @property {boolean} loggedIn - true if the user is logged in, otherwise false. * Read-only. - * @property {string} findableBy - The user's visibility to other people:
+ * @property {string} findableBy - The user's visibility to other users:
* "none" - user appears offline.
* "friends" - user is visible only to friends.
* "connections" - user is visible to friends and connections.
@@ -74,23 +74,23 @@ public: public slots: /**jsdoc - * Get information on the progress of downloading assets in the domain. + * Gets information on the download progress of assets in the domain. * @function AccountServices.getDownloadInfo - * @returns {AccountServices.DownloadInfoResult} Information on the progress of assets download. + * @returns {AccountServices.DownloadInfoResult} Information on the download progress of assets. */ DownloadInfoResult getDownloadInfo(); /**jsdoc - * Cause a {@link AccountServices.downloadInfoChanged|downloadInfoChanged} signal to be triggered with information on the - * current progress of the download of assets in the domain. + * Triggers a {@link AccountServices.downloadInfoChanged|downloadInfoChanged} signal with information on the current + * download progress of the assets in the domain. * @function AccountServices.updateDownloadInfo */ void updateDownloadInfo(); /**jsdoc - * Check whether the user is logged in. + * Checks whether the user is logged in. * @function AccountServices.isLoggedIn - * @returns {boolean} true if the user is logged in, false otherwise. + * @returns {boolean} true if the user is logged in, false if not. * @example Report whether you are logged in. * var isLoggedIn = AccountServices.isLoggedIn(); * print("You are logged in: " + isLoggedIn); // true or false @@ -100,7 +100,7 @@ public slots: /**jsdoc * Prompts the user to log in (the login dialog is displayed) if they're not already logged in. * @function AccountServices.checkAndSignalForAccessToken - * @returns {boolean} true if the user is already logged in, false otherwise. + * @returns {boolean} true if the user is logged in, false if not. */ bool checkAndSignalForAccessToken(); @@ -140,7 +140,7 @@ signals: /**jsdoc * Triggered when the username logged in with changes, i.e., when the user logs in or out. * @function AccountServices.myUsernameChanged - * @param {string} username - The username logged in with if the user is logged in, otherwise "". + * @param {string} username - The user name of the user logged in. If there is no user logged in, it is "". * @returns {Signal} * @example Report when your username changes. * AccountServices.myUsernameChanged.connect(function (username) { @@ -150,9 +150,9 @@ signals: void myUsernameChanged(const QString& username); /**jsdoc - * Triggered when the progress of the download of assets for the domain changes. + * Triggered when the download progress of the assets in the domain changes. * @function AccountServices.downloadInfoChanged - * @param {AccountServices.DownloadInfoResult} downloadInfo - Information on the progress of assets download. + * @param {AccountServices.DownloadInfoResult} downloadInfo - Information on the download progress of assets. * @returns {Signal} */ void downloadInfoChanged(DownloadInfoResult info); @@ -186,7 +186,7 @@ signals: /**jsdoc * Triggered when the login status of the user changes. * @function AccountServices.loggedInChanged - * @param {boolean} loggedIn - true if the user is logged in, otherwise false. + * @param {boolean} loggedIn - true if the user is logged in, false if not. * @returns {Signal} * @example Report when your login status changes. * AccountServices.loggedInChanged.connect(function(loggedIn) { diff --git a/interface/src/scripting/WalletScriptingInterface.h b/interface/src/scripting/WalletScriptingInterface.h index 7482b8be00..3ef9c7953a 100644 --- a/interface/src/scripting/WalletScriptingInterface.h +++ b/interface/src/scripting/WalletScriptingInterface.h @@ -41,8 +41,8 @@ public: * * @property {WalletScriptingInterface.WalletStatus} walletStatus - The status of the user's wallet. Read-only. * @property {boolean} limitedCommerce - true if Interface is running in limited commerce mode. In limited commerce - * mode, certain Interface functionality is disabled, e.g., users can't buy non-free items from the Marketplace. The Oculus - * Store version of Interface runs in limited commerce mode. Read-only. + * mode, certain Interface functionalities are disabled, e.g., users can't buy items that are not free from the Marketplace. + * The Oculus Store version of Interface runs in limited commerce mode. Read-only. */ class WalletScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -55,16 +55,16 @@ public: WalletScriptingInterface(); /**jsdoc - * Check and update the user's wallet status. + * Checks and updates the user's wallet status. * @function WalletScriptingInterface.refreshWalletStatus */ Q_INVOKABLE void refreshWalletStatus(); /**jsdoc - * Get the current status of the user's wallet. + * Gets the current status of the user's wallet. * @function WalletScriptingInterface.getWalletStatus * @returns {WalletScriptingInterface.WalletStatus} - * @example Two ways to report your wallet status. + * @example Use two methods to report your wallet's status. * print("Wallet status: " + WalletScriptingInterface.walletStatus); // Same value as next line. * print("Wallet status: " + WalletScriptingInterface.getWalletStatus()); */ @@ -74,11 +74,11 @@ public: * Check that a certified avatar entity is owned by the avatar whose entity it is. The result of the check is provided via * the {@link WalletScriptingInterface.ownershipVerificationSuccess|ownershipVerificationSuccess} and * {@link WalletScriptingInterface.ownershipVerificationFailed|ownershipVerificationFailed} signals.
- * Warning: Neither of these signals fire if the entity is not an avatar entity or it's not a certified - * entity. + * Warning: Neither of these signals are triggered if the entity is not an avatar entity or is not + * certified. * @function WalletScriptingInterface.proveAvatarEntityOwnershipVerification - * @param {Uuid} entityID - The ID of the avatar entity to check. - * @example Check ownership of all nearby certified avatar entities. + * @param {Uuid} entityID - The avatar entity's ID. + * @example Check the ownership of all nearby certified avatar entities. * // Set up response handling. * function ownershipSuccess(entityID) { * print("Ownership test succeeded for: " + entityID); @@ -118,7 +118,7 @@ public: signals: /**jsdoc - * Triggered when the status of the user's wallet changes. + * Triggered when the user's wallet status changes. * @function WalletScriptingInterface.walletStatusChanged * @returns {Signal} * @example Report when your wallet status changes, e.g., when you log in and out. @@ -136,7 +136,7 @@ signals: void limitedCommerceChanged(); /**jsdoc - * Triggered when the user rezzes a certified entity but the user's wallet is not ready and so the certified location of the + * Triggered when the user rezzes a certified entity but the user's wallet is not ready. So the certified location of the * entity cannot be updated in the metaverse. * @function WalletScriptingInterface.walletNotSetup * @returns {Signal} From 2bcee4e454f4a727800e3d6081a9367079b319ae Mon Sep 17 00:00:00 2001 From: nimisha20 Date: Mon, 25 Feb 2019 08:54:47 -0800 Subject: [PATCH 02/21] Update AccountServicesScriptingInterface.cpp Changes according to ctrlaltdavid's comments. --- interface/src/scripting/AccountServicesScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AccountServicesScriptingInterface.cpp b/interface/src/scripting/AccountServicesScriptingInterface.cpp index 5ede7c7a98..5f8fb065ff 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.cpp +++ b/interface/src/scripting/AccountServicesScriptingInterface.cpp @@ -115,7 +115,7 @@ DownloadInfoResult::DownloadInfoResult() : /**jsdoc * Information on the assets currently being downloaded and pending download. * @typedef {object} AccountServices.DownloadInfoResult - * @property {number[]} downloading - The download percentage of each asset currently downloading. + * @property {number[]} downloading - The download percentage remaining of each asset currently downloading. * @property {number} pending - The number of assets pending download. */ QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result) { From e20f13f0ae8a17aa01ed0911a86228e94a905dea Mon Sep 17 00:00:00 2001 From: nimisha20 Date: Mon, 25 Feb 2019 09:28:56 -0800 Subject: [PATCH 03/21] Update AccountServicesScriptingInterface.h Adding ctrlaltdavid's changes --- interface/src/scripting/AccountServicesScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index b5c4a6e0df..415b405e53 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -98,7 +98,7 @@ public slots: bool isLoggedIn(); /**jsdoc - * Prompts the user to log in (the login dialog is displayed) if they're not already logged in. + * Prompts the user to log in (with a login dialog) if they're not already logged in. The function returns if the user is logged in or not before the user completes the login dialog. * @function AccountServices.checkAndSignalForAccessToken * @returns {boolean} true if the user is logged in, false if not. */ From 4825ecdbf35c78b624c739128a790f147530e52c Mon Sep 17 00:00:00 2001 From: nimisha20 Date: Mon, 25 Feb 2019 22:44:16 -0800 Subject: [PATCH 04/21] Update AccountServicesScriptingInterface.h --- interface/src/scripting/AccountServicesScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index 415b405e53..1555caba3c 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -98,7 +98,7 @@ public slots: bool isLoggedIn(); /**jsdoc - * Prompts the user to log in (with a login dialog) if they're not already logged in. The function returns if the user is logged in or not before the user completes the login dialog. + * Prompts the user to log in (with a login dialog) if they're not already logged in. The function returns a value before the user completes the login dialog. * @function AccountServices.checkAndSignalForAccessToken * @returns {boolean} true if the user is logged in, false if not. */ From 736a050e6808ff0913e819558937d3b06d8d9e3c Mon Sep 17 00:00:00 2001 From: nimisha20 Date: Mon, 25 Feb 2019 22:55:56 -0800 Subject: [PATCH 05/21] Update AccountServicesScriptingInterface.h --- interface/src/scripting/AccountServicesScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index 1555caba3c..b5bee6a7e4 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -98,7 +98,7 @@ public slots: bool isLoggedIn(); /**jsdoc - * Prompts the user to log in (with a login dialog) if they're not already logged in. The function returns a value before the user completes the login dialog. + * The function returns the log in status of the user and prompts the user to log in (with a login dialog) if they're not already logged in. * @function AccountServices.checkAndSignalForAccessToken * @returns {boolean} true if the user is logged in, false if not. */ From ba3895efdd942ed40d24ad5134b23d5bc05c4756 Mon Sep 17 00:00:00 2001 From: nimisha20 Date: Mon, 25 Feb 2019 22:56:36 -0800 Subject: [PATCH 06/21] Update AccountServicesScriptingInterface.h Minor copy-edit --- interface/src/scripting/AccountServicesScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index b5bee6a7e4..b188b4e63b 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -98,7 +98,7 @@ public slots: bool isLoggedIn(); /**jsdoc - * The function returns the log in status of the user and prompts the user to log in (with a login dialog) if they're not already logged in. + * The function returns the login status of the user and prompts the user to log in (with a login dialog) if they're not already logged in. * @function AccountServices.checkAndSignalForAccessToken * @returns {boolean} true if the user is logged in, false if not. */ From db1c78246fc640971ea55f273a1132ac4966e2ce Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 26 Feb 2019 11:32:43 -0700 Subject: [PATCH 07/21] Read and apply the FBX upVector parameter --- libraries/fbx/src/FBXSerializer.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 9e7f422b40..3c8aa8f799 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -167,7 +167,6 @@ glm::mat4 getGlobalTransform(const QMultiMap& _connectionParen } } } - return globalTransform; } @@ -436,6 +435,8 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr hfmModel.originalURL = url; float unitScaleFactor = 1.0f; + glm::quat upAxisZRotation; + bool applyUpAxisZRotation = false; glm::vec3 ambientColor; QString hifiGlobalNodeID; unsigned int meshIndex = 0; @@ -473,11 +474,20 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr if (subobject.name == propertyName) { static const QVariant UNIT_SCALE_FACTOR = QByteArray("UnitScaleFactor"); static const QVariant AMBIENT_COLOR = QByteArray("AmbientColor"); + static const QVariant UP_AXIS = QByteArray("UpAxis"); const auto& subpropName = subobject.properties.at(0); if (subpropName == UNIT_SCALE_FACTOR) { unitScaleFactor = subobject.properties.at(index).toFloat(); } else if (subpropName == AMBIENT_COLOR) { ambientColor = getVec3(subobject.properties, index); + } else if (subpropName == UP_AXIS) { + constexpr int UP_AXIS_Y = 1; + constexpr int UP_AXIS_Z = 2; + int upAxis = subobject.properties.at(index).toInt(); + if (upAxis == UP_AXIS_Z) { + upAxisZRotation = glm::angleAxis(glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); + applyUpAxisZRotation = true; + } } } } @@ -1271,7 +1281,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr hfmModel.hasSkeletonJoints = (hfmModel.hasSkeletonJoints || joint.isSkeletonJoint); glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation; - if (joint.parentIndex == -1) { joint.transform = hfmModel.offset * glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform; @@ -1664,6 +1673,9 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr } } + if (applyUpAxisZRotation) { + hfmModelPtr->bindExtents.rotate(upAxisZRotation); + } return hfmModelPtr; } From f47ec099273548a1300be6699571727bc29aaf32 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 26 Feb 2019 14:01:30 -0700 Subject: [PATCH 08/21] use UP_AXIS_Y --- libraries/fbx/src/FBXSerializer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 3c8aa8f799..0b31eda94b 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -484,7 +484,9 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr constexpr int UP_AXIS_Y = 1; constexpr int UP_AXIS_Z = 2; int upAxis = subobject.properties.at(index).toInt(); - if (upAxis == UP_AXIS_Z) { + if (upAxis == UP_AXIS_Y) { + // No update necessary, y up is the default + } else if (upAxis == UP_AXIS_Z) { upAxisZRotation = glm::angleAxis(glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); applyUpAxisZRotation = true; } From ff7995ae18a9e6262fbb58167912ce9240f9b586 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 26 Feb 2019 18:29:55 -0700 Subject: [PATCH 09/21] Right fix --- libraries/fbx/src/FBXSerializer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 0b31eda94b..e022ca8921 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1281,7 +1281,9 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr joint.geometricScaling = fbxModel.geometricScaling; joint.isSkeletonJoint = fbxModel.isLimbNode; hfmModel.hasSkeletonJoints = (hfmModel.hasSkeletonJoints || joint.isSkeletonJoint); - + if (applyUpAxisZRotation && joint.parentIndex == -1 && !joint.isSkeletonJoint) { + joint.rotation *= upAxisZRotation; + } glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation; if (joint.parentIndex == -1) { joint.transform = hfmModel.offset * glm::translate(joint.translation) * joint.preTransform * @@ -1676,6 +1678,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr } if (applyUpAxisZRotation) { + hfmModelPtr->meshExtents.rotate(upAxisZRotation); hfmModelPtr->bindExtents.rotate(upAxisZRotation); } return hfmModelPtr; From 3e6061e4350684f88e2313cbed423a40a324821b Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 1 Mar 2019 13:45:00 -0800 Subject: [PATCH 10/21] try to not clear my avatar entities on domain switch --- interface/src/Application.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 24 +++++++++---------- .../src/EntityTreeRenderer.h | 6 ++--- libraries/entities/src/EntityTree.cpp | 16 +++++++------ libraries/entities/src/EntityTree.h | 3 ++- libraries/entities/src/EntityTreeElement.cpp | 4 ++-- libraries/entities/src/EntityTreeElement.h | 2 +- libraries/octree/src/Octree.h | 2 +- libraries/octree/src/OctreeProcessor.cpp | 4 ++-- libraries/octree/src/OctreeProcessor.h | 2 +- 10 files changed, 34 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 29d260cb5f..1a64378c36 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6948,7 +6948,7 @@ void Application::clearDomainOctreeDetails(bool clearAll) { }); // reset the model renderer - clearAll ? getEntities()->clear() : getEntities()->clearNonLocalEntities(); + clearAll ? getEntities()->clear() : getEntities()->clearDomainAndNonOwnedEntities(); auto skyStage = DependencyManager::get()->getSkyStage(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index e54258fc3e..1e2c17fa8e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -196,8 +196,8 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() { }); } -void EntityTreeRenderer::stopNonLocalEntityScripts() { - leaveNonLocalEntities(); +void EntityTreeRenderer::stopDomainAndNonOwnedEntities() { + leaveDomainAndNonOwnedEntities(); // unload and stop the engine if (_entitiesScriptEngine) { QList entitiesWithEntityScripts = _entitiesScriptEngine->getListOfEntityScriptIDs(); @@ -206,7 +206,7 @@ void EntityTreeRenderer::stopNonLocalEntityScripts() { EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); if (entityItem) { - if (!entityItem->isLocalEntity()) { + if (!(entityItem->isLocalEntity() || (entityItem->isAvatarEntity() && entityItem->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) { _entitiesScriptEngine->unloadEntityScript(entityID, true); } } @@ -214,8 +214,8 @@ void EntityTreeRenderer::stopNonLocalEntityScripts() { } } -void EntityTreeRenderer::clearNonLocalEntities() { - stopNonLocalEntityScripts(); +void EntityTreeRenderer::clearDomainAndNonOwnedEntities() { + stopDomainAndNonOwnedEntities(); std::unordered_map savedEntities; // remove all entities from the scene @@ -225,7 +225,7 @@ void EntityTreeRenderer::clearNonLocalEntities() { for (const auto& entry : _entitiesInScene) { const auto& renderer = entry.second; const EntityItemPointer& entityItem = renderer->getEntity(); - if (!entityItem->isLocalEntity()) { + if (!(entityItem->isLocalEntity() || (entityItem->isAvatarEntity() && entityItem->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) { renderer->removeFromScene(scene, transaction); } else { savedEntities[entry.first] = entry.second; @@ -239,7 +239,7 @@ void EntityTreeRenderer::clearNonLocalEntities() { _layeredZones.clearNonLocalLayeredZones(); - OctreeProcessor::clearNonLocalEntities(); + OctreeProcessor::clearDomainAndNonOwnedEntities(); } void EntityTreeRenderer::clear() { @@ -655,22 +655,22 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() { return didUpdate; } -void EntityTreeRenderer::leaveNonLocalEntities() { +void EntityTreeRenderer::leaveDomainAndNonOwnedEntities() { if (_tree && !_shuttingDown) { - QVector currentLocalEntitiesInside; + QVector currentEntitiesInsideToSave; foreach (const EntityItemID& entityID, _currentEntitiesInside) { EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); - if (!entityItem->isLocalEntity()) { + if (!(entityItem->isLocalEntity() || (entityItem->isAvatarEntity() && entityItem->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) { emit leaveEntity(entityID); if (_entitiesScriptEngine) { _entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); } } else { - currentLocalEntitiesInside.push_back(entityID); + currentEntitiesInsideToSave.push_back(entityID); } } - _currentEntitiesInside = currentLocalEntitiesInside; + _currentEntitiesInside = currentEntitiesInsideToSave; forceRecheckEntities(); } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 51568ab744..b4d3507c17 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -87,7 +87,7 @@ public: virtual void init() override; /// clears the tree - virtual void clearNonLocalEntities() override; + virtual void clearDomainAndNonOwnedEntities() override; virtual void clear() override; /// reloads the entity scripts, calling unload and preload @@ -170,7 +170,7 @@ private: bool findBestZoneAndMaybeContainingEntities(QVector* entitiesContainingAvatar = nullptr); bool applyLayeredZones(); - void stopNonLocalEntityScripts(); + void stopDomainAndNonOwnedEntities(); void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false); @@ -179,7 +179,7 @@ private: QScriptValueList createEntityArgs(const EntityItemID& entityID); bool checkEnterLeaveEntities(); - void leaveNonLocalEntities(); + void leaveDomainAndNonOwnedEntities(); void leaveAllEntities(); void forceRecheckEntities(); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 6e404ce690..cdf021638b 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -78,13 +78,14 @@ OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) { return std::static_pointer_cast(newElement); } -void EntityTree::eraseNonLocalEntities() { +void EntityTree::eraseDomainAndNonOwnedEntities() { emit clearingEntities(); if (_simulation) { // local entities are not in the simulation, so we clear ALL _simulation->clearEntities(); } + this->withWriteLock([&] { QHash savedEntities; // NOTE: lock the Tree first, then lock the _entityMap. @@ -93,10 +94,10 @@ void EntityTree::eraseNonLocalEntities() { foreach(EntityItemPointer entity, _entityMap) { EntityTreeElementPointer element = entity->getElement(); if (element) { - element->cleanupNonLocalEntities(); + element->cleanupDomainAndNonOwnedEntities(); } - if (entity->isLocalEntity()) { + if (entity->isLocalEntity() || (entity->isAvatarEntity() && entity->getOwningAvatarID() == getMyAvatarSessionUUID())) { savedEntities[entity->getEntityItemID()] = entity; } else { int32_t spaceIndex = entity->getSpaceIndex(); @@ -114,15 +115,16 @@ void EntityTree::eraseNonLocalEntities() { { QWriteLocker locker(&_needsParentFixupLock); - QVector localEntitiesNeedsParentFixup; + QVector needParentFixup; foreach (EntityItemWeakPointer entityItem, _needsParentFixup) { - if (!entityItem.expired() && entityItem.lock()->isLocalEntity()) { - localEntitiesNeedsParentFixup.push_back(entityItem); + auto entity = entityItem.lock(); + if (entity && (entity->isLocalEntity() || (entity->isAvatarEntity() && entity->getOwningAvatarID() == getMyAvatarSessionUUID()))) { + needParentFixup.push_back(entityItem); } } - _needsParentFixup = localEntitiesNeedsParentFixup; + _needsParentFixup = needParentFixup; } } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index dcce0e4b99..9da0ecedd8 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -75,7 +75,7 @@ public: } - virtual void eraseNonLocalEntities() override; + virtual void eraseDomainAndNonOwnedEntities() override; virtual void eraseAllOctreeElements(bool createNewRoot = true) override; virtual void readBitstreamToTree(const unsigned char* bitstream, @@ -255,6 +255,7 @@ public: QByteArray computeNonce(const QString& certID, const QString ownerKey); bool verifyNonce(const QString& certID, const QString& nonce, EntityItemID& id); + QUuid getMyAvatarSessionUUID() { return _myAvatar ? _myAvatar->getSessionUUID() : QUuid(); } void setMyAvatar(std::shared_ptr myAvatar) { _myAvatar = myAvatar; } void swapStaleProxies(std::vector& proxies) { proxies.swap(_staleProxies); } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index ce6f20262f..aab98adb52 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -697,11 +697,11 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI return foundEntity; } -void EntityTreeElement::cleanupNonLocalEntities() { +void EntityTreeElement::cleanupDomainAndNonOwnedEntities() { withWriteLock([&] { EntityItems savedEntities; foreach(EntityItemPointer entity, _entityItems) { - if (!entity->isLocalEntity()) { + if (!(entity->isLocalEntity() || (entity->isAvatarEntity() && entity->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) { entity->preDelete(); entity->_element = NULL; } else { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index f82eaa7fb1..f94da44138 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -190,7 +190,7 @@ public: EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const; void getEntitiesInside(const AACube& box, QVector& foundEntities); - void cleanupNonLocalEntities(); + void cleanupDomainAndNonOwnedEntities(); void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities bool removeEntityItem(EntityItemPointer entity, bool deletion = false); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index aac29201f1..82076f618b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -149,7 +149,7 @@ public: OctreeElementPointer getRoot() { return _rootElement; } - virtual void eraseNonLocalEntities() { _isDirty = true; }; + virtual void eraseDomainAndNonOwnedEntities() { _isDirty = true; }; virtual void eraseAllOctreeElements(bool createNewRoot = true); virtual void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args); diff --git a/libraries/octree/src/OctreeProcessor.cpp b/libraries/octree/src/OctreeProcessor.cpp index 18c8630391..03c8b9ca2f 100644 --- a/libraries/octree/src/OctreeProcessor.cpp +++ b/libraries/octree/src/OctreeProcessor.cpp @@ -198,10 +198,10 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe } -void OctreeProcessor::clearNonLocalEntities() { +void OctreeProcessor::clearDomainAndNonOwnedEntities() { if (_tree) { _tree->withWriteLock([&] { - _tree->eraseNonLocalEntities(); + _tree->eraseDomainAndNonOwnedEntities(); }); } } diff --git a/libraries/octree/src/OctreeProcessor.h b/libraries/octree/src/OctreeProcessor.h index bc5618e657..40af7a39f8 100644 --- a/libraries/octree/src/OctreeProcessor.h +++ b/libraries/octree/src/OctreeProcessor.h @@ -43,7 +43,7 @@ public: virtual void init(); /// clears the tree - virtual void clearNonLocalEntities(); + virtual void clearDomainAndNonOwnedEntities(); virtual void clear(); float getAverageElementsPerPacket() const { return _elementsPerPacket.getAverage(); } From 708632ee82ce326c25dc7ee73e9b83fa63998673 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 4 Mar 2019 10:00:26 -0800 Subject: [PATCH 11/21] possible fix for model crash --- libraries/render-utils/src/Model.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9bb3f72b31..683c517a15 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1346,14 +1346,18 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { } void Model::computeMeshPartLocalBounds() { - for (auto& part : _modelMeshRenderItems) { - const Model::MeshState& state = _meshStates.at(part->_meshIndex); - if (_useDualQuaternionSkinning) { - part->computeAdjustedLocalBound(state.clusterDualQuaternions); - } else { - part->computeAdjustedLocalBound(state.clusterMatrices); - } + render::Transaction transaction; + for (auto renderItem : _modelMeshRenderItemIDs) { + transaction.updateItem(renderItem, [&](ModelMeshPartPayload& data) { + const Model::MeshState& state = _meshStates.at(data._meshIndex); + if (_useDualQuaternionSkinning) { + data.computeAdjustedLocalBound(state.clusterDualQuaternions); + } else { + data.computeAdjustedLocalBound(state.clusterMatrices); + } + }); } + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); } // virtual From b2d08e9d42f152c4beff350b37842f4af93bcf0c Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 4 Mar 2019 15:33:21 -0700 Subject: [PATCH 12/21] apply axis rotation to translation and meshes --- libraries/fbx/src/FBXSerializer.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index e022ca8921..5246242a1e 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1281,8 +1281,9 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr joint.geometricScaling = fbxModel.geometricScaling; joint.isSkeletonJoint = fbxModel.isLimbNode; hfmModel.hasSkeletonJoints = (hfmModel.hasSkeletonJoints || joint.isSkeletonJoint); - if (applyUpAxisZRotation && joint.parentIndex == -1 && !joint.isSkeletonJoint) { + if (applyUpAxisZRotation && joint.parentIndex == -1) { joint.rotation *= upAxisZRotation; + joint.translation = upAxisZRotation * joint.translation; } glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation; if (joint.parentIndex == -1) { @@ -1678,8 +1679,12 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr } if (applyUpAxisZRotation) { - hfmModelPtr->meshExtents.rotate(upAxisZRotation); - hfmModelPtr->bindExtents.rotate(upAxisZRotation); + hfmModelPtr->meshExtents.transform(glm::mat4_cast(upAxisZRotation)); + hfmModelPtr->bindExtents.transform(glm::mat4_cast(upAxisZRotation)); + for (auto &mesh : hfmModelPtr->meshes) { + mesh.modelTransform *= glm::mat4_cast(upAxisZRotation); + mesh.meshExtents.transform(glm::mat4_cast(upAxisZRotation)); + } } return hfmModelPtr; } From 12f5a735d93e61e74c1824d1f5b0f9c88e3a2342 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 4 Mar 2019 14:50:09 -0800 Subject: [PATCH 13/21] simplifying mouse events and fix mouse on create --- interface/src/Application.cpp | 11 +- interface/src/ui/overlays/Overlays.cpp | 239 ++++++------------ interface/src/ui/overlays/Overlays.h | 17 +- .../src/EntityTreeRenderer.cpp | 34 +-- .../src/EntityTreeRenderer.h | 2 +- scripts/system/edit.js | 6 +- 6 files changed, 103 insertions(+), 206 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2c8d71af00..e41d51de47 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4392,7 +4392,6 @@ void Application::mouseMoveEvent(QMouseEvent* event) { if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() || getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_ENTITY_ID) { getEntities()->mouseMoveEvent(&mappedEvent); - getOverlays().mouseMoveEvent(&mappedEvent); } _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts @@ -4426,14 +4425,10 @@ void Application::mousePressEvent(QMouseEvent* event) { #endif QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers()); - std::pair entityResult; if (!_controllerScriptingInterface->areEntityClicksCaptured()) { - entityResult = getEntities()->mousePressEvent(&mappedEvent); + QUuid result = getEntities()->mousePressEvent(&mappedEvent); + setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(result) ? result : UNKNOWN_ENTITY_ID); } - std::pair overlayResult = getOverlays().mousePressEvent(&mappedEvent); - - QUuid focusedEntity = entityResult.first < overlayResult.first ? entityResult.second : overlayResult.second; - setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(focusedEntity) ? focusedEntity : UNKNOWN_ENTITY_ID); _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts @@ -4476,7 +4471,6 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { if (!_controllerScriptingInterface->areEntityClicksCaptured()) { getEntities()->mouseDoublePressEvent(&mappedEvent); } - getOverlays().mouseDoublePressEvent(&mappedEvent); // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { @@ -4501,7 +4495,6 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { event->buttons(), event->modifiers()); getEntities()->mouseReleaseEvent(&mappedEvent); - getOverlays().mouseReleaseEvent(&mappedEvent); _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 5ae3f7d38e..dfd698f6c5 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -43,14 +43,6 @@ std::unordered_map Overlays::_entityToOverlayTypes; std::unordered_map Overlays::_overlayToEntityTypes; Overlays::Overlays() { - auto pointerManager = DependencyManager::get(); - connect(pointerManager.data(), &PointerManager::hoverBeginOverlay, this, &Overlays::hoverEnterPointerEvent); - connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, this, &Overlays::hoverOverPointerEvent); - connect(pointerManager.data(), &PointerManager::hoverEndOverlay, this, &Overlays::hoverLeavePointerEvent); - connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, this, &Overlays::mousePressPointerEvent); - connect(pointerManager.data(), &PointerManager::triggerContinueOverlay, this, &Overlays::mouseMovePointerEvent); - connect(pointerManager.data(), &PointerManager::triggerEndOverlay, this, &Overlays::mouseReleasePointerEvent); - ADD_TYPE_MAP(Box, cube); ADD_TYPE_MAP(Sphere, sphere); _overlayToEntityTypes["rectangle3d"] = "Shape"; @@ -81,13 +73,23 @@ void Overlays::cleanupAllOverlays() { void Overlays::init() { auto entityScriptingInterface = DependencyManager::get().data(); - auto pointerManager = DependencyManager::get(); - connect(pointerManager.data(), &PointerManager::hoverBeginOverlay, entityScriptingInterface , &EntityScriptingInterface::hoverEnterEntity); - connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity); - connect(pointerManager.data(), &PointerManager::hoverEndOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity); - connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity); - connect(pointerManager.data(), &PointerManager::triggerContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity); - connect(pointerManager.data(), &PointerManager::triggerEndOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity); + auto pointerManager = DependencyManager::get().data(); + connect(pointerManager, &PointerManager::hoverBeginOverlay, entityScriptingInterface , &EntityScriptingInterface::hoverEnterEntity); + connect(pointerManager, &PointerManager::hoverContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity); + connect(pointerManager, &PointerManager::hoverEndOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity); + connect(pointerManager, &PointerManager::triggerBeginOverlay, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity); + connect(pointerManager, &PointerManager::triggerContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity); + connect(pointerManager, &PointerManager::triggerEndOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity); + + connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &Overlays::mousePressOnPointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOffEntity, this, &Overlays::mousePressOffPointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::mouseDoublePressOnEntity, this, &Overlays::mouseDoublePressOnPointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::mouseDoublePressOffEntity, this, &Overlays::mouseDoublePressOffPointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, &Overlays::mouseReleasePointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity, this, &Overlays::mouseMovePointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity , this, &Overlays::hoverEnterPointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity, this, &Overlays::hoverOverPointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &Overlays::hoverLeavePointerEvent); } void Overlays::update(float deltatime) { @@ -1159,7 +1161,7 @@ bool Overlays::isAddedOverlay(const QUuid& id) { } void Overlays::sendMousePressOnOverlay(const QUuid& id, const PointerEvent& event) { - mousePressPointerEvent(id, event); + mousePressOnPointerEvent(id, event); } void Overlays::sendMouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event) { @@ -1206,57 +1208,66 @@ float Overlays::height() { return offscreenUi->getWindow()->size().height(); } -static uint32_t toPointerButtons(const QMouseEvent& event) { - uint32_t buttons = 0; - buttons |= event.buttons().testFlag(Qt::LeftButton) ? PointerEvent::PrimaryButton : 0; - buttons |= event.buttons().testFlag(Qt::RightButton) ? PointerEvent::SecondaryButton : 0; - buttons |= event.buttons().testFlag(Qt::MiddleButton) ? PointerEvent::TertiaryButton : 0; - return buttons; -} - -static PointerEvent::Button toPointerButton(const QMouseEvent& event) { - switch (event.button()) { - case Qt::LeftButton: - return PointerEvent::PrimaryButton; - case Qt::RightButton: - return PointerEvent::SecondaryButton; - case Qt::MiddleButton: - return PointerEvent::TertiaryButton; - default: - return PointerEvent::NoButtons; - } -} - -RayToOverlayIntersectionResult getPrevPickResult() { - RayToOverlayIntersectionResult overlayResult; - overlayResult.intersects = false; - auto pickResult = DependencyManager::get()->getPrevPickResultTyped(DependencyManager::get()->getMouseRayPickID()); - if (pickResult) { - overlayResult.intersects = pickResult->type == IntersectionType::LOCAL_ENTITY; - if (overlayResult.intersects) { - overlayResult.intersection = pickResult->intersection; - overlayResult.distance = pickResult->distance; - overlayResult.surfaceNormal = pickResult->surfaceNormal; - overlayResult.overlayID = pickResult->objectID; - overlayResult.extraInfo = pickResult->extraInfo; +void Overlays::mousePressOnPointerEvent(const QUuid& id, const PointerEvent& event) { + auto keyboard = DependencyManager::get(); + // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed + if (!keyboard->getKeyIDs().contains(id)) { + auto entity = DependencyManager::get()->getEntity(id); + if (entity && entity->isLocalEntity()) { + emit mousePressOnOverlay(id, event); } } - return overlayResult; } -PointerEvent Overlays::calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, - const RayToOverlayIntersectionResult& rayPickResult, QMouseEvent* event, - PointerEvent::EventType eventType) { - glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(id, rayPickResult.intersection); - return PointerEvent(eventType, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, - ray.direction, toPointerButton(*event), toPointerButtons(*event), event->modifiers()); +void Overlays::mousePressOffPointerEvent() { + emit mousePressOffOverlay(); +} + +void Overlays::mouseDoublePressOnPointerEvent(const QUuid& id, const PointerEvent& event) { + auto keyboard = DependencyManager::get(); + // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed + if (!keyboard->getKeyIDs().contains(id)) { + auto entity = DependencyManager::get()->getEntity(id); + if (entity && entity->isLocalEntity()) { + emit mouseDoublePressOnOverlay(id, event); + } + } +} + +void Overlays::mouseDoublePressOffPointerEvent() { + emit mouseDoublePressOffOverlay(); +} + +void Overlays::mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event) { + auto keyboard = DependencyManager::get(); + // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed + if (!keyboard->getKeyIDs().contains(id)) { + auto entity = DependencyManager::get()->getEntity(id); + if (entity && entity->isLocalEntity()) { + emit mouseReleaseOnOverlay(id, event); + } + } +} + +void Overlays::mouseMovePointerEvent(const QUuid& id, const PointerEvent& event) { + auto keyboard = DependencyManager::get(); + // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed + if (!keyboard->getKeyIDs().contains(id)) { + auto entity = DependencyManager::get()->getEntity(id); + if (entity && entity->isLocalEntity()) { + emit mouseMoveOnOverlay(id, event); + } + } } void Overlays::hoverEnterPointerEvent(const QUuid& id, const PointerEvent& event) { auto keyboard = DependencyManager::get(); // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed if (!keyboard->getKeyIDs().contains(id)) { - emit hoverEnterOverlay(id, event); + auto entity = DependencyManager::get()->getEntity(id); + if (entity && entity->isLocalEntity()) { + emit hoverEnterOverlay(id, event); + } } } @@ -1264,7 +1275,10 @@ void Overlays::hoverOverPointerEvent(const QUuid& id, const PointerEvent& event) auto keyboard = DependencyManager::get(); // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed if (!keyboard->getKeyIDs().contains(id)) { - emit hoverOverOverlay(id, event); + auto entity = DependencyManager::get()->getEntity(id); + if (entity && entity->isLocalEntity()) { + emit hoverOverOverlay(id, event); + } } } @@ -1272,113 +1286,10 @@ void Overlays::hoverLeavePointerEvent(const QUuid& id, const PointerEvent& event auto keyboard = DependencyManager::get(); // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed if (!keyboard->getKeyIDs().contains(id)) { - emit hoverLeaveOverlay(id, event); - } -} - -std::pair Overlays::mousePressEvent(QMouseEvent* event) { - PerformanceTimer perfTimer("Overlays::mousePressEvent"); - - PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); - if (rayPickResult.intersects) { - _currentClickingOnOverlayID = rayPickResult.overlayID; - - PointerEvent pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press); - mousePressPointerEvent(_currentClickingOnOverlayID, pointerEvent); - return { rayPickResult.distance, rayPickResult.overlayID }; - } - emit mousePressOffOverlay(); - return { FLT_MAX, UNKNOWN_ENTITY_ID }; -} - -void Overlays::mousePressPointerEvent(const QUuid& id, const PointerEvent& event) { - auto keyboard = DependencyManager::get(); - // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed - if (!keyboard->getKeyIDs().contains(id)) { - emit mousePressOnOverlay(id, event); - } -} - -bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { - PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent"); - - PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); - if (rayPickResult.intersects) { - _currentClickingOnOverlayID = rayPickResult.overlayID; - - auto pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press); - emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent); - return true; - } - emit mouseDoublePressOffOverlay(); - return false; -} - -bool Overlays::mouseReleaseEvent(QMouseEvent* event) { - PerformanceTimer perfTimer("Overlays::mouseReleaseEvent"); - - PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); - if (rayPickResult.intersects) { - auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release); - mouseReleasePointerEvent(rayPickResult.overlayID, pointerEvent); - } - - _currentClickingOnOverlayID = UNKNOWN_ENTITY_ID; - return false; -} - -void Overlays::mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event) { - auto keyboard = DependencyManager::get(); - // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed - if (!keyboard->getKeyIDs().contains(id)) { - emit mouseReleaseOnOverlay(id, event); - } -} - -bool Overlays::mouseMoveEvent(QMouseEvent* event) { - PerformanceTimer perfTimer("Overlays::mouseMoveEvent"); - - PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); - if (rayPickResult.intersects) { - auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move); - mouseMovePointerEvent(rayPickResult.overlayID, pointerEvent); - - // If previously hovering over a different overlay then leave hover on that overlay. - if (_currentHoverOverOverlayID != UNKNOWN_ENTITY_ID && rayPickResult.overlayID != _currentHoverOverOverlayID) { - auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move); - hoverLeavePointerEvent(_currentHoverOverOverlayID, pointerEvent); + auto entity = DependencyManager::get()->getEntity(id); + if (entity && entity->isLocalEntity()) { + emit hoverLeaveOverlay(id, event); } - - // If hovering over a new overlay then enter hover on that overlay. - if (rayPickResult.overlayID != _currentHoverOverOverlayID) { - hoverEnterPointerEvent(rayPickResult.overlayID, pointerEvent); - } - - // Hover over current overlay. - hoverOverPointerEvent(rayPickResult.overlayID, pointerEvent); - - _currentHoverOverOverlayID = rayPickResult.overlayID; - } else { - // If previously hovering an overlay then leave hover. - if (_currentHoverOverOverlayID != UNKNOWN_ENTITY_ID) { - auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move); - hoverLeavePointerEvent(_currentHoverOverOverlayID, pointerEvent); - - _currentHoverOverOverlayID = UNKNOWN_ENTITY_ID; - } - } - return false; -} - -void Overlays::mouseMovePointerEvent(const QUuid& id, const PointerEvent& event) { - auto keyboard = DependencyManager::get(); - // Do not send keyboard key event to scripts to prevent malignant scripts from gathering what you typed - if (!keyboard->getKeyIDs().contains(id)) { - emit mouseMoveOnOverlay(id, event); } } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 93efc2bc0b..0b2994b872 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -112,11 +112,6 @@ public: const QVector& discard, bool visibleOnly = false, bool collidableOnly = false); - std::pair mousePressEvent(QMouseEvent* event); - bool mouseDoublePressEvent(QMouseEvent* event); - bool mouseReleaseEvent(QMouseEvent* event); - bool mouseMoveEvent(QMouseEvent* event); - void cleanupAllOverlays(); mutable QScriptEngine _scriptEngine; @@ -719,9 +714,6 @@ private: PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult, QMouseEvent* event, PointerEvent::EventType eventType); - QUuid _currentClickingOnOverlayID; - QUuid _currentHoverOverOverlayID; - static QString entityToOverlayType(const QString& type); static QString overlayToEntityType(const QString& type); static std::unordered_map _entityToOverlayTypes; @@ -732,12 +724,17 @@ private: EntityItemProperties convertOverlayToEntityProperties(QVariantMap& overlayProps, std::pair& rotationToSave, const QString& type, bool add, const QUuid& id = QUuid()); private slots: - void mousePressPointerEvent(const QUuid& id, const PointerEvent& event); - void mouseMovePointerEvent(const QUuid& id, const PointerEvent& event); + void mousePressOnPointerEvent(const QUuid& id, const PointerEvent& event); + void mousePressOffPointerEvent(); + void mouseDoublePressOnPointerEvent(const QUuid& id, const PointerEvent& event); + void mouseDoublePressOffPointerEvent(); void mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event); + void mouseMovePointerEvent(const QUuid& id, const PointerEvent& event); void hoverEnterPointerEvent(const QUuid& id, const PointerEvent& event); void hoverOverPointerEvent(const QUuid& id, const PointerEvent& event); void hoverLeavePointerEvent(const QUuid& id, const PointerEvent& event); + + }; #define ADD_TYPE_MAP(entity, overlay) \ diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index e54258fc3e..c7457c6443 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -73,14 +73,14 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf _currentHoverOverEntityID = UNKNOWN_ENTITY_ID; _currentClickingOnEntityID = UNKNOWN_ENTITY_ID; - auto entityScriptingInterface = DependencyManager::get(); + auto entityScriptingInterface = DependencyManager::get().data(); auto pointerManager = DependencyManager::get(); - connect(pointerManager.data(), &PointerManager::hoverBeginEntity, entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity); - connect(pointerManager.data(), &PointerManager::hoverContinueEntity, entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity); - connect(pointerManager.data(), &PointerManager::hoverEndEntity, entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity); - connect(pointerManager.data(), &PointerManager::triggerBeginEntity, entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity); - connect(pointerManager.data(), &PointerManager::triggerContinueEntity, entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity); - connect(pointerManager.data(), &PointerManager::triggerEndEntity, entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity); + connect(pointerManager.data(), &PointerManager::hoverBeginEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity); + connect(pointerManager.data(), &PointerManager::hoverContinueEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity); + connect(pointerManager.data(), &PointerManager::hoverEndEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity); + connect(pointerManager.data(), &PointerManager::triggerBeginEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity); + connect(pointerManager.data(), &PointerManager::triggerContinueEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity); + connect(pointerManager.data(), &PointerManager::triggerEndEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity); // Forward mouse events to web entities auto handlePointerEvent = [&](const QUuid& entityID, const PointerEvent& event) { @@ -93,10 +93,10 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf QMetaObject::invokeMethod(thisEntity.get(), "handlePointerEvent", Q_ARG(const PointerEvent&, event)); } }; - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) { + connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) { @@ -106,8 +106,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf QMetaObject::invokeMethod(thisEntity.get(), "hoverEnterEntity", Q_ARG(const PointerEvent&, event)); } }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, this, handlePointerEvent); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) { + connect(entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity, this, handlePointerEvent); + connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) { @@ -792,11 +792,11 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) { } } -std::pair EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { +QUuid EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { // If we don't have a tree, or we're in the process of shutting down, then don't // process these events. if (!_tree || _shuttingDown) { - return { FLT_MAX, UNKNOWN_ENTITY_ID }; + return UNKNOWN_ENTITY_ID; } PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); @@ -827,10 +827,10 @@ std::pair EntityTreeRenderer::mousePressEvent(QMouseEvent* event) _lastPointerEvent = pointerEvent; _lastPointerEventValid = true; - return { rayPickResult.distance, rayPickResult.entityID }; + return rayPickResult.entityID; } emit entityScriptingInterface->mousePressOffEntity(); - return { FLT_MAX, UNKNOWN_ENTITY_ID }; + return UNKNOWN_ENTITY_ID; } void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 51568ab744..8cc34cda10 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -94,7 +94,7 @@ public: void reloadEntityScripts(); // event handles which may generate entity related events - std::pair mousePressEvent(QMouseEvent* event); + QUuid mousePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); void mouseDoublePressEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 9d807264aa..bce308d5fc 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -924,11 +924,7 @@ var toolBar = (function () { that.setActive = function (active) { ContextOverlay.enabled = !active; Settings.setValue(EDIT_SETTING, active); - if (active) { - Controller.captureEntityClickEvents(); - } else { - Controller.releaseEntityClickEvents(); - + if (!active) { closeExistingDialogWindow(); } if (active === isActive) { From fd88ec0d16caafe1bef84a4287b3b9e1b5cec846 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 4 Mar 2019 15:25:02 -0800 Subject: [PATCH 14/21] need to copy meshStates on main thread --- libraries/render-utils/src/Model.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 683c517a15..dd9b0280ca 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1347,9 +1347,10 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { void Model::computeMeshPartLocalBounds() { render::Transaction transaction; + auto meshStates = _meshStates; for (auto renderItem : _modelMeshRenderItemIDs) { - transaction.updateItem(renderItem, [&](ModelMeshPartPayload& data) { - const Model::MeshState& state = _meshStates.at(data._meshIndex); + transaction.updateItem(renderItem, [this, meshStates](ModelMeshPartPayload& data) { + const Model::MeshState& state = meshStates.at(data._meshIndex); if (_useDualQuaternionSkinning) { data.computeAdjustedLocalBound(state.clusterDualQuaternions); } else { From f2c248c0a26a56b8c7969a14e274422524322cf3 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 4 Mar 2019 17:08:09 -0800 Subject: [PATCH 15/21] disable href and entity script events when in edit mode --- interface/src/Application.cpp | 15 +++++++-------- .../entities-renderer/src/EntityTreeRenderer.cpp | 12 +++++++----- libraries/entities/src/EntityTree.cpp | 8 ++++++++ libraries/entities/src/EntityTree.h | 4 ++++ libraries/script-engine/src/ScriptEngine.cpp | 4 +++- scripts/system/edit.js | 6 +++++- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e41d51de47..c85ced5dee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1061,6 +1061,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(PluginManager::getInstance().data(), &PluginManager::inputDeviceRunningChanged, controllerScriptingInterface, &controller::ScriptingInterface::updateRunningInputDevices); + EntityTree::setEntityClicksCapturedOperator([this] { + return _controllerScriptingInterface->areEntityClicksCaptured(); + }); + _entityClipboard->createRootElement(); #ifdef Q_OS_WIN @@ -4425,10 +4429,8 @@ void Application::mousePressEvent(QMouseEvent* event) { #endif QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers()); - if (!_controllerScriptingInterface->areEntityClicksCaptured()) { - QUuid result = getEntities()->mousePressEvent(&mappedEvent); - setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(result) ? result : UNKNOWN_ENTITY_ID); - } + QUuid result = getEntities()->mousePressEvent(&mappedEvent); + setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(result) ? result : UNKNOWN_ENTITY_ID); _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts @@ -4467,10 +4469,7 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers()); - - if (!_controllerScriptingInterface->areEntityClicksCaptured()) { - getEntities()->mouseDoublePressEvent(&mappedEvent); - } + getEntities()->mouseDoublePressEvent(&mappedEvent); // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c7457c6443..576137390e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -805,11 +805,13 @@ QUuid EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); EntityItemPointer entity; if (rayPickResult.intersects && (entity = getTree()->findEntityByID(rayPickResult.entityID))) { - auto properties = entity->getProperties(); - QString urlString = properties.getHref(); - QUrl url = QUrl(urlString, QUrl::StrictMode); - if (url.isValid() && !url.isEmpty()){ - DependencyManager::get()->handleLookupString(urlString); + if (!EntityTree::areEntityClicksCaptured()) { + auto properties = entity->getProperties(); + QString urlString = properties.getHref(); + QUrl url = QUrl(urlString, QUrl::StrictMode); + if (url.isValid() && !url.isEmpty()) { + DependencyManager::get()->handleLookupString(urlString); + } } glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 6e404ce690..644fe0620e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2972,6 +2972,7 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { std::function EntityTree::_getEntityObjectOperator = nullptr; std::function EntityTree::_textSizeOperator = nullptr; +std::function EntityTree::_areEntityClicksCapturedOperator = nullptr; QObject* EntityTree::getEntityObject(const QUuid& id) { if (_getEntityObjectOperator) { @@ -2987,6 +2988,13 @@ QSizeF EntityTree::textSize(const QUuid& id, const QString& text) { return QSizeF(0.0f, 0.0f); } +bool EntityTree::areEntityClicksCaptured() { + if (_areEntityClicksCapturedOperator) { + return _areEntityClicksCapturedOperator(); + } + return false; +} + void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, MovingEntitiesOperator& moveOperator, bool force, bool tellServer) { // if the queryBox has changed, tell the entity-server diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index dcce0e4b99..01829df7f8 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -268,6 +268,9 @@ public: static void setTextSizeOperator(std::function textSizeOperator) { _textSizeOperator = textSizeOperator; } static QSizeF textSize(const QUuid& id, const QString& text); + static void setEntityClicksCapturedOperator(std::function areEntityClicksCapturedOperator) { _areEntityClicksCapturedOperator = areEntityClicksCapturedOperator; } + static bool areEntityClicksCaptured(); + std::map getNamedPaths() const { return _namedPaths; } void updateEntityQueryAACube(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, @@ -378,6 +381,7 @@ private: static std::function _getEntityObjectOperator; static std::function _textSizeOperator; + static std::function _areEntityClicksCapturedOperator; std::vector _staleProxies; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 5d33a6a061..825017b1fe 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -976,7 +976,9 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& using PointerHandler = std::function; auto makePointerHandler = [this](QString eventName) -> PointerHandler { return [this, eventName](const EntityItemID& entityItemID, const PointerEvent& event) { - forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); + if (!EntityTree::areEntityClicksCaptured()) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); + } }; }; diff --git a/scripts/system/edit.js b/scripts/system/edit.js index bce308d5fc..9d807264aa 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -924,7 +924,11 @@ var toolBar = (function () { that.setActive = function (active) { ContextOverlay.enabled = !active; Settings.setValue(EDIT_SETTING, active); - if (!active) { + if (active) { + Controller.captureEntityClickEvents(); + } else { + Controller.releaseEntityClickEvents(); + closeExistingDialogWindow(); } if (active === isActive) { From 29a308dcaacfa138b721d183a146b38befe3988a Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Tue, 5 Mar 2019 10:07:33 -0800 Subject: [PATCH 16/21] adding modelScale initialization so that it does not fail the validScale check assert --- libraries/entities/src/ModelEntityItem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 505ee26c0f..87d80ee044 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -40,6 +40,7 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem( _type = EntityTypes::Model; _lastKnownCurrentFrame = -1; _visuallyReady = false; + _modelScale=glm::vec3(1.0f); } const QString ModelEntityItem::getTextures() const { From 36e9c604e9e70efde65c5a7f64044d0da052a022 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Tue, 5 Mar 2019 10:45:15 -0800 Subject: [PATCH 17/21] fixed based on comment --- libraries/entities/src/ModelEntityItem.cpp | 1 - libraries/entities/src/ModelEntityItem.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 87d80ee044..505ee26c0f 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -40,7 +40,6 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem( _type = EntityTypes::Model; _lastKnownCurrentFrame = -1; _visuallyReady = false; - _modelScale=glm::vec3(1.0f); } const QString ModelEntityItem::getTextures() const { diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 0efbbbb16c..89acd6179b 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -164,7 +164,7 @@ protected: int _lastKnownCurrentFrame{-1}; glm::u8vec3 _color; - glm::vec3 _modelScale; + glm::vec3 _modelScale {1.0f}; QString _modelURL; bool _relayParentJoints; bool _groupCulled { false }; From fab343a1d4d703009c585aca2bc7eba64e983cfe Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Tue, 5 Mar 2019 10:52:54 -0800 Subject: [PATCH 18/21] correcting spacing --- libraries/entities/src/ModelEntityItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 89acd6179b..08468617ba 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -164,7 +164,7 @@ protected: int _lastKnownCurrentFrame{-1}; glm::u8vec3 _color; - glm::vec3 _modelScale {1.0f}; + glm::vec3 _modelScale { 1.0f }; QString _modelURL; bool _relayParentJoints; bool _groupCulled { false }; From d88235a08f577bc4145bd6b8e518e02e256ae3ce Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Tue, 5 Mar 2019 17:09:54 -0800 Subject: [PATCH 19/21] Initial implementation (deadlocks still occurring in Audio.cpp) --- interface/resources/qml/hifi/audio/Audio.qml | 19 ++ interface/resources/qml/hifi/audio/MicBar.qml | 9 +- interface/src/Application.cpp | 18 ++ interface/src/Application.h | 2 + interface/src/scripting/Audio.cpp | 174 +++++++++++++++++- interface/src/scripting/Audio.h | 89 ++++++++- scripts/system/audio.js | 3 + 7 files changed, 302 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index c8dd83cd62..45358f59a2 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -148,6 +148,25 @@ Rectangle { checked = Qt.binding(function() { return AudioScriptingInterface.noiseReduction; }); // restore binding } } + AudioControls.CheckBox { + spacing: muteMic.spacing + text: qsTr("Push To Talk"); + checked: isVR ? AudioScriptingInterface.pushToTalkHMD : AudioScriptingInterface.pushToTalkDesktop; + onClicked: { + if (isVR) { + AudioScriptingInterface.pushToTalkHMD = checked; + } else { + AudioScriptingInterface.pushToTalkDesktop = checked; + } + checked = Qt.binding(function() { + if (isVR) { + return AudioScriptingInterface.pushToTalkHMD; + } else { + return AudioScriptingInterface.pushToTalkDesktop; + } + }); // restore binding + } + } AudioControls.CheckBox { spacing: muteMic.spacing text: qsTr("Show audio level meter"); diff --git a/interface/resources/qml/hifi/audio/MicBar.qml b/interface/resources/qml/hifi/audio/MicBar.qml index 39f75a9182..f91058bc3c 100644 --- a/interface/resources/qml/hifi/audio/MicBar.qml +++ b/interface/resources/qml/hifi/audio/MicBar.qml @@ -11,10 +11,13 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 +import stylesUit 1.0 import TabletScriptingInterface 1.0 Rectangle { + HifiConstants { id: hifi; } + readonly property var level: AudioScriptingInterface.inputLevel; property bool gated: false; @@ -131,9 +134,9 @@ Rectangle { Item { id: status; - readonly property string color: AudioScriptingInterface.muted ? colors.muted : colors.unmuted; + readonly property string color: (AudioScriptingInterface.pushingToTalk && AudioScriptingInterface.muted) ? hifi.colors.blueHighlight : AudioScriptingInterface.muted ? colors.muted : colors.unmuted; - visible: AudioScriptingInterface.muted; + visible: AudioScriptingInterface.pushingToTalk || AudioScriptingInterface.muted; anchors { left: parent.left; @@ -152,7 +155,7 @@ Rectangle { color: parent.color; - text: AudioScriptingInterface.muted ? "MUTED" : "MUTE"; + text: AudioScriptingInterface.pushToTalk ? (AudioScriptingInterface.pushingToTalk ? "SPEAKING" : "PUSH TO TALK") : (AudioScriptingInterface.muted ? "MUTED" : "MUTE"); font.pointSize: 12; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b8ab4d10db..fa63757560 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1435,6 +1435,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }); connect(this, &Application::activeDisplayPluginChanged, reinterpret_cast(audioScriptingInterface.data()), &scripting::Audio::onContextChanged); + connect(this, &Application::pushedToTalk, + reinterpret_cast(audioScriptingInterface.data()), &scripting::Audio::handlePushedToTalk); } // Create the rendering engine. This can be slow on some machines due to lots of @@ -4199,6 +4201,10 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; + case Qt::Key_T: + emit pushedToTalk(true); + break; + case Qt::Key_P: { if (!isShifted && !isMeta && !isOption && !event->isAutoRepeat()) { AudioInjectorOptions options; @@ -4304,6 +4310,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) { if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->keyReleaseEvent(event); } + + switch (event->key()) { + case Qt::Key_T: + emit pushedToTalk(false); + break; + } } void Application::focusOutEvent(QFocusEvent* event) { @@ -5235,6 +5247,9 @@ void Application::loadSettings() { } } + auto audioScriptingInterface = reinterpret_cast(DependencyManager::get().data()); + audioScriptingInterface->loadData(); + getMyAvatar()->loadData(); _settingsLoaded = true; } @@ -5244,6 +5259,9 @@ void Application::saveSettings() const { DependencyManager::get()->saveSettings(); DependencyManager::get()->saveSettings(); + auto audioScriptingInterface = reinterpret_cast(DependencyManager::get().data()); + audioScriptingInterface->saveData(); + Menu::getInstance()->saveSettings(); getMyAvatar()->saveData(); PluginManager::getInstance()->saveSettings(); diff --git a/interface/src/Application.h b/interface/src/Application.h index a8cc9450c5..1c86326f90 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -358,6 +358,8 @@ signals: void miniTabletEnabledChanged(bool enabled); + void pushedToTalk(bool enabled); + public slots: QVector pasteEntities(float x, float y, float z); bool exportEntities(const QString& filename, const QVector& entityIDs, const glm::vec3* givenOffset = nullptr); diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index 2c4c29ff65..fe04ce47ca 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -63,26 +63,163 @@ void Audio::stopRecording() { } bool Audio::isMuted() const { - return resultWithReadLock([&] { - return _isMuted; - }); + bool isHMD = qApp->isHMDMode(); + if (isHMD) { + return getMutedHMD(); + } + else { + return getMutedDesktop(); + } } void Audio::setMuted(bool isMuted) { + withWriteLock([&] { + bool isHMD = qApp->isHMDMode(); + if (isHMD) { + setMutedHMD(isMuted); + } + else { + setMutedDesktop(isMuted); + } + }); +} + +void Audio::setMutedDesktop(bool isMuted) { + bool changed = false; + if (_desktopMuted != isMuted) { + changed = true; + _desktopMuted = isMuted; + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); + } + if (changed) { + emit mutedChanged(isMuted); + emit desktopMutedChanged(isMuted); + } +} + +bool Audio::getMutedDesktop() const { + return resultWithReadLock([&] { + return _desktopMuted; + }); +} + +void Audio::setMutedHMD(bool isMuted) { + bool changed = false; + if (_hmdMuted != isMuted) { + changed = true; + _hmdMuted = isMuted; + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); + } + if (changed) { + emit mutedChanged(isMuted); + emit hmdMutedChanged(isMuted); + } +} + +bool Audio::getMutedHMD() const { + return resultWithReadLock([&] { + return _hmdMuted; + }); +} + +bool Audio::getPTT() { + bool isHMD = qApp->isHMDMode(); + if (isHMD) { + return getPTTHMD(); + } + else { + return getPTTDesktop(); + } +} + +bool Audio::getPushingToTalk() const { + return resultWithReadLock([&] { + return _pushingToTalk; + }); +} + +void Audio::setPTT(bool enabled) { + bool isHMD = qApp->isHMDMode(); + if (isHMD) { + setPTTHMD(enabled); + } + else { + setPTTDesktop(enabled); + } +} + +void Audio::setPTTDesktop(bool enabled) { bool changed = false; withWriteLock([&] { - if (_isMuted != isMuted) { - _isMuted = isMuted; - auto client = DependencyManager::get().data(); - QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); + if (_pttDesktop != enabled) { changed = true; + _pttDesktop = enabled; + if (!enabled) { + // Set to default behavior (unmuted for Desktop) on Push-To-Talk disable. + setMutedDesktop(true); + } + else { + // Should be muted when not pushing to talk while PTT is enabled. + setMutedDesktop(true); + } } }); if (changed) { - emit mutedChanged(isMuted); + emit pushToTalkChanged(enabled); + emit pushToTalkDesktopChanged(enabled); } } +bool Audio::getPTTDesktop() const { + return resultWithReadLock([&] { + return _pttDesktop; + }); +} + +void Audio::setPTTHMD(bool enabled) { + bool changed = false; + withWriteLock([&] { + if (_pttHMD != enabled) { + changed = true; + _pttHMD = enabled; + if (!enabled) { + // Set to default behavior (unmuted for HMD) on Push-To-Talk disable. + setMutedHMD(false); + } + else { + // Should be muted when not pushing to talk while PTT is enabled. + setMutedHMD(true); + } + } + }); + if (changed) { + emit pushToTalkChanged(enabled); + emit pushToTalkHMDChanged(enabled); + } +} + +bool Audio::getPTTHMD() const { + return resultWithReadLock([&] { + return _pttHMD; + }); +} + +void Audio::saveData() { + _desktopMutedSetting.set(getMutedDesktop()); + _hmdMutedSetting.set(getMutedHMD()); + _pttDesktopSetting.set(getPTTDesktop()); + _pttHMDSetting.set(getPTTHMD()); +} + +void Audio::loadData() { + _desktopMuted = _desktopMutedSetting.get(); + _hmdMuted = _hmdMutedSetting.get(); + _pttDesktop = _pttDesktopSetting.get(); + _pttHMD = _pttHMDSetting.get(); +} + bool Audio::noiseReductionEnabled() const { return resultWithReadLock([&] { return _enableNoiseReduction; @@ -179,11 +316,32 @@ void Audio::onContextChanged() { changed = true; } }); + if (isHMD) { + setMuted(getMutedHMD()); + } + else { + setMuted(getMutedDesktop()); + } if (changed) { emit contextChanged(isHMD ? Audio::HMD : Audio::DESKTOP); } } +void Audio::handlePushedToTalk(bool enabled) { + if (getPTT()) { + if (enabled) { + setMuted(false); + } + else { + setMuted(true); + } + if (_pushingToTalk != enabled) { + _pushingToTalk = enabled; + emit pushingToTalkChanged(enabled); + } + } +} + void Audio::setReverb(bool enable) { withWriteLock([&] { DependencyManager::get()->setReverb(enable); diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index e4dcba9130..6aa589e399 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -12,6 +12,7 @@ #ifndef hifi_scripting_Audio_h #define hifi_scripting_Audio_h +#include #include "AudioScriptingInterface.h" #include "AudioDevices.h" #include "AudioEffectOptions.h" @@ -19,6 +20,9 @@ #include "AudioFileWav.h" #include +using MutedGetter = std::function; +using MutedSetter = std::function; + namespace scripting { class Audio : public AudioScriptingInterface, protected ReadWriteLockable { @@ -63,6 +67,12 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable { Q_PROPERTY(bool clipping READ isClipping NOTIFY clippingChanged) Q_PROPERTY(QString context READ getContext NOTIFY contextChanged) Q_PROPERTY(AudioDevices* devices READ getDevices NOTIFY nop) + Q_PROPERTY(bool desktopMuted READ getMutedDesktop WRITE setMutedDesktop NOTIFY desktopMutedChanged) + Q_PROPERTY(bool hmdMuted READ getMutedHMD WRITE setMutedHMD NOTIFY hmdMutedChanged) + Q_PROPERTY(bool pushToTalk READ getPTT WRITE setPTT NOTIFY pushToTalkChanged); + Q_PROPERTY(bool pushToTalkDesktop READ getPTTDesktop WRITE setPTTDesktop NOTIFY pushToTalkDesktopChanged) + Q_PROPERTY(bool pushToTalkHMD READ getPTTHMD WRITE setPTTHMD NOTIFY pushToTalkHMDChanged) + Q_PROPERTY(bool pushingToTalk READ getPushingToTalk NOTIFY pushingToTalkChanged) public: static QString AUDIO; @@ -82,6 +92,25 @@ public: void showMicMeter(bool show); + // Mute setting setters and getters + void setMutedDesktop(bool isMuted); + bool getMutedDesktop() const; + void setMutedHMD(bool isMuted); + bool getMutedHMD() const; + void setPTT(bool enabled); + bool getPTT(); + bool getPushingToTalk() const; + + // Push-To-Talk setters and getters + void setPTTDesktop(bool enabled); + bool getPTTDesktop() const; + void setPTTHMD(bool enabled); + bool getPTTHMD() const; + + // Settings handlers + void saveData(); + void loadData(); + /**jsdoc * @function Audio.setInputDevice * @param {object} device @@ -193,6 +222,46 @@ signals: */ void mutedChanged(bool isMuted); + /**jsdoc + * Triggered when desktop audio input is muted or unmuted. + * @function Audio.desktopMutedChanged + * @param {boolean} isMuted - true if the audio input is muted for desktop mode, otherwise false. + * @returns {Signal} + */ + void desktopMutedChanged(bool isMuted); + + /**jsdoc + * Triggered when HMD audio input is muted or unmuted. + * @function Audio.hmdMutedChanged + * @param {boolean} isMuted - true if the audio input is muted for HMD mode, otherwise false. + * @returns {Signal} + */ + void hmdMutedChanged(bool isMuted); + + /** + * Triggered when Push-to-Talk has been enabled or disabled. + * @function Audio.pushToTalkChanged + * @param {boolean} enabled - true if Push-to-Talk is enabled, otherwise false. + * @returns {Signal} + */ + void pushToTalkChanged(bool enabled); + + /** + * Triggered when Push-to-Talk has been enabled or disabled for desktop mode. + * @function Audio.pushToTalkDesktopChanged + * @param {boolean} enabled - true if Push-to-Talk is emabled for Desktop mode, otherwise false. + * @returns {Signal} + */ + void pushToTalkDesktopChanged(bool enabled); + + /** + * Triggered when Push-to-Talk has been enabled or disabled for HMD mode. + * @function Audio.pushToTalkHMDChanged + * @param {boolean} enabled - true if Push-to-Talk is emabled for HMD mode, otherwise false. + * @returns {Signal} + */ + void pushToTalkHMDChanged(bool enabled); + /**jsdoc * Triggered when the audio input noise reduction is enabled or disabled. * @function Audio.noiseReductionChanged @@ -237,6 +306,14 @@ signals: */ void contextChanged(const QString& context); + /**jsdoc + * Triggered when pushing to talk. + * @function Audio.pushingToTalkChanged + * @param {boolean} talking - true if broadcasting with PTT, false otherwise. + * @returns {Signal} + */ + void pushingToTalkChanged(bool talking); + public slots: /**jsdoc @@ -245,6 +322,8 @@ public slots: */ void onContextChanged(); + void handlePushedToTalk(bool enabled); + private slots: void setMuted(bool muted); void enableNoiseReduction(bool enable); @@ -260,11 +339,19 @@ private: float _inputVolume { 1.0f }; float _inputLevel { 0.0f }; bool _isClipping { false }; - bool _isMuted { false }; bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled. bool _contextIsHMD { false }; AudioDevices* getDevices() { return &_devices; } AudioDevices _devices; + Setting::Handle _desktopMutedSetting{ QStringList { Audio::AUDIO, "desktopMuted" }, true }; + Setting::Handle _hmdMutedSetting{ QStringList { Audio::AUDIO, "hmdMuted" }, true }; + Setting::Handle _pttDesktopSetting{ QStringList { Audio::AUDIO, "pushToTalkDesktop" }, false }; + Setting::Handle _pttHMDSetting{ QStringList { Audio::AUDIO, "pushToTalkHMD" }, false }; + bool _desktopMuted{ true }; + bool _hmdMuted{ false }; + bool _pttDesktop{ false }; + bool _pttHMD{ false }; + bool _pushingToTalk{ false }; }; }; diff --git a/scripts/system/audio.js b/scripts/system/audio.js index ee82c0c6ea..51d070d8cd 100644 --- a/scripts/system/audio.js +++ b/scripts/system/audio.js @@ -28,6 +28,9 @@ var UNMUTE_ICONS = { }; function onMuteToggled() { + if (Audio.pushingToTalk) { + return; + } if (Audio.muted) { button.editProperties(MUTE_ICONS); } else { From 8b4123b5dc7a92bedd7a533a2fd6f16b66a1ade5 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Wed, 6 Mar 2019 11:00:09 -0800 Subject: [PATCH 20/21] laying groundwork for audio app + fixing deadlocks --- interface/resources/qml/hifi/audio/MicBar.qml | 6 +- interface/src/scripting/Audio.cpp | 108 +++++++++--------- interface/src/scripting/Audio.h | 1 + scripts/system/audio.js | 11 +- 4 files changed, 69 insertions(+), 57 deletions(-) diff --git a/interface/resources/qml/hifi/audio/MicBar.qml b/interface/resources/qml/hifi/audio/MicBar.qml index f91058bc3c..2ab1085408 100644 --- a/interface/resources/qml/hifi/audio/MicBar.qml +++ b/interface/resources/qml/hifi/audio/MicBar.qml @@ -134,7 +134,7 @@ Rectangle { Item { id: status; - readonly property string color: (AudioScriptingInterface.pushingToTalk && AudioScriptingInterface.muted) ? hifi.colors.blueHighlight : AudioScriptingInterface.muted ? colors.muted : colors.unmuted; + readonly property string color: AudioScriptingInterface.pushToTalk ? hifi.colors.blueHighlight : AudioScriptingInterface.muted ? colors.muted : colors.unmuted; visible: AudioScriptingInterface.pushingToTalk || AudioScriptingInterface.muted; @@ -165,7 +165,7 @@ Rectangle { verticalCenter: parent.verticalCenter; } - width: 50; + width: AudioScriptingInterface.pushToTalk ? (AudioScriptingInterface.pushingToTalk ? 45: 30) : 50; height: 4; color: parent.color; } @@ -176,7 +176,7 @@ Rectangle { verticalCenter: parent.verticalCenter; } - width: 50; + width: AudioScriptingInterface.pushToTalk ? (AudioScriptingInterface.pushingToTalk ? 45: 30) : 50; height: 4; color: parent.color; } diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index fe04ce47ca..63ce9d2b2e 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -66,32 +66,30 @@ bool Audio::isMuted() const { bool isHMD = qApp->isHMDMode(); if (isHMD) { return getMutedHMD(); - } - else { + } else { return getMutedDesktop(); } } void Audio::setMuted(bool isMuted) { - withWriteLock([&] { - bool isHMD = qApp->isHMDMode(); - if (isHMD) { - setMutedHMD(isMuted); - } - else { - setMutedDesktop(isMuted); - } - }); + bool isHMD = qApp->isHMDMode(); + if (isHMD) { + setMutedHMD(isMuted); + } else { + setMutedDesktop(isMuted); + } } void Audio::setMutedDesktop(bool isMuted) { bool changed = false; - if (_desktopMuted != isMuted) { - changed = true; - _desktopMuted = isMuted; - auto client = DependencyManager::get().data(); - QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); - } + withWriteLock([&] { + if (_desktopMuted != isMuted) { + changed = true; + _desktopMuted = isMuted; + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); + } + }); if (changed) { emit mutedChanged(isMuted); emit desktopMutedChanged(isMuted); @@ -106,12 +104,14 @@ bool Audio::getMutedDesktop() const { void Audio::setMutedHMD(bool isMuted) { bool changed = false; - if (_hmdMuted != isMuted) { - changed = true; - _hmdMuted = isMuted; - auto client = DependencyManager::get().data(); - QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); - } + withWriteLock([&] { + if (_hmdMuted != isMuted) { + changed = true; + _hmdMuted = isMuted; + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); + } + }); if (changed) { emit mutedChanged(isMuted); emit hmdMutedChanged(isMuted); @@ -128,12 +128,24 @@ bool Audio::getPTT() { bool isHMD = qApp->isHMDMode(); if (isHMD) { return getPTTHMD(); - } - else { + } else { return getPTTDesktop(); } } +void scripting::Audio::setPushingToTalk(bool pushingToTalk) { + bool changed = false; + withWriteLock([&] { + if (_pushingToTalk != pushingToTalk) { + changed = true; + _pushingToTalk = pushingToTalk; + } + }); + if (changed) { + emit pushingToTalkChanged(pushingToTalk); + } +} + bool Audio::getPushingToTalk() const { return resultWithReadLock([&] { return _pushingToTalk; @@ -144,8 +156,7 @@ void Audio::setPTT(bool enabled) { bool isHMD = qApp->isHMDMode(); if (isHMD) { setPTTHMD(enabled); - } - else { + } else { setPTTDesktop(enabled); } } @@ -156,16 +167,16 @@ void Audio::setPTTDesktop(bool enabled) { if (_pttDesktop != enabled) { changed = true; _pttDesktop = enabled; - if (!enabled) { - // Set to default behavior (unmuted for Desktop) on Push-To-Talk disable. - setMutedDesktop(true); - } - else { - // Should be muted when not pushing to talk while PTT is enabled. - setMutedDesktop(true); - } } }); + if (!enabled) { + // Set to default behavior (unmuted for Desktop) on Push-To-Talk disable. + setMutedDesktop(true); + } else { + // Should be muted when not pushing to talk while PTT is enabled. + setMutedDesktop(true); + } + if (changed) { emit pushToTalkChanged(enabled); emit pushToTalkDesktopChanged(enabled); @@ -184,16 +195,16 @@ void Audio::setPTTHMD(bool enabled) { if (_pttHMD != enabled) { changed = true; _pttHMD = enabled; - if (!enabled) { - // Set to default behavior (unmuted for HMD) on Push-To-Talk disable. - setMutedHMD(false); - } - else { - // Should be muted when not pushing to talk while PTT is enabled. - setMutedHMD(true); - } } }); + if (!enabled) { + // Set to default behavior (unmuted for HMD) on Push-To-Talk disable. + setMutedHMD(false); + } else { + // Should be muted when not pushing to talk while PTT is enabled. + setMutedHMD(true); + } + if (changed) { emit pushToTalkChanged(enabled); emit pushToTalkHMDChanged(enabled); @@ -318,8 +329,7 @@ void Audio::onContextChanged() { }); if (isHMD) { setMuted(getMutedHMD()); - } - else { + } else { setMuted(getMutedDesktop()); } if (changed) { @@ -331,14 +341,10 @@ void Audio::handlePushedToTalk(bool enabled) { if (getPTT()) { if (enabled) { setMuted(false); - } - else { + } else { setMuted(true); } - if (_pushingToTalk != enabled) { - _pushingToTalk = enabled; - emit pushingToTalkChanged(enabled); - } + setPushingToTalk(enabled); } } diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 6aa589e399..94f8a7bf54 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -99,6 +99,7 @@ public: bool getMutedHMD() const; void setPTT(bool enabled); bool getPTT(); + void setPushingToTalk(bool pushingToTalk); bool getPushingToTalk() const; // Push-To-Talk setters and getters diff --git a/scripts/system/audio.js b/scripts/system/audio.js index 51d070d8cd..bf44cfa7cc 100644 --- a/scripts/system/audio.js +++ b/scripts/system/audio.js @@ -26,12 +26,15 @@ var UNMUTE_ICONS = { icon: "icons/tablet-icons/mic-unmute-i.svg", activeIcon: "icons/tablet-icons/mic-unmute-a.svg" }; +var PTT_ICONS = { + icon: "icons/tablet-icons/mic-unmute-i.svg", + activeIcon: "icons/tablet-icons/mic-unmute-a.svg" +}; function onMuteToggled() { if (Audio.pushingToTalk) { - return; - } - if (Audio.muted) { + button.editProperties(PTT_ICONS); + } else if (Audio.muted) { button.editProperties(MUTE_ICONS); } else { button.editProperties(UNMUTE_ICONS); @@ -71,6 +74,7 @@ onMuteToggled(); button.clicked.connect(onClicked); tablet.screenChanged.connect(onScreenChanged); Audio.mutedChanged.connect(onMuteToggled); +Audio.pushingToTalkChanged.connect(onMuteToggled); Script.scriptEnding.connect(function () { if (onAudioScreen) { @@ -79,6 +83,7 @@ Script.scriptEnding.connect(function () { button.clicked.disconnect(onClicked); tablet.screenChanged.disconnect(onScreenChanged); Audio.mutedChanged.disconnect(onMuteToggled); + Audio.pushingToTalkChanged.disconnect(onMuteToggled); tablet.removeButton(button); }); From 4467567ee6b6dd478f3baef76dc8e089b760fba8 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Wed, 6 Mar 2019 11:18:57 -0800 Subject: [PATCH 21/21] changing text display --- interface/resources/qml/hifi/audio/MicBar.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/audio/MicBar.qml b/interface/resources/qml/hifi/audio/MicBar.qml index 2ab1085408..9d1cbfbc6c 100644 --- a/interface/resources/qml/hifi/audio/MicBar.qml +++ b/interface/resources/qml/hifi/audio/MicBar.qml @@ -134,9 +134,9 @@ Rectangle { Item { id: status; - readonly property string color: AudioScriptingInterface.pushToTalk ? hifi.colors.blueHighlight : AudioScriptingInterface.muted ? colors.muted : colors.unmuted; + readonly property string color: AudioScriptingInterface.muted ? colors.muted : colors.unmuted; - visible: AudioScriptingInterface.pushingToTalk || AudioScriptingInterface.muted; + visible: (AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk) || AudioScriptingInterface.muted; anchors { left: parent.left; @@ -155,7 +155,7 @@ Rectangle { color: parent.color; - text: AudioScriptingInterface.pushToTalk ? (AudioScriptingInterface.pushingToTalk ? "SPEAKING" : "PUSH TO TALK") : (AudioScriptingInterface.muted ? "MUTED" : "MUTE"); + text: (AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk) ? "MUTED-PTT (T)" : (AudioScriptingInterface.muted ? "MUTED" : "MUTE"); font.pointSize: 12; } @@ -165,7 +165,7 @@ Rectangle { verticalCenter: parent.verticalCenter; } - width: AudioScriptingInterface.pushToTalk ? (AudioScriptingInterface.pushingToTalk ? 45: 30) : 50; + width: AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk ? 25 : 50; height: 4; color: parent.color; } @@ -176,7 +176,7 @@ Rectangle { verticalCenter: parent.verticalCenter; } - width: AudioScriptingInterface.pushToTalk ? (AudioScriptingInterface.pushingToTalk ? 45: 30) : 50; + width: AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk ? 25 : 50; height: 4; color: parent.color; }