From dafa830c0db183fd844404269e11085aaad97249 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 25 Oct 2017 14:07:02 -0700 Subject: [PATCH 001/102] First steps --- .../qml/hifi/commerce/checkout/Checkout.qml | 22 +++++++-------- .../common/EmulatedMarketplaceHeader.qml | 12 ++++----- .../InspectionCertificate.qml | 6 ++--- .../qml/hifi/commerce/purchases/Purchases.qml | 18 ++++++------- .../qml/hifi/commerce/wallet/Help.qml | 10 +++---- .../qml/hifi/commerce/wallet/NeedsLogIn.qml | 4 +-- .../hifi/commerce/wallet/PassphraseModal.qml | 10 +++---- .../commerce/wallet/PassphraseSelection.qml | 8 +++--- .../qml/hifi/commerce/wallet/Security.qml | 6 ++--- .../commerce/wallet/SecurityImageChange.qml | 8 +++--- .../qml/hifi/commerce/wallet/SendMoney.qml | 4 +-- .../qml/hifi/commerce/wallet/Wallet.qml | 16 +++++------ .../qml/hifi/commerce/wallet/WalletHome.qml | 12 ++++----- .../qml/hifi/commerce/wallet/WalletSetup.qml | 12 ++++----- interface/src/Application.cpp | 27 ++++++++++++++++++- interface/src/commerce/QmlCommerce.cpp | 4 +-- interface/src/commerce/QmlCommerce.h | 6 ++--- libraries/ui/src/QmlWindowClass.cpp | 2 +- scripts/system/commerce/wallet.js | 8 ++++-- 19 files changed, 110 insertions(+), 85 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 8ea9ce494c..0a4b2e2cff 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -43,8 +43,8 @@ Rectangle { property bool isWearable; // Style color: hifi.colors.white; - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onWalletStatusResult: { if (walletStatus === 0) { @@ -71,7 +71,7 @@ Rectangle { if (!isLoggedIn && root.activeView !== "needsLogIn") { root.activeView = "needsLogIn"; } else { - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } } @@ -112,7 +112,7 @@ Rectangle { } onItemIdChanged: { - commerce.inventory(); + Commerce.inventory(); itemPreviewImage.source = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/" + itemId + "/thumbnail/hifi-mp-" + itemId + ".jpg"; } @@ -121,7 +121,7 @@ Rectangle { } onItemPriceChanged: { - commerce.balance(); + Commerce.balance(); } Timer { @@ -200,7 +200,7 @@ Rectangle { Component.onCompleted: { purchasesReceived = false; balanceReceived = false; - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } } @@ -221,7 +221,7 @@ Rectangle { Connections { target: GlobalServices onMyUsernameChanged: { - commerce.getLoginStatus(); + Commerce.getLoginStatus(); } } @@ -471,9 +471,9 @@ Rectangle { if (itemIsJson) { buyButton.enabled = false; if (!root.shouldBuyWithControlledFailure) { - commerce.buy(itemId, itemPrice); + Commerce.buy(itemId, itemPrice); } else { - commerce.buy(itemId, itemPrice, true); + Commerce.buy(itemId, itemPrice, true); } } else { if (urlHandler.canHandleUrl(itemHref)) { @@ -938,8 +938,8 @@ Rectangle { } root.balanceReceived = false; root.purchasesReceived = false; - commerce.inventory(); - commerce.balance(); + Commerce.inventory(); + Commerce.balance(); } // diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml index cc316a70e9..e95c720e5f 100644 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml @@ -31,14 +31,14 @@ Item { height: mainContainer.height + additionalDropdownHeight; - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onWalletStatusResult: { if (walletStatus === 0) { sendToParent({method: "needsLogIn"}); } else if (walletStatus === 3) { - commerce.getSecurityImage(); + Commerce.getSecurityImage(); } else if (walletStatus > 3) { console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus); } @@ -48,7 +48,7 @@ Item { if (!isLoggedIn) { sendToParent({method: "needsLogIn"}); } else { - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } } @@ -61,13 +61,13 @@ Item { } Component.onCompleted: { - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } Connections { target: GlobalServices onMyUsernameChanged: { - commerce.getLoginStatus(); + Commerce.getLoginStatus(); } } diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index aa1372494f..ec34de6adc 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -35,8 +35,8 @@ Rectangle { property bool isMyCert: false; // Style color: hifi.colors.faintGray; - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onCertificateInfoResult: { if (result.status !== 'success') { @@ -69,7 +69,7 @@ Rectangle { onCertificateIdChanged: { if (certificateId !== "") { - commerce.certificateInfo(certificateId); + Commerce.certificateInfo(certificateId); } } diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index f292f9603e..b88710d19c 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -38,8 +38,8 @@ Rectangle { property bool isDebuggingFirstUseTutorial: false; // Style color: hifi.colors.white; - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onWalletStatusResult: { if (walletStatus === 0) { @@ -60,7 +60,7 @@ Rectangle { root.activeView = "firstUseTutorial"; } else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") { root.activeView = "purchasesMain"; - commerce.inventory(); + Commerce.inventory(); } } else { console.log("ERROR in Purchases.qml: Unknown wallet status: " + walletStatus); @@ -71,7 +71,7 @@ Rectangle { if (!isLoggedIn && root.activeView !== "needsLogIn") { root.activeView = "needsLogIn"; } else { - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } } @@ -197,7 +197,7 @@ Rectangle { Component.onCompleted: { securityImageResultReceived = false; purchasesReceived = false; - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } } @@ -218,7 +218,7 @@ Rectangle { Connections { target: GlobalServices onMyUsernameChanged: { - commerce.getLoginStatus(); + Commerce.getLoginStatus(); } } @@ -233,7 +233,7 @@ Rectangle { onSendSignalToParent: { if (msg.method === "authSuccess") { root.activeView = "initialize"; - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } else { sendToScript(msg); } @@ -254,7 +254,7 @@ Rectangle { case 'tutorial_finished': Settings.setValue("isFirstUseOfPurchases", false); root.activeView = "purchasesMain"; - commerce.inventory(); + Commerce.inventory(); break; } } @@ -589,7 +589,7 @@ Rectangle { if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) { console.log("Refreshing Purchases..."); root.pendingInventoryReply = true; - commerce.inventory(); + Commerce.inventory(); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml index 0026bf6cdb..f41c6932c0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -27,8 +27,8 @@ Item { property string keyFilePath; property bool showDebugButtons: true; - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onKeyFilePathIfExistsResult: { root.keyFilePath = path; @@ -37,7 +37,7 @@ Item { onVisibleChanged: { if (visible) { - commerce.getKeyFilePathIfExists(); + Commerce.getKeyFilePathIfExists(); } } @@ -67,7 +67,7 @@ Item { width: 150; text: "DBG: Clear Pass"; onClicked: { - commerce.setPassphrase(""); + Commerce.setPassphrase(""); sendSignalToWallet({method: 'passphraseReset'}); } } @@ -82,7 +82,7 @@ Item { width: 150; text: "DBG: RST Wallet"; onClicked: { - commerce.reset(); + Commerce.reset(); sendSignalToWallet({method: 'walletReset'}); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml index 7ce0cf3853..404d7e84cf 100644 --- a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml +++ b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml @@ -30,8 +30,8 @@ Item { source: "images/wallet-bg.jpg"; } - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; } // diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index d967a36b68..9f04db7d5c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -36,8 +36,8 @@ Item { source: "images/wallet-bg.jpg"; } - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onSecurityImageResult: { titleBarSecurityImage.source = ""; @@ -218,7 +218,7 @@ Item { onAccepted: { submitPassphraseInputButton.enabled = false; - commerce.setPassphrase(passphraseField.text); + Commerce.setPassphrase(passphraseField.text); } } @@ -258,7 +258,7 @@ Item { source: "image://security/securityImage"; cache: false; onVisibleChanged: { - commerce.getSecurityImage(); + Commerce.getSecurityImage(); } } Item { @@ -326,7 +326,7 @@ Item { text: "Submit" onClicked: { submitPassphraseInputButton.enabled = false; - commerce.setPassphrase(passphraseField.text); + Commerce.setPassphrase(passphraseField.text); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index ffeedde8f0..0145f92b96 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -36,8 +36,8 @@ Item { propagateComposedEvents: false; } - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onSecurityImageResult: { passphrasePageSecurityImage.source = ""; passphrasePageSecurityImage.source = "image://security/securityImage"; @@ -193,7 +193,7 @@ Item { source: "image://security/securityImage"; cache: false; onVisibleChanged: { - commerce.getSecurityImage(); + Commerce.getSecurityImage(); } } Item { @@ -316,7 +316,7 @@ Item { passphraseFieldAgain.error = false; currentPassphraseField.error = false; setErrorText(""); - commerce.changePassphrase(currentPassphraseField.text, passphraseField.text); + Commerce.changePassphrase(currentPassphraseField.text, passphraseField.text); return true; } } diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index 485b0ec086..d825196655 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -27,8 +27,8 @@ Item { id: root; property string keyFilePath; - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onKeyFilePathIfExistsResult: { root.keyFilePath = path; @@ -234,7 +234,7 @@ Item { onVisibleChanged: { if (visible) { - commerce.getKeyFilePathIfExists(); + Commerce.getKeyFilePathIfExists(); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index 7f767060f6..7cb4a3068f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -30,8 +30,8 @@ Item { id: securityImageModel; } - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onSecurityImageResult: { securityImageChangePageSecurityImage.source = ""; @@ -70,7 +70,7 @@ Item { source: "image://security/securityImage"; cache: false; onVisibleChanged: { - commerce.getSecurityImage(); + Commerce.getSecurityImage(); } } Item { @@ -198,7 +198,7 @@ Item { securityImageSubmitButton.text = "Submitting..."; securityImageSubmitButton.enabled = false; var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) - commerce.chooseSecurityImage(securityImagePath); + Commerce.chooseSecurityImage(securityImagePath); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/SendMoney.qml index 75334b1686..11a6c99b0c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SendMoney.qml @@ -25,8 +25,8 @@ Item { id: root; - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; } // "Unavailable" diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 759d7a37eb..21bf7bace0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -36,8 +36,8 @@ Rectangle { source: "images/wallet-bg.jpg"; } - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onWalletStatusResult: { if (walletStatus === 0) { @@ -54,7 +54,7 @@ Rectangle { } } else if (walletStatus === 3) { root.activeView = "walletHome"; - commerce.getSecurityImage(); + Commerce.getSecurityImage(); } else { console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus); } @@ -64,7 +64,7 @@ Rectangle { if (!isLoggedIn && root.activeView !== "needsLogIn") { root.activeView = "needsLogIn"; } else if (isLoggedIn) { - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } } @@ -174,7 +174,7 @@ Rectangle { if (msg.method === 'walletSetup_finished') { if (msg.referrer === '') { root.activeView = "initialize"; - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } else if (msg.referrer === 'purchases') { sendToScript({method: 'goToPurchases'}); } else { @@ -254,7 +254,7 @@ Rectangle { color: hifi.colors.baseGray; Component.onCompleted: { - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } } @@ -275,7 +275,7 @@ Rectangle { Connections { target: GlobalServices onMyUsernameChanged: { - commerce.getLoginStatus(); + Commerce.getLoginStatus(); } } @@ -289,7 +289,7 @@ Rectangle { Connections { onSendSignalToParent: { if (msg.method === "authSuccess") { - commerce.getWalletStatus(); + Commerce.getWalletStatus(); } else { sendToScript(msg); } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 1fe0dcc58b..929dd1e7e8 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -28,8 +28,8 @@ Item { property bool historyReceived: false; property int pendingCount: 0; - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onBalanceResult : { balanceText.text = result.data.balance; @@ -116,8 +116,8 @@ Item { onVisibleChanged: { if (visible) { historyReceived = false; - commerce.balance(); - commerce.history(); + Commerce.balance(); + Commerce.history(); } else { refreshTimer.stop(); } @@ -147,8 +147,8 @@ Item { onTriggered: { console.log("Refreshing Wallet Home..."); historyReceived = false; - commerce.balance(); - commerce.history(); + Commerce.balance(); + Commerce.history(); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml index 99fe933bd6..6672f4b97e 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml @@ -37,8 +37,8 @@ Item { source: "images/wallet-bg.jpg"; } - Hifi.QmlCommerce { - id: commerce; + Connections { + target: Commerce; onSecurityImageResult: { if (!exists && root.lastPage === "step_2") { @@ -356,7 +356,7 @@ Item { onClicked: { root.lastPage = "step_2"; var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) - commerce.chooseSecurityImage(securityImagePath); + Commerce.chooseSecurityImage(securityImagePath); root.activeView = "step_3"; passphraseSelection.clearPassphraseFields(); } @@ -440,7 +440,7 @@ Item { onVisibleChanged: { if (visible) { - commerce.getWalletAuthenticatedStatus(); + Commerce.getWalletAuthenticatedStatus(); if (!root.hasShownSecurityImageTip) { securityImageTip.visible = true; } @@ -529,7 +529,7 @@ Item { onClicked: { if (passphraseSelection.validateAndSubmitPassphrase()) { root.lastPage = "step_3"; - commerce.generateKeyPair(); + Commerce.generateKeyPair(); root.activeView = "step_4"; } } @@ -662,7 +662,7 @@ Item { onVisibleChanged: { if (visible) { - commerce.getKeyFilePathIfExists(); + Commerce.getKeyFilePathIfExists(); } } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 87d4db9936..4f6e871d48 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2246,7 +2246,32 @@ void Application::initializeUi() { LoginDialog::registerType(); Tooltip::registerType(); UpdateDialog::registerType(); - QmlCommerce::registerType(); + QmlContextCallback callback = [](QQmlContext* context, QObject*) { + context->setContextProperty("Commerce", new QmlCommerce()); + }; + OffscreenQmlSurface::addWhitelistContextHandler({ + QUrl{ "qrc://qml/hifi/commerce/checkout/Checkout.qml" }, + QUrl{ "qrc://qml/hifi/commerce/common/CommerceLightbox.qml" }, + QUrl{ "qrc://qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, + QUrl{ "qrc://qml/hifi/commerce/common/FirstUseTutorial.qml" }, + QUrl{ "qrc://qml/hifi/commerce/common/SortableListModel.qml" }, + QUrl{ "qrc://qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, + QUrl{ "qrc://qml/hifi/commerce/purchases/PurchasedItem.qml" }, + QUrl{ "qrc://qml/hifi/commerce/purchases/Purchases.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/Help.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/NeedsLogIn.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/PassphraseChange.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/PassphraseModal.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/PassphraseSelection.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/Security.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/SecurityImageChange.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/SecurityImageModel.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/SecurityImageSelection.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/SendMoney.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/Wallet.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/WalletHome.qml" }, + QUrl{ "qrc://qml/hifi/commerce/wallet/WalletSetup.qml" }, + }, callback); qmlRegisterType("Hifi", 1, 0, "ResourceImageItem"); qmlRegisterType("Hifi", 1, 0, "Preference"); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 803264fa9f..ecce682896 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -16,9 +16,7 @@ #include "Wallet.h" #include -HIFI_QML_DEF(QmlCommerce) - -QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) { +QmlCommerce::QmlCommerce() { auto ledger = DependencyManager::get(); auto wallet = DependencyManager::get(); connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index ae63133425..915edb71ef 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -16,16 +16,14 @@ #define hifi_QmlCommerce_h #include -#include #include -class QmlCommerce : public OffscreenQmlDialog { +class QmlCommerce : public QObject { Q_OBJECT - HIFI_QML_DECL public: - QmlCommerce(QQuickItem* parent = nullptr); + QmlCommerce(); signals: void walletStatusResult(uint walletStatus); diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 14d8ec8985..1758150e0a 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -62,7 +62,7 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { QUrl url { properties[SOURCE_PROPERTY].toString() }; if (url.scheme() != "http" && url.scheme() != "https" && url.scheme() != "file" && url.scheme() != "about" && - url.scheme() != "atp") { + url.scheme() != "atp" && url.scheme() != "qrc") { properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url.toString()).toString(); } diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 04b67ec14f..7b260dacfc 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -26,7 +26,7 @@ // Relevant Variables: // -WALLET_QML_SOURCE: The path to the Wallet QML // -onWalletScreen: true/false depending on whether we're looking at the app. - var WALLET_QML_SOURCE = Script.resourcesPath() + "qml/hifi/commerce/wallet/Wallet.qml"; + var WALLET_QML_SOURCE = "qrc:///qml/hifi/commerce/wallet/Wallet.qml"; var MARKETPLACE_PURCHASES_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/purchases/Purchases.qml"; var onWalletScreen = false; function onButtonClicked() { @@ -38,7 +38,11 @@ // for toolbar-mode: go back to home screen, this will close the window. tablet.gotoHomeScreen(); } else { - tablet.loadQMLSource(WALLET_QML_SOURCE); + var window = new OverlayWindow({ + title: "Wallet", + source: WALLET_QML_SOURCE, + width: 480, height: 706 + }); } } From 5898f0bd0caadb5091f4e3247d8a7a89e0605772 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 25 Oct 2017 15:04:47 -0700 Subject: [PATCH 002/102] Gotta do some fancy stuff with anchors for this to work --- interface/resources/qml/hifi/commerce/wallet/Wallet.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 21bf7bace0..ce4400b33d 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -31,6 +31,8 @@ Rectangle { property bool keyboardRaised: false; property bool isPassword: false; + anchors.fill: (typeof parent === undefined) ? undefined : parent; + Image { anchors.fill: parent; source: "images/wallet-bg.jpg"; From a5caae373978f8317e28686b08bbe96fc22b3f7c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 25 Oct 2017 16:49:23 -0700 Subject: [PATCH 003/102] Modify QML context population order --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 29 ++++++++++----------- libraries/ui/src/ui/OffscreenQmlSurface.h | 15 ++++++----- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index ecd07a5874..cf746b26fd 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -98,7 +98,7 @@ void OffscreenQmlSurface::addWhitelistContextHandler(const std::initializer_list } -QmlContextCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QObject*) {}; +QmlContextObjectCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QObject*) {}; struct TextureSet { // The number of surfaces with this size @@ -688,7 +688,7 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) { _qmlContext->setBaseUrl(baseUrl); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback) { +void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback) { if (QThread::currentThread() != thread()) { qCWarning(uiLogging) << "Called load on a non-surface thread"; } @@ -699,13 +699,16 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, con QList callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource); // If we have whitelisted content, we must load a new context createNewContext |= !callbacks.empty(); - callbacks.push_back(onQmlLoadedCallback); QQmlContext* targetContext = _qmlContext; if (_rootItem && createNewContext) { targetContext = new QQmlContext(targetContext); } + for (const auto& callback : callbacks) { + callback(targetContext); + } + // FIXME eliminate loading of relative file paths for QML QUrl finalQmlSource = qmlSource; @@ -716,23 +719,23 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, con auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); if (qmlComponent->isLoading()) { connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) { - finishQmlLoad(qmlComponent, targetContext, callbacks); + finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); }); return; } - finishQmlLoad(qmlComponent, targetContext, callbacks); + finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); } -void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) { +void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback) { load(qmlSource, true, onQmlLoadedCallback); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) { +void OffscreenQmlSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback) { load(qmlSource, false, onQmlLoadedCallback); } -void OffscreenQmlSurface::load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback) { +void OffscreenQmlSurface::load(const QString& qmlSourceFile, const QmlContextObjectCallback& onQmlLoadedCallback) { return load(QUrl(qmlSourceFile), onQmlLoadedCallback); } @@ -740,7 +743,7 @@ void OffscreenQmlSurface::clearCache() { _qmlContext->engine()->clearComponentCache(); } -void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList& callbacks) { +void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QmlContextObjectCallback& callback) { disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { @@ -775,9 +778,7 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext // Make sure we will call callback for this codepath // Call this before qmlComponent->completeCreate() otherwise ghost window appears if (newItem && _rootItem) { - for (const auto& callback : callbacks) { - callback(qmlContext, newObject); - } + callback(qmlContext, newObject); } QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); @@ -814,9 +815,7 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext _rootItem->setSize(_quickWindow->renderTargetSize()); // Call this callback after rootitem is set, otherwise VrMenu wont work - for (const auto& callback : callbacks) { - callback(qmlContext, newObject); - } + callback(qmlContext, newObject); } void OffscreenQmlSurface::updateQuick() { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 12ee9e59a1..890a1d263c 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -35,7 +35,8 @@ class QQuickItem; // one copy in flight, and one copy being used by the receiver #define GPU_RESOURCE_BUFFER_SIZE 3 -using QmlContextCallback = std::function; +using QmlContextCallback = std::function; +using QmlContextObjectCallback = std::function; class OffscreenQmlSurface : public QObject { Q_OBJECT @@ -43,7 +44,7 @@ class OffscreenQmlSurface : public QObject { public: static void setSharedContext(QOpenGLContext* context); - static QmlContextCallback DEFAULT_CONTEXT_CALLBACK; + static QmlContextObjectCallback DEFAULT_CONTEXT_CALLBACK; static void addWhitelistContextHandler(const std::initializer_list& urls, const QmlContextCallback& callback); static void addWhitelistContextHandler(const QUrl& url, const QmlContextCallback& callback) { addWhitelistContextHandler({ { url } }, callback); }; @@ -56,10 +57,10 @@ public: void resize(const QSize& size, bool forceResize = false); QSize size() const; - Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); - Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); - Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); - Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); void clearCache(); void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; } // Optional values for event handling @@ -124,7 +125,7 @@ protected: private: static QOpenGLContext* getSharedContext(); - void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList& callbacks); + void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QmlContextObjectCallback& callbacks); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); void setupFbo(); bool allowNewFrame(uint8_t fps); From 7027dbb8d4de70b680a09bf0048ad61060805f38 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 26 Oct 2017 10:48:26 -0700 Subject: [PATCH 004/102] Integrate Austin's changes --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dbc1d4cfbd..1de17b1568 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2251,7 +2251,7 @@ void Application::initializeUi() { LoginDialog::registerType(); Tooltip::registerType(); UpdateDialog::registerType(); - QmlContextCallback callback = [](QQmlContext* context, QObject*) { + QmlContextCallback callback = [](QQmlContext* context) { context->setContextProperty("Commerce", new QmlCommerce()); }; OffscreenQmlSurface::addWhitelistContextHandler({ From 40aa3b522c8edf06d9c683c1955bb36f0c0fe51f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 26 Oct 2017 10:59:18 -0700 Subject: [PATCH 005/102] Three slashes, not two --- interface/src/Application.cpp | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1de17b1568..d437b1532f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2255,27 +2255,27 @@ void Application::initializeUi() { context->setContextProperty("Commerce", new QmlCommerce()); }; OffscreenQmlSurface::addWhitelistContextHandler({ - QUrl{ "qrc://qml/hifi/commerce/checkout/Checkout.qml" }, - QUrl{ "qrc://qml/hifi/commerce/common/CommerceLightbox.qml" }, - QUrl{ "qrc://qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, - QUrl{ "qrc://qml/hifi/commerce/common/FirstUseTutorial.qml" }, - QUrl{ "qrc://qml/hifi/commerce/common/SortableListModel.qml" }, - QUrl{ "qrc://qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, - QUrl{ "qrc://qml/hifi/commerce/purchases/PurchasedItem.qml" }, - QUrl{ "qrc://qml/hifi/commerce/purchases/Purchases.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/Help.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/NeedsLogIn.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/PassphraseChange.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/PassphraseModal.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/PassphraseSelection.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/Security.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/SecurityImageChange.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/SecurityImageModel.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/SecurityImageSelection.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/SendMoney.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/Wallet.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/WalletHome.qml" }, - QUrl{ "qrc://qml/hifi/commerce/wallet/WalletSetup.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/checkout/Checkout.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/common/CommerceLightbox.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/common/FirstUseTutorial.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/common/SortableListModel.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/purchases/PurchasedItem.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/purchases/Purchases.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/Help.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/NeedsLogIn.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/PassphraseChange.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/PassphraseModal.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/PassphraseSelection.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/Security.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/SecurityImageChange.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/SecurityImageModel.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/SecurityImageSelection.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/SendMoney.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/Wallet.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/WalletHome.qml" }, + QUrl{ "qrc:///qml/hifi/commerce/wallet/WalletSetup.qml" }, }, callback); qmlRegisterType("Hifi", 1, 0, "ResourceImageItem"); qmlRegisterType("Hifi", 1, 0, "Preference"); From ffc51d5387a350a9d24d4c9430dfafc1ed0d74eb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 26 Oct 2017 14:20:13 -0700 Subject: [PATCH 006/102] Working on QML whitelist functionality --- interface/resources/qml/OverlayWindowTest.qml | 18 +++ interface/resources/qml/QmlWindow.qml | 30 ++--- interface/src/Application.cpp | 6 + libraries/ui/src/QmlWindowClass.cpp | 2 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 109 ++++++++++++------ libraries/ui/src/ui/OffscreenQmlSurface.h | 8 +- scripts/developer/tests/qmlTest.js | 2 +- 7 files changed, 113 insertions(+), 62 deletions(-) create mode 100644 interface/resources/qml/OverlayWindowTest.qml diff --git a/interface/resources/qml/OverlayWindowTest.qml b/interface/resources/qml/OverlayWindowTest.qml new file mode 100644 index 0000000000..7b82b2f705 --- /dev/null +++ b/interface/resources/qml/OverlayWindowTest.qml @@ -0,0 +1,18 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Rectangle { + width: 100 + height: 100 + color: "white" + Rectangle { + width: 10 + height: 10 + color: "red" + } + + Label { + text: OverlayWindowTestString + anchors.centerIn: parent + } +} diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index 9a84418b3a..23b435074d 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -22,7 +22,6 @@ Windows.Window { // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer destroyOnCloseButton: false property var source; - property var component; property var dynamicContent; // Keyboard control properties in case needed by QML content. @@ -35,28 +34,13 @@ Windows.Window { dynamicContent.destroy(); dynamicContent = null; } - component = Qt.createComponent(source); - console.log("Created component " + component + " from source " + source); - } - - onComponentChanged: { - console.log("Component changed to " + component) - populate(); - } - - function populate() { - console.log("Populate called: dynamicContent " + dynamicContent + " component " + component); - if (!dynamicContent && component) { - if (component.status == Component.Error) { - console.log("Error loading component:", component.errorString()); - } else if (component.status == Component.Ready) { - console.log("Building dynamic content"); - dynamicContent = component.createObject(contentHolder); - } else { - console.log("Component not yet ready, connecting to status change"); - component.statusChanged.connect(populate); - } - } + console.log("QQQ Foo"); + QmlSurface.createContentFromQml(source, contentHolder, function(newObject) { + console.log("QQQ Bar " + dynamicContent); + dynamicContent = newObject; + dynamicContent.visible = true; + }); + console.log("QQQ Baz"); } // Handle message traffic from the script that launched us to the loaded QML diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 87d4db9936..deb4963ff4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2240,6 +2240,12 @@ extern void setupPreferences(); void Application::initializeUi() { // Make sure all QML surfaces share the main thread GL context OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext()); + OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "qrc:///qml/OverlayWindowTest.qml" }, + [](QQmlContext* context) { + qDebug() << "Whitelist OverlayWindow worked"; + context->setContextProperty("OverlayWindowTestString", "TestWorked"); + }); + AddressBarDialog::registerType(); ErrorDialog::registerType(); diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 14d8ec8985..1758150e0a 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -62,7 +62,7 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { QUrl url { properties[SOURCE_PROPERTY].toString() }; if (url.scheme() != "http" && url.scheme() != "https" && url.scheme() != "file" && url.scheme() != "about" && - url.scheme() != "atp") { + url.scheme() != "atp" && url.scheme() != "qrc") { properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url.toString()).toString(); } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index cf746b26fd..5ef804330b 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -64,11 +64,19 @@ public: for (const auto& url : urls) { _callbacks[url].push_back(callback); } + for (const auto& url : _callbacks.keys()) { + qDebug() << "URL found for " << url << " with " << _callbacks[url].size() << " items"; + } }); } QList getCallbacksForUrl(const QUrl& url) const { + qDebug() << "Looking for callbacks for " << url; + return resultWithReadLock>([&] { + for (const auto& url : _callbacks.keys()) { + qDebug() << "URL found for " << url << " with " << _callbacks[url].size() << " items"; + } QList result; auto itr = _callbacks.find(url); if (_callbacks.end() != itr) { @@ -98,7 +106,7 @@ void OffscreenQmlSurface::addWhitelistContextHandler(const std::initializer_list } -QmlContextObjectCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QObject*) {}; +QmlContextObjectCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QQuickItem*) {}; struct TextureSet { // The number of surfaces with this size @@ -590,6 +598,7 @@ void OffscreenQmlSurface::create() { _qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow())); _qmlContext->setContextProperty("eventBridge", this); _qmlContext->setContextProperty("webEntity", this); + _qmlContext->setContextProperty("QmlSurface", this); // FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper // Find a way to flag older scripts using this mechanism and wanr that this is deprecated @@ -688,20 +697,14 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) { _qmlContext->setBaseUrl(baseUrl); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback) { - if (QThread::currentThread() != thread()) { - qCWarning(uiLogging) << "Called load on a non-surface thread"; - } - // Synchronous loading may take a while; restart the deadlock timer - QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection); - +QQmlContext* OffscreenQmlSurface::contextForUrl(const QUrl& qmlSource, bool forceNewContext) { // Get any whitelist functionality QList callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource); // If we have whitelisted content, we must load a new context - createNewContext |= !callbacks.empty(); + forceNewContext |= !callbacks.empty(); QQmlContext* targetContext = _qmlContext; - if (_rootItem && createNewContext) { + if (_rootItem && forceNewContext) { targetContext = new QQmlContext(targetContext); } @@ -709,6 +712,15 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, con callback(targetContext); } + return targetContext; +} + +void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback) { + if (QThread::currentThread() != thread()) { + qCWarning(uiLogging) << "Called load on a non-surface thread"; + } + // Synchronous loading may take a while; restart the deadlock timer + QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection); // FIXME eliminate loading of relative file paths for QML QUrl finalQmlSource = qmlSource; @@ -716,17 +728,36 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, con finalQmlSource = _qmlContext->resolvedUrl(qmlSource); } + auto targetContext = contextForUrl(finalQmlSource); auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); if (qmlComponent->isLoading()) { connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) { - finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); + finishQmlLoad(qmlComponent, targetContext, nullptr, onQmlLoadedCallback); }); return; } - finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); + finishQmlLoad(qmlComponent, targetContext, nullptr, onQmlLoadedCallback); } +void OffscreenQmlSurface::createContentFromQml(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) { + auto targetContext = contextForUrl(qmlSource); + + auto onQmlLoadedCallback = [=](QQmlContext*, QObject* newItem) { + QJSValue(callback).call(QJSValueList() << _qmlContext->engine()->newQObject(newItem)); + }; + + auto qmlComponent = new QQmlComponent(_qmlContext->engine(), qmlSource, QQmlComponent::PreferSynchronous); + if (qmlComponent->isLoading()) { + connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) { + finishQmlLoad(qmlComponent, targetContext, parent, onQmlLoadedCallback); + }); + return; + } + finishQmlLoad(qmlComponent, targetContext, parent, onQmlLoadedCallback); +} + + void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback) { load(qmlSource, true, onQmlLoadedCallback); } @@ -743,7 +774,8 @@ void OffscreenQmlSurface::clearCache() { _qmlContext->engine()->clearComponentCache(); } -void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QmlContextObjectCallback& callback) { + +void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, QQuickItem* parent, const QmlContextObjectCallback& callback) { disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { @@ -765,6 +797,22 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext return; } + if (!newObject) { + if (!_rootItem) { + qFatal("Could not load object as root item"); + return; + } + qCWarning(uiLogging) << "Unable to load QML item"; + return; + } + + QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); + if (qmlContext != _qmlContext && eventBridge && eventBridge != this) { + // FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper + // Find a way to flag older scripts using this mechanism and wanr that this is deprecated + qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(eventBridge, qmlContext)); + } + qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership); // All quick items should be focusable @@ -775,35 +823,26 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext newItem->setFlag(QQuickItem::ItemIsFocusScope, true); } + // Make sure we will call callback for this codepath // Call this before qmlComponent->completeCreate() otherwise ghost window appears - if (newItem && _rootItem) { - callback(qmlContext, newObject); - } + // If we already have a root, just set a couple of flags and the ancestry + if (_rootItem) { + callback(qmlContext, newItem); - QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); - if (qmlContext != _qmlContext && eventBridge && eventBridge != this) { - // FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper - // Find a way to flag older scripts using this mechanism and wanr that this is deprecated - qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(eventBridge, qmlContext)); + if (!parent) { + parent = _rootItem; + } + // Allow child windows to be destroyed from JS + QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership); + newObject->setParent(parent); + newItem->setParentItem(parent); } qmlComponent->completeCreate(); qmlComponent->deleteLater(); - // If we already have a root, just set a couple of flags and the ancestry - if (newItem && _rootItem) { - // Allow child windows to be destroyed from JS - QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership); - newObject->setParent(_rootItem); - if (newItem) { - newItem->setParentItem(_rootItem); - } - return; - } - - if (!newItem) { - qFatal("Could not load object as root item"); + if (_rootItem) { return; } @@ -815,7 +854,7 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext _rootItem->setSize(_quickWindow->renderTargetSize()); // Call this callback after rootitem is set, otherwise VrMenu wont work - callback(qmlContext, newObject); + callback(qmlContext, newItem); } void OffscreenQmlSurface::updateQuick() { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 890a1d263c..185630905d 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -30,13 +30,14 @@ class QQmlContext; class QQmlComponent; class QQuickWindow; class QQuickItem; +class QJSValue; // GPU resources are typically buffered for one copy being used by the renderer, // one copy in flight, and one copy being used by the receiver #define GPU_RESOURCE_BUFFER_SIZE 3 using QmlContextCallback = std::function; -using QmlContextObjectCallback = std::function; +using QmlContextObjectCallback = std::function; class OffscreenQmlSurface : public QObject { Q_OBJECT @@ -57,6 +58,8 @@ public: void resize(const QSize& size, bool forceResize = false); QSize size() const; + Q_INVOKABLE void createContentFromQml(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback); + Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); @@ -123,9 +126,10 @@ protected: void setFocusText(bool newFocusText); private: + QQmlContext* contextForUrl(const QUrl& url, bool forceNewContext = false); static QOpenGLContext* getSharedContext(); - void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QmlContextObjectCallback& callbacks); + void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, QQuickItem* parent, const QmlContextObjectCallback& callbacks); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); void setupFbo(); bool allowNewFrame(uint8_t fps); diff --git a/scripts/developer/tests/qmlTest.js b/scripts/developer/tests/qmlTest.js index c891b6a1b7..0eaabac6d1 100644 --- a/scripts/developer/tests/qmlTest.js +++ b/scripts/developer/tests/qmlTest.js @@ -1,7 +1,7 @@ print("Launching web window"); qmlWindow = new OverlayWindow({ title: 'Test Qml', - source: "https://s3.amazonaws.com/DreamingContent/qml/content.qml", + source: "qrc:///qml/OverlayWindowTest.qml", height: 240, width: 320, toolWindow: false, From d162e1cff67c870516fb34672e59e82f99015050 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 25 Oct 2017 16:49:23 -0700 Subject: [PATCH 007/102] Whitelist functionality for tablet apps --- interface/resources/qml/OverlayWindowTest.qml | 18 +++ interface/resources/qml/QmlWindow.qml | 26 +--- .../resources/qml/hifi/tablet/Tablet.qml | 35 +++-- .../resources/qml/hifi/tablet/TabletRoot.qml | 122 ++++++++++------- interface/src/Application.cpp | 24 +++- interface/src/Menu.cpp | 4 +- .../scripting/WalletScriptingInterface.cpp | 4 +- interface/src/ui/DialogsManager.cpp | 4 +- interface/src/ui/LoginDialog.cpp | 2 +- .../ui/overlays/ContextOverlayInterface.cpp | 2 +- .../src/RenderableWebEntityItem.cpp | 7 +- libraries/ui/src/QmlWindowClass.cpp | 2 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 128 +++++++++++------- libraries/ui/src/ui/OffscreenQmlSurface.h | 26 ++-- .../ui/src/ui/OffscreenQmlSurfaceCache.cpp | 1 - .../ui/src/ui/TabletScriptingInterface.cpp | 65 +++------ .../ui/src/ui/TabletScriptingInterface.h | 8 +- scripts/developer/inputRecording.js | 2 +- scripts/developer/tests/qmlTest.js | 2 +- scripts/system/audio.js | 2 +- scripts/system/commerce/wallet.js | 4 +- scripts/system/edit.js | 2 +- scripts/system/generalSettings.js | 2 +- scripts/system/marketplaces/marketplaces.js | 2 +- scripts/system/pal.js | 2 +- scripts/system/tablet-goto.js | 2 +- .../skyboxChanger/skyboxchanger.js | 2 +- .../spectator-camera/spectatorCamera.js | 2 +- 28 files changed, 284 insertions(+), 218 deletions(-) create mode 100644 interface/resources/qml/OverlayWindowTest.qml diff --git a/interface/resources/qml/OverlayWindowTest.qml b/interface/resources/qml/OverlayWindowTest.qml new file mode 100644 index 0000000000..7b82b2f705 --- /dev/null +++ b/interface/resources/qml/OverlayWindowTest.qml @@ -0,0 +1,18 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Rectangle { + width: 100 + height: 100 + color: "white" + Rectangle { + width: 10 + height: 10 + color: "red" + } + + Label { + text: OverlayWindowTestString + anchors.centerIn: parent + } +} diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index 9a84418b3a..7c1ce704c3 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -22,7 +22,6 @@ Windows.Window { // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer destroyOnCloseButton: false property var source; - property var component; property var dynamicContent; // Keyboard control properties in case needed by QML content. @@ -35,28 +34,9 @@ Windows.Window { dynamicContent.destroy(); dynamicContent = null; } - component = Qt.createComponent(source); - console.log("Created component " + component + " from source " + source); - } - - onComponentChanged: { - console.log("Component changed to " + component) - populate(); - } - - function populate() { - console.log("Populate called: dynamicContent " + dynamicContent + " component " + component); - if (!dynamicContent && component) { - if (component.status == Component.Error) { - console.log("Error loading component:", component.errorString()); - } else if (component.status == Component.Ready) { - console.log("Building dynamic content"); - dynamicContent = component.createObject(contentHolder); - } else { - console.log("Component not yet ready, connecting to status change"); - component.statusChanged.connect(populate); - } - } + QmlSurface.load(source, contentHolder, function(newObject) { + dynamicContent = newObject; + }); } // Handle message traffic from the script that launched us to the loaded QML diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 66e3dfdbbb..b21bf9c506 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -2,6 +2,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.3 +import "." import "../../styles-uit" import "../audio" as HifiAudio @@ -12,6 +13,31 @@ Item { property int columnIndex: 0 property int count: (flowMain.children.length - 1) + Component { + id: buttonComponent + TabletButton { } + } + + Component.onCompleted: { + tablet.populateButtons(); + } + + function createClickedHandler(proxy) { + return function() { proxy.clicked(); } + } + + function populateButtons() { + var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var buttons = tabletProxy.getButtons(); + for (var i = 0; i < buttons.length; i++) { + var proxy = buttons[i]; + var button = tablet.addButtonProxy(proxy.getProperties()); + button.clicked.connect(createClickedHandler(proxy)); + proxy.setQmlButton(button); + } + sortButtons(); + } + // used to look up a button by its uuid function findButtonIndex(uuid) { if (!uuid) { @@ -47,9 +73,7 @@ Item { // called by C++ code when a button should be added to the tablet function addButtonProxy(properties) { - var component = Qt.createComponent("TabletButton.qml"); - var button = component.createObject(flowMain); - + var button = buttonComponent.createObject(flowMain); // copy all properites to button var keys = Object.keys(properties).forEach(function (key) { button[key] = properties[key]; @@ -62,8 +86,6 @@ Item { button.tabletRoot = parent.parent; } - sortButtons(); - return button; } @@ -83,11 +105,8 @@ Item { anchors { top: parent.top - topMargin: 0 left: parent.left - leftMargin: 0 right: parent.right - rightMargin: 0 } gradient: Gradient { diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index a161741049..028ac2d8b6 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -68,18 +68,17 @@ Item { function loadSource(url) { tabletApps.clear(); - loader.source = ""; // make sure we load the qml fresh each time. - loader.source = url; - tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""}); + loader.load(url) + tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""}); } function loadQMLOnTop(url) { tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""}); - loader.source = ""; - loader.source = tabletApps.get(currentApp).appUrl; - if (loader.item.hasOwnProperty("gotoPreviousApp")) { - loader.item.gotoPreviousApp = true; - } + loader.load(tabletApps.get(currentApp).appUrl, function(){ + if (loader.item.hasOwnProperty("gotoPreviousApp")) { + loader.item.gotoPreviousApp = true; + } + }) } function loadWebOnTop(url, injectJavaScriptUrl) { @@ -92,13 +91,11 @@ Item { } function loadWebBase() { - loader.source = ""; - loader.source = "TabletWebView.qml"; + loader.load("hifi/tablet/TabletWebView.qml"); } function loadTabletWebBase() { - loader.source = ""; - loader.source = "./BlocksWebView.qml"; + loader.load("hifi/tablet/BlocksWebView.qml"); } function returnToPreviousApp() { @@ -110,7 +107,7 @@ Item { loadSource("TabletWebView.qml"); loadWebUrl(webUrl, scriptUrl); } else { - loader.source = tabletApps.get(currentApp).appUrl; + loader.load(tabletApps.get(currentApp).appUrl); } } @@ -173,47 +170,72 @@ Item { } } - Loader { - id: loader - objectName: "loader" - asynchronous: false - - width: parent.width - height: parent.height - - // Hook up callback for clara.io download from the marketplace. - Connections { - id: eventBridgeConnection - target: eventBridge - onWebEventReceived: { - if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") { - ApplicationInterface.addAssetToWorldFromURL(message.slice(18)); - } - } - } - - onLoaded: { - if (loader.item.hasOwnProperty("sendToScript")) { - loader.item.sendToScript.connect(tabletRoot.sendToScript); - } - if (loader.item.hasOwnProperty("setRootMenu")) { - loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu); - } - loader.item.forceActiveFocus(); - - if (openModal) { - openModal.canceled(); - openModal.destroy(); - openModal = null; - } - - if (openBrowser) { - openBrowser.destroy(); - openBrowser = null; + // Hook up callback for clara.io download from the marketplace. + Connections { + id: eventBridgeConnection + target: eventBridge + onWebEventReceived: { + if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") { + ApplicationInterface.addAssetToWorldFromURL(message.slice(18)); } } } + Item { + id: loader + objectName: "loader"; + anchors.fill: parent; + property string source: ""; + property var item: null; + signal loaded; + + onWidthChanged: { + if (loader.item) { + loader.item.width = loader.width; + } + } + + onHeightChanged: { + if (loader.item) { + loader.item.height = loader.height; + } + } + + function load(newSource, callback) { + loader.source = newSource; + loader.item = null; + QmlSurface.load(newSource, loader, function(newItem) { + loader.item = newItem; + loader.item.width = loader.width; + loader.item.height = loader.height; + loader.loaded(); + if (loader.item.hasOwnProperty("sendToScript")) { + loader.item.sendToScript.connect(tabletRoot.sendToScript); + } + if (loader.item.hasOwnProperty("setRootMenu")) { + loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu); + } + loader.item.forceActiveFocus(); + + if (openModal) { + openModal.canceled(); + openModal.destroy(); + openModal = null; + } + + if (openBrowser) { + openBrowser.destroy(); + openBrowser = null; + } + + if (callback) { + callback(); + } + }); + console.log("QQQ done calling QmlSurface.load") + } + } + width: 480 height: 706 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4f051697ad..8689b167c9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2214,6 +2214,16 @@ extern void setupPreferences(); void Application::initializeUi() { // Make sure all QML surfaces share the main thread GL context OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext()); + OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "qrc:///qml/OverlayWindowTest.qml" }, + [](QQmlContext* context) { + qDebug() << "Whitelist OverlayWindow worked"; + context->setContextProperty("OverlayWindowTestString", "TestWorked"); + }); + OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "qrc:///qml/hifi/audio/Audio.qml" }, + [](QQmlContext* context) { + qDebug() << "QQQ" << __FUNCTION__ << "Whitelist Audio worked"; + }); + AddressBarDialog::registerType(); ErrorDialog::registerType(); @@ -2230,10 +2240,9 @@ void Application::initializeUi() { auto surfaceContext = offscreenUi->getSurfaceContext(); offscreenUi->setProxyWindow(_window->windowHandle()); - offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); // OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to // support the window management and scripting proxies for VR use - offscreenUi->createDesktop(QString("qrc:///qml/hifi/Desktop.qml")); + offscreenUi->createDesktop(QString("hifi/Desktop.qml")); // FIXME either expose so that dialogs can set this themselves or // do better detection in the offscreen UI of what has focus @@ -7194,13 +7203,17 @@ void Application::updateDisplayMode() { } auto offscreenUi = DependencyManager::get(); + auto desktop = offscreenUi->getDesktop(); // Make the switch atomic from the perspective of other threads { std::unique_lock lock(_displayPluginLock); - // Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below. - bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool(); - offscreenUi->getDesktop()->setProperty("repositionLocked", true); + bool wasRepositionLocked = false; + if (desktop) { + // Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below. + wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool(); + offscreenUi->getDesktop()->setProperty("repositionLocked", true); + } if (_displayPlugin) { disconnect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); @@ -7246,7 +7259,6 @@ void Application::updateDisplayMode() { getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); _displayPlugin = newDisplayPlugin; connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection); - auto desktop = offscreenUi->getDesktop(); if (desktop) { desktop->setProperty("repositionLocked", wasRepositionLocked); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9df22ab08e..7025022c0a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -101,7 +101,7 @@ Menu::Menu() { auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J); connect(action, &QAction::triggered, [] { static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml"); - static const QUrl tabletUrl("../../hifi/dialogs/TabletRunningScripts.qml"); + static const QUrl tabletUrl("hifi/dialogs/TabletRunningScripts.qml"); static const QString name("RunningScripts"); qApp->showDialog(widgetUrl, tabletUrl, name); }); @@ -338,7 +338,7 @@ Menu::Menu() { connect(action, &QAction::triggered, [] { auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); auto hmd = DependencyManager::get(); - tablet->loadQMLSource("ControllerSettings.qml"); + tablet->loadQMLSource("hifi/tablet/ControllerSettings.qml"); if (!hmd->getShouldShowTablet()) { hmd->toggleShouldShowTablet(); diff --git a/interface/src/scripting/WalletScriptingInterface.cpp b/interface/src/scripting/WalletScriptingInterface.cpp index 99fdd5fbde..c866bac2b2 100644 --- a/interface/src/scripting/WalletScriptingInterface.cpp +++ b/interface/src/scripting/WalletScriptingInterface.cpp @@ -1,4 +1,4 @@ -// +// // WalletScriptingInterface.cpp // interface/src/scripting // @@ -23,7 +23,7 @@ void WalletScriptingInterface::refreshWalletStatus() { wallet->getWalletStatus(); } -static const QString CHECKOUT_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/checkout/Checkout.qml"; +static const QString CHECKOUT_QML_PATH = "hifi/commerce/checkout/Checkout.qml"; void WalletScriptingInterface::buy(const QString& name, const QString& id, const int& price, const QString& href) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "buy", Q_ARG(const QString&, name), Q_ARG(const QString&, id), Q_ARG(const int&, price), Q_ARG(const QString&, href)); diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index f216bb4edc..ff2d4868df 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -31,7 +31,7 @@ #include "scripting/HMDScriptingInterface.h" -static const QVariant TABLET_ADDRESS_DIALOG = "TabletAddressDialog.qml"; +static const QVariant TABLET_ADDRESS_DIALOG = "hifi/tablet/TabletAddressDialog.qml"; template void DialogsManager::maybeCreateDialog(QPointer& member) { if (!member) { @@ -91,7 +91,7 @@ void DialogsManager::setDomainConnectionFailureVisibility(bool visible) { ConnectionFailureDialog::hide(); } } else { - static const QUrl url("../../dialogs/TabletConnectionFailureDialog.qml"); + static const QUrl url("dialogs/TabletConnectionFailureDialog.qml"); auto hmd = DependencyManager::get(); if (visible) { tablet->initialScreen(url); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 7ce2a0146d..2e40d3c087 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -46,7 +46,7 @@ void LoginDialog::showWithSelection() if (tablet->getToolbarMode()) { LoginDialog::show(); } else { - static const QUrl url("../../dialogs/TabletLoginDialog.qml"); + static const QUrl url("dialogs/TabletLoginDialog.qml"); tablet->initialScreen(url); if (!hmd->getShouldShowTablet()) { hmd->openTablet(); diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index b5af529f2b..a8d0c3cc54 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -264,7 +264,7 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI } } -static const QString INSPECTION_CERTIFICATE_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml"; +static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml"; void ContextOverlayInterface::openInspectionCertificate() { // lets open the tablet to the inspection certificate QML if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) { diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index a2e574a829..d8e1fa7cf1 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -30,6 +30,8 @@ using namespace render; using namespace render::entities; +static const QString WEB_ENTITY_QML = "controls/WebEntityView.qml"; + const float METERS_TO_INCHES = 39.3701f; static uint32_t _currentWebCount{ 0 }; // Don't allow more than 100 concurrent web views @@ -218,6 +220,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { }; { + // FIXME use the surface cache instead of explicit creation _webSurface = QSharedPointer(new OffscreenQmlSurface(), deleter); _webSurface->create(); } @@ -289,7 +292,6 @@ void WebEntityRenderer::loadSourceURL() { if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" || _lastSourceUrl.toLower().endsWith(".htm") || _lastSourceUrl.toLower().endsWith(".html")) { _contentType = htmlContent; - _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "qml/controls/")); // We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS. if (sourceUrl.host().endsWith("youtube.com", Qt::CaseInsensitive)) { @@ -298,12 +300,11 @@ void WebEntityRenderer::loadSourceURL() { _webSurface->setMaxFps(DEFAULT_MAX_FPS); } - _webSurface->load("WebEntityView.qml", [this](QQmlContext* context, QObject* item) { + _webSurface->load("controls/WebEntityView.qml", [this](QQmlContext* context, QObject* item) { item->setProperty("url", _lastSourceUrl); }); } else { _contentType = qmlContent; - _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath())); _webSurface->load(_lastSourceUrl); if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") { auto tabletScriptingInterface = DependencyManager::get(); diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 14d8ec8985..1758150e0a 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -62,7 +62,7 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { QUrl url { properties[SOURCE_PROPERTY].toString() }; if (url.scheme() != "http" && url.scheme() != "https" && url.scheme() != "file" && url.scheme() != "about" && - url.scheme() != "atp") { + url.scheme() != "atp" && url.scheme() != "qrc") { properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url.toString()).toString(); } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index ecd07a5874..8711e52eff 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -47,6 +47,7 @@ #include "types/HFWebEngineProfile.h" #include "types/SoundEffect.h" +#include "TabletScriptingInterface.h" #include "Logging.h" Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml") @@ -98,7 +99,7 @@ void OffscreenQmlSurface::addWhitelistContextHandler(const std::initializer_list } -QmlContextCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QObject*) {}; +QmlContextObjectCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QQuickItem*) {}; struct TextureSet { // The number of surfaces with this size @@ -586,10 +587,11 @@ void OffscreenQmlSurface::create() { auto qmlEngine = acquireEngine(_quickWindow); _qmlContext = new QQmlContext(qmlEngine->rootContext()); - + _qmlContext->setBaseUrl(QUrl{ "qrc:///qml/" }); _qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow())); _qmlContext->setContextProperty("eventBridge", this); _qmlContext->setContextProperty("webEntity", this); + _qmlContext->setContextProperty("QmlSurface", this); // FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper // Find a way to flag older scripts using this mechanism and wanr that this is deprecated @@ -684,55 +686,69 @@ QQuickItem* OffscreenQmlSurface::getRootItem() { return _rootItem; } -void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) { - _qmlContext->setBaseUrl(baseUrl); +QQmlContext* OffscreenQmlSurface::contextForUrl(const QUrl& qmlSource, bool forceNewContext) { + // Get any whitelist functionality + QList callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource); + // If we have whitelisted content, we must load a new context + forceNewContext |= !callbacks.empty(); + + QQmlContext* targetContext = _qmlContext; + if (_rootItem && forceNewContext) { + targetContext = new QQmlContext(targetContext); + } + + for (const auto& callback : callbacks) { + callback(targetContext); + } + + return targetContext; } -void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback) { +void OffscreenQmlSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) { + loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) { + QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem)); + }); +} + +void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback) { + loadInternal(qmlSource, createNewContext, nullptr, onQmlLoadedCallback); +} + +void OffscreenQmlSurface::loadInternal(const QUrl& qmlSource, bool createNewContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback) { + qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << qmlSource; if (QThread::currentThread() != thread()) { qCWarning(uiLogging) << "Called load on a non-surface thread"; } // Synchronous loading may take a while; restart the deadlock timer QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection); - // Get any whitelist functionality - QList callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource); - // If we have whitelisted content, we must load a new context - createNewContext |= !callbacks.empty(); - callbacks.push_back(onQmlLoadedCallback); - - QQmlContext* targetContext = _qmlContext; - if (_rootItem && createNewContext) { - targetContext = new QQmlContext(targetContext); - } - - - // FIXME eliminate loading of relative file paths for QML QUrl finalQmlSource = qmlSource; if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) { finalQmlSource = _qmlContext->resolvedUrl(qmlSource); + qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << "resolved to " << finalQmlSource; } + auto targetContext = contextForUrl(finalQmlSource, createNewContext); auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); if (qmlComponent->isLoading()) { connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) { - finishQmlLoad(qmlComponent, targetContext, callbacks); + finishQmlLoad(qmlComponent, targetContext, parent, onQmlLoadedCallback); }); return; } - finishQmlLoad(qmlComponent, targetContext, callbacks); + finishQmlLoad(qmlComponent, targetContext, parent, onQmlLoadedCallback); } -void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) { +void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback) { load(qmlSource, true, onQmlLoadedCallback); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) { +void OffscreenQmlSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback) { load(qmlSource, false, onQmlLoadedCallback); } -void OffscreenQmlSurface::load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback) { +void OffscreenQmlSurface::load(const QString& qmlSourceFile, const QmlContextObjectCallback& onQmlLoadedCallback) { return load(QUrl(qmlSourceFile), onQmlLoadedCallback); } @@ -740,7 +756,8 @@ void OffscreenQmlSurface::clearCache() { _qmlContext->engine()->clearComponentCache(); } -void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList& callbacks) { + +void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, QQuickItem* parent, const QmlContextObjectCallback& callback) { disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { @@ -762,6 +779,22 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext return; } + if (!newObject) { + if (!_rootItem) { + qFatal("Could not load object as root item"); + return; + } + qCWarning(uiLogging) << "Unable to load QML item"; + return; + } + + QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); + if (qmlContext != _qmlContext && eventBridge && eventBridge != this) { + // FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper + // Find a way to flag older scripts using this mechanism and wanr that this is deprecated + qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(eventBridge, qmlContext)); + } + qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership); // All quick items should be focusable @@ -772,37 +805,26 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext newItem->setFlag(QQuickItem::ItemIsFocusScope, true); } + // Make sure we will call callback for this codepath // Call this before qmlComponent->completeCreate() otherwise ghost window appears - if (newItem && _rootItem) { - for (const auto& callback : callbacks) { - callback(qmlContext, newObject); - } - } + // If we already have a root, just set a couple of flags and the ancestry + if (_rootItem) { + callback(qmlContext, newItem); - QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); - if (qmlContext != _qmlContext && eventBridge && eventBridge != this) { - // FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper - // Find a way to flag older scripts using this mechanism and wanr that this is deprecated - qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(eventBridge, qmlContext)); + if (!parent) { + parent = _rootItem; + } + // Allow child windows to be destroyed from JS + QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership); + newObject->setParent(parent); + newItem->setParentItem(parent); } qmlComponent->completeCreate(); qmlComponent->deleteLater(); - // If we already have a root, just set a couple of flags and the ancestry - if (newItem && _rootItem) { - // Allow child windows to be destroyed from JS - QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership); - newObject->setParent(_rootItem); - if (newItem) { - newItem->setParentItem(_rootItem); - } - return; - } - - if (!newItem) { - qFatal("Could not load object as root item"); + if (_rootItem) { return; } @@ -813,10 +835,16 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext _rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setSize(_quickWindow->renderTargetSize()); - // Call this callback after rootitem is set, otherwise VrMenu wont work - for (const auto& callback : callbacks) { - callback(qmlContext, newObject); + if (_rootItem->objectName() == "tabletRoot") { + _qmlContext->setContextProperty("tabletRoot", QVariant::fromValue(_rootItem)); + auto tabletScriptingInterface = DependencyManager::get(); + tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", this); + QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"); + _qmlContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership); } + + // Call this callback after rootitem is set, otherwise VrMenu wont work + callback(qmlContext, newItem); } void OffscreenQmlSurface::updateQuick() { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 12ee9e59a1..2d2eb0811b 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -30,12 +30,14 @@ class QQmlContext; class QQmlComponent; class QQuickWindow; class QQuickItem; +class QJSValue; // GPU resources are typically buffered for one copy being used by the renderer, // one copy in flight, and one copy being used by the receiver #define GPU_RESOURCE_BUFFER_SIZE 3 -using QmlContextCallback = std::function; +using QmlContextCallback = std::function; +using QmlContextObjectCallback = std::function; class OffscreenQmlSurface : public QObject { Q_OBJECT @@ -43,7 +45,7 @@ class OffscreenQmlSurface : public QObject { public: static void setSharedContext(QOpenGLContext* context); - static QmlContextCallback DEFAULT_CONTEXT_CALLBACK; + static QmlContextObjectCallback DEFAULT_CONTEXT_CALLBACK; static void addWhitelistContextHandler(const std::initializer_list& urls, const QmlContextCallback& callback); static void addWhitelistContextHandler(const QUrl& url, const QmlContextCallback& callback) { addWhitelistContextHandler({ { url } }, callback); }; @@ -56,10 +58,15 @@ public: void resize(const QSize& size, bool forceResize = false); QSize size() const; - Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); - Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); - Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); - Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + // Usable from QML code as QmlSurface.load(url, parent, function(newItem){ ... }) + Q_INVOKABLE void load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback); + + // For C++ use + Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + void clearCache(); void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; } // Optional values for event handling @@ -73,7 +80,6 @@ public: void resume(); bool isPaused() const; - void setBaseUrl(const QUrl& baseUrl); QQuickItem* getRootItem(); QQuickWindow* getWindow(); QObject* getEventHandler(); @@ -124,13 +130,13 @@ protected: private: static QOpenGLContext* getSharedContext(); - void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList& callbacks); + QQmlContext* contextForUrl(const QUrl& url, bool forceNewContext = false); + void loadInternal(const QUrl& qmlSource, bool createNewContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback); + void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); - void setupFbo(); bool allowNewFrame(uint8_t fps); void render(); void cleanup(); - QJsonObject getGLContextData(); private slots: void updateQuick(); diff --git a/libraries/ui/src/ui/OffscreenQmlSurfaceCache.cpp b/libraries/ui/src/ui/OffscreenQmlSurfaceCache.cpp index 2a0ca4a2e9..9b6b031dd9 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurfaceCache.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurfaceCache.cpp @@ -45,7 +45,6 @@ void OffscreenQmlSurfaceCache::release(const QString& rootSource, const QSharedP QSharedPointer OffscreenQmlSurfaceCache::buildSurface(const QString& rootSource) { auto surface = QSharedPointer(new OffscreenQmlSurface()); surface->create(); - surface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); surface->load(rootSource); surface->resize(QSize(100, 100)); return surface; diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index b9da230715..a261ae45b1 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -210,9 +210,9 @@ QObject* TabletScriptingInterface::getFlags() { // TabletProxy // -static const char* TABLET_SOURCE_URL = "Tablet.qml"; -static const char* WEB_VIEW_SOURCE_URL = "TabletWebView.qml"; -static const char* VRMENU_SOURCE_URL = "TabletMenu.qml"; +static const char* TABLET_SOURCE_URL = "hifi/tablet/Tablet.qml"; +static const char* WEB_VIEW_SOURCE_URL = "hifi/tablet/TabletWebView.qml"; +static const char* VRMENU_SOURCE_URL = "hifi/tablet/TabletMenu.qml"; class TabletRootWindow : public QmlWindowClass { virtual QString qmlSource() const override { return "hifi/tablet/WindowRoot.qml"; } @@ -232,6 +232,15 @@ TabletProxy::~TabletProxy() { disconnect(this, &TabletProxy::tabletShownChanged, this, &TabletProxy::onTabletShown); } +QVariant TabletProxy::getButtons() { + Q_ASSERT(QThread::currentThread() == qApp->thread()); + QVariantList result; + for (const auto& button : _tabletButtonProxies) { + result.push_back(QVariant::fromValue(button.data())); + } + return result; +} + void TabletProxy::setToolbarMode(bool toolbarMode) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setToolbarMode", Q_ARG(bool, toolbarMode)); @@ -247,7 +256,6 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { auto offscreenUi = DependencyManager::get(); if (toolbarMode) { - removeButtonsFromHomeScreen(); addButtonsToToolbar(); // create new desktop window @@ -267,7 +275,7 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { removeButtonsFromToolbar(); if (_currentPathLoaded == TABLET_SOURCE_URL) { - addButtonsToHomeScreen(); + // Tablet QML now pulls buttons from Tablet proxy } else { loadHomeScreen(true); } @@ -284,18 +292,20 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { } } +#if 0 static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* buttonProxy) { Q_ASSERT(QThread::currentThread() == qApp->thread()); if (buttonProxy == NULL){ - qCCritical(uiLogging) << "TabletScriptingInterface addButtonProxyToQmlTablet buttonProxy is NULL"; + qCCritical(uiLogging) << __FUNCTION__ << "buttonProxy is NULL"; return; } QVariant resultVar; + qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << "adding button " << buttonProxy; bool hasResult = QMetaObject::invokeMethod(qmlTablet, "addButtonProxy", Qt::DirectConnection, Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, buttonProxy->getProperties())); if (!hasResult) { - qCWarning(uiLogging) << "TabletScriptingInterface addButtonProxyToQmlTablet has no result"; + qCWarning(uiLogging) << __FUNCTION__ << " has no result"; return; } @@ -307,6 +317,8 @@ static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* QObject::connect(qmlButton, SIGNAL(clicked()), buttonProxy, SLOT(clickedSlot())); buttonProxy->setQmlButton(qobject_cast(qmlButton)); } +#endif + static QString getUsername() { QString username = "Unknown user"; @@ -362,7 +374,7 @@ void TabletProxy::onTabletShown() { static_cast(parent())->playSound(TabletScriptingInterface::TabletOpen); if (_showRunningScripts) { _showRunningScripts = false; - pushOntoStack("../../hifi/dialogs/TabletRunningScripts.qml"); + pushOntoStack("hifi/dialogs/TabletRunningScripts.qml"); } } } @@ -396,9 +408,6 @@ void TabletProxy::setQmlTabletRoot(OffscreenQmlSurface* qmlOffscreenSurface) { }); if (_toolbarMode) { - // if someone creates the tablet in toolbar mode, make sure to display the home screen on the tablet. - auto loader = _qmlTabletRoot->findChild("loader"); - QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen())); QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL))); } @@ -427,7 +436,6 @@ void TabletProxy::setQmlTabletRoot(OffscreenQmlSurface* qmlOffscreenSurface) { QMetaObject::invokeMethod(_qmlTabletRoot, "setShown", Q_ARG(const QVariant&, QVariant(true))); } } else { - removeButtonsFromHomeScreen(); _state = State::Uninitialized; emit screenChanged(QVariant("Closed"), QVariant("")); _currentPathLoaded = ""; @@ -456,7 +464,6 @@ void TabletProxy::gotoMenuScreen(const QString& submenu) { } if (root) { - removeButtonsFromHomeScreen(); auto offscreenUi = DependencyManager::get(); QObject* menu = offscreenUi->getRootMenu(); QMetaObject::invokeMethod(root, "setMenuProperties", Q_ARG(QVariant, QVariant::fromValue(menu)), Q_ARG(const QVariant&, QVariant(submenu))); @@ -530,7 +537,6 @@ void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) { } if (root) { - removeButtonsFromHomeScreen(); //works only in Tablet QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path)); _state = State::QML; if (path != _currentPathLoaded) { @@ -612,8 +618,6 @@ void TabletProxy::loadHomeScreen(bool forceOntoHomeScreen) { if ((_state != State::Home && _state != State::Uninitialized) || forceOntoHomeScreen) { if (!_toolbarMode && _qmlTabletRoot) { - auto loader = _qmlTabletRoot->findChild("loader"); - QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen())); QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL))); QMetaObject::invokeMethod(_qmlTabletRoot, "playButtonClickSound"); } else if (_toolbarMode && _desktopWindow) { @@ -674,7 +678,6 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS } if (root) { - removeButtonsFromHomeScreen(); if (loadOtherBase) { QMetaObject::invokeMethod(root, "loadTabletWebBase"); } else { @@ -701,12 +704,8 @@ TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { auto tabletButtonProxy = QSharedPointer(new TabletButtonProxy(properties.toMap())); _tabletButtonProxies.push_back(tabletButtonProxy); if (!_toolbarMode && _qmlTabletRoot) { - auto tablet = getQmlTablet(); - if (tablet) { - addButtonProxyToQmlTablet(tablet, tabletButtonProxy.data()); - } else { - qCCritical(uiLogging) << "Could not find tablet in TabletRoot.qml"; - } + // Tablet now pulls buttons from the tablet proxy + // FIXME emit a signal so that the tablet can refresh buttons if they change } else if (_toolbarMode) { auto toolbarProxy = DependencyManager::get()->getSystemToolbarProxy(); if (toolbarProxy) { @@ -791,31 +790,11 @@ void TabletProxy::sendToQml(const QVariant& msg) { } } -void TabletProxy::addButtonsToHomeScreen() { - auto tablet = getQmlTablet(); - if (!tablet || _toolbarMode) { - return; - } - for (auto& buttonProxy : _tabletButtonProxies) { - addButtonProxyToQmlTablet(tablet, buttonProxy.data()); - } - auto loader = _qmlTabletRoot->findChild("loader"); - QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen())); -} OffscreenQmlSurface* TabletProxy::getTabletSurface() { return _qmlOffscreenSurface; } -void TabletProxy::removeButtonsFromHomeScreen() { - auto tablet = getQmlTablet(); - for (auto& buttonProxy : _tabletButtonProxies) { - if (tablet) { - QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getProperties())); - } - buttonProxy->setQmlButton(nullptr); - } -} void TabletProxy::desktopWindowClosed() { gotoHomeScreen(); diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index bd195fdd20..e7dc5ede1f 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -196,6 +196,8 @@ public: Q_INVOKABLE bool isPathLoaded(const QVariant& path); + Q_INVOKABLE QVariant getButtons(); + QQuickItem* getTabletRoot() const { return _qmlTabletRoot; } OffscreenQmlSurface* getTabletSurface(); @@ -237,12 +239,10 @@ signals: void tabletShownChanged(); protected slots: - void addButtonsToHomeScreen(); void desktopWindowClosed(); void emitWebEvent(const QVariant& msg); void onTabletShown(); protected: - void removeButtonsFromHomeScreen(); void loadHomeScreen(bool forceOntoHomeScreen); void addButtonsToToolbar(); void removeButtonsFromToolbar(); @@ -277,7 +277,9 @@ public: TabletButtonProxy(const QVariantMap& properties); ~TabletButtonProxy(); - void setQmlButton(QQuickItem* qmlButton); + + Q_INVOKABLE void setQmlButton(QQuickItem* qmlButton); + void setToolbarButtonProxy(QObject* toolbarButtonProxy); QUuid getUuid() const { return _uuid; } diff --git a/scripts/developer/inputRecording.js b/scripts/developer/inputRecording.js index 85bda623b3..6fb8e471cd 100644 --- a/scripts/developer/inputRecording.js +++ b/scripts/developer/inputRecording.js @@ -19,7 +19,7 @@ tablet.gotoHomeScreen(); onRecordingScreen = false; } else { - tablet.loadQMLSource("InputRecorder.qml"); + tablet.loadQMLSource("hifi/tablet/InputRecorder.qml"); onRecordingScreen = true; } } diff --git a/scripts/developer/tests/qmlTest.js b/scripts/developer/tests/qmlTest.js index c891b6a1b7..0eaabac6d1 100644 --- a/scripts/developer/tests/qmlTest.js +++ b/scripts/developer/tests/qmlTest.js @@ -1,7 +1,7 @@ print("Launching web window"); qmlWindow = new OverlayWindow({ title: 'Test Qml', - source: "https://s3.amazonaws.com/DreamingContent/qml/content.qml", + source: "qrc:///qml/OverlayWindowTest.qml", height: 240, width: 320, toolWindow: false, diff --git a/scripts/system/audio.js b/scripts/system/audio.js index 0a3471fa81..a93177ca38 100644 --- a/scripts/system/audio.js +++ b/scripts/system/audio.js @@ -15,7 +15,7 @@ var TABLET_BUTTON_NAME = "AUDIO"; var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; -var AUDIO_QML_SOURCE = "../audio/Audio.qml"; +var AUDIO_QML_SOURCE = "hifi/audio/Audio.qml"; var MUTE_ICONS = { icon: "icons/tablet-icons/mic-mute-i.svg", diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 8e4a3215fd..9b2367b762 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -26,8 +26,8 @@ // Relevant Variables: // -WALLET_QML_SOURCE: The path to the Wallet QML // -onWalletScreen: true/false depending on whether we're looking at the app. - var WALLET_QML_SOURCE = Script.resourcesPath() + "qml/hifi/commerce/wallet/Wallet.qml"; - var MARKETPLACE_PURCHASES_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/purchases/Purchases.qml"; + var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml"; + var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml"; var onWalletScreen = false; function onButtonClicked() { if (!tablet) { diff --git a/scripts/system/edit.js b/scripts/system/edit.js index e76a02b6f5..07551f31e5 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -656,7 +656,7 @@ var toolBar = (function () { selectionDisplay.triggerMapping.disable(); tablet.landscape = false; } else { - tablet.loadQMLSource("Edit.qml", true); + tablet.loadQMLSource("hifi/tablet/Edit.qml", true); UserActivityLogger.enabledEdit(); entityListTool.setVisible(true); gridTool.setVisible(true); diff --git a/scripts/system/generalSettings.js b/scripts/system/generalSettings.js index 7d97f13757..082528ffc5 100644 --- a/scripts/system/generalSettings.js +++ b/scripts/system/generalSettings.js @@ -18,7 +18,7 @@ var buttonName = "Settings"; var toolBar = null; var tablet = null; - var settings = "TabletGeneralPreferences.qml" + var settings = "hifi/tablet/TabletGeneralPreferences.qml" function onClicked(){ if (tablet) { tablet.loadQMLSource(settings); diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index f0044084f6..b427739292 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -346,7 +346,7 @@ Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled); break; case 'purchases_openGoTo': - tablet.loadQMLSource("TabletAddressDialog.qml"); + tablet.loadQMLSource("hifi/tablet/TabletAddressDialog.qml"); break; case 'purchases_itemCertificateClicked': setCertificateInfo("", message.itemCertificateId); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 44ff7c2acd..05a7dc8975 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -40,7 +40,7 @@ var HOVER_TEXTURES = { var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6}; var SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29}; var HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now -var PAL_QML_SOURCE = "../Pal.qml"; +var PAL_QML_SOURCE = "hifi/Pal.qml"; var conserveResources = true; Script.include("/~/system/libraries/controllers.js"); diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 929c6e0e5c..2a0e827932 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -24,7 +24,7 @@ print('tablet-goto.js:', [].map.call(arguments, JSON.stringify)); } - var gotoQmlSource = "TabletAddressDialog.qml"; + var gotoQmlSource = "hifi/tablet/TabletAddressDialog.qml"; var buttonName = "GOTO"; var onGotoScreen = false; var shouldActivateButton = false; diff --git a/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js b/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js index e7a135ec9e..7bc65722cd 100644 --- a/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js +++ b/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js @@ -24,7 +24,7 @@ if (onSkyboxChangerScreen) { tablet.gotoHomeScreen(); } else { - tablet.loadQMLSource("../SkyboxChanger.qml"); + tablet.loadQMLSource("hifi/SkyboxChanger.qml"); } } diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js index f0b943ad92..76044d2975 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js @@ -390,7 +390,7 @@ // Relevant Variables: // -SPECTATOR_CAMERA_QML_SOURCE: The path to the SpectatorCamera QML // -onSpectatorCameraScreen: true/false depending on whether we're looking at the spectator camera app. - var SPECTATOR_CAMERA_QML_SOURCE = Script.resourcesPath() + "qml/hifi/SpectatorCamera.qml"; + var SPECTATOR_CAMERA_QML_SOURCE = "hifi/SpectatorCamera.qml"; var onSpectatorCameraScreen = false; function onTabletButtonClicked() { if (!tablet) { From 2cd76be6c487de87bbdfa58fdf54e1d653311fba Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 6 Nov 2017 10:31:32 -0800 Subject: [PATCH 008/102] Fix encoding for wallet scripting interface --- interface/src/scripting/WalletScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/WalletScriptingInterface.cpp b/interface/src/scripting/WalletScriptingInterface.cpp index c866bac2b2..55d53000b7 100644 --- a/interface/src/scripting/WalletScriptingInterface.cpp +++ b/interface/src/scripting/WalletScriptingInterface.cpp @@ -1,4 +1,4 @@ -// +// // WalletScriptingInterface.cpp // interface/src/scripting // From 803e5d143d2e5bb638ffc31ff93db6368d8fa480 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Tue, 7 Nov 2017 11:48:46 -0800 Subject: [PATCH 009/102] Moved Haze pass to be before transparency pass. --- libraries/render-utils/src/RenderDeferredTask.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 6a3b560167..0f095900be 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -159,6 +159,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job task.addJob("DrawBackgroundDeferred", lightingModel); + const auto drawHazeInputs = render::Varying(DrawHaze::Inputs(hazeModel, lightingFramebuffer, linearDepthTarget, deferredFrameTransform, lightingFramebuffer)); + task.addJob("DrawHazeDeferred", drawHazeInputs); + // Render transparent objects forward in LightingBuffer const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying(); task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); @@ -169,9 +172,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DebugLightClusters", debugLightClustersInputs); } - const auto drawHazeInputs = render::Varying(DrawHaze::Inputs(hazeModel, lightingFramebuffer, linearDepthTarget, deferredFrameTransform, lightingFramebuffer)); - task.addJob("DrawHaze", drawHazeInputs); - const auto toneAndPostRangeTimer = task.addJob("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing"); // Lighting Buffer ready for tone mapping From b7f31eb5b9cabf53c205178895aed8bb50ba48b0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 7 Nov 2017 12:42:26 -0800 Subject: [PATCH 010/102] Fixing desktop QML loading, tablet clickthrough bugs --- .../resources/qml/hifi/tablet/TabletRoot.qml | 13 ++- .../resources/qml/hifi/tablet/WindowRoot.qml | 82 +++++++++++++------ 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index 028ac2d8b6..6eb8e59ed1 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -202,8 +202,16 @@ Item { } function load(newSource, callback) { - loader.source = newSource; - loader.item = null; + if (loader.source == newSource) { + loader.loaded(); + return; + } + + if (loader.item) { + loader.item.destroy(); + loader.item = null; + } + QmlSurface.load(newSource, loader, function(newItem) { loader.item = newItem; loader.item.width = loader.width; @@ -232,7 +240,6 @@ Item { callback(); } }); - console.log("QQQ done calling QmlSurface.load") } } diff --git a/interface/resources/qml/hifi/tablet/WindowRoot.qml b/interface/resources/qml/hifi/tablet/WindowRoot.qml index e3170f85ef..baf2fa05c2 100644 --- a/interface/resources/qml/hifi/tablet/WindowRoot.qml +++ b/interface/resources/qml/hifi/tablet/WindowRoot.qml @@ -59,18 +59,15 @@ Windows.ScrollingWindow { } function loadSource(url) { - loader.source = ""; // make sure we load the qml fresh each time. - loader.source = url; + loader.load(url) } function loadWebBase() { - loader.source = ""; - loader.source = "WindowWebView.qml"; + loader.load("hifi/tablet/TabletWebView.qml"); } function loadTabletWebBase() { - loader.source = ""; - loader.source = "./BlocksWebView.qml"; + loader.load("hifi/tablet/BlocksWebView.qml"); } function loadWebUrl(url, injectedJavaScriptUrl) { @@ -111,38 +108,73 @@ Windows.ScrollingWindow { username = newUsername; } - Loader { + // Hook up callback for clara.io download from the marketplace. + Connections { + id: eventBridgeConnection + target: eventBridge + onWebEventReceived: { + if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") { + ApplicationInterface.addAssetToWorldFromURL(message.slice(18)); + } + } + } + + Item { id: loader - objectName: "loader" - asynchronous: false + objectName: "loader"; + property string source: ""; + property var item: null; height: pane.scrollHeight width: pane.contentWidth anchors.left: parent.left anchors.top: parent.top - - // Hook up callback for clara.io download from the marketplace. - Connections { - id: eventBridgeConnection - target: eventBridge - onWebEventReceived: { - if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") { - ApplicationInterface.addAssetToWorldFromURL(message.slice(18)); - } + signal loaded; + + onWidthChanged: { + if (loader.item) { + loader.item.width = loader.width; } } + + onHeightChanged: { + if (loader.item) { + loader.item.height = loader.height; + } + } + + function load(newSource, callback) { + if (loader.source == newSource) { + loader.loaded(); + return; + } - onLoaded: { - if (loader.item.hasOwnProperty("sendToScript")) { - loader.item.sendToScript.connect(tabletRoot.sendToScript); + if (loader.item) { + loader.item.destroy(); + loader.item = null; } - if (loader.item.hasOwnProperty("setRootMenu")) { - loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu); - } - loader.item.forceActiveFocus(); + + QmlSurface.load(newSource, loader, function(newItem) { + loader.item = newItem; + loader.item.width = loader.width; + loader.item.height = loader.height; + loader.loaded(); + if (loader.item.hasOwnProperty("sendToScript")) { + loader.item.sendToScript.connect(tabletRoot.sendToScript); + } + if (loader.item.hasOwnProperty("setRootMenu")) { + loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu); + } + loader.item.forceActiveFocus(); + + if (callback) { + callback(); + } + }); } } + implicitWidth: 480 implicitHeight: 706 } From 87aee7242aa1957d80ba2bfd606e72046c32fdb0 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Tue, 7 Nov 2017 15:25:42 -0800 Subject: [PATCH 011/102] Moved linearDepthMap into Haze.slf Refactored computation of keylight attenuation - now function in Haze.slh --- .../render-utils/src/DeferredGlobalLight.slh | 50 ++----------------- libraries/render-utils/src/Haze.slf | 1 + libraries/render-utils/src/Haze.slh | 43 +++++++++++++++- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index f70daf1e77..881de119b0 100644 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -123,6 +123,9 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu color += ambientSpecular; // Directional + // Get directional light (used by both directional light and haze attenuation) + Light directionalLight = getLight(); + vec3 directionalDiffuse; vec3 directionalSpecular; evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation @@ -135,52 +138,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu // Attenuate the light if haze effect selected if ((hazeParams.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) { - // Directional light attenuation is simulated by assuming the light source is at a fixed height above the - // fragment. This height is where the haze density is reduced by 95% from the haze at the fragment's height - // - // The distance is computed from the height and the directional light orientation - // The distance is limited to height * 1,000, which gives an angle of ~0.057 degrees - - // Get directional light - Light light = getLight(); - vec3 lightDirection = getLightDirection(light); - - // Height at which haze density is reduced by 95% (default set to 2000.0 for safety ,this should never happen) - float height_95p = 2000.0; - if (hazeParams.hazeKeyLightAltitudeFactor > 0.0f) { - height_95p = -log(0.05) / hazeParams.hazeKeyLightAltitudeFactor; - } - - // Note that the sine will always be positive - float sin_pitch = sqrt(1.0 - lightDirection.y * lightDirection.y); - - float distance; - const float minimumSinPitch = 0.001; - if (sin_pitch < minimumSinPitch) { - distance = height_95p / minimumSinPitch; - } else { - distance = height_95p / sin_pitch; - } - - // Position of fragment in world coordinates - vec4 worldFragPos = invViewMat * vec4(position, 0.0); - - // Integration is from the fragment towards the light source - // Note that the haze base reference affects only the haze density as function of altitude - float hazeDensityDistribution = - hazeParams.hazeKeyLightRangeFactor * - exp(-hazeParams.hazeKeyLightAltitudeFactor * (worldFragPos.y - hazeParams.hazeBaseReference)); - - float hazeIntegral = hazeDensityDistribution * distance; - - // Note that t is constant and equal to -log(0.05) - // float t = hazeParams.hazeAltitudeFactor * height_95p; - // hazeIntegral *= (1.0 - exp (-t)) / t; - hazeIntegral *= 0.3171178; - - float hazeAmount = 1.0 - exp(-hazeIntegral); - - color = mix(color, vec3(0.0, 0.0, 0.0), hazeAmount); + color = computeHazeColor(color, directionalLight, invViewMat, position); } return color; diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index b366e6d639..79cca8b17b 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -23,6 +23,7 @@ <@include Haze.slh@> uniform sampler2D colorMap; +uniform sampler2D linearDepthMap; vec4 unpackPositionFromZeye(vec2 texcoord) { float Zeye = -texture(linearDepthMap, texcoord).x; diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index de7f0ac246..ea72b305c2 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -40,7 +40,48 @@ layout(std140) uniform hazeBuffer { HazeParams hazeParams; }; -uniform sampler2D linearDepthMap; +vec3 computeHazeColor(vec3 color, Light directionalLight, mat4 invViewMat, vec3 worldFragPos) { + // Directional light attenuation is simulated by assuming the light source is at a fixed height above the + // fragment. This height is where the haze density is reduced by 95% from the haze at the fragment's height + // + // The distance is computed from the height and the directional light orientation + // The distance is limited to height * 1,000, which gives an angle of ~0.057 degrees + vec3 lightDirection = getLightDirection(directionalLight); + // Height at which haze density is reduced by 95% (default set to 2000.0 for safety ,this should never happen) + float height_95p = 2000.0; + const float log_p_005 = log(0.05); + if (hazeParams.hazeKeyLightAltitudeFactor > 0.0f) { + height_95p = -log_p_005 / hazeParams.hazeKeyLightAltitudeFactor; + } + + // Note that we need the sine to be positive + float sin_pitch = abs(lightDirection.y); + + float distance; + const float minimumSinPitch = 0.001; + if (sin_pitch < minimumSinPitch) { + distance = height_95p / minimumSinPitch; + } else { + distance = height_95p / sin_pitch; + } + + // Integration is from the fragment towards the light source + // Note that the haze base reference affects only the haze density as function of altitude + float hazeDensityDistribution = + hazeParams.hazeKeyLightRangeFactor * + exp(-hazeParams.hazeKeyLightAltitudeFactor * (worldFragPos.y - hazeParams.hazeBaseReference)); + + float hazeIntegral = hazeDensityDistribution * distance; + + // Note that t is constant and equal to -log(0.05) + // float t = hazeParams.hazeAltitudeFactor * height_95p; + // hazeIntegral *= (1.0 - exp (-t)) / t; + hazeIntegral *= 0.3171178; + + float hazeAmount = 1.0 - exp(-hazeIntegral); + + return mix(color, vec3(0.0, 0.0, 0.0), hazeAmount); +} <@endif@> From ee6a8510c6c8cda61b506fac9619f52ace116690 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Tue, 7 Nov 2017 17:22:57 -0800 Subject: [PATCH 012/102] Refactored haze computation. --- .../render-utils/src/DeferredGlobalLight.slh | 2 +- libraries/render-utils/src/Haze.slf | 99 +------------------ libraries/render-utils/src/Haze.slh | 99 ++++++++++++++++++- 3 files changed, 102 insertions(+), 98 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 881de119b0..67a45e6ddf 100644 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -138,7 +138,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu // Attenuate the light if haze effect selected if ((hazeParams.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) { - color = computeHazeColor(color, directionalLight, invViewMat, position); + color = computeHazeColorKeyLightAttenuation(color, directionalLight, invViewMat, position); } return color; diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index 79cca8b17b..18deb9c891 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -46,104 +46,11 @@ void main(void) { discard; } - // Distance to fragment - vec4 eyeFragPos = unpackPositionFromZeye(varTexCoord0); - float distance = length(eyeFragPos.xyz); - vec4 fragColor = texture(colorMap, varTexCoord0); - vec4 hazeColor = vec4(hazeParams.hazeColor, 1.0); - - // Directional light component is a function of the angle from the eye, between the fragment and the sun - DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); + vec4 eyeFragPos = unpackPositionFromZeye(varTexCoord0); vec4 worldFragPos = getViewInverse() * eyeFragPos; - vec3 eyeFragDir = normalize(worldFragPos.xyz); + vec3 worldEyePos = getViewInverse()[3].xyz; - Light light = getLight(); - vec3 lightDirection = getLightDirection(light); - - float glareComponent = max(0.0, dot(eyeFragDir, -lightDirection)); - float power = min(1.0, pow(glareComponent, hazeParams.hazeGlareBlend)); - - vec4 glareColor = vec4(hazeParams.hazeGlareColor, 1.0); - - // Use the haze colour for the glare colour, if blend is not enabled - vec4 blendedHazeColor; - if ((hazeParams.hazeMode & HAZE_MODE_IS_ENABLE_LIGHT_BLEND) == HAZE_MODE_IS_ENABLE_LIGHT_BLEND) { - blendedHazeColor = mix(hazeColor, glareColor, power); - } else { - blendedHazeColor = hazeColor; - } - - vec4 potentialFragColor; - - if ((hazeParams.hazeMode & HAZE_MODE_IS_MODULATE_COLOR) == HAZE_MODE_IS_MODULATE_COLOR) { - // Compute separately for each colour - // Haze is based on both range and altitude - // Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt - - // The eyepoint position is in the last column of the matrix - vec3 worldEyePos = getViewInverse()[3].xyz; - - // Note that the haze base reference affects only the haze density as function of altitude - vec3 hazeDensityDistribution = - hazeParams.colorModulationFactor * - exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference)); - - vec3 hazeIntegral = hazeDensityDistribution * distance; - - const float slopeThreshold = 0.01; - float deltaHeight = worldFragPos.y - worldEyePos.y; - if (abs(deltaHeight) > slopeThreshold) { - float t = hazeParams.hazeHeightFactor * deltaHeight; - hazeIntegral *= (1.0 - exp (-t)) / t; - } - - vec3 hazeAmount = 1.0 - exp(-hazeIntegral); - - // Compute color after haze effect - potentialFragColor = mix(fragColor, vec4(1.0, 1.0, 1.0, 1.0), vec4(hazeAmount, 1.0)); - } else if ((hazeParams.hazeMode & HAZE_MODE_IS_ALTITUDE_BASED) != HAZE_MODE_IS_ALTITUDE_BASED) { - // Haze is based only on range - float hazeAmount = 1.0 - exp(-distance * hazeParams.hazeRangeFactor); - - // Compute color after haze effect - potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount); - } else { - // Haze is based on both range and altitude - // Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt - - // The eyepoint position is in the last column of the matrix - vec3 worldEyePos = getViewInverse()[3].xyz; - - // Note that the haze base reference affects only the haze density as function of altitude - float hazeDensityDistribution = - hazeParams.hazeRangeFactor * - exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference)); - - float hazeIntegral = hazeDensityDistribution * distance; - - const float slopeThreshold = 0.01; - float deltaHeight = worldFragPos.y - worldEyePos.y; - if (abs(deltaHeight) > slopeThreshold) { - float t = hazeParams.hazeHeightFactor * deltaHeight; - // Protect from wild values - if (abs(t) > 0.0000001) { - hazeIntegral *= (1.0 - exp (-t)) / t; - } - } - - float hazeAmount = 1.0 - exp(-hazeIntegral); - - // Compute color after haze effect - potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount); - } - - // Mix with background at far range - const float BLEND_DISTANCE = 27000.0; - if (distance > BLEND_DISTANCE) { - outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlend); - } else { - outFragColor = potentialFragColor; - } + outFragColor = computeHazeColor(fragColor, eyeFragPos, worldFragPos, worldEyePos); } diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index ea72b305c2..0633802c84 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -40,7 +40,7 @@ layout(std140) uniform hazeBuffer { HazeParams hazeParams; }; -vec3 computeHazeColor(vec3 color, Light directionalLight, mat4 invViewMat, vec3 worldFragPos) { +vec3 computeHazeColorKeyLightAttenuation(vec3 color, Light directionalLight, mat4 invViewMat, vec3 worldFragPos) { // Directional light attenuation is simulated by assuming the light source is at a fixed height above the // fragment. This height is where the haze density is reduced by 95% from the haze at the fragment's height // @@ -83,5 +83,102 @@ vec3 computeHazeColor(vec3 color, Light directionalLight, mat4 invViewMat, vec3 return mix(color, vec3(0.0, 0.0, 0.0), hazeAmount); } + +vec4 computeHazeColor(vec4 fragColor, vec4 eyeFragPos, vec4 worldFragPos, vec3 worldEyePos) { + // Distance to fragment + float distance = length(eyeFragPos.xyz); + + // Convert haze colour from uniform into a vec4 + vec4 hazeColor = vec4(hazeParams.hazeColor, 1.0); + + // Directional light component is a function of the angle from the eye, between the fragment and the sun + vec3 eyeFragDir = normalize(worldFragPos.xyz); + + Light light = getLight(); + vec3 lightDirection = getLightDirection(light); + + float glareComponent = max(0.0, dot(eyeFragDir, -lightDirection)); + float power = min(1.0, pow(glareComponent, hazeParams.hazeGlareBlend)); + + vec4 glareColor = vec4(hazeParams.hazeGlareColor, 1.0); + + // Use the haze colour for the glare colour, if blend is not enabled + vec4 blendedHazeColor; + if ((hazeParams.hazeMode & HAZE_MODE_IS_ENABLE_LIGHT_BLEND) == HAZE_MODE_IS_ENABLE_LIGHT_BLEND) { + blendedHazeColor = mix(hazeColor, glareColor, power); + } else { + blendedHazeColor = hazeColor; + } + + vec4 potentialFragColor; + + if ((hazeParams.hazeMode & HAZE_MODE_IS_MODULATE_COLOR) == HAZE_MODE_IS_MODULATE_COLOR) { + // Compute separately for each colour + // Haze is based on both range and altitude + // Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt + + // Note that the haze base reference affects only the haze density as function of altitude + vec3 hazeDensityDistribution = + hazeParams.colorModulationFactor * + exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference)); + + vec3 hazeIntegral = hazeDensityDistribution * distance; + + const float slopeThreshold = 0.01; + float deltaHeight = worldFragPos.y - worldEyePos.y; + if (abs(deltaHeight) > slopeThreshold) { + float t = hazeParams.hazeHeightFactor * deltaHeight; + hazeIntegral *= (1.0 - exp (-t)) / t; + } + + vec3 hazeAmount = 1.0 - exp(-hazeIntegral); + + // Compute color after haze effect + potentialFragColor = mix(fragColor, vec4(1.0, 1.0, 1.0, 1.0), vec4(hazeAmount, 1.0)); + } else if ((hazeParams.hazeMode & HAZE_MODE_IS_ALTITUDE_BASED) != HAZE_MODE_IS_ALTITUDE_BASED) { + // Haze is based only on range + float hazeAmount = 1.0 - exp(-distance * hazeParams.hazeRangeFactor); + + // Compute color after haze effect + potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount); + } else { + // Haze is based on both range and altitude + // Taken from www.crytek.com/download/GDC2007_RealtimeAtmoFxInGamesRev.ppt + + // Note that the haze base reference affects only the haze density as function of altitude + float hazeDensityDistribution = + hazeParams.hazeRangeFactor * + exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference)); + + float hazeIntegral = hazeDensityDistribution * distance; + + const float slopeThreshold = 0.01; + float deltaHeight = worldFragPos.y - worldEyePos.y; + if (abs(deltaHeight) > slopeThreshold) { + float t = hazeParams.hazeHeightFactor * deltaHeight; + // Protect from wild values + if (abs(t) > 0.0000001) { + hazeIntegral *= (1.0 - exp (-t)) / t; + } + } + + float hazeAmount = 1.0 - exp(-hazeIntegral); + + // Compute color after haze effect + potentialFragColor = mix(fragColor, blendedHazeColor, hazeAmount); + } + + // Mix with background at far range + const float BLEND_DISTANCE = 27000.0; + vec4 outFragColor; + if (distance > BLEND_DISTANCE) { + outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlend); + } else { + outFragColor = potentialFragColor; + } + + return outFragColor; +} + <@endif@> From 83ff20b599445a740a44f5847572e2e836b8764a Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 8 Nov 2017 08:00:31 -0800 Subject: [PATCH 013/102] Renamed getHazeParametersBuffer to getParametersBuffer --- libraries/model/src/model/Haze.h | 2 +- libraries/render-utils/src/DeferredLightingEffect.cpp | 2 +- libraries/render-utils/src/DrawHaze.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/model/src/model/Haze.h b/libraries/model/src/model/Haze.h index a0cc7c3bc7..e8b680705f 100644 --- a/libraries/model/src/model/Haze.h +++ b/libraries/model/src/model/Haze.h @@ -95,7 +95,7 @@ namespace model { void setZoneTransform(const glm::mat4& zoneTransform); using UniformBufferView = gpu::BufferView; - UniformBufferView getHazeParametersBuffer() const { return _hazeParametersBuffer; } + UniformBufferView getParametersBuffer() const { return _hazeParametersBuffer; } protected: class Parameters { diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 2187cb70b1..aae908c835 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -560,7 +560,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, // Haze if (haze) { - batch.setUniformBuffer(HAZE_MODEL_BUFFER_SLOT, haze->getHazeParametersBuffer()); + batch.setUniformBuffer(HAZE_MODEL_BUFFER_SLOT, haze->getParametersBuffer()); } batch.draw(gpu::TRIANGLE_STRIP, 4); diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index 7cf07d8f33..6b544eeb30 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -169,7 +169,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu auto hazeStage = args->_scene->getStage(); if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) { model::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front()); - batch.setUniformBuffer(HazeEffect_ParamsSlot, hazePointer->getHazeParametersBuffer()); + batch.setUniformBuffer(HazeEffect_ParamsSlot, hazePointer->getParametersBuffer()); } batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer()); From 3d2c8186e7c4a1067e752c0adc36d2886d1107f1 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 8 Nov 2017 08:01:19 -0800 Subject: [PATCH 014/102] Added Haze model as input to transparency shader. --- libraries/render-utils/src/RenderDeferredTask.cpp | 4 +++- libraries/render-utils/src/RenderDeferredTask.h | 4 ++-- libraries/render/src/render/ShapePipeline.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 0f095900be..79a8bc0827 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -163,7 +163,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawHazeDeferred", drawHazeInputs); // Render transparent objects forward in LightingBuffer - const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying(); + const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel, hazeModel).asVarying(); task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); // LIght Cluster Grid Debuging job @@ -291,6 +291,7 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& const auto& inItems = inputs.get0(); const auto& lightingModel = inputs.get1(); + const auto& hazeModel = inputs.get2(); RenderArgs* args = renderContext->args; @@ -311,6 +312,7 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& // Setup lighting model for all items; batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); + batch.setUniformBuffer(render::ShapePipeline::Slot::HAZE_MODEL, hazeModel->getParametersBuffer()); // From the lighting model define a global shapKey ORED with individiual keys ShapeKey::Builder keyBuilder; diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 452420589b..9a1e37ea92 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -15,7 +15,7 @@ #include #include #include "LightingModel.h" - +#include "model/Haze.h" class BeginGPURangeTimer { public: @@ -66,7 +66,7 @@ protected: class DrawDeferred { public: - using Inputs = render::VaryingSet2 ; + using Inputs = render::VaryingSet3 ; using Config = DrawConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index f0749504eb..0184c4275f 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -238,6 +238,7 @@ public: LIGHT, LIGHT_AMBIENT_BUFFER, FADE_PARAMETERS, + HAZE_MODEL }; enum MAP { From a8a118582dc344cd4ddcd505147eb81b9574ec8f Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 8 Nov 2017 09:37:58 -0800 Subject: [PATCH 015/102] WIP - passing uniform into model translucency shader. --- libraries/model/src/model/Haze.h | 4 ++-- libraries/render-utils/src/DeferredLightingEffect.cpp | 2 +- libraries/render-utils/src/DrawHaze.cpp | 2 +- libraries/render-utils/src/RenderDeferredTask.cpp | 8 +++++++- libraries/render/src/render/ShapePipeline.cpp | 2 ++ libraries/render/src/render/ShapePipeline.h | 1 + 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/model/src/model/Haze.h b/libraries/model/src/model/Haze.h index e8b680705f..5c916c3b91 100644 --- a/libraries/model/src/model/Haze.h +++ b/libraries/model/src/model/Haze.h @@ -95,7 +95,7 @@ namespace model { void setZoneTransform(const glm::mat4& zoneTransform); using UniformBufferView = gpu::BufferView; - UniformBufferView getParametersBuffer() const { return _hazeParametersBuffer; } + UniformBufferView getHazeParametersBuffer() const { return _hazeParametersBuffer; } protected: class Parameters { @@ -128,7 +128,7 @@ namespace model { Parameters() {} }; - UniformBufferView _hazeParametersBuffer; + UniformBufferView _hazeParametersBuffer{ nullptr }; }; using HazePointer = std::shared_ptr; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index aae908c835..2187cb70b1 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -560,7 +560,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, // Haze if (haze) { - batch.setUniformBuffer(HAZE_MODEL_BUFFER_SLOT, haze->getParametersBuffer()); + batch.setUniformBuffer(HAZE_MODEL_BUFFER_SLOT, haze->getHazeParametersBuffer()); } batch.draw(gpu::TRIANGLE_STRIP, 4); diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index 6b544eeb30..7cf07d8f33 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -169,7 +169,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu auto hazeStage = args->_scene->getStage(); if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) { model::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front()); - batch.setUniformBuffer(HazeEffect_ParamsSlot, hazePointer->getParametersBuffer()); + batch.setUniformBuffer(HazeEffect_ParamsSlot, hazePointer->getHazeParametersBuffer()); } batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer()); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 79a8bc0827..a9ad01902d 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -312,7 +312,13 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& // Setup lighting model for all items; batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); - batch.setUniformBuffer(render::ShapePipeline::Slot::HAZE_MODEL, hazeModel->getParametersBuffer()); + + // Setup haze iff curretn zone has haze + auto hazeStage = args->_scene->getStage(); + if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) { + model::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front()); + batch.setUniformBuffer(render::ShapePipeline::Slot::HAZE_MODEL, hazePointer->getHazeParametersBuffer()); + } // From the lighting model define a global shapKey ORED with individiual keys ShapeKey::Builder keyBuilder; diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 762b7712d7..4254280fa1 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -87,6 +87,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT)); slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK)); slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS)); + slotBindings.insert(gpu::Shader::Binding(std::string("hazeParametersBuffer"), Slot::BUFFER::HAZE_MODEL)); gpu::Shader::makeProgram(*program, slotBindings); @@ -107,6 +108,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap"); locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap"); locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer"); + locations->hazeParameterBufferUnit = program->getUniformBuffers().findLocation("hazeParametersBuffer"); ShapeKey key{filter._flags}; auto gpuPipeline = gpu::Pipeline::create(program, state); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 0184c4275f..101c060306 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -271,6 +271,7 @@ public: int lightAmbientMapUnit; int fadeMaskTextureUnit; int fadeParameterBufferUnit; + int hazeParameterBufferUnit; }; using LocationsPointer = std::shared_ptr; From 1a58aee385ad8c3bc68ac4b8d7da519b8d703eec Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 8 Nov 2017 12:00:29 -0800 Subject: [PATCH 016/102] Fix scripting URL injection, I hope --- .../resources/qml/hifi/tablet/TabletRoot.qml | 24 ++++++++++--------- .../ui/src/ui/TabletScriptingInterface.cpp | 13 +++++----- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index 6eb8e59ed1..bc795ce7ed 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -81,21 +81,23 @@ Item { }) } - function loadWebOnTop(url, injectJavaScriptUrl) { - tabletApps.append({"appUrl": loader.source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url}); - loader.item.url = tabletApps.get(currentApp).appWebUrl; - loader.item.scriptUrl = tabletApps.get(currentApp).scriptUrl; - if (loader.item.hasOwnProperty("gotoPreviousApp")) { - loader.item.gotoPreviousApp = true; - } + function loadWebContent(source, url, injectJavaScriptUrl) { + tabletApps.append({"appUrl": source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url}); + loader.load(source, function() { + loader.item.url = tabletApps.get(currentApp).appWebUrl; + loader.item.scriptUrl = tabletApps.get(currentApp).scriptUrl; + if (loader.item.hasOwnProperty("gotoPreviousApp")) { + loader.item.gotoPreviousApp = true; + } + }); } - function loadWebBase() { - loader.load("hifi/tablet/TabletWebView.qml"); + function loadWebBase(url, injectJavaScriptUrl) { + loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl); } - function loadTabletWebBase() { - loader.load("hifi/tablet/BlocksWebView.qml"); + function loadTabletWebBase(url, injectJavaScriptUrl) { + loadWebContent("hifi/tablet/BlocksWebView.qml", url, injectJavaScriptUrl); } function returnToPreviousApp() { diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index a261ae45b1..7440d0b5d0 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -679,19 +679,20 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS if (root) { if (loadOtherBase) { - QMetaObject::invokeMethod(root, "loadTabletWebBase"); + QMetaObject::invokeMethod(root, "loadTabletWebBase", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl))); } else { - QMetaObject::invokeMethod(root, "loadWebBase"); + QMetaObject::invokeMethod(root, "loadWebBase", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl))); } QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); if (_toolbarMode && _desktopWindow) { QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false))); } - QMetaObject::invokeMethod(root, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl))); + _state = State::Web; + emit screenChanged(QVariant("Web"), QVariant(url)); + _currentPathLoaded = QVariant(url); + } else { + qWarning() << "Unable to load web content due to missing root"; } - _state = State::Web; - emit screenChanged(QVariant("Web"), QVariant(url)); - _currentPathLoaded = QVariant(url); } TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { From 4433e79c9c9b70dc6f2a561366b759a23d4e2e43 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 8 Nov 2017 14:08:37 -0800 Subject: [PATCH 017/102] Seems to work. --- .../render-utils/src/DeferredGlobalLight.slh | 44 ++++++++++++++++--- libraries/render-utils/src/Haze.slf | 2 +- libraries/render-utils/src/Haze.slh | 24 +++++++++- .../render-utils/src/model_translucent.slf | 2 +- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 67a45e6ddf..311012716a 100644 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -91,6 +91,7 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness <@endfunc@> +<@include Haze.slh@> <@func declareEvalSkyboxGlobalColor(supportScattering)@> @@ -101,8 +102,6 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness <$declareDeferredCurvature()$> <@endif@> -<@include Haze.slh@> - vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, float roughness <@if supportScattering@> @@ -138,7 +137,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu // Attenuate the light if haze effect selected if ((hazeParams.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) { - color = computeHazeColorKeyLightAttenuation(color, directionalLight, invViewMat, position); + color = computeHazeColorKeyLightAttenuation(color, directionalLight, position); } return color; @@ -171,9 +170,6 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur } <@endfunc@> - - - <@func declareEvalGlobalLightingAlphaBlended()@> <$declareLightingAmbient(1, 1, 1)$> @@ -191,7 +187,6 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl color += ambientDiffuse; color += ambientSpecular / opacity; - // Directional vec3 directionalDiffuse; vec3 directionalSpecular; @@ -202,6 +197,41 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl return color; } +vec3 evalGlobalLightingAlphaBlendedWithHaze( + mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, + vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, float roughness, float opacity) +{ + <$prepareGlobalLight()$> + + color += emissive * isEmissiveEnabled(); + + // Ambient + vec3 ambientDiffuse; + vec3 ambientSpecular; + evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance); + color += ambientDiffuse; + color += ambientSpecular / opacity; + + // Directional + vec3 directionalDiffuse; + vec3 directionalSpecular; + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); + color += directionalDiffuse; + color += directionalSpecular / opacity; + + // Haze + if ((hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE) { + vec4 colorV4 = computeHazeColor( + vec4(color, 0.0), // fragment original color + vec4(position, 0.0), // fragment position in eye coordinates + vec4(fragEyeVector, 0.0), // fragment position in world coordinates + invViewMat[3]); // eye position in world coordinates + + color = colorV4.rgb; + } + + return color; +} <@endfunc@> diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index 18deb9c891..d758756975 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -49,7 +49,7 @@ void main(void) { vec4 fragColor = texture(colorMap, varTexCoord0); vec4 eyeFragPos = unpackPositionFromZeye(varTexCoord0); vec4 worldFragPos = getViewInverse() * eyeFragPos; - vec3 worldEyePos = getViewInverse()[3].xyz; + vec4 worldEyePos = getViewInverse()[3]; outFragColor = computeHazeColor(fragColor, eyeFragPos, worldFragPos, worldEyePos); } diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index 0633802c84..97284f1c2a 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -40,7 +40,17 @@ layout(std140) uniform hazeBuffer { HazeParams hazeParams; }; -vec3 computeHazeColorKeyLightAttenuation(vec3 color, Light directionalLight, mat4 invViewMat, vec3 worldFragPos) { + +// Input: +// color - fragment original color +// directionalLight - parameters of the keylight +// worldFragPos - fragment position in world coordinates +// Output: +// fragment colour after haze effect +// +// General algorithm taken from http://www.iquilezles.org/www/articles/fog/fog.htm, with permission +// +vec3 computeHazeColorKeyLightAttenuation(vec3 color, Light directionalLight, vec3 worldFragPos) { // Directional light attenuation is simulated by assuming the light source is at a fixed height above the // fragment. This height is where the haze density is reduced by 95% from the haze at the fragment's height // @@ -84,7 +94,17 @@ vec3 computeHazeColorKeyLightAttenuation(vec3 color, Light directionalLight, mat return mix(color, vec3(0.0, 0.0, 0.0), hazeAmount); } -vec4 computeHazeColor(vec4 fragColor, vec4 eyeFragPos, vec4 worldFragPos, vec3 worldEyePos) { +// Input: +// fragColor - fragment original color +// eyeFragPos - fragment position in eye coordinates +// worldFragPos - fragment position in world coordinates +// worldEyePos - eye position in world coordinates +// Output: +// fragment colour after haze effect +// +// General algorithm taken from http://www.iquilezles.org/www/articles/fog/fog.htm, with permission +// +vec4 computeHazeColor(vec4 fragColor, vec4 eyeFragPos, vec4 worldFragPos, vec4 worldEyePos) { // Distance to fragment float distance = length(eyeFragPos.xyz); diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index 6cf99a68ef..38f162fdc3 100644 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -66,7 +66,7 @@ void main(void) { TransformCamera cam = getTransformCamera(); - _fragColor = vec4(evalGlobalLightingAlphaBlended( + _fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze( cam._viewInverse, 1.0, occlusionTex, From 25df649b44fac06719208228c24657c5444d2d6d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 8 Nov 2017 14:55:34 -0800 Subject: [PATCH 018/102] Fix desktop mode script URL injection --- .../resources/qml/hifi/tablet/TabletRoot.qml | 8 +++---- .../resources/qml/hifi/tablet/WindowRoot.qml | 22 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index bc795ce7ed..da544c2114 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -68,8 +68,8 @@ Item { function loadSource(url) { tabletApps.clear(); - loader.load(url) - tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""}); + tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""}); + loader.load(url) } function loadQMLOnTop(url) { @@ -84,8 +84,8 @@ Item { function loadWebContent(source, url, injectJavaScriptUrl) { tabletApps.append({"appUrl": source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url}); loader.load(source, function() { - loader.item.url = tabletApps.get(currentApp).appWebUrl; - loader.item.scriptUrl = tabletApps.get(currentApp).scriptUrl; + loader.item.scriptURL = injectJavaScriptUrl; + loader.item.url = url; if (loader.item.hasOwnProperty("gotoPreviousApp")) { loader.item.gotoPreviousApp = true; } diff --git a/interface/resources/qml/hifi/tablet/WindowRoot.qml b/interface/resources/qml/hifi/tablet/WindowRoot.qml index baf2fa05c2..0b631326f4 100644 --- a/interface/resources/qml/hifi/tablet/WindowRoot.qml +++ b/interface/resources/qml/hifi/tablet/WindowRoot.qml @@ -62,20 +62,22 @@ Windows.ScrollingWindow { loader.load(url) } - function loadWebBase() { - loader.load("hifi/tablet/TabletWebView.qml"); + function loadWebContent(source, url, injectJavaScriptUrl) { + loader.load(source, function() { + loader.item.url = url + loader.item.scriptURL = injectJavaScriptUrl; + if (loader.item.hasOwnProperty("closeButtonVisible")) { + loader.item.closeButtonVisible = false; + } + }); } - function loadTabletWebBase() { - loader.load("hifi/tablet/BlocksWebView.qml"); + function loadWebBase(url, injectJavaScriptUrl) { + loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl); } - function loadWebUrl(url, injectedJavaScriptUrl) { - loader.item.url = url; - loader.item.scriptURL = injectedJavaScriptUrl; - if (loader.item.hasOwnProperty("closeButtonVisible")) { - loader.item.closeButtonVisible = false; - } + function loadTabletWebBase(url, injectJavaScriptUrl) { + loadWebContent("hifi/tablet/BlocksWebView.qml", url, injectJavaScriptUrl); } // used to send a message from qml to interface script. From 3c5fd73ca80d3b8dcdb5c4ff8de4493c88668802 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 8 Nov 2017 14:56:21 -0800 Subject: [PATCH 019/102] Removed unused argument. --- libraries/render-utils/src/RenderDeferredTask.cpp | 3 +-- libraries/render-utils/src/RenderDeferredTask.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index a9ad01902d..c301e71296 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -163,7 +163,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawHazeDeferred", drawHazeInputs); // Render transparent objects forward in LightingBuffer - const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel, hazeModel).asVarying(); + const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying(); task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); // LIght Cluster Grid Debuging job @@ -291,7 +291,6 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& const auto& inItems = inputs.get0(); const auto& lightingModel = inputs.get1(); - const auto& hazeModel = inputs.get2(); RenderArgs* args = renderContext->args; diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 9a1e37ea92..1573a6cbb0 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -15,7 +15,6 @@ #include #include #include "LightingModel.h" -#include "model/Haze.h" class BeginGPURangeTimer { public: @@ -66,7 +65,7 @@ protected: class DrawDeferred { public: - using Inputs = render::VaryingSet3 ; + using Inputs = render::VaryingSet2 ; using Config = DrawConfig; using JobModel = render::Job::ModelI; From 7bf1b176d72215077545d7fbac9743b24e26aa76 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 10 Nov 2017 12:34:52 -0800 Subject: [PATCH 020/102] Renaming Tablet API to Tablets, supporting dev-mode QML loading from filesystem --- interface/CMakeLists.txt | 8 +- .../qml/LoginDialog/LinkAccountBody.qml | 2 +- .../resources/qml/LoginDialog/SignUpBody.qml | 2 +- .../qml/LoginDialog/UsernameCollisionBody.qml | 2 +- .../resources/qml/controls-uit/Button.qml | 4 +- .../resources/qml/controls-uit/CheckBox.qml | 4 +- .../qml/controls-uit/CheckBoxQQC2.qml | 4 +- .../qml/controls-uit/GlyphButton.qml | 4 +- interface/resources/qml/controls-uit/Key.qml | 4 +- .../qml/controls-uit/RadioButton.qml | 4 +- .../qml/controls/FlickableWebViewCore.qml | 2 +- .../dialogs/TabletConnectionFailureDialog.qml | 2 +- .../qml/dialogs/TabletLoginDialog.qml | 4 +- .../dialogs/preferences/ButtonPreference.qml | 4 +- .../preferences/CheckBoxPreference.qml | 4 +- interface/resources/qml/hifi/Card.qml | 6 +- interface/resources/qml/hifi/audio/MicBar.qml | 4 +- .../qml/hifi/tablet/NewEntityButton.qml | 4 +- .../resources/qml/hifi/tablet/Tablet.qml | 280 ------------------ .../qml/hifi/tablet/TabletAddressDialog.qml | 4 +- .../hifi/tablet/TabletAttachmentsDialog.qml | 2 +- .../qml/hifi/tablet/TabletButton.qml | 5 +- .../resources/qml/hifi/tablet/TabletHome.qml | 159 ++++++++++ .../qml/hifi/tablet/TabletMenuView.qml | 4 +- .../tabletWindows/TabletPreferencesDialog.qml | 4 +- interface/src/Application.cpp | 10 +- interface/src/ui/overlays/Web3DOverlay.cpp | 4 - .../src/model-networking/TextureCache.cpp | 2 - libraries/octree/src/Octree.cpp | 4 - libraries/shared/src/PathUtils.cpp | 25 +- libraries/shared/src/PathUtils.h | 4 + libraries/ui/src/ui/OffscreenQmlSurface.cpp | 17 +- .../ui/src/ui/TabletScriptingInterface.cpp | 12 +- scripts/developer/EZrecord.js | 4 +- scripts/developer/inputRecording.js | 2 +- .../developer/tests/dynamics/dynamicsTests.js | 4 +- scripts/developer/tests/puck-attach.js | 2 +- scripts/developer/tests/sliderTestMain.js | 2 +- .../developer/tests/tabletEventBridgeTest.js | 4 +- scripts/developer/tests/tabletTest.js | 2 +- scripts/developer/utilities/audio/stats.js | 2 +- scripts/developer/utilities/render/luci.js | 2 +- .../render/photobooth/photoboothApp.js | 4 +- scripts/system/audio.js | 2 +- scripts/system/audioMuteOverlay.js | 2 +- scripts/system/audioScope.js | 4 +- scripts/system/bubble.js | 2 +- scripts/system/chat.js | 2 +- scripts/system/commerce/wallet.js | 2 +- scripts/system/controllers/godView.js | 4 +- scripts/system/edit.js | 14 +- scripts/system/fingerPaint.js | 4 +- scripts/system/generalSettings.js | 4 +- scripts/system/goto.js | 4 +- scripts/system/help.js | 4 +- scripts/system/hmd.js | 4 +- scripts/system/libraries/WebTablet.js | 6 +- scripts/system/libraries/entityList.js | 4 +- scripts/system/libraries/gridTool.js | 2 +- scripts/system/libraries/utils.js | 2 +- scripts/system/marketplaces/marketplace.js | 2 +- scripts/system/marketplaces/marketplaces.js | 4 +- scripts/system/menu.js | 2 +- scripts/system/mod.js | 2 +- scripts/system/notifications.js | 4 +- scripts/system/pal.js | 4 +- .../particle_explorer/particleExplorerTool.js | 2 +- scripts/system/snapshot.js | 4 +- scripts/system/tablet-goto.js | 4 +- scripts/system/tablet-ui/tabletUI.js | 6 +- scripts/system/tablet-users.js | 2 +- scripts/tutorials/createFloatingLanternBox.js | 2 +- scripts/tutorials/createTetherballStick.js | 2 +- .../entity_scripts/floatingLantern.js | 2 +- .../entity_scripts/floatingLanternBox.js | 2 +- .../entity_scripts/tetherballStick.js | 2 +- tests/shared/src/PathUtilsTests.cpp | 28 ++ tests/shared/src/PathUtilsTests.h | 20 ++ .../marketplace/blocks/blocksApp.js | 2 +- .../camera-move/app-camera-move.js | 4 +- .../marketplace/clap/clapApp.js | 2 +- .../app-doppleganger-attachments.js | 2 +- .../dist/app-doppleganger-marketplace.js | 2 +- .../doppleganger-mirror/app-doppleganger.js | 2 +- .../marketplace/emoji-tablet/emojiTablet.js | 2 +- .../marketplace/laser/laserPointerApp.js | 2 +- .../marketplace/record/record.js | 4 +- .../marketplace/shapes/shapes.js | 2 +- .../skyboxChanger/skyboxchanger.js | 2 +- .../spectator-camera/spectatorCamera.js | 4 +- .../tablet-raiseHand/tablet-raiseHand.js | 2 +- 91 files changed, 388 insertions(+), 436 deletions(-) delete mode 100644 interface/resources/qml/hifi/tablet/Tablet.qml create mode 100644 interface/resources/qml/hifi/tablet/TabletHome.qml create mode 100644 tests/shared/src/PathUtilsTests.cpp create mode 100644 tests/shared/src/PathUtilsTests.h diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 4c1b8d8d92..b3400c8dd0 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -12,8 +12,10 @@ function(JOIN VALUES GLUE OUTPUT) endfunction() -set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc) -generate_qrc(OUTPUT ${INTERFACE_QML_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *.qml *.qss *.js *.html *.ttf *.gif *.svg *.png *.jpg) +if (NOT DEV_BUILD) + set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc) + generate_qrc(OUTPUT ${INTERFACE_QML_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *.qml *.qss *.js *.html *.ttf *.gif *.svg *.png *.jpg) +endif() # set a default root dir for each of our optional externals if it was not passed set(OPTIONAL_EXTERNALS "LeapMotion") @@ -80,7 +82,9 @@ qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}") # add them to the interface source files set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") +if (NOT DEV_BUILD) list(APPEND INTERFACE_SRCS ${INTERFACE_QML_QRC}) +endif() if (UNIX) install( diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 300bcd46f0..552291c186 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -248,7 +248,7 @@ Item { //dont rise local keyboard keyboardEnabled = !root.isTablet && HMD.active; - //but rise Tablet's one instead for Tablet interface + //but rise Tablet's one instead for Tablets interface if (root.isTablet) { root.keyboardEnabled = HMD.active; root.keyboardRaised = Qt.binding( function() { return keyboardRaised; }) diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index 9d55998b40..e521e16a60 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -221,7 +221,7 @@ Item { root.iconText = "<" //dont rise local keyboard keyboardEnabled = !root.isTablet && HMD.active; - //but rise Tablet's one instead for Tablet interface + //but rise Tablet's one instead for Tablets interface if (root.isTablet) { root.keyboardEnabled = HMD.active; root.keyboardRaised = Qt.binding( function() { return keyboardRaised; }) diff --git a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml index 5c212578b8..185cbd9d47 100644 --- a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml +++ b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml @@ -131,7 +131,7 @@ Item { root.iconText = "<" //dont rise local keyboard keyboardEnabled = !root.isTablet && HMD.active; - //but rise Tablet's one instead for Tablet interface + //but rise Tablet's one instead for Tablets interface if (root.isTablet) { root.keyboardEnabled = HMD.active; root.keyboardRaised = Qt.binding( function() { return keyboardRaised; }) diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index c068fdcfaf..a305bea8dc 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -29,12 +29,12 @@ Original.Button { onHoveredChanged: { if (hovered) { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); } } onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } style: ButtonStyle { diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 22b25671c3..37bc936aa1 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -31,12 +31,12 @@ Original.CheckBox { activeFocusOnPress: true onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } // TODO: doesnt works for QQC1. check with QQC2 // onHovered: { -// tabletInterface.playSound(TabletEnums.ButtonHover); +// Tablets.playSound(TabletEnums.ButtonHover); // } style: CheckBoxStyle { diff --git a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml index 32d69cf339..404d83ebd2 100644 --- a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml +++ b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml @@ -36,12 +36,12 @@ CheckBox { hoverEnabled: true onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } onHoveredChanged: { if (hovered) { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); } } diff --git a/interface/resources/qml/controls-uit/GlyphButton.qml b/interface/resources/qml/controls-uit/GlyphButton.qml index bc7bc636fe..d225c8e1d1 100644 --- a/interface/resources/qml/controls-uit/GlyphButton.qml +++ b/interface/resources/qml/controls-uit/GlyphButton.qml @@ -27,12 +27,12 @@ Original.Button { onHoveredChanged: { if (hovered) { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); } } onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } style: ButtonStyle { diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controls-uit/Key.qml index e54250c872..3ec579a4eb 100644 --- a/interface/resources/qml/controls-uit/Key.qml +++ b/interface/resources/qml/controls-uit/Key.qml @@ -35,13 +35,13 @@ Item { onContainsMouseChanged: { if (containsMouse) { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); } } onClicked: { mouse.accepted = true; - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); webEntity.synthesizeKeyPress(glyph); webEntity.synthesizeKeyPress(glyph, mirrorText); diff --git a/interface/resources/qml/controls-uit/RadioButton.qml b/interface/resources/qml/controls-uit/RadioButton.qml index 65d36d2dcb..da4e944f35 100644 --- a/interface/resources/qml/controls-uit/RadioButton.qml +++ b/interface/resources/qml/controls-uit/RadioButton.qml @@ -30,12 +30,12 @@ Original.RadioButton { readonly property int checkRadius: 2 onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } // TODO: doesnt works for QQC1. check with QQC2 // onHovered: { -// tabletInterface.playSound(TabletEnums.ButtonHover); +// Tablets.playSound(TabletEnums.ButtonHover); // } style: RadioButtonStyle { diff --git a/interface/resources/qml/controls/FlickableWebViewCore.qml b/interface/resources/qml/controls/FlickableWebViewCore.qml index cbc4d19334..9e1751ee51 100644 --- a/interface/resources/qml/controls/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/FlickableWebViewCore.qml @@ -41,7 +41,7 @@ Item { } if (WebEngineView.LoadFailedStatus === loadRequest.status) { - console.log(" Tablet WebEngineView failed to load url: " + loadRequest.url.toString()); + console.log("Tablet WebEngineView failed to load url: " + loadRequest.url.toString()); } if (WebEngineView.LoadSucceededStatus === loadRequest.status) { diff --git a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml index 6d2ff36550..750ed0edd4 100644 --- a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml +++ b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml @@ -24,7 +24,7 @@ Item { }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Ok) { - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); tablet.gotoHomeScreen() } }); diff --git a/interface/resources/qml/dialogs/TabletLoginDialog.qml b/interface/resources/qml/dialogs/TabletLoginDialog.qml index 269788a808..5f1e9cd3bf 100644 --- a/interface/resources/qml/dialogs/TabletLoginDialog.qml +++ b/interface/resources/qml/dialogs/TabletLoginDialog.qml @@ -89,10 +89,10 @@ TabletModalWindow { //bodyLoader.active = false } if (gotoPreviousApp) { - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); tablet.returnToPreviousApp(); } else { - Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); + Tablets.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); } } diff --git a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml index 3a5c850031..bae581a47f 100644 --- a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml @@ -25,13 +25,13 @@ Preference { id: button onHoveredChanged: { if (hovered) { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); } } onClicked: { preference.trigger(); - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } width: 180 anchors.bottom: parent.bottom diff --git a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml index 8904896ab7..81884d9a72 100644 --- a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml @@ -41,12 +41,12 @@ Preference { id: checkBox onHoveredChanged: { if (hovered) { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); } } onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } anchors { diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index fc7b8c6200..8d69afab46 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -246,12 +246,12 @@ Item { anchors.fill: parent; acceptedButtons: Qt.LeftButton; onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); goFunction("hifi://" + hifiUrl); } hoverEnabled: true; onEntered: { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); hoverThunk(); } onExited: unhoverThunk(); @@ -269,7 +269,7 @@ Item { } } function go() { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); goFunction(drillDownToPlace ? ("/places/" + placeName) : ("/user_stories/" + storyId)); } MouseArea { diff --git a/interface/resources/qml/hifi/audio/MicBar.qml b/interface/resources/qml/hifi/audio/MicBar.qml index b6699d6ceb..9ef8bf3698 100644 --- a/interface/resources/qml/hifi/audio/MicBar.qml +++ b/interface/resources/qml/hifi/audio/MicBar.qml @@ -61,12 +61,12 @@ Rectangle { scrollGestureEnabled: false; onClicked: { Audio.muted = !Audio.muted; - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } drag.target: dragTarget; onContainsMouseChanged: { if (containsMouse) { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); } } } diff --git a/interface/resources/qml/hifi/tablet/NewEntityButton.qml b/interface/resources/qml/hifi/tablet/NewEntityButton.qml index 7f838717df..49fdb4368f 100644 --- a/interface/resources/qml/hifi/tablet/NewEntityButton.qml +++ b/interface/resources/qml/hifi/tablet/NewEntityButton.qml @@ -123,11 +123,11 @@ Item { hoverEnabled: true enabled: true onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); newEntityButton.clicked(); } onEntered: { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); newEntityButton.state = "hover state"; } onExited: { diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml deleted file mode 100644 index b21bf9c506..0000000000 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ /dev/null @@ -1,280 +0,0 @@ -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import QtQuick.Layouts 1.3 - -import "." -import "../../styles-uit" -import "../audio" as HifiAudio - -Item { - id: tablet - objectName: "tablet" - property int rowIndex: 0 - property int columnIndex: 0 - property int count: (flowMain.children.length - 1) - - Component { - id: buttonComponent - TabletButton { } - } - - Component.onCompleted: { - tablet.populateButtons(); - } - - function createClickedHandler(proxy) { - return function() { proxy.clicked(); } - } - - function populateButtons() { - var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - var buttons = tabletProxy.getButtons(); - for (var i = 0; i < buttons.length; i++) { - var proxy = buttons[i]; - var button = tablet.addButtonProxy(proxy.getProperties()); - button.clicked.connect(createClickedHandler(proxy)); - proxy.setQmlButton(button); - } - sortButtons(); - } - - // used to look up a button by its uuid - function findButtonIndex(uuid) { - if (!uuid) { - return -1; - } - - for (var i in flowMain.children) { - var child = flowMain.children[i]; - if (child.uuid === uuid) { - return i; - } - } - return -1; - } - - function sortButtons() { - var children = []; - for (var i = 0; i < flowMain.children.length; i++) { - children[i] = flowMain.children[i]; - } - - children.sort(function (a, b) { - if (a.sortOrder === b.sortOrder) { - // subsort by stableOrder, because JS sort is not stable in qml. - return a.stableOrder - b.stableOrder; - } else { - return a.sortOrder - b.sortOrder; - } - }); - - flowMain.children = children; - } - - // called by C++ code when a button should be added to the tablet - function addButtonProxy(properties) { - var button = buttonComponent.createObject(flowMain); - // copy all properites to button - var keys = Object.keys(properties).forEach(function (key) { - button[key] = properties[key]; - }); - - // pass a reference to the tabletRoot object to the button. - if (tabletRoot) { - button.tabletRoot = tabletRoot; - } else { - button.tabletRoot = parent.parent; - } - - return button; - } - - // called by C++ code when a button should be removed from the tablet - function removeButtonProxy(properties) { - var index = findButtonIndex(properties.uuid); - if (index < 0) { - console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid); - } else { - flowMain.children[index].destroy(); - } - } - - Rectangle { - id: bgTopBar - height: 90 - - anchors { - top: parent.top - left: parent.left - right: parent.right - } - - gradient: Gradient { - GradientStop { - position: 0 - color: "#2b2b2b" - } - - GradientStop { - position: 1 - color: "#1e1e1e" - } - } - - HifiAudio.MicBar { - anchors { - left: parent.left - leftMargin: 30 - verticalCenter: parent.verticalCenter - } - } - - Item { - width: 150 - height: 50 - anchors.right: parent.right - anchors.rightMargin: 30 - anchors.verticalCenter: parent.verticalCenter - - ColumnLayout { - anchors.fill: parent - - RalewaySemiBold { - text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in") - horizontalAlignment: Text.AlignRight - anchors.right: parent.right - font.pixelSize: 20 - color: "#afafaf" - } - - RalewaySemiBold { - visible: Account.loggedIn - height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0 - text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : "" - horizontalAlignment: Text.AlignRight - anchors.right: parent.right - font.pixelSize: 20 - color: "#afafaf" - } - } - - MouseArea { - anchors.fill: parent - onClicked: { - if (!Account.loggedIn) { - DialogsManager.showLoginDialog() - } else { - Account.logOut() - } - } - } - } - } - - Rectangle { - id: bgMain - gradient: Gradient { - GradientStop { - position: 0 - color: "#2b2b2b" - } - - GradientStop { - position: 1 - color: "#0f212e" - } - } - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.top: bgTopBar.bottom - anchors.topMargin: 0 - - Flickable { - id: flickable - width: parent.width - height: parent.height - contentWidth: parent.width - contentHeight: flowMain.childrenRect.height + flowMain.anchors.topMargin + flowMain.anchors.bottomMargin + flowMain.spacing - clip: true - Flow { - id: flowMain - spacing: 16 - anchors.right: parent.right - anchors.rightMargin: 30 - anchors.left: parent.left - anchors.leftMargin: 30 - anchors.bottom: parent.bottom - anchors.bottomMargin: 30 - anchors.top: parent.top - anchors.topMargin: 30 - } - } - } - - function setCurrentItemState(state) { - var index = rowIndex + columnIndex; - - if (index >= 0 && index <= count ) { - flowMain.children[index].state = state; - } - } - - function nextItem() { - setCurrentItemState("base state"); - var nextColumnIndex = (columnIndex + 3 + 1) % 3; - var nextIndex = rowIndex + nextColumnIndex; - if(nextIndex <= count) { - columnIndex = nextColumnIndex; - }; - setCurrentItemState("hover state"); - } - - function previousItem() { - setCurrentItemState("base state"); - var prevIndex = (columnIndex + 3 - 1) % 3; - if((rowIndex + prevIndex) <= count){ - columnIndex = prevIndex; - } - setCurrentItemState("hover state"); - } - - function upItem() { - setCurrentItemState("base state"); - rowIndex = rowIndex - 3; - if (rowIndex < 0 ) { - rowIndex = (count - (count % 3)); - var index = rowIndex + columnIndex; - if(index > count) { - rowIndex = rowIndex - 3; - } - } - setCurrentItemState("hover state"); - } - - function downItem() { - setCurrentItemState("base state"); - rowIndex = rowIndex + 3; - var index = rowIndex + columnIndex; - if (index > count ) { - rowIndex = 0; - } - setCurrentItemState("hover state"); - } - - function selectItem() { - flowMain.children[rowIndex + columnIndex].clicked(); - if (tabletRoot) { - tabletRoot.playButtonClickSound(); - } - } - - Keys.onRightPressed: nextItem(); - Keys.onLeftPressed: previousItem(); - Keys.onDownPressed: downItem(); - Keys.onUpPressed: upItem(); - Keys.onReturnPressed: selectItem(); -} diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 4d9a83817a..3242de89b1 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -72,7 +72,7 @@ StackView { addressLine.focus = !HMD.active; root.parentChanged.connect(center); center(); - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); } Component.onDestruction: { root.parentChanged.disconnect(center); @@ -149,7 +149,7 @@ StackView { onClicked: { addressBarDialog.loadHome(); tabletRoot.shown = false; - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); tablet.gotoHomeScreen(); } anchors { diff --git a/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml b/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml index 19548365aa..14d7d09dba 100644 --- a/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml @@ -37,7 +37,7 @@ Item { } function closeDialog() { - Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); + Tablets.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); } anchors.topMargin: hifi.dimensions.tabletMenuHeader // Space for header. diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index 169c7acec1..3a66738b82 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -121,7 +121,6 @@ Item { enabled: true preventStealing: true onClicked: { - console.log("Tablet Button Clicked!"); if (tabletButton.inDebugMode) { if (tabletButton.isActive) { tabletButton.isActive = false; @@ -131,12 +130,12 @@ Item { } tabletButton.clicked(); if (tabletRoot) { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); } } onEntered: { tabletButton.isEntered = true; - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); if (tabletButton.isActive) { tabletButton.state = "hover active state"; diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml new file mode 100644 index 0000000000..0b30496c44 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -0,0 +1,159 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 +import QtQuick.Layouts 1.3 + +import "." +import "../../styles-uit" +import "../audio" as HifiAudio + +Item { + id: tablet + objectName: "tablet" + property var tabletProxy: Tablets.getTablet("com.highfidelity.interface.tablet.system"); + + Rectangle { + id: bgTopBar + height: 90 + + anchors { + top: parent.top + left: parent.left + right: parent.right + } + + gradient: Gradient { + GradientStop { + position: 0 + color: "#2b2b2b" + } + + GradientStop { + position: 1 + color: "#1e1e1e" + } + } + + HifiAudio.MicBar { + anchors { + left: parent.left + leftMargin: 30 + verticalCenter: parent.verticalCenter + } + } + + Item { + width: 150 + height: 50 + anchors.right: parent.right + anchors.rightMargin: 30 + anchors.verticalCenter: parent.verticalCenter + + ColumnLayout { + anchors.fill: parent + + RalewaySemiBold { + text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in") + horizontalAlignment: Text.AlignRight + anchors.right: parent.right + font.pixelSize: 20 + color: "#afafaf" + } + + RalewaySemiBold { + visible: Account.loggedIn + height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0 + text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : "" + horizontalAlignment: Text.AlignRight + anchors.right: parent.right + font.pixelSize: 20 + color: "#afafaf" + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (!Account.loggedIn) { + DialogsManager.showLoginDialog() + } else { + Account.logOut() + } + } + } + } + } + + Rectangle { + id: bgMain + clip: true + gradient: Gradient { + GradientStop { + position: 0 + color: "#2b2b2b" + } + + GradientStop { + position: 1 + color: "#0f212e" + } + } + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + anchors.top: bgTopBar.bottom + + GridView { + id: flickable + anchors.top: parent.top + anchors.topMargin: 15 + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: cellWidth * 3 + cellHeight: 145 + cellWidth: 145 + model: tabletProxy.buttons + delegate: Item { + width: flickable.cellWidth + height: flickable.cellHeight + property var proxy: modelData + + TabletButton { + id: tabletButton + anchors.centerIn: parent + onClicked: modelData.clicked() + state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" + } + + Connections { + target: modelData; + onPropertiesChanged: { + updateProperties(); + } + } + + Component.onCompleted: updateProperties() + + function updateProperties() { + var keys = Object.keys(modelData.properties).forEach(function (key) { + if (tabletButton[key] !== modelData.properties[key]) { + tabletButton[key] = modelData.properties[key]; + } + }); + } + } + } + } + + Keys.onRightPressed: flickable.moveCurrentIndexRight(); + Keys.onLeftPressed: flickable.moveCurrentIndexLeft(); + Keys.onDownPressed: flickable.moveCurrentIndexDown(); + Keys.onUpPressed: flickable.moveCurrentIndexUp(); + Keys.onReturnPressed: { + if (flickable.currentItem) { + flickable.currentItem.proxy.clicked(); + if (tabletRoot) { + tabletRoot.playButtonClickSound(); + } + } + } +} diff --git a/interface/resources/qml/hifi/tablet/TabletMenuView.qml b/interface/resources/qml/hifi/tablet/TabletMenuView.qml index 4a4a6b7f87..e069ce8cb1 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuView.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuView.qml @@ -77,12 +77,12 @@ FocusScope { anchors.fill: parent hoverEnabled: true onEntered: { - tabletInterface.playSound(TabletEnums.ButtonHover); + Tablets.playSound(TabletEnums.ButtonHover); listView.currentIndex = index } onClicked: { - tabletInterface.playSound(TabletEnums.ButtonClick); + Tablets.playSound(TabletEnums.ButtonClick); root.selected(item); } } diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index fcb3e9ff92..0665b9971e 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -56,7 +56,7 @@ Item { } function closeDialog() { - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); if (gotoPreviousApp) { tablet.returnToPreviousApp(); @@ -206,7 +206,7 @@ Item { } Component.onCompleted: { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); keyboardEnabled = HMD.active; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 929184fc14..30d93482f8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2214,12 +2214,12 @@ extern void setupPreferences(); void Application::initializeUi() { // Make sure all QML surfaces share the main thread GL context OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext()); - OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "qrc:///qml/OverlayWindowTest.qml" }, + OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "OverlayWindowTest.qml" }, [](QQmlContext* context) { qDebug() << "Whitelist OverlayWindow worked"; context->setContextProperty("OverlayWindowTestString", "TestWorked"); }); - OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "qrc:///qml/hifi/audio/Audio.qml" }, + OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "hifi/audio/Audio.qml" }, [](QQmlContext* context) { qDebug() << "QQQ" << __FUNCTION__ << "Whitelist Audio worked"; }); @@ -2310,9 +2310,6 @@ void Application::initializeUi() { surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get().data()); surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance()); - surfaceContext->setContextProperty("Tablet", DependencyManager::get().data()); - // Tablet inteference with Tablet.qml. Need to avoid this in QML space - surfaceContext->setContextProperty("tabletInterface", DependencyManager::get().data()); surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface); surfaceContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); surfaceContext->setContextProperty("FaceTracker", DependencyManager::get().data()); @@ -5807,7 +5804,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - // Tablet inteference with Tablet.qml. Need to avoid this in QML space + scriptEngine->registerGlobalObject("Tablets", DependencyManager::get().data()); + // FIXME remove these deprecated names for the tablet scripting interface scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index d418a79fbf..07a953c219 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -209,7 +209,6 @@ void Web3DOverlay::setupQmlSurface() { _webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper()); _webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get()->getMyAvatar().get()); _webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); - _webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get().data()); @@ -228,9 +227,6 @@ void Web3DOverlay::setupQmlSurface() { _webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../"); - // Tablet inteference with Tablet.qml. Need to avoid this in QML space - _webSurface->getSurfaceContext()->setContextProperty("tabletInterface", DependencyManager::get().data()); - tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data()); // mark the TabletProxy object as cpp ownership. QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 4184351c2d..092afe1a90 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -217,8 +217,6 @@ gpu::TexturePointer TextureCache::cacheTextureByHash(const std::string& hash, co if (!result) { _texturesByHashes[hash] = texture; result = texture; - } else { - qCWarning(modelnetworking) << "QQQ Swapping out texture with previous live texture in hash " << hash.c_str(); } } return result; diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 7563122290..3190f25d7e 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -9,10 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifdef _WIN32 -#define _USE_MATH_DEFINES -#endif - #include #include #include diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 46613f1283..00a11ef06c 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -24,9 +24,30 @@ const QString& PathUtils::resourcesPath() { #ifdef Q_OS_MAC - static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; + static const QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; #else - static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; + static const QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; +#endif + return staticResourcePath; +} + +#ifdef DEV_BUILD +const QString& PathUtils::projectRootPath() { + static QString sourceFolder; + static std::once_flag once; + std::call_once(once, [&] { + QDir thisDir = QFileInfo(__FILE__).absoluteDir(); + sourceFolder = QDir::cleanPath(thisDir.absoluteFilePath("../../../")); + }); + return sourceFolder; +} +#endif + +const QString& PathUtils::qmlBasePath() { +#ifdef DEV_BUILD + static const QString staticResourcePath = QUrl::fromLocalFile(projectRootPath() + "/interface/resources/qml/").toString(); +#else + static const QString staticResourcePath = "qrc:///qml/"; #endif return staticResourcePath; diff --git a/libraries/shared/src/PathUtils.h b/libraries/shared/src/PathUtils.h index 8c4bcf2394..9b5b6ef67f 100644 --- a/libraries/shared/src/PathUtils.h +++ b/libraries/shared/src/PathUtils.h @@ -30,6 +30,10 @@ class PathUtils : public QObject, public Dependency { Q_PROPERTY(QUrl defaultScripts READ defaultScriptsLocation CONSTANT) public: static const QString& resourcesPath(); + static const QString& qmlBasePath(); +#ifdef DEV_BUILD + static const QString& projectRootPath(); +#endif static QString getAppDataPath(); static QString getAppLocalDataPath(); diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 8711e52eff..aab89ccd4d 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -48,6 +48,7 @@ #include "types/SoundEffect.h" #include "TabletScriptingInterface.h" +#include "ToolbarScriptingInterface.h" #include "Logging.h" Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml") @@ -62,7 +63,10 @@ public: void addWhitelistContextHandler(const std::initializer_list& urls, const QmlContextCallback& callback) { withWriteLock([&] { - for (const auto& url : urls) { + for (auto url : urls) { + if (url.isRelative()) { + url = QUrl(PathUtils::qmlBasePath() + url.toString()); + } _callbacks[url].push_back(callback); } }); @@ -382,6 +386,13 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) { rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext)); rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext)); rootContext->setContextProperty("Paths", DependencyManager::get().data()); + static std::once_flag once; + std::call_once(once, [&] { + qRegisterMetaType(); + qRegisterMetaType(); + }); + rootContext->setContextProperty("Tablets", DependencyManager::get().data()); + rootContext->setContextProperty("Toolbars", DependencyManager::get().data()); } QQmlEngine* acquireEngine(QQuickWindow* window) { @@ -587,7 +598,7 @@ void OffscreenQmlSurface::create() { auto qmlEngine = acquireEngine(_quickWindow); _qmlContext = new QQmlContext(qmlEngine->rootContext()); - _qmlContext->setBaseUrl(QUrl{ "qrc:///qml/" }); + _qmlContext->setBaseUrl(QUrl{ PathUtils::qmlBasePath() }); _qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow())); _qmlContext->setContextProperty("eventBridge", this); _qmlContext->setContextProperty("webEntity", this); @@ -715,7 +726,6 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, con } void OffscreenQmlSurface::loadInternal(const QUrl& qmlSource, bool createNewContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback) { - qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << qmlSource; if (QThread::currentThread() != thread()) { qCWarning(uiLogging) << "Called load on a non-surface thread"; } @@ -725,7 +735,6 @@ void OffscreenQmlSurface::loadInternal(const QUrl& qmlSource, bool createNewCont QUrl finalQmlSource = qmlSource; if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) { finalQmlSource = _qmlContext->resolvedUrl(qmlSource); - qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << "resolved to " << finalQmlSource; } auto targetContext = contextForUrl(finalQmlSource, createNewContext); diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 7440d0b5d0..93d493539e 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -210,7 +210,7 @@ QObject* TabletScriptingInterface::getFlags() { // TabletProxy // -static const char* TABLET_SOURCE_URL = "hifi/tablet/Tablet.qml"; +static const char* TABLET_HOME_SOURCE_URL = "hifi/tablet/TabletHome.qml"; static const char* WEB_VIEW_SOURCE_URL = "hifi/tablet/TabletWebView.qml"; static const char* VRMENU_SOURCE_URL = "hifi/tablet/TabletMenu.qml"; @@ -274,7 +274,7 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { } else { removeButtonsFromToolbar(); - if (_currentPathLoaded == TABLET_SOURCE_URL) { + if (_currentPathLoaded == TABLET_HOME_SOURCE_URL) { // Tablet QML now pulls buttons from Tablet proxy } else { loadHomeScreen(true); @@ -408,7 +408,7 @@ void TabletProxy::setQmlTabletRoot(OffscreenQmlSurface* qmlOffscreenSurface) { }); if (_toolbarMode) { - QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL))); + QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_HOME_SOURCE_URL))); } // force to the tablet to go to the homescreen @@ -618,7 +618,7 @@ void TabletProxy::loadHomeScreen(bool forceOntoHomeScreen) { if ((_state != State::Home && _state != State::Uninitialized) || forceOntoHomeScreen) { if (!_toolbarMode && _qmlTabletRoot) { - QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL))); + QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_HOME_SOURCE_URL))); QMetaObject::invokeMethod(_qmlTabletRoot, "playButtonClickSound"); } else if (_toolbarMode && _desktopWindow) { // close desktop window @@ -627,8 +627,8 @@ void TabletProxy::loadHomeScreen(bool forceOntoHomeScreen) { } } _state = State::Home; - emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL)); - _currentPathLoaded = TABLET_SOURCE_URL; + emit screenChanged(QVariant("Home"), QVariant(TABLET_HOME_SOURCE_URL)); + _currentPathLoaded = TABLET_HOME_SOURCE_URL; } } diff --git a/scripts/developer/EZrecord.js b/scripts/developer/EZrecord.js index 7fdebada79..3cfc6e9928 100644 --- a/scripts/developer/EZrecord.js +++ b/scripts/developer/EZrecord.js @@ -227,14 +227,14 @@ } function setUp() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { return; } Recorder.setUp(); - // Tablet/toolbar button. + // tablet/toolbar button. button = tablet.addButton({ icon: APP_ICON_INACTIVE, activeIcon: APP_ICON_ACTIVE, diff --git a/scripts/developer/inputRecording.js b/scripts/developer/inputRecording.js index 6fb8e471cd..574cbbeb3d 100644 --- a/scripts/developer/inputRecording.js +++ b/scripts/developer/inputRecording.js @@ -10,7 +10,7 @@ var recording = false; var onRecordingScreen = false; var passedSaveDirectory = false; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: "IRecord" }); diff --git a/scripts/developer/tests/dynamics/dynamicsTests.js b/scripts/developer/tests/dynamics/dynamicsTests.js index c0b001eab3..be22e2c5fb 100644 --- a/scripts/developer/tests/dynamics/dynamicsTests.js +++ b/scripts/developer/tests/dynamics/dynamicsTests.js @@ -11,14 +11,14 @@ "use strict"; -/* global Entities, Script, Tablet, MyAvatar, Vec3 */ +/* global Entities, Script, Tablets, MyAvatar, Vec3 */ (function() { // BEGIN LOCAL_SCOPE var DYNAMICS_TESTS_URL = Script.resolvePath("dynamics-tests.html"); var DEFAULT_LIFETIME = 120; // seconds - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: Script.resolvePath("dynamicsTests.svg"), diff --git a/scripts/developer/tests/puck-attach.js b/scripts/developer/tests/puck-attach.js index 04d5db5710..6971ec02cd 100644 --- a/scripts/developer/tests/puck-attach.js +++ b/scripts/developer/tests/puck-attach.js @@ -19,7 +19,7 @@ Script.include("/~/system/libraries/Xform.js"); var TABLET_BUTTON_NAME = "PUCKTACH"; var TABLET_APP_URL = "https://hifi-content.s3.amazonaws.com/seefo/production/puck-attach/puck-attach.html"; -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var tabletButton = tablet.addButton({ text: TABLET_BUTTON_NAME, icon: "https://s3.amazonaws.com/hifi-public/tony/icons/puck-i.svg", diff --git a/scripts/developer/tests/sliderTestMain.js b/scripts/developer/tests/sliderTestMain.js index 22bf4fa911..e7542ef177 100644 --- a/scripts/developer/tests/sliderTestMain.js +++ b/scripts/developer/tests/sliderTestMain.js @@ -1,6 +1,6 @@ (function () { var HTML_URL = Script.resolvePath("sliderTest.html"); - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: "SLIDER" }); diff --git a/scripts/developer/tests/tabletEventBridgeTest.js b/scripts/developer/tests/tabletEventBridgeTest.js index 83031741fc..3f988303f2 100644 --- a/scripts/developer/tests/tabletEventBridgeTest.js +++ b/scripts/developer/tests/tabletEventBridgeTest.js @@ -11,10 +11,10 @@ // Adds a button to the tablet that will switch to a web page. // This web page contains buttons that will use the event bridge to trigger sounds. -/* globals Tablet */ +/* globals Tablets */ -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var tabletButton = tablet.addButton({ text: "SOUNDS", icon: "http://s3.amazonaws.com/hifi-public/tony/icons/trombone-i.png", diff --git a/scripts/developer/tests/tabletTest.js b/scripts/developer/tests/tabletTest.js index 438d0a4b99..9c1ce0e3bd 100644 --- a/scripts/developer/tests/tabletTest.js +++ b/scripts/developer/tests/tabletTest.js @@ -10,7 +10,7 @@ // Adds a BAM! button to the tablet ui. -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: "BAM!!!" }); diff --git a/scripts/developer/utilities/audio/stats.js b/scripts/developer/utilities/audio/stats.js index 382e14df5f..a828d79340 100644 --- a/scripts/developer/utilities/audio/stats.js +++ b/scripts/developer/utilities/audio/stats.js @@ -10,7 +10,7 @@ // if (HMD.active && !Settings.getValue("HUDUIEnabled")) { - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var qml = Script.resolvePath("TabletStats.qml"); tablet.loadQMLSource(qml); Script.stop(); diff --git a/scripts/developer/utilities/render/luci.js b/scripts/developer/utilities/render/luci.js index 1e2ac1261f..b2203ce72f 100644 --- a/scripts/developer/utilities/render/luci.js +++ b/scripts/developer/utilities/render/luci.js @@ -27,7 +27,7 @@ } } - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: TABLET_BUTTON_NAME, icon: ICON_URL, diff --git a/scripts/developer/utilities/render/photobooth/photoboothApp.js b/scripts/developer/utilities/render/photobooth/photoboothApp.js index 154028f091..375a98e543 100644 --- a/scripts/developer/utilities/render/photobooth/photoboothApp.js +++ b/scripts/developer/utilities/render/photobooth/photoboothApp.js @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablet, Toolbars, Script, HMD, Controller, Menu */ +/* globals Tablets, Toolbars, Script, HMD, Controller, Menu */ (function () { var SNAPSHOT_DELAY = 500; // 500ms var PHOTOBOOTH_WINDOW_HTML_URL = Script.resolvePath("./html/photobooth.html"); @@ -16,7 +16,7 @@ var MODEL_BOUNDING_BOX_DIMENSIONS = {x: 1.0174,y: 1.1925,z: 1.0165}; var PhotoBooth = {}; var photoboothCreated = false; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/snap-i.svg", text: "PHOTOBOOTH" diff --git a/scripts/system/audio.js b/scripts/system/audio.js index a93177ca38..ea0626a30c 100644 --- a/scripts/system/audio.js +++ b/scripts/system/audio.js @@ -54,7 +54,7 @@ function onScreenChanged(type, url) { button.editProperties({isActive: onAudioScreen}); } -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: Audio.muted ? MUTE_ICONS.icon : UNMUTE_ICONS.icon, activeIcon: Audio.muted ? MUTE_ICONS.activeIcon : UNMUTE_ICONS.activeIcon, diff --git a/scripts/system/audioMuteOverlay.js b/scripts/system/audioMuteOverlay.js index 731d62017d..0db4edb85d 100644 --- a/scripts/system/audioMuteOverlay.js +++ b/scripts/system/audioMuteOverlay.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // audioMuteOverlay.js diff --git a/scripts/system/audioScope.js b/scripts/system/audioScope.js index 81d8e8fbd4..268c883983 100644 --- a/scripts/system/audioScope.js +++ b/scripts/system/audioScope.js @@ -9,7 +9,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global Script, Tablet, AudioScope, Audio */ +/* global Script, Tablets, AudioScope, Audio */ (function () { // BEGIN LOCAL_SCOPE @@ -17,7 +17,7 @@ var scopePaused = AudioScope.getPause(); var autoPause = false; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var showScopeButton = tablet.addButton({ icon: "icons/tablet-icons/scope.svg", text: "Audio Scope", diff --git a/scripts/system/bubble.js b/scripts/system/bubble.js index 4ea684ff06..2b6924d84f 100644 --- a/scripts/system/bubble.js +++ b/scripts/system/bubble.js @@ -183,7 +183,7 @@ // Setup the bubble button var buttonName = "BUBBLE"; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ icon: "icons/tablet-icons/bubble-i.svg", activeIcon: "icons/tablet-icons/bubble-a.svg", diff --git a/scripts/system/chat.js b/scripts/system/chat.js index fa997e20cc..220c87195a 100644 --- a/scripts/system/chat.js +++ b/scripts/system/chat.js @@ -19,7 +19,7 @@ var tabletButtonIcon = "icons/tablet-icons/menu-i.svg"; // Icon for chat button. var tabletButtonActiveIcon = "icons/tablet-icons/menu-a.svg"; // Active icon for chat button. var tabletButton = null; // The button we create in the tablet. - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); // The awesome tablet. + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); // The awesome tablet. var chatLog = []; // Array of chat messages in the form of [avatarID, displayName, message, data]. var avatarIdentifiers = {}; // Map of avatar ids to dict of identifierParams. var speechBubbleShowing = false; // Is the speech bubble visible? diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 9b2367b762..7f05dcf3d8 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -148,7 +148,7 @@ var walletEnabled = Settings.getValue("commerce", false); function startup() { if (walletEnabled) { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ text: buttonName, icon: "icons/tablet-icons/wallet-i.svg", diff --git a/scripts/system/controllers/godView.js b/scripts/system/controllers/godView.js index 4b406399fd..eb38308cb9 100644 --- a/scripts/system/controllers/godView.js +++ b/scripts/system/controllers/godView.js @@ -9,7 +9,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals HMD, Script, Menu, Tablet, Camera */ +/* globals HMD, Script, Menu, Tablets, Camera */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function() { // BEGIN LOCAL_SCOPE @@ -81,7 +81,7 @@ function endGodView() { } var button; -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); function onClicked() { if (godView) { diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 2bbd422c65..abd69e2697 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -11,7 +11,7 @@ // /* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger, - Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */ + Settings, Entities, Tablets, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */ (function() { // BEGIN LOCAL_SCOPE @@ -390,7 +390,7 @@ var toolBar = (function () { } function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); tablet.popFromStack(); switch (message.method) { case "newModelDialogAdd": @@ -417,7 +417,7 @@ var toolBar = (function () { var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified()); var createButtonIconRsrc = (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON); - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); activeButton = tablet.addButton({ captionColorOverride: hasRezPermissions ? "" : "#888888", icon: createButtonIconRsrc, @@ -463,7 +463,7 @@ var toolBar = (function () { var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; // tablet version of new-model dialog - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); tablet.pushOntoStack("NewModelDialog.qml"); }); @@ -644,7 +644,7 @@ var toolBar = (function () { isActive = active; activeButton.editProperties({isActive: isActive}); - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); if (!isActive) { entityListTool.setVisible(false); @@ -1850,7 +1850,7 @@ var PropertiesTool = function (opts) { var that = {}; var webView = null; - webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + webView = Tablets.getTablet("com.highfidelity.interface.tablet.system"); webView.setVisible = function(value) {}; var visible = false; @@ -2293,7 +2293,7 @@ function selectParticleEntity(entityID) { particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData)); // Switch to particle explorer - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); tablet.sendToQml({method: 'selectTab', params: {id: 'particle'}}); } diff --git a/scripts/system/fingerPaint.js b/scripts/system/fingerPaint.js index 88245503e8..ad4973890b 100644 --- a/scripts/system/fingerPaint.js +++ b/scripts/system/fingerPaint.js @@ -414,12 +414,12 @@ } function setUp() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { return; } - // Tablet button. + // Tablets button. button = tablet.addButton({ icon: "icons/tablet-icons/finger-paint-i.svg", activeIcon: "icons/tablet-icons/finger-paint-a.svg", diff --git a/scripts/system/generalSettings.js b/scripts/system/generalSettings.js index 082528ffc5..8a9001107a 100644 --- a/scripts/system/generalSettings.js +++ b/scripts/system/generalSettings.js @@ -10,7 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablet, Toolbars, Script, HMD, DialogsManager */ +/* globals Tablets, Toolbars, Script, HMD, DialogsManager */ (function() { // BEGIN LOCAL_SCOPE @@ -34,7 +34,7 @@ alpha: 0.9 }); } else { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ icon: "icons/tablet-icons/goto-i.svg", text: buttonName, diff --git a/scripts/system/goto.js b/scripts/system/goto.js index d364bf579e..31394c8750 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -10,7 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablet, Toolbars, Script, HMD, DialogsManager */ +/* globals Tablets, Toolbars, Script, HMD, DialogsManager */ (function() { // BEGIN LOCAL_SCOPE @@ -37,7 +37,7 @@ if (Settings.getValue("HUDUIEnabled")) { alpha: 0.9 }); } else { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ icon: "icons/tablet-icons/goto-i.svg", activeIcon: "icons/tablet-icons/goto-a.svg", diff --git a/scripts/system/help.js b/scripts/system/help.js index 9ab7fa3fb3..5687c8961f 100644 --- a/scripts/system/help.js +++ b/scripts/system/help.js @@ -10,14 +10,14 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablet, Script, HMD, Controller, Menu */ +/* globals Tablets, Script, HMD, Controller, Menu */ (function() { // BEGIN LOCAL_SCOPE var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; var buttonName = "HELP"; var onHelpScreen = false; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/help-i.svg", activeIcon: "icons/tablet-icons/help-a.svg", diff --git a/scripts/system/hmd.js b/scripts/system/hmd.js index b9fd7f725c..a86bbd9a62 100644 --- a/scripts/system/hmd.js +++ b/scripts/system/hmd.js @@ -10,7 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals HMD, Script, Menu, Tablet, Camera */ +/* globals HMD, Script, Menu, Tablets, Camera */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function() { // BEGIN LOCAL_SCOPE @@ -38,7 +38,7 @@ function updateControllerDisplay() { } var button; -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); // Independent and Entity mode make people sick; disable them in hmd. var desktopOnlyViews = ['Independent Mode', 'Entity Mode']; diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index c46cfaa073..cd7c575205 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -7,7 +7,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global getControllerWorldLocation, Tablet, WebTablet:true, HMD, Settings, Script, +/* global getControllerWorldLocation, Tablets, WebTablet:true, HMD, Settings, Script, Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp, Controller, Mat4, resizeTablet */ Script.include(Script.resolvePath("../libraries/utils.js")); @@ -168,7 +168,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) { this.receive = function (channel, senderID, senderUUID, localOnly) { if (_this.homeButtonID == senderID) { - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var onHomeScreen = tablet.onHomeScreen(); var isMessageOpen; if (onHomeScreen) { @@ -513,7 +513,7 @@ WebTablet.prototype.mousePressEvent = function (event) { entityPickResults.overlayID === this.tabletEntityID)) { var overlayPickResults = Overlays.findRayIntersection(pickRay, true, [this.webOverlayID, this.homeButtonID], []); if (overlayPickResults.intersects && overlayPickResults.overlayID === this.homeButtonID) { - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var onHomeScreen = tablet.onHomeScreen(); var isMessageOpen = tablet.isMessageDialogOpen(); if (onHomeScreen) { diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index 9d9689000e..a1f5d31a1a 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -8,14 +8,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global EntityListTool, Tablet, selectionManager, Entities, Camera, MyAvatar, Vec3, Menu, Messages, +/* global EntityListTool, Tablets, selectionManager, Entities, Camera, MyAvatar, Vec3, Menu, Messages, cameraManager, MENU_EASE_ON_FOCUS, deleteSelectedEntities, toggleSelectedEntitiesLocked, toggleSelectedEntitiesVisible */ EntityListTool = function(opts) { var that = {}; var webView = null; - webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + webView = Tablets.getTablet("com.highfidelity.interface.tablet.system"); webView.setVisible = function(value) {}; var filterInView = false; diff --git a/scripts/system/libraries/gridTool.js b/scripts/system/libraries/gridTool.js index 2c417a9dde..41cbc59502 100644 --- a/scripts/system/libraries/gridTool.js +++ b/scripts/system/libraries/gridTool.js @@ -237,7 +237,7 @@ GridTool = function(opts) { var listeners = []; var webView = null; - webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + webView = Tablets.getTablet("com.highfidelity.interface.tablet.system"); webView.setVisible = function(value) {}; horizontalGrid.addListener(function(data) { diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index 76c248d880..8ea176bbd4 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -354,7 +354,7 @@ flatten = function(array) { getTabletWidthFromSettings = function () { var DEFAULT_TABLET_WIDTH = 0.4375; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var toolbarMode = tablet.toolbarMode; var DEFAULT_TABLET_SCALE = 100; var tabletScalePercentage = DEFAULT_TABLET_SCALE; diff --git a/scripts/system/marketplaces/marketplace.js b/scripts/system/marketplaces/marketplace.js index d90695c767..6d6550ecbc 100644 --- a/scripts/system/marketplaces/marketplace.js +++ b/scripts/system/marketplaces/marketplace.js @@ -82,7 +82,7 @@ function toggleMarketplace() { } } -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var browseExamplesButton = tablet.addButton({ icon: "icons/tablet-icons/market-i.svg", diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index b427739292..a831d761d2 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global Tablet, Script, HMD, UserActivityLogger, Entities */ +/* global Tablets, Script, HMD, UserActivityLogger, Entities */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function () { // BEGIN LOCAL_SCOPE @@ -81,7 +81,7 @@ } } - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var marketplaceButton = tablet.addButton({ icon: "icons/tablet-icons/market-i.svg", activeIcon: "icons/tablet-icons/market-a.svg", diff --git a/scripts/system/menu.js b/scripts/system/menu.js index c7a44d3e48..004ece17c3 100644 --- a/scripts/system/menu.js +++ b/scripts/system/menu.js @@ -13,7 +13,7 @@ var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet- // var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; (function() { - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/menu-i.svg", activeIcon: "icons/tablet-icons/menu-a.svg", diff --git a/scripts/system/mod.js b/scripts/system/mod.js index a3b4974f8d..defdb662b3 100644 --- a/scripts/system/mod.js +++ b/scripts/system/mod.js @@ -18,7 +18,7 @@ Script.include("/~/system/libraries/controllers.js"); // grab the toolbar -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var ASSETS_PATH = Script.resolvePath("assets"); var TOOLS_PATH = Script.resolvePath("assets/images/tools/"); diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index b6ddd9d33e..612c0e50e2 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Script, Settings, Window, Controller, Overlays, SoundArray, LODManager, MyAvatar, Tablet, Camera, HMD, Menu, Quat, Vec3*/ +/*global Script, Settings, Window, Controller, Overlays, SoundArray, LODManager, MyAvatar, Tablets, Camera, HMD, Menu, Quat, Vec3*/ // // notifications.js // Version 0.801 @@ -696,7 +696,7 @@ Window.announcement.connect(onNotify); Window.notifyEditError = onEditError; Window.notify = onNotify; - Tablet.tabletNotification.connect(tabletNotification); + Tablets.tabletNotification.connect(tabletNotification); Wallet.walletNotSetup.connect(walletNotSetup); Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 05a7dc8975..26bec518b4 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Tablet, Settings, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, HMD, Controller, Account, UserActivityLogger, Messages, Window, XMLHttpRequest, print, location, getControllerWorldLocation*/ +/*global Tablets, Settings, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, HMD, Controller, Account, UserActivityLogger, Messages, Window, XMLHttpRequest, print, location, getControllerWorldLocation*/ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // pal.js @@ -677,7 +677,7 @@ var buttonName = "PEOPLE"; var tablet = null; function startup() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ text: buttonName, icon: "icons/tablet-icons/people-i.svg", diff --git a/scripts/system/particle_explorer/particleExplorerTool.js b/scripts/system/particle_explorer/particleExplorerTool.js index d85fc169b1..c2231df406 100644 --- a/scripts/system/particle_explorer/particleExplorerTool.js +++ b/scripts/system/particle_explorer/particleExplorerTool.js @@ -17,7 +17,7 @@ var PARTICLE_EXPLORER_HTML_URL = Script.resolvePath('particleExplorer.html'); ParticleExplorerTool = function() { var that = {}; that.createWebView = function() { - that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + that.webView = Tablets.getTablet("com.highfidelity.interface.tablet.system"); that.webView.setVisible = function(value) {}; that.webView.webEventReceived.connect(that.webEventReceived); } diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 9afdb4ec53..3f29238c24 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -7,7 +7,7 @@ // Distributed under the Apache License, Version 2.0 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablet, Script, HMD, Settings, DialogsManager, Menu, Reticle, OverlayWebWindow, Desktop, Account, MyAvatar, Snapshot */ +/* globals Tablets, Script, HMD, Settings, DialogsManager, Menu, Reticle, OverlayWebWindow, Desktop, Account, MyAvatar, Snapshot */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function () { // BEGIN LOCAL_SCOPE @@ -22,7 +22,7 @@ var clearOverlayWhenMoving; var buttonName = "SNAP"; var buttonConnected = false; -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/snap-i.svg", activeIcon: "icons/tablet-icons/snap-a.svg", diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 2a0e827932..41b7b84d4c 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Window, Script, Tablet, HMD, Controller, Account, XMLHttpRequest, location, print*/ +/*global Window, Script, Tablets, HMD, Controller, Account, XMLHttpRequest, location, print*/ // // goto.js @@ -30,7 +30,7 @@ var shouldActivateButton = false; function ignore() { } - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var NORMAL_ICON = "icons/tablet-icons/goto-i.svg"; var NORMAL_ACTIVE = "icons/tablet-icons/goto-a.svg"; var WAITING_ICON = "icons/tablet-icons/goto-msg.svg"; diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 17821c737e..0044ca0496 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablet, Overlays, +/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablets, Overlays, MyAvatar, Menu, AvatarInputs, Vec3 */ (function() { // BEGIN LOCAL_SCOPE @@ -33,7 +33,7 @@ function checkTablet() { if (gTablet === null) { - gTablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + gTablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); } } @@ -315,7 +315,7 @@ Script.scriptEnding.connect(function () { // if we reload scripts in tablet mode make sure we close the currently open window, by calling gotoHomeScreen - var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tabletProxy = Tablets.getTablet("com.highfidelity.interface.tablet.system"); if (tabletProxy && tabletProxy.toolbarMode) { tabletProxy.gotoHomeScreen(); } diff --git a/scripts/system/tablet-users.js b/scripts/system/tablet-users.js index 6f37cd55eb..7efd49ae55 100644 --- a/scripts/system/tablet-users.js +++ b/scripts/system/tablet-users.js @@ -33,7 +33,7 @@ GlobalServices.findableBy = myVisibility; } - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/users-i.svg", activeIcon: "icons/tablet-icons/users-a.svg", diff --git a/scripts/tutorials/createFloatingLanternBox.js b/scripts/tutorials/createFloatingLanternBox.js index c84214e295..c83535fa37 100644 --- a/scripts/tutorials/createFloatingLanternBox.js +++ b/scripts/tutorials/createFloatingLanternBox.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // createFloatinLanternBox.js diff --git a/scripts/tutorials/createTetherballStick.js b/scripts/tutorials/createTetherballStick.js index 35f5fb0344..3ad0939c2e 100644 --- a/scripts/tutorials/createTetherballStick.js +++ b/scripts/tutorials/createTetherballStick.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // createTetherballStick.js diff --git a/scripts/tutorials/entity_scripts/floatingLantern.js b/scripts/tutorials/entity_scripts/floatingLantern.js index aa25dc0003..c2a79c9c5b 100644 --- a/scripts/tutorials/entity_scripts/floatingLantern.js +++ b/scripts/tutorials/entity_scripts/floatingLantern.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // floatinLantern.js diff --git a/scripts/tutorials/entity_scripts/floatingLanternBox.js b/scripts/tutorials/entity_scripts/floatingLanternBox.js index b5fb0c27d9..b8e0fbda3e 100644 --- a/scripts/tutorials/entity_scripts/floatingLanternBox.js +++ b/scripts/tutorials/entity_scripts/floatingLanternBox.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // floatingLanternBox.js diff --git a/scripts/tutorials/entity_scripts/tetherballStick.js b/scripts/tutorials/entity_scripts/tetherballStick.js index 867074abd4..50bac88caf 100644 --- a/scripts/tutorials/entity_scripts/tetherballStick.js +++ b/scripts/tutorials/entity_scripts/tetherballStick.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // tetherballStick.js diff --git a/tests/shared/src/PathUtilsTests.cpp b/tests/shared/src/PathUtilsTests.cpp new file mode 100644 index 0000000000..fc31d475d0 --- /dev/null +++ b/tests/shared/src/PathUtilsTests.cpp @@ -0,0 +1,28 @@ +// +// Created by Bradley Austin Davis on 2017/11/08 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#include "PathUtilsTests.h" + +#include + +#include + + +QTEST_MAIN(PathUtilsTests) + +void PathUtilsTests::testPathUtils() { + QString result = PathUtils::qmlBasePath(); +#if DEV_BUILD + QVERIFY(result.startsWith("file:///")); +#else + QVERIFY(result.startsWith("qrc:///")); +#endif + QVERIFY(result.endsWith("/")); +} + diff --git a/tests/shared/src/PathUtilsTests.h b/tests/shared/src/PathUtilsTests.h new file mode 100644 index 0000000000..8ae410d6cb --- /dev/null +++ b/tests/shared/src/PathUtilsTests.h @@ -0,0 +1,20 @@ +// +// Created by Bradley Austin Davis on 2017/11/08 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_PathUtilsTests_h +#define hifi_PathUtilsTests_h + +#include + +class PathUtilsTests : public QObject { + Q_OBJECT +private slots: + void testPathUtils(); +}; + +#endif // hifi_PathUtilsTests_h diff --git a/unpublishedScripts/marketplace/blocks/blocksApp.js b/unpublishedScripts/marketplace/blocks/blocksApp.js index c9e8682b23..8088f438de 100644 --- a/unpublishedScripts/marketplace/blocks/blocksApp.js +++ b/unpublishedScripts/marketplace/blocks/blocksApp.js @@ -26,7 +26,7 @@ APP_URL = APP_OUTDATED_URL; } - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: APP_ICON, activeIcon: APP_ICON_ACTIVE, diff --git a/unpublishedScripts/marketplace/camera-move/app-camera-move.js b/unpublishedScripts/marketplace/camera-move/app-camera-move.js index f58dd3d3bd..177565a332 100644 --- a/unpublishedScripts/marketplace/camera-move/app-camera-move.js +++ b/unpublishedScripts/marketplace/camera-move/app-camera-move.js @@ -162,7 +162,7 @@ var globalState = { function main() { log('initializing...', VERSION); - var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'), + var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'), button = tablet.addButton(BUTTON_CONFIG); Script.scriptEnding.connect(function() { @@ -601,7 +601,7 @@ function _patchCameraModeSetting() { } function getSystemMetadata() { - var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'); + var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'); return { mode: { hmd: HMD.active, diff --git a/unpublishedScripts/marketplace/clap/clapApp.js b/unpublishedScripts/marketplace/clap/clapApp.js index b2d8ce55db..a975d9d8b5 100644 --- a/unpublishedScripts/marketplace/clap/clapApp.js +++ b/unpublishedScripts/marketplace/clap/clapApp.js @@ -16,7 +16,7 @@ // Load up engine var APP_NAME = "CLAP"; var ClapEngine = Script.require(Script.resolvePath("scripts/ClapEngine.js?v9")); -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); // Define Menu var blackIcon = Script.resolvePath("icons/tablet-icons/clap-a.svg?foxv2"); diff --git a/unpublishedScripts/marketplace/doppleganger-attachments/app-doppleganger-attachments.js b/unpublishedScripts/marketplace/doppleganger-attachments/app-doppleganger-attachments.js index c09ad602f8..278f4efbaa 100644 --- a/unpublishedScripts/marketplace/doppleganger-attachments/app-doppleganger-attachments.js +++ b/unpublishedScripts/marketplace/doppleganger-attachments/app-doppleganger-attachments.js @@ -45,7 +45,7 @@ var buttonConfig = utils.assign({ activeIcon: require('./doppleganger-a.svg.json'), }); -var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'), +var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'), button = tablet.addButton(buttonConfig); Script.scriptEnding.connect(function() { diff --git a/unpublishedScripts/marketplace/doppleganger-attachments/dist/app-doppleganger-marketplace.js b/unpublishedScripts/marketplace/doppleganger-attachments/dist/app-doppleganger-marketplace.js index bc5368ba5b..1cb7610ff3 100644 --- a/unpublishedScripts/marketplace/doppleganger-attachments/dist/app-doppleganger-marketplace.js +++ b/unpublishedScripts/marketplace/doppleganger-attachments/dist/app-doppleganger-marketplace.js @@ -905,7 +905,7 @@ var buttonConfig = utils.assign({ activeIcon: __webpack_require__(7), }); -var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'), +var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'), button = tablet.addButton(buttonConfig); Script.scriptEnding.connect(function() { diff --git a/unpublishedScripts/marketplace/doppleganger-mirror/app-doppleganger.js b/unpublishedScripts/marketplace/doppleganger-mirror/app-doppleganger.js index f4c7bf99c0..d02dd3e9ba 100644 --- a/unpublishedScripts/marketplace/doppleganger-mirror/app-doppleganger.js +++ b/unpublishedScripts/marketplace/doppleganger-mirror/app-doppleganger.js @@ -12,7 +12,7 @@ var DopplegangerClass = Script.require('./doppleganger.js'); -var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'), +var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'), button = tablet.addButton({ icon: Script.resolvePath('./doppleganger-i.svg'), activeIcon: Script.resolvePath('./doppleganger-a.svg'), diff --git a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js index b4d01e77cf..687c9445cd 100644 --- a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js +++ b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js @@ -19,7 +19,7 @@ var lib = Script.require("https://hifi-content.s3.amazonaws.com/elisalj/emoji_sc var APP_NAME = "EMOJIS"; var APP_URL = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/emojiTabletUI.html?" + Date.now(); var APP_ICON = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/icons/emoji-i.svg"; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: APP_ICON, diff --git a/unpublishedScripts/marketplace/laser/laserPointerApp.js b/unpublishedScripts/marketplace/laser/laserPointerApp.js index 515a2c3a76..32cc75dd42 100644 --- a/unpublishedScripts/marketplace/laser/laserPointerApp.js +++ b/unpublishedScripts/marketplace/laser/laserPointerApp.js @@ -17,7 +17,7 @@ var TRIGGER_PRESSURE = 0.95; - var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'); + var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'); var button = tablet.addButton({ icon: APP_ICON, diff --git a/unpublishedScripts/marketplace/record/record.js b/unpublishedScripts/marketplace/record/record.js index 68c7ea3f5a..6392f10892 100644 --- a/unpublishedScripts/marketplace/record/record.js +++ b/unpublishedScripts/marketplace/record/record.js @@ -631,7 +631,7 @@ } function setUp() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { return; } @@ -694,7 +694,7 @@ } // FIXME: If setUp() is run immediately at Interface start-up, Interface hangs and crashes because of the line of code: - // tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + // tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); //setUp(); //Script.scriptEnding.connect(tearDown); Script.setTimeout(function () { diff --git a/unpublishedScripts/marketplace/shapes/shapes.js b/unpublishedScripts/marketplace/shapes/shapes.js index cd5f119588..de177f435e 100644 --- a/unpublishedScripts/marketplace/shapes/shapes.js +++ b/unpublishedScripts/marketplace/shapes/shapes.js @@ -1930,7 +1930,7 @@ function setUp() { var hasRezPermissions; - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { App.log("ERROR: Tablet not found! App not started."); return; diff --git a/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js b/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js index 7bc65722cd..114bccb034 100644 --- a/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js +++ b/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js @@ -28,7 +28,7 @@ } } - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: ICONS.icon, activeIcon: ICONS.activeIcon, diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js index 76044d2975..cc600632e5 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Tablet, Script, */ +/*global Tablets, Script, */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // spectatorCamera.js @@ -188,7 +188,7 @@ // -tablet: The tablet instance to be modified. var tablet = null; function startup() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); addOrRemoveButton(false, HMD.active); tablet.screenChanged.connect(onTabletScreenChanged); Window.domainChanged.connect(onDomainChanged); diff --git a/unpublishedScripts/marketplace/tablet-raiseHand/tablet-raiseHand.js b/unpublishedScripts/marketplace/tablet-raiseHand/tablet-raiseHand.js index f7702053a4..2f895d5f94 100644 --- a/unpublishedScripts/marketplace/tablet-raiseHand/tablet-raiseHand.js +++ b/unpublishedScripts/marketplace/tablet-raiseHand/tablet-raiseHand.js @@ -20,7 +20,7 @@ var isRaiseHandButtonActive = false; var animHandlerId; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: BUTTON_NAME, icon: "icons/tablet-icons/raise-hand-i.svg", From 8f85c7650b88a7e5e91a90f66f4b09d35fa25b02 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 13 Nov 2017 14:16:04 -0800 Subject: [PATCH 021/102] Make sure loaded components get the right parent context --- interface/resources/qml/hifi/tablet/WindowRoot.qml | 7 +------ libraries/ui/src/ui/OffscreenQmlSurface.cpp | 9 ++++++--- libraries/ui/src/ui/OffscreenQmlSurface.h | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/WindowRoot.qml b/interface/resources/qml/hifi/tablet/WindowRoot.qml index 0b631326f4..9c027308b8 100644 --- a/interface/resources/qml/hifi/tablet/WindowRoot.qml +++ b/interface/resources/qml/hifi/tablet/WindowRoot.qml @@ -64,8 +64,8 @@ Windows.ScrollingWindow { function loadWebContent(source, url, injectJavaScriptUrl) { loader.load(source, function() { - loader.item.url = url loader.item.scriptURL = injectJavaScriptUrl; + loader.item.url = url; if (loader.item.hasOwnProperty("closeButtonVisible")) { loader.item.closeButtonVisible = false; } @@ -146,11 +146,6 @@ Windows.ScrollingWindow { } function load(newSource, callback) { - if (loader.source == newSource) { - loader.loaded(); - return; - } - if (loader.item) { loader.item.destroy(); loader.item = null; diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index aab89ccd4d..a0c6790b93 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -697,13 +697,16 @@ QQuickItem* OffscreenQmlSurface::getRootItem() { return _rootItem; } -QQmlContext* OffscreenQmlSurface::contextForUrl(const QUrl& qmlSource, bool forceNewContext) { +QQmlContext* OffscreenQmlSurface::contextForUrl(const QUrl& qmlSource, QQuickItem* parent, bool forceNewContext) { // Get any whitelist functionality QList callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource); // If we have whitelisted content, we must load a new context forceNewContext |= !callbacks.empty(); - QQmlContext* targetContext = _qmlContext; + QQmlContext* targetContext = parent ? QQmlEngine::contextForObject(parent) : _qmlContext; + if (!targetContext) { + targetContext = _qmlContext; + } if (_rootItem && forceNewContext) { targetContext = new QQmlContext(targetContext); } @@ -737,7 +740,7 @@ void OffscreenQmlSurface::loadInternal(const QUrl& qmlSource, bool createNewCont finalQmlSource = _qmlContext->resolvedUrl(qmlSource); } - auto targetContext = contextForUrl(finalQmlSource, createNewContext); + auto targetContext = contextForUrl(finalQmlSource, parent, createNewContext); auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); if (qmlComponent->isLoading()) { connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 2d2eb0811b..62754efe14 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -130,7 +130,7 @@ protected: private: static QOpenGLContext* getSharedContext(); - QQmlContext* contextForUrl(const QUrl& url, bool forceNewContext = false); + QQmlContext* contextForUrl(const QUrl& url, QQuickItem* parent, bool forceNewContext = false); void loadInternal(const QUrl& qmlSource, bool createNewContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback); void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); From d71fd151c5b802c66479ad4fae6c960fc7b7891c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 13 Nov 2017 16:45:27 -0800 Subject: [PATCH 022/102] Fixing button model exposure --- interface/resources/qml/hifi/Desktop.qml | 4 +- .../resources/qml/hifi/toolbars/Toolbar.qml | 127 +++-------- .../qml/hifi/toolbars/ToolbarButton.qml | 3 +- interface/src/Application.cpp | 4 + libraries/ui/src/OffscreenUi.cpp | 3 + .../ui/src/ui/TabletScriptingInterface.cpp | 204 ++++++------------ .../ui/src/ui/TabletScriptingInterface.h | 66 ++++-- tests/shared/src/PathUtilsTests.cpp | 1 - 8 files changed, 149 insertions(+), 263 deletions(-) diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index ea9ec2f6c9..960d3e0649 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -45,11 +45,13 @@ OriginalDesktop.Desktop { Toolbar { id: sysToolbar; objectName: "com.highfidelity.interface.toolbar.system"; + property var tablet: Tablets.getTablet("com.highfidelity.interface.tablet.system"); anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined; // Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained. x: sysToolbar.x y: 50 - shown: true + buttonModel: tablet.buttons; + shown: tablet.toolbarMode; } Settings { diff --git a/interface/resources/qml/hifi/toolbars/Toolbar.qml b/interface/resources/qml/hifi/toolbars/Toolbar.qml index 01aa29f665..ff7e835690 100644 --- a/interface/resources/qml/hifi/toolbars/Toolbar.qml +++ b/interface/resources/qml/hifi/toolbars/Toolbar.qml @@ -11,6 +11,8 @@ Window { horizontalSpacers: horizontal verticalSpacers: !horizontal } + property var tabletProxy; + property var buttonModel: ListModel {} hideBackground: true resizable: false destroyOnCloseButton: false @@ -23,24 +25,32 @@ Window { activator: Item {} property bool horizontal: true property real buttonSize: 50; - property var buttons: [] - property var container: horizontal ? row : column Settings { category: "toolbar/" + window.objectName property alias x: window.x property alias y: window.y } + + Component { + id: buttonComponent + ToolbarButton { + id: toolbarButton + property var proxy: modelData; + onClicked: proxy.clicked() + Component.onCompleted: updateProperties() - onHorizontalChanged: { - var newParent = horizontal ? row : column; - for (var i in buttons) { - var child = buttons[i]; - child.parent = newParent; - if (horizontal) { - child.y = 0 - } else { - child.x = 0 + Connections { + target: proxy; + onPropertiesChanged: updateProperties(); + } + + function updateProperties() { + Object.keys(proxy.properties).forEach(function (key) { + if (toolbarButton[key] !== proxy.properties[key]) { + toolbarButton[key] = proxy.properties[key]; + } + }); } } } @@ -52,97 +62,22 @@ Window { Row { id: row + visible: window.horizontal spacing: 6 + Repeater { + model: buttonModel + delegate: buttonComponent + } } - + Column { id: column + visible: !window.horizontal spacing: 6 - } - - Component { id: toolbarButtonBuilder; ToolbarButton { } } - } - - - function findButtonIndex(name) { - if (!name) { - return -1; - } - - for (var i in buttons) { - var child = buttons[i]; - if (child.objectName === name) { - return i; + Repeater { + model: buttonModel + delegate: buttonComponent } } - return -1; - } - - function findButton(name) { - var index = findButtonIndex(name); - if (index < 0) { - return; - } - return buttons[index]; - } - - function sortButtons() { - var children = []; - for (var i = 0; i < container.children.length; i++) { - children[i] = container.children[i]; - } - - children.sort(function (a, b) { - if (a.sortOrder === b.sortOrder) { - // subsort by stableOrder, because JS sort is not stable in qml. - return a.stableOrder - b.stableOrder; - } else { - return a.sortOrder - b.sortOrder; - } - }); - - container.children = children; - } - - function addButton(properties) { - properties = properties || {} - - // If a name is specified, then check if there's an existing button with that name - // and return it if so. This will allow multiple clients to listen to a single button, - // and allow scripts to be idempotent so they don't duplicate buttons if they're reloaded - var result = findButton(properties.objectName); - if (result) { - for (var property in properties) { - result[property] = properties[property]; - } - return result; - } - properties.toolbar = this; - properties.opacity = 0; - result = toolbarButtonBuilder.createObject(container, properties); - buttons.push(result); - - result.opacity = 1; - - sortButtons(); - - fadeIn(null); - - return result; - } - - function removeButton(name) { - var index = findButtonIndex(name); - if (index < -1) { - console.warn("Tried to remove non-existent button " + name); - return; - } - - buttons[index].destroy(); - buttons.splice(index, 1); - - if (buttons.length === 0) { - fadeOut(null); - } } } diff --git a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml index 63149ad23b..3c64d4bf2e 100644 --- a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml +++ b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml @@ -25,7 +25,8 @@ StateImage { property string activeHoverIcon: button.activeIcon property int sortOrder: 100 - property int stableSortOrder: 0 + property int stableOrder: 0 + property var uuid; signal clicked() diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d388128709..2d7ae29379 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2234,6 +2234,10 @@ void Application::initializeUi() { qmlRegisterType("Hifi", 1, 0, "ResourceImageItem"); qmlRegisterType("Hifi", 1, 0, "Preference"); + { + auto tabletScriptingInterface = DependencyManager::get(); + tabletScriptingInterface->getTablet(SYSTEM_TABLET); + } auto offscreenUi = DependencyManager::get(); offscreenUi->create(); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 252c08a1f0..d8a2c2c3cb 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -106,6 +106,9 @@ void OffscreenUi::create() { myContext->setContextProperty("offscreenFlags", offscreenFlags = new OffscreenFlags()); myContext->setContextProperty("fileDialogHelper", new FileDialogHelper()); auto tabletScriptingInterface = DependencyManager::get(); + qRegisterMetaType(); + qRegisterMetaType(); + myContext->setContextProperty("Tablets", tabletScriptingInterface.data()); TabletProxy* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"); myContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership); } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 93d493539e..f006547e2b 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -32,6 +32,14 @@ const QString SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system"; const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; const QString TabletScriptingInterface::QML = "hifi/tablet/TabletRoot.qml"; +static QString getUsername() { + QString username = "Unknown user"; + auto accountManager = DependencyManager::get(); + if (accountManager->isLoggedIn()) { + username = accountManager->getAccountInfo().getUsername(); + } + return username; +} static Setting::Handle tabletSoundsButtonClick("TabletSounds", QStringList { "/sounds/Button06.wav", "/sounds/Button04.wav", @@ -39,6 +47,51 @@ static Setting::Handle tabletSoundsButtonClick("TabletSounds", QStr "/sounds/Tab01.wav", "/sounds/Tab02.wav" }); +TabletButtonListModel::TabletButtonListModel() { + +} + +TabletButtonListModel::~TabletButtonListModel() { + +} + +enum ButtonDeviceRole { + ButtonProxyRole = Qt::UserRole, +}; + +QHash TabletButtonListModel::_roles{ + { ButtonProxyRole, "buttonProxy" }, +}; + +Qt::ItemFlags TabletButtonListModel::_flags{ Qt::ItemIsSelectable | Qt::ItemIsEnabled }; + +QVariant TabletButtonListModel::data(const QModelIndex& index, int role) const { + if (!index.isValid() || index.row() >= rowCount() || role != ButtonProxyRole) { + return QVariant(); + } + + return QVariant::fromValue(_buttons.at(index.row()).data()); +} + +TabletButtonProxy* TabletButtonListModel::addButton(const QVariant& properties) { + auto tabletButtonProxy = QSharedPointer(new TabletButtonProxy(properties.toMap())); + beginResetModel(); + _buttons.push_back(tabletButtonProxy); + endResetModel(); + return tabletButtonProxy.data(); +} + +void TabletButtonListModel::removeButton(TabletButtonProxy* button) { + auto itr = std::find(_buttons.begin(), _buttons.end(), button); + if (itr == _buttons.end()) { + qCWarning(uiLogging) << "TabletProxy::removeButton() could not find button " << button; + return; + } + beginResetModel(); + _buttons.erase(itr); + endResetModel(); +} + TabletScriptingInterface::TabletScriptingInterface() { qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletEnums"); } @@ -232,15 +285,6 @@ TabletProxy::~TabletProxy() { disconnect(this, &TabletProxy::tabletShownChanged, this, &TabletProxy::onTabletShown); } -QVariant TabletProxy::getButtons() { - Q_ASSERT(QThread::currentThread() == qApp->thread()); - QVariantList result; - for (const auto& button : _tabletButtonProxies) { - result.push_back(QVariant::fromValue(button.data())); - } - return result; -} - void TabletProxy::setToolbarMode(bool toolbarMode) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setToolbarMode", Q_ARG(bool, toolbarMode)); @@ -256,8 +300,6 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { auto offscreenUi = DependencyManager::get(); if (toolbarMode) { - addButtonsToToolbar(); - // create new desktop window auto tabletRootWindow = new TabletRootWindow(); tabletRootWindow->initQml(QVariantMap()); @@ -272,11 +314,7 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { // forward qml surface events to interface js connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml); } else { - removeButtonsFromToolbar(); - - if (_currentPathLoaded == TABLET_HOME_SOURCE_URL) { - // Tablet QML now pulls buttons from Tablet proxy - } else { + if (_currentPathLoaded != TABLET_HOME_SOURCE_URL) { loadHomeScreen(true); } //check if running scripts window opened and save it for reopen in Tablet @@ -290,44 +328,8 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { _desktopWindow = nullptr; } } -} -#if 0 -static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* buttonProxy) { - Q_ASSERT(QThread::currentThread() == qApp->thread()); - if (buttonProxy == NULL){ - qCCritical(uiLogging) << __FUNCTION__ << "buttonProxy is NULL"; - return; - } - - QVariant resultVar; - qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << "adding button " << buttonProxy; - bool hasResult = QMetaObject::invokeMethod(qmlTablet, "addButtonProxy", Qt::DirectConnection, - Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, buttonProxy->getProperties())); - if (!hasResult) { - qCWarning(uiLogging) << __FUNCTION__ << " has no result"; - return; - } - - QObject* qmlButton = qvariant_cast(resultVar); - if (!qmlButton) { - qCWarning(uiLogging) << "TabletScriptingInterface addButtonProxyToQmlTablet result not a QObject"; - return; - } - QObject::connect(qmlButton, SIGNAL(clicked()), buttonProxy, SLOT(clickedSlot())); - buttonProxy->setQmlButton(qobject_cast(qmlButton)); -} -#endif - - -static QString getUsername() { - QString username = "Unknown user"; - auto accountManager = DependencyManager::get(); - if (accountManager->isLoggedIn()) { - return accountManager->getAccountInfo().getUsername(); - } else { - return "Unknown user"; - } + emit toolbarModeChanged(); } void TabletProxy::initialScreen(const QVariant& url) { @@ -702,20 +704,7 @@ TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { return result; } - auto tabletButtonProxy = QSharedPointer(new TabletButtonProxy(properties.toMap())); - _tabletButtonProxies.push_back(tabletButtonProxy); - if (!_toolbarMode && _qmlTabletRoot) { - // Tablet now pulls buttons from the tablet proxy - // FIXME emit a signal so that the tablet can refresh buttons if they change - } else if (_toolbarMode) { - auto toolbarProxy = DependencyManager::get()->getSystemToolbarProxy(); - if (toolbarProxy) { - // copy properties from tablet button proxy to toolbar button proxy. - auto toolbarButtonProxy = toolbarProxy->addButton(tabletButtonProxy->getProperties()); - tabletButtonProxy->setToolbarButtonProxy(toolbarButtonProxy); - } - } - return tabletButtonProxy.data(); + return _buttons.addButton(properties); } bool TabletProxy::onHomeScreen() { @@ -734,35 +723,7 @@ void TabletProxy::removeButton(TabletButtonProxy* tabletButtonProxy) { return; } - auto tablet = getQmlTablet(); - if (!tablet) { - qCCritical(uiLogging) << "Could not find tablet in TabletRoot.qml"; - } - - QSharedPointer buttonProxy; - { - auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy); - if (iter == _tabletButtonProxies.end()) { - qCWarning(uiLogging) << "TabletProxy::removeButton() could not find button " << tabletButtonProxy; - return; - } - buttonProxy = *iter; - _tabletButtonProxies.erase(iter); - } - - if (!_toolbarMode && _qmlTabletRoot) { - buttonProxy->setQmlButton(nullptr); - if (tablet) { - QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getProperties())); - } - } else if (_toolbarMode) { - auto toolbarProxy = DependencyManager::get()->getSystemToolbarProxy(); - // remove button from toolbarProxy - if (toolbarProxy) { - toolbarProxy->removeButton(buttonProxy->getUuid().toString()); - buttonProxy->setToolbarButtonProxy(nullptr); - } - } + _buttons.removeButton(tabletButtonProxy); } void TabletProxy::emitScriptEvent(const QVariant& msg) { @@ -801,27 +762,6 @@ void TabletProxy::desktopWindowClosed() { gotoHomeScreen(); } -void TabletProxy::addButtonsToToolbar() { - Q_ASSERT(QThread::currentThread() == thread()); - ToolbarProxy* toolbarProxy = DependencyManager::get()->getSystemToolbarProxy(); - for (auto& buttonProxy : _tabletButtonProxies) { - // copy properties from tablet button proxy to toolbar button proxy. - buttonProxy->setToolbarButtonProxy(toolbarProxy->addButton(buttonProxy->getProperties())); - } - - // make the toolbar visible - toolbarProxy->writeProperty("visible", QVariant(true)); -} - -void TabletProxy::removeButtonsFromToolbar() { - Q_ASSERT(QThread::currentThread() == thread()); - ToolbarProxy* toolbarProxy = DependencyManager::get()->getSystemToolbarProxy(); - for (auto& buttonProxy : _tabletButtonProxies) { - // remove button from toolbarProxy - toolbarProxy->removeButton(buttonProxy->getUuid().toString()); - buttonProxy->setToolbarButtonProxy(nullptr); - } -} QQuickItem* TabletProxy::getQmlTablet() const { if (!_qmlTabletRoot) { @@ -891,25 +831,6 @@ TabletButtonProxy::~TabletButtonProxy() { } } -void TabletButtonProxy::setQmlButton(QQuickItem* qmlButton) { - Q_ASSERT(QThread::currentThread() == qApp->thread()); - if (_qmlButton) { - QObject::disconnect(_qmlButton, &QQuickItem::destroyed, this, nullptr); - } - _qmlButton = qmlButton; - if (_qmlButton) { - QObject::connect(_qmlButton, &QQuickItem::destroyed, this, [this] { _qmlButton = nullptr; }); - } -} - -void TabletButtonProxy::setToolbarButtonProxy(QObject* toolbarButtonProxy) { - Q_ASSERT(QThread::currentThread() == thread()); - _toolbarButtonProxy = toolbarButtonProxy; - if (_toolbarButtonProxy) { - QObject::connect(_toolbarButtonProxy, SIGNAL(clicked()), this, SLOT(clickedSlot())); - } -} - QVariantMap TabletButtonProxy::getProperties() { if (QThread::currentThread() != thread()) { QVariantMap result; @@ -926,20 +847,19 @@ void TabletButtonProxy::editProperties(const QVariantMap& properties) { return; } + bool changed = false; QVariantMap::const_iterator iter = properties.constBegin(); while (iter != properties.constEnd()) { const auto& key = iter.key(); const auto& value = iter.value(); if (!_properties.contains(key) || _properties[key] != value) { - _properties[iter.key()] = iter.value(); - if (_qmlButton) { - QMetaObject::invokeMethod(_qmlButton, "changeProperty", Qt::AutoConnection, Q_ARG(QVariant, QVariant(iter.key())), Q_ARG(QVariant, iter.value())); - } + _properties[key] = value; + changed = true; } ++iter; } - if (_toolbarButtonProxy) { - QMetaObject::invokeMethod(_toolbarButtonProxy, "editProperties", Qt::AutoConnection, Q_ARG(QVariantMap, properties)); + if (changed) { + emit propertiesChanged(); } } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index e7dc5ede1f..718d5123db 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -12,13 +12,16 @@ #include #include -#include -#include +#include +#include +#include +#include + #include -#include -#include -#include -#include +#include +#include + +#include #include #include @@ -90,6 +93,31 @@ protected: bool _toolbarMode { false }; }; +class TabletButtonListModel : public QAbstractListModel { + Q_OBJECT + +public: + TabletButtonListModel(); + ~TabletButtonListModel(); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override { Q_UNUSED(parent); return (int)_buttons.size(); } + QHash roleNames() const override { return _roles; } + Qt::ItemFlags flags(const QModelIndex& index) const override { return _flags; } + QVariant data(const QModelIndex& index, int role) const override; + + +protected: + friend class TabletProxy; + TabletButtonProxy* addButton(const QVariant& properties); + void removeButton(TabletButtonProxy* button); + using List = std::list>; + static QHash _roles; + static Qt::ItemFlags _flags; + std::vector> _buttons; +}; + +Q_DECLARE_METATYPE(TabletButtonListModel*); + /**jsdoc * @class TabletProxy * @property name {string} READ_ONLY: name of this tablet @@ -99,9 +127,10 @@ protected: class TabletProxy : public QObject { Q_OBJECT Q_PROPERTY(QString name READ getName) - Q_PROPERTY(bool toolbarMode READ getToolbarMode WRITE setToolbarMode) + Q_PROPERTY(bool toolbarMode READ getToolbarMode WRITE setToolbarMode NOTIFY toolbarModeChanged) Q_PROPERTY(bool landscape READ getLandscape WRITE setLandscape) Q_PROPERTY(bool tabletShown MEMBER _tabletShown NOTIFY tabletShownChanged) + Q_PROPERTY(TabletButtonListModel* buttons READ getButtons CONSTANT) public: TabletProxy(QObject* parent, const QString& name); ~TabletProxy(); @@ -196,8 +225,6 @@ public: Q_INVOKABLE bool isPathLoaded(const QVariant& path); - Q_INVOKABLE QVariant getButtons(); - QQuickItem* getTabletRoot() const { return _qmlTabletRoot; } OffscreenQmlSurface* getTabletSurface(); @@ -206,6 +233,7 @@ public: QQuickItem* getQmlMenu() const; + TabletButtonListModel* getButtons() { return &_buttons; } signals: /**jsdoc * Signaled when this tablet receives an event from the html/js embedded in the tablet @@ -238,20 +266,20 @@ signals: */ void tabletShownChanged(); + void toolbarModeChanged(); + protected slots: void desktopWindowClosed(); void emitWebEvent(const QVariant& msg); void onTabletShown(); + protected: void loadHomeScreen(bool forceOntoHomeScreen); - void addButtonsToToolbar(); - void removeButtonsFromToolbar(); bool _initialScreen { false }; QVariant _initialPath { "" }; QVariant _currentPathLoaded { "" }; QString _name; - std::vector> _tabletButtonProxies; QQuickItem* _qmlTabletRoot { nullptr }; OffscreenQmlSurface* _qmlOffscreenSurface { nullptr }; QmlWindowClass* _desktopWindow { nullptr }; @@ -262,6 +290,8 @@ protected: State _state { State::Uninitialized }; bool _landscape { false }; bool _showRunningScripts { false }; + + TabletButtonListModel _buttons; }; Q_DECLARE_METATYPE(TabletProxy*); @@ -273,15 +303,11 @@ Q_DECLARE_METATYPE(TabletProxy*); class TabletButtonProxy : public QObject { Q_OBJECT Q_PROPERTY(QUuid uuid READ getUuid) + Q_PROPERTY(QVariantMap properties READ getProperties NOTIFY propertiesChanged) public: TabletButtonProxy(const QVariantMap& properties); ~TabletButtonProxy(); - - Q_INVOKABLE void setQmlButton(QQuickItem* qmlButton); - - void setToolbarButtonProxy(QObject* toolbarButtonProxy); - QUuid getUuid() const { return _uuid; } /**jsdoc @@ -298,9 +324,6 @@ public: */ Q_INVOKABLE void editProperties(const QVariantMap& properties); -public slots: - void clickedSlot() { emit clicked(); } - signals: /**jsdoc * Signaled when this button has been clicked on by the user. @@ -308,12 +331,11 @@ signals: * @returns {Signal} */ void clicked(); + void propertiesChanged(); protected: QUuid _uuid; int _stableOrder; - QQuickItem* _qmlButton { nullptr }; - QObject* _toolbarButtonProxy { nullptr }; QVariantMap _properties; }; diff --git a/tests/shared/src/PathUtilsTests.cpp b/tests/shared/src/PathUtilsTests.cpp index fc31d475d0..1c445908f7 100644 --- a/tests/shared/src/PathUtilsTests.cpp +++ b/tests/shared/src/PathUtilsTests.cpp @@ -13,7 +13,6 @@ #include - QTEST_MAIN(PathUtilsTests) void PathUtilsTests::testPathUtils() { From 8f855c6c9568dc921783914818a859fcea3baeff Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 15 Nov 2017 09:21:10 -0800 Subject: [PATCH 023/102] Update QUrls --- interface/src/Application.cpp | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 60182ce5b6..76f8cc1505 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2234,27 +2234,27 @@ void Application::initializeUi() { context->setContextProperty("Commerce", new QmlCommerce()); }; OffscreenQmlSurface::addWhitelistContextHandler({ - QUrl{ "qrc:///qml/hifi/commerce/checkout/Checkout.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/common/CommerceLightbox.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/common/FirstUseTutorial.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/common/SortableListModel.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/purchases/PurchasedItem.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/purchases/Purchases.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/Help.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/NeedsLogIn.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/PassphraseChange.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/PassphraseModal.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/PassphraseSelection.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/Security.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/SecurityImageChange.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/SecurityImageModel.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/SecurityImageSelection.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/SendMoney.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/Wallet.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/WalletHome.qml" }, - QUrl{ "qrc:///qml/hifi/commerce/wallet/WalletSetup.qml" }, + QUrl{ "hifi/commerce/checkout/Checkout.qml" }, + QUrl{ "hifi/commerce/common/CommerceLightbox.qml" }, + QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, + QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" }, + QUrl{ "hifi/commerce/common/SortableListModel.qml" }, + QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, + QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" }, + QUrl{ "hifi/commerce/purchases/Purchases.qml" }, + QUrl{ "hifi/commerce/wallet/Help.qml" }, + QUrl{ "hifi/commerce/wallet/NeedsLogIn.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" }, + QUrl{ "hifi/commerce/wallet/Security.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" }, + QUrl{ "hifi/commerce/wallet/SendMoney.qml" }, + QUrl{ "hifi/commerce/wallet/Wallet.qml" }, + QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, + QUrl{ "hifi/commerce/wallet/WalletSetup.qml" }, }, callback); qmlRegisterType("Hifi", 1, 0, "ResourceImageItem"); qmlRegisterType("Hifi", 1, 0, "Preference"); From 64592d66d7aa6e08f05d21f2f40d824a6bd9a50c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 15 Nov 2017 11:46:56 -0800 Subject: [PATCH 024/102] Fix relative path for tablet login dialog --- scripts/system/libraries/accountUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/libraries/accountUtils.js b/scripts/system/libraries/accountUtils.js index 6df0aa3a87..69092b30fc 100644 --- a/scripts/system/libraries/accountUtils.js +++ b/scripts/system/libraries/accountUtils.js @@ -10,7 +10,7 @@ openLoginWindow = function openLoginWindow() { || (!HMD.active && Settings.getValue("desktopTabletBecomesToolbar", true))) { Menu.triggerOption("Login / Sign Up"); } else { - tablet.loadQMLOnTop("../../dialogs/TabletLoginDialog.qml"); + tablet.loadQMLOnTop("dialogs/TabletLoginDialog.qml"); HMD.openTablet(); } }; From 1167be410250d38979dd78a6b3d9983f472a0fa9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 15 Nov 2017 11:50:11 -0800 Subject: [PATCH 025/102] Reverting tablet API rename, cleaning up duplicated code --- interface/resources/qml/controls-uit/Button.qml | 4 ++-- interface/resources/qml/controls-uit/CheckBox.qml | 4 ++-- .../resources/qml/controls-uit/CheckBoxQQC2.qml | 4 ++-- interface/resources/qml/controls-uit/GlyphButton.qml | 4 ++-- interface/resources/qml/controls-uit/Key.qml | 4 ++-- interface/resources/qml/controls-uit/RadioButton.qml | 4 ++-- .../qml/dialogs/TabletConnectionFailureDialog.qml | 2 +- .../resources/qml/dialogs/TabletLoginDialog.qml | 4 ++-- .../qml/dialogs/preferences/ButtonPreference.qml | 4 ++-- .../qml/dialogs/preferences/CheckBoxPreference.qml | 4 ++-- interface/resources/qml/hifi/Card.qml | 6 +++--- interface/resources/qml/hifi/Desktop.qml | 2 +- interface/resources/qml/hifi/audio/MicBar.qml | 4 ++-- .../resources/qml/hifi/tablet/NewEntityButton.qml | 4 ++-- .../qml/hifi/tablet/TabletAddressDialog.qml | 4 ++-- .../qml/hifi/tablet/TabletAttachmentsDialog.qml | 2 +- interface/resources/qml/hifi/tablet/TabletButton.qml | 4 ++-- interface/resources/qml/hifi/tablet/TabletHome.qml | 2 +- .../resources/qml/hifi/tablet/TabletMenuView.qml | 4 ++-- .../tablet/tabletWindows/TabletPreferencesDialog.qml | 4 ++-- interface/src/Application.cpp | 3 +-- libraries/ui/src/OffscreenUi.cpp | 6 ------ libraries/ui/src/ui/OffscreenQmlSurface.cpp | 4 +++- scripts/developer/EZrecord.js | 2 +- scripts/developer/inputRecording.js | 2 +- scripts/developer/tests/dynamics/dynamicsTests.js | 2 +- scripts/developer/tests/puck-attach.js | 2 +- scripts/developer/tests/sliderTestMain.js | 2 +- scripts/developer/tests/tabletEventBridgeTest.js | 2 +- scripts/developer/tests/tabletTest.js | 2 +- scripts/developer/utilities/audio/stats.js | 2 +- scripts/developer/utilities/render/luci.js | 2 +- .../utilities/render/photobooth/photoboothApp.js | 2 +- scripts/system/audio.js | 2 +- scripts/system/audioScope.js | 2 +- scripts/system/bubble.js | 2 +- scripts/system/chat.js | 2 +- scripts/system/commerce/wallet.js | 2 +- scripts/system/controllers/godView.js | 2 +- scripts/system/edit.js | 12 ++++++------ scripts/system/fingerPaint.js | 2 +- scripts/system/generalSettings.js | 2 +- scripts/system/goto.js | 2 +- scripts/system/help.js | 2 +- scripts/system/hmd.js | 2 +- scripts/system/libraries/WebTablet.js | 4 ++-- scripts/system/libraries/entityList.js | 2 +- scripts/system/libraries/gridTool.js | 2 +- scripts/system/libraries/utils.js | 2 +- scripts/system/marketplaces/marketplace.js | 2 +- scripts/system/marketplaces/marketplaces.js | 2 +- scripts/system/menu.js | 2 +- scripts/system/mod.js | 2 +- scripts/system/notifications.js | 2 +- scripts/system/pal.js | 2 +- .../system/particle_explorer/particleExplorerTool.js | 2 +- scripts/system/snapshot.js | 2 +- scripts/system/tablet-goto.js | 2 +- scripts/system/tablet-ui/tabletUI.js | 4 ++-- scripts/system/tablet-users.js | 2 +- unpublishedScripts/marketplace/blocks/blocksApp.js | 2 +- .../marketplace/camera-move/app-camera-move.js | 4 ++-- unpublishedScripts/marketplace/clap/clapApp.js | 2 +- .../app-doppleganger-attachments.js | 2 +- .../dist/app-doppleganger-marketplace.js | 2 +- .../doppleganger-mirror/app-doppleganger.js | 2 +- .../marketplace/emoji-tablet/emojiTablet.js | 2 +- .../marketplace/laser/laserPointerApp.js | 2 +- unpublishedScripts/marketplace/record/record.js | 4 ++-- unpublishedScripts/marketplace/shapes/shapes.js | 2 +- .../marketplace/skyboxChanger/skyboxchanger.js | 2 +- .../marketplace/spectator-camera/spectatorCamera.js | 2 +- .../marketplace/tablet-raiseHand/tablet-raiseHand.js | 2 +- 73 files changed, 100 insertions(+), 105 deletions(-) diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index a305bea8dc..02c6181952 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -29,12 +29,12 @@ Original.Button { onHoveredChanged: { if (hovered) { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); } } onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } style: ButtonStyle { diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 37bc936aa1..e60f646327 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -31,12 +31,12 @@ Original.CheckBox { activeFocusOnPress: true onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } // TODO: doesnt works for QQC1. check with QQC2 // onHovered: { -// Tablets.playSound(TabletEnums.ButtonHover); +// Tablet.playSound(TabletEnums.ButtonHover); // } style: CheckBoxStyle { diff --git a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml index 404d83ebd2..12b8c80003 100644 --- a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml +++ b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml @@ -36,12 +36,12 @@ CheckBox { hoverEnabled: true onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } onHoveredChanged: { if (hovered) { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); } } diff --git a/interface/resources/qml/controls-uit/GlyphButton.qml b/interface/resources/qml/controls-uit/GlyphButton.qml index d225c8e1d1..9c23171ee1 100644 --- a/interface/resources/qml/controls-uit/GlyphButton.qml +++ b/interface/resources/qml/controls-uit/GlyphButton.qml @@ -27,12 +27,12 @@ Original.Button { onHoveredChanged: { if (hovered) { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); } } onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } style: ButtonStyle { diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controls-uit/Key.qml index 3ec579a4eb..54834549ae 100644 --- a/interface/resources/qml/controls-uit/Key.qml +++ b/interface/resources/qml/controls-uit/Key.qml @@ -35,13 +35,13 @@ Item { onContainsMouseChanged: { if (containsMouse) { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); } } onClicked: { mouse.accepted = true; - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); webEntity.synthesizeKeyPress(glyph); webEntity.synthesizeKeyPress(glyph, mirrorText); diff --git a/interface/resources/qml/controls-uit/RadioButton.qml b/interface/resources/qml/controls-uit/RadioButton.qml index da4e944f35..a818be072b 100644 --- a/interface/resources/qml/controls-uit/RadioButton.qml +++ b/interface/resources/qml/controls-uit/RadioButton.qml @@ -30,12 +30,12 @@ Original.RadioButton { readonly property int checkRadius: 2 onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } // TODO: doesnt works for QQC1. check with QQC2 // onHovered: { -// Tablets.playSound(TabletEnums.ButtonHover); +// Tablet.playSound(TabletEnums.ButtonHover); // } style: RadioButtonStyle { diff --git a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml index 750ed0edd4..6d2ff36550 100644 --- a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml +++ b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml @@ -24,7 +24,7 @@ Item { }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Ok) { - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.gotoHomeScreen() } }); diff --git a/interface/resources/qml/dialogs/TabletLoginDialog.qml b/interface/resources/qml/dialogs/TabletLoginDialog.qml index 5f1e9cd3bf..269788a808 100644 --- a/interface/resources/qml/dialogs/TabletLoginDialog.qml +++ b/interface/resources/qml/dialogs/TabletLoginDialog.qml @@ -89,10 +89,10 @@ TabletModalWindow { //bodyLoader.active = false } if (gotoPreviousApp) { - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.returnToPreviousApp(); } else { - Tablets.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); + Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); } } diff --git a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml index bae581a47f..454a9124ae 100644 --- a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml @@ -25,13 +25,13 @@ Preference { id: button onHoveredChanged: { if (hovered) { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); } } onClicked: { preference.trigger(); - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } width: 180 anchors.bottom: parent.bottom diff --git a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml index 81884d9a72..73819839a1 100644 --- a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml @@ -41,12 +41,12 @@ Preference { id: checkBox onHoveredChanged: { if (hovered) { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); } } onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } anchors { diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 8d69afab46..83bf1e2c54 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -246,12 +246,12 @@ Item { anchors.fill: parent; acceptedButtons: Qt.LeftButton; onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); goFunction("hifi://" + hifiUrl); } hoverEnabled: true; onEntered: { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); hoverThunk(); } onExited: unhoverThunk(); @@ -269,7 +269,7 @@ Item { } } function go() { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); goFunction(drillDownToPlace ? ("/places/" + placeName) : ("/user_stories/" + storyId)); } MouseArea { diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 960d3e0649..ddf5a69a33 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -45,7 +45,7 @@ OriginalDesktop.Desktop { Toolbar { id: sysToolbar; objectName: "com.highfidelity.interface.toolbar.system"; - property var tablet: Tablets.getTablet("com.highfidelity.interface.tablet.system"); + property var tablet: Tablet.getTablet("com.highfidelity.interface.tablet.system"); anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined; // Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained. x: sysToolbar.x diff --git a/interface/resources/qml/hifi/audio/MicBar.qml b/interface/resources/qml/hifi/audio/MicBar.qml index 9ef8bf3698..c66904034b 100644 --- a/interface/resources/qml/hifi/audio/MicBar.qml +++ b/interface/resources/qml/hifi/audio/MicBar.qml @@ -61,12 +61,12 @@ Rectangle { scrollGestureEnabled: false; onClicked: { Audio.muted = !Audio.muted; - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } drag.target: dragTarget; onContainsMouseChanged: { if (containsMouse) { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); } } } diff --git a/interface/resources/qml/hifi/tablet/NewEntityButton.qml b/interface/resources/qml/hifi/tablet/NewEntityButton.qml index 49fdb4368f..1952ef7ee8 100644 --- a/interface/resources/qml/hifi/tablet/NewEntityButton.qml +++ b/interface/resources/qml/hifi/tablet/NewEntityButton.qml @@ -123,11 +123,11 @@ Item { hoverEnabled: true enabled: true onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); newEntityButton.clicked(); } onEntered: { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); newEntityButton.state = "hover state"; } onExited: { diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 3242de89b1..4d9a83817a 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -72,7 +72,7 @@ StackView { addressLine.focus = !HMD.active; root.parentChanged.connect(center); center(); - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); } Component.onDestruction: { root.parentChanged.disconnect(center); @@ -149,7 +149,7 @@ StackView { onClicked: { addressBarDialog.loadHome(); tabletRoot.shown = false; - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.gotoHomeScreen(); } anchors { diff --git a/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml b/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml index 14d7d09dba..19548365aa 100644 --- a/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml @@ -37,7 +37,7 @@ Item { } function closeDialog() { - Tablets.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); + Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); } anchors.topMargin: hifi.dimensions.tabletMenuHeader // Space for header. diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index 3a66738b82..56cc3ed0f7 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -130,12 +130,12 @@ Item { } tabletButton.clicked(); if (tabletRoot) { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); } } onEntered: { tabletButton.isEntered = true; - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); if (tabletButton.isActive) { tabletButton.state = "hover active state"; diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 0b30496c44..3f9451436c 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -9,7 +9,7 @@ import "../audio" as HifiAudio Item { id: tablet objectName: "tablet" - property var tabletProxy: Tablets.getTablet("com.highfidelity.interface.tablet.system"); + property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system"); Rectangle { id: bgTopBar diff --git a/interface/resources/qml/hifi/tablet/TabletMenuView.qml b/interface/resources/qml/hifi/tablet/TabletMenuView.qml index e069ce8cb1..636ebfe71f 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuView.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuView.qml @@ -77,12 +77,12 @@ FocusScope { anchors.fill: parent hoverEnabled: true onEntered: { - Tablets.playSound(TabletEnums.ButtonHover); + Tablet.playSound(TabletEnums.ButtonHover); listView.currentIndex = index } onClicked: { - Tablets.playSound(TabletEnums.ButtonClick); + Tablet.playSound(TabletEnums.ButtonClick); root.selected(item); } } diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index 0665b9971e..fcb3e9ff92 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -56,7 +56,7 @@ Item { } function closeDialog() { - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); if (gotoPreviousApp) { tablet.returnToPreviousApp(); @@ -206,7 +206,7 @@ Item { } Component.onCompleted: { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); keyboardEnabled = HMD.active; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 76f8cc1505..7e54c6bf40 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5833,10 +5833,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - scriptEngine->registerGlobalObject("Tablets", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); // FIXME remove these deprecated names for the tablet scripting interface scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); auto toolbarScriptingInterface = DependencyManager::get().data(); DependencyManager::get().data()->setToolbarScriptingInterface(toolbarScriptingInterface); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index d8a2c2c3cb..adb7b4d49b 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -105,12 +105,6 @@ void OffscreenUi::create() { myContext->setContextProperty("OffscreenUi", this); myContext->setContextProperty("offscreenFlags", offscreenFlags = new OffscreenFlags()); myContext->setContextProperty("fileDialogHelper", new FileDialogHelper()); - auto tabletScriptingInterface = DependencyManager::get(); - qRegisterMetaType(); - qRegisterMetaType(); - myContext->setContextProperty("Tablets", tabletScriptingInterface.data()); - TabletProxy* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"); - myContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership); } void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index a0c6790b93..76fa5c9ec8 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -391,8 +391,10 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) { qRegisterMetaType(); qRegisterMetaType(); }); - rootContext->setContextProperty("Tablets", DependencyManager::get().data()); + rootContext->setContextProperty("Tablet", DependencyManager::get().data()); rootContext->setContextProperty("Toolbars", DependencyManager::get().data()); + TabletProxy* tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); + myContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership); } QQmlEngine* acquireEngine(QQuickWindow* window) { diff --git a/scripts/developer/EZrecord.js b/scripts/developer/EZrecord.js index 3cfc6e9928..049ccbc03d 100644 --- a/scripts/developer/EZrecord.js +++ b/scripts/developer/EZrecord.js @@ -227,7 +227,7 @@ } function setUp() { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { return; } diff --git a/scripts/developer/inputRecording.js b/scripts/developer/inputRecording.js index 574cbbeb3d..6fb8e471cd 100644 --- a/scripts/developer/inputRecording.js +++ b/scripts/developer/inputRecording.js @@ -10,7 +10,7 @@ var recording = false; var onRecordingScreen = false; var passedSaveDirectory = false; - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: "IRecord" }); diff --git a/scripts/developer/tests/dynamics/dynamicsTests.js b/scripts/developer/tests/dynamics/dynamicsTests.js index be22e2c5fb..fa51403732 100644 --- a/scripts/developer/tests/dynamics/dynamicsTests.js +++ b/scripts/developer/tests/dynamics/dynamicsTests.js @@ -18,7 +18,7 @@ var DYNAMICS_TESTS_URL = Script.resolvePath("dynamics-tests.html"); var DEFAULT_LIFETIME = 120; // seconds - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: Script.resolvePath("dynamicsTests.svg"), diff --git a/scripts/developer/tests/puck-attach.js b/scripts/developer/tests/puck-attach.js index 6971ec02cd..04d5db5710 100644 --- a/scripts/developer/tests/puck-attach.js +++ b/scripts/developer/tests/puck-attach.js @@ -19,7 +19,7 @@ Script.include("/~/system/libraries/Xform.js"); var TABLET_BUTTON_NAME = "PUCKTACH"; var TABLET_APP_URL = "https://hifi-content.s3.amazonaws.com/seefo/production/puck-attach/puck-attach.html"; -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tabletButton = tablet.addButton({ text: TABLET_BUTTON_NAME, icon: "https://s3.amazonaws.com/hifi-public/tony/icons/puck-i.svg", diff --git a/scripts/developer/tests/sliderTestMain.js b/scripts/developer/tests/sliderTestMain.js index e7542ef177..22bf4fa911 100644 --- a/scripts/developer/tests/sliderTestMain.js +++ b/scripts/developer/tests/sliderTestMain.js @@ -1,6 +1,6 @@ (function () { var HTML_URL = Script.resolvePath("sliderTest.html"); - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: "SLIDER" }); diff --git a/scripts/developer/tests/tabletEventBridgeTest.js b/scripts/developer/tests/tabletEventBridgeTest.js index 3f988303f2..d386b220fc 100644 --- a/scripts/developer/tests/tabletEventBridgeTest.js +++ b/scripts/developer/tests/tabletEventBridgeTest.js @@ -14,7 +14,7 @@ /* globals Tablets */ -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tabletButton = tablet.addButton({ text: "SOUNDS", icon: "http://s3.amazonaws.com/hifi-public/tony/icons/trombone-i.png", diff --git a/scripts/developer/tests/tabletTest.js b/scripts/developer/tests/tabletTest.js index 9c1ce0e3bd..438d0a4b99 100644 --- a/scripts/developer/tests/tabletTest.js +++ b/scripts/developer/tests/tabletTest.js @@ -10,7 +10,7 @@ // Adds a BAM! button to the tablet ui. -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: "BAM!!!" }); diff --git a/scripts/developer/utilities/audio/stats.js b/scripts/developer/utilities/audio/stats.js index a828d79340..382e14df5f 100644 --- a/scripts/developer/utilities/audio/stats.js +++ b/scripts/developer/utilities/audio/stats.js @@ -10,7 +10,7 @@ // if (HMD.active && !Settings.getValue("HUDUIEnabled")) { - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var qml = Script.resolvePath("TabletStats.qml"); tablet.loadQMLSource(qml); Script.stop(); diff --git a/scripts/developer/utilities/render/luci.js b/scripts/developer/utilities/render/luci.js index b2203ce72f..1e2ac1261f 100644 --- a/scripts/developer/utilities/render/luci.js +++ b/scripts/developer/utilities/render/luci.js @@ -27,7 +27,7 @@ } } - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: TABLET_BUTTON_NAME, icon: ICON_URL, diff --git a/scripts/developer/utilities/render/photobooth/photoboothApp.js b/scripts/developer/utilities/render/photobooth/photoboothApp.js index 375a98e543..0e8eef7352 100644 --- a/scripts/developer/utilities/render/photobooth/photoboothApp.js +++ b/scripts/developer/utilities/render/photobooth/photoboothApp.js @@ -16,7 +16,7 @@ var MODEL_BOUNDING_BOX_DIMENSIONS = {x: 1.0174,y: 1.1925,z: 1.0165}; var PhotoBooth = {}; var photoboothCreated = false; - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/snap-i.svg", text: "PHOTOBOOTH" diff --git a/scripts/system/audio.js b/scripts/system/audio.js index ea0626a30c..a93177ca38 100644 --- a/scripts/system/audio.js +++ b/scripts/system/audio.js @@ -54,7 +54,7 @@ function onScreenChanged(type, url) { button.editProperties({isActive: onAudioScreen}); } -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: Audio.muted ? MUTE_ICONS.icon : UNMUTE_ICONS.icon, activeIcon: Audio.muted ? MUTE_ICONS.activeIcon : UNMUTE_ICONS.activeIcon, diff --git a/scripts/system/audioScope.js b/scripts/system/audioScope.js index 268c883983..07efb17046 100644 --- a/scripts/system/audioScope.js +++ b/scripts/system/audioScope.js @@ -17,7 +17,7 @@ var scopePaused = AudioScope.getPause(); var autoPause = false; - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var showScopeButton = tablet.addButton({ icon: "icons/tablet-icons/scope.svg", text: "Audio Scope", diff --git a/scripts/system/bubble.js b/scripts/system/bubble.js index 2b6924d84f..4ea684ff06 100644 --- a/scripts/system/bubble.js +++ b/scripts/system/bubble.js @@ -183,7 +183,7 @@ // Setup the bubble button var buttonName = "BUBBLE"; - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ icon: "icons/tablet-icons/bubble-i.svg", activeIcon: "icons/tablet-icons/bubble-a.svg", diff --git a/scripts/system/chat.js b/scripts/system/chat.js index 220c87195a..fa997e20cc 100644 --- a/scripts/system/chat.js +++ b/scripts/system/chat.js @@ -19,7 +19,7 @@ var tabletButtonIcon = "icons/tablet-icons/menu-i.svg"; // Icon for chat button. var tabletButtonActiveIcon = "icons/tablet-icons/menu-a.svg"; // Active icon for chat button. var tabletButton = null; // The button we create in the tablet. - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); // The awesome tablet. + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); // The awesome tablet. var chatLog = []; // Array of chat messages in the form of [avatarID, displayName, message, data]. var avatarIdentifiers = {}; // Map of avatar ids to dict of identifierParams. var speechBubbleShowing = false; // Is the speech bubble visible? diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 7f05dcf3d8..9b2367b762 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -148,7 +148,7 @@ var walletEnabled = Settings.getValue("commerce", false); function startup() { if (walletEnabled) { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ text: buttonName, icon: "icons/tablet-icons/wallet-i.svg", diff --git a/scripts/system/controllers/godView.js b/scripts/system/controllers/godView.js index eb38308cb9..9551c886c9 100644 --- a/scripts/system/controllers/godView.js +++ b/scripts/system/controllers/godView.js @@ -81,7 +81,7 @@ function endGodView() { } var button; -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); function onClicked() { if (godView) { diff --git a/scripts/system/edit.js b/scripts/system/edit.js index abd69e2697..c4a8f0f54f 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -390,7 +390,7 @@ var toolBar = (function () { } function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.popFromStack(); switch (message.method) { case "newModelDialogAdd": @@ -417,7 +417,7 @@ var toolBar = (function () { var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified()); var createButtonIconRsrc = (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON); - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); activeButton = tablet.addButton({ captionColorOverride: hasRezPermissions ? "" : "#888888", icon: createButtonIconRsrc, @@ -463,7 +463,7 @@ var toolBar = (function () { var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; // tablet version of new-model dialog - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.pushOntoStack("NewModelDialog.qml"); }); @@ -644,7 +644,7 @@ var toolBar = (function () { isActive = active; activeButton.editProperties({isActive: isActive}); - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); if (!isActive) { entityListTool.setVisible(false); @@ -1850,7 +1850,7 @@ var PropertiesTool = function (opts) { var that = {}; var webView = null; - webView = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); webView.setVisible = function(value) {}; var visible = false; @@ -2293,7 +2293,7 @@ function selectParticleEntity(entityID) { particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData)); // Switch to particle explorer - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.sendToQml({method: 'selectTab', params: {id: 'particle'}}); } diff --git a/scripts/system/fingerPaint.js b/scripts/system/fingerPaint.js index ad4973890b..06403b77b7 100644 --- a/scripts/system/fingerPaint.js +++ b/scripts/system/fingerPaint.js @@ -414,7 +414,7 @@ } function setUp() { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { return; } diff --git a/scripts/system/generalSettings.js b/scripts/system/generalSettings.js index 8a9001107a..0e917d6ae4 100644 --- a/scripts/system/generalSettings.js +++ b/scripts/system/generalSettings.js @@ -34,7 +34,7 @@ alpha: 0.9 }); } else { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ icon: "icons/tablet-icons/goto-i.svg", text: buttonName, diff --git a/scripts/system/goto.js b/scripts/system/goto.js index 31394c8750..f301af60bd 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -37,7 +37,7 @@ if (Settings.getValue("HUDUIEnabled")) { alpha: 0.9 }); } else { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ icon: "icons/tablet-icons/goto-i.svg", activeIcon: "icons/tablet-icons/goto-a.svg", diff --git a/scripts/system/help.js b/scripts/system/help.js index 5687c8961f..cf0cd3c003 100644 --- a/scripts/system/help.js +++ b/scripts/system/help.js @@ -17,7 +17,7 @@ var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; var buttonName = "HELP"; var onHelpScreen = false; - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/help-i.svg", activeIcon: "icons/tablet-icons/help-a.svg", diff --git a/scripts/system/hmd.js b/scripts/system/hmd.js index a86bbd9a62..e4f6455876 100644 --- a/scripts/system/hmd.js +++ b/scripts/system/hmd.js @@ -38,7 +38,7 @@ function updateControllerDisplay() { } var button; -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); // Independent and Entity mode make people sick; disable them in hmd. var desktopOnlyViews = ['Independent Mode', 'Entity Mode']; diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index cd7c575205..0fb4258f68 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -168,7 +168,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) { this.receive = function (channel, senderID, senderUUID, localOnly) { if (_this.homeButtonID == senderID) { - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var onHomeScreen = tablet.onHomeScreen(); var isMessageOpen; if (onHomeScreen) { @@ -513,7 +513,7 @@ WebTablet.prototype.mousePressEvent = function (event) { entityPickResults.overlayID === this.tabletEntityID)) { var overlayPickResults = Overlays.findRayIntersection(pickRay, true, [this.webOverlayID, this.homeButtonID], []); if (overlayPickResults.intersects && overlayPickResults.overlayID === this.homeButtonID) { - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var onHomeScreen = tablet.onHomeScreen(); var isMessageOpen = tablet.isMessageDialogOpen(); if (onHomeScreen) { diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index a1f5d31a1a..70e0645757 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -15,7 +15,7 @@ EntityListTool = function(opts) { var that = {}; var webView = null; - webView = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); webView.setVisible = function(value) {}; var filterInView = false; diff --git a/scripts/system/libraries/gridTool.js b/scripts/system/libraries/gridTool.js index 41cbc59502..2c417a9dde 100644 --- a/scripts/system/libraries/gridTool.js +++ b/scripts/system/libraries/gridTool.js @@ -237,7 +237,7 @@ GridTool = function(opts) { var listeners = []; var webView = null; - webView = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); webView.setVisible = function(value) {}; horizontalGrid.addListener(function(data) { diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index 8ea176bbd4..76c248d880 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -354,7 +354,7 @@ flatten = function(array) { getTabletWidthFromSettings = function () { var DEFAULT_TABLET_WIDTH = 0.4375; - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var toolbarMode = tablet.toolbarMode; var DEFAULT_TABLET_SCALE = 100; var tabletScalePercentage = DEFAULT_TABLET_SCALE; diff --git a/scripts/system/marketplaces/marketplace.js b/scripts/system/marketplaces/marketplace.js index 6d6550ecbc..d90695c767 100644 --- a/scripts/system/marketplaces/marketplace.js +++ b/scripts/system/marketplaces/marketplace.js @@ -82,7 +82,7 @@ function toggleMarketplace() { } } -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var browseExamplesButton = tablet.addButton({ icon: "icons/tablet-icons/market-i.svg", diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index f65781840d..fd30bde3a0 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -81,7 +81,7 @@ } } - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var marketplaceButton = tablet.addButton({ icon: "icons/tablet-icons/market-i.svg", activeIcon: "icons/tablet-icons/market-a.svg", diff --git a/scripts/system/menu.js b/scripts/system/menu.js index 004ece17c3..c7a44d3e48 100644 --- a/scripts/system/menu.js +++ b/scripts/system/menu.js @@ -13,7 +13,7 @@ var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet- // var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; (function() { - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/menu-i.svg", activeIcon: "icons/tablet-icons/menu-a.svg", diff --git a/scripts/system/mod.js b/scripts/system/mod.js index defdb662b3..a3b4974f8d 100644 --- a/scripts/system/mod.js +++ b/scripts/system/mod.js @@ -18,7 +18,7 @@ Script.include("/~/system/libraries/controllers.js"); // grab the toolbar -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var ASSETS_PATH = Script.resolvePath("assets"); var TOOLS_PATH = Script.resolvePath("assets/images/tools/"); diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 612c0e50e2..e1741cfa3b 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -696,7 +696,7 @@ Window.announcement.connect(onNotify); Window.notifyEditError = onEditError; Window.notify = onNotify; - Tablets.tabletNotification.connect(tabletNotification); + Tablet.tabletNotification.connect(tabletNotification); Wallet.walletNotSetup.connect(walletNotSetup); Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 26bec518b4..7ba7c8c0f1 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -677,7 +677,7 @@ var buttonName = "PEOPLE"; var tablet = null; function startup() { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ text: buttonName, icon: "icons/tablet-icons/people-i.svg", diff --git a/scripts/system/particle_explorer/particleExplorerTool.js b/scripts/system/particle_explorer/particleExplorerTool.js index c2231df406..d85fc169b1 100644 --- a/scripts/system/particle_explorer/particleExplorerTool.js +++ b/scripts/system/particle_explorer/particleExplorerTool.js @@ -17,7 +17,7 @@ var PARTICLE_EXPLORER_HTML_URL = Script.resolvePath('particleExplorer.html'); ParticleExplorerTool = function() { var that = {}; that.createWebView = function() { - that.webView = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); that.webView.setVisible = function(value) {}; that.webView.webEventReceived.connect(that.webEventReceived); } diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 3f29238c24..a14e1f2772 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -22,7 +22,7 @@ var clearOverlayWhenMoving; var buttonName = "SNAP"; var buttonConnected = false; -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/snap-i.svg", activeIcon: "icons/tablet-icons/snap-a.svg", diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 41b7b84d4c..8347fcff9a 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -30,7 +30,7 @@ var shouldActivateButton = false; function ignore() { } - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var NORMAL_ICON = "icons/tablet-icons/goto-i.svg"; var NORMAL_ACTIVE = "icons/tablet-icons/goto-a.svg"; var WAITING_ICON = "icons/tablet-icons/goto-msg.svg"; diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 0044ca0496..0032239867 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -33,7 +33,7 @@ function checkTablet() { if (gTablet === null) { - gTablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + gTablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); } } @@ -315,7 +315,7 @@ Script.scriptEnding.connect(function () { // if we reload scripts in tablet mode make sure we close the currently open window, by calling gotoHomeScreen - var tabletProxy = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); if (tabletProxy && tabletProxy.toolbarMode) { tabletProxy.gotoHomeScreen(); } diff --git a/scripts/system/tablet-users.js b/scripts/system/tablet-users.js index 7efd49ae55..6f37cd55eb 100644 --- a/scripts/system/tablet-users.js +++ b/scripts/system/tablet-users.js @@ -33,7 +33,7 @@ GlobalServices.findableBy = myVisibility; } - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/users-i.svg", activeIcon: "icons/tablet-icons/users-a.svg", diff --git a/unpublishedScripts/marketplace/blocks/blocksApp.js b/unpublishedScripts/marketplace/blocks/blocksApp.js index 8088f438de..c9e8682b23 100644 --- a/unpublishedScripts/marketplace/blocks/blocksApp.js +++ b/unpublishedScripts/marketplace/blocks/blocksApp.js @@ -26,7 +26,7 @@ APP_URL = APP_OUTDATED_URL; } - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: APP_ICON, activeIcon: APP_ICON_ACTIVE, diff --git a/unpublishedScripts/marketplace/camera-move/app-camera-move.js b/unpublishedScripts/marketplace/camera-move/app-camera-move.js index 177565a332..f58dd3d3bd 100644 --- a/unpublishedScripts/marketplace/camera-move/app-camera-move.js +++ b/unpublishedScripts/marketplace/camera-move/app-camera-move.js @@ -162,7 +162,7 @@ var globalState = { function main() { log('initializing...', VERSION); - var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'), + var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'), button = tablet.addButton(BUTTON_CONFIG); Script.scriptEnding.connect(function() { @@ -601,7 +601,7 @@ function _patchCameraModeSetting() { } function getSystemMetadata() { - var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'); + var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'); return { mode: { hmd: HMD.active, diff --git a/unpublishedScripts/marketplace/clap/clapApp.js b/unpublishedScripts/marketplace/clap/clapApp.js index a975d9d8b5..b2d8ce55db 100644 --- a/unpublishedScripts/marketplace/clap/clapApp.js +++ b/unpublishedScripts/marketplace/clap/clapApp.js @@ -16,7 +16,7 @@ // Load up engine var APP_NAME = "CLAP"; var ClapEngine = Script.require(Script.resolvePath("scripts/ClapEngine.js?v9")); -var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); // Define Menu var blackIcon = Script.resolvePath("icons/tablet-icons/clap-a.svg?foxv2"); diff --git a/unpublishedScripts/marketplace/doppleganger-attachments/app-doppleganger-attachments.js b/unpublishedScripts/marketplace/doppleganger-attachments/app-doppleganger-attachments.js index 278f4efbaa..c09ad602f8 100644 --- a/unpublishedScripts/marketplace/doppleganger-attachments/app-doppleganger-attachments.js +++ b/unpublishedScripts/marketplace/doppleganger-attachments/app-doppleganger-attachments.js @@ -45,7 +45,7 @@ var buttonConfig = utils.assign({ activeIcon: require('./doppleganger-a.svg.json'), }); -var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'), +var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'), button = tablet.addButton(buttonConfig); Script.scriptEnding.connect(function() { diff --git a/unpublishedScripts/marketplace/doppleganger-attachments/dist/app-doppleganger-marketplace.js b/unpublishedScripts/marketplace/doppleganger-attachments/dist/app-doppleganger-marketplace.js index 1cb7610ff3..bc5368ba5b 100644 --- a/unpublishedScripts/marketplace/doppleganger-attachments/dist/app-doppleganger-marketplace.js +++ b/unpublishedScripts/marketplace/doppleganger-attachments/dist/app-doppleganger-marketplace.js @@ -905,7 +905,7 @@ var buttonConfig = utils.assign({ activeIcon: __webpack_require__(7), }); -var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'), +var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'), button = tablet.addButton(buttonConfig); Script.scriptEnding.connect(function() { diff --git a/unpublishedScripts/marketplace/doppleganger-mirror/app-doppleganger.js b/unpublishedScripts/marketplace/doppleganger-mirror/app-doppleganger.js index d02dd3e9ba..f4c7bf99c0 100644 --- a/unpublishedScripts/marketplace/doppleganger-mirror/app-doppleganger.js +++ b/unpublishedScripts/marketplace/doppleganger-mirror/app-doppleganger.js @@ -12,7 +12,7 @@ var DopplegangerClass = Script.require('./doppleganger.js'); -var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'), +var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'), button = tablet.addButton({ icon: Script.resolvePath('./doppleganger-i.svg'), activeIcon: Script.resolvePath('./doppleganger-a.svg'), diff --git a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js index 687c9445cd..b4d01e77cf 100644 --- a/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js +++ b/unpublishedScripts/marketplace/emoji-tablet/emojiTablet.js @@ -19,7 +19,7 @@ var lib = Script.require("https://hifi-content.s3.amazonaws.com/elisalj/emoji_sc var APP_NAME = "EMOJIS"; var APP_URL = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/emojiTabletUI.html?" + Date.now(); var APP_ICON = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/icons/emoji-i.svg"; - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: APP_ICON, diff --git a/unpublishedScripts/marketplace/laser/laserPointerApp.js b/unpublishedScripts/marketplace/laser/laserPointerApp.js index 32cc75dd42..515a2c3a76 100644 --- a/unpublishedScripts/marketplace/laser/laserPointerApp.js +++ b/unpublishedScripts/marketplace/laser/laserPointerApp.js @@ -17,7 +17,7 @@ var TRIGGER_PRESSURE = 0.95; - var tablet = Tablets.getTablet('com.highfidelity.interface.tablet.system'); + var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'); var button = tablet.addButton({ icon: APP_ICON, diff --git a/unpublishedScripts/marketplace/record/record.js b/unpublishedScripts/marketplace/record/record.js index 6392f10892..68c7ea3f5a 100644 --- a/unpublishedScripts/marketplace/record/record.js +++ b/unpublishedScripts/marketplace/record/record.js @@ -631,7 +631,7 @@ } function setUp() { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { return; } @@ -694,7 +694,7 @@ } // FIXME: If setUp() is run immediately at Interface start-up, Interface hangs and crashes because of the line of code: - // tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + // tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); //setUp(); //Script.scriptEnding.connect(tearDown); Script.setTimeout(function () { diff --git a/unpublishedScripts/marketplace/shapes/shapes.js b/unpublishedScripts/marketplace/shapes/shapes.js index de177f435e..cd5f119588 100644 --- a/unpublishedScripts/marketplace/shapes/shapes.js +++ b/unpublishedScripts/marketplace/shapes/shapes.js @@ -1930,7 +1930,7 @@ function setUp() { var hasRezPermissions; - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { App.log("ERROR: Tablet not found! App not started."); return; diff --git a/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js b/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js index 114bccb034..7bc65722cd 100644 --- a/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js +++ b/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js @@ -28,7 +28,7 @@ } } - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: ICONS.icon, activeIcon: ICONS.activeIcon, diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js index cc600632e5..27c4eaef7b 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js @@ -188,7 +188,7 @@ // -tablet: The tablet instance to be modified. var tablet = null; function startup() { - tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); addOrRemoveButton(false, HMD.active); tablet.screenChanged.connect(onTabletScreenChanged); Window.domainChanged.connect(onDomainChanged); diff --git a/unpublishedScripts/marketplace/tablet-raiseHand/tablet-raiseHand.js b/unpublishedScripts/marketplace/tablet-raiseHand/tablet-raiseHand.js index 2f895d5f94..f7702053a4 100644 --- a/unpublishedScripts/marketplace/tablet-raiseHand/tablet-raiseHand.js +++ b/unpublishedScripts/marketplace/tablet-raiseHand/tablet-raiseHand.js @@ -20,7 +20,7 @@ var isRaiseHandButtonActive = false; var animHandlerId; - var tablet = Tablets.getTablet("com.highfidelity.interface.tablet.system"); + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ text: BUTTON_NAME, icon: "icons/tablet-icons/raise-hand-i.svg", From bb2e061d77d2d38cb95b048a10055428330b2d19 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 15 Nov 2017 12:00:52 -0800 Subject: [PATCH 026/102] Fixing global declarations in JS --- interface/resources/qml/LoginDialog/LinkAccountBody.qml | 2 +- interface/resources/qml/LoginDialog/SignUpBody.qml | 2 +- interface/resources/qml/LoginDialog/UsernameCollisionBody.qml | 2 +- scripts/developer/tests/dynamics/dynamicsTests.js | 2 +- scripts/developer/tests/tabletEventBridgeTest.js | 2 +- scripts/developer/utilities/render/photobooth/photoboothApp.js | 2 +- scripts/system/audioMuteOverlay.js | 2 +- scripts/system/audioScope.js | 2 +- scripts/system/controllers/godView.js | 2 +- scripts/system/edit.js | 2 +- scripts/system/fingerPaint.js | 2 +- scripts/system/generalSettings.js | 2 +- scripts/system/goto.js | 2 +- scripts/system/help.js | 2 +- scripts/system/hmd.js | 2 +- scripts/system/libraries/WebTablet.js | 2 +- scripts/system/libraries/entityList.js | 2 +- scripts/system/marketplaces/marketplaces.js | 2 +- scripts/system/notifications.js | 2 +- scripts/system/pal.js | 2 +- scripts/system/snapshot.js | 2 +- scripts/system/tablet-goto.js | 2 +- scripts/system/tablet-ui/tabletUI.js | 2 +- scripts/tutorials/createFloatingLanternBox.js | 2 +- scripts/tutorials/createTetherballStick.js | 2 +- scripts/tutorials/entity_scripts/floatingLantern.js | 2 +- scripts/tutorials/entity_scripts/floatingLanternBox.js | 2 +- scripts/tutorials/entity_scripts/tetherballStick.js | 2 +- .../marketplace/spectator-camera/spectatorCamera.js | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 552291c186..300bcd46f0 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -248,7 +248,7 @@ Item { //dont rise local keyboard keyboardEnabled = !root.isTablet && HMD.active; - //but rise Tablet's one instead for Tablets interface + //but rise Tablet's one instead for Tablet interface if (root.isTablet) { root.keyboardEnabled = HMD.active; root.keyboardRaised = Qt.binding( function() { return keyboardRaised; }) diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index e521e16a60..9d55998b40 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -221,7 +221,7 @@ Item { root.iconText = "<" //dont rise local keyboard keyboardEnabled = !root.isTablet && HMD.active; - //but rise Tablet's one instead for Tablets interface + //but rise Tablet's one instead for Tablet interface if (root.isTablet) { root.keyboardEnabled = HMD.active; root.keyboardRaised = Qt.binding( function() { return keyboardRaised; }) diff --git a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml index 185cbd9d47..5c212578b8 100644 --- a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml +++ b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml @@ -131,7 +131,7 @@ Item { root.iconText = "<" //dont rise local keyboard keyboardEnabled = !root.isTablet && HMD.active; - //but rise Tablet's one instead for Tablets interface + //but rise Tablet's one instead for Tablet interface if (root.isTablet) { root.keyboardEnabled = HMD.active; root.keyboardRaised = Qt.binding( function() { return keyboardRaised; }) diff --git a/scripts/developer/tests/dynamics/dynamicsTests.js b/scripts/developer/tests/dynamics/dynamicsTests.js index fa51403732..c0b001eab3 100644 --- a/scripts/developer/tests/dynamics/dynamicsTests.js +++ b/scripts/developer/tests/dynamics/dynamicsTests.js @@ -11,7 +11,7 @@ "use strict"; -/* global Entities, Script, Tablets, MyAvatar, Vec3 */ +/* global Entities, Script, Tablet, MyAvatar, Vec3 */ (function() { // BEGIN LOCAL_SCOPE diff --git a/scripts/developer/tests/tabletEventBridgeTest.js b/scripts/developer/tests/tabletEventBridgeTest.js index d386b220fc..83031741fc 100644 --- a/scripts/developer/tests/tabletEventBridgeTest.js +++ b/scripts/developer/tests/tabletEventBridgeTest.js @@ -11,7 +11,7 @@ // Adds a button to the tablet that will switch to a web page. // This web page contains buttons that will use the event bridge to trigger sounds. -/* globals Tablets */ +/* globals Tablet */ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); diff --git a/scripts/developer/utilities/render/photobooth/photoboothApp.js b/scripts/developer/utilities/render/photobooth/photoboothApp.js index 0e8eef7352..154028f091 100644 --- a/scripts/developer/utilities/render/photobooth/photoboothApp.js +++ b/scripts/developer/utilities/render/photobooth/photoboothApp.js @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablets, Toolbars, Script, HMD, Controller, Menu */ +/* globals Tablet, Toolbars, Script, HMD, Controller, Menu */ (function () { var SNAPSHOT_DELAY = 500; // 500ms var PHOTOBOOTH_WINDOW_HTML_URL = Script.resolvePath("./html/photobooth.html"); diff --git a/scripts/system/audioMuteOverlay.js b/scripts/system/audioMuteOverlay.js index 0db4edb85d..731d62017d 100644 --- a/scripts/system/audioMuteOverlay.js +++ b/scripts/system/audioMuteOverlay.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // audioMuteOverlay.js diff --git a/scripts/system/audioScope.js b/scripts/system/audioScope.js index 07efb17046..81d8e8fbd4 100644 --- a/scripts/system/audioScope.js +++ b/scripts/system/audioScope.js @@ -9,7 +9,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global Script, Tablets, AudioScope, Audio */ +/* global Script, Tablet, AudioScope, Audio */ (function () { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/controllers/godView.js b/scripts/system/controllers/godView.js index 9551c886c9..4b406399fd 100644 --- a/scripts/system/controllers/godView.js +++ b/scripts/system/controllers/godView.js @@ -9,7 +9,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals HMD, Script, Menu, Tablets, Camera */ +/* globals HMD, Script, Menu, Tablet, Camera */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function() { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/edit.js b/scripts/system/edit.js index c4a8f0f54f..2bbd422c65 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -11,7 +11,7 @@ // /* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger, - Settings, Entities, Tablets, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */ + Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */ (function() { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/fingerPaint.js b/scripts/system/fingerPaint.js index 06403b77b7..88245503e8 100644 --- a/scripts/system/fingerPaint.js +++ b/scripts/system/fingerPaint.js @@ -419,7 +419,7 @@ return; } - // Tablets button. + // Tablet button. button = tablet.addButton({ icon: "icons/tablet-icons/finger-paint-i.svg", activeIcon: "icons/tablet-icons/finger-paint-a.svg", diff --git a/scripts/system/generalSettings.js b/scripts/system/generalSettings.js index 0e917d6ae4..082528ffc5 100644 --- a/scripts/system/generalSettings.js +++ b/scripts/system/generalSettings.js @@ -10,7 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablets, Toolbars, Script, HMD, DialogsManager */ +/* globals Tablet, Toolbars, Script, HMD, DialogsManager */ (function() { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/goto.js b/scripts/system/goto.js index f301af60bd..d364bf579e 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -10,7 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablets, Toolbars, Script, HMD, DialogsManager */ +/* globals Tablet, Toolbars, Script, HMD, DialogsManager */ (function() { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/help.js b/scripts/system/help.js index cf0cd3c003..9ab7fa3fb3 100644 --- a/scripts/system/help.js +++ b/scripts/system/help.js @@ -10,7 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablets, Script, HMD, Controller, Menu */ +/* globals Tablet, Script, HMD, Controller, Menu */ (function() { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/hmd.js b/scripts/system/hmd.js index e4f6455876..b9fd7f725c 100644 --- a/scripts/system/hmd.js +++ b/scripts/system/hmd.js @@ -10,7 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals HMD, Script, Menu, Tablets, Camera */ +/* globals HMD, Script, Menu, Tablet, Camera */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function() { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 0fb4258f68..c46cfaa073 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -7,7 +7,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global getControllerWorldLocation, Tablets, WebTablet:true, HMD, Settings, Script, +/* global getControllerWorldLocation, Tablet, WebTablet:true, HMD, Settings, Script, Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp, Controller, Mat4, resizeTablet */ Script.include(Script.resolvePath("../libraries/utils.js")); diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index 70e0645757..9d9689000e 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global EntityListTool, Tablets, selectionManager, Entities, Camera, MyAvatar, Vec3, Menu, Messages, +/* global EntityListTool, Tablet, selectionManager, Entities, Camera, MyAvatar, Vec3, Menu, Messages, cameraManager, MENU_EASE_ON_FOCUS, deleteSelectedEntities, toggleSelectedEntitiesLocked, toggleSelectedEntitiesVisible */ EntityListTool = function(opts) { diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 750194bed2..4f2e47ee07 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global Tablets, Script, HMD, UserActivityLogger, Entities */ +/* global Tablet, Script, HMD, UserActivityLogger, Entities */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function () { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index e1741cfa3b..b6ddd9d33e 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Script, Settings, Window, Controller, Overlays, SoundArray, LODManager, MyAvatar, Tablets, Camera, HMD, Menu, Quat, Vec3*/ +/*global Script, Settings, Window, Controller, Overlays, SoundArray, LODManager, MyAvatar, Tablet, Camera, HMD, Menu, Quat, Vec3*/ // // notifications.js // Version 0.801 diff --git a/scripts/system/pal.js b/scripts/system/pal.js index bd318193cf..ed7059f9f3 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Tablets, Settings, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, HMD, Controller, Account, UserActivityLogger, Messages, Window, XMLHttpRequest, print, location, getControllerWorldLocation*/ +/*global Tablet, Settings, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, HMD, Controller, Account, UserActivityLogger, Messages, Window, XMLHttpRequest, print, location, getControllerWorldLocation*/ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // pal.js diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index a14e1f2772..9afdb4ec53 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -7,7 +7,7 @@ // Distributed under the Apache License, Version 2.0 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals Tablets, Script, HMD, Settings, DialogsManager, Menu, Reticle, OverlayWebWindow, Desktop, Account, MyAvatar, Snapshot */ +/* globals Tablet, Script, HMD, Settings, DialogsManager, Menu, Reticle, OverlayWebWindow, Desktop, Account, MyAvatar, Snapshot */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function () { // BEGIN LOCAL_SCOPE diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 8347fcff9a..2a0e827932 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Window, Script, Tablets, HMD, Controller, Account, XMLHttpRequest, location, print*/ +/*global Window, Script, Tablet, HMD, Controller, Account, XMLHttpRequest, location, print*/ // // goto.js diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 0032239867..17821c737e 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablets, Overlays, +/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablet, Overlays, MyAvatar, Menu, AvatarInputs, Vec3 */ (function() { // BEGIN LOCAL_SCOPE diff --git a/scripts/tutorials/createFloatingLanternBox.js b/scripts/tutorials/createFloatingLanternBox.js index c83535fa37..c84214e295 100644 --- a/scripts/tutorials/createFloatingLanternBox.js +++ b/scripts/tutorials/createFloatingLanternBox.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // createFloatinLanternBox.js diff --git a/scripts/tutorials/createTetherballStick.js b/scripts/tutorials/createTetherballStick.js index 3ad0939c2e..35f5fb0344 100644 --- a/scripts/tutorials/createTetherballStick.js +++ b/scripts/tutorials/createTetherballStick.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // createTetherballStick.js diff --git a/scripts/tutorials/entity_scripts/floatingLantern.js b/scripts/tutorials/entity_scripts/floatingLantern.js index c2a79c9c5b..aa25dc0003 100644 --- a/scripts/tutorials/entity_scripts/floatingLantern.js +++ b/scripts/tutorials/entity_scripts/floatingLantern.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // floatinLantern.js diff --git a/scripts/tutorials/entity_scripts/floatingLanternBox.js b/scripts/tutorials/entity_scripts/floatingLanternBox.js index b8e0fbda3e..b5fb0c27d9 100644 --- a/scripts/tutorials/entity_scripts/floatingLanternBox.js +++ b/scripts/tutorials/entity_scripts/floatingLanternBox.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // floatingLanternBox.js diff --git a/scripts/tutorials/entity_scripts/tetherballStick.js b/scripts/tutorials/entity_scripts/tetherballStick.js index 50bac88caf..867074abd4 100644 --- a/scripts/tutorials/entity_scripts/tetherballStick.js +++ b/scripts/tutorials/entity_scripts/tetherballStick.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablets, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // tetherballStick.js diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js index 27c4eaef7b..76044d2975 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Tablets, Script, */ +/*global Tablet, Script, */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // spectatorCamera.js From 0ad399974132417c0181d35af6dd46806730022e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 15 Nov 2017 12:24:00 -0800 Subject: [PATCH 027/102] Fixing misname --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index ebd30f9342..b83e7e3afa 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -394,7 +394,7 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) { rootContext->setContextProperty("Tablet", DependencyManager::get().data()); rootContext->setContextProperty("Toolbars", DependencyManager::get().data()); TabletProxy* tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); - myContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership); + engine->setObjectOwnership(tablet, QQmlEngine::CppOwnership); } QQmlEngine* acquireEngine(QQuickWindow* window) { From 93c3d5314421256547d8518885993f91e76387b1 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 15 Nov 2017 16:46:00 -0800 Subject: [PATCH 028/102] Fix marketplaces.js URLs --- scripts/system/marketplaces/marketplaces.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 4f2e47ee07..c94db0d0e6 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -20,10 +20,9 @@ var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page. var MARKETPLACES_URL = Script.resolvePath("../html/marketplaces.html"); var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js"); - var MARKETPLACE_CHECKOUT_QML_PATH_BASE = "qml/hifi/commerce/checkout/Checkout.qml"; - var MARKETPLACE_CHECKOUT_QML_PATH = Script.resourcesPath() + MARKETPLACE_CHECKOUT_QML_PATH_BASE; - var MARKETPLACE_PURCHASES_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/purchases/Purchases.qml"; - var MARKETPLACE_WALLET_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/wallet/Wallet.qml"; + var MARKETPLACE_CHECKOUT_QML_PATH = "hifi/commerce/checkout/Checkout.qml"; + var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml"; + var MARKETPLACE_WALLET_QML_PATH = "hifi/commerce/wallet/Wallet.qml"; var MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH = "commerce/inspectionCertificate/InspectionCertificate.qml"; var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; @@ -110,7 +109,7 @@ var filterText; // Used for updating Purchases QML function onScreenChanged(type, url) { onMarketplaceScreen = type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1; - onCommerceScreen = type === "QML" && (url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH_BASE) !== -1 || url === MARKETPLACE_PURCHASES_QML_PATH || url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1); + onCommerceScreen = type === "QML" && (url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH) !== -1 || url === MARKETPLACE_PURCHASES_QML_PATH || url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1); wireEventBridge(onCommerceScreen); if (url === MARKETPLACE_PURCHASES_QML_PATH) { From d31578abae3a1310b8224e6505a19866c1c54ebd Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 17 Nov 2017 15:47:02 -0800 Subject: [PATCH 029/102] FIXME LATER! Remove mouseareas from passphrase screens --- .../hifi/commerce/wallet/PassphraseModal.qml | 16 +++---- .../commerce/wallet/PassphraseSelection.qml | 48 +++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index 9f04db7d5c..44dda1b7ad 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -206,15 +206,15 @@ Item { root.isPasswordField = (focus && passphraseField.echoMode === TextInput.Password); } - MouseArea { - anchors.fill: parent; + //MouseArea { + // anchors.fill: parent; - onClicked: { - root.keyboardRaised = true; - root.isPasswordField = (passphraseField.echoMode === TextInput.Password); - mouse.accepted = false; - } - } + // onClicked: { + // root.keyboardRaised = true; + // root.isPasswordField = (passphraseField.echoMode === TextInput.Password); + // mouse.accepted = false; + // } + //} onAccepted: { submitPassphraseInputButton.enabled = false; diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 0145f92b96..cc23e6bb4d 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -87,14 +87,14 @@ Item { } } - MouseArea { - anchors.fill: parent; - onPressed: { - var hidePassword = (currentPassphraseField.echoMode === TextInput.Password); - sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); - mouse.accepted = false; - } - } + //MouseArea { + // anchors.fill: parent; + // onPressed: { + // var hidePassword = (currentPassphraseField.echoMode === TextInput.Password); + // sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); + // mouse.accepted = false; + // } + //} onAccepted: { passphraseField.focus = true; @@ -115,14 +115,14 @@ Item { activeFocusOnPress: true; activeFocusOnTab: true; - MouseArea { - anchors.fill: parent; - onPressed: { - var hidePassword = (passphraseField.echoMode === TextInput.Password); - sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); - mouse.accepted = false; - } - } + //MouseArea { + // anchors.fill: parent; + // onPressed: { + // var hidePassword = (passphraseField.echoMode === TextInput.Password); + // sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); + // mouse.accepted = false; + // } + //} onFocusChanged: { if (focus) { @@ -151,14 +151,14 @@ Item { activeFocusOnPress: true; activeFocusOnTab: true; - MouseArea { - anchors.fill: parent; - onPressed: { - var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password); - sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); - mouse.accepted = false; - } - } + //MouseArea { + // anchors.fill: parent; + // onPressed: { + // var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password); + // sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); + // mouse.accepted = false; + // } + //} onFocusChanged: { if (focus) { From 572e208a1ef86078755325e12388e93d5645f47c Mon Sep 17 00:00:00 2001 From: Joshua Chamberlain Date: Tue, 21 Nov 2017 17:19:09 -0800 Subject: [PATCH 030/102] Create BUILD_LINUX_CHEATSHEET.md --- BUILD_LINUX_CHEATSHEET.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 BUILD_LINUX_CHEATSHEET.md diff --git a/BUILD_LINUX_CHEATSHEET.md b/BUILD_LINUX_CHEATSHEET.md new file mode 100644 index 0000000000..7d77f5d685 --- /dev/null +++ b/BUILD_LINUX_CHEATSHEET.md @@ -0,0 +1,27 @@ + # this guide is specific to Ubuntu 16.04. + # deb packages of High Fidelity domain server and assignment client are stored on debian.highfidelity.com +sudo su - +apt-get -y update +apt-get install -y software-properties-common +apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 15FF1AAE +add-apt-repository "deb http://debian.highfidelity.com stable main" +apt-get -y update +apt-get install -y hifi-domain-server +apt-get install -y hifi-assignment-client + + # When installing master/dev builds, the packages are slightly different and you just need to change the last 2 steps to: +apt-get install -y hifi-dev-domain-server +apt-get install -y hifi-dev-assignment-client + + # domain server and assignment clients should already be running. The processes are controlled via: +systemctl start hifi-domain-server +systemctl stop hifi-domain-server + + # Once the machine is setup and processes are running you should ensure that your firewall exposes port 40100 on TCP and all UDP ports. This will get your domain up and running and you could connect to it (for now) by using High Fidelity Interface and typing in the IP for the place name. (further customizations can be done via http://IPAddress:40100). + + # The server always depends on both hifi-domain-server and hifi-assignment-client running at the same time. + # As an additional step, you should ensure that your packages are automatically updated when a new version goes out. You could, for example, set the automatic update checks to happen every hour (though this could potentially result in the domain being unreachable for a whole hour by new clients when they are released - adjust the update checks accordingly). +To do this you can modify /etc/crontab by adding the following lines +0 */1 * * * root apt-get update +1 */1 * * * root apt-get install --only-upgrade -y hifi-domain-server +2 */1 * * * root apt-get install --only-upgrade -y hifi-assignment-client From 4374b4f9a83c4775a99719b6fd6c7193cdb402dc Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 11 Dec 2017 00:39:23 -0500 Subject: [PATCH 031/102] forward MIDI_CONTROL_CHANGE events --- libraries/midi/src/Midi.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index ad650cf067..6c2471f680 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -177,9 +177,10 @@ void Midi::MidiCleanup() { #endif void Midi::noteReceived(int status, int note, int velocity) { - if (((status & MIDI_STATUS_MASK) != MIDI_NOTE_OFF) && - ((status & MIDI_STATUS_MASK) != MIDI_NOTE_ON)) { - return; // NOTE: only sending note-on and note-off to Javascript + if (((status & MIDI_STATUS_MASK) != MIDI_NOTE_OFF) && + ((status & MIDI_STATUS_MASK) != MIDI_NOTE_ON) && + ((status & MIDI_STATUS_MASK) != MIDI_CONTROL_CHANGE)) { + return; // NOTE: only sending note-on, note-off, and control-change to Javascript } QVariantMap eventData; From 2d786451c2a8be3221b9f4c6c618a0b0a4ca10b8 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 11 Dec 2017 10:50:24 -0800 Subject: [PATCH 032/102] Add comment --- libraries/ui/src/QmlWindowClass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 1758150e0a..90b91c5ec2 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -61,6 +61,7 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { } QUrl url { properties[SOURCE_PROPERTY].toString() }; + // If the passed URL doesn't correspond to a known scheme, assume it's a local file path if (url.scheme() != "http" && url.scheme() != "https" && url.scheme() != "file" && url.scheme() != "about" && url.scheme() != "atp" && url.scheme() != "qrc") { properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url.toString()).toString(); From 2225352b1e151d574d03356838a3e1e10e65f703 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 11 Dec 2017 17:15:15 -0800 Subject: [PATCH 033/102] Fix wallet setup --- .../qml/hifi/commerce/wallet/Wallet.qml | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 74d3b294bc..8ebd3ecc84 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -49,7 +49,7 @@ Rectangle { } else if (walletStatus === 1) { if (root.activeView !== "walletSetup") { root.activeView = "walletSetup"; - commerce.resetLocalWalletOnly(); + Commerce.resetLocalWalletOnly(); var timestamp = new Date(); walletSetup.startingTimestamp = timestamp; walletSetup.setupAttemptID = generateUUID(); @@ -61,8 +61,10 @@ Rectangle { root.activeView = "passphraseModal"; } } else if (walletStatus === 3) { - root.activeView = "walletHome"; - Commerce.getSecurityImage(); + if (root.activeView !== "walletSetup") { + root.activeView = "walletHome"; + Commerce.getSecurityImage(); + } } else { console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus); } @@ -211,17 +213,19 @@ Rectangle { Connections { onSendSignalToWallet: { - if (msg.method === 'walletSetup_raiseKeyboard') { - root.keyboardRaised = true; - root.isPassword = msg.isPasswordField; - } else if (msg.method === 'walletSetup_lowerKeyboard') { - root.keyboardRaised = false; - } else if (msg.method === 'walletSecurity_changePassphraseCancelled') { - root.activeView = "security"; - } else if (msg.method === 'walletSecurity_changePassphraseSuccess') { - root.activeView = "security"; - } else { - sendToScript(msg); + if (passphraseChange.visible) { + if (msg.method === 'walletSetup_raiseKeyboard') { + root.keyboardRaised = true; + root.isPassword = msg.isPasswordField; + } else if (msg.method === 'walletSetup_lowerKeyboard') { + root.keyboardRaised = false; + } else if (msg.method === 'walletSecurity_changePassphraseCancelled') { + root.activeView = "security"; + } else if (msg.method === 'walletSecurity_changePassphraseSuccess') { + root.activeView = "security"; + } else { + sendToScript(msg); + } } } } From a1f1e7b587959b541cd17c1b5ead0474a20960ac Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 12 Dec 2017 18:20:29 -0700 Subject: [PATCH 034/102] Fix web entities accessing the webcam RC61 --- interface/resources/html/createGlobalEventBridge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/html/createGlobalEventBridge.js b/interface/resources/html/createGlobalEventBridge.js index b85aa33e33..a180fbc6cc 100644 --- a/interface/resources/html/createGlobalEventBridge.js +++ b/interface/resources/html/createGlobalEventBridge.js @@ -34,7 +34,7 @@ var EventBridge; var tempEventBridge = EventBridge; EventBridge = channel.objects.eventBridge; EventBridge.audioOutputDeviceChanged.connect(function(deviceName) { - navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(function(mediaStream) { + navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function(mediaStream) { navigator.mediaDevices.enumerateDevices().then(function(devices) { devices.forEach(function(device) { if (device.kind == "audiooutput") { From 3a45907df078bdc20bc915ac7103e810fbf28d5c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Dec 2017 17:16:07 -0800 Subject: [PATCH 035/102] Keep connection alive as long as the node is connected --- libraries/networking/src/udt/Connection.cpp | 82 ++++++++------------- libraries/networking/src/udt/Connection.h | 9 +-- libraries/networking/src/udt/SendQueue.cpp | 52 ++++++------- libraries/networking/src/udt/SendQueue.h | 8 +- libraries/networking/src/udt/Socket.cpp | 3 - 5 files changed, 57 insertions(+), 97 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index f42049f107..7a31bbeedc 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -11,6 +11,8 @@ #include "Connection.h" +#include + #include #include @@ -60,6 +62,15 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::uniq _ack2Packet = ControlPacket::create(ControlPacket::ACK2, ACK2_PAYLOAD_BYTES); _lossReport = ControlPacket::create(ControlPacket::NAK, NAK_PACKET_PAYLOAD_BYTES); _handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, HANDSHAKE_ACK_PAYLOAD_BYTES); + + + // setup psuedo-random number generation shared by all connections + static std::random_device rd; + static std::mt19937 generator(rd()); + static std::uniform_int_distribution<> distribution(0, SequenceNumber::MAX); + + // randomize the intial sequence number + _initialSequenceNumber = SequenceNumber(distribution(generator)); } Connection::~Connection() { @@ -81,9 +92,6 @@ void Connection::stopSendQueue() { sendQueue->stop(); sendQueue->deleteLater(); - // since we're stopping the send queue we should consider our handshake ACK not receieved - _hasReceivedHandshakeACK = false; - // wait on the send queue thread so we know the send queue is gone sendQueueThread->quit(); sendQueueThread->wait(); @@ -101,13 +109,22 @@ void Connection::setMaxBandwidth(int maxBandwidth) { SendQueue& Connection::getSendQueue() { if (!_sendQueue) { - // we may have a sequence number from the previous inactive queue - re-use that so that the // receiver is getting the sequence numbers it expects (given that the connection must still be active) // Lasily create send queue - _sendQueue = SendQueue::create(_parentSocket, _destination); - _lastReceivedACK = _sendQueue->getCurrentSequenceNumber(); + + if (!_hasReceivedHandshakeACK) { + // First time creating a send queue for this connection + _sendQueue = SendQueue::create(_parentSocket, _destination, _initialSequenceNumber - 1); + _lastReceivedACK = _sendQueue->getCurrentSequenceNumber(); + } else { + // Connection already has a handshake from a previous send queue + _sendQueue = SendQueue::create(_parentSocket, _destination, _lastReceivedACK); + // This connection has already gone through the handshake + // bypass it in the send queue + _sendQueue->handshakeACK(); + } #ifdef UDT_CONNECTION_DEBUG qCDebug(networking) << "Created SendQueue for connection to" << _destination; @@ -142,14 +159,6 @@ void Connection::queueInactive() { #ifdef UDT_CONNECTION_DEBUG qCDebug(networking) << "Connection to" << _destination << "has stopped its SendQueue."; #endif - - if (!_hasReceivedHandshake || !_isReceivingData) { -#ifdef UDT_CONNECTION_DEBUG - qCDebug(networking) << "Connection SendQueue to" << _destination << "stopped and no data is being received - stopping connection."; -#endif - - deactivate(); - } } void Connection::queueTimeout() { @@ -208,19 +217,6 @@ void Connection::sync() { && duration_cast(sincePacketReceive).count() >= MIN_SECONDS_BEFORE_EXPIRY ) { // the receive side of this connection is expired _isReceivingData = false; - - // if we don't have a send queue that means the whole connection has expired and we can emit our signal - // otherwise we'll wait for it to also timeout before cleaning up - if (!_sendQueue) { - -#ifdef UDT_CONNECTION_DEBUG - qCDebug(networking) << "Connection to" << _destination << "no longer receiving any data and there is currently no send queue - stopping connection."; -#endif - - deactivate(); - - return; - } } // reset the number of light ACKs or non SYN ACKs during this sync interval @@ -242,26 +238,6 @@ void Connection::sync() { sendTimeoutNAK(); } } - } else if (!_sendQueue) { - // we haven't received a packet and we're not sending - // this most likely means we were started erroneously - // check the start time for this connection and auto expire it after 5 seconds of not receiving or sending any data - static const int CONNECTION_NOT_USED_EXPIRY_SECONDS = 5; - auto secondsSinceStart = duration_cast(p_high_resolution_clock::now() - _connectionStart).count(); - - if (secondsSinceStart >= CONNECTION_NOT_USED_EXPIRY_SECONDS) { - // it's been CONNECTION_NOT_USED_EXPIRY_SECONDS and nothing has actually happened with this connection - // consider it inactive and emit our inactivity signal - -#ifdef UDT_CONNECTION_DEBUG - qCDebug(networking) << "Connection to" << _destination << "did not receive or send any data in last" - << CONNECTION_NOT_USED_EXPIRY_SECONDS << "seconds - stopping connection."; -#endif - - deactivate(); - - return; - } } } @@ -827,11 +803,13 @@ void Connection::processHandshakeACK(ControlPacketPointer controlPacket) { SequenceNumber initialSequenceNumber; controlPacket->readPrimitive(&initialSequenceNumber); - // hand off this handshake ACK to the send queue so it knows it can start sending - getSendQueue().handshakeACK(initialSequenceNumber); - - // indicate that handshake ACK was received - _hasReceivedHandshakeACK = true; + if (initialSequenceNumber == _initialSequenceNumber) { + // hand off this handshake ACK to the send queue so it knows it can start sending + getSendQueue().handshakeACK(); + + // indicate that handshake ACK was received + _hasReceivedHandshakeACK = true; + } } } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index c134081dde..a13c29adc8 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -72,8 +72,6 @@ public: void queueReceivedMessagePacket(std::unique_ptr packet); ConnectionStats::Stats sampleStats() { return _stats.sample(); } - - bool isActive() const { return _isActive; } HifiSockAddr getDestination() const { return _destination; } @@ -83,7 +81,6 @@ public: signals: void packetSent(); - void connectionInactive(const HifiSockAddr& sockAddr); void receiverHandshakeRequestComplete(const HifiSockAddr& sockAddr); private slots: @@ -112,8 +109,6 @@ private: void resetReceiveState(); void resetRTT(); - void deactivate() { _isActive = false; emit connectionInactive(_destination); } - SendQueue& getSendQueue(); SequenceNumber nextACK() const; void updateRTT(int rtt); @@ -138,9 +133,9 @@ private: p_high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection - bool _isActive { true }; // flag used for inactivity of connection - SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer SendQueue on creation, identifies connection during re-connect requests + SequenceNumber _initialSequenceNumber; // Randomized on Connection creation, identifies connection during re-connect requests + SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer Connection on creation, identifies connection during re-connect requests LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 0c029751aa..ef249b8f75 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -12,7 +12,6 @@ #include "SendQueue.h" #include -#include #include #include @@ -62,10 +61,10 @@ private: Mutex2& _mutex2; }; -std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination) { +std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber) { Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*"); - auto queue = std::unique_ptr(new SendQueue(socket, destination)); + auto queue = std::unique_ptr(new SendQueue(socket, destination, currentSequenceNumber)); // Setup queue private thread QThread* thread = new QThread; @@ -84,20 +83,12 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destin return queue; } -SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : +SendQueue::SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber) : _socket(socket), _destination(dest) { - // setup psuedo-random number generation for all instances of SendQueue - static std::random_device rd; - static std::mt19937 generator(rd()); - static std::uniform_int_distribution<> distribution(0, SequenceNumber::MAX); - - // randomize the intial sequence number - _initialSequenceNumber = SequenceNumber(distribution(generator)); - - // set our member variables from randomized initial number - _currentSequenceNumber = _initialSequenceNumber - 1; + // set our member variables from current sequence number + _currentSequenceNumber = currentSequenceNumber; _atomicCurrentSequenceNumber = uint32_t(_currentSequenceNumber); _lastACKSequenceNumber = uint32_t(_currentSequenceNumber) - 1; @@ -114,8 +105,8 @@ void SendQueue::queuePacket(std::unique_ptr packet) { // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for packets _emptyCondition.notify_one(); - if (!this->thread()->isRunning() && _state == State::NotStarted) { - this->thread()->start(); + if (!thread()->isRunning() && _state == State::NotStarted) { + thread()->start(); } } @@ -125,8 +116,8 @@ void SendQueue::queuePacketList(std::unique_ptr packetList) { // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for packets _emptyCondition.notify_one(); - if (!this->thread()->isRunning() && _state == State::NotStarted) { - this->thread()->start(); + if (!thread()->isRunning() && _state == State::NotStarted) { + thread()->start(); } } @@ -225,8 +216,11 @@ void SendQueue::sendHandshake() { std::unique_lock handshakeLock { _handshakeMutex }; if (!_hasReceivedHandshakeACK) { // we haven't received a handshake ACK from the client, send another now + // if the handshake hasn't been completed, then the initial sequence number + // should be the current sequence number + 1 + SequenceNumber initialSequenceNumber = _currentSequenceNumber + 1; auto handshakePacket = ControlPacket::create(ControlPacket::Handshake, sizeof(SequenceNumber)); - handshakePacket->writePrimitive(_initialSequenceNumber); + handshakePacket->writePrimitive(initialSequenceNumber); _socket->writeBasePacket(*handshakePacket, _destination); // we wait for the ACK or the re-send interval to expire @@ -235,18 +229,16 @@ void SendQueue::sendHandshake() { } } -void SendQueue::handshakeACK(SequenceNumber initialSequenceNumber) { - if (initialSequenceNumber == _initialSequenceNumber) { - { - std::lock_guard locker { _handshakeMutex }; - _hasReceivedHandshakeACK = true; - } - - _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch(); - - // Notify on the handshake ACK condition - _handshakeACKCondition.notify_one(); +void SendQueue::handshakeACK() { + { + std::lock_guard locker { _handshakeMutex }; + _hasReceivedHandshakeACK = true; } + + _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch(); + + // Notify on the handshake ACK condition + _handshakeACKCondition.notify_one(); } SequenceNumber SendQueue::getNextSequenceNumber() { diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 484afcb88e..b6cec15ffd 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -50,7 +50,7 @@ public: Stopped }; - static std::unique_ptr create(Socket* socket, HifiSockAddr destination); + static std::unique_ptr create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber); virtual ~SendQueue(); @@ -76,7 +76,7 @@ public slots: void nak(SequenceNumber start, SequenceNumber end); void fastRetransmit(SequenceNumber ack); void overrideNAKListFromPacket(ControlPacket& packet); - void handshakeACK(SequenceNumber initialSequenceNumber); + void handshakeACK(); signals: void packetSent(int wireSize, int payloadSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint); @@ -91,7 +91,7 @@ private slots: void run(); private: - SendQueue(Socket* socket, HifiSockAddr dest); + SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber); SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; @@ -115,8 +115,6 @@ private: Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr - - SequenceNumber _initialSequenceNumber; // Randomized on SendQueue creation, identifies connection during re-connect requests std::atomic _lastACKSequenceNumber { 0 }; // Last ACKed sequence number diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index a3374a0f47..55643985c8 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -257,9 +257,6 @@ Connection* Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { congestionControl->setMaxBandwidth(_maxBandwidth); auto connection = std::unique_ptr(new Connection(this, sockAddr, std::move(congestionControl))); - // we queue the connection to cleanup connection in case it asks for it during its own rate control sync - QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection); - // allow higher-level classes to find out when connections have completed a handshake QObject::connect(connection.get(), &Connection::receiverHandshakeRequestComplete, this, &Socket::clientHandshakeRequestComplete); From 44190f16c09fa3aae2330318c426364bbe0e8c47 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 13 Dec 2017 16:55:08 -0800 Subject: [PATCH 036/102] Reset ACK in ctor --- libraries/networking/src/udt/Connection.cpp | 7 ++----- libraries/networking/src/udt/SendQueue.cpp | 15 +++++++++++---- libraries/networking/src/udt/SendQueue.h | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 7a31bbeedc..5f632fa25f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -116,14 +116,11 @@ SendQueue& Connection::getSendQueue() { if (!_hasReceivedHandshakeACK) { // First time creating a send queue for this connection - _sendQueue = SendQueue::create(_parentSocket, _destination, _initialSequenceNumber - 1); + _sendQueue = SendQueue::create(_parentSocket, _destination, _initialSequenceNumber - 1, _hasReceivedHandshakeACK); _lastReceivedACK = _sendQueue->getCurrentSequenceNumber(); } else { // Connection already has a handshake from a previous send queue - _sendQueue = SendQueue::create(_parentSocket, _destination, _lastReceivedACK); - // This connection has already gone through the handshake - // bypass it in the send queue - _sendQueue->handshakeACK(); + _sendQueue = SendQueue::create(_parentSocket, _destination, _lastReceivedACK, _hasReceivedHandshakeACK); } #ifdef UDT_CONNECTION_DEBUG diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index ef249b8f75..3dbfb35fbe 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -61,10 +61,10 @@ private: Mutex2& _mutex2; }; -std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber) { +std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber, bool hasReceivedHandshakeACK) { Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*"); - auto queue = std::unique_ptr(new SendQueue(socket, destination, currentSequenceNumber)); + auto queue = std::unique_ptr(new SendQueue(socket, destination, currentSequenceNumber, hasReceivedHandshakeACK)); // Setup queue private thread QThread* thread = new QThread; @@ -83,14 +83,21 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destin return queue; } -SendQueue::SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber) : +SendQueue::SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber, bool hasReceivedHandshakeACK) : _socket(socket), _destination(dest) { // set our member variables from current sequence number _currentSequenceNumber = currentSequenceNumber; _atomicCurrentSequenceNumber = uint32_t(_currentSequenceNumber); - _lastACKSequenceNumber = uint32_t(_currentSequenceNumber) - 1; + + if (hasReceivedHandshakeACK) { + _lastACKSequenceNumber = uint32_t(_currentSequenceNumber); + } else { + _lastACKSequenceNumber = uint32_t(_currentSequenceNumber - 1); + } + + _hasReceivedHandshakeACK = hasReceivedHandshakeACK; // default the last receiver response to the current time _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch(); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index b6cec15ffd..29fe6b35ff 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -50,7 +50,7 @@ public: Stopped }; - static std::unique_ptr create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber); + static std::unique_ptr create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber, bool hasReceivedHandshakeACK); virtual ~SendQueue(); @@ -91,7 +91,7 @@ private slots: void run(); private: - SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber); + SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber, bool hasReceivedHandshakeACK); SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; From 553e4e24493080d66b1787bf534595144f97e77c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Dec 2017 17:26:23 -0800 Subject: [PATCH 037/102] fix RPATH for oven so it loads things from macdeployqt --- tools/oven/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/oven/CMakeLists.txt b/tools/oven/CMakeLists.txt index 321f81ba8f..5e30b84803 100644 --- a/tools/oven/CMakeLists.txt +++ b/tools/oven/CMakeLists.txt @@ -8,13 +8,14 @@ setup_memory_debugger() if (WIN32) package_libraries_for_deployment() -endif () - -if (UNIX) +elseif (UNIX) find_package(Threads REQUIRED) if(THREADS_HAVE_PTHREAD_ARG) target_compile_options(PUBLIC oven "-pthread") endif() -endif () +elseif (APPLE) + # Fix up the rpath so macdeployqt works + set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks") +endif() install_beside_console() From 1f57ac608124b54e1e69d0dd18a52ebf93f19187 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Dec 2017 18:08:39 -0800 Subject: [PATCH 038/102] don't trigger unix step on apple for oven --- tools/oven/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/oven/CMakeLists.txt b/tools/oven/CMakeLists.txt index 5e30b84803..00344179bd 100644 --- a/tools/oven/CMakeLists.txt +++ b/tools/oven/CMakeLists.txt @@ -8,7 +8,7 @@ setup_memory_debugger() if (WIN32) package_libraries_for_deployment() -elseif (UNIX) +elseif (UNIX AND NOT APPLE) find_package(Threads REQUIRED) if(THREADS_HAVE_PTHREAD_ARG) target_compile_options(PUBLIC oven "-pthread") From ad547f483d76cb488f929dbc95874795e144e503 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 13 Dec 2017 19:25:24 -0800 Subject: [PATCH 039/102] Keep track of message numbers --- libraries/networking/src/udt/Connection.cpp | 10 ++++++---- libraries/networking/src/udt/Connection.h | 2 ++ libraries/networking/src/udt/PacketQueue.cpp | 2 +- libraries/networking/src/udt/PacketQueue.h | 4 +++- libraries/networking/src/udt/SendQueue.cpp | 19 +++++++++---------- libraries/networking/src/udt/SendQueue.h | 8 ++++++-- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 5f632fa25f..fc590c3a66 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -90,6 +90,9 @@ void Connection::stopSendQueue() { // tell the send queue to stop and be deleted sendQueue->stop(); + + _lastMessageNumber = sendQueue->getCurrentMessageNumber(); + sendQueue->deleteLater(); // wait on the send queue thread so we know the send queue is gone @@ -116,11 +119,11 @@ SendQueue& Connection::getSendQueue() { if (!_hasReceivedHandshakeACK) { // First time creating a send queue for this connection - _sendQueue = SendQueue::create(_parentSocket, _destination, _initialSequenceNumber - 1, _hasReceivedHandshakeACK); + _sendQueue = SendQueue::create(_parentSocket, _destination, _initialSequenceNumber - 1, _lastMessageNumber, _hasReceivedHandshakeACK); _lastReceivedACK = _sendQueue->getCurrentSequenceNumber(); } else { // Connection already has a handshake from a previous send queue - _sendQueue = SendQueue::create(_parentSocket, _destination, _lastReceivedACK, _hasReceivedHandshakeACK); + _sendQueue = SendQueue::create(_parentSocket, _destination, _lastReceivedACK, _lastMessageNumber, _hasReceivedHandshakeACK); } #ifdef UDT_CONNECTION_DEBUG @@ -417,7 +420,6 @@ void Connection::sendHandshakeRequest() { } bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize) { - if (!_hasReceivedHandshake) { // Refuse to process any packets until we've received the handshake // Send handshake request to re-request a handshake @@ -509,7 +511,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in } else { _stats.recordReceivedPackets(payloadSize, packetSize); } - + return !wasDuplicate; } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index a13c29adc8..4f979750f9 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -137,6 +137,8 @@ private: SequenceNumber _initialSequenceNumber; // Randomized on Connection creation, identifies connection during re-connect requests SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer Connection on creation, identifies connection during re-connect requests + MessageNumber _lastMessageNumber; + LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer SequenceNumber _lastReceivedACK; // The last ACK received diff --git a/libraries/networking/src/udt/PacketQueue.cpp b/libraries/networking/src/udt/PacketQueue.cpp index 9560f2f187..0560855ecb 100644 --- a/libraries/networking/src/udt/PacketQueue.cpp +++ b/libraries/networking/src/udt/PacketQueue.cpp @@ -15,7 +15,7 @@ using namespace udt; -PacketQueue::PacketQueue() { +PacketQueue::PacketQueue(MessageNumber messageNumber) : _currentMessageNumber(messageNumber) { _channels.emplace_back(new std::list()); } diff --git a/libraries/networking/src/udt/PacketQueue.h b/libraries/networking/src/udt/PacketQueue.h index 2b3d3a4b5b..bc4c5e3432 100644 --- a/libraries/networking/src/udt/PacketQueue.h +++ b/libraries/networking/src/udt/PacketQueue.h @@ -34,7 +34,7 @@ class PacketQueue { using Channels = std::vector; public: - PacketQueue(); + PacketQueue(MessageNumber messageNumber = 0); void queuePacket(PacketPointer packet); void queuePacketList(PacketListPointer packetList); @@ -42,6 +42,8 @@ public: PacketPointer takePacket(); Mutex& getLock() { return _packetsLock; } + + MessageNumber getCurrentMessageNumber() const { return _currentMessageNumber; } private: MessageNumber getNextMessageNumber(); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 3dbfb35fbe..43477e4562 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -61,10 +61,12 @@ private: Mutex2& _mutex2; }; -std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber, bool hasReceivedHandshakeACK) { +std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber, + MessageNumber currentMessageNumber, bool hasReceivedHandshakeACK) { Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*"); - auto queue = std::unique_ptr(new SendQueue(socket, destination, currentSequenceNumber, hasReceivedHandshakeACK)); + auto queue = std::unique_ptr(new SendQueue(socket, destination, currentSequenceNumber, + currentMessageNumber, hasReceivedHandshakeACK)); // Setup queue private thread QThread* thread = new QThread; @@ -83,19 +85,16 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destin return queue; } -SendQueue::SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber, bool hasReceivedHandshakeACK) : +SendQueue::SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber, + MessageNumber currentMessageNumber, bool hasReceivedHandshakeACK) : _socket(socket), - _destination(dest) + _destination(dest), + _packets(currentMessageNumber) { // set our member variables from current sequence number _currentSequenceNumber = currentSequenceNumber; _atomicCurrentSequenceNumber = uint32_t(_currentSequenceNumber); - - if (hasReceivedHandshakeACK) { - _lastACKSequenceNumber = uint32_t(_currentSequenceNumber); - } else { - _lastACKSequenceNumber = uint32_t(_currentSequenceNumber - 1); - } + _lastACKSequenceNumber = uint32_t(_currentSequenceNumber); _hasReceivedHandshakeACK = hasReceivedHandshakeACK; diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 29fe6b35ff..b33180c1e2 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -50,7 +50,9 @@ public: Stopped }; - static std::unique_ptr create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber, bool hasReceivedHandshakeACK); + static std::unique_ptr create(Socket* socket, HifiSockAddr destination, + SequenceNumber currentSequenceNumber, MessageNumber currentMessageNumber, + bool hasReceivedHandshakeACK); virtual ~SendQueue(); @@ -58,6 +60,7 @@ public: void queuePacketList(std::unique_ptr packetList); SequenceNumber getCurrentSequenceNumber() const { return SequenceNumber(_atomicCurrentSequenceNumber); } + MessageNumber getCurrentMessageNumber() const { return _packets.getCurrentMessageNumber(); } void setFlowWindowSize(int flowWindowSize) { _flowWindowSize = flowWindowSize; } @@ -91,7 +94,8 @@ private slots: void run(); private: - SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber, bool hasReceivedHandshakeACK); + SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber, + MessageNumber currentMessageNumber, bool hasReceivedHandshakeACK); SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; From 77b102669e454b59f394e768b1752ff831719ee9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 12 Dec 2017 12:38:01 -0800 Subject: [PATCH 040/102] try harder to keep setTimeout loop going in controller-dispatcher --- scripts/system/controllers/controllerDispatcher.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 57f3b4fd8b..af3b1d2ed6 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -154,6 +154,15 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; this.update = function () { + try { + this.updateInternal(); + } catch (e) { + print(e); + } + Script.setTimeout(_this.update, BASIC_TIMER_INTERVAL_MS); + }; + + this.updateInternal = function () { if (PROFILE) { Script.beginProfileRange("dispatch.pre"); } @@ -376,7 +385,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (PROFILE) { Script.endProfileRange("dispatch.run"); } - Script.setTimeout(_this.update, BASIC_TIMER_INTERVAL_MS); }; this.setBlacklist = function() { From 9863458fef38ca0243c6d7945e16ba7a1192d6c5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 12 Dec 2017 12:59:35 -0800 Subject: [PATCH 041/102] oops --- scripts/system/controllers/controllerDispatcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index af3b1d2ed6..915b3b3680 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -155,7 +155,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.update = function () { try { - this.updateInternal(); + _this.updateInternal(); } catch (e) { print(e); } From 7f948586dd09afd464f7b5bb53756a29f45abd59 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Dec 2017 12:07:32 -0800 Subject: [PATCH 042/102] fix message erase in conn, SendQueue ctor order --- libraries/networking/src/udt/Connection.cpp | 13 +++++++++---- libraries/networking/src/udt/Connection.h | 1 - libraries/networking/src/udt/SendQueue.cpp | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index fc590c3a66..2f57523f79 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -193,11 +193,16 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { while (pendingMessage.hasAvailablePackets()) { auto packet = pendingMessage.removeNextPacket(); - _parentSocket->messageReceived(std::move(packet)); - } - if (pendingMessage.isComplete()) { - _pendingReceivedMessages.erase(messageNumber); + auto packetPosition = packet->getPacketPosition(); + + _parentSocket->messageReceived(std::move(packet)); + + // if this was the last or only packet, then we can remove the pending message from our hash + if (packetPosition == Packet::PacketPosition::LAST || + packetPosition == Packet::PacketPosition::ONLY) { + _pendingReceivedMessages.erase(messageNumber); + } } } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 4f979750f9..8a96b1ded3 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -37,7 +37,6 @@ class Socket; class PendingReceivedMessage { public: void enqueuePacket(std::unique_ptr packet); - bool isComplete() const { return _hasLastPacket && _numPackets == _packets.size(); } bool hasAvailablePackets() const; std::unique_ptr removeNextPacket(); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 43477e4562..e7d1ab104a 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -87,9 +87,9 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destin SendQueue::SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber, MessageNumber currentMessageNumber, bool hasReceivedHandshakeACK) : + _packets(currentMessageNumber), _socket(socket), - _destination(dest), - _packets(currentMessageNumber) + _destination(dest) { // set our member variables from current sequence number _currentSequenceNumber = currentSequenceNumber; From 1d4801adf5edad026571b84dae96c3bce0a938b4 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 14 Dec 2017 13:48:31 -0800 Subject: [PATCH 043/102] Fix for Haze crash (bug 10537) --- libraries/render-utils/src/DrawHaze.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index 4431c1bbc3..da07f5bd9b 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -169,7 +169,12 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu auto hazeStage = args->_scene->getStage(); if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) { model::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front()); - batch.setUniformBuffer(HazeEffect_ParamsSlot, hazePointer->getHazeParametersBuffer()); + if (hazePointer) { + batch.setUniformBuffer(HazeEffect_ParamsSlot, hazePointer->getHazeParametersBuffer()); + } else { + // Something is wrong, so just quit Haze + return; + } } batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer()); @@ -178,7 +183,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu if (lightStage) { model::LightPointer keyLight; keyLight = lightStage->getCurrentKeyLight(); - if (keyLight != nullptr) { + if (keyLight) { batch.setUniformBuffer(HazeEffect_LightingMapSlot, keyLight->getLightSchemaBuffer()); } } From 8b5e8f8d0843ead1df30949ad2900390de938a00 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Dec 2017 15:30:25 -0800 Subject: [PATCH 044/102] only de-activate the SendQueue when it has nothing to send --- libraries/networking/src/udt/SendQueue.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index e7d1ab104a..4a0500f642 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -538,28 +538,6 @@ bool SendQueue::maybeResendPacket() { bool SendQueue::isInactive(bool attemptedToSendPacket) { // check for connection timeout first - // that will be the case if we have had 16 timeouts since hearing back from the client, and it has been - // at least 5 seconds - static const int NUM_TIMEOUTS_BEFORE_INACTIVE = 16; - static const int MIN_MS_BEFORE_INACTIVE = 5 * 1000; - - auto sinceLastResponse = (QDateTime::currentMSecsSinceEpoch() - _lastReceiverResponse); - - if (sinceLastResponse > 0 && - sinceLastResponse >= int64_t(NUM_TIMEOUTS_BEFORE_INACTIVE * (_estimatedTimeout / USECS_PER_MSEC)) && - sinceLastResponse > MIN_MS_BEFORE_INACTIVE) { - // If the flow window has been full for over CONSIDER_INACTIVE_AFTER, - // then signal the queue is inactive and return so it can be cleaned up - -#ifdef UDT_CONNECTION_DEBUG - qCDebug(networking) << "SendQueue to" << _destination << "reached" << NUM_TIMEOUTS_BEFORE_INACTIVE << "timeouts" - << "and" << MIN_MS_BEFORE_INACTIVE << "milliseconds before receiving any ACK/NAK and is now inactive. Stopping."; -#endif - - deactivate(); - return true; - } - if (!attemptedToSendPacket) { // During our processing above we didn't send any packets From da56d4730747bfa5ff8073249694cb3f9adc0a16 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Dec 2017 15:30:51 -0800 Subject: [PATCH 045/102] make the _lastMessageNumber in Connection default to 0 --- libraries/networking/src/udt/Connection.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 8a96b1ded3..0017eb204a 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -136,7 +136,7 @@ private: SequenceNumber _initialSequenceNumber; // Randomized on Connection creation, identifies connection during re-connect requests SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer Connection on creation, identifies connection during re-connect requests - MessageNumber _lastMessageNumber; + MessageNumber _lastMessageNumber { 0 }; LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer From 00a2013b6064b71e14a90aa19148fb3c8818dff0 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 14 Dec 2017 15:38:07 -0800 Subject: [PATCH 046/102] Added missing space before { --- libraries/model/src/model/Haze.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model/src/model/Haze.h b/libraries/model/src/model/Haze.h index 5c916c3b91..2a575eb151 100644 --- a/libraries/model/src/model/Haze.h +++ b/libraries/model/src/model/Haze.h @@ -128,7 +128,7 @@ namespace model { Parameters() {} }; - UniformBufferView _hazeParametersBuffer{ nullptr }; + UniformBufferView _hazeParametersBuffer { nullptr }; }; using HazePointer = std::shared_ptr; From d5d4c22a3d4aedd7de0d27bea1d6b71610352589 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 14 Dec 2017 15:55:31 -0800 Subject: [PATCH 047/102] Removed dual calls to getViewInverse(). --- libraries/render-utils/src/Haze.slf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index d758756975..e394207d16 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -48,8 +48,10 @@ void main(void) { vec4 fragColor = texture(colorMap, varTexCoord0); vec4 eyeFragPos = unpackPositionFromZeye(varTexCoord0); - vec4 worldFragPos = getViewInverse() * eyeFragPos; - vec4 worldEyePos = getViewInverse()[3]; + + mat4 viewInverse = getViewInverse(); + vec4 worldFragPos = viewInverse * eyeFragPos; + vec4 worldEyePos = viewInverse[3]; outFragColor = computeHazeColor(fragColor, eyeFragPos, worldFragPos, worldEyePos); } From 05e47ae668254ea2437da0bb6ac2e93fb43048b0 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 14 Dec 2017 16:14:08 -0800 Subject: [PATCH 048/102] Removed unneeded 'mix'. Defined EPSILON. --- libraries/render-utils/src/Haze.slh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index 97284f1c2a..ddc4e6e945 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -89,9 +89,7 @@ vec3 computeHazeColorKeyLightAttenuation(vec3 color, Light directionalLight, vec // hazeIntegral *= (1.0 - exp (-t)) / t; hazeIntegral *= 0.3171178; - float hazeAmount = 1.0 - exp(-hazeIntegral); - - return mix(color, vec3(0.0, 0.0, 0.0), hazeAmount); + return color * exp(-hazeIntegral); } // Input: @@ -177,7 +175,8 @@ vec4 computeHazeColor(vec4 fragColor, vec4 eyeFragPos, vec4 worldFragPos, vec4 w if (abs(deltaHeight) > slopeThreshold) { float t = hazeParams.hazeHeightFactor * deltaHeight; // Protect from wild values - if (abs(t) > 0.0000001) { + const float EPSILON = 0.0000001f; + if (abs(t) > EPSILON) { hazeIntegral *= (1.0 - exp (-t)) / t; } } @@ -189,7 +188,7 @@ vec4 computeHazeColor(vec4 fragColor, vec4 eyeFragPos, vec4 worldFragPos, vec4 w } // Mix with background at far range - const float BLEND_DISTANCE = 27000.0; + const float BLEND_DISTANCE = 27000.0f; vec4 outFragColor; if (distance > BLEND_DISTANCE) { outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlend); From 026b19d770f121bad061bd7375525626e7c69227 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 14 Dec 2017 16:17:50 -0800 Subject: [PATCH 049/102] Set 4th position component from 0.0 to 1.0 --- libraries/render-utils/src/DeferredGlobalLight.slh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 311012716a..831f5732ab 100644 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -224,7 +224,7 @@ vec3 evalGlobalLightingAlphaBlendedWithHaze( vec4 colorV4 = computeHazeColor( vec4(color, 0.0), // fragment original color vec4(position, 0.0), // fragment position in eye coordinates - vec4(fragEyeVector, 0.0), // fragment position in world coordinates + vec4(fragEyeVector, 1.0), // fragment position in world coordinates invViewMat[3]); // eye position in world coordinates color = colorV4.rgb; From c352d5fc23c52ee12eb5fb4875caf157a21c4ff0 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 14 Dec 2017 16:23:14 -0800 Subject: [PATCH 050/102] Passed light direction instead of light object into `computeHazeColorKeyLightAttenuation`. --- libraries/render-utils/src/DeferredGlobalLight.slh | 6 +----- libraries/render-utils/src/Haze.slh | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 831f5732ab..9de7c7eb3a 100644 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -121,10 +121,6 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu color += ambientDiffuse; color += ambientSpecular; - // Directional - // Get directional light (used by both directional light and haze attenuation) - Light directionalLight = getLight(); - vec3 directionalDiffuse; vec3 directionalSpecular; evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation @@ -137,7 +133,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu // Attenuate the light if haze effect selected if ((hazeParams.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) { - color = computeHazeColorKeyLightAttenuation(color, directionalLight, position); + color = computeHazeColorKeyLightAttenuation(color, lightDirection, position); } return color; diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index ddc4e6e945..7e74b91ede 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -50,13 +50,12 @@ layout(std140) uniform hazeBuffer { // // General algorithm taken from http://www.iquilezles.org/www/articles/fog/fog.htm, with permission // -vec3 computeHazeColorKeyLightAttenuation(vec3 color, Light directionalLight, vec3 worldFragPos) { +vec3 computeHazeColorKeyLightAttenuation(vec3 color, vec3 lightDirection, vec3 worldFragPos) { // Directional light attenuation is simulated by assuming the light source is at a fixed height above the // fragment. This height is where the haze density is reduced by 95% from the haze at the fragment's height // // The distance is computed from the height and the directional light orientation // The distance is limited to height * 1,000, which gives an angle of ~0.057 degrees - vec3 lightDirection = getLightDirection(directionalLight); // Height at which haze density is reduced by 95% (default set to 2000.0 for safety ,this should never happen) float height_95p = 2000.0; From a4696cc2b3ac311739b43266aa4f876b2b056e2d Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 8 Dec 2017 00:20:35 +0300 Subject: [PATCH 051/102] 8992 Login window is small in tablet --- interface/resources/qml/LoginDialog/LinkAccountBody.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 300bcd46f0..0e2f2a5282 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -52,7 +52,11 @@ Item { targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height } - parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth)); + var newWidth = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth)); + if(!isNaN(newWidth)) { + parent.width = root.width = newWidth; + } + parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)) + (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y); } From 82b94eaacd58d33157017f03c47d5a23198f8ff1 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 14 Dec 2017 18:50:41 -0800 Subject: [PATCH 052/102] Reduced size of parameters in (shader) function call. --- .../render-utils/src/DeferredGlobalLight.slh | 9 ++++---- libraries/render-utils/src/Haze.slf | 2 +- libraries/render-utils/src/Haze.slh | 22 +++++++++---------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 9de7c7eb3a..6cdc02b7a5 100644 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -218,10 +218,11 @@ vec3 evalGlobalLightingAlphaBlendedWithHaze( // Haze if ((hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE) { vec4 colorV4 = computeHazeColor( - vec4(color, 0.0), // fragment original color - vec4(position, 0.0), // fragment position in eye coordinates - vec4(fragEyeVector, 1.0), // fragment position in world coordinates - invViewMat[3]); // eye position in world coordinates + vec4(color, 1.0), // fragment original color + position, // fragment position in eye coordinates + fragEyeVector, // fragment position in world coordinates + invViewMat[3].y // eye height in world coordinates + ); color = colorV4.rgb; } diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index e394207d16..5f05d52f83 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -53,6 +53,6 @@ void main(void) { vec4 worldFragPos = viewInverse * eyeFragPos; vec4 worldEyePos = viewInverse[3]; - outFragColor = computeHazeColor(fragColor, eyeFragPos, worldFragPos, worldEyePos); + outFragColor = computeHazeColor(fragColor, eyeFragPos.xyz, worldFragPos.xyz, worldEyePos.y); } diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index 7e74b91ede..2fcf5f4418 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -92,24 +92,24 @@ vec3 computeHazeColorKeyLightAttenuation(vec3 color, vec3 lightDirection, vec3 w } // Input: -// fragColor - fragment original color -// eyeFragPos - fragment position in eye coordinates -// worldFragPos - fragment position in world coordinates -// worldEyePos - eye position in world coordinates +// fragColor - fragment original color +// eyeFragPos - fragment position in eye coordinates +// worldFragPos - fragment position in world coordinates +// worldEyeHeight - eye height in world coordinates // Output: // fragment colour after haze effect // // General algorithm taken from http://www.iquilezles.org/www/articles/fog/fog.htm, with permission // -vec4 computeHazeColor(vec4 fragColor, vec4 eyeFragPos, vec4 worldFragPos, vec4 worldEyePos) { +vec4 computeHazeColor(vec4 fragColor, vec3 eyeFragPos, vec3 worldFragPos, float worldEyeHeight) { // Distance to fragment - float distance = length(eyeFragPos.xyz); + float distance = length(eyeFragPos); // Convert haze colour from uniform into a vec4 vec4 hazeColor = vec4(hazeParams.hazeColor, 1.0); // Directional light component is a function of the angle from the eye, between the fragment and the sun - vec3 eyeFragDir = normalize(worldFragPos.xyz); + vec3 eyeFragDir = normalize(worldFragPos); Light light = getLight(); vec3 lightDirection = getLightDirection(light); @@ -137,12 +137,12 @@ vec4 computeHazeColor(vec4 fragColor, vec4 eyeFragPos, vec4 worldFragPos, vec4 w // Note that the haze base reference affects only the haze density as function of altitude vec3 hazeDensityDistribution = hazeParams.colorModulationFactor * - exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference)); + exp(-hazeParams.hazeHeightFactor * (worldEyeHeight - hazeParams.hazeBaseReference)); vec3 hazeIntegral = hazeDensityDistribution * distance; const float slopeThreshold = 0.01; - float deltaHeight = worldFragPos.y - worldEyePos.y; + float deltaHeight = worldFragPos.y - worldEyeHeight; if (abs(deltaHeight) > slopeThreshold) { float t = hazeParams.hazeHeightFactor * deltaHeight; hazeIntegral *= (1.0 - exp (-t)) / t; @@ -165,12 +165,12 @@ vec4 computeHazeColor(vec4 fragColor, vec4 eyeFragPos, vec4 worldFragPos, vec4 w // Note that the haze base reference affects only the haze density as function of altitude float hazeDensityDistribution = hazeParams.hazeRangeFactor * - exp(-hazeParams.hazeHeightFactor * (worldEyePos.y - hazeParams.hazeBaseReference)); + exp(-hazeParams.hazeHeightFactor * (worldEyeHeight - hazeParams.hazeBaseReference)); float hazeIntegral = hazeDensityDistribution * distance; const float slopeThreshold = 0.01; - float deltaHeight = worldFragPos.y - worldEyePos.y; + float deltaHeight = worldFragPos.y - worldEyeHeight; if (abs(deltaHeight) > slopeThreshold) { float t = hazeParams.hazeHeightFactor * deltaHeight; // Protect from wild values From 52c4aef72125ed834c444e3a1868aab827621bdb Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Dec 2017 16:23:53 -0800 Subject: [PATCH 053/102] keep _cacheFile alive --- libraries/gpu/src/gpu/Texture.h | 5 ++--- libraries/gpu/src/gpu/Texture_ktx.cpp | 29 +++++---------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 1877b494cf..26de5a0804 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -324,9 +324,8 @@ public: protected: std::shared_ptr maybeOpenFile() const; - mutable std::mutex _cacheFileCreateMutex; - mutable std::mutex _cacheFileWriteMutex; - mutable std::weak_ptr _cacheFile; + mutable std::mutex _cacheFileMutex; + mutable std::shared_ptr _cacheFile; std::string _filename; cache::FilePointer _cacheEntry; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 08fc4ec101..49e18aaf78 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -188,35 +188,17 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { } std::shared_ptr KtxStorage::maybeOpenFile() const { - // 1. Try to get the shared ptr - // 2. If it doesn't exist, grab the mutex around its creation - // 3. If it was created before we got the mutex, return it - // 4. Otherwise, create it - - std::shared_ptr file = _cacheFile.lock(); - if (file) { - return file; + if (!_cacheFile) { + _cacheFile = std::make_shared(_filename.c_str()); } - - { - std::lock_guard lock{ _cacheFileCreateMutex }; - - file = _cacheFile.lock(); - if (file) { - return file; - } - - file = std::make_shared(_filename.c_str()); - _cacheFile = file; - } - - return file; + return _cacheFile; } PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face); auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); if (faceSize != 0 && faceOffset != 0) { + std::lock_guard lock(_cacheFileMutex); auto file = maybeOpenFile(); if (file) { auto storageView = file->createView(faceSize, faceOffset); @@ -262,6 +244,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor return; } + std::lock_guard lock(_cacheFileMutex); auto file = maybeOpenFile(); if (!file) { qWarning() << "Failed to open file to assign mip data " << QString::fromStdString(_filename); @@ -279,8 +262,6 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor imageData += ktx::IMAGE_SIZE_WIDTH; { - std::lock_guard lock { _cacheFileWriteMutex }; - if (level != _minMipLevelAvailable - 1) { qWarning() << "Invalid level to be stored"; return; From 3477aa57a8980413a66d7cd2ed3c55f03eeadd9a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Dec 2017 16:36:07 -0800 Subject: [PATCH 054/102] remove extra recycle --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 0993daaa8b..cb9d06dce1 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -685,11 +685,6 @@ void OpenGLDisplayPlugin::present() { } incrementPresentCount(); - { - PROFILE_RANGE_EX(render, "recycle", 0xff00ff00, frameId) - _gpuContext->recycle(); - } - if (_currentFrame) { { withPresentThreadLock([&] { From 3ae52c0e0ef2cc54b2c31c6e02ddb71e7a13b6c8 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Dec 2017 17:52:48 -0800 Subject: [PATCH 055/102] clear all _cacheFiles on recycle --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 2 +- libraries/gpu/src/gpu/Texture.h | 7 ++++++- libraries/gpu/src/gpu/Texture_ktx.cpp | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 6fb0d7b152..fa336665a5 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -772,7 +772,7 @@ void GLBackend::recycle() const { GLVariableAllocationSupport::manageMemory(); GLVariableAllocationSupport::_frameTexturesCreated = 0; - + Texture::KtxStorage::clearKtxFiles(); } void GLBackend::setCameraCorrection(const Mat4& correction) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 26de5a0804..10edd895c0 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -321,10 +321,15 @@ public: void reset() override { } + // Don't keep files open forever. We close them at the beginning of each frame (GLBackend::recycle) + static std::vector, std::shared_ptr>> _cachedKtxFiles; + static std::mutex _cachedKtxFilesMutex; + static void clearKtxFiles(); + protected: std::shared_ptr maybeOpenFile() const; - mutable std::mutex _cacheFileMutex; + mutable std::shared_ptr _cacheFileMutex { std::make_shared() }; mutable std::shared_ptr _cacheFile; std::string _filename; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 49e18aaf78..46804b4b44 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -23,6 +23,9 @@ using namespace gpu; using PixelsPointer = Texture::PixelsPointer; using KtxStorage = Texture::KtxStorage; +std::vector, std::shared_ptr>> KtxStorage::_cachedKtxFiles; +std::mutex KtxStorage::_cachedKtxFilesMutex; + struct GPUKTXPayload { using Version = uint8; @@ -190,15 +193,26 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { std::shared_ptr KtxStorage::maybeOpenFile() const { if (!_cacheFile) { _cacheFile = std::make_shared(_filename.c_str()); + std::lock_guard lock(KtxStorage::_cachedKtxFilesMutex); + _cachedKtxFiles.emplace_back(_cacheFile, _cacheFileMutex); } return _cacheFile; } +void KtxStorage::clearKtxFiles() { + std::lock_guard lock(KtxStorage::_cachedKtxFilesMutex); + for (auto& cacheFileAndMutex : KtxStorage::_cachedKtxFiles) { + std::lock_guard lock(*(cacheFileAndMutex.second)); + cacheFileAndMutex.first.reset(); + } + _cachedKtxFiles.clear(); +} + PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face); auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); if (faceSize != 0 && faceOffset != 0) { - std::lock_guard lock(_cacheFileMutex); + std::lock_guard lock(*_cacheFileMutex); auto file = maybeOpenFile(); if (file) { auto storageView = file->createView(faceSize, faceOffset); @@ -244,7 +258,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor return; } - std::lock_guard lock(_cacheFileMutex); + std::lock_guard lock(*_cacheFileMutex); auto file = maybeOpenFile(); if (!file) { qWarning() << "Failed to open file to assign mip data " << QString::fromStdString(_filename); From d69297c02e9c9724cf093ad6cd1a5c09c933536f Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Sat, 16 Dec 2017 00:22:26 -0800 Subject: [PATCH 056/102] Replace `evalGlobalLightingAlphaBlended` with `evalGlobalLightingAlphaBlendedWithHaze` in all shaders. --- libraries/render-utils/src/forward_model_translucent.slf | 2 +- libraries/render-utils/src/model_translucent_fade.slf | 2 +- libraries/render-utils/src/overlay3D_model_translucent.slf | 2 +- libraries/render-utils/src/simple_transparent_textured.slf | 2 +- libraries/render-utils/src/simple_transparent_textured_fade.slf | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/forward_model_translucent.slf b/libraries/render-utils/src/forward_model_translucent.slf index 52e8ce50e7..906393db1f 100644 --- a/libraries/render-utils/src/forward_model_translucent.slf +++ b/libraries/render-utils/src/forward_model_translucent.slf @@ -66,7 +66,7 @@ void main(void) { TransformCamera cam = getTransformCamera(); - _fragColor = vec4(evalGlobalLightingAlphaBlended( + _fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze( cam._viewInverse, 1.0, occlusionTex, diff --git a/libraries/render-utils/src/model_translucent_fade.slf b/libraries/render-utils/src/model_translucent_fade.slf index c46b396ebc..9d5477304c 100644 --- a/libraries/render-utils/src/model_translucent_fade.slf +++ b/libraries/render-utils/src/model_translucent_fade.slf @@ -76,7 +76,7 @@ void main(void) { TransformCamera cam = getTransformCamera(); - _fragColor = vec4(evalGlobalLightingAlphaBlended( + _fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze( cam._viewInverse, 1.0, occlusionTex, diff --git a/libraries/render-utils/src/overlay3D_model_translucent.slf b/libraries/render-utils/src/overlay3D_model_translucent.slf index 748eea329c..b26e70f465 100644 --- a/libraries/render-utils/src/overlay3D_model_translucent.slf +++ b/libraries/render-utils/src/overlay3D_model_translucent.slf @@ -65,7 +65,7 @@ void main(void) { vec3 fragNormal; <$transformEyeToWorldDir(cam, _normal, fragNormal)$> - vec4 color = vec4(evalGlobalLightingAlphaBlended( + vec4 color = vec4(evalGlobalLightingAlphaBlendedWithHaze( cam._viewInverse, 1.0, occlusionTex, diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf index b9eb921e9d..b16b19c8b4 100644 --- a/libraries/render-utils/src/simple_transparent_textured.slf +++ b/libraries/render-utils/src/simple_transparent_textured.slf @@ -45,7 +45,7 @@ void main(void) { TransformCamera cam = getTransformCamera(); - _fragColor0 = vec4(evalGlobalLightingAlphaBlended( + _fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze( cam._viewInverse, 1.0, 1.0, diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf index 20c7907bbe..ad260210a7 100644 --- a/libraries/render-utils/src/simple_transparent_textured_fade.slf +++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf @@ -57,7 +57,7 @@ void main(void) { TransformCamera cam = getTransformCamera(); - _fragColor0 = vec4(evalGlobalLightingAlphaBlended( + _fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze( cam._viewInverse, 1.0, 1.0, From 6990dda48d9d4504f732871968a44da3ff9cd5df Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Sun, 17 Dec 2017 15:56:34 -0800 Subject: [PATCH 057/102] cr and cleanup --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 2 +- libraries/gpu/src/gpu/Texture.h | 7 ++++--- libraries/gpu/src/gpu/Texture_ktx.cpp | 13 ++++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index fa336665a5..f93d430152 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -772,7 +772,7 @@ void GLBackend::recycle() const { GLVariableAllocationSupport::manageMemory(); GLVariableAllocationSupport::_frameTexturesCreated = 0; - Texture::KtxStorage::clearKtxFiles(); + Texture::KtxStorage::releaseOpenKtxFiles(); } void GLBackend::setCameraCorrection(const Mat4& correction) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 10edd895c0..7c087fec2b 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -322,9 +322,7 @@ public: void reset() override { } // Don't keep files open forever. We close them at the beginning of each frame (GLBackend::recycle) - static std::vector, std::shared_ptr>> _cachedKtxFiles; - static std::mutex _cachedKtxFilesMutex; - static void clearKtxFiles(); + static void releaseOpenKtxFiles(); protected: std::shared_ptr maybeOpenFile() const; @@ -332,6 +330,9 @@ public: mutable std::shared_ptr _cacheFileMutex { std::make_shared() }; mutable std::shared_ptr _cacheFile; + static std::vector, std::shared_ptr>> _cachedKtxFiles; + static std::mutex _cachedKtxFilesMutex; + std::string _filename; cache::FilePointer _cacheEntry; std::atomic _minMipLevelAvailable; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 46804b4b44..8b054816bb 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -193,19 +193,22 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { std::shared_ptr KtxStorage::maybeOpenFile() const { if (!_cacheFile) { _cacheFile = std::make_shared(_filename.c_str()); - std::lock_guard lock(KtxStorage::_cachedKtxFilesMutex); + std::lock_guard lock(_cachedKtxFilesMutex); _cachedKtxFiles.emplace_back(_cacheFile, _cacheFileMutex); } return _cacheFile; } -void KtxStorage::clearKtxFiles() { - std::lock_guard lock(KtxStorage::_cachedKtxFilesMutex); - for (auto& cacheFileAndMutex : KtxStorage::_cachedKtxFiles) { +void KtxStorage::releaseOpenKtxFiles() { + std::vector, std::shared_ptr>> localKtxFiles; + { + std::lock_guard lock(_cachedKtxFilesMutex); + localKtxFiles.swap(_cachedKtxFiles); + } + for (auto& cacheFileAndMutex : localKtxFiles) { std::lock_guard lock(*(cacheFileAndMutex.second)); cacheFileAndMutex.first.reset(); } - _cachedKtxFiles.clear(); } PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { From 6814dfcbfc5eee145e6201ebb86de729842952bf Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Sun, 17 Dec 2017 22:09:20 -0800 Subject: [PATCH 058/102] weak_ptr _cacheFile --- libraries/gpu/src/gpu/Texture.h | 2 +- libraries/gpu/src/gpu/Texture_ktx.cpp | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 7c087fec2b..06208179e0 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -328,7 +328,7 @@ public: std::shared_ptr maybeOpenFile() const; mutable std::shared_ptr _cacheFileMutex { std::make_shared() }; - mutable std::shared_ptr _cacheFile; + mutable std::weak_ptr _cacheFile; static std::vector, std::shared_ptr>> _cachedKtxFiles; static std::mutex _cachedKtxFilesMutex; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 8b054816bb..883d9abf15 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -190,13 +190,25 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { } } +// maybeOpenFile should be called with _cacheFileMutex already held to avoid modifying the file from multiple threads std::shared_ptr KtxStorage::maybeOpenFile() const { - if (!_cacheFile) { - _cacheFile = std::make_shared(_filename.c_str()); - std::lock_guard lock(_cachedKtxFilesMutex); - _cachedKtxFiles.emplace_back(_cacheFile, _cacheFileMutex); + // Try to get the shared_ptr + std::shared_ptr file = _cacheFile.lock(); + if (file) { + return file; } - return _cacheFile; + + // If the file isn't open, create it and save a weak_ptr to it + file = std::make_shared(_filename.c_str()); + _cacheFile = file; + + { + // Add the shared_ptr to the global list of open KTX files, to be released at the beginning of the next present thread frame + std::lock_guard lock(_cachedKtxFilesMutex); + _cachedKtxFiles.emplace_back(file, _cacheFileMutex); + } + + return file; } void KtxStorage::releaseOpenKtxFiles() { From 355ceddcc6a0b839bb20a515fc329d6939b98e68 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Dec 2017 16:23:53 -0800 Subject: [PATCH 059/102] keep _cacheFile alive --- libraries/gpu/src/gpu/Texture.h | 5 ++--- libraries/gpu/src/gpu/Texture_ktx.cpp | 29 +++++---------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 1877b494cf..26de5a0804 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -324,9 +324,8 @@ public: protected: std::shared_ptr maybeOpenFile() const; - mutable std::mutex _cacheFileCreateMutex; - mutable std::mutex _cacheFileWriteMutex; - mutable std::weak_ptr _cacheFile; + mutable std::mutex _cacheFileMutex; + mutable std::shared_ptr _cacheFile; std::string _filename; cache::FilePointer _cacheEntry; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 08fc4ec101..49e18aaf78 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -188,35 +188,17 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { } std::shared_ptr KtxStorage::maybeOpenFile() const { - // 1. Try to get the shared ptr - // 2. If it doesn't exist, grab the mutex around its creation - // 3. If it was created before we got the mutex, return it - // 4. Otherwise, create it - - std::shared_ptr file = _cacheFile.lock(); - if (file) { - return file; + if (!_cacheFile) { + _cacheFile = std::make_shared(_filename.c_str()); } - - { - std::lock_guard lock{ _cacheFileCreateMutex }; - - file = _cacheFile.lock(); - if (file) { - return file; - } - - file = std::make_shared(_filename.c_str()); - _cacheFile = file; - } - - return file; + return _cacheFile; } PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face); auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); if (faceSize != 0 && faceOffset != 0) { + std::lock_guard lock(_cacheFileMutex); auto file = maybeOpenFile(); if (file) { auto storageView = file->createView(faceSize, faceOffset); @@ -262,6 +244,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor return; } + std::lock_guard lock(_cacheFileMutex); auto file = maybeOpenFile(); if (!file) { qWarning() << "Failed to open file to assign mip data " << QString::fromStdString(_filename); @@ -279,8 +262,6 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor imageData += ktx::IMAGE_SIZE_WIDTH; { - std::lock_guard lock { _cacheFileWriteMutex }; - if (level != _minMipLevelAvailable - 1) { qWarning() << "Invalid level to be stored"; return; From 90b97aba59214e9d5b5a70dd94141f95c0fb82ed Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Dec 2017 16:36:07 -0800 Subject: [PATCH 060/102] remove extra recycle --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 0993daaa8b..cb9d06dce1 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -685,11 +685,6 @@ void OpenGLDisplayPlugin::present() { } incrementPresentCount(); - { - PROFILE_RANGE_EX(render, "recycle", 0xff00ff00, frameId) - _gpuContext->recycle(); - } - if (_currentFrame) { { withPresentThreadLock([&] { From 9bdcf34c9162cb3651d6eabbb32903fdec0cfa15 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Dec 2017 17:52:48 -0800 Subject: [PATCH 061/102] clear all _cacheFiles on recycle --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 2 +- libraries/gpu/src/gpu/Texture.h | 7 ++++++- libraries/gpu/src/gpu/Texture_ktx.cpp | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index f138244fa2..0a71ee513a 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -776,7 +776,7 @@ void GLBackend::recycle() const { GLVariableAllocationSupport::manageMemory(); GLVariableAllocationSupport::_frameTexturesCreated = 0; - + Texture::KtxStorage::clearKtxFiles(); } void GLBackend::setCameraCorrection(const Mat4& correction) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 26de5a0804..10edd895c0 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -321,10 +321,15 @@ public: void reset() override { } + // Don't keep files open forever. We close them at the beginning of each frame (GLBackend::recycle) + static std::vector, std::shared_ptr>> _cachedKtxFiles; + static std::mutex _cachedKtxFilesMutex; + static void clearKtxFiles(); + protected: std::shared_ptr maybeOpenFile() const; - mutable std::mutex _cacheFileMutex; + mutable std::shared_ptr _cacheFileMutex { std::make_shared() }; mutable std::shared_ptr _cacheFile; std::string _filename; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 49e18aaf78..46804b4b44 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -23,6 +23,9 @@ using namespace gpu; using PixelsPointer = Texture::PixelsPointer; using KtxStorage = Texture::KtxStorage; +std::vector, std::shared_ptr>> KtxStorage::_cachedKtxFiles; +std::mutex KtxStorage::_cachedKtxFilesMutex; + struct GPUKTXPayload { using Version = uint8; @@ -190,15 +193,26 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { std::shared_ptr KtxStorage::maybeOpenFile() const { if (!_cacheFile) { _cacheFile = std::make_shared(_filename.c_str()); + std::lock_guard lock(KtxStorage::_cachedKtxFilesMutex); + _cachedKtxFiles.emplace_back(_cacheFile, _cacheFileMutex); } return _cacheFile; } +void KtxStorage::clearKtxFiles() { + std::lock_guard lock(KtxStorage::_cachedKtxFilesMutex); + for (auto& cacheFileAndMutex : KtxStorage::_cachedKtxFiles) { + std::lock_guard lock(*(cacheFileAndMutex.second)); + cacheFileAndMutex.first.reset(); + } + _cachedKtxFiles.clear(); +} + PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face); auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); if (faceSize != 0 && faceOffset != 0) { - std::lock_guard lock(_cacheFileMutex); + std::lock_guard lock(*_cacheFileMutex); auto file = maybeOpenFile(); if (file) { auto storageView = file->createView(faceSize, faceOffset); @@ -244,7 +258,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor return; } - std::lock_guard lock(_cacheFileMutex); + std::lock_guard lock(*_cacheFileMutex); auto file = maybeOpenFile(); if (!file) { qWarning() << "Failed to open file to assign mip data " << QString::fromStdString(_filename); From a39eea5a34812497203d42be1b885c504356cdce Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Sun, 17 Dec 2017 15:56:34 -0800 Subject: [PATCH 062/102] cr and cleanup --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 2 +- libraries/gpu/src/gpu/Texture.h | 7 ++++--- libraries/gpu/src/gpu/Texture_ktx.cpp | 13 ++++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 0a71ee513a..a36a6e0fb5 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -776,7 +776,7 @@ void GLBackend::recycle() const { GLVariableAllocationSupport::manageMemory(); GLVariableAllocationSupport::_frameTexturesCreated = 0; - Texture::KtxStorage::clearKtxFiles(); + Texture::KtxStorage::releaseOpenKtxFiles(); } void GLBackend::setCameraCorrection(const Mat4& correction) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 10edd895c0..7c087fec2b 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -322,9 +322,7 @@ public: void reset() override { } // Don't keep files open forever. We close them at the beginning of each frame (GLBackend::recycle) - static std::vector, std::shared_ptr>> _cachedKtxFiles; - static std::mutex _cachedKtxFilesMutex; - static void clearKtxFiles(); + static void releaseOpenKtxFiles(); protected: std::shared_ptr maybeOpenFile() const; @@ -332,6 +330,9 @@ public: mutable std::shared_ptr _cacheFileMutex { std::make_shared() }; mutable std::shared_ptr _cacheFile; + static std::vector, std::shared_ptr>> _cachedKtxFiles; + static std::mutex _cachedKtxFilesMutex; + std::string _filename; cache::FilePointer _cacheEntry; std::atomic _minMipLevelAvailable; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 46804b4b44..8b054816bb 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -193,19 +193,22 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { std::shared_ptr KtxStorage::maybeOpenFile() const { if (!_cacheFile) { _cacheFile = std::make_shared(_filename.c_str()); - std::lock_guard lock(KtxStorage::_cachedKtxFilesMutex); + std::lock_guard lock(_cachedKtxFilesMutex); _cachedKtxFiles.emplace_back(_cacheFile, _cacheFileMutex); } return _cacheFile; } -void KtxStorage::clearKtxFiles() { - std::lock_guard lock(KtxStorage::_cachedKtxFilesMutex); - for (auto& cacheFileAndMutex : KtxStorage::_cachedKtxFiles) { +void KtxStorage::releaseOpenKtxFiles() { + std::vector, std::shared_ptr>> localKtxFiles; + { + std::lock_guard lock(_cachedKtxFilesMutex); + localKtxFiles.swap(_cachedKtxFiles); + } + for (auto& cacheFileAndMutex : localKtxFiles) { std::lock_guard lock(*(cacheFileAndMutex.second)); cacheFileAndMutex.first.reset(); } - _cachedKtxFiles.clear(); } PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { From c39da5094ba883d3c5edcce1c1adb6207f66477e Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Sun, 17 Dec 2017 22:09:20 -0800 Subject: [PATCH 063/102] weak_ptr _cacheFile --- libraries/gpu/src/gpu/Texture.h | 2 +- libraries/gpu/src/gpu/Texture_ktx.cpp | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 7c087fec2b..06208179e0 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -328,7 +328,7 @@ public: std::shared_ptr maybeOpenFile() const; mutable std::shared_ptr _cacheFileMutex { std::make_shared() }; - mutable std::shared_ptr _cacheFile; + mutable std::weak_ptr _cacheFile; static std::vector, std::shared_ptr>> _cachedKtxFiles; static std::mutex _cachedKtxFilesMutex; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 8b054816bb..883d9abf15 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -190,13 +190,25 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { } } +// maybeOpenFile should be called with _cacheFileMutex already held to avoid modifying the file from multiple threads std::shared_ptr KtxStorage::maybeOpenFile() const { - if (!_cacheFile) { - _cacheFile = std::make_shared(_filename.c_str()); - std::lock_guard lock(_cachedKtxFilesMutex); - _cachedKtxFiles.emplace_back(_cacheFile, _cacheFileMutex); + // Try to get the shared_ptr + std::shared_ptr file = _cacheFile.lock(); + if (file) { + return file; } - return _cacheFile; + + // If the file isn't open, create it and save a weak_ptr to it + file = std::make_shared(_filename.c_str()); + _cacheFile = file; + + { + // Add the shared_ptr to the global list of open KTX files, to be released at the beginning of the next present thread frame + std::lock_guard lock(_cachedKtxFilesMutex); + _cachedKtxFiles.emplace_back(file, _cacheFileMutex); + } + + return file; } void KtxStorage::releaseOpenKtxFiles() { From b0ecaa10d4511a70ed6a80e2a659df46d84fc604 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 18 Dec 2017 12:38:25 -0800 Subject: [PATCH 064/102] fix equirectangular skybox loading --- libraries/image/src/image/Image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 9e4ab2e43f..f78ed1a583 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -981,7 +981,7 @@ public: static QImage extractEquirectangularFace(const QImage& source, gpu::Texture::CubeFace face, int faceWidth) { QImage image(faceWidth, faceWidth, source.format()); - glm::vec2 dstInvSize(1.0f / (float)source.width(), 1.0f / (float)source.height()); + glm::vec2 dstInvSize(1.0f / faceWidth); struct CubeToXYZ { gpu::Texture::CubeFace _face; From 2fcf11455bfefa3107a533d9622610fa143bd887 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 18 Dec 2017 14:03:13 -0800 Subject: [PATCH 065/102] Fixing edit state detection --- scripts/system/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 1d9398fda8..e28f877d85 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -427,7 +427,7 @@ var toolBar = (function () { }); createButton = activeButton; tablet.screenChanged.connect(function (type, url) { - if (isActive && (type !== "QML" || url !== "Edit.qml")) { + if (isActive && (type !== "QML" || url !== "hifi/tablet/Edit.qml")) { that.setActive(false) } }); From bd666406f4635168b0dc1f4ce68810a6b580e13d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 19 Dec 2017 14:17:17 +0100 Subject: [PATCH 066/102] Removed glColor reset hack in MeshPartPayload and replaced it by a reset of the color attribute to white in the execution of the setInputFormat command of the various GLBackends --- .../src/RenderablePolyLineEntityItem.cpp | 1 + .../src/RenderableShapeEntityItem.cpp | 5 ++-- .../src/RenderableWebEntityItem.cpp | 1 - libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 4 +++ libraries/gpu-gl/src/gpu/gl/GLBackend.h | 1 + .../gpu-gl/src/gpu/gl41/GL41BackendInput.cpp | 13 ++++++++ .../gpu-gl/src/gpu/gl45/GL45BackendInput.cpp | 14 +++++++++ libraries/render-utils/src/GeometryCache.cpp | 30 +++++++++++++++++++ libraries/render-utils/src/GeometryCache.h | 6 ++++ .../render-utils/src/MeshPartPayload.cpp | 10 ------- tests/gpu-test/src/TestShapes.cpp | 9 +++--- 11 files changed, 75 insertions(+), 19 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index fbf85fa8c2..21764dff7f 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -303,6 +303,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { batch.setInputBuffer(0, _verticesBuffer, 0, sizeof(Vertex)); #ifndef POLYLINE_ENTITY_USE_FADE_EFFECT + // glColor4f must be called after setInputFormat if it must be taken into account if (_isFading) { batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime)); } else { diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 3524709395..b00ad0259e 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -137,11 +137,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { }); if (proceduralRender) { - batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { - geometryCache->renderWireShape(batch, geometryShape); + geometryCache->renderWireShape(batch, geometryShape, outColor); } else { - geometryCache->renderShape(batch, geometryShape); + geometryCache->renderShape(batch, geometryShape, outColor); } } else { // FIXME, support instanced multi-shape rendering using multidraw indirect diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index cdd260e73c..b253e73b87 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -188,7 +188,6 @@ void WebEntityRenderer::doRender(RenderArgs* args) { }); batch.setResourceTexture(0, _texture); float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; - batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio); DependencyManager::get()->bindWebBrowserProgram(batch, fadeRatio < OPAQUE_ALPHA_THRESHOLD); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio), _geometryId); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 6fb0d7b152..93077e240b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -605,6 +605,10 @@ void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) { if (_input._colorAttribute != newColor) { _input._colorAttribute = newColor; glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r); + // Color has been changed and is not white. To prevent colors from bleeding + // between different objects, we need to set the _hadColorAttribute flag + // as if a previous render call had potential colors + _input._hadColorAttribute = (newColor != glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } (void)CHECK_GL_ERROR(); } diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 1908db614d..5558d3ada1 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -253,6 +253,7 @@ protected: struct InputStageState { bool _invalidFormat { true }; + bool _hadColorAttribute{ true }; Stream::FormatPointer _format; std::string _formatKey; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp index e8ebcbe05c..42bd56e6e4 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp @@ -62,6 +62,8 @@ void GL41Backend::updateInput() { // now we need to bind the buffers and assign the attrib pointers if (_input._format) { + bool hasColorAttribute{ false }; + const Buffers& buffers = _input._buffers; const Offsets& offsets = _input._bufferOffsets; const Offsets& strides = _input._bufferStrides; @@ -98,6 +100,8 @@ void GL41Backend::updateInput() { uintptr_t pointer = (uintptr_t)(attrib._offset + offsets[bufferNum]); GLboolean isNormalized = attrib._element.isNormalized(); + hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR); + for (size_t locNum = 0; locNum < locationCount; ++locNum) { if (attrib._element.isInteger()) { glVertexAttribIPointer(slot + (GLuint)locNum, count, type, stride, @@ -117,6 +121,15 @@ void GL41Backend::updateInput() { } } } + + if (_input._hadColorAttribute && !hasColorAttribute) { + // The previous input stage had a color attribute but this one doesn't so reset + // color to pure white. + const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); + glVertexAttrib4fv(Stream::COLOR, &white.r); + _input._colorAttribute = white; + } + _input._hadColorAttribute = hasColorAttribute; } // everything format related should be in sync now _input._invalidFormat = false; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp index ece62e15f1..4a43fc988c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp @@ -32,6 +32,8 @@ void GL45Backend::updateInput() { // Assign the vertex format required if (_input._format) { + bool hasColorAttribute{ false }; + _input._attribBindingBuffers.reset(); const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); @@ -54,6 +56,9 @@ void GL45Backend::updateInput() { GLboolean isNormalized = attrib._element.isNormalized(); GLenum perLocationSize = attrib._element.getLocationSize(); + + hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR); + for (GLuint locNum = 0; locNum < locationCount; ++locNum) { GLuint attriNum = (GLuint)(slot + locNum); newActivation.set(attriNum); @@ -84,6 +89,15 @@ void GL45Backend::updateInput() { glVertexBindingDivisor(bufferChannelNum, frequency); #endif } + + if (_input._hadColorAttribute && !hasColorAttribute) { + // The previous input stage had a color attribute but this one doesn't so reset + // color to pure white. + const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); + glVertexAttrib4fv(Stream::COLOR, &white.r); + _input._colorAttribute = white; + } + _input._hadColorAttribute = hasColorAttribute; } // Manage Activation what was and what is expected now diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 76c354bdf8..2616d08600 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -760,6 +760,20 @@ void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape) { _shapes[shape].drawWire(batch); } +void GeometryCache::renderShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) { + batch.setInputFormat(getSolidStreamFormat()); + // Color must be set after input format + batch._glColor4f(color.r, color.g, color.b, color.a); + _shapes[shape].draw(batch); +} + +void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) { + batch.setInputFormat(getSolidStreamFormat()); + // Color must be set after input format + batch._glColor4f(color.r, color.g, color.b, color.a); + _shapes[shape].drawWire(batch); +} + void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) { gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT); batch.setInputBuffer(gpu::Stream::COLOR, colorView); @@ -811,6 +825,14 @@ void GeometryCache::renderWireCube(gpu::Batch& batch) { renderWireShape(batch, Cube); } +void GeometryCache::renderCube(gpu::Batch& batch, const glm::vec4& color) { + renderShape(batch, Cube, color); +} + +void GeometryCache::renderWireCube(gpu::Batch& batch, const glm::vec4& color) { + renderWireShape(batch, Cube, color); +} + void GeometryCache::renderSphere(gpu::Batch& batch) { renderShape(batch, Sphere); } @@ -819,6 +841,14 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) { renderWireShape(batch, Sphere); } +void GeometryCache::renderSphere(gpu::Batch& batch, const glm::vec4& color) { + renderShape(batch, Sphere, color); +} + +void GeometryCache::renderWireSphere(gpu::Batch& batch, const glm::vec4& color) { + renderWireShape(batch, Sphere, color); +} + void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge, diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index cd8c43f1df..0585cc9e55 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -251,14 +251,20 @@ public: // Dynamic geometry void renderShape(gpu::Batch& batch, Shape shape); void renderWireShape(gpu::Batch& batch, Shape shape); + void renderShape(gpu::Batch& batch, Shape shape, const glm::vec4& color); + void renderWireShape(gpu::Batch& batch, Shape shape, const glm::vec4& color); size_t getShapeTriangleCount(Shape shape); void renderCube(gpu::Batch& batch); void renderWireCube(gpu::Batch& batch); + void renderCube(gpu::Batch& batch, const glm::vec4& color); + void renderWireCube(gpu::Batch& batch, const glm::vec4& color); size_t getCubeTriangleCount(); void renderSphere(gpu::Batch& batch); void renderWireSphere(gpu::Batch& batch); + void renderSphere(gpu::Batch& batch, const glm::vec4& color); + void renderWireSphere(gpu::Batch& batch, const glm::vec4& color); size_t getSphereTriangleCount(); void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 1ea3e1a705..cf895a73fa 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -122,11 +122,6 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputFormat((_drawMesh->getVertexFormat())); batch.setInputStream(0, _drawMesh->getVertexStream()); - - // TODO: Get rid of that extra call - if (!_hasColorAttrib) { - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } } void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool enableTextures) const { @@ -526,11 +521,6 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } } - - // TODO: Get rid of that extra call - if (!_hasColorAttrib) { - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } } void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { diff --git a/tests/gpu-test/src/TestShapes.cpp b/tests/gpu-test/src/TestShapes.cpp index 253d89cf61..67a348c002 100644 --- a/tests/gpu-test/src/TestShapes.cpp +++ b/tests/gpu-test/src/TestShapes.cpp @@ -29,19 +29,18 @@ void TestShapes::renderTest(size_t testId, RenderArgs* args) { float seconds = secTimestampNow() - startSecs; seconds /= 4.0f; batch.setModelTransform(Transform()); - batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f); + const auto color = glm::vec4(0.8f, 0.25f, 0.25f, 1.0f); bool wire = (seconds - floorf(seconds) > 0.5f); int shapeIndex = ((int)seconds) % TYPE_COUNT; if (wire) { - geometryCache->renderWireShape(batch, SHAPE[shapeIndex]); + geometryCache->renderWireShape(batch, SHAPE[shapeIndex], color); } else { - geometryCache->renderShape(batch, SHAPE[shapeIndex]); + geometryCache->renderShape(batch, SHAPE[shapeIndex], color); } batch.setModelTransform(Transform().setScale(1.01f)); - batch._glColor4f(1, 1, 1, 1); - geometryCache->renderWireCube(batch); + geometryCache->renderWireCube(batch, glm::vec4(1,1,1,1)); } From 63ac426bf27c9782c0406224275862790aed1c3f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 18 Dec 2017 17:30:56 -0800 Subject: [PATCH 067/102] fix logic that resets own-avatar collisions after a parenting grab is released --- libraries/entities/src/EntityItem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 48370b02fd..ddc5e9795f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1626,6 +1626,10 @@ void EntityItem::setParentID(const QUuid& value) { newParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING; } + if (!oldParentID.isNull() && (oldParentID == Physics::getSessionUUID() || oldParentID == AVATAR_SELF_ID)) { + oldParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING; + } + if ((bool)(oldParentNoBootstrapping ^ newParentNoBootstrapping)) { if ((bool)(newParentNoBootstrapping & Simulation::NO_BOOTSTRAPPING)) { markDirtyFlags(Simulation::NO_BOOTSTRAPPING); From 661a63bd0ca5d2935c88c32066c538989fda240d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Dec 2017 11:05:27 -0800 Subject: [PATCH 068/102] fix crash for bad QVector index --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e578e4858d..cf555203dc 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -998,7 +998,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) { // in the case where the last frame is greater than the framecount then clamp // it to the end of the animation until it loops around. - if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) { + if (animationCurrentFrame < 0 || animationCurrentFrame >= frameCount) { animationCurrentFrame = 0; } From 559cb33563b794ce84f39232a164bbc04307fd31 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Dec 2017 11:13:11 -0800 Subject: [PATCH 069/102] remove incorrect comment --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index cf555203dc..543c3bfbe9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -993,11 +993,8 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) { } { - // the current frame is set on the server in update() in ModelEntityItem.cpp + // the current frame is set on the server in update() in ModelEntityItem.cpp int animationCurrentFrame = (int)(glm::floor(entity->getAnimationCurrentFrame())); - - // in the case where the last frame is greater than the framecount then clamp - // it to the end of the animation until it loops around. if (animationCurrentFrame < 0 || animationCurrentFrame >= frameCount) { animationCurrentFrame = 0; } From bad2c1df7693f9794a6f935483a0c64529d9bfc8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Dec 2017 12:21:23 -0800 Subject: [PATCH 070/102] proper modulus of animation frame --- .../src/RenderableModelEntityItem.cpp | 13 ++++++------- libraries/entities/src/ModelEntityItem.cpp | 6 ++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 543c3bfbe9..bc99522d0f 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -993,16 +993,15 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) { } { - // the current frame is set on the server in update() in ModelEntityItem.cpp - int animationCurrentFrame = (int)(glm::floor(entity->getAnimationCurrentFrame())); - if (animationCurrentFrame < 0 || animationCurrentFrame >= frameCount) { - animationCurrentFrame = 0; + float currentFrame = fmod(entity->getAnimationCurrentFrame(), (float)(frameCount)); + if (currentFrame < 0.0f) { + currentFrame += (float)frameCount; } - - if (animationCurrentFrame == _lastKnownCurrentFrame) { + int currentIntegerFrame = (int)(glm::floor(currentFrame)); + if (currentIntegerFrame == _lastKnownCurrentFrame) { return; } - _lastKnownCurrentFrame = animationCurrentFrame; + _lastKnownCurrentFrame = currentIntegerFrame; } if (_jointMapping.size() != _model->getJointStateCount()) { diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 323584c7ee..3a79df34c6 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -245,7 +245,7 @@ void ModelEntityItem::updateFrameCount() { if (_currentFrame < 0.0f) { return; } - + if (!_lastAnimated) { _lastAnimated = usecTimestampNow(); return; @@ -263,7 +263,7 @@ void ModelEntityItem::updateFrameCount() { } int updatedFrameCount = getAnimationLastFrame() - getAnimationFirstFrame() + 1; - + if (!getAnimationHold() && getAnimationIsPlaying()) { float deltaTime = (float)interval / (float)USECS_PER_SECOND; _currentFrame += (deltaTime * getAnimationFPS()); @@ -283,8 +283,6 @@ void ModelEntityItem::updateFrameCount() { // qCDebug(entities) << "in update frame " << _currentFrame; setAnimationCurrentFrame(_currentFrame); } - - } void ModelEntityItem::debugDump() const { From 2c6868b03ead25a00986fa6b9c94734d23d8a6c7 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Tue, 19 Dec 2017 11:12:27 -0800 Subject: [PATCH 071/102] Pass keylight direction as parameter to the shader. --- libraries/render-utils/src/DeferredGlobalLight.slh | 3 ++- libraries/render-utils/src/Haze.slf | 6 ++++-- libraries/render-utils/src/Haze.slh | 7 ++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 6cdc02b7a5..de2d41be6b 100644 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -221,7 +221,8 @@ vec3 evalGlobalLightingAlphaBlendedWithHaze( vec4(color, 1.0), // fragment original color position, // fragment position in eye coordinates fragEyeVector, // fragment position in world coordinates - invViewMat[3].y // eye height in world coordinates + invViewMat[3].y, // eye height in world coordinates + lightDirection // keylight direction vector ); color = colorV4.rgb; diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index 5f05d52f83..0270aa58f0 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -53,6 +53,8 @@ void main(void) { vec4 worldFragPos = viewInverse * eyeFragPos; vec4 worldEyePos = viewInverse[3]; - outFragColor = computeHazeColor(fragColor, eyeFragPos.xyz, worldFragPos.xyz, worldEyePos.y); -} + Light light = getLight(); + vec3 lightDirection = getLightDirection(light); + outFragColor = computeHazeColor(fragColor, eyeFragPos.xyz, worldFragPos.xyz, worldEyePos.y, lightDirection); +} diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index 2fcf5f4418..15e484e055 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -43,7 +43,7 @@ layout(std140) uniform hazeBuffer { // Input: // color - fragment original color -// directionalLight - parameters of the keylight +// lightDirection - parameters of the keylight // worldFragPos - fragment position in world coordinates // Output: // fragment colour after haze effect @@ -101,7 +101,7 @@ vec3 computeHazeColorKeyLightAttenuation(vec3 color, vec3 lightDirection, vec3 w // // General algorithm taken from http://www.iquilezles.org/www/articles/fog/fog.htm, with permission // -vec4 computeHazeColor(vec4 fragColor, vec3 eyeFragPos, vec3 worldFragPos, float worldEyeHeight) { +vec4 computeHazeColor(vec4 fragColor, vec3 eyeFragPos, vec3 worldFragPos, float worldEyeHeight, vec3 lightDirection) { // Distance to fragment float distance = length(eyeFragPos); @@ -111,9 +111,6 @@ vec4 computeHazeColor(vec4 fragColor, vec3 eyeFragPos, vec3 worldFragPos, float // Directional light component is a function of the angle from the eye, between the fragment and the sun vec3 eyeFragDir = normalize(worldFragPos); - Light light = getLight(); - vec3 lightDirection = getLightDirection(light); - float glareComponent = max(0.0, dot(eyeFragDir, -lightDirection)); float power = min(1.0, pow(glareComponent, hazeParams.hazeGlareBlend)); From ed5da4f83b59797ed81b0706a8616a6aa38ac9f3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 19 Dec 2017 15:07:50 -0800 Subject: [PATCH 072/102] Fix bug preventing 'get' buttons from working in marketplace --- scripts/system/html/js/marketplacesInject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 96c1916889..63d36f1a72 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -415,7 +415,7 @@ } purchaseButton.on('click', function () { - if ('availabile' === availability) { + if ('available' === availability) { buyButtonClicked(window.location.pathname.split("/")[3], $('#top-center').find('h1').text(), $('#creator').find('.value').text(), From 1a6546999aeead1a89ac89bccf97b358c661a61d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Dec 2017 16:00:55 -0800 Subject: [PATCH 073/102] track reliably sent adds in sent packet history from OEPS --- libraries/networking/src/SentPacketHistory.cpp | 7 +++++-- libraries/networking/src/SentPacketHistory.h | 2 ++ libraries/octree/src/OctreeEditPacketSender.cpp | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/SentPacketHistory.cpp b/libraries/networking/src/SentPacketHistory.cpp index fbb7eff41a..3bd6d4cf03 100644 --- a/libraries/networking/src/SentPacketHistory.cpp +++ b/libraries/networking/src/SentPacketHistory.cpp @@ -24,8 +24,7 @@ SentPacketHistory::SentPacketHistory(int size) } -void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& packet) { - +void SentPacketHistory::untrackedPacketSent(uint16_t sequenceNumber) { // check if given seq number has the expected value. if not, something's wrong with // the code calling this function uint16_t expectedSequenceNumber = _newestSequenceNumber + (uint16_t)1; @@ -34,6 +33,10 @@ void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& pack << "Expected:" << expectedSequenceNumber << "Actual:" << sequenceNumber; } _newestSequenceNumber = sequenceNumber; +} + +void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& packet) { + untrackedPacketSent(sequenceNumber); QWriteLocker locker(&_packetsLock); _sentPackets.insert(NLPacket::createCopy(packet)); diff --git a/libraries/networking/src/SentPacketHistory.h b/libraries/networking/src/SentPacketHistory.h index 72150658e3..dc92d38b25 100644 --- a/libraries/networking/src/SentPacketHistory.h +++ b/libraries/networking/src/SentPacketHistory.h @@ -27,6 +27,8 @@ class SentPacketHistory { public: SentPacketHistory(int size = MAX_REASONABLE_SEQUENCE_GAP); + void untrackedPacketSent(uint16_t sequenceNumber); + void packetSent(uint16_t sequenceNumber, const NLPacket& packet); const NLPacket* getPacket(uint16_t sequenceNumber) const; diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 9cb383df41..7e46831faa 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -291,6 +291,9 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& // release the new packet releaseQueuedPacketList(nodeUUID, std::move(newPacket)); + // tell the sent packet history that we used a sequence number for an untracked packet + auto& sentPacketHistory = _sentPacketHistories[nodeUUID]; + sentPacketHistory.untrackedPacketSent(sequence); } else { std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; //only a NLPacket for now From 5da49d156ebdeaac49de2e6e753d06894ea4f295 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 19 Dec 2017 16:26:58 -0800 Subject: [PATCH 074/102] Commerce: Fix the behavior of the 'cancel' button in Wallet Setup --- .../qml/hifi/commerce/checkout/Checkout.qml | 4 +++- .../qml/hifi/commerce/wallet/WalletSetup.qml | 2 +- scripts/system/commerce/wallet.js | 16 +++++++++++++++- scripts/system/html/js/marketplacesInject.js | 11 +++++++---- scripts/system/marketplaces/marketplaces.js | 2 +- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index c9e5d2aaec..79332d08fa 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -41,6 +41,7 @@ Rectangle { property bool debugCheckoutSuccess: false; property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified(); property bool isWearable; + property string referrer; // Style color: hifi.colors.white; Hifi.QmlCommerce { @@ -131,7 +132,7 @@ Rectangle { id: notSetUpTimer; interval: 200; onTriggered: { - sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId}); + sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId, referrer: referrer}); } } @@ -877,6 +878,7 @@ Rectangle { itemName = message.params.itemName; root.itemPrice = message.params.itemPrice; itemHref = message.params.itemHref; + referrer = message.params.referrer; setBuyText(); break; default: diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml index 1f9b56ca22..5d05b8fba3 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml @@ -252,7 +252,7 @@ Item { height: 50; text: "Cancel"; onClicked: { - sendSignalToWallet({method: 'walletSetup_cancelClicked'}); + sendSignalToWallet({method: 'walletSetup_cancelClicked', referrer: root.referrer ? root.referrer : "" }); } } } diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index a4cdc5b097..a37f2bfe91 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -61,10 +61,24 @@ function fromQml(message) { switch (message.method) { case 'passphrasePopup_cancelClicked': - case 'walletSetup_cancelClicked': case 'needsLogIn_cancelClicked': tablet.gotoHomeScreen(); break; + case 'walletSetup_cancelClicked': + switch (message.referrer) { + case '': // User clicked "Wallet" app + tablet.gotoHomeScreen(); + break; + case 'purchases': + case 'marketplace cta': + case 'mainPage': + tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL); + break; + default: // User needs to return to an individual marketplace item URL + tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.referrer, MARKETPLACES_INJECT_SCRIPT_URL); + break; + } + break; case 'needsLogIn_loginClicked': openLoginWindow(); break; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 63d36f1a72..698dd93f29 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -243,13 +243,14 @@ }); } - function buyButtonClicked(id, name, author, price, href) { + function buyButtonClicked(id, name, author, price, href, referrer) { EventBridge.emitWebEvent(JSON.stringify({ type: "CHECKOUT", itemId: id, itemName: name, itemPrice: price ? parseInt(price, 10) : 0, - itemHref: href + itemHref: href, + referrer: referrer })); } @@ -316,7 +317,8 @@ $(this).closest('.grid-item').find('.item-title').text(), $(this).closest('.grid-item').find('.creator').find('.value').text(), $(this).closest('.grid-item').find('.item-cost').text(), - $(this).attr('data-href')); + $(this).attr('data-href'), + "mainPage"); }); } @@ -420,7 +422,8 @@ $('#top-center').find('h1').text(), $('#creator').find('.value').text(), cost, - href); + href, + "itemPage"); } }); maybeAddPurchasesButton(); diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 004375bff7..a365730cd5 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -437,7 +437,7 @@ var selectionDisplay = null; // for gridTool.js to ignore wireEventBridge(true); tablet.sendToQml({ method: 'updateWalletReferrer', - referrer: message.itemId + referrer: message.referrer === "itemPage" ? message.itemId : message.referrer }); openWallet(); break; From a72ed27a25c5faf8034a7aa73544e5b877e75c47 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 19 Dec 2017 16:57:48 -0800 Subject: [PATCH 075/102] CR feedback --- interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml | 2 +- scripts/system/commerce/wallet.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml index 5d05b8fba3..36f29b3f31 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml @@ -252,7 +252,7 @@ Item { height: 50; text: "Cancel"; onClicked: { - sendSignalToWallet({method: 'walletSetup_cancelClicked', referrer: root.referrer ? root.referrer : "" }); + sendSignalToWallet({method: 'walletSetup_cancelClicked', referrer: root.referrer }); } } } diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index a37f2bfe91..4ad043f71e 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -67,6 +67,8 @@ case 'walletSetup_cancelClicked': switch (message.referrer) { case '': // User clicked "Wallet" app + case undefined: + case null: tablet.gotoHomeScreen(); break; case 'purchases': From bd06dc6443e68b7d4ad26f0a8b1a90d9b192e398 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 19 Dec 2017 16:57:16 -0800 Subject: [PATCH 076/102] cleaning up modelmeshpartpayload --- interface/src/ui/overlays/ModelOverlay.cpp | 2 - .../src/avatars-renderer/Avatar.cpp | 1 - .../src/RenderableModelEntityItem.cpp | 1 - .../render-utils/src/CauterizedModel.cpp | 14 +- .../render-utils/src/MeshPartPayload.cpp | 122 ++++++------------ libraries/render-utils/src/MeshPartPayload.h | 21 +-- libraries/render-utils/src/Model.cpp | 42 ++++-- libraries/render-utils/src/Model.h | 7 +- 8 files changed, 97 insertions(+), 113 deletions(-) diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index ba8bf8cbef..67fa94f7e5 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -24,7 +24,6 @@ ModelOverlay::ModelOverlay() : _model(std::make_shared(nullptr, this)), _modelTextures(QVariantMap()) { - _model->init(); _model->setLoadingPriority(_loadPriority); _isLoaded = false; } @@ -38,7 +37,6 @@ ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) : _scaleToFit(modelOverlay->_scaleToFit), _loadPriority(modelOverlay->_loadPriority) { - _model->init(); _model->setLoadingPriority(_loadPriority); if (_url.isValid()) { _updateModel = true; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index bb7f141cd9..c532e7659f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -138,7 +138,6 @@ Avatar::~Avatar() { void Avatar::init() { getHead()->init(); - _skeletonModel->init(); _initialized = true; } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e578e4858d..485cc93ca2 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1213,7 +1213,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate); connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate); model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity)); - model->init(); entity->setModel(model); withWriteLock([&] { _model = model; }); } diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index c437a8c556..745e995cc4 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -178,6 +178,11 @@ void CauterizedModel::updateRenderItems() { modelTransform.setTranslation(self->getTranslation()); modelTransform.setRotation(self->getRotation()); + bool isWireframe = self->isWireframe(); + bool isVisible = self->isVisible(); + bool isLayeredInFront = self->isLayeredInFront(); + bool isLayeredInHUD = self->isLayeredInHUD(); + render::Transaction transaction; for (int i = 0; i < (int)self->_modelMeshRenderItemIDs.size(); i++) { @@ -186,7 +191,10 @@ void CauterizedModel::updateRenderItems() { auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices); auto clusterMatricesCauterized(self->getCauterizeMeshState(meshIndex).clusterMatrices); - transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized](CauterizedMeshPartPayload& data) { + bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); + + transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized, invalidatePayloadShapeKey, + isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](CauterizedMeshPartPayload& data) { data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized); Transform renderTransform = modelTransform; @@ -200,6 +208,10 @@ void CauterizedModel::updateRenderItems() { renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0])); } data.updateTransformForCauterizedMesh(renderTransform); + + data.setKey(data.evalKey(isVisible, isLayeredInFront, isLayeredInHUD)); + data.setLayer(data.evalLayer(isLayeredInFront, isLayeredInHUD)); + data.setShapeKey(invalidatePayloadShapeKey ? render::ShapeKey::Builder::invalid() : data.evalShapeKey(isWireframe)); }); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 1ea3e1a705..2be9781935 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -339,13 +339,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in } updateTransformForSkinnedMesh(renderTransform, transform); - initCache(); + initCache(model); } -void ModelMeshPartPayload::initCache() { - ModelPointer model = _model.lock(); - assert(model && model->isLoaded()); - +void ModelMeshPartPayload::initCache(const ModelPointer& model) { if (_drawMesh) { auto vertexFormat = _drawMesh->getVertexFormat(); _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); @@ -355,6 +352,7 @@ void ModelMeshPartPayload::initCache() { const FBXMesh& mesh = geometry.meshes.at(_meshIndex); _isBlendShaped = !mesh.blendshapes.isEmpty(); + _hasTangents = !mesh.tangents.isEmpty(); } auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); @@ -388,94 +386,65 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render _worldBound.transform(boundTransform); } -ItemKey ModelMeshPartPayload::getKey() const { +render::ItemKey ModelMeshPartPayload::evalKey(bool isVisible, bool isLayeredInFront, bool isLayeredInHUD) const { ItemKey::Builder builder; builder.withTypeShape(); - ModelPointer model = _model.lock(); - if (model) { - if (!model->isVisible()) { - builder.withInvisible(); - } + if (!isVisible) { + builder.withInvisible(); + } - if (model->isLayeredInFront() || model->isLayeredInHUD()) { - builder.withLayered(); - } + if (isLayeredInFront || isLayeredInHUD) { + builder.withLayered(); + } - if (_isBlendShaped || _isSkinned) { - builder.withDeformed(); - } + if (_isBlendShaped || _isSkinned) { + builder.withDeformed(); + } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); - if (matKey.isTranslucent()) { - builder.withTransparent(); - } + if (_drawMaterial) { + auto matKey = _drawMaterial->getKey(); + if (matKey.isTranslucent()) { + builder.withTransparent(); } } + return builder.build(); } -int ModelMeshPartPayload::getLayer() const { - ModelPointer model = _model.lock(); - if (model) { - if (model->isLayeredInFront()) { - return Item::LAYER_3D_FRONT; - } else if (model->isLayeredInHUD()) { - return Item::LAYER_3D_HUD; - } - } - return Item::LAYER_3D; +ItemKey ModelMeshPartPayload::getKey() const { + return _itemKey; } -ShapeKey ModelMeshPartPayload::getShapeKey() const { - // guard against partially loaded meshes - ModelPointer model = _model.lock(); - if (!model || !model->isLoaded() || !model->getGeometry()) { - return ShapeKey::Builder::invalid(); - } - - const FBXGeometry& geometry = model->getFBXGeometry(); - const auto& networkMeshes = model->getGeometry()->getMeshes(); - - // guard against partially loaded meshes - if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)model->_meshStates.size()) { - return ShapeKey::Builder::invalid(); - } - - const FBXMesh& mesh = geometry.meshes.at(_meshIndex); - - // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown - // to false to rebuild out mesh groups. - if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) { - model->_needsFixupInScene = true; // trigger remove/add cycle - model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid - return ShapeKey::Builder::invalid(); - } - - - int vertexCount = mesh.vertices.size(); - if (vertexCount == 0) { - // sanity check - return ShapeKey::Builder::invalid(); // FIXME +int ModelMeshPartPayload::evalLayer(bool isLayeredInFront, bool isLayeredInHUD) const { + if (isLayeredInFront) { + return Item::LAYER_3D_FRONT; + } else if (isLayeredInHUD) { + return Item::LAYER_3D_HUD; + } else { + return Item::LAYER_3D; } +} +int ModelMeshPartPayload::getLayer() const { + return _layer; +} +ShapeKey ModelMeshPartPayload::evalShapeKey(bool isWireframe) const { model::MaterialKey drawMaterialKey; if (_drawMaterial) { drawMaterialKey = _drawMaterial->getKey(); } bool isTranslucent = drawMaterialKey.isTranslucent(); - bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); + bool hasTangents = drawMaterialKey.isNormalMap() && _hasTangents; bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); bool isUnlit = drawMaterialKey.isUnlit(); bool isSkinned = _isSkinned; - bool wireframe = model->isWireframe(); - if (wireframe) { + if (isWireframe) { isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false; } @@ -500,12 +469,16 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { if (isSkinned) { builder.withSkinned(); } - if (wireframe) { + if (isWireframe) { builder.withWireframe(); } return builder.build(); } +ShapeKey ModelMeshPartPayload::getShapeKey() const { + return _shapeKey; +} + void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { if (!_isBlendShaped) { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); @@ -549,26 +522,9 @@ void ModelMeshPartPayload::render(RenderArgs* args) { return; // bail asap } - if (_state == WAITING_TO_START) { - if (model->isLoaded()) { - _state = STARTED; - model->setRenderItemsNeedUpdate(); - } else { - return; - } - } - - if (_materialNeedsUpdate && model->getGeometry()->areTexturesLoaded()) { - model->setRenderItemsNeedUpdate(); - _materialNeedsUpdate = false; - } - if (!args) { return; } - if (!getShapeKey().isValid()) { - return; - } gpu::Batch& batch = *(args->_batch); auto locations = args->_shapePipeline->locations; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 971c6fe90b..e56623ae16 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -96,12 +96,17 @@ public: render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) override; + render::ItemKey evalKey(bool isVisible, bool isLayeredInFront, bool isLayeredInHUD) const; + void setKey(const render::ItemKey& itemKey) { _itemKey = itemKey; } + int evalLayer(bool isLayeredInFront, bool isLayeredInHUD) const; + void setLayer(int layer) { _layer = layer; } + render::ShapeKey evalShapeKey(bool isWireframe) const; + void setShapeKey(const render::ShapeKey& shapeKey) { _shapeKey = shapeKey; }; + // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; - void initCache(); - void computeAdjustedLocalBound(const std::vector& clusterMatrices); gpu::BufferPointer _clusterBuffer; @@ -112,16 +117,14 @@ public: bool _isSkinned{ false }; bool _isBlendShaped { false }; - bool _materialNeedsUpdate { true }; + bool _hasTangents { false }; private: + void initCache(const ModelPointer& model); - enum State : uint8_t { - WAITING_TO_START = 0, - STARTED = 1, - }; - - mutable State _state { WAITING_TO_START } ; + render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() }; + int _layer { render::Item::LAYER_3D }; + render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; }; namespace render { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c4bc435691..7dff629183 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -210,6 +210,24 @@ int Model::getRenderInfoTextureCount() { return _renderInfoTextureCount; } +bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) { + if (!getGeometry()) { + return true; + } + + const FBXGeometry& geometry = getFBXGeometry(); + const auto& networkMeshes = getGeometry()->getMeshes(); + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown + // to false to rebuild out mesh groups. + if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size()) { + _needsFixupInScene = true; // trigger remove/add cycle + invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid + return true; + } + + return false; +} + void Model::updateRenderItems() { if (!_addedToScene) { return; @@ -237,6 +255,11 @@ void Model::updateRenderItems() { Transform modelTransform = self->getTransform(); modelTransform.setScale(glm::vec3(1.0f)); + bool isWireframe = self->isWireframe(); + bool isVisible = self->isVisible(); + bool isLayeredInFront = self->isLayeredInFront(); + bool isLayeredInHUD = self->isLayeredInHUD(); + render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -244,13 +267,20 @@ void Model::updateRenderItems() { auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices); - transaction.updateItem(itemID, [modelTransform, clusterMatrices](ModelMeshPartPayload& data) { + bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); + + transaction.updateItem(itemID, [modelTransform, clusterMatrices, invalidatePayloadShapeKey, + isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { data.updateClusterBuffer(clusterMatrices); Transform renderTransform = modelTransform; if (clusterMatrices.size() == 1) { renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0])); } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); + + data.setKey(data.evalKey(isVisible, isLayeredInFront, isLayeredInHUD)); + data.setLayer(data.evalLayer(isLayeredInFront, isLayeredInHUD)); + data.setShapeKey(invalidatePayloadShapeKey ? render::ShapeKey::Builder::invalid() : data.evalShapeKey(isWireframe)); }); } @@ -272,16 +302,6 @@ void Model::setRenderItemsNeedUpdate() { emit requestRenderUpdate(); } -void Model::initJointTransforms() { - if (isLoaded()) { - glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); - _rig.setModelOffset(modelOffset); - } -} - -void Model::init() { -} - void Model::reset() { if (isLoaded()) { const FBXGeometry& geometry = getFBXGeometry(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 7568a17342..50ccb22131 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -122,7 +122,6 @@ public: void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } bool isWireframe() const { return _isWireframe; } - void init(); void reset(); void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint); @@ -346,11 +345,7 @@ protected: // hook for derived classes to be notified when setUrl invalidates the current model. virtual void onInvalidate() {}; - -protected: - virtual void deleteGeometry(); - void initJointTransforms(); QVector _blendshapeCoefficients; @@ -419,6 +414,8 @@ protected: bool _isLayeredInFront { false }; bool _isLayeredInHUD { false }; + bool shouldInvalidatePayloadShapeKey(int meshIndex); + private: float _loadingPriority { 0.0f }; From e02e6790fea7397befa2da9d624830904ab55a4b Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 20 Dec 2017 13:46:02 -0800 Subject: [PATCH 077/102] Fix error state for Commerce passphrase TextInputs --- .../resources/qml/hifi/commerce/wallet/PassphraseModal.qml | 3 +++ .../resources/qml/hifi/commerce/wallet/PassphraseSelection.qml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index 379a217adb..87430246f3 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -50,9 +50,11 @@ Item { submitPassphraseInputButton.enabled = true; if (!isAuthenticated) { errorText.text = "Authentication failed - please try again."; + passphraseField.error = true; UserActivityLogger.commercePassphraseAuthenticationStatus("auth failure"); } else { sendSignalToParent({method: 'authSuccess'}); + passphraseField.error = false; UserActivityLogger.commercePassphraseAuthenticationStatus("auth success"); } } @@ -72,6 +74,7 @@ Item { // TODO: Fix this unlikely bug onVisibleChanged: { if (visible) { + passphraseField.error = false; passphraseField.focus = true; sendSignalToParent({method: 'disableHmdPreview'}); } else { diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 3ed66f703b..50e58f8cc4 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -54,6 +54,9 @@ Item { // TODO: Fix this unlikely bug onVisibleChanged: { if (visible) { + passphraseField.error = false; + passphraseFieldAgain.error = false; + currentPassphraseField.error = false; if (root.shouldImmediatelyFocus) { focusFirstTextField(); } From 7a7b1f7089b27f2fb74ea4d06815d528e32855a3 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 20 Dec 2017 13:58:58 -0800 Subject: [PATCH 078/102] fix web entity crash --- libraries/entities-renderer/src/RenderableWebEntityItem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index cdd260e73c..ff0d6bea2d 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -124,7 +124,10 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene withWriteLock([&] { // This work must be done on the main thread if (!hasWebSurface()) { - buildWebSurface(entity); + // If we couldn't create a new web surface, exit + if (!buildWebSurface(entity)) { + return; + } } if (_contextPosition != entity->getWorldPosition()) { From 2ba3e337db8a122d9ecfb49c7cec853f1f257547 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 20 Dec 2017 14:18:01 -0800 Subject: [PATCH 079/102] cleanup --- .../render-utils/src/CauterizedModel.cpp | 6 ++--- .../render-utils/src/MeshPartPayload.cpp | 23 +++++++++++-------- libraries/render-utils/src/MeshPartPayload.h | 11 ++++----- libraries/render-utils/src/Model.cpp | 6 ++--- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 745e995cc4..52095ee25a 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -209,9 +209,9 @@ void CauterizedModel::updateRenderItems() { } data.updateTransformForCauterizedMesh(renderTransform); - data.setKey(data.evalKey(isVisible, isLayeredInFront, isLayeredInHUD)); - data.setLayer(data.evalLayer(isLayeredInFront, isLayeredInHUD)); - data.setShapeKey(invalidatePayloadShapeKey ? render::ShapeKey::Builder::invalid() : data.evalShapeKey(isWireframe)); + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + data.setShapeKey(invalidatePayloadShapeKey, isWireframe); }); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2be9781935..313cd383f9 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -386,7 +386,7 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render _worldBound.transform(boundTransform); } -render::ItemKey ModelMeshPartPayload::evalKey(bool isVisible, bool isLayeredInFront, bool isLayeredInHUD) const { +void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) { ItemKey::Builder builder; builder.withTypeShape(); @@ -394,7 +394,7 @@ render::ItemKey ModelMeshPartPayload::evalKey(bool isVisible, bool isLayeredInFr builder.withInvisible(); } - if (isLayeredInFront || isLayeredInHUD) { + if (isLayered) { builder.withLayered(); } @@ -409,20 +409,20 @@ render::ItemKey ModelMeshPartPayload::evalKey(bool isVisible, bool isLayeredInFr } } - return builder.build(); + _itemKey = builder.build(); } ItemKey ModelMeshPartPayload::getKey() const { return _itemKey; } -int ModelMeshPartPayload::evalLayer(bool isLayeredInFront, bool isLayeredInHUD) const { +void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) { if (isLayeredInFront) { - return Item::LAYER_3D_FRONT; + _layer = Item::LAYER_3D_FRONT; } else if (isLayeredInHUD) { - return Item::LAYER_3D_HUD; + _layer = Item::LAYER_3D_HUD; } else { - return Item::LAYER_3D; + _layer = Item::LAYER_3D; } } @@ -430,7 +430,12 @@ int ModelMeshPartPayload::getLayer() const { return _layer; } -ShapeKey ModelMeshPartPayload::evalShapeKey(bool isWireframe) const { +void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe) { + if (invalidateShapeKey) { + _shapeKey = ShapeKey::Builder::invalid(); + return; + } + model::MaterialKey drawMaterialKey; if (_drawMaterial) { drawMaterialKey = _drawMaterial->getKey(); @@ -472,7 +477,7 @@ ShapeKey ModelMeshPartPayload::evalShapeKey(bool isWireframe) const { if (isWireframe) { builder.withWireframe(); } - return builder.build(); + _shapeKey = builder.build(); } ShapeKey ModelMeshPartPayload::getShapeKey() const { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index e56623ae16..8715b6a7a0 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -96,12 +96,9 @@ public: render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) override; - render::ItemKey evalKey(bool isVisible, bool isLayeredInFront, bool isLayeredInHUD) const; - void setKey(const render::ItemKey& itemKey) { _itemKey = itemKey; } - int evalLayer(bool isLayeredInFront, bool isLayeredInHUD) const; - void setLayer(int layer) { _layer = layer; } - render::ShapeKey evalShapeKey(bool isWireframe) const; - void setShapeKey(const render::ShapeKey& shapeKey) { _shapeKey = shapeKey; }; + void setKey(bool isVisible, bool isLayered); + void setLayer(bool isLayeredInFront, bool isLayeredInHUD); + void setShapeKey(bool invalidateShapeKey, bool isWireframe); // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; @@ -123,8 +120,8 @@ private: void initCache(const ModelPointer& model); render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() }; - int _layer { render::Item::LAYER_3D }; render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; + int _layer { render::Item::LAYER_3D }; }; namespace render { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7dff629183..7717ceda6f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -278,9 +278,9 @@ void Model::updateRenderItems() { } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); - data.setKey(data.evalKey(isVisible, isLayeredInFront, isLayeredInHUD)); - data.setLayer(data.evalLayer(isLayeredInFront, isLayeredInHUD)); - data.setShapeKey(invalidatePayloadShapeKey ? render::ShapeKey::Builder::invalid() : data.evalShapeKey(isWireframe)); + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + data.setShapeKey(invalidatePayloadShapeKey, isWireframe); }); } From b30d3fcc12ad48145cbb6f0e592e2fdba4379507 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 20 Dec 2017 15:40:10 -0800 Subject: [PATCH 080/102] Change three lines of code. Fix one thing. Break another. --- libraries/entities/src/EntityItemProperties.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 678ddfcea5..22e7ce5257 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2530,7 +2530,8 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte return false; } - const unsigned char* key = reinterpret_cast(publicKey.toUtf8().constData()); + auto keyByteArray = publicKey.toUtf8(); + auto key = keyByteArray.constData(); int keyLength = publicKey.length(); BIO *bio = BIO_new_mem_buf((void*)key, keyLength); @@ -2548,14 +2549,14 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte // ECSDA verification prototype: note that type is currently ignored // int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, // const unsigned char *sig, int siglen, EC_KEY *eckey); - bool answer = ECDSA_verify(0, + int answer = ECDSA_verify(0, digest, digestLength, signature, signatureLength, ec); long error = ERR_get_error(); - if (error != 0) { + if (error != 0 || answer == -1) { const char* error_str = ERR_error_string(error, NULL); qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str << "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength @@ -2569,7 +2570,7 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte if (evp_key) { EVP_PKEY_free(evp_key); } - return answer; + return (answer == 1); } else { if (bio) { BIO_free(bio); From 7a9d566e023dd4b7080bfc1f8d4758ef281fe56d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Dec 2017 13:56:20 -0800 Subject: [PATCH 081/102] remove unnecessary whitespace --- interface/src/LODManager.cpp | 42 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 01ccbd0d9a..7b99c89cee 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -64,11 +64,11 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta // translate into fps for legacy implementation float currentFPS = (float)MSECS_PER_SECOND / _avgRenderTime; - + _fpsAverageStartWindow.updateAverage(currentFPS); _fpsAverageDownWindow.updateAverage(currentFPS); _fpsAverageUpWindow.updateAverage(currentFPS); - + quint64 now = usecTimestampNow(); quint64 elapsedSinceDownShift = now - _lastDownShift; @@ -76,22 +76,22 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable); quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift; - + if (_automaticLODAdjust) { bool changed = false; - - // LOD Downward adjustment + + // LOD Downward adjustment // If we've been downshifting, we watch a shorter downshift window so that we will quickly move toward our // target frame rate. But if we haven't just done a downshift (either because our last shift was an upshift, // or because we've just started out) then we look at a much longer window to consider whether or not to start // downshifting. - bool doDownShift = false; + bool doDownShift = false; if (_isDownshifting) { // only consider things if our DOWN_SHIFT time has elapsed... if (elapsedSinceDownShift > DOWN_SHIFT_ELPASED) { doDownShift = _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS(); - + if (!doDownShift) { qCDebug(interfaceapp) << "---- WE APPEAR TO BE DONE DOWN SHIFTING -----"; _isDownshifting = false; @@ -99,10 +99,10 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta } } } else { - doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED + doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()); } - + if (doDownShift) { // Octree items... stepwise adjustment @@ -118,17 +118,17 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta if (_isDownshifting) { // subsequent downshift qCDebug(interfaceapp) << "adjusting LOD DOWN..." - << "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was " - << _fpsAverageDownWindow.getAverage() - << "minimum is:" << getLODDecreaseFPS() + << "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageDownWindow.getAverage() + << "minimum is:" << getLODDecreaseFPS() << "elapsedSinceDownShift:" << elapsedSinceDownShift << " NEW _octreeSizeScale=" << _octreeSizeScale; } else { // first downshift qCDebug(interfaceapp) << "adjusting LOD DOWN after initial delay..." - << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " - << _fpsAverageStartWindow.getAverage() - << "minimum is:" << getLODDecreaseFPS() + << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageStartWindow.getAverage() + << "minimum is:" << getLODDecreaseFPS() << "elapsedSinceUpShift:" << elapsedSinceUpShift << " NEW _octreeSizeScale=" << _octreeSizeScale; } @@ -139,10 +139,10 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta emit LODDecreased(); } } else { - + // LOD Upward adjustment if (elapsedSinceUpShift > UP_SHIFT_ELPASED) { - + if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) { // Octee items... stepwise adjustment @@ -158,11 +158,11 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta changed = true; } } - + if (changed) { - qCDebug(interfaceapp) << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was " + qCDebug(interfaceapp) << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was " << _fpsAverageUpWindow.getAverage() - << "upshift point is:" << getLODIncreaseFPS() + << "upshift point is:" << getLODIncreaseFPS() << "elapsedSinceUpShift:" << elapsedSinceUpShift << " NEW _octreeSizeScale=" << _octreeSizeScale; @@ -173,7 +173,7 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta } } } - + if (changed) { auto lodToolsDialog = DependencyManager::get()->getLodToolsDialog(); if (lodToolsDialog) { From 5c84c5f84572e1882b6cc42f552b924a3a6d2e02 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Dec 2017 13:03:36 -0800 Subject: [PATCH 082/102] measure average time of 'present' --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 2 ++ libraries/plugins/src/plugins/DisplayPlugin.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index cb9d06dce1..e646ba27f5 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -679,6 +679,7 @@ void OpenGLDisplayPlugin::internalPresent() { void OpenGLDisplayPlugin::present() { auto frameId = (uint64_t)presentCount(); PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, frameId) + uint64_t startPresent = usecTimestampNow(); { PROFILE_RANGE_EX(render, "updateFrameData", 0xff00ff00, frameId) updateFrameData(); @@ -713,6 +714,7 @@ void OpenGLDisplayPlugin::present() { gpu::Backend::freeGPUMemSize.set(gpu::gl::getFreeDedicatedMemory()); } + _movingAveragePresent.addSample((float)(usecTimestampNow() - startPresent)); } float OpenGLDisplayPlugin::newFramePresentRate() const { diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index efce158864..2c717f629c 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -21,8 +21,10 @@ #include #include +#include #include #include +#include #include #include "Plugin.h" @@ -203,6 +205,7 @@ public: virtual void cycleDebugOutput() {} void waitForPresent(); + float getAveragePresentTime() { return _movingAveragePresent.average / (float)USECS_PER_MSEC; } // in msec std::function getHUDOperator(); @@ -220,6 +223,8 @@ protected: std::function _hudOperator { std::function() }; + MovingAverage _movingAveragePresent; + private: QMutex _presentMutex; QWaitCondition _presentCondition; From 8e0d367a2d7fa0a8a6636dfd82153794c7aa96ea Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Dec 2017 13:13:13 -0800 Subject: [PATCH 083/102] use full 'present' time for FPS calculation also, refactor LOD adjust logic --- interface/src/Application.cpp | 4 +- interface/src/LODManager.cpp | 189 ++++++++++------------------------ interface/src/LODManager.h | 42 ++------ 3 files changed, 68 insertions(+), 167 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 81ed5a0578..174424f4ca 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4323,9 +4323,9 @@ void Application::updateLOD(float deltaTime) const { PerformanceTimer perfTimer("LOD"); // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode if (!isThrottleRendering()) { - float batchTime = (float)_gpuContext->getFrameTimerBatchAverage(); + float presentTime = getActiveDisplayPlugin()->getAveragePresentTime(); float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime()); - DependencyManager::get()->autoAdjustLOD(batchTime, engineRunTime, deltaTime); + DependencyManager::get()->autoAdjustLOD(presentTime, engineRunTime, deltaTime); } else { DependencyManager::get()->resetLODAdjust(); } diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 7b99c89cee..c416e6a6c7 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -19,6 +19,11 @@ #include "LODManager.h" +const uint64_t LOD_AUTO_ADJUST_PERIOD = 500 * USECS_PER_MSEC; +const float LOD_AUTO_ADJUST_DECREMENT_FACTOR = 0.8f; +const float LOD_AUTO_ADJUST_INCREMENT_FACTOR = 1.2f; + + Setting::Handle desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS); Setting::Handle hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS); @@ -39,156 +44,74 @@ float LODManager::getLODIncreaseFPS() { return getDesktopLODIncreaseFPS(); } -void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float deltaTimeSec) { - - // NOTE: our first ~100 samples at app startup are completely all over the place, and we don't - // really want to count them in our average, so we will ignore the real frame rates and stuff - // our moving average with simulated good data - const int IGNORE_THESE_SAMPLES = 100; - if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) { - _lastStable = _lastUpShift = _lastDownShift = usecTimestampNow(); - } - +void LODManager::autoAdjustLOD(float presentTime, float engineRunTime, float deltaTimeSec) { // compute time-weighted running average renderTime - const float OVERLAY_AND_SWAP_TIME_BUDGET = 2.0f; // msec - float renderTime = batchTime + OVERLAY_AND_SWAP_TIME_BUDGET; - float maxTime = glm::max(renderTime, engineRunTime); - const float BLEND_TIMESCALE = 0.3f; // sec - const float MIN_DELTA_TIME = 0.001f; - const float safeDeltaTime = glm::max(deltaTimeSec, MIN_DELTA_TIME); - float blend = BLEND_TIMESCALE / safeDeltaTime; - if (blend > 1.0f) { - blend = 1.0f; - } + float maxTime = glm::max(presentTime, engineRunTime); + const float LOD_ADJUST_TIMESCALE = 0.1f; // sec + float blend = (deltaTimeSec < LOD_ADJUST_TIMESCALE) ? deltaTimeSec / LOD_ADJUST_TIMESCALE : 1.0f; _avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxTime; // msec + if (!_automaticLODAdjust) { + // early exit + return; + } - // translate into fps for legacy implementation + float oldOctreeSizeScale = _octreeSizeScale; float currentFPS = (float)MSECS_PER_SECOND / _avgRenderTime; - - _fpsAverageStartWindow.updateAverage(currentFPS); - _fpsAverageDownWindow.updateAverage(currentFPS); - _fpsAverageUpWindow.updateAverage(currentFPS); - - quint64 now = usecTimestampNow(); - - quint64 elapsedSinceDownShift = now - _lastDownShift; - quint64 elapsedSinceUpShift = now - _lastUpShift; - - quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable); - quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift; - - if (_automaticLODAdjust) { - bool changed = false; - - // LOD Downward adjustment - // If we've been downshifting, we watch a shorter downshift window so that we will quickly move toward our - // target frame rate. But if we haven't just done a downshift (either because our last shift was an upshift, - // or because we've just started out) then we look at a much longer window to consider whether or not to start - // downshifting. - bool doDownShift = false; - - if (_isDownshifting) { - // only consider things if our DOWN_SHIFT time has elapsed... - if (elapsedSinceDownShift > DOWN_SHIFT_ELPASED) { - doDownShift = _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS(); - - if (!doDownShift) { - qCDebug(interfaceapp) << "---- WE APPEAR TO BE DONE DOWN SHIFTING -----"; - _isDownshifting = false; - _lastStable = now; - } - } - } else { - doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED - && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()); - } - - if (doDownShift) { - - // Octree items... stepwise adjustment + uint64_t now = usecTimestampNow(); + if (currentFPS < getLODDecreaseFPS()) { + if (now > _decreaseFPSExpiry) { + _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale *= ADJUST_LOD_DOWN_BY; + _octreeSizeScale *= LOD_AUTO_ADJUST_DECREMENT_FACTOR; if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; } - changed = true; + qCDebug(interfaceapp) << "adjusting LOD UP" + << "fps =" << currentFPS + << "targetFPS =" << getLODDecreaseFPS(); } - - if (changed) { - if (_isDownshifting) { - // subsequent downshift - qCDebug(interfaceapp) << "adjusting LOD DOWN..." - << "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was " - << _fpsAverageDownWindow.getAverage() - << "minimum is:" << getLODDecreaseFPS() - << "elapsedSinceDownShift:" << elapsedSinceDownShift - << " NEW _octreeSizeScale=" << _octreeSizeScale; + _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; + } + _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; + } else if (currentFPS > getLODIncreaseFPS()) { + if (now > _increaseFPSExpiry) { + _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; + if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { + if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; } else { - // first downshift - qCDebug(interfaceapp) << "adjusting LOD DOWN after initial delay..." - << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " - << _fpsAverageStartWindow.getAverage() - << "minimum is:" << getLODDecreaseFPS() - << "elapsedSinceUpShift:" << elapsedSinceUpShift - << " NEW _octreeSizeScale=" << _octreeSizeScale; - } - - _lastDownShift = now; - _isDownshifting = true; - - emit LODDecreased(); - } - } else { - - // LOD Upward adjustment - if (elapsedSinceUpShift > UP_SHIFT_ELPASED) { - - if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) { - - // Octee items... stepwise adjustment - if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { - if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; - } else { - _octreeSizeScale *= ADJUST_LOD_UP_BY; - } - if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; - } - changed = true; - } - } - - if (changed) { - qCDebug(interfaceapp) << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was " - << _fpsAverageUpWindow.getAverage() - << "upshift point is:" << getLODIncreaseFPS() - << "elapsedSinceUpShift:" << elapsedSinceUpShift - << " NEW _octreeSizeScale=" << _octreeSizeScale; - - _lastUpShift = now; - _isDownshifting = false; - - emit LODIncreased(); + _octreeSizeScale *= LOD_AUTO_ADJUST_INCREMENT_FACTOR; } + if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; + } + qCDebug(interfaceapp) << "adjusting LOD DOWN" + << "fps =" << currentFPS + << "targetFPS =" << getLODDecreaseFPS(); } + _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; } + _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; + } else { + _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; + _decreaseFPSExpiry = _increaseFPSExpiry; + } - if (changed) { - auto lodToolsDialog = DependencyManager::get()->getLodToolsDialog(); - if (lodToolsDialog) { - lodToolsDialog->reloadSliders(); - } + if (oldOctreeSizeScale != _octreeSizeScale) { + auto lodToolsDialog = DependencyManager::get()->getLodToolsDialog(); + if (lodToolsDialog) { + lodToolsDialog->reloadSliders(); } + // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime + // to be at middle of target zone. It will drift close to its true value within + // about three few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary. + float expectedFPS = 0.5f * (getLODIncreaseFPS() + getLODDecreaseFPS()); + _avgRenderTime = MSECS_PER_SECOND / expectedFPS; } } void LODManager::resetLODAdjust() { - _fpsAverageStartWindow.reset(); - _fpsAverageDownWindow.reset(); - _fpsAverageUpWindow.reset(); - _lastUpShift = _lastDownShift = usecTimestampNow(); - _isDownshifting = false; + _decreaseFPSExpiry = _increaseFPSExpiry = usecTimestampNow() + LOD_AUTO_ADJUST_PERIOD; } const float MIN_DECREASE_FPS = 0.5f; @@ -206,7 +129,7 @@ float LODManager::getDesktopLODDecreaseFPS() const { } float LODManager::getDesktopLODIncreaseFPS() const { - return glm::max(((float)MSECS_PER_SECOND / _desktopMaxRenderTime) + INCREASE_LOD_GAP, MAX_LIKELY_DESKTOP_FPS); + return glm::max(((float)MSECS_PER_SECOND / _desktopMaxRenderTime) + INCREASE_LOD_GAP_FPS, MAX_LIKELY_DESKTOP_FPS); } void LODManager::setHMDLODDecreaseFPS(float fps) { @@ -222,7 +145,7 @@ float LODManager::getHMDLODDecreaseFPS() const { } float LODManager::getHMDLODIncreaseFPS() const { - return glm::max(((float)MSECS_PER_SECOND / _hmdMaxRenderTime) + INCREASE_LOD_GAP, MAX_LIKELY_HMD_FPS); + return glm::max(((float)MSECS_PER_SECOND / _hmdMaxRenderTime) + INCREASE_LOD_GAP_FPS, MAX_LIKELY_HMD_FPS); } QString LODManager::getLODFeedbackText() { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 1b3797a0ca..4ec36e613b 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -19,29 +19,13 @@ #include #include -const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 20.0; -const float DEFAULT_HMD_LOD_DOWN_FPS = 20.0; +const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 20.0f; +const float DEFAULT_HMD_LOD_DOWN_FPS = 45.0f; const float DEFAULT_DESKTOP_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_DESKTOP_LOD_DOWN_FPS; // msec const float DEFAULT_HMD_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_HMD_LOD_DOWN_FPS; // msec -const float MAX_LIKELY_DESKTOP_FPS = 59.0; // this is essentially, V-synch - 1 fps -const float MAX_LIKELY_HMD_FPS = 74.0; // this is essentially, V-synch - 1 fps -const float INCREASE_LOD_GAP = 15.0f; - -const float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts -const float DOWN_SHIFT_WINDOW_IN_SECS = 0.5f; -const float UP_SHIFT_WINDOW_IN_SECS = 2.5f; - -const int ASSUMED_FPS = 60; -const quint64 START_SHIFT_ELPASED = USECS_PER_SECOND * START_DELAY_WINDOW_IN_SECS; -const quint64 DOWN_SHIFT_ELPASED = USECS_PER_SECOND * DOWN_SHIFT_WINDOW_IN_SECS; // Consider adjusting LOD down after half a second -const quint64 UP_SHIFT_ELPASED = USECS_PER_SECOND * UP_SHIFT_WINDOW_IN_SECS; - -const int START_DELAY_SAMPLES_OF_FRAMES = ASSUMED_FPS * START_DELAY_WINDOW_IN_SECS; -const int DOWN_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * DOWN_SHIFT_WINDOW_IN_SECS; -const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS; - -const float ADJUST_LOD_DOWN_BY = 0.9f; -const float ADJUST_LOD_UP_BY = 1.1f; +const float MAX_LIKELY_DESKTOP_FPS = 59.0f; // this is essentially, V-synch - 1 fps +const float MAX_LIKELY_HMD_FPS = 74.0f; // this is essentially, V-synch - 1 fps +const float INCREASE_LOD_GAP_FPS = 15.0f; // fps // The default value DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision). const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; @@ -78,7 +62,7 @@ public: Q_INVOKABLE float getLODIncreaseFPS(); static bool shouldRender(const RenderArgs* args, const AABox& bounds); - void autoAdjustLOD(float batchTime, float engineRunTime, float deltaTimeSec); + void autoAdjustLOD(float presentTime, float engineRunTime, float deltaTimeSec); void loadSettings(); void saveSettings(); @@ -92,21 +76,15 @@ private: LODManager(); bool _automaticLODAdjust = true; - float _avgRenderTime { 0.0 }; + float _avgRenderTime { 0.0f }; float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME }; float _hmdMaxRenderTime { DEFAULT_HMD_MAX_RENDER_TIME }; float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; int _boundaryLevelAdjust = 0; - - quint64 _lastDownShift = 0; - quint64 _lastUpShift = 0; - quint64 _lastStable = 0; - bool _isDownshifting = false; // start out as if we're not downshifting - - SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES; - SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES; - SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES; + + uint64_t _decreaseFPSExpiry { 0 }; + uint64_t _increaseFPSExpiry { 0 }; }; #endif // hifi_LODManager_h From 9c4a0c8c702b6f3565c2c1c1945aa058503d48e4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Dec 2017 14:12:46 -0800 Subject: [PATCH 084/102] tweak LOD adjustment logging --- interface/src/LODManager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index c416e6a6c7..77aabccb78 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -66,9 +66,10 @@ void LODManager::autoAdjustLOD(float presentTime, float engineRunTime, float del if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; } - qCDebug(interfaceapp) << "adjusting LOD UP" + qCDebug(interfaceapp) << "adjusting LOD DOWN" << "fps =" << currentFPS - << "targetFPS =" << getLODDecreaseFPS(); + << "targetFPS =" << getLODDecreaseFPS() + << "octreeSizeScale =" << _octreeSizeScale; } _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; } @@ -85,9 +86,10 @@ void LODManager::autoAdjustLOD(float presentTime, float engineRunTime, float del if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; } - qCDebug(interfaceapp) << "adjusting LOD DOWN" + qCDebug(interfaceapp) << "adjusting LOD UP" << "fps =" << currentFPS - << "targetFPS =" << getLODDecreaseFPS(); + << "targetFPS =" << getLODDecreaseFPS() + << "octreeSizeScale =" << _octreeSizeScale; } _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; } From 4fb9680f3b96654675cff9fcec91b6efcb64755f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Dec 2017 16:43:49 -0800 Subject: [PATCH 085/102] also consider GPU render time for LOD adjust --- interface/src/Application.cpp | 4 +++- interface/src/LODManager.cpp | 5 ++--- interface/src/LODManager.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 174424f4ca..f17e06cb35 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4325,7 +4325,9 @@ void Application::updateLOD(float deltaTime) const { if (!isThrottleRendering()) { float presentTime = getActiveDisplayPlugin()->getAveragePresentTime(); float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime()); - DependencyManager::get()->autoAdjustLOD(presentTime, engineRunTime, deltaTime); + float gpuTime = getGPUContext()->getFrameTimerGPUAverage(); + float maxRenderTime = glm::max(gpuTime, glm::max(presentTime, engineRunTime)); + DependencyManager::get()->autoAdjustLOD(maxRenderTime, deltaTime); } else { DependencyManager::get()->resetLODAdjust(); } diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 77aabccb78..c369920cf3 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -44,12 +44,11 @@ float LODManager::getLODIncreaseFPS() { return getDesktopLODIncreaseFPS(); } -void LODManager::autoAdjustLOD(float presentTime, float engineRunTime, float deltaTimeSec) { +void LODManager::autoAdjustLOD(float renderTime, float deltaTimeSec) { // compute time-weighted running average renderTime - float maxTime = glm::max(presentTime, engineRunTime); const float LOD_ADJUST_TIMESCALE = 0.1f; // sec float blend = (deltaTimeSec < LOD_ADJUST_TIMESCALE) ? deltaTimeSec / LOD_ADJUST_TIMESCALE : 1.0f; - _avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxTime; // msec + _avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * renderTime; // msec if (!_automaticLODAdjust) { // early exit return; diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 4ec36e613b..eadb3f2e5c 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -62,7 +62,7 @@ public: Q_INVOKABLE float getLODIncreaseFPS(); static bool shouldRender(const RenderArgs* args, const AABox& bounds); - void autoAdjustLOD(float presentTime, float engineRunTime, float deltaTimeSec); + void autoAdjustLOD(float renderTime, float deltaTimeSec); void loadSettings(); void saveSettings(); From 5c11ae346962639c57fb8a89fc1b4979cec5a079 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Dec 2017 16:50:31 -0800 Subject: [PATCH 086/102] bump desktop min FPS from 20 to 30 msec --- interface/src/LODManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index eadb3f2e5c..374f6a2e73 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -19,7 +19,7 @@ #include #include -const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 20.0f; +const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0f; const float DEFAULT_HMD_LOD_DOWN_FPS = 45.0f; const float DEFAULT_DESKTOP_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_DESKTOP_LOD_DOWN_FPS; // msec const float DEFAULT_HMD_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_HMD_LOD_DOWN_FPS; // msec From 721e9d426aa3462c63e141ff55ebe5c874bde722 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 20 Dec 2017 09:14:53 -0800 Subject: [PATCH 087/102] restore signals on LOD change --- interface/src/LODManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index c369920cf3..714cc31f13 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -69,6 +69,7 @@ void LODManager::autoAdjustLOD(float renderTime, float deltaTimeSec) { << "fps =" << currentFPS << "targetFPS =" << getLODDecreaseFPS() << "octreeSizeScale =" << _octreeSizeScale; + emit LODDecreased(); } _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; } @@ -89,6 +90,7 @@ void LODManager::autoAdjustLOD(float renderTime, float deltaTimeSec) { << "fps =" << currentFPS << "targetFPS =" << getLODDecreaseFPS() << "octreeSizeScale =" << _octreeSizeScale; + emit LODIncreased(); } _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; } From c1906215ba455113fc7c24ad3d89f21b76782b62 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 20 Dec 2017 11:36:51 -0800 Subject: [PATCH 088/102] add comments --- interface/src/LODManager.cpp | 28 +++++++++++++++++++++------- interface/src/LODManager.h | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 714cc31f13..9e6fabd439 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -19,10 +19,6 @@ #include "LODManager.h" -const uint64_t LOD_AUTO_ADJUST_PERIOD = 500 * USECS_PER_MSEC; -const float LOD_AUTO_ADJUST_DECREMENT_FACTOR = 0.8f; -const float LOD_AUTO_ADJUST_INCREMENT_FACTOR = 1.2f; - Setting::Handle desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS); Setting::Handle hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS); @@ -44,10 +40,28 @@ float LODManager::getLODIncreaseFPS() { return getDesktopLODIncreaseFPS(); } -void LODManager::autoAdjustLOD(float renderTime, float deltaTimeSec) { +// We use a "time-weighted running average" of the renderTime and compare it against min/max thresholds +// to determine if we should adjust the level of detail (LOD). +// +// A time-weighted running average has a timescale which determines how fast the average tracks the measured +// value in real-time. Given a step-function in the mesured value, and assuming measurements happen +// faster than the runningAverage is computed, the error between the value and its runningAverage will be +// reduced by 1/e every timescale of real-time that passes. +const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.1f; // sec +// +// Assuming the measured value is affected by logic invoked by the runningAverage bumping up against its +// thresholds, we expect the adjustment to introduce a step-function. We want the runningAverage settle +// to the new value BEFORE we test it aginst its thresholds again. Hence we test on a period that is a few +// multiples of the running average timescale: +const uint64_t LOD_AUTO_ADJUST_PERIOD = 5 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec + +const float LOD_AUTO_ADJUST_DECREMENT_FACTOR = 0.8f; +const float LOD_AUTO_ADJUST_INCREMENT_FACTOR = 1.2f; + +void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) { // compute time-weighted running average renderTime - const float LOD_ADJUST_TIMESCALE = 0.1f; // sec - float blend = (deltaTimeSec < LOD_ADJUST_TIMESCALE) ? deltaTimeSec / LOD_ADJUST_TIMESCALE : 1.0f; + // Note: we MUST clamp the blend to 1.0 for stability + float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f; _avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * renderTime; // msec if (!_automaticLODAdjust) { // early exit diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 374f6a2e73..cf38342db0 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -62,7 +62,7 @@ public: Q_INVOKABLE float getLODIncreaseFPS(); static bool shouldRender(const RenderArgs* args, const AABox& bounds); - void autoAdjustLOD(float renderTime, float deltaTimeSec); + void autoAdjustLOD(float renderTime, float realTimeDelta); void loadSettings(); void saveSettings(); From 31e9f26772c5e3d9cde34624b32450863538b363 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 21 Dec 2017 11:34:03 -0800 Subject: [PATCH 089/102] fix use after free of pending message --- libraries/networking/src/udt/Connection.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 2f57523f79..77ed589e0b 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -191,6 +191,8 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { pendingMessage.enqueuePacket(std::move(packet)); + bool processedLastOrOnly = false; + while (pendingMessage.hasAvailablePackets()) { auto packet = pendingMessage.removeNextPacket(); @@ -201,9 +203,13 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { // if this was the last or only packet, then we can remove the pending message from our hash if (packetPosition == Packet::PacketPosition::LAST || packetPosition == Packet::PacketPosition::ONLY) { - _pendingReceivedMessages.erase(messageNumber); + processedLastOrOnly = true; } } + + if (processedLastOrOnly) { + _pendingReceivedMessages.erase(messageNumber); + } } void Connection::sync() { From e96367340971a3c1411664d74fa75006e4055162 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 21 Dec 2017 13:48:35 -0800 Subject: [PATCH 090/102] Progress? --- interface/src/commerce/Ledger.cpp | 2 +- interface/src/commerce/Wallet.cpp | 9 +++++---- libraries/entities/src/EntityItemProperties.cpp | 8 ++++++-- libraries/entities/src/EntityTree.cpp | 7 ++++--- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 3257a634c7..59d274158b 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -61,7 +61,7 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) { auto wallet = DependencyManager::get(); - QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key); + QString signature = wallet->signWithKey(text, key); QJsonObject request; request[propertyName] = QString(text); if (!controlled_failure) { diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 00941d6c50..04a14e2a54 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -548,13 +548,16 @@ QStringList Wallet::listPublicKeys() { // the horror of code pages and so on (changing the bytes) by just returning a base64 // encoded string representing the signature (suitable for http, etc...) QString Wallet::signWithKey(const QByteArray& text, const QString& key) { - qCInfo(commerce) << "Signing text" << text << "with key" << key; EC_KEY* ecPrivateKey = NULL; + + auto keyFilePathString = keyFilePath().toStdString(); if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) { unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)]; unsigned int signatureBytes = 0; + qCInfo(commerce) << "Signing text" << text << "with key at" << ecPrivateKey; + QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256); @@ -747,12 +750,10 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack } EC_KEY_free(ec); - QByteArray ba = sig.toLocal8Bit(); - const char *sigChar = ba.data(); QByteArray textByteArray; if (status > -1) { - textByteArray = QByteArray(sigChar, (int) strlen(sigChar)); + textByteArray = sig.toUtf8(); } textByteArraySize = textByteArray.size(); int certIDSize = certID.size(); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 22e7ce5257..13ebd9ef9f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2557,11 +2557,15 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte ec); long error = ERR_get_error(); if (error != 0 || answer == -1) { - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str + qCWarning(entities) << "ERROR while verifying signature!" << "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength << "\nDigest:" << digest << "\nDigest Length:" << digestLength << "\nSignature:" << signature << "\nSignature Length:" << signatureLength; + while (error != 0) { + const char* error_str = ERR_error_string(error, NULL); + qCWarning(entities) << "EC error:" << error_str; + error = ERR_get_error(); + } } EC_KEY_free(ec); if (bio) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b5765bb44b..6aaddfaa57 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1189,13 +1189,14 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity key = sent.second; } - QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----"; - bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8()); + QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; + QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray::fromBase64(actualNonce.toUtf8()), QCryptographicHash::Sha256); + bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8())); if (verificationSuccess) { qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded."; } else { - qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for nonce" << actualNonce << "key" << key << "signature" << nonce; + qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed.\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key; } return verificationSuccess; From 69c1c65eb8853a6ebd0701c53f6b732d962c138a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 21 Dec 2017 12:48:43 -0800 Subject: [PATCH 091/102] get rid of _model completely --- .../render-utils/src/CauterizedMeshPartPayload.cpp | 12 +----------- .../render-utils/src/CauterizedMeshPartPayload.h | 3 +++ libraries/render-utils/src/CauterizedModel.cpp | 4 +++- libraries/render-utils/src/MeshPartPayload.cpp | 14 ++++---------- libraries/render-utils/src/MeshPartPayload.h | 2 +- 5 files changed, 12 insertions(+), 23 deletions(-) diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index 3bb2aa2ef9..396cd13508 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -40,17 +40,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { // Still relying on the raw data from the model - bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE); - if (useCauterizedMesh) { - ModelPointer model = _model.lock(); - if (model) { - CauterizedModel* skeleton = static_cast(model.get()); - useCauterizedMesh = useCauterizedMesh && skeleton->getEnableCauterization(); - } else { - useCauterizedMesh = false; - } - } - + bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _cauterizedClusterBuffer); diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 1c98f5abf3..44eddc6e31 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -21,9 +21,12 @@ public: void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; + void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } + private: gpu::BufferPointer _cauterizedClusterBuffer; Transform _cauterizedTransform; + bool _enableCauterization { false }; }; #endif // hifi_CauterizedMeshPartPayload_h diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 52095ee25a..dbb82ab638 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -182,6 +182,7 @@ void CauterizedModel::updateRenderItems() { bool isVisible = self->isVisible(); bool isLayeredInFront = self->isLayeredInFront(); bool isLayeredInHUD = self->isLayeredInHUD(); + bool enableCauterization = self->getEnableCauterization(); render::Transaction transaction; for (int i = 0; i < (int)self->_modelMeshRenderItemIDs.size(); i++) { @@ -194,7 +195,7 @@ void CauterizedModel::updateRenderItems() { bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized, invalidatePayloadShapeKey, - isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](CauterizedMeshPartPayload& data) { + isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) { data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized); Transform renderTransform = modelTransform; @@ -209,6 +210,7 @@ void CauterizedModel::updateRenderItems() { } data.updateTransformForCauterizedMesh(renderTransform); + data.setEnableCauterization(enableCauterization); data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 313cd383f9..61a5175efd 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -325,7 +325,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in _shapeID(shapeIndex) { assert(model && model->isLoaded()); - _model = model; + _blendedVertexBuffer = model->_blendedVertexBuffers[_meshIndex]; auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); const Model::MeshState& state = model->getMeshState(_meshIndex); @@ -493,10 +493,9 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); batch.setInputFormat((_drawMesh->getVertexFormat())); - ModelPointer model = _model.lock(); - if (model) { - batch.setInputBuffer(0, model->_blendedVertexBuffers[_meshIndex], 0, sizeof(glm::vec3)); - batch.setInputBuffer(1, model->_blendedVertexBuffers[_meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); + if (_blendedVertexBuffer) { + batch.setInputBuffer(0, _blendedVertexBuffer, 0, sizeof(glm::vec3)); + batch.setInputBuffer(1, _blendedVertexBuffer, _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2)); } else { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); @@ -522,11 +521,6 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - ModelPointer model = _model.lock(); - if (!model || !model->isAddedToScene() || !model->isVisible()) { - return; // bail asap - } - if (!args) { return; } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 8715b6a7a0..fb55883101 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -107,7 +107,6 @@ public: void computeAdjustedLocalBound(const std::vector& clusterMatrices); gpu::BufferPointer _clusterBuffer; - ModelWeakPointer _model; int _meshIndex; int _shapeID; @@ -119,6 +118,7 @@ public: private: void initCache(const ModelPointer& model); + gpu::BufferPointer _blendedVertexBuffer; render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() }; render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; int _layer { render::Item::LAYER_3D }; From 18993a8f72784415fc3e1f9129e38aaa58d6a573 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 21 Dec 2017 14:53:47 -0800 Subject: [PATCH 092/102] fix for AvatarData retrieval from SortableAvatar in PriorityQueue --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 47a81ba1fe..fb4b65726a 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -214,7 +214,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) uint64_t getTimestamp() const override { return _lastEncodeTime; } - const AvatarSharedPointer& getAvatar() const { return _avatar; } + AvatarSharedPointer getAvatar() const { return _avatar; } private: AvatarSharedPointer _avatar; @@ -326,7 +326,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) int remainingAvatars = (int)sortedAvatars.size(); while (!sortedAvatars.empty()) { - const auto& avatarData = sortedAvatars.top().getAvatar(); + const auto avatarData = sortedAvatars.top().getAvatar(); sortedAvatars.pop(); remainingAvatars--; From 73eb258e794062255f31a26e8ac1118c116c8020 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 21 Dec 2017 15:01:49 -0800 Subject: [PATCH 093/102] IT'S WORKING!!! --- interface/src/commerce/Ledger.cpp | 2 +- interface/src/commerce/Wallet.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 5 +++-- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 ++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 59d274158b..d7d36dabf6 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -61,7 +61,7 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) { auto wallet = DependencyManager::get(); - QString signature = wallet->signWithKey(text, key); + QString signature = wallet->signWithKey(text, key); QJsonObject request; request[propertyName] = QString(text); if (!controlled_failure) { diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 04a14e2a54..c3c91e82a8 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -556,7 +556,7 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) { unsigned int signatureBytes = 0; - qCInfo(commerce) << "Signing text" << text << "with key at" << ecPrivateKey; + qCInfo(commerce) << "Hashing and signing plaintext" << text << "with key at address" << ecPrivateKey; QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 6aaddfaa57..8f780355db 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1190,13 +1190,14 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity } QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; - QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray::fromBase64(actualNonce.toUtf8()), QCryptographicHash::Sha256); + QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256); bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8())); if (verificationSuccess) { qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded."; } else { - qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed.\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key; + qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed. Actual nonce:" << actualNonce << + "\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key; } return verificationSuccess; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 62354da11a..0a75e8c31b 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::StaticCertJsonVersionOne); + return static_cast(EntityVersion::OwnershipChallengeFix); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConnectionIdentifier); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 618ac2de0c..05d40f9621 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -200,7 +200,8 @@ enum class EntityVersion : PacketVersion { StrokeColorProperty = 77, HasDynamicOwnershipTests, HazeEffect, - StaticCertJsonVersionOne + StaticCertJsonVersionOne, + OwnershipChallengeFix, }; enum class EntityScriptCallMethodVersion : PacketVersion { From 7bf0cc2f63f2818ae115bcb8ff8104fed6ba8274 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 21 Dec 2017 15:17:18 -0800 Subject: [PATCH 094/102] cleanup other ref returns of shared pointers from sortables --- interface/src/avatar/AvatarManager.cpp | 6 +++--- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 8a294182bd..93caef555f 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -150,7 +150,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); } float getRadius() const override { return std::static_pointer_cast(_avatar)->getBoundingRadius(); } uint64_t getTimestamp() const override { return std::static_pointer_cast(_avatar)->getLastRenderUpdateTime(); } - const AvatarSharedPointer& getAvatar() const { return _avatar; } + AvatarSharedPointer getAvatar() const { return _avatar; } private: AvatarSharedPointer _avatar; }; @@ -185,7 +185,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { render::Transaction transaction; while (!sortedAvatars.empty()) { const SortableAvatar& sortData = sortedAvatars.top(); - const auto& avatar = std::static_pointer_cast(sortData.getAvatar()); + const auto avatar = std::static_pointer_cast(sortData.getAvatar()); bool ignoring = DependencyManager::get()->isPersonalMutingNode(avatar->getID()); if (ignoring) { @@ -239,7 +239,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { sortedAvatars.pop(); while (inView && !sortedAvatars.empty()) { const SortableAvatar& newSortData = sortedAvatars.top(); - const auto& newAvatar = std::static_pointer_cast(newSortData.getAvatar()); + const auto newAvatar = std::static_pointer_cast(newSortData.getAvatar()); inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD; if (inView && newAvatar->hasNewJointData()) { numAVatarsNotUpdated++; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 5f7899ae74..a629b2046f 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -349,7 +349,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene float getRadius() const override { return 0.5f * _renderer->getEntity()->getQueryAACube().getScale(); } uint64_t getTimestamp() const override { return _renderer->getUpdateTime(); } - const EntityRendererPointer& getRenderer() const { return _renderer; } + EntityRendererPointer getRenderer() const { return _renderer; } private: EntityRendererPointer _renderer; }; @@ -382,7 +382,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene std::unordered_map::iterator itr; size_t numSorted = sortedRenderables.size(); while (!sortedRenderables.empty() && usecTimestampNow() < expiry) { - const EntityRendererPointer& renderable = sortedRenderables.top().getRenderer(); + const auto renderable = sortedRenderables.top().getRenderer(); renderable->updateInScene(scene, transaction); _renderablesToUpdate.erase(renderable->getEntity()->getID()); sortedRenderables.pop(); From 05b45f2e7ec94ed1ebdf5d216eef215acfbfe3fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 21 Dec 2017 15:40:08 -0800 Subject: [PATCH 095/102] adjust example and add clarifying comments to PrioritySortUtil --- libraries/shared/src/PrioritySortUtil.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h index dc6a877bb9..279fa42ea4 100644 --- a/libraries/shared/src/PrioritySortUtil.h +++ b/libraries/shared/src/PrioritySortUtil.h @@ -28,7 +28,7 @@ glm::vec3 getPosition() const override { return _thing->getPosition(); } float getRadius() const override { return 0.5f * _thing->getBoundingRadius(); } uint64_t getTimestamp() const override { return _thing->getLastTime(); } - const Thing& getThing() const { return _thing; } + Thing getThing() const { return _thing; } private: Thing _thing; }; @@ -43,6 +43,13 @@ (3) Loop over your priority queue and do timeboxed work: + NOTE: Be careful using references to members of instances of T from std::priority_queue. + Under the hood std::priority_queue may re-use instances of T. + For example, after a pop() or a push() the top T may have the same memory address + as the top T before the pop() or push() (but point to a swapped instance of T). + This causes a reference to member variable of T to point to a different value + when operations taken on std::priority_queue shuffle around the instances of T. + uint64_t cutoffTime = usecTimestampNow() + TIME_BUDGET; while (!sortedThings.empty()) { const Thing& thing = sortedThings.top(); From 618e5c9032dbb25bad9acbf3e56171781885508b Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 21 Dec 2017 15:46:01 -0800 Subject: [PATCH 096/102] Commerce Data Tracking: Iteration 3 (Purchases) --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 6 ++++-- .../networking/src/UserActivityLoggerScriptingInterface.cpp | 6 ++++-- .../networking/src/UserActivityLoggerScriptingInterface.h | 4 ++-- scripts/system/html/js/marketplacesInject.js | 3 ++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 6b7432b8b2..9a3d9e1e19 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -33,6 +33,7 @@ Rectangle { property string itemName; property string itemId; property string itemHref; + property string itemAuthor; property double balanceAfterPurchase; property bool alreadyOwned: false; property int itemPrice: -1; @@ -81,12 +82,12 @@ Rectangle { if (result.status !== 'success') { failureErrorText.text = result.message; root.activeView = "checkoutFailure"; - UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemPrice, !root.alreadyOwned, result.message); + UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message); } else { root.itemHref = result.data.download_url; root.isWearable = result.data.categories.indexOf("Wearables") > -1; root.activeView = "checkoutSuccess"; - UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemPrice, !root.alreadyOwned); + UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned); } } @@ -879,6 +880,7 @@ Rectangle { root.itemPrice = message.params.itemPrice; itemHref = message.params.itemHref; referrer = message.params.referrer; + itemAuthor = message.params.itemAuthor; setBuyText(); break; default: diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp index aec6df4f14..c63170de75 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp @@ -89,17 +89,19 @@ void UserActivityLoggerScriptingInterface::doLogAction(QString action, QJsonObje Q_ARG(QJsonObject, details)); } -void UserActivityLoggerScriptingInterface::commercePurchaseSuccess(QString marketplaceID, int cost, bool firstPurchaseOfThisItem) { +void UserActivityLoggerScriptingInterface::commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem) { QJsonObject payload; payload["marketplaceID"] = marketplaceID; + payload["contentCreator"] = contentCreator; payload["cost"] = cost; payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem; doLogAction("commercePurchaseSuccess", payload); } -void UserActivityLoggerScriptingInterface::commercePurchaseFailure(QString marketplaceID, int cost, bool firstPurchaseOfThisItem, QString errorDetails) { +void UserActivityLoggerScriptingInterface::commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails) { QJsonObject payload; payload["marketplaceID"] = marketplaceID; + payload["contentCreator"] = contentCreator; payload["cost"] = cost; payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem; payload["errorDetails"] = errorDetails; diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.h b/libraries/networking/src/UserActivityLoggerScriptingInterface.h index 0e08b050d7..71d411056d 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.h +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.h @@ -33,8 +33,8 @@ public: Q_INVOKABLE void bubbleToggled(bool newValue); Q_INVOKABLE void bubbleActivated(); Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{}); - Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, int cost, bool firstPurchaseOfThisItem); - Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, int cost, bool firstPurchaseOfThisItem, QString errorDetails); + Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem); + Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails); Q_INVOKABLE void commerceEntityRezzed(QString marketplaceID, QString source, QString type); Q_INVOKABLE void commerceWalletSetupStarted(int timestamp, QString setupAttemptID, int setupFlowVersion, QString referrer, QString currentDomain); Q_INVOKABLE void commerceWalletSetupProgress(int timestamp, QString setupAttemptID, int secondsElapsed, int currentStepNumber, QString currentStepName); diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 698dd93f29..2b016884f1 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -250,7 +250,8 @@ itemName: name, itemPrice: price ? parseInt(price, 10) : 0, itemHref: href, - referrer: referrer + referrer: referrer, + itemAuthor: author })); } From 2acea75db33d19a54d99f7e704246fca9e771e24 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 21 Dec 2017 16:05:39 -0800 Subject: [PATCH 097/102] Commerce: Checkout Layout Revisions --- .../qml/hifi/commerce/checkout/Checkout.qml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 6b7432b8b2..6f31fc6ed2 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -410,7 +410,8 @@ Rectangle { Rectangle { id: buyTextContainer; visible: buyText.text !== ""; - anchors.top: parent.top; + anchors.top: cancelPurchaseButton.bottom; + anchors.topMargin: 16; anchors.left: parent.left; anchors.right: parent.right; height: buyText.height + 30; @@ -465,8 +466,8 @@ Rectangle { enabled: (root.balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || !itemIsJson; color: hifi.buttons.blue; colorScheme: hifi.colorSchemes.light; - anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top; - anchors.topMargin: buyTextContainer.visible ? 12 : 16; + anchors.top: checkoutActionButtonsContainer.top; + anchors.topMargin: 16; height: 40; anchors.left: parent.left; anchors.right: parent.right; @@ -926,11 +927,11 @@ Rectangle { buyText.text = ""; } } else { - buyText.text = "This free item will not be added to your Purchases. Non-entities can't yet be purchased for HFC."; - buyTextContainer.color = "#FFD6AD"; - buyTextContainer.border.color = "#FAC07D"; - buyGlyph.text = hifi.glyphs.alert; - buyGlyph.size = 46; + buyText.text = 'Note: This free item will not show up in "My Purchases". You can access it again later from the Marketplace.'; + buyTextContainer.color = hifi.colors.white; + buyTextContainer.border.color = hifi.colors.white; + buyGlyph.text = ""; + buyGlyph.size = 0; } } From a2f2c233371f4ff997d332a8ae77cda60f1d8aaa Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 20 Dec 2017 15:40:10 -0800 Subject: [PATCH 098/102] Change three lines of code. Fix one thing. Break another. --- libraries/entities/src/EntityItemProperties.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 9f7ba1cc80..6e7fe9c1b2 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2513,7 +2513,8 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte return false; } - const unsigned char* key = reinterpret_cast(publicKey.toUtf8().constData()); + auto keyByteArray = publicKey.toUtf8(); + auto key = keyByteArray.constData(); int keyLength = publicKey.length(); BIO *bio = BIO_new_mem_buf((void*)key, keyLength); @@ -2531,14 +2532,14 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte // ECSDA verification prototype: note that type is currently ignored // int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, // const unsigned char *sig, int siglen, EC_KEY *eckey); - bool answer = ECDSA_verify(0, + int answer = ECDSA_verify(0, digest, digestLength, signature, signatureLength, ec); long error = ERR_get_error(); - if (error != 0) { + if (error != 0 || answer == -1) { const char* error_str = ERR_error_string(error, NULL); qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str << "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength @@ -2552,7 +2553,7 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte if (evp_key) { EVP_PKEY_free(evp_key); } - return answer; + return (answer == 1); } else { if (bio) { BIO_free(bio); From 373ef6c6ce11dceccfee7ae425e4e47aa9eee305 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 21 Dec 2017 13:48:35 -0800 Subject: [PATCH 099/102] Progress? --- interface/src/commerce/Ledger.cpp | 2 +- interface/src/commerce/Wallet.cpp | 9 +++++---- libraries/entities/src/EntityItemProperties.cpp | 8 ++++++-- libraries/entities/src/EntityTree.cpp | 7 ++++--- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index b0d293584c..33c23ccf2f 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -61,7 +61,7 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) { auto wallet = DependencyManager::get(); - QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key); + QString signature = wallet->signWithKey(text, key); QJsonObject request; request[propertyName] = QString(text); if (!controlled_failure) { diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 69914e97a4..2f8a470b51 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -547,13 +547,16 @@ QStringList Wallet::listPublicKeys() { // the horror of code pages and so on (changing the bytes) by just returning a base64 // encoded string representing the signature (suitable for http, etc...) QString Wallet::signWithKey(const QByteArray& text, const QString& key) { - qCInfo(commerce) << "Signing text" << text << "with key" << key; EC_KEY* ecPrivateKey = NULL; + + auto keyFilePathString = keyFilePath().toStdString(); if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) { unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)]; unsigned int signatureBytes = 0; + qCInfo(commerce) << "Signing text" << text << "with key at" << ecPrivateKey; + QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256); @@ -746,12 +749,10 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack } EC_KEY_free(ec); - QByteArray ba = sig.toLocal8Bit(); - const char *sigChar = ba.data(); QByteArray textByteArray; if (status > -1) { - textByteArray = QByteArray(sigChar, (int) strlen(sigChar)); + textByteArray = sig.toUtf8(); } textByteArraySize = textByteArray.size(); int certIDSize = certID.size(); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 6e7fe9c1b2..9982f4d6a1 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2540,11 +2540,15 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte ec); long error = ERR_get_error(); if (error != 0 || answer == -1) { - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str + qCWarning(entities) << "ERROR while verifying signature!" << "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength << "\nDigest:" << digest << "\nDigest Length:" << digestLength << "\nSignature:" << signature << "\nSignature Length:" << signatureLength; + while (error != 0) { + const char* error_str = ERR_error_string(error, NULL); + qCWarning(entities) << "EC error:" << error_str; + error = ERR_get_error(); + } } EC_KEY_free(ec); if (bio) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index e62399ce95..3d5bf1dd12 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1189,13 +1189,14 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity key = sent.second; } - QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----"; - bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8()); + QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; + QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray::fromBase64(actualNonce.toUtf8()), QCryptographicHash::Sha256); + bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8())); if (verificationSuccess) { qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded."; } else { - qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for nonce" << actualNonce << "key" << key << "signature" << nonce; + qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed.\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key; } return verificationSuccess; From 07a1cf434a2484b2493be7ed1d64932642119047 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 21 Dec 2017 15:01:49 -0800 Subject: [PATCH 100/102] IT'S WORKING!!! --- interface/src/commerce/Ledger.cpp | 2 +- interface/src/commerce/Wallet.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 5 +++-- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 ++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 33c23ccf2f..2865392e9a 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -61,7 +61,7 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) { auto wallet = DependencyManager::get(); - QString signature = wallet->signWithKey(text, key); + QString signature = wallet->signWithKey(text, key); QJsonObject request; request[propertyName] = QString(text); if (!controlled_failure) { diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 2f8a470b51..602684756f 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -555,7 +555,7 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) { unsigned int signatureBytes = 0; - qCInfo(commerce) << "Signing text" << text << "with key at" << ecPrivateKey; + qCInfo(commerce) << "Hashing and signing plaintext" << text << "with key at address" << ecPrivateKey; QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 3d5bf1dd12..5afea35d1c 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1190,13 +1190,14 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity } QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; - QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray::fromBase64(actualNonce.toUtf8()), QCryptographicHash::Sha256); + QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256); bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8())); if (verificationSuccess) { qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded."; } else { - qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed.\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key; + qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed. Actual nonce:" << actualNonce << + "\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key; } return verificationSuccess; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 207ddf6bbb..0a75e8c31b 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::HazeEffect); + return static_cast(EntityVersion::OwnershipChallengeFix); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConnectionIdentifier); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e5cb87c379..640d9962d2 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -199,7 +199,8 @@ QDebug operator<<(QDebug debug, const PacketType& type); enum class EntityVersion : PacketVersion { StrokeColorProperty = 77, HasDynamicOwnershipTests, - HazeEffect + HazeEffect, + OwnershipChallengeFix }; enum class EntityScriptCallMethodVersion : PacketVersion { From ef71470d85737384efde4f38fe8463a3476b024a Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 21 Dec 2017 17:03:04 -0800 Subject: [PATCH 101/102] Small change --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 6f31fc6ed2..a380632425 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -927,7 +927,7 @@ Rectangle { buyText.text = ""; } } else { - buyText.text = 'Note: This free item will not show up in "My Purchases". You can access it again later from the Marketplace.'; + buyText.text = 'This type of item cannot currently be certified, so it will not show up in "My Purchases". You can access it again for free from the Marketplace.'; buyTextContainer.color = hifi.colors.white; buyTextContainer.border.color = hifi.colors.white; buyGlyph.text = ""; From 95c7f876bfb4a76b983d927f4578a9b0e2de0644 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 21 Dec 2017 18:34:37 -0800 Subject: [PATCH 102/102] manually force OwnershipChallengeFix to avoid StaticCertJsonVersionOne --- libraries/networking/src/udt/PacketHeaders.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 640d9962d2..2c28f54014 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -197,7 +197,7 @@ uint qHash(const PacketType& key, uint seed); QDebug operator<<(QDebug debug, const PacketType& type); enum class EntityVersion : PacketVersion { - StrokeColorProperty = 77, + StrokeColorProperty = 0, HasDynamicOwnershipTests, HazeEffect, OwnershipChallengeFix