diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 0ced0a632e..c8067ce81f 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -30,6 +30,8 @@ #include #include +#include // for EntityScriptServerServices + #include "EntityScriptServerLogging.h" #include "../entities/AssignmentParentFinder.h" @@ -68,6 +70,9 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig DependencyManager::set(); DependencyManager::set(ScriptEngine::ENTITY_SERVER_SCRIPT); + DependencyManager::set(); + + // Needed to ensure the creation of the DebugDraw instance on the main thread DebugDraw::getInstance(); @@ -583,6 +588,7 @@ void EntityScriptServer::aboutToFinish() { // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); // cleanup codec & encoder if (_codec && _encoder) { diff --git a/interface/resources/html/raiseAndLowerKeyboard.js b/interface/resources/html/raiseAndLowerKeyboard.js index 2535416fd8..23f3a7e9a8 100644 --- a/interface/resources/html/raiseAndLowerKeyboard.js +++ b/interface/resources/html/raiseAndLowerKeyboard.js @@ -14,6 +14,12 @@ var isWindowFocused = true; var isKeyboardRaised = false; var isNumericKeyboard = false; + var isPasswordField = false; + + function shouldSetPasswordField() { + var nodeType = document.activeElement.type; + return nodeType === "password"; + } function shouldRaiseKeyboard() { var nodeName = document.activeElement.nodeName; @@ -53,12 +59,14 @@ setInterval(function () { var keyboardRaised = shouldRaiseKeyboard(); var numericKeyboard = shouldSetNumeric(); + var passwordField = shouldSetPasswordField(); - if (isWindowFocused && (keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard)) { + if (isWindowFocused && + (keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard || passwordField !== isPasswordField)) { if (typeof EventBridge !== "undefined" && EventBridge !== null) { EventBridge.emitWebEvent( - keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "")) : "_LOWER_KEYBOARD" + keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "") + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD" ); } else { if (numWarnings < MAX_WARNINGS) { @@ -74,6 +82,7 @@ isKeyboardRaised = keyboardRaised; isNumericKeyboard = numericKeyboard; + isPasswordField = passwordField; } }, POLL_FREQUENCY); diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index c73aab08c3..300bcd46f0 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -119,6 +119,7 @@ Item { width: parent.width focus: true label: "Username or Email" + activeFocusOnPress: true ShortcutText { anchors { @@ -135,6 +136,9 @@ Item { onLinkActivated: loginDialog.openUrl(link) } + onFocusChanged: { + root.text = ""; + } } TextField { @@ -143,6 +147,7 @@ Item { label: "Password" echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password + activeFocusOnPress: true ShortcutText { anchors { @@ -159,6 +164,10 @@ Item { onLinkActivated: loginDialog.openUrl(link) } + onFocusChanged: { + root.text = ""; + root.isPassword = true; + } } CheckBoxQQC2 { @@ -233,18 +242,6 @@ Item { } } - // Override ScrollingWindow's keyboard that would be at very bottom of dialog. - Keyboard { - raised: keyboardEnabled && keyboardRaised - numeric: punctuationMode - anchors { - left: parent.left - right: parent.right - bottom: parent.bottom - bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0 - } - } - Component.onCompleted: { root.title = qsTr("Sign Into High Fidelity") root.iconText = "<" diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index f6cf40db8e..9d55998b40 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -108,12 +108,17 @@ Item { id: emailField width: parent.width label: "Email" + activeFocusOnPress: true + onFocusChanged: { + root.text = ""; + } } TextField { id: usernameField width: parent.width label: "Username" + activeFocusOnPress: true ShortcutText { anchors { @@ -128,6 +133,9 @@ Item { horizontalAlignment: Text.AlignHCenter color: hifi.colors.blueAccent + onFocusChanged: { + root.text = ""; + } } } @@ -136,6 +144,7 @@ Item { width: parent.width label: "Password" echoMode: TextInput.Password + activeFocusOnPress: true ShortcutText { anchors { @@ -151,6 +160,11 @@ Item { color: hifi.colors.blueAccent } + + onFocusChanged: { + root.text = ""; + root.isPassword = focus + } } Row { @@ -202,18 +216,6 @@ Item { } } - // Override ScrollingWindow's keyboard that would be at very bottom of dialog. - Keyboard { - raised: keyboardEnabled && keyboardRaised - numeric: punctuationMode - anchors { - left: parent.left - right: parent.right - bottom: parent.bottom - bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0 - } - } - Component.onCompleted: { root.title = qsTr("Create an Account") root.iconText = "<" diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index 8d6634c9b4..66a61742c9 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -39,6 +39,10 @@ Rectangle { property bool shiftMode: false property bool numericShiftMode: false + onRaisedChanged: { + mirroredText = ""; + } + function resetShiftMode(mode) { shiftMode = mode; shiftKey.resetToggledMode(mode); diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index 23143db3ba..8cd61bc90b 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -16,6 +16,7 @@ Item { property bool keyboardEnabled: false property bool keyboardRaised: false property bool punctuationMode: false + property bool passwordField: false property bool isDesktop: false property alias webView: web.webViewCore property alias profile: web.webViewCoreProfile @@ -41,7 +42,7 @@ Item { horizontalCenter: parent.horizontalCenter } spacing: 120 - + TabletWebButton { id: back enabledColor: hifi.colors.darkGray @@ -165,6 +166,11 @@ Item { id: keyboard raised: parent.keyboardEnabled && parent.keyboardRaised numeric: parent.punctuationMode + password: parent.passwordField + + onPasswordChanged: { + keyboard.mirroredText = ""; + } anchors { left: parent.left @@ -172,7 +178,7 @@ Item { bottom: parent.bottom } } - + Component.onCompleted: { root.isDesktop = (typeof desktop !== "undefined"); keyboardEnabled = HMD.active; diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index c38c5df9cf..923c8f3fa1 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -13,6 +13,7 @@ Item { property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false property bool keyboardRaised: false property bool punctuationMode: false + property bool passwordField: false property alias flickable: webroot.interactive // FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface @@ -50,6 +51,7 @@ Item { id: keyboard raised: parent.keyboardEnabled && parent.keyboardRaised numeric: parent.punctuationMode + password: parent.passwordField anchors { left: parent.left right: parent.right diff --git a/interface/resources/qml/dialogs/TabletLoginDialog.qml b/interface/resources/qml/dialogs/TabletLoginDialog.qml index 9722f31144..269788a808 100644 --- a/interface/resources/qml/dialogs/TabletLoginDialog.qml +++ b/interface/resources/qml/dialogs/TabletLoginDialog.qml @@ -37,6 +37,8 @@ TabletModalWindow { property bool keyboardEnabled: false property bool keyboardRaised: false property bool punctuationMode: false + property bool isPassword: false + property alias text: loginKeyboard.mirroredText readonly property bool isTablet: true @@ -130,6 +132,7 @@ TabletModalWindow { id: loginKeyboard raised: root.keyboardEnabled && root.keyboardRaised numeric: root.punctuationMode + password: root.isPassword anchors { left: parent.left right: parent.right diff --git a/interface/resources/qml/hifi/SkyboxChanger.qml b/interface/resources/qml/hifi/SkyboxChanger.qml index a4798ba959..f0c97a11a3 100644 --- a/interface/resources/qml/hifi/SkyboxChanger.qml +++ b/interface/resources/qml/hifi/SkyboxChanger.qml @@ -1,6 +1,6 @@ // -// skyboxchanger.qml -// +// SkyboxChanger.qml +// qml/hifi // // Created by Cain Kilgore on 9th August 2017 // Copyright 2017 High Fidelity, Inc. @@ -9,33 +9,73 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick.Layouts 1.3 +import QtQuick 2.5 +import "../styles-uit" +import "../controls-uit" as HifiControls +import QtQuick.Controls 2.2 -Rectangle { +Item { id: root; - - color: hifi.colors.baseGray; - + HifiConstants { id: hifi; } + + property var defaultThumbnails: []; + property var defaultFulls: []; + + ListModel { + id: skyboxModel; + } + + function getSkyboxes() { + var xmlhttp = new XMLHttpRequest(); + var url = "http://mpassets.highfidelity.com/5fbdbeef-1cf8-4954-811d-3d4acbba4dc9-v1/skyboxes.json"; + xmlhttp.onreadystatechange = function() { + if (xmlhttp.readyState === XMLHttpRequest.DONE && xmlhttp.status === 200) { + sortSkyboxes(xmlhttp.responseText); + } + } + xmlhttp.open("GET", url, true); + xmlhttp.send(); + } + + function sortSkyboxes(response) { + var arr = JSON.parse(response); + var arrLength = arr.length; + for (var i = 0; i < arrLength; i++) { + defaultThumbnails.push(arr[i].thumb); + defaultFulls.push(arr[i].full); + skyboxModel.append({}); + } + setSkyboxes(); + } + + function setSkyboxes() { + for (var i = 0; i < skyboxModel.count; i++) { + skyboxModel.setProperty(i, "thumbnailPath", defaultThumbnails[i]); + skyboxModel.setProperty(i, "fullSkyboxPath", defaultFulls[i]); + } + } + + Component.onCompleted: { + getSkyboxes(); + } + Item { id: titleBarContainer; - // Size width: parent.width; - height: 50; - // Anchors + height: childrenRect.height; anchors.left: parent.left; anchors.top: parent.top; - - RalewaySemiBold { + anchors.right: parent.right; + anchors.topMargin: 20; + RalewayBold { id: titleBarText; text: "Skybox Changer"; - // Text size size: hifi.fontSizes.overlayTitle; - // Anchors - anchors.fill: parent; - anchors.leftMargin: 16; - // Style + anchors.top: parent.top; + anchors.left: parent.left; + anchors.leftMargin: 40 + height: paintedHeight; color: hifi.colors.lightGrayText; - // Alignment horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter; } @@ -43,131 +83,61 @@ Rectangle { id: titleBarDesc; text: "Click an image to choose a new Skybox."; wrapMode: Text.Wrap - // Text size size: 14; - // Anchors - anchors.fill: parent; - anchors.top: titleBarText.bottom - anchors.leftMargin: 16; - anchors.rightMargin: 16; - // Style + anchors.top: titleBarText.bottom; + anchors.left: parent.left; + anchors.leftMargin: 40 + height: paintedHeight; color: hifi.colors.lightGrayText; - // Alignment horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter; - } + } } - // This RowLayout could be a GridLayout instead for further expandability. - // As this SkyboxChanger task only required 6 images, implementing GridLayout wasn't necessary. - // In the future if this is to be expanded to add more Skyboxes, it might be worth changing this. - RowLayout { - id: row1 + GridView { + id: gridView + interactive: true + clip: true anchors.top: titleBarContainer.bottom - anchors.left: parent.left - anchors.leftMargin: 30 - Layout.fillWidth: true - anchors.topMargin: 30 - spacing: 10 - Image { - width: 200; height: 200 - fillMode: Image.Stretch - source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_1.jpg" - clip: true - id: preview1 - MouseArea { + anchors.topMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter + width: 400 + anchors.bottom: parent.bottom + currentIndex: -1 + cellWidth: 200 + cellHeight: 200 + model: skyboxModel + delegate: Item { + width: gridView.cellWidth + height: gridView.cellHeight + Item { anchors.fill: parent - onClicked: { - sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/1.jpg'}); + Image { + source: thumbnailPath + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.Stretch + sourceSize.width: parent.width + sourceSize.height: parent.height + mipmap: true } } - Layout.fillWidth: true - } - Image { - width: 200; height: 200 - fillMode: Image.Stretch - source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_2.jpg" - clip: true - id: preview2 MouseArea { anchors.fill: parent onClicked: { - sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/2.png'}); + sendToScript({method: 'changeSkybox', url: fullSkyboxPath}); } } } - } - RowLayout { - id: row2 - anchors.top: row1.bottom - anchors.topMargin: 10 - anchors.left: parent.left - Layout.fillWidth: true - anchors.leftMargin: 30 - spacing: 10 - Image { - width: 200; height: 200 - fillMode: Image.Stretch - source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_3.jpg" - clip: true - id: preview3 - MouseArea { - anchors.fill: parent - onClicked: { - sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/3.jpg'}); - } - } - } - Image { - width: 200; height: 200 - fillMode: Image.Stretch - source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_4.jpg" - clip: true - id: preview4 - MouseArea { - anchors.fill: parent - onClicked: { - sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/4.jpg'}); - } - } - } - } - RowLayout { - id: row3 - anchors.top: row2.bottom - anchors.topMargin: 10 - anchors.left: parent.left - Layout.fillWidth: true - anchors.leftMargin: 30 - spacing: 10 - Image { - width: 200; height: 200 - fillMode: Image.Stretch - source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_5.jpg" - clip: true - id: preview5 - MouseArea { - anchors.fill: parent - onClicked: { - sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/5.png'}); - } - } - } - Image { - width: 200; height: 200 - fillMode: Image.Stretch - source: "http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/thumbnails/thumb_6.jpg" - clip: true - id: preview6 - MouseArea { - anchors.fill: parent - onClicked: { - sendToScript({method: 'changeSkybox', url: 'http://mpassets.highfidelity.com/05904016-8f7d-4dfc-88e1-2bf9ba3fac20-v1/skyboxes/6.jpg'}); - } - } + ScrollBar.vertical: ScrollBar { + parent: gridView.parent + anchors.top: gridView.top + anchors.left: gridView.right + anchors.bottom: gridView.bottom + anchors.leftMargin: 10 + width: 19 } } signal sendToScript(var message); - -} +} \ No newline at end of file diff --git a/interface/resources/qml/hifi/audio/PlaySampleSound.qml b/interface/resources/qml/hifi/audio/PlaySampleSound.qml index fdf579420d..dec2e9bfc9 100644 --- a/interface/resources/qml/hifi/audio/PlaySampleSound.qml +++ b/interface/resources/qml/hifi/audio/PlaySampleSound.qml @@ -22,8 +22,7 @@ RowLayout { property var sample: null; property bool isPlaying: false; function createSampleSound() { - var SOUND = Qt.resolvedUrl("../../../sounds/sample.wav"); - sound = SoundCache.getSound(SOUND); + sound = ApplicationInterface.getSampleSound(); sample = null; } function playSound() { diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 177dfed420..8ea9ce494c 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -39,7 +39,8 @@ Rectangle { property bool itemIsJson: true; property bool shouldBuyWithControlledFailure: false; property bool debugCheckoutSuccess: false; - property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified; + property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified(); + property bool isWearable; // Style color: hifi.colors.white; Hifi.QmlCommerce { @@ -80,6 +81,7 @@ Rectangle { root.activeView = "checkoutFailure"; } else { root.itemHref = result.data.download_url; + root.isWearable = result.data.categories.indexOf("Wearables") > -1; root.activeView = "checkoutSuccess"; } } @@ -592,7 +594,7 @@ Rectangle { height: 50; anchors.left: parent.left; anchors.right: parent.right; - text: "Rez It" + text: root.isWearable ? "Wear It" : "Rez It" onClicked: { if (urlHandler.canHandleUrl(root.itemHref)) { urlHandler.handleUrl(root.itemHref); @@ -603,7 +605,7 @@ Rectangle { } RalewaySemiBold { id: noPermissionText; - visible: !root.canRezCertifiedItems; + visible: !root.canRezCertifiedItems && !root.isWearable; text: 'You do not have Certified Rez permissions in this domain.' // Text size size: 16; diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index e7e16668fe..fb42865ba4 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -39,6 +39,7 @@ Item { property int itemEdition; property int numberSold; property int limitedRun; + property bool isWearable; property string originalStatusText; property string originalStatusColor; @@ -342,7 +343,7 @@ Item { anchors.bottom: parent.bottom; anchors.right: parent.right; width: height; - enabled: root.canRezCertifiedItems && root.purchaseStatus !== "invalidated"; + enabled: (root.canRezCertifiedItems || root.isWearable) && root.purchaseStatus !== "invalidated"; onClicked: { if (urlHandler.canHandleUrl(root.itemHref)) { @@ -415,7 +416,7 @@ Item { size: 16; verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter - text: "Rez It" + text: root.isWearable ? "Wear It" : "Rez It" } } } diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index d75fd6604b..f292f9603e 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -32,7 +32,7 @@ Rectangle { property bool securityImageResultReceived: false; property bool purchasesReceived: false; property bool punctuationMode: false; - property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified; + property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified(); property bool pendingInventoryReply: true; property bool isShowingMyItems: false; property bool isDebuggingFirstUseTutorial: false; @@ -434,6 +434,7 @@ Rectangle { numberSold: model.number_sold; limitedRun: model.limited_run; displayedItemCount: model.displayedItemCount; + isWearable: model.categories.indexOf("Wearables") > -1; anchors.topMargin: 12; anchors.bottomMargin: 12; @@ -582,9 +583,11 @@ Rectangle { Timer { id: inventoryTimer; - interval: 90000; + interval: 4000; // Change this back to 90000 after demo + //interval: 90000; onTriggered: { if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) { + console.log("Refreshing Purchases..."); root.pendingInventoryReply = true; commerce.inventory(); } @@ -660,6 +663,8 @@ Rectangle { currentPurchasesModelStatus !== previousPurchasesModelStatus) { purchasesModel.setProperty(i, "statusChanged", true); + } else { + purchasesModel.setProperty(i, "statusChanged", false); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index 2243143906..d967a36b68 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -27,6 +27,7 @@ Item { id: root; z: 997; property bool keyboardRaised: false; + property bool isPasswordField: false; property string titleBarIcon: ""; property string titleBarText: ""; @@ -202,6 +203,7 @@ Item { onFocusChanged: { root.keyboardRaised = focus; + root.isPasswordField = (focus && passphraseField.echoMode === TextInput.Password); } MouseArea { @@ -209,6 +211,7 @@ Item { onClicked: { root.keyboardRaised = true; + root.isPasswordField = (passphraseField.echoMode === TextInput.Password); mouse.accepted = false; } } @@ -382,6 +385,7 @@ Item { id: keyboard; raised: HMD.mounted && root.keyboardRaised; numeric: parent.punctuationMode; + password: root.isPasswordField; anchors { bottom: parent.bottom; left: parent.left; diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 7c0cecd98d..ffeedde8f0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -80,16 +80,18 @@ Item { onFocusChanged: { if (focus) { - sendSignalToWallet({method: 'walletSetup_raiseKeyboard'}); + var hidePassword = (currentPassphraseField.echoMode === TextInput.Password); + sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); } else if (!passphraseFieldAgain.focus) { - sendSignalToWallet({method: 'walletSetup_lowerKeyboard'}); + sendSignalToWallet({method: 'walletSetup_lowerKeyboard', isPasswordField: false}); } } MouseArea { anchors.fill: parent; onPressed: { - sendSignalToWallet({method: 'walletSetup_raiseKeyboard'}); + var hidePassword = (currentPassphraseField.echoMode === TextInput.Password); + sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); mouse.accepted = false; } } @@ -116,16 +118,18 @@ Item { MouseArea { anchors.fill: parent; onPressed: { - sendSignalToWallet({method: 'walletSetup_raiseKeyboard'}); + var hidePassword = (passphraseField.echoMode === TextInput.Password); + sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); mouse.accepted = false; } } onFocusChanged: { if (focus) { - sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'}); + var hidePassword = (passphraseField.echoMode === TextInput.Password); + sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); } else if (!passphraseFieldAgain.focus) { - sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'}); + sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false}); } } @@ -150,16 +154,18 @@ Item { MouseArea { anchors.fill: parent; onPressed: { - sendSignalToWallet({method: 'walletSetup_raiseKeyboard'}); + var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password); + sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); mouse.accepted = false; } } onFocusChanged: { if (focus) { - sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'}); + var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password); + sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); } else if (!passphraseField.focus) { - sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'}); + sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false}); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 472dd50b7d..759d7a37eb 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -29,6 +29,7 @@ Rectangle { property string activeView: "initialize"; property bool keyboardRaised: false; + property bool isPassword: false; Image { anchors.fill: parent; @@ -181,8 +182,10 @@ Rectangle { } } else if (msg.method === 'walletSetup_raiseKeyboard') { root.keyboardRaised = true; + root.isPassword = msg.isPasswordField; } else if (msg.method === 'walletSetup_lowerKeyboard') { root.keyboardRaised = false; + root.isPassword = msg.isPasswordField; } else { sendToScript(msg); } @@ -202,6 +205,7 @@ Rectangle { 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') { @@ -685,6 +689,7 @@ Rectangle { id: keyboard; raised: HMD.mounted && root.keyboardRaised; numeric: parent.punctuationMode; + password: root.isPassword; anchors { bottom: parent.bottom; left: parent.left; diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 280d49ceed..1fe0dcc58b 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -43,6 +43,7 @@ Item { calculatePendingAndInvalidated(); } + refreshTimer.start(); } } @@ -117,6 +118,8 @@ Item { historyReceived = false; commerce.balance(); commerce.history(); + } else { + refreshTimer.stop(); } } } @@ -138,6 +141,17 @@ Item { } } + Timer { + id: refreshTimer; + interval: 4000; // Remove this after demo? + onTriggered: { + console.log("Refreshing Wallet Home..."); + historyReceived = false; + commerce.balance(); + commerce.history(); + } + } + // Recent Activity Rectangle { id: recentActivityContainer; diff --git a/interface/resources/sounds/sample.wav b/interface/resources/sounds/sample.wav index d461ab9186..9c9289bb51 100644 Binary files a/interface/resources/sounds/sample.wav and b/interface/resources/sounds/sample.wav differ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0b99ce5004..f2bb52ea47 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -120,6 +120,7 @@ #include #include #include +#include #include #include #include @@ -691,7 +692,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -759,7 +759,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _notifiedPacketVersionMismatchThisDomain(false), _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0), - _snapshotSound(nullptr) + _snapshotSound(nullptr), + _sampleSound(nullptr) + { auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); @@ -804,7 +806,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo installNativeEventFilter(&MyNativeEventFilter::getInstance()); #endif - _logger = new FileLogger(this); qInstallMessageHandler(messageHandler); @@ -981,6 +982,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(myAvatar.get(), &MyAvatar::positionGoneTo, DependencyManager::get().data(), &AddressManager::storeCurrentAddress); + // Inititalize sample before registering + QFileInfo infSample = QFileInfo(PathUtils::resourcesPath() + "sounds/sample.wav"); + _sampleSound = DependencyManager::get()->getSound(QUrl::fromLocalFile(infSample.absoluteFilePath())); + auto scriptEngines = DependencyManager::get().data(); scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){ registerScriptEngineWithApplicationServices(engine); @@ -1182,7 +1187,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // allow you to move an entity around in your hand _entityEditSender.setPacketsPerSecond(3000); // super high!! + // Overlays need to exist before we set the ContextOverlayInterface dependency _overlays.init(); // do this before scripts load + DependencyManager::set(); + // Make sure we don't time out during slow operations at startup updateHeartbeat(); @@ -1472,53 +1480,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - // If the user clicks somewhere where there is NO entity at all, we will release focus - connect(getEntities().data(), &EntityTreeRenderer::mousePressOffEntity, [=]() { - setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); - }); - // Keyboard focus handling for Web overlays. auto overlays = &(qApp->getOverlays()); - - connect(overlays, &Overlays::mousePressOnOverlay, [=](const OverlayID& overlayID, const PointerEvent& event) { - auto thisOverlay = std::dynamic_pointer_cast(overlays->getOverlay(overlayID)); - // Only Web overlays can have keyboard focus. - if (thisOverlay) { - setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); - setKeyboardFocusOverlay(overlayID); - } - }); - connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) { if (overlayID == _keyboardFocusedOverlay.get()) { setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); } }); - connect(overlays, &Overlays::mousePressOffOverlay, [=]() { - setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); - }); - connect(this, &Application::aboutToQuit, [=]() { setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); }); - connect(overlays, - SIGNAL(mousePressOnOverlay(const OverlayID&, const PointerEvent&)), - DependencyManager::get().data(), - SLOT(contextOverlays_mousePressOnOverlay(const OverlayID&, const PointerEvent&))); - - connect(overlays, - SIGNAL(hoverEnterOverlay(const OverlayID&, const PointerEvent&)), - DependencyManager::get().data(), - SLOT(contextOverlays_hoverEnterOverlay(const OverlayID&, const PointerEvent&))); - - connect(overlays, - SIGNAL(hoverLeaveOverlay(const OverlayID&, const PointerEvent&)), - DependencyManager::get().data(), - SLOT(contextOverlays_hoverLeaveOverlay(const OverlayID&, const PointerEvent&))); - // Add periodic checks to send user activity data static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000; static int NEARBY_AVATAR_RADIUS_METERS = 10; @@ -1787,9 +1761,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return entityServerNode && !isPhysicsEnabled(); }); - QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); - _snapshotSound = DependencyManager::get()->getSound(QUrl::fromLocalFile(inf.absoluteFilePath())); - + QFileInfo infSnap = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); + _snapshotSound = DependencyManager::get()->getSound(QUrl::fromLocalFile(infSnap.absoluteFilePath())); + QVariant testProperty = property(hifi::properties::TEST); qDebug() << testProperty; if (testProperty.isValid()) { @@ -4202,6 +4176,7 @@ void Application::initDisplay() { } void Application::init() { + // Make sure Login state is up to date DependencyManager::get()->toggleLoginDialog(); @@ -4228,6 +4203,10 @@ void Application::init() { // fire off an immediate domain-server check in now that settings are loaded DependencyManager::get()->sendDomainServerCheckIn(); + // This allows collision to be set up properly for shape entities supported by GeometryCache. + // This is before entity setup to ensure that it's ready for whenever instance collision is initialized. + ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator(&shapeInfoCalculator)); + getEntities()->init(); getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) { auto dims = item.getDimensions(); @@ -4550,14 +4529,9 @@ QUuid Application::getKeyboardFocusEntity() const { return _keyboardFocusedEntity.get(); } -void Application::setKeyboardFocusEntity(QUuid id) { - EntityItemID entityItemID(id); - setKeyboardFocusEntity(entityItemID); -} - static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f; -void Application::setKeyboardFocusEntity(EntityItemID entityItemID) { +void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) { if (_keyboardFocusedEntity.get() != entityItemID) { _keyboardFocusedEntity.set(entityItemID); @@ -4594,7 +4568,7 @@ OverlayID Application::getKeyboardFocusOverlay() { return _keyboardFocusedOverlay.get(); } -void Application::setKeyboardFocusOverlay(OverlayID overlayID) { +void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) { if (overlayID != _keyboardFocusedOverlay.get()) { _keyboardFocusedOverlay.set(overlayID); @@ -5090,6 +5064,7 @@ void Application::update(float deltaTime) { } this->updateCamera(appRenderArgs._renderArgs); + appRenderArgs._eyeToWorld = _myCamera.getTransform(); appRenderArgs._isStereo = false; { @@ -6805,6 +6780,10 @@ void Application::loadScriptURLDialog() const { }); } +SharedSoundPointer Application::getSampleSound() const { + return _sampleSound; +} + void Application::loadLODToolsDialog() { auto tabletScriptingInterface = DependencyManager::get(); auto tablet = dynamic_cast(tabletScriptingInterface->getTablet(SYSTEM_TABLET)); @@ -7427,51 +7406,6 @@ bool Application::isForeground() const { return _isForeground && !_window->isMinimized(); } -void Application::sendMousePressOnEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->mousePressOnEntity(entityItemID, event); -} - -void Application::sendMouseMoveOnEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->mouseMoveOnEntity(entityItemID, event); -} - -void Application::sendMouseReleaseOnEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->mouseReleaseOnEntity(entityItemID, event); -} - -void Application::sendClickDownOnEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->clickDownOnEntity(entityItemID, event); -} - -void Application::sendHoldingClickOnEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->holdingClickOnEntity(entityItemID, event); -} - -void Application::sendClickReleaseOnEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->clickReleaseOnEntity(entityItemID, event); -} - -void Application::sendHoverEnterEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->hoverEnterEntity(entityItemID, event); -} - -void Application::sendHoverOverEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->hoverOverEntity(entityItemID, event); -} - -void Application::sendHoverLeaveEntity(QUuid id, PointerEvent event) { - EntityItemID entityItemID(id); - emit getEntities()->hoverLeaveEntity(entityItemID, event); -} - // FIXME? perhaps two, one for the main thread and one for the offscreen UI rendering thread? static const int UI_RESERVED_THREADS = 1; // Windows won't let you have all the cores diff --git a/interface/src/Application.h b/interface/src/Application.h index b6c09bbd87..ab7acc8166 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -277,18 +277,6 @@ public: gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; } gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; } - Q_INVOKABLE void sendMousePressOnEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendMouseMoveOnEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendMouseReleaseOnEntity(QUuid id, PointerEvent event); - - Q_INVOKABLE void sendClickDownOnEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendHoldingClickOnEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendClickReleaseOnEntity(QUuid id, PointerEvent event); - - Q_INVOKABLE void sendHoverEnterEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendHoverOverEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendHoverLeaveEntity(QUuid id, PointerEvent event); - OverlayID getTabletScreenID() const; OverlayID getTabletHomeButtonID() const; QUuid getTabletFrameID() const; // may be an entity or an overlay @@ -326,6 +314,7 @@ public slots: void toggleEntityScriptServerLogDialog(); Q_INVOKABLE void showAssetServerWidget(QString filePath = ""); Q_INVOKABLE void loadAddAvatarBookmarkDialog() const; + Q_INVOKABLE SharedSoundPointer getSampleSound() const; void showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const; @@ -388,11 +377,10 @@ public slots: void setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions); QUuid getKeyboardFocusEntity() const; // thread-safe - void setKeyboardFocusEntity(QUuid id); - void setKeyboardFocusEntity(EntityItemID entityItemID); + void setKeyboardFocusEntity(const EntityItemID& entityItemID); OverlayID getKeyboardFocusOverlay(); - void setKeyboardFocusOverlay(OverlayID overlayID); + void setKeyboardFocusOverlay(const OverlayID& overlayID); void addAssetToWorldMessageClose(); @@ -702,6 +690,7 @@ private: FileScriptingInterface* _fileDownload; AudioInjectorPointer _snapshotSoundInjector; SharedSoundPointer _snapshotSound; + SharedSoundPointer _sampleSound; DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin; QString _autoSwitchDisplayModeSupportedHMDPluginName; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 7822b78244..aad7768b99 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "InterfaceLogging.h" #include "world.h" @@ -393,4 +395,20 @@ void runUnitTests() { } } +void shapeInfoCalculator(const ShapeEntityItem * const shapeEntity, ShapeInfo &shapeInfo) { + + if (shapeEntity == nullptr) { + + //--EARLY EXIT-- + return; + } + + ShapeInfo::PointCollection pointCollection; + ShapeInfo::PointList points; + pointCollection.push_back(points); + + GeometryCache::computeSimpleHullPointListForShape((int)shapeEntity->getShape(), shapeEntity->getDimensions(), pointCollection.back()); + shapeInfo.setPointCollection(pointCollection); +} + diff --git a/interface/src/Util.h b/interface/src/Util.h index 48acb53936..976a26ce82 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -18,6 +18,9 @@ #include #include +class ShapeEntityItem; +class ShapeInfo; + void renderWorldBox(RenderArgs* args, gpu::Batch& batch); void runTimingTests(); @@ -28,4 +31,6 @@ bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNorma bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadius); +void shapeInfoCalculator(const ShapeEntityItem * const shapeEntity, ShapeInfo &shapeInfo); + #endif // hifi_Util_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5d82405aee..3189ad3c77 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -587,14 +587,16 @@ void MyAvatar::simulate(float deltaTime) { MovingEntitiesOperator moveOperator; forEachDescendant([&](SpatiallyNestablePointer object) { // if the queryBox has changed, tell the entity-server - if (object->getNestableType() == NestableType::Entity && object->checkAndMaybeUpdateQueryAACube()) { + if (object->getNestableType() == NestableType::Entity && object->updateQueryAACube()) { EntityItemPointer entity = std::static_pointer_cast(object); bool success; AACube newCube = entity->getQueryAACube(success); if (success) { moveOperator.addEntityToMoveList(entity, newCube); } - if (packetSender) { + // send an edit packet to update the entity-server about the queryAABox. If it's an + // avatar-entity, don't. + if (packetSender && !entity->getClientOnly()) { EntityItemProperties properties = entity->getProperties(); properties.setQueryAACubeDirty(); properties.setLastEdited(now); diff --git a/interface/src/ui/overlays/Billboardable.cpp b/interface/src/ui/overlays/Billboardable.cpp index 34a4ef6df5..5e912864fc 100644 --- a/interface/src/ui/overlays/Billboardable.cpp +++ b/interface/src/ui/overlays/Billboardable.cpp @@ -3,6 +3,7 @@ // interface/src/ui/overlays // // Created by Zander Otavka on 8/7/15. +// Modified by Daniela Fontes on 24/10/17. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -13,6 +14,7 @@ #include #include +#include "avatar/AvatarManager.h" void Billboardable::setProperties(const QVariantMap& properties) { auto isFacingAvatar = properties["isFacingAvatar"]; @@ -32,10 +34,11 @@ bool Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offse if (isFacingAvatar()) { glm::vec3 billboardPos = transform.getTranslation(); glm::vec3 cameraPos = qApp->getCamera().getPosition(); - glm::vec3 look = cameraPos - billboardPos; - float elevation = -asinf(look.y / glm::length(look)); - float azimuth = atan2f(look.x, look.z); - glm::quat rotation(glm::vec3(elevation, azimuth, 0)); + // use the referencial from the avatar, y isn't always up + glm::vec3 avatarUP = DependencyManager::get()->getMyAvatar()->getOrientation()*Vectors::UP; + + glm::quat rotation(conjugate(toQuat(glm::lookAt(cameraPos, billboardPos, avatarUP)))); + transform.setRotation(rotation); transform.postRotate(offsetRotation); return true; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 3a3026d5ae..a5db45cf43 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -34,13 +34,6 @@ ContextOverlayInterface::ContextOverlayInterface() { _tabletScriptingInterface = DependencyManager::get(); _selectionScriptingInterface = DependencyManager::get(); - _selectionToSceneHandlers[0].initialize("contextOverlayHighlightList"); - connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged); - for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT ; i++) { - _selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList")+QString::number(i)); - connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged); - } - _entityPropertyFlags += PROP_POSITION; _entityPropertyFlags += PROP_ROTATION; _entityPropertyFlags += PROP_MARKETPLACE_ID; @@ -48,10 +41,10 @@ ContextOverlayInterface::ContextOverlayInterface() { _entityPropertyFlags += PROP_REGISTRATION_POINT; _entityPropertyFlags += PROP_CERTIFICATE_ID; - auto entityTreeRenderer = DependencyManager::get().data(); - connect(entityTreeRenderer, SIGNAL(mousePressOnEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(createOrDestroyContextOverlay(const EntityItemID&, const PointerEvent&))); - connect(entityTreeRenderer, SIGNAL(hoverEnterEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverEnterEntity(const EntityItemID&, const PointerEvent&))); - connect(entityTreeRenderer, SIGNAL(hoverLeaveEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverLeaveEntity(const EntityItemID&, const PointerEvent&))); + auto entityScriptingInterface = DependencyManager::get().data(); + connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::createOrDestroyContextOverlay); + connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, &ContextOverlayInterface::contextOverlays_hoverEnterEntity); + connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &ContextOverlayInterface::contextOverlays_hoverLeaveEntity); connect(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"), &TabletProxy::tabletShownChanged, this, [&]() { if (_contextOverlayJustClicked && _hmdScriptingInterface->isMounted()) { QUuid tabletFrameID = _hmdScriptingInterface->getCurrentTabletFrameID(); @@ -64,8 +57,17 @@ ContextOverlayInterface::ContextOverlayInterface() { _contextOverlayJustClicked = false; } }); - auto entityScriptingInterface = DependencyManager::get().data(); connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity); + connect(&qApp->getOverlays(), &Overlays::mousePressOnOverlay, this, &ContextOverlayInterface::contextOverlays_mousePressOnOverlay); + connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay); + connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay); + + _selectionToSceneHandlers[0].initialize("contextOverlayHighlightList"); + connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged); + for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT; i++) { + _selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList") + QString::number(i)); + connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged); + } } static const uint32_t MOUSE_HW_ID = 0; @@ -143,8 +145,8 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& if (event.getID() == LEFT_HAND_HW_ID) { offsetAngle *= -1.0f; } - contextOverlayPosition = (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) * - ((cameraPosition + direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE))); + contextOverlayPosition = cameraPosition + + (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) * (direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE)); contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition); } diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 69f52c5f2e..bdb35d4f49 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -96,6 +96,7 @@ void Line3DOverlay::setEnd(const glm::vec3& end) { } else { _direction = glm::vec3(0.0f); } + notifyRenderTransformChange(); } void Line3DOverlay::setLocalEnd(const glm::vec3& localEnd) { diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 5e5b9367a6..fd5aae4027 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -717,39 +717,34 @@ bool Overlays::isAddedOverlay(OverlayID id) { } void Overlays::sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) { - QMetaObject::invokeMethod(this, "mousePressOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event)); + mousePressEvent(overlayID, event); } void Overlays::sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event) { - QMetaObject::invokeMethod(this, "mouseReleaseOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event)); + mouseReleaseEvent(overlayID, event); } void Overlays::sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event) { - QMetaObject::invokeMethod(this, "mouseMoveOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event)); + mouseMoveEvent(overlayID, event); } -void Overlays::sendHoverEnterOverlay(const OverlayID& id, const PointerEvent& event) { - QMetaObject::invokeMethod(this, "hoverEnterOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event)); +void Overlays::sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event) { + emit hoverEnterOverlay(overlayID, event); } -void Overlays::sendHoverOverOverlay(const OverlayID& id, const PointerEvent& event) { - QMetaObject::invokeMethod(this, "hoverOverOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event)); +void Overlays::sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event) { + emit hoverOverOverlay(overlayID, event); } -void Overlays::sendHoverLeaveOverlay(const OverlayID& id, const PointerEvent& event) { - QMetaObject::invokeMethod(this, "hoverLeaveOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event)); +void Overlays::sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event) { + hoverLeaveEvent(overlayID, event); } OverlayID Overlays::getKeyboardFocusOverlay() { return qApp->getKeyboardFocusOverlay(); } -void Overlays::setKeyboardFocusOverlay(OverlayID id) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setKeyboardFocusOverlay", Q_ARG(OverlayID, id)); - return; - } - +void Overlays::setKeyboardFocusOverlay(const OverlayID& id) { qApp->setKeyboardFocusOverlay(id); } @@ -884,13 +879,35 @@ bool Overlays::mousePressEvent(QMouseEvent* event) { _currentClickingOnOverlayID = rayPickResult.overlayID; PointerEvent pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press); - emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent); + mousePressEvent(_currentClickingOnOverlayID, pointerEvent); return true; } + // if we didn't press on an overlay, disable overlay keyboard focus + setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); + // emit to scripts emit mousePressOffOverlay(); return false; } +void Overlays::mousePressEvent(const OverlayID& overlayID, const PointerEvent& event) { + // TODO: generalize this to allow any overlay to recieve events + std::shared_ptr thisOverlay; + if (getOverlayType(overlayID) == "web3d") { + thisOverlay = std::static_pointer_cast(getOverlay(overlayID)); + } + if (thisOverlay) { + // Focus keyboard on web overlays + DependencyManager::get()->setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); + setKeyboardFocusOverlay(overlayID); + + // Send to web overlay + QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event)); + } + + // emit to scripts + emit mousePressOnOverlay(overlayID, event); +} + bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent"); @@ -900,13 +917,30 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { _currentClickingOnOverlayID = rayPickResult.overlayID; auto pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press); + // emit to scripts emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent); return true; } + // emit to scripts emit mouseDoublePressOffOverlay(); return false; } +void Overlays::hoverLeaveEvent(const OverlayID& overlayID, const PointerEvent& event) { + // TODO: generalize this to allow any overlay to recieve events + std::shared_ptr thisOverlay; + if (getOverlayType(overlayID) == "web3d") { + thisOverlay = std::static_pointer_cast(getOverlay(overlayID)); + } + if (thisOverlay) { + // Send to web overlay + QMetaObject::invokeMethod(thisOverlay.get(), "hoverLeaveOverlay", Q_ARG(PointerEvent, event)); + } + + // emit to scripts + emit hoverLeaveOverlay(overlayID, event); +} + bool Overlays::mouseReleaseEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseReleaseEvent"); @@ -914,13 +948,28 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) { RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); if (rayPickResult.intersects) { auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release); - emit mouseReleaseOnOverlay(rayPickResult.overlayID, pointerEvent); + mouseReleaseEvent(rayPickResult.overlayID, pointerEvent); } _currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID; return false; } +void Overlays::mouseReleaseEvent(const OverlayID& overlayID, const PointerEvent& event) { + // TODO: generalize this to allow any overlay to recieve events + std::shared_ptr thisOverlay; + if (getOverlayType(overlayID) == "web3d") { + thisOverlay = std::static_pointer_cast(getOverlay(overlayID)); + } + if (thisOverlay) { + // Send to web overlay + QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event)); + } + + // emit to scripts + emit mouseReleaseOnOverlay(overlayID, event); +} + bool Overlays::mouseMoveEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseMoveEvent"); @@ -928,12 +977,12 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); if (rayPickResult.intersects) { auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move); - emit mouseMoveOnOverlay(rayPickResult.overlayID, pointerEvent); + mouseMoveEvent(rayPickResult.overlayID, pointerEvent); // If previously hovering over a different overlay then leave hover on that overlay. if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID && rayPickResult.overlayID != _currentHoverOverOverlayID) { auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move); - emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent); + hoverLeaveEvent(_currentHoverOverOverlayID, pointerEvent); } // If hovering over a new overlay then enter hover on that overlay. @@ -949,7 +998,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { // If previously hovering an overlay then leave hover. if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID) { auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move); - emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent); + hoverLeaveEvent(_currentHoverOverOverlayID, pointerEvent); _currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID; } @@ -957,6 +1006,21 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { return false; } +void Overlays::mouseMoveEvent(const OverlayID& overlayID, const PointerEvent& event) { + // TODO: generalize this to allow any overlay to recieve events + std::shared_ptr thisOverlay; + if (getOverlayType(overlayID) == "web3d") { + thisOverlay = std::static_pointer_cast(getOverlay(overlayID)); + } + if (thisOverlay) { + // Send to web overlay + QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event)); + } + + // emit to scripts + emit mouseMoveOnOverlay(overlayID, event); +} + QVector Overlays::findOverlays(const glm::vec3& center, float radius) { QVector result; //if (QThread::currentThread() != thread()) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 732a437eae..988b288741 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -107,6 +107,11 @@ public: bool mouseReleaseEvent(QMouseEvent* event); bool mouseMoveEvent(QMouseEvent* event); + void mousePressEvent(const OverlayID& overlayID, const PointerEvent& event); + void mouseMoveEvent(const OverlayID& overlayID, const PointerEvent& event); + void mouseReleaseEvent(const OverlayID& overlayID, const PointerEvent& event); + void hoverLeaveEvent(const OverlayID& overlayID, const PointerEvent& event); + void cleanupAllOverlays(); public slots: @@ -298,12 +303,12 @@ public slots: void sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event); void sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event); - void sendHoverEnterOverlay(const OverlayID& id, const PointerEvent& event); - void sendHoverOverOverlay(const OverlayID& id, const PointerEvent& event); - void sendHoverLeaveOverlay(const OverlayID& id, const PointerEvent& event); + void sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event); + void sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event); + void sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event); OverlayID getKeyboardFocusOverlay(); - void setKeyboardFocusOverlay(OverlayID id); + void setKeyboardFocusOverlay(const OverlayID& id); signals: /**jsdoc diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 363c85b395..0c75803d35 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -125,11 +125,7 @@ void Web3DOverlay::destroyWebSurface() { } _webSurface->pause(); - auto overlays = &(qApp->getOverlays()); - QObject::disconnect(overlays, &Overlays::mousePressOnOverlay, this, nullptr); - QObject::disconnect(overlays, &Overlays::mouseReleaseOnOverlay, this, nullptr); - QObject::disconnect(overlays, &Overlays::mouseMoveOnOverlay, this, nullptr); - QObject::disconnect(overlays, &Overlays::hoverLeaveOverlay, this, nullptr); + QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent); QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived); DependencyManager::get()->release(QML, _webSurface); @@ -160,35 +156,17 @@ void Web3DOverlay::buildWebSurface() { _webSurface->resume(); }); - auto selfOverlayID = getOverlayID(); - std::weak_ptr weakSelf = std::dynamic_pointer_cast(qApp->getOverlays().getOverlay(selfOverlayID)); - auto forwardPointerEvent = [=](OverlayID overlayID, const PointerEvent& event) { - auto self = weakSelf.lock(); - if (self && overlayID == selfOverlayID) { - self->handlePointerEvent(event); - } - }; - - auto overlays = &(qApp->getOverlays()); - QObject::connect(overlays, &Overlays::mousePressOnOverlay, this, forwardPointerEvent); - QObject::connect(overlays, &Overlays::mouseReleaseOnOverlay, this, forwardPointerEvent); - QObject::connect(overlays, &Overlays::mouseMoveOnOverlay, this, forwardPointerEvent); - QObject::connect(overlays, &Overlays::hoverLeaveOverlay, this, [=](OverlayID overlayID, const PointerEvent& event) { - auto self = weakSelf.lock(); - if (!self) { - return; - } - if (overlayID == selfOverlayID && (self->_pressed || (!self->_activeTouchPoints.empty() && self->_touchBeginAccepted))) { - PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), - event.getButton(), event.getButtons(), event.getKeyboardModifiers()); - forwardPointerEvent(overlayID, endEvent); - } - }); - QObject::connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent); QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived); } +void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) { + if ((_pressed || (!_activeTouchPoints.empty() && _touchBeginAccepted))) { + PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), + event.getButton(), event.getButtons(), event.getKeyboardModifiers()); + handlePointerEvent(endEvent); + } +} void Web3DOverlay::update(float deltatime) { if (_webSurface) { diff --git a/interface/src/ui/overlays/Web3DOverlay.h b/interface/src/ui/overlays/Web3DOverlay.h index de74b95b3e..c7f338f0e6 100644 --- a/interface/src/ui/overlays/Web3DOverlay.h +++ b/interface/src/ui/overlays/Web3DOverlay.h @@ -39,7 +39,8 @@ public: QObject* getEventHandler(); void setProxyWindow(QWindow* proxyWindow); - void handlePointerEvent(const PointerEvent& event); + Q_INVOKABLE void hoverLeaveOverlay(const PointerEvent& event); + Q_INVOKABLE void handlePointerEvent(const PointerEvent& event); void handlePointerEventAsTouch(const PointerEvent& event); void handlePointerEventAsMouse(const PointerEvent& event); diff --git a/libraries/audio/src/SoundCache.h b/libraries/audio/src/SoundCache.h index 97d5f659d8..bc4ddf303f 100644 --- a/libraries/audio/src/SoundCache.h +++ b/libraries/audio/src/SoundCache.h @@ -23,7 +23,6 @@ class SoundCache : public ResourceCache, public Dependency { public: Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); - protected: virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; diff --git a/libraries/baking/src/JSBaker.cpp b/libraries/baking/src/JSBaker.cpp index 75811bea49..a97a7fe5b3 100644 --- a/libraries/baking/src/JSBaker.cpp +++ b/libraries/baking/src/JSBaker.cpp @@ -72,7 +72,7 @@ void JSBaker::bake() { bool JSBaker::bakeJS(const QByteArray& inputFile, QByteArray& outputFile) { // Read from inputFile and write to outputFile per character QTextStream in(inputFile, QIODevice::ReadOnly); - QTextStream out(outputFile, QIODevice::WriteOnly); + QTextStream out(&outputFile, QIODevice::WriteOnly); // Algorithm requires the knowledge of previous and next character for each character read QChar currentCharacter; diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp index 2f57cc29d0..7b639e8308 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp @@ -234,7 +234,8 @@ void CompositorHelper::handleLeaveEvent() { bool CompositorHelper::handleRealMouseMoveEvent(bool sendFakeEvent) { // If the mouse move came from a capture mouse related move, we completely ignore it. - if (_ignoreMouseMove) { + // Note: if not going to synthesize event - do not touch _ignoreMouseMove flag + if (_ignoreMouseMove && sendFakeEvent) { _ignoreMouseMove = false; return true; // swallow the event } @@ -246,7 +247,12 @@ bool CompositorHelper::handleRealMouseMoveEvent(bool sendFakeEvent) { auto changeInRealMouse = newPosition - _lastKnownRealMouse; auto newReticlePosition = _reticlePositionInHMD + toGlm(changeInRealMouse); setReticlePosition(newReticlePosition, sendFakeEvent); - _ignoreMouseMove = true; + + // Note: if not going to synthesize event - do not touch _ignoreMouseMove flag + if (sendFakeEvent) { + _ignoreMouseMove = true; + } + QCursor::setPos(QPoint(_lastKnownRealMouse.x(), _lastKnownRealMouse.y())); // move cursor back to where it was return true; // swallow the event } else { diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 88aa56cccf..0993daaa8b 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -418,6 +418,19 @@ void OpenGLDisplayPlugin::customizeContext() { _hudPipeline = gpu::Pipeline::create(program, state); } + { + auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); + auto ps = gpu::StandardShaderLib::getDrawTextureMirroredXPS(); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + gpu::Shader::makeProgram(*program); + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(gpu::State::DepthTest(false)); + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _mirrorHUDPipeline = gpu::Pipeline::create(program, state); + } + { auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); auto ps = gpu::StandardShaderLib::getDrawTexturePS(); @@ -438,6 +451,7 @@ void OpenGLDisplayPlugin::uncustomizeContext() { _presentPipeline.reset(); _cursorPipeline.reset(); _hudPipeline.reset(); + _mirrorHUDPipeline.reset(); _compositeFramebuffer.reset(); withPresentThreadLock([&] { _currentFrame.reset(); @@ -562,11 +576,11 @@ void OpenGLDisplayPlugin::updateFrameData() { }); } -std::function OpenGLDisplayPlugin::getHUDOperator() { - return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) { +std::function OpenGLDisplayPlugin::getHUDOperator() { + return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) { if (_hudPipeline) { batch.enableStereo(false); - batch.setPipeline(_hudPipeline); + batch.setPipeline(mirror ? _mirrorHUDPipeline : _hudPipeline); batch.setResourceTexture(0, hudTexture); if (isStereo()) { for_each_eye([&](Eye eye) { diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index ec775aed4c..d67c0b8663 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -95,7 +95,7 @@ protected: virtual QThread::Priority getPresentPriority() { return QThread::HighPriority; } virtual void compositeLayers(); virtual void compositeScene(); - virtual std::function getHUDOperator(); + virtual std::function getHUDOperator(); virtual void compositePointer(); virtual void compositeExtra() {}; @@ -140,6 +140,8 @@ protected: gpu::Frame* _lastFrame { nullptr }; gpu::FramebufferPointer _compositeFramebuffer; gpu::PipelinePointer _hudPipeline; + gpu::PipelinePointer _mirrorHUDPipeline; + gpu::ShaderPointer _mirrorHUDPS; gpu::PipelinePointer _simplePipeline; gpu::PipelinePointer _presentPipeline; gpu::PipelinePointer _cursorPipeline; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 0785226836..1d7fee38eb 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -419,9 +419,9 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() { } } -std::function HmdDisplayPlugin::HUDRenderer::render(HmdDisplayPlugin& plugin) { +std::function HmdDisplayPlugin::HUDRenderer::render(HmdDisplayPlugin& plugin) { updatePipeline(); - return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) { + return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) { if (pipeline) { batch.setPipeline(pipeline); @@ -436,7 +436,11 @@ std::function HmdDisplayPlugin::H batch.setUniformBuffer(uniformsLocation, uniformsBuffer); auto compositorHelper = DependencyManager::get(); - batch.setModelTransform(compositorHelper->getUiTransform()); + glm::mat4 modelTransform = compositorHelper->getUiTransform(); + if (mirror) { + modelTransform = glm::scale(modelTransform, glm::vec3(-1, 1, 1)); + } + batch.setModelTransform(modelTransform); batch.setResourceTexture(0, hudTexture); batch.drawIndexed(gpu::TRIANGLES, indexCount); @@ -468,7 +472,7 @@ void HmdDisplayPlugin::compositePointer() { }); } -std::function HmdDisplayPlugin::getHUDOperator() { +std::function HmdDisplayPlugin::getHUDOperator() { return _hudRenderer.render(*this); } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index a7a6d2938d..d2d30df093 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -53,7 +53,7 @@ protected: bool internalActivate() override; void internalDeactivate() override; - std::function getHUDOperator() override; + std::function getHUDOperator() override; void compositePointer() override; void internalPresent() override; void customizeContext() override; @@ -116,6 +116,6 @@ private: void build(); void updatePipeline(); - std::function render(HmdDisplayPlugin& plugin); + std::function render(HmdDisplayPlugin& plugin); } _hudRenderer; }; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4238eb4050..bf17f34749 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -35,6 +35,8 @@ #include "EntitiesRendererLogging.h" #include "RenderableEntityItem.h" +#include "RenderableWebEntityItem.h" + size_t std::hash::operator()(const EntityItemID& id) const { return qHash(id); } std::function EntityTreeRenderer::_entitiesShouldFadeFunction; @@ -55,6 +57,32 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf EntityRenderer::initEntityRenderers(); _currentHoverOverEntityID = UNKNOWN_ENTITY_ID; _currentClickingOnEntityID = UNKNOWN_ENTITY_ID; + + // Forward mouse events to web entities + auto handlePointerEvent = [&](const EntityItemID& entityID, const PointerEvent& event) { + std::shared_ptr thisEntity; + auto entity = getEntity(entityID); + if (entity && entity->getType() == EntityTypes::Web) { + thisEntity = std::static_pointer_cast(renderableForEntityId(entityID)); + } + if (thisEntity) { + QMetaObject::invokeMethod(thisEntity.get(), "handlePointerEvent", Q_ARG(PointerEvent, event)); + } + }; + auto entityScriptingInterface = DependencyManager::get(); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const EntityItemID& entityID, const PointerEvent& event) { + std::shared_ptr thisEntity; + auto entity = getEntity(entityID); + if (entity && entity->getType() == EntityTypes::Web) { + thisEntity = std::static_pointer_cast(renderableForEntityId(entityID)); + } + if (thisEntity) { + QMetaObject::invokeMethod(thisEntity.get(), "hoverLeaveEntity", Q_ARG(PointerEvent, event)); + } + }); } EntityTreeRenderer::~EntityTreeRenderer() { @@ -78,13 +106,49 @@ render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& i int EntityTreeRenderer::_entitiesScriptEngineCount = 0; void EntityTreeRenderer::resetEntitiesScriptEngine() { - auto oldEngine = _entitiesScriptEngine; _entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); _scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine); _entitiesScriptEngine->runInThread(); auto entitiesScriptEngineProvider = qSharedPointerCast(_entitiesScriptEngine); - DependencyManager::get()->setEntitiesScriptEngine(entitiesScriptEngineProvider); + auto entityScriptingInterface = DependencyManager::get(); + entityScriptingInterface->setEntitiesScriptEngine(entitiesScriptEngineProvider); + + // Connect mouse events to entity script callbacks + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "mousePressOnEntity", event); + }); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseDoublePressOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseDoublePressOnEntity", event); + }); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseMoveOnEntity", event); + // FIXME: this is a duplicate of mouseMoveOnEntity, but it seems like some scripts might use this naming + _entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseMoveEvent", event); + }); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "mouseReleaseOnEntity", event); + }); + + connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "clickDownOnEntity", event); + }); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::holdingClickOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "holdingClickOnEntity", event); + }); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickReleaseOnEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "clickReleaseOnEntity", event); + }); + + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverEnterEntity", event); + }); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverOverEntity", event); + }); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverLeaveEntity", event); + }); } void EntityTreeRenderer::clear() { @@ -264,8 +328,7 @@ void EntityTreeRenderer::update(bool simulate) { // not yet released the hold then this is still considered a holdingClickOnEntity event // and we want to simulate this message here as well as in mouse move if (_lastPointerEventValid && !_currentClickingOnEntityID.isInvalidID()) { - emit holdingClickOnEntity(_currentClickingOnEntityID, _lastPointerEvent); - _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", _lastPointerEvent); + emit DependencyManager::get()->holdingClickOnEntity(_currentClickingOnEntityID, _lastPointerEvent); } } @@ -435,19 +498,6 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha } void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) { - - connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity); - connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity); - connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity); - - connect(this, &EntityTreeRenderer::clickDownOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickDownOnEntity); - connect(this, &EntityTreeRenderer::holdingClickOnEntity, entityScriptingInterface, &EntityScriptingInterface::holdingClickOnEntity); - connect(this, &EntityTreeRenderer::clickReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickReleaseOnEntity); - - connect(this, &EntityTreeRenderer::hoverEnterEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity); - connect(this, &EntityTreeRenderer::hoverOverEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity); - connect(this, &EntityTreeRenderer::hoverLeaveEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity); - connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity); connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity); connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity); @@ -516,13 +566,11 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { } PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); + auto entityScriptingInterface = DependencyManager::get(); PickRay ray = _viewState->computePickRay(event->x(), event->y()); RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); - if (rayPickResult.intersects) { - //qCDebug(entitiesrenderer) << "mousePressEvent over entity:" << rayPickResult.entityID; - - auto entity = getTree()->findEntityByEntityItemID(rayPickResult.entityID); - auto properties = entity->getProperties(); + if (rayPickResult.intersects && rayPickResult.entity) { + auto properties = rayPickResult.entity->getProperties(); QString urlString = properties.getHref(); QUrl url = QUrl(urlString, QUrl::StrictMode); if (url.isValid() && !url.isEmpty()){ @@ -536,23 +584,16 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier); // TODO -- check for modifier keys? - emit mousePressOnEntity(rayPickResult.entityID, pointerEvent); - - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", pointerEvent); - } + emit entityScriptingInterface->mousePressOnEntity(rayPickResult.entityID, pointerEvent); _currentClickingOnEntityID = rayPickResult.entityID; - emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", pointerEvent); - } + emit entityScriptingInterface->clickDownOnEntity(_currentClickingOnEntityID, pointerEvent); _lastPointerEvent = pointerEvent; _lastPointerEventValid = true; } else { - emit mousePressOffEntity(); + emit entityScriptingInterface->mousePressOffEntity(); } } @@ -564,34 +605,25 @@ void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) { } PerformanceTimer perfTimer("EntityTreeRenderer::mouseDoublePressEvent"); + auto entityScriptingInterface = DependencyManager::get(); PickRay ray = _viewState->computePickRay(event->x(), event->y()); RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); - if (rayPickResult.intersects) { - //qCDebug(entitiesrenderer) << "mouseDoublePressEvent over entity:" << rayPickResult.entityID; - + if (rayPickResult.intersects && rayPickResult.entity) { glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier); - emit mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent); - - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseDoublePressOnEntity", pointerEvent); - } + emit entityScriptingInterface->mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent); _currentClickingOnEntityID = rayPickResult.entityID; - emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "doubleclickOnEntity", pointerEvent); - } + emit entityScriptingInterface->clickDownOnEntity(_currentClickingOnEntityID, pointerEvent); _lastPointerEvent = pointerEvent; _lastPointerEventValid = true; - } else { - emit mouseDoublePressOffEntity(); + emit entityScriptingInterface->mouseDoublePressOffEntity(); } } @@ -603,9 +635,10 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) { } PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent"); + auto entityScriptingInterface = DependencyManager::get(); PickRay ray = _viewState->computePickRay(event->x(), event->y()); RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); - if (rayPickResult.intersects) { + if (rayPickResult.intersects && rayPickResult.entity) { //qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID; glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); @@ -615,31 +648,23 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) { toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier); // TODO -- check for modifier keys? - emit mouseReleaseOnEntity(rayPickResult.entityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", pointerEvent); - } + emit entityScriptingInterface->mouseReleaseOnEntity(rayPickResult.entityID, pointerEvent); _lastPointerEvent = pointerEvent; _lastPointerEventValid = true; } // Even if we're no longer intersecting with an entity, if we started clicking on it, and now - // we're releasing the button, then this is considered a clickOn event + // we're releasing the button, then this is considered a clickReleaseOn event if (!_currentClickingOnEntityID.isInvalidID()) { - - auto entity = getTree()->findEntityByID(_currentClickingOnEntityID); - glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult); + glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier); // TODO -- check for modifier keys? - emit clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", pointerEvent); - } + emit entityScriptingInterface->clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent); } // makes it the unknown ID, we just released so we can't be clicking on anything @@ -654,9 +679,10 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { } PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent"); + auto entityScriptingInterface = DependencyManager::get(); PickRay ray = _viewState->computePickRay(event->x(), event->y()); RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); - if (rayPickResult.intersects) { + if (rayPickResult.intersects && rayPickResult.entity) { glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, @@ -664,48 +690,32 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier); // TODO -- check for modifier keys? - emit mouseMoveOnEntity(rayPickResult.entityID, pointerEvent); - - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", pointerEvent); - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", pointerEvent); - } + emit entityScriptingInterface->mouseMoveOnEntity(rayPickResult.entityID, pointerEvent); // handle the hover logic... // if we were previously hovering over an entity, and this new entity is not the same as our previous entity // then we need to send the hover leave. if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) { - - auto entity = getTree()->findEntityByID(_currentHoverOverEntityID); - glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult); + glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier); // TODO -- check for modifier keys? - emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", pointerEvent); - } + emit entityScriptingInterface->hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent); } // If the new hover entity does not match the previous hover entity then we are entering the new one // this is true if the _currentHoverOverEntityID is known or unknown if (rayPickResult.entityID != _currentHoverOverEntityID) { - emit hoverEnterEntity(rayPickResult.entityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", pointerEvent); - } + emit entityScriptingInterface->hoverEnterEntity(rayPickResult.entityID, pointerEvent); } // and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and // we should send our hover over event - emit hoverOverEntity(rayPickResult.entityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", pointerEvent); - } + emit entityScriptingInterface->hoverOverEntity(rayPickResult.entityID, pointerEvent); // remember what we're hovering over _currentHoverOverEntityID = rayPickResult.entityID; @@ -718,38 +728,18 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { // if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to // send the hover leave for our previous entity if (!_currentHoverOverEntityID.isInvalidID()) { - - auto entity = getTree()->findEntityByID(_currentHoverOverEntityID); - glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult); + glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier); // TODO -- check for modifier keys? - emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", pointerEvent); - } + emit entityScriptingInterface->hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent); _currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID - } - } - // Even if we're no longer intersecting with an entity, if we started clicking on an entity and we have - // not yet released the hold then this is still considered a holdingClickOnEntity event - if (!_currentClickingOnEntityID.isInvalidID()) { - - auto entity = getTree()->findEntityByID(_currentClickingOnEntityID); - glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult); - PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID, - pos2D, rayPickResult.intersection, - rayPickResult.surfaceNormal, ray.direction, - toPointerButton(*event), toPointerButtons(*event), - Qt::NoModifier); // TODO -- check for modifier keys? - - emit holdingClickOnEntity(_currentClickingOnEntityID, pointerEvent); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", pointerEvent); + _lastPointerEvent = pointerEvent; + _lastPointerEventValid = true; } } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 1b1d46d50c..1eb44f996a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -117,21 +117,6 @@ public: void onEntityChanged(const EntityItemID& id); signals: - void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void mouseDoublePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void mousePressOffEntity(); - void mouseDoublePressOffEntity(); - - void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void clickReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - - void hoverEnterEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void hoverOverEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void hoverLeaveEntity(const EntityItemID& entityItemID, const PointerEvent& event); - void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 07c5694a2a..f9e88b430f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -50,7 +50,9 @@ void EntityRenderer::initEntityRenderers() { REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory) } - +const Transform& EntityRenderer::getModelTransform() const { + return _modelTransform; +} void EntityRenderer::makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters) { auto nodeList = DependencyManager::get(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 34dbceb643..d770e7c7aa 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -105,8 +105,10 @@ protected: template std::shared_ptr asTypedEntity() { return std::static_pointer_cast(_entity); } + static void makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters); static std::function _entitiesShouldFadeFunction; + const Transform& getModelTransform() const; SharedSoundPointer _collisionSound; QUuid _changeHandlerId; @@ -114,7 +116,6 @@ protected: quint64 _fadeStartTime{ usecTimestampNow() }; bool _isFading{ _entitiesShouldFadeFunction() }; bool _prevIsTransparent { false }; - Transform _modelTransform; Item::Bound _bound; bool _visible { false }; bool _moving { false }; @@ -123,6 +124,10 @@ protected: private: + // The base class relies on comparing the model transform to the entity transform in order + // to trigger an update, so the member must not be visible to derived classes as a modifiable + // transform + Transform _modelTransform; // The rendering code only gets access to the entity in very specific circumstances // i.e. to see if the rendering code needs to update because of a change in state of the // entity. This forces all the rendering code itself to be independent of the entity diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index ca6ad5a32b..9ac7e9921f 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -49,9 +49,10 @@ void LineEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderableLineEntityItem::render"); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; + const auto& modelTransform = getModelTransform(); Transform transform = Transform(); - transform.setTranslation(_modelTransform.getTranslation()); - transform.setRotation(_modelTransform.getRotation()); + transform.setTranslation(modelTransform.getTranslation()); + transform.setRotation(modelTransform.getRotation()); batch.setModelTransform(transform); if (_linePoints.size() > 1) { DependencyManager::get()->bindSimpleProgram(batch); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0f764d3a29..7db19704b4 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -695,12 +695,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { const void* key = static_cast(shape); if (_collisionMeshKey != key) { - if (_collisionMeshKey) { - collisionMeshCache.releaseMesh(_collisionMeshKey); - } _collisionMeshKey = key; - // toggle _showCollisionGeometry forces re-evaluation later - _showCollisionGeometry = !_showCollisionGeometry; + emit requestCollisionGeometryUpdate(); } } @@ -1103,6 +1099,10 @@ bool ModelEntityRenderer::needsRenderUpdate() const { if (model->getRenderItemsNeedUpdate()) { return true; } + + if (_needsCollisionGeometryUpdate) { + return true; + } } return Parent::needsRenderUpdate(); } @@ -1169,6 +1169,15 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin return false; } +void ModelEntityRenderer::setCollisionMeshKey(const void*key) { + if (key != _collisionMeshKey) { + if (_collisionMeshKey) { + collisionMeshCache.releaseMesh(_collisionMeshKey); + } + _collisionMeshKey = key; + } +} + void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__); if (_hasModel != entity->hasModel()) { @@ -1201,6 +1210,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce model = std::make_shared(nullptr, entity.get()); connect(model.get(), &Model::setURLFinished, this, &ModelEntityRenderer::requestRenderUpdate); 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); @@ -1259,6 +1269,26 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } // TODO? early exit here when not visible? + if (_needsCollisionGeometryUpdate) { + setCollisionMeshKey(entity->getCollisionMeshKey()); + _needsCollisionGeometryUpdate = false; + ShapeType type = entity->getShapeType(); + if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) { + // NOTE: it is OK if _collisionMeshKey is nullptr + model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); + // NOTE: the model will render the collisionGeometry if it has one + _model->setCollisionMesh(mesh); + } else { + if (_collisionMeshKey) { + // release mesh + collisionMeshCache.releaseMesh(_collisionMeshKey); + } + // clear model's collision geometry + model::MeshPointer mesh = nullptr; + _model->setCollisionMesh(mesh); + } + } + { DETAILED_PROFILE_RANGE(simulation_physics, "Fixup"); if (model->needsFixupInScene()) { @@ -1297,6 +1327,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } } +void ModelEntityRenderer::flagForCollisionGeometryUpdate() { + _needsCollisionGeometryUpdate = true; + emit requestRenderUpdate(); +} + // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items void ModelEntityRenderer::doRender(RenderArgs* args) { DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender"); @@ -1311,7 +1346,7 @@ void ModelEntityRenderer::doRender(RenderArgs* args) { if (!model || (model && model->didVisualGeometryRequestFail())) { static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); gpu::Batch& batch = *args->_batch; - batch.setModelTransform(_modelTransform); // we want to include the scale as well + batch.setModelTransform(getModelTransform()); // we want to include the scale as well DependencyManager::get()->renderWireCubeInstance(args, batch, greenColor); return; } @@ -1327,28 +1362,11 @@ void ModelEntityRenderer::doRender(RenderArgs* args) { // Remap textures for the next frame to avoid flicker // remapTextures(); -#if 0 - // update whether the model should be showing collision mesh (this may flag for fixupInScene) - bool showingCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS); - if (showingCollisionGeometry != _showCollisionGeometry) { - ShapeType type = _entity->getShapeType(); - _showCollisionGeometry = showingCollisionGeometry; - if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) { - // NOTE: it is OK if _collisionMeshKey is nullptr - model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); - // NOTE: the model will render the collisionGeometry if it has one - _model->setCollisionMesh(mesh); - } else { - // release mesh - if (_collisionMeshKey) { - collisionMeshCache.releaseMesh(_collisionMeshKey); - } - // clear model's collision geometry - model::MeshPointer mesh = nullptr; - _model->setCollisionMesh(mesh); - } + bool showCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS); + if (showCollisionGeometry != _showCollisionGeometry) { + _showCollisionGeometry = showCollisionGeometry; + flagForCollisionGeometryUpdate(); } -#endif } void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index a50ca63382..0272bed575 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -50,6 +50,8 @@ private: }; class RenderableModelEntityItem : public ModelEntityWrapper { + Q_OBJECT + friend class render::entities::ModelEntityRenderer; using Parent = ModelEntityWrapper; public: @@ -105,6 +107,10 @@ public: virtual QStringList getJointNames() const override; bool getMeshes(MeshProxyList& result) override; + const void* getCollisionMeshKey() const { return _collisionMeshKey; } + +signals: + void requestCollisionGeometryUpdate(); private: bool needsUpdateModelBounds() const; @@ -117,7 +123,6 @@ private: QVariantMap _originalTextures; bool _dimensionsInitialized { true }; bool _needsJointSimulation { false }; - bool _showCollisionGeometry { false }; const void* _collisionMeshKey { nullptr }; }; @@ -141,6 +146,8 @@ protected: virtual bool needsRenderUpdate() const override; virtual void doRender(RenderArgs* args) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + void flagForCollisionGeometryUpdate(); + void setCollisionMeshKey(const void* key); private: void animate(const TypedEntityPointer& entity); @@ -163,6 +170,7 @@ private: bool _needsJointSimulation{ false }; bool _showCollisionGeometry{ false }; + bool _needsCollisionGeometryUpdate{ false }; const void* _collisionMeshKey{ nullptr }; // used on client side diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 3328076911..bc96e45881 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -69,8 +69,8 @@ ParticleEffectEntityRenderer::ParticleEffectEntityRenderer(const EntityItemPoint } bool ParticleEffectEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { - entity->checkAndMaybeUpdateQueryAACube(); - + entity->updateQueryAACube(); + if (_emitting != entity->getIsEmitting()) { return true; } @@ -251,12 +251,13 @@ void ParticleEffectEntityRenderer::stepSimulation() { }); if (_emitting && particleProperties.emitting()) { + const auto& modelTransform = getModelTransform(); uint64_t emitInterval = particleProperties.emitIntervalUsecs(); if (emitInterval > 0 && interval >= _timeUntilNextEmit) { auto timeRemaining = interval; while (timeRemaining > _timeUntilNextEmit) { // emit particle - _cpuParticles.push_back(createParticle(now, _modelTransform, particleProperties)); + _cpuParticles.push_back(createParticle(now, modelTransform, particleProperties)); _timeUntilNextEmit = emitInterval; if (emitInterval < timeRemaining) { timeRemaining -= emitInterval; @@ -315,7 +316,7 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) { // In trail mode, the particles are created in world space. // so we only set a transform if they're not in trail mode if (!_particleProperties.emission.shouldTrail) { - transform = _modelTransform; + transform = getModelTransform(); transform.setScale(vec3(1)); } batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 4028f105c8..332d87f930 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -30,23 +30,6 @@ using namespace render::entities; // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down. static const float SPHERE_ENTITY_SCALE = 0.5f; -static std::array MAPPING { { - GeometryCache::Triangle, - GeometryCache::Quad, - GeometryCache::Hexagon, - GeometryCache::Octagon, - GeometryCache::Circle, - GeometryCache::Cube, - GeometryCache::Sphere, - GeometryCache::Tetrahedron, - GeometryCache::Octahedron, - GeometryCache::Dodecahedron, - GeometryCache::Icosahedron, - GeometryCache::Torus, - GeometryCache::Cone, - GeometryCache::Cylinder, -} }; - ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { _procedural._vertexSource = simple_vert; @@ -76,6 +59,14 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin return true; } + if (_shape != entity->getShape()) { + return true; + } + + if (_dimensions != entity->getDimensions()) { + return true; + } + return false; } @@ -93,12 +84,13 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _position = entity->getPosition(); _dimensions = entity->getDimensions(); _orientation = entity->getOrientation(); + _renderTransform = getModelTransform(); if (_shape == entity::Sphere) { - _modelTransform.postScale(SPHERE_ENTITY_SCALE); + _renderTransform.postScale(SPHERE_ENTITY_SCALE); } - _modelTransform.postScale(_dimensions); + _renderTransform.postScale(_dimensions); }); } @@ -128,12 +120,13 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { gpu::Batch& batch = *args->_batch; + auto geometryCache = DependencyManager::get(); GeometryCache::Shape geometryShape; bool proceduralRender = false; glm::vec4 outColor; withReadLock([&] { - geometryShape = MAPPING[_shape]; - batch.setModelTransform(_modelTransform); // use a transform with scale, rotation, registration point and translation + geometryShape = geometryCache->getShapeForEntityShape(_shape); + batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation outColor = _color; if (_procedural.isReady()) { _procedural.prepare(batch, _position, _dimensions, _orientation); @@ -146,14 +139,13 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { if (proceduralRender) { batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { - DependencyManager::get()->renderWireShape(batch, geometryShape); + geometryCache->renderWireShape(batch, geometryShape); } else { - DependencyManager::get()->renderShape(batch, geometryShape); + geometryCache->renderShape(batch, geometryShape); } } else { // FIXME, support instanced multi-shape rendering using multidraw indirect outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; - auto geometryCache = DependencyManager::get(); auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline); @@ -162,6 +154,6 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { } } - static const auto triCount = DependencyManager::get()->getShapeTriangleCount(geometryShape); + const auto triCount = geometryCache->getShapeTriangleCount(geometryShape); args->_details._trianglesRendered += (int)triCount; } diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index f0af5b917a..433cb41ad2 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -32,6 +32,7 @@ private: Procedural _procedural; QString _lastUserData; + Transform _renderTransform; entity::Shape _shape { entity::Sphere }; glm::vec4 _color; glm::vec3 _position; diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index b4c64aed6f..6c0f4447ae 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -93,10 +93,11 @@ void TextEntityRenderer::doRender(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; - auto transformToTopLeft = _modelTransform; + const auto& modelTransform = getModelTransform(); + auto transformToTopLeft = modelTransform; if (_faceCamera) { //rotate about vertical to face the camera - glm::vec3 dPosition = args->getViewFrustum().getPosition() - _modelTransform.getTranslation(); + glm::vec3 dPosition = args->getViewFrustum().getPosition() - modelTransform.getTranslation(); // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 4688ef5d2b..a2e574a829 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -24,7 +24,6 @@ #include #include -#include "EntityTreeRenderer.h" #include "EntitiesRendererLogging.h" @@ -86,6 +85,10 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe return true; } + if (_lastLocked != entity->getLocked()) { + return true; + } + return false; } @@ -136,11 +139,12 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene } _lastDPI = entity->getDPI(); + _lastLocked = entity->getLocked(); glm::vec2 windowSize = getWindowSize(entity); _webSurface->resize(QSize(windowSize.x, windowSize.y)); - - _modelTransform.postScale(entity->getDimensions()); + _renderTransform = getModelTransform(); + _renderTransform.postScale(entity->getDimensions()); }); } @@ -180,7 +184,7 @@ void WebEntityRenderer::doRender(RenderArgs* args) { gpu::Batch& batch = *args->_batch; withReadLock([&] { - batch.setModelTransform(_modelTransform); + batch.setModelTransform(_renderTransform); }); batch.setResourceTexture(0, _texture); float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; @@ -234,38 +238,6 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { emit entities->webEventReceived(entityItemID, message); }); - auto forwardPointerEvent = [=](const EntityItemID& entityItemID, const PointerEvent& event) { - if (entityItemID == entity->getID()) { - handlePointerEvent(entity, event); - } - }; - - auto renderer = DependencyManager::get(); - QObject::connect(renderer.data(), &EntityTreeRenderer::mousePressOnEntity, this, forwardPointerEvent); - QObject::connect(renderer.data(), &EntityTreeRenderer::mouseReleaseOnEntity, this, forwardPointerEvent); - QObject::connect(renderer.data(), &EntityTreeRenderer::mouseMoveOnEntity, this, forwardPointerEvent); - QObject::connect(renderer.data(), &EntityTreeRenderer::hoverLeaveEntity, this, - [=](const EntityItemID& entityItemID, const PointerEvent& event) { - if (this->_pressed && entity->getID() == entityItemID) { - // If the user mouses off the entity while the button is down, simulate a touch end. - QTouchEvent::TouchPoint point; - point.setId(event.getID()); - point.setState(Qt::TouchPointReleased); - glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI); - QPointF windowPoint(windowPos.x, windowPos.y); - point.setScenePos(windowPoint); - point.setPos(windowPoint); - QList touchPoints; - touchPoints.push_back(point); - QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr, - Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - touchEvent->setWindow(_webSurface->getWindow()); - touchEvent->setDevice(&_touchDevice); - touchEvent->setTarget(_webSurface->getRootItem()); - QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent); - } - }); - return true; } @@ -295,13 +267,6 @@ void WebEntityRenderer::destroyWebSurface() { } webSurface->pause(); - auto renderer = DependencyManager::get(); - if (renderer) { - QObject::disconnect(renderer.data(), &EntityTreeRenderer::mousePressOnEntity, this, nullptr); - QObject::disconnect(renderer.data(), &EntityTreeRenderer::mouseReleaseOnEntity, this, nullptr); - QObject::disconnect(renderer.data(), &EntityTreeRenderer::mouseMoveOnEntity, this, nullptr); - QObject::disconnect(renderer.data(), &EntityTreeRenderer::hoverLeaveEntity, this, nullptr); - } webSurface.reset(); } } @@ -347,13 +312,34 @@ void WebEntityRenderer::loadSourceURL() { } } -void WebEntityRenderer::handlePointerEvent(const TypedEntityPointer& entity, const PointerEvent& event) { +void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) { + if (!_lastLocked && _webSurface && _pressed) { + // If the user mouses off the entity while the button is down, simulate a touch end. + QTouchEvent::TouchPoint point; + point.setId(event.getID()); + point.setState(Qt::TouchPointReleased); + glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI); + QPointF windowPoint(windowPos.x, windowPos.y); + point.setScenePos(windowPoint); + point.setPos(windowPoint); + QList touchPoints; + touchPoints.push_back(point); + QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr, + Qt::NoModifier, Qt::TouchPointReleased, touchPoints); + touchEvent->setWindow(_webSurface->getWindow()); + touchEvent->setDevice(&_touchDevice); + touchEvent->setTarget(_webSurface->getRootItem()); + QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent); + } +} + +void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) { // Ignore mouse interaction if we're locked - if (entity->getLocked() || !_webSurface) { + if (_lastLocked || !_webSurface) { return; } - glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * entity->getDPI()); + glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI); QPointF windowPoint(windowPos.x, windowPos.y); if (event.getType() == PointerEvent::Move) { // Forward a mouse move event to webSurface diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 4b7e7e25a1..2d162e57fe 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -18,12 +18,16 @@ class PointerEvent; namespace render { namespace entities { class WebEntityRenderer : public TypedEntityRenderer { + Q_OBJECT using Parent = TypedEntityRenderer; friend class EntityRenderer; public: WebEntityRenderer(const EntityItemPointer& entity); + Q_INVOKABLE void hoverLeaveEntity(const PointerEvent& event); + Q_INVOKABLE void handlePointerEvent(const PointerEvent& event); + protected: virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override; virtual bool needsRenderUpdate() const override; @@ -44,9 +48,6 @@ private: bool hasWebSurface(); void loadSourceURL(); glm::vec2 getWindowSize(const TypedEntityPointer& entity) const; - void handlePointerEvent(const TypedEntityPointer& entity, const PointerEvent& event); - -private: int _geometryId{ 0 }; enum contentType { @@ -60,8 +61,10 @@ private: bool _pressed{ false }; QString _lastSourceUrl; uint16_t _lastDPI; + bool _lastLocked; QTimer _timer; uint64_t _lastRenderTime { 0 }; + Transform _renderTransform; }; } } // namespace diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index f3b664f9b4..0235f1b7a3 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -112,6 +112,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { // Do we need to allocate the light in the stage ? if (LightStage::isIndexInvalid(_sunIndex)) { _sunIndex = _stage->addLight(_sunLight); + _shadowIndex = _stage->addShadow(_sunIndex); } else { _stage->updateLightArrayBuffer(_sunIndex); } @@ -248,7 +249,8 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { if (entity->getShapeType() == SHAPE_TYPE_SPHERE) { - _modelTransform.postScale(SPHERE_ENTITY_SCALE); + _renderTransform = getModelTransform(); + _renderTransform.postScale(SPHERE_ENTITY_SCALE); } } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 30da96cd9d..050a8a4386 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -88,6 +88,7 @@ private: ComponentMode _hazeMode{ COMPONENT_MODE_INHERIT }; indexed_container::Index _sunIndex{ LightStage::INVALID_INDEX }; + indexed_container::Index _shadowIndex{ LightStage::INVALID_INDEX }; indexed_container::Index _ambientIndex{ LightStage::INVALID_INDEX }; BackgroundStagePointer _backgroundStage; @@ -119,6 +120,7 @@ private: bool _validSkyboxTexture{ false }; QString _proceduralUserData; + Transform _renderTransform; }; } } // namespace diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 58b8dd22bf..008ec9769f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -43,7 +43,7 @@ int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; EntityItem::EntityItem(const EntityItemID& entityItemID) : - SpatiallyNestable(NestableType::Entity, entityItemID) + SpatiallyNestable(NestableType::Entity, entityItemID) { setLocalVelocity(ENTITY_ITEM_DEFAULT_VELOCITY); setLocalAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY); @@ -355,14 +355,6 @@ int EntityItem::expectedBytes() { // clients use this method to unpack FULL updates from entity-server int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { - - // NOTE: This shouldn't happen. The only versions of the bit stream that didn't support split mtu buffers should - // be handled by the model subclass and shouldn't call this routine. - qCDebug(entities) << "EntityItem::readEntityDataFromBuffer()... " - "ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU"; - return 0; - } setSourceUUID(args.sourceUUID); args.entitiesPerPacket++; @@ -588,34 +580,32 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // Newer bitstreams will have a last simulated and a last updated value quint64 lastSimulatedFromBufferAdjusted = now; - if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) { - // last simulated is stored as ByteCountCoded delta from lastEdited - quint64 simulatedDelta; - parser.readCompressedCount(simulatedDelta); + // last simulated is stored as ByteCountCoded delta from lastEdited + quint64 simulatedDelta; + parser.readCompressedCount(simulatedDelta); #ifdef VALIDATE_ENTITY_ITEM_PARSER - { - QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size - ByteCountCoded simulatedDeltaCoder = encodedSimulatedDelta; - quint64 simulatedDelta2 = simulatedDeltaCoder; - Q_ASSERT(simulatedDelta2 == simulatedDelta); - encodedSimulatedDelta = simulatedDeltaCoder; // determine true length - dataAt += encodedSimulatedDelta.size(); - bytesRead += encodedSimulatedDelta.size(); - Q_ASSERT(parser.offset() == (unsigned int) bytesRead); - } + { + QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size + ByteCountCoded simulatedDeltaCoder = encodedSimulatedDelta; + quint64 simulatedDelta2 = simulatedDeltaCoder; + Q_ASSERT(simulatedDelta2 == simulatedDelta); + encodedSimulatedDelta = simulatedDeltaCoder; // determine true length + dataAt += encodedSimulatedDelta.size(); + bytesRead += encodedSimulatedDelta.size(); + Q_ASSERT(parser.offset() == (unsigned int) bytesRead); + } #endif - if (overwriteLocalData) { - lastSimulatedFromBufferAdjusted = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that - if (lastSimulatedFromBufferAdjusted > now) { - lastSimulatedFromBufferAdjusted = now; - } - #ifdef WANT_DEBUG - qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now); - qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); - qCDebug(entities) << " lastSimulatedFromBufferAdjusted:" << debugTime(lastSimulatedFromBufferAdjusted, now); - #endif + if (overwriteLocalData) { + lastSimulatedFromBufferAdjusted = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that + if (lastSimulatedFromBufferAdjusted > now) { + lastSimulatedFromBufferAdjusted = now; } + #ifdef WANT_DEBUG + qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now); + qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); + qCDebug(entities) << " lastSimulatedFromBufferAdjusted:" << debugTime(lastSimulatedFromBufferAdjusted, now); + #endif } #ifdef WANT_DEBUG @@ -717,9 +707,17 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); } } + + auto lastEdited = lastEditedFromBufferAdjusted; + bool otherOverwrites = overwriteLocalData && !weOwnSimulation; + auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) { + bool simulationChanged = lastEdited > updatedTimestamp; + return otherOverwrites && simulationChanged && (valueChanged || filterRejection); + }; + { // When we own the simulation we don't accept updates to the entity's transform/velocities // we also want to ignore any duplicate packets that have the same "recently updated" values - // as a packet we've already recieved. This is because we want multiple edits of the same + // as a packet we've already recieved. This is because we want multiple edits of the same // information to be idempotent, but if we applied new physics properties we'd resimulation // with small differences in results. @@ -727,17 +725,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // made these lambdas that can access other details about the previous updates to suppress // any duplicates. - // Note: duplicate packets are expected and not wrong. They may be sent for any number of + // Note: duplicate packets are expected and not wrong. They may be sent for any number of // reasons and the contract is that the client handles them in an idempotent manner. - auto lastEdited = lastEditedFromBufferAdjusted; - bool otherOverwrites = overwriteLocalData && !weOwnSimulation; - auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) { - bool simulationChanged = lastEdited > updatedTimestamp; - return otherOverwrites && simulationChanged && (valueChanged || filterRejection); - }; auto customUpdatePositionFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){ if (shouldUpdate(_lastUpdatedPositionTimestamp, value != _lastUpdatedPositionValue)) { - updatePositionFromNetwork(value); + updatePosition(value); _lastUpdatedPositionTimestamp = lastEdited; _lastUpdatedPositionValue = value; } @@ -745,7 +737,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value){ if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) { - updateRotationFromNetwork(value); + updateRotation(value); _lastUpdatedRotationTimestamp = lastEdited; _lastUpdatedRotationValue = value; } @@ -753,7 +745,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto customUpdateVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){ if (shouldUpdate(_lastUpdatedVelocityTimestamp, value != _lastUpdatedVelocityValue)) { - updateVelocityFromNetwork(value); + updateVelocity(value); _lastUpdatedVelocityTimestamp = lastEdited; _lastUpdatedVelocityValue = value; } @@ -761,7 +753,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto customUpdateAngularVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){ if (shouldUpdate(_lastUpdatedAngularVelocityTimestamp, value != _lastUpdatedAngularVelocityValue)) { - updateAngularVelocityFromNetwork(value); + updateAngularVelocity(value); _lastUpdatedAngularVelocityTimestamp = lastEdited; _lastUpdatedAngularVelocityValue = value; } @@ -780,8 +772,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, customUpdateVelocityFromNetwork); READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, customUpdateAngularVelocityFromNetwork); READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, customSetAcceleration); - - } READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); @@ -817,20 +807,16 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LOCKED, bool, updateLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); - if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) { - READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); - } - if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_CERTIFICATE_PROPERTIES) { - READ_ENTITY_PROPERTY(PROP_ITEM_NAME, QString, setItemName); - READ_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString, setItemDescription); - READ_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString, setItemCategories); - READ_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString, setItemArtist); - READ_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString, setItemLicense); - READ_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32, setLimitedRun); - READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber); - READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber); - READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID); - } + READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); + READ_ENTITY_PROPERTY(PROP_ITEM_NAME, QString, setItemName); + READ_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString, setItemDescription); + READ_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString, setItemCategories); + READ_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString, setItemArtist); + READ_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString, setItemLicense); + READ_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32, setLimitedRun); + READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber); + READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber); + READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID); READ_ENTITY_PROPERTY(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); @@ -846,7 +832,18 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef overwriteLocalData = oldOverwrite; } - READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, setQueryAACube); + + { + auto customUpdateQueryAACubeFromNetwork = [this, shouldUpdate, lastEdited](AACube value){ + if (shouldUpdate(_lastUpdatedQueryAACubeTimestamp, value != _lastUpdatedQueryAACubeValue)) { + setQueryAACube(value); + _lastUpdatedQueryAACubeTimestamp = lastEdited; + _lastUpdatedQueryAACubeValue = value; + } + }; + READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, customUpdateQueryAACubeFromNetwork); + } + READ_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, @@ -858,10 +855,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover // by doing this parsing here... but it's not likely going to fully recover the content. // - // TODO: Remove this code once we've sufficiently migrated content past this damaged version - if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) { - READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); - } if (overwriteLocalData && (getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES))) { // NOTE: This code is attempting to "repair" the old data we just got from the server to make it more @@ -1381,8 +1374,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy); - AACube saveQueryAACube = _queryAACube; - if (checkAndMaybeUpdateQueryAACube() && saveQueryAACube != _queryAACube) { + if (updateQueryAACube()) { somethingChanged = true; } @@ -1546,6 +1538,9 @@ AACube EntityItem::getQueryAACube(bool& success) const { return result; } +bool EntityItem::shouldPuffQueryAACube() const { + return hasActions() || isChildOfMyAvatar() || isMovingRelativeToParent(); +} // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension @@ -1659,7 +1654,7 @@ bool EntityItem::verifyStaticCertificateProperties() { const auto hash = getStaticCertificateHash(); const auto text = reinterpret_cast(hash.constData()); const unsigned int textLength = hash.length(); - + // After DEBUG_CERT ends, we will get/cache this once from the marketplace when needed, and it likely won't be RSA. const char publicKey[] = "-----BEGIN PUBLIC KEY-----\n\ MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALCoBiDAZOClO26tC5pd7JikBL61WIgp\n\ @@ -1750,16 +1745,10 @@ void EntityItem::updateParentID(const QUuid& value) { if (tree) { tree->addToNeedsParentFixupList(getThisPointer()); } + updateQueryAACube(); } } -void EntityItem::updatePositionFromNetwork(const glm::vec3& value) { - if (shouldSuppressLocationEdits()) { - return; - } - updatePosition(value); -} - void EntityItem::updateDimensions(const glm::vec3& value) { if (getDimensions() != value) { setDimensions(value); @@ -1782,13 +1771,6 @@ void EntityItem::updateRotation(const glm::quat& rotation) { } } -void EntityItem::updateRotationFromNetwork(const glm::quat& rotation) { - if (shouldSuppressLocationEdits()) { - return; - } - updateRotation(rotation); -} - void EntityItem::updateMass(float mass) { // Setting the mass actually changes the _density (at fixed volume), however // we must protect the density range to help maintain stability of physics simulation @@ -1839,13 +1821,6 @@ void EntityItem::updateVelocity(const glm::vec3& value) { } } -void EntityItem::updateVelocityFromNetwork(const glm::vec3& value) { - if (shouldSuppressLocationEdits()) { - return; - } - updateVelocity(value); -} - void EntityItem::updateDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); if (_damping != clampedDamping) { @@ -1897,13 +1872,6 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) { } } -void EntityItem::updateAngularVelocityFromNetwork(const glm::vec3& value) { - if (shouldSuppressLocationEdits()) { - return; - } - updateAngularVelocity(value); -} - void EntityItem::updateAngularDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); if (_angularDamping != clampedDamping) { @@ -2016,9 +1984,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask // if this entity is a descendant of MyAvatar, don't collide with MyAvatar. This avoids the // "bootstrapping" problem where you can shoot yourself across the room by grabbing something // and holding it against your own avatar. - QUuid ancestorID = findAncestorOfType(NestableType::Avatar); - if (!ancestorID.isNull() && - (ancestorID == Physics::getSessionUUID() || ancestorID == AVATAR_SELF_ID)) { + if (isChildOfMyAvatar()) { iAmHoldingThis = true; } // also, don't bootstrap our own avatar with a hold action @@ -2125,6 +2091,7 @@ bool EntityItem::addAction(EntitySimulationPointer simulation, EntityDynamicPoin removeActionInternal(action->getID()); } }); + updateQueryAACube(); return result; } @@ -2183,6 +2150,8 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a checkWaitingToRemove(simulation); success = removeActionInternal(actionID); }); + updateQueryAACube(); + return success; } @@ -2425,6 +2394,7 @@ QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const { } bool EntityItem::shouldSuppressLocationEdits() const { + // if any of the actions indicate they'd like suppression, suppress QHash::const_iterator i = _objectActions.begin(); while (i != _objectActions.end()) { if (i.value()->shouldSuppressLocationEdits()) { @@ -2433,6 +2403,11 @@ bool EntityItem::shouldSuppressLocationEdits() const { i++; } + // if any of the ancestors are MyAvatar, suppress + if (isChildOfMyAvatar()) { + return true; + } + return false; } @@ -2495,16 +2470,16 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const { - + // The intention for the query JSON filter and this method is to be flexible to handle a variety of filters for // ALL entity properties. Some work will need to be done to the property system so that it can be more flexible // (to grab the value and default value of a property given the string representation of that property, for example) - + // currently the only property filter we handle is '+' for serverScripts // which means that we only handle a filtered query asking for entities where the serverScripts property is non-default - + static const QString SERVER_SCRIPTS_PROPERTY = "serverScripts"; - + foreach(const auto& property, jsonFilters.keys()) { if (property == SERVER_SCRIPTS_PROPERTY && jsonFilters[property] == EntityQueryFilterSymbol::NonDefault) { // check if this entity has a non-default value for serverScripts @@ -2515,7 +2490,7 @@ bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const { } } } - + // the json filter syntax did not match what we expected, return a match return true; } @@ -2528,7 +2503,7 @@ quint64 EntityItem::getLastSimulated() const { return result; } -void EntityItem::setLastSimulated(quint64 now) { +void EntityItem::setLastSimulated(quint64 now) { withWriteLock([&] { _lastSimulated = now; }); @@ -2549,7 +2524,7 @@ void EntityItem::setLastEdited(quint64 lastEdited) { }); } -quint64 EntityItem::getLastBroadcast() const { +quint64 EntityItem::getLastBroadcast() const { quint64 result; withReadLock([&] { result = _lastBroadcast; @@ -2557,19 +2532,19 @@ quint64 EntityItem::getLastBroadcast() const { return result; } -void EntityItem::setLastBroadcast(quint64 lastBroadcast) { +void EntityItem::setLastBroadcast(quint64 lastBroadcast) { withWriteLock([&] { _lastBroadcast = lastBroadcast; }); } -void EntityItem::markAsChangedOnServer() { +void EntityItem::markAsChangedOnServer() { withWriteLock([&] { _changedOnServer = usecTimestampNow(); }); } -quint64 EntityItem::getLastChangedOnServer() const { +quint64 EntityItem::getLastChangedOnServer() const { quint64 result; withReadLock([&] { result = _changedOnServer; @@ -2577,13 +2552,13 @@ quint64 EntityItem::getLastChangedOnServer() const { return result; } -void EntityItem::update(const quint64& now) { +void EntityItem::update(const quint64& now) { withWriteLock([&] { - _lastUpdated = now; + _lastUpdated = now; }); } -quint64 EntityItem::getLastUpdated() const { +quint64 EntityItem::getLastUpdated() const { quint64 result; withReadLock([&] { result = _lastUpdated; @@ -2591,10 +2566,10 @@ quint64 EntityItem::getLastUpdated() const { return result; } -void EntityItem::requiresRecalcBoxes() { +void EntityItem::requiresRecalcBoxes() { withWriteLock([&] { - _recalcAABox = true; - _recalcMinAACube = true; + _recalcAABox = true; + _recalcMinAACube = true; _recalcMaxAACube = true; }); } @@ -2607,7 +2582,7 @@ QString EntityItem::getHref() const { return result; } -QString EntityItem::getDescription() const { +QString EntityItem::getDescription() const { QString result; withReadLock([&] { result = _description; @@ -2629,54 +2604,54 @@ float EntityItem::getLocalRenderAlpha() const { return result; } -void EntityItem::setLocalRenderAlpha(float localRenderAlpha) { +void EntityItem::setLocalRenderAlpha(float localRenderAlpha) { withWriteLock([&] { _localRenderAlpha = localRenderAlpha; }); } -glm::vec3 EntityItem::getGravity() const { +glm::vec3 EntityItem::getGravity() const { glm::vec3 result; withReadLock([&] { result = _gravity; }); return result; -} +} -void EntityItem::setGravity(const glm::vec3& value) { +void EntityItem::setGravity(const glm::vec3& value) { withWriteLock([&] { _gravity = value; }); } -glm::vec3 EntityItem::getAcceleration() const { +glm::vec3 EntityItem::getAcceleration() const { glm::vec3 result; withReadLock([&] { result = _acceleration; }); return result; -} +} -void EntityItem::setAcceleration(const glm::vec3& value) { +void EntityItem::setAcceleration(const glm::vec3& value) { withWriteLock([&] { _acceleration = value; }); } -float EntityItem::getDamping() const { +float EntityItem::getDamping() const { float result; withReadLock([&] { result = _damping; }); return result; } -void EntityItem::setDamping(float value) { +void EntityItem::setDamping(float value) { withWriteLock([&] { _damping = value; }); } -float EntityItem::getRestitution() const { +float EntityItem::getRestitution() const { float result; withReadLock([&] { result = _restitution; @@ -2684,7 +2659,7 @@ float EntityItem::getRestitution() const { return result; } -float EntityItem::getFriction() const { +float EntityItem::getFriction() const { float result; withReadLock([&] { result = _friction; @@ -2693,35 +2668,35 @@ float EntityItem::getFriction() const { } // lifetime related properties. -float EntityItem::getLifetime() const { +float EntityItem::getLifetime() const { float result; withReadLock([&] { result = _lifetime; }); return result; -} +} -void EntityItem::setLifetime(float value) { +void EntityItem::setLifetime(float value) { withWriteLock([&] { _lifetime = value; }); } -quint64 EntityItem::getCreated() const { +quint64 EntityItem::getCreated() const { quint64 result; withReadLock([&] { result = _created; }); return result; -} +} -void EntityItem::setCreated(quint64 value) { +void EntityItem::setCreated(quint64 value) { withWriteLock([&] { _created = value; }); } -QString EntityItem::getScript() const { +QString EntityItem::getScript() const { QString result; withReadLock([&] { result = _script; @@ -2729,13 +2704,13 @@ QString EntityItem::getScript() const { return result; } -void EntityItem::setScript(const QString& value) { +void EntityItem::setScript(const QString& value) { withWriteLock([&] { _script = value; }); } -quint64 EntityItem::getScriptTimestamp() const { +quint64 EntityItem::getScriptTimestamp() const { quint64 result; withReadLock([&] { result = _scriptTimestamp; @@ -2743,13 +2718,13 @@ quint64 EntityItem::getScriptTimestamp() const { return result; } -void EntityItem::setScriptTimestamp(const quint64 value) { +void EntityItem::setScriptTimestamp(const quint64 value) { withWriteLock([&] { _scriptTimestamp = value; }); } -QString EntityItem::getServerScripts() const { +QString EntityItem::getServerScripts() const { QString result; withReadLock([&] { result = _serverScripts; @@ -2759,12 +2734,12 @@ QString EntityItem::getServerScripts() const { void EntityItem::setServerScripts(const QString& serverScripts) { withWriteLock([&] { - _serverScripts = serverScripts; + _serverScripts = serverScripts; _serverScriptsChangedTimestamp = usecTimestampNow(); }); } -QString EntityItem::getCollisionSoundURL() const { +QString EntityItem::getCollisionSoundURL() const { QString result; withReadLock([&] { result = _collisionSoundURL; @@ -2772,22 +2747,22 @@ QString EntityItem::getCollisionSoundURL() const { return result; } -glm::vec3 EntityItem::getRegistrationPoint() const { +glm::vec3 EntityItem::getRegistrationPoint() const { glm::vec3 result; withReadLock([&] { result = _registrationPoint; }); return result; -} +} void EntityItem::setRegistrationPoint(const glm::vec3& value) { withWriteLock([&] { - _registrationPoint = glm::clamp(value, 0.0f, 1.0f); + _registrationPoint = glm::clamp(value, 0.0f, 1.0f); }); dimensionsChanged(); // Registration Point affects the bounding box } -float EntityItem::getAngularDamping() const { +float EntityItem::getAngularDamping() const { float result; withReadLock([&] { result = _angularDamping; @@ -2795,13 +2770,13 @@ float EntityItem::getAngularDamping() const { return result; } -void EntityItem::setAngularDamping(float value) { +void EntityItem::setAngularDamping(float value) { withWriteLock([&] { _angularDamping = value; }); } -QString EntityItem::getName() const { +QString EntityItem::getName() const { QString result; withReadLock([&] { result = _name; @@ -2809,13 +2784,13 @@ QString EntityItem::getName() const { return result; } -void EntityItem::setName(const QString& value) { +void EntityItem::setName(const QString& value) { withWriteLock([&] { _name = value; }); } -QString EntityItem::getDebugName() { +QString EntityItem::getDebugName() { QString result = getName(); if (result.isEmpty()) { result = getID().toString(); @@ -2823,7 +2798,7 @@ QString EntityItem::getDebugName() { return result; } -bool EntityItem::getVisible() const { +bool EntityItem::getVisible() const { bool result; withReadLock([&] { result = _visible; @@ -2831,13 +2806,18 @@ bool EntityItem::getVisible() const { return result; } -void EntityItem::setVisible(bool value) { +void EntityItem::setVisible(bool value) { withWriteLock([&] { _visible = value; }); } -bool EntityItem::getCollisionless() const { +bool EntityItem::isChildOfMyAvatar() const { + QUuid ancestorID = findAncestorOfType(NestableType::Avatar); + return !ancestorID.isNull() && (ancestorID == Physics::getSessionUUID() || ancestorID == AVATAR_SELF_ID); +} + +bool EntityItem::getCollisionless() const { bool result; withReadLock([&] { result = _collisionless; @@ -2845,13 +2825,13 @@ bool EntityItem::getCollisionless() const { return result; } -void EntityItem::setCollisionless(bool value) { +void EntityItem::setCollisionless(bool value) { withWriteLock([&] { _collisionless = value; }); } -uint8_t EntityItem::getCollisionMask() const { +uint8_t EntityItem::getCollisionMask() const { uint8_t result; withReadLock([&] { result = _collisionMask; @@ -2859,13 +2839,13 @@ uint8_t EntityItem::getCollisionMask() const { return result; } -void EntityItem::setCollisionMask(uint8_t value) { +void EntityItem::setCollisionMask(uint8_t value) { withWriteLock([&] { _collisionMask = value; }); } -bool EntityItem::getDynamic() const { +bool EntityItem::getDynamic() const { if (SHAPE_TYPE_STATIC_MESH == getShapeType()) { return false; } @@ -2876,13 +2856,13 @@ bool EntityItem::getDynamic() const { return result; } -void EntityItem::setDynamic(bool value) { +void EntityItem::setDynamic(bool value) { withWriteLock([&] { _dynamic = value; }); } -bool EntityItem::getLocked() const { +bool EntityItem::getLocked() const { bool result; withReadLock([&] { result = _locked; @@ -2890,7 +2870,7 @@ bool EntityItem::getLocked() const { return result; } -void EntityItem::setLocked(bool value) { +void EntityItem::setLocked(bool value) { withWriteLock([&] { _locked = value; }); @@ -2913,7 +2893,7 @@ void EntityItem::updateLocked(bool value) { } } -QString EntityItem::getUserData() const { +QString EntityItem::getUserData() const { QString result; withReadLock([&] { result = _userData; @@ -2921,7 +2901,7 @@ QString EntityItem::getUserData() const { return result; } -void EntityItem::setUserData(const QString& value) { +void EntityItem::setUserData(const QString& value) { withWriteLock([&] { _userData = value; }); @@ -2955,7 +2935,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, EditionNumber, editionNumber) DEFINE_PROPERTY_ACCESSOR(quint32, EntityInstanceNumber, entityInstanceNumber) DEFINE_PROPERTY_ACCESSOR(QString, CertificateID, certificateID) -uint32_t EntityItem::getDirtyFlags() const { +uint32_t EntityItem::getDirtyFlags() const { uint32_t result; withReadLock([&] { result = _dirtyFlags; @@ -2970,7 +2950,7 @@ void EntityItem::markDirtyFlags(uint32_t mask) { }); } -void EntityItem::clearDirtyFlags(uint32_t mask) { +void EntityItem::clearDirtyFlags(uint32_t mask) { withWriteLock([&] { _dirtyFlags &= ~mask; }); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index c26f1694a9..ce4bf13896 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -240,6 +240,7 @@ public: using SpatiallyNestable::getQueryAACube; virtual AACube getQueryAACube(bool& success) const override; + virtual bool shouldPuffQueryAACube() const override; QString getScript() const; void setScript(const QString& value); @@ -273,6 +274,8 @@ public: inline bool isVisible() const { return getVisible(); } inline bool isInvisible() const { return !getVisible(); } + bool isChildOfMyAvatar() const; + bool getCollisionless() const; void setCollisionless(bool value); @@ -354,20 +357,16 @@ public: virtual void updateRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); void updateParentID(const QUuid& value); - void updatePositionFromNetwork(const glm::vec3& value); void updateDimensions(const glm::vec3& value); void updateRotation(const glm::quat& rotation); - void updateRotationFromNetwork(const glm::quat& rotation); void updateDensity(float value); void updateMass(float value); void updateVelocity(const glm::vec3& value); - void updateVelocityFromNetwork(const glm::vec3& value); void updateDamping(float value); void updateRestitution(float value); void updateFriction(float value); void updateGravity(const glm::vec3& value); void updateAngularVelocity(const glm::vec3& value); - void updateAngularVelocityFromNetwork(const glm::vec3& value); void updateAngularDamping(float value); void updateCollisionless(bool value); void updateCollisionMask(uint8_t value); @@ -629,12 +628,14 @@ protected: glm::vec3 _lastUpdatedVelocityValue; glm::vec3 _lastUpdatedAngularVelocityValue; glm::vec3 _lastUpdatedAccelerationValue; + AACube _lastUpdatedQueryAACubeValue; quint64 _lastUpdatedPositionTimestamp { 0 }; quint64 _lastUpdatedRotationTimestamp { 0 }; quint64 _lastUpdatedVelocityTimestamp { 0 }; quint64 _lastUpdatedAngularVelocityTimestamp { 0 }; quint64 _lastUpdatedAccelerationTimestamp { 0 }; + quint64 _lastUpdatedQueryAACubeTimestamp { 0 }; }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 51ed66bb23..3bbd6ce8e6 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -84,28 +84,11 @@ void EntityItemProperties::setLastEdited(quint64 usecTime) { _lastEdited = usecTime > _created ? usecTime : _created; } -const char* shapeTypeNames[] = { - "none", - "box", - "sphere", - "capsule-x", - "capsule-y", - "capsule-z", - "cylinder-x", - "cylinder-y", - "cylinder-z", - "hull", - "plane", - "compound", - "simple-hull", - "simple-compound", - "static-mesh" -}; QHash stringToShapeTypeLookup; void addShapeType(ShapeType type) { - stringToShapeTypeLookup[shapeTypeNames[type]] = type; + stringToShapeTypeLookup[ShapeInfo::getNameForShapeType(type)] = type; } void buildStringToShapeTypeLookup() { @@ -180,9 +163,7 @@ void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) } QString EntityItemProperties::getShapeTypeAsString() const { - if (_shapeType < sizeof(shapeTypeNames) / sizeof(char *)) - return QString(shapeTypeNames[_shapeType]); - return QString(shapeTypeNames[SHAPE_TYPE_NONE]); + return ShapeInfo::getNameForShapeType(_shapeType); } void EntityItemProperties::setShapeTypeFromString(const QString& shapeName) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 39f19323e3..ed7a1469b3 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -50,6 +50,14 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership connect(nodeList.data(), &NodeList::canRezCertifiedChanged, this, &EntityScriptingInterface::canRezCertifiedChanged); connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged); connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged); + + // If the user clicks somewhere where there is no entity at all, we will release focus + connect(this, &EntityScriptingInterface::mousePressOffEntity, [=]() { + setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); + }); + + auto& packetReceiver = nodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket"); } void EntityScriptingInterface::queueEntityMessage(PacketType packetType, @@ -457,7 +465,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& // if they've changed. entity->forEachDescendant([&](SpatiallyNestablePointer descendant) { if (descendant->getNestableType() == NestableType::Entity) { - if (descendant->checkAndMaybeUpdateQueryAACube()) { + if (descendant->updateQueryAACube()) { EntityItemPointer entityDescendant = std::static_pointer_cast(descendant); EntityItemProperties newQueryCubeProperties; newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube()); @@ -571,6 +579,48 @@ void EntityScriptingInterface::callEntityServerMethod(QUuid id, const QString& m DependencyManager::get()->callEntityServerMethod(id, method, params); } +void EntityScriptingInterface::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) { + PROFILE_RANGE(script_entities, __FUNCTION__); + auto scriptServerServices = DependencyManager::get(); + + // this won't be available on clients + if (scriptServerServices) { + scriptServerServices->callEntityClientMethod(clientSessionID, entityID, method, params); + } else { + qWarning() << "Entities.callEntityClientMethod() not allowed in client"; + } +} + + +void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode) { + PROFILE_RANGE(script_entities, __FUNCTION__); + + auto nodeList = DependencyManager::get(); + SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer); + + if (entityScriptServer == senderNode) { + auto entityID = QUuid::fromRfc4122(receivedMessage->read(NUM_BYTES_RFC4122_UUID)); + + auto method = receivedMessage->readString(); + + quint16 paramCount; + receivedMessage->readPrimitive(¶mCount); + + QStringList params; + for (int param = 0; param < paramCount; param++) { + auto paramString = receivedMessage->readString(); + params << paramString; + } + + std::lock_guard lock(_entitiesScriptEngineLock); + if (_entitiesScriptEngine) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, method, params, senderNode->getUUID()); + } + } +} + + + QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { PROFILE_RANGE(script_entities, __FUNCTION__); @@ -1628,44 +1678,44 @@ QUuid EntityScriptingInterface::getKeyboardFocusEntity() const { return result; } -void EntityScriptingInterface::setKeyboardFocusEntity(QUuid id) { - QMetaObject::invokeMethod(qApp, "setKeyboardFocusEntity", Qt::QueuedConnection, Q_ARG(QUuid, id)); +void EntityScriptingInterface::setKeyboardFocusEntity(const EntityItemID& id) { + QMetaObject::invokeMethod(qApp, "setKeyboardFocusEntity", Qt::DirectConnection, Q_ARG(EntityItemID, id)); } -void EntityScriptingInterface::sendMousePressOnEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendMousePressOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendMousePressOnEntity(const EntityItemID& id, const PointerEvent& event) { + emit mousePressOnEntity(id, event); } -void EntityScriptingInterface::sendMouseMoveOnEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendMouseMoveOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendMouseMoveOnEntity(const EntityItemID& id, const PointerEvent& event) { + emit mouseMoveOnEntity(id, event); } -void EntityScriptingInterface::sendMouseReleaseOnEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendMouseReleaseOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendMouseReleaseOnEntity(const EntityItemID& id, const PointerEvent& event) { + emit mouseReleaseOnEntity(id, event); } -void EntityScriptingInterface::sendClickDownOnEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendClickDownOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendClickDownOnEntity(const EntityItemID& id, const PointerEvent& event) { + emit clickDownOnEntity(id, event); } -void EntityScriptingInterface::sendHoldingClickOnEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendHoldingClickOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendHoldingClickOnEntity(const EntityItemID& id, const PointerEvent& event) { + emit holdingClickOnEntity(id, event); } -void EntityScriptingInterface::sendClickReleaseOnEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendClickReleaseOnEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendClickReleaseOnEntity(const EntityItemID& id, const PointerEvent& event) { + emit clickReleaseOnEntity(id, event); } -void EntityScriptingInterface::sendHoverEnterEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendHoverEnterEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendHoverEnterEntity(const EntityItemID& id, const PointerEvent& event) { + emit hoverEnterEntity(id, event); } -void EntityScriptingInterface::sendHoverOverEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendHoverOverEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendHoverOverEntity(const EntityItemID& id, const PointerEvent& event) { + emit hoverOverEntity(id, event); } -void EntityScriptingInterface::sendHoverLeaveEntity(QUuid id, PointerEvent event) { - QMetaObject::invokeMethod(qApp, "sendHoverLeaveEntity", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(PointerEvent, event)); +void EntityScriptingInterface::sendHoverLeaveEntity(const EntityItemID& id, const PointerEvent& event) { + emit hoverLeaveEntity(id, event); } bool EntityScriptingInterface::wantsHandControllerPointerEvents(QUuid id) { @@ -1797,4 +1847,4 @@ QString EntityScriptingInterface::computeCertificateID(const QUuid& entityID) { } return result; } -#endif \ No newline at end of file +#endif diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index ee5011e99d..141289884b 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -189,12 +189,15 @@ public slots: Q_INVOKABLE void deleteEntity(QUuid entityID); /**jsdoc - * Call a method on an entity. Allows a script to call a method on an entity's script. - * The method will execute in the entity script engine. If the entity does not have an - * entity script or the method does not exist, this call will have no effect. - * If it is running an entity script (specified by the `script` property) + * Call a method on an entity in the same context as this function is called. Allows a script + * to call a method on an entity's script. The method will execute in the entity script engine. + * If the entity does not have an entity script or the method does not exist, this call will + * have no effect. If it is running an entity script (specified by the `script` property) * and it exposes a property with the specified name `method`, it will be called - * using `params` as the list of arguments. + * using `params` as the list of arguments. If this is called within an entity script, the + * method will be executed on the client in the entity script engine in which it was called. If + * this is called in an entity server script, the method will be executed on the entity server + * script engine. * * @function Entities.callEntityMethod * @param {EntityID} entityID The ID of the entity to call the method on. @@ -218,6 +221,21 @@ public slots: */ Q_INVOKABLE void callEntityServerMethod(QUuid entityID, const QString& method, const QStringList& params = QStringList()); + /**jsdoc + * Call a client method on an entity on a specific client node. Allows a server entity script to call a + * method on an entity's client script for a particular client. The method will execute in the entity script + * engine on that single client. If the entity does not have an entity script or the method does not exist, or + * the client is not connected to the domain, or you attempt to make this call outside of the entity server + * script, this call will have no effect. + * + * @function Entities.callEntityClientMethod + * @param {SessionID} clientSessionID The session ID of the client to call the method on. + * @param {EntityID} entityID The ID of the entity to call the method on. + * @param {string} method The name of the method to call. + * @param {string[]} params The list of parameters to call the specified method with. + */ + Q_INVOKABLE void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params = QStringList()); + /**jsdoc * finds the closest model to the center point, within the radius * will return a EntityItemID.isKnownID = false if no models are in the radius @@ -362,19 +380,19 @@ public slots: Q_INVOKABLE QString getNestableType(QUuid id); Q_INVOKABLE QUuid getKeyboardFocusEntity() const; - Q_INVOKABLE void setKeyboardFocusEntity(QUuid id); + Q_INVOKABLE void setKeyboardFocusEntity(const EntityItemID& id); - Q_INVOKABLE void sendMousePressOnEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendMouseMoveOnEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendMouseReleaseOnEntity(QUuid id, PointerEvent event); + Q_INVOKABLE void sendMousePressOnEntity(const EntityItemID& id, const PointerEvent& event); + Q_INVOKABLE void sendMouseMoveOnEntity(const EntityItemID& id, const PointerEvent& event); + Q_INVOKABLE void sendMouseReleaseOnEntity(const EntityItemID& id, const PointerEvent& event); - Q_INVOKABLE void sendClickDownOnEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendHoldingClickOnEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendClickReleaseOnEntity(QUuid id, PointerEvent event); + Q_INVOKABLE void sendClickDownOnEntity(const EntityItemID& id, const PointerEvent& event); + Q_INVOKABLE void sendHoldingClickOnEntity(const EntityItemID& id, const PointerEvent& event); + Q_INVOKABLE void sendClickReleaseOnEntity(const EntityItemID& id, const PointerEvent& event); - Q_INVOKABLE void sendHoverEnterEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendHoverOverEntity(QUuid id, PointerEvent event); - Q_INVOKABLE void sendHoverLeaveEntity(QUuid id, PointerEvent event); + Q_INVOKABLE void sendHoverEnterEntity(const EntityItemID& id, const PointerEvent& event); + Q_INVOKABLE void sendHoverOverEntity(const EntityItemID& id, const PointerEvent& event); + Q_INVOKABLE void sendHoverLeaveEntity(const EntityItemID& id, const PointerEvent& event); Q_INVOKABLE bool wantsHandControllerPointerEvents(QUuid id); @@ -421,8 +439,11 @@ signals: void canWriteAssetsChanged(bool canWriteAssets); void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + void mouseDoublePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + void mousePressOffEntity(); + void mouseDoublePressOffEntity(); void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); @@ -447,6 +468,10 @@ protected: std::lock_guard lock(_entitiesScriptEngineLock); function(_entitiesScriptEngine); }; + +private slots: + void handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode); + private: bool actionWorker(const QUuid& entityID, std::function actor); bool polyVoxWorker(QUuid entityID, std::function actor); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 4c7795dc75..bde82d96a1 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1029,7 +1029,8 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList EntityTree::sendEntities(EntityEditPacketSender* packetSen addToNeedsParentFixupList(entity); } entity->forceQueryAACubeUpdate(); - entity->checkAndMaybeUpdateQueryAACube(); + entity->updateQueryAACube(); moveOperator.addEntityToMoveList(entity, entity->getQueryAACube()); i++; } else { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 53e36bc7c7..25e36c8ffb 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -89,8 +89,6 @@ public: // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const override { return true; } virtual PacketType expectedDataPacketType() const override { return PacketType::EntityData; } - virtual bool canProcessVersion(PacketVersion thisVersion) const override - { return thisVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS; } virtual bool handlesEditPacketType(PacketType packetType) const override; void fixupTerseEditLogging(EntityItemProperties& properties, QList& changedProperties); virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, @@ -111,9 +109,6 @@ public: virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const override; virtual bool mustIncludeAllChildData() const override { return false; } - virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const override - { return thisVersion >= VERSION_ENTITIES_HAS_FILE_BREAKS; } - virtual void update() override { update(true); } void update(bool simulate); diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 4ba4ad5676..cb17c28fd7 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -102,12 +102,6 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const EntityItemPointer EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead, ReadBitstreamToTreeParams& args) { - if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { - EntityItemID tempEntityID; - EntityItemProperties tempProperties; - return constructEntityItem(Model, tempEntityID, tempProperties); - } - // Header bytes // object ID [16 bytes] // ByteCountCoded(type code) [~1 byte] diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index e1ccf8556b..f4944603f1 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -175,35 +175,12 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - if (args.bitstreamVersion < VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES) { - READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); - - // _diffuseColor has been renamed to _color - READ_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, rgbColor, setColor); - - // Ambient and specular color are from an older format and are no longer supported. - // Their values will be ignored. - READ_ENTITY_PROPERTY(PROP_AMBIENT_COLOR_UNUSED, rgbColor, setIgnoredColor); - READ_ENTITY_PROPERTY(PROP_SPECULAR_COLOR_UNUSED, rgbColor, setIgnoredColor); - - // _constantAttenuation has been renamed to _intensity - READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity); - - // Linear and quadratic attenuation are from an older format and are no longer supported. - // Their values will be ignored. - READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION_UNUSED, float, setIgnoredAttenuation); - READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION_UNUSED, float, setIgnoredAttenuation); - - READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent); - READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff); - } else { - READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); - READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); - READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity); - READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent); - READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff); - READ_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, float, setFalloffRadius); - } + READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); + READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); + READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity); + READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent); + READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff); + READ_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, float, setFalloffRadius); return bytesRead; } diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index a5d259ea87..26f063f7cc 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -111,38 +111,19 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL); - if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { - setCompoundShapeURL(""); - } else { - READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - } - - // Because we're using AnimationLoop which will reset the frame index if you change it's running state - // we want to read these values in the order they appear in the buffer, but call our setters in an - // order that allows AnimationLoop to preserve the correct frame rate. - if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) { - READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setAnimationURL); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setAnimationFPS); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setAnimationCurrentFrame); - READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); - } - + READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) { - READ_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings); - } else { - int bytesFromAnimation; - withWriteLock([&] { - // Note: since we've associated our _animationProperties with our _animationLoop, the readEntitySubclassDataFromBuffer() - // will automatically read into the animation loop - bytesFromAnimation = _animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, animationPropertiesChanged); - }); + int bytesFromAnimation; + withWriteLock([&] { + // Note: since we've associated our _animationProperties with our _animationLoop, the readEntitySubclassDataFromBuffer() + // will automatically read into the animation loop + bytesFromAnimation = _animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, animationPropertiesChanged); + }); - bytesRead += bytesFromAnimation; - dataAt += bytesFromAnimation; - } + bytesRead += bytesFromAnimation; + dataAt += bytesFromAnimation; READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 1a815de632..b216144ded 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -464,76 +464,40 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch const unsigned char* dataAt = data; READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); - // Because we're using AnimationLoop which will reset the frame index if you change it's running state - // we want to read these values in the order they appear in the buffer, but call our setters in an - // order that allows AnimationLoop to preserve the correct frame rate. - if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) { - SKIP_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float); - SKIP_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float); - SKIP_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool); - SKIP_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString); - } else { - READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting); - } - + READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting); READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles); READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan); READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate); - if (args.bitstreamVersion < VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) { - // OLD PROP_EMIT_VELOCITY FAKEOUT - SKIP_ENTITY_PROPERTY(PROP_EMIT_SPEED, glm::vec3); - } - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_MODIFICATIONS) { - READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); - READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); - READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); - READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - if (args.bitstreamVersion < VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) { - // OLD PROP_VELOCITY_SPREAD FAKEOUT - SKIP_ENTITY_PROPERTY(PROP_SPEED_SPREAD, glm::vec3); - } - } else { - // OLD PROP_EMIT_ACCELERATION FAKEOUT - SKIP_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float); - // OLD PROP_ACCELERATION_SPREAD FAKEOUT - SKIP_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float); - READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); - READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - } + READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); + READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); + READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); + READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES) { - READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); - READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); - READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); - } + READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); + READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES) { - READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread); - READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart); - READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish); - READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); - READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); - READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); - READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish); - } + READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread); + READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart); + READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish); + READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); + READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); + READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); + READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish); - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) { - READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed); - READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread); - READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, glm::quat, setEmitOrientation); - READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions); - READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart); - READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart); - READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish); - READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart); - READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish); - } + READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed); + READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread); + READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, glm::quat, setEmitOrientation); + READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions); + READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart); + READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart); + READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish); + READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart); + READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish); - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING) { - READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); - } + READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); return bytesRead; } diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 6e3bdc27a4..9a1a500a54 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -51,6 +51,14 @@ namespace entity { } } +// shapeCalculator is a hook for external code that knows how to configure a ShapeInfo +// for given entity::Shape and dimensions +ShapeEntityItem::ShapeInfoCalculator shapeCalculator = nullptr; + +void ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator callback) { + shapeCalculator = callback; +} + ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { Pointer entity(new ShapeEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); @@ -87,6 +95,7 @@ EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredP } void ShapeEntityItem::setShape(const entity::Shape& shape) { + const entity::Shape prevShape = _shape; _shape = shape; switch (_shape) { case entity::Shape::Cube: @@ -99,6 +108,11 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) { _type = EntityTypes::Shape; break; } + + if (_shape != prevShape) { + // Internally grabs writeLock + markDirtyFlags(Simulation::DIRTY_SHAPE); + } } bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) { @@ -219,6 +233,7 @@ void ShapeEntityItem::debugDump() const { qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " name:" << _name; qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )"; + qCDebug(entities) << " collisionShapeType:" << ShapeInfo::getNameForShapeType(getShapeType()); qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; qCDebug(entities) << " position:" << debugTreeVector(getPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); @@ -233,73 +248,101 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { const glm::vec3 entityDimensions = getDimensions(); - switch (_shape) { - case entity::Shape::Quad: - case entity::Shape::Cube: - { - _collisionShapeType = SHAPE_TYPE_BOX; + switch (_shape){ + case entity::Shape::Quad: { + // Not in GeometryCache::buildShapes, unsupported. + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; + //TODO WL21389: Add a SHAPE_TYPE_QUAD ShapeType and treat + // as a special box (later if desired support) + } + break; + case entity::Shape::Cube: { + _collisionShapeType = SHAPE_TYPE_BOX; + } + break; + case entity::Shape::Sphere: { + + float diameter = entityDimensions.x; + const float MIN_DIAMETER = 0.001f; + const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + if (diameter > MIN_DIAMETER + && fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR + && fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) { + + _collisionShapeType = SHAPE_TYPE_SPHERE; + } else { + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; } - break; - case entity::Shape::Sphere: - { + } + break; + case entity::Shape::Circle: { + _collisionShapeType = SHAPE_TYPE_CIRCLE; + } + break; + case entity::Shape::Cylinder: { + _collisionShapeType = SHAPE_TYPE_CYLINDER_Y; + // TODO WL21389: determine if rotation is axis-aligned + //const Transform::Quat & rot = _transform.getRotation(); - float diameter = entityDimensions.x; - const float MIN_DIAMETER = 0.001f; - const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; - if (diameter > MIN_DIAMETER - && fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR - && fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) { + // TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and + // hull ( or dimensions, need circular cross section) + // Should allow for minor variance along axes? - _collisionShapeType = SHAPE_TYPE_SPHERE; - } else { - _collisionShapeType = SHAPE_TYPE_ELLIPSOID; - } + } + break; + case entity::Shape::Cone: { + if (shapeCalculator) { + shapeCalculator(this, info); + // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL) + _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; + } else { + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; } - break; - case entity::Shape::Cylinder: - { - _collisionShapeType = SHAPE_TYPE_CYLINDER_Y; - // TODO WL21389: determine if rotation is axis-aligned - //const Transform::Quat & rot = _transform.getRotation(); - - // TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and - // hull ( or dimensions, need circular cross section) - // Should allow for minor variance along axes? - - } - break; + } + break; + // gons, ones, & angles built via GeometryCache::extrudePolygon case entity::Shape::Triangle: case entity::Shape::Hexagon: - case entity::Shape::Octagon: - case entity::Shape::Circle: + case entity::Shape::Octagon: { + if (shapeCalculator) { + shapeCalculator(this, info); + // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL) + _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; + } else { + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; + } + } + break; + // hedrons built via GeometryCache::setUpFlatShapes case entity::Shape::Tetrahedron: case entity::Shape::Octahedron: case entity::Shape::Dodecahedron: - case entity::Shape::Icosahedron: - case entity::Shape::Cone: - { - //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later) + case entity::Shape::Icosahedron: { + if ( shapeCalculator ) { + shapeCalculator(this, info); + // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL) + _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; + } else { _collisionShapeType = SHAPE_TYPE_ELLIPSOID; } - break; - case entity::Shape::Torus: - { - // Not in GeometryCache::buildShapes, unsupported. - _collisionShapeType = SHAPE_TYPE_ELLIPSOID; - //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support) - } - break; - default: - { - _collisionShapeType = SHAPE_TYPE_ELLIPSOID; - } - break; + } + break; + case entity::Shape::Torus: { + // Not in GeometryCache::buildShapes, unsupported. + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; + //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support) + } + break; + default: { + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; + } + break; } EntityItem::computeShapeInfo(info); } -// This value specifes how the shape should be treated by physics calculations. +// This value specifies how the shape should be treated by physics calculations. ShapeType ShapeEntityItem::getShapeType() const { return _collisionShapeType; } diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index a20cecb60b..a88a2098e9 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -34,7 +34,6 @@ namespace entity { ::QString stringFromShape(Shape shape); } - class ShapeEntityItem : public EntityItem { using Pointer = std::shared_ptr; static Pointer baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -43,6 +42,9 @@ public: static EntityItemPointer sphereFactory(const EntityItemID& entityID, const EntityItemProperties& properties); static EntityItemPointer boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties); + using ShapeInfoCalculator = std::function; + static void setShapeInfoCalulator(ShapeInfoCalculator callback); + ShapeEntityItem(const EntityItemID& entityItemID); void pureVirtualFunctionPlaceHolder() override { }; diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index d41b22137e..3203c2968c 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -136,7 +136,7 @@ void SimpleEntitySimulation::sortEntitiesThatMoved() { SetOfEntities::iterator itemItr = _entitiesToSort.begin(); while (itemItr != _entitiesToSort.end()) { EntityItemPointer entity = *itemItr; - entity->checkAndMaybeUpdateQueryAACube(); + entity->updateQueryAACube(); ++itemItr; } EntitySimulation::sortEntitiesThatMoved(); diff --git a/libraries/gpu/src/gpu/DrawTextureMirroredX.slf b/libraries/gpu/src/gpu/DrawTextureMirroredX.slf new file mode 100644 index 0000000000..aef4033496 --- /dev/null +++ b/libraries/gpu/src/gpu/DrawTextureMirroredX.slf @@ -0,0 +1,22 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Draw texture 0 fetched at (1.0 - texcoord.x, texcoord.y) +// +// Created by Sam Gondelman on 10/24/2017 +// Copyright 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 +// + + +uniform sampler2D colorMap; + +in vec2 varTexCoord0; +out vec4 outFragColor; + +void main(void) { + outFragColor = texture(colorMap, vec2(1.0 - varTexCoord0.x, varTexCoord0.y)); +} diff --git a/libraries/gpu/src/gpu/StandardShaderLib.cpp b/libraries/gpu/src/gpu/StandardShaderLib.cpp index 756070ff68..7143242618 100755 --- a/libraries/gpu/src/gpu/StandardShaderLib.cpp +++ b/libraries/gpu/src/gpu/StandardShaderLib.cpp @@ -23,6 +23,7 @@ const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple. #include "DrawWhite_frag.h" #include "DrawTexture_frag.h" +#include "DrawTextureMirroredX_frag.h" #include "DrawTextureOpaque_frag.h" #include "DrawColoredTexture_frag.h" @@ -37,6 +38,7 @@ ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS; ShaderPointer StandardShaderLib::_drawNadaPS; ShaderPointer StandardShaderLib::_drawWhitePS; ShaderPointer StandardShaderLib::_drawTexturePS; +ShaderPointer StandardShaderLib::_drawTextureMirroredXPS; ShaderPointer StandardShaderLib::_drawTextureOpaquePS; ShaderPointer StandardShaderLib::_drawColoredTexturePS; StandardShaderLib::ProgramMap StandardShaderLib::_programs; @@ -130,6 +132,13 @@ ShaderPointer StandardShaderLib::getDrawTexturePS() { return _drawTexturePS; } +ShaderPointer StandardShaderLib::getDrawTextureMirroredXPS() { + if (!_drawTextureMirroredXPS) { + _drawTextureMirroredXPS = gpu::Shader::createPixel(std::string(DrawTextureMirroredX_frag)); + } + return _drawTextureMirroredXPS; +} + ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() { if (!_drawTextureOpaquePS) { _drawTextureOpaquePS = gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag)); diff --git a/libraries/gpu/src/gpu/StandardShaderLib.h b/libraries/gpu/src/gpu/StandardShaderLib.h index a21d4dea9a..94885b8ca0 100755 --- a/libraries/gpu/src/gpu/StandardShaderLib.h +++ b/libraries/gpu/src/gpu/StandardShaderLib.h @@ -47,6 +47,7 @@ public: static ShaderPointer getDrawWhitePS(); static ShaderPointer getDrawTexturePS(); + static ShaderPointer getDrawTextureMirroredXPS(); static ShaderPointer getDrawTextureOpaquePS(); static ShaderPointer getDrawColoredTexturePS(); @@ -67,6 +68,7 @@ protected: static ShaderPointer _drawNadaPS; static ShaderPointer _drawWhitePS; static ShaderPointer _drawTexturePS; + static ShaderPointer _drawTextureMirroredXPS; static ShaderPointer _drawTextureOpaquePS; static ShaderPointer _drawColoredTexturePS; diff --git a/libraries/networking/src/EntityScriptClient.cpp b/libraries/networking/src/EntityScriptClient.cpp index 399cb80bfa..75ae7369fb 100644 --- a/libraries/networking/src/EntityScriptClient.cpp +++ b/libraries/networking/src/EntityScriptClient.cpp @@ -92,6 +92,28 @@ void EntityScriptClient::callEntityServerMethod(QUuid entityID, const QString& m } } +void EntityScriptServerServices::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) { + // only valid to call this function if you are the entity script server + auto nodeList = DependencyManager::get(); + SharedNodePointer targetClient = nodeList->nodeWithUUID(clientSessionID); + + if (nodeList->getOwnerType() == NodeType::EntityScriptServer && targetClient) { + auto packetList = NLPacketList::create(PacketType::EntityScriptCallMethod, QByteArray(), true, true); + + packetList->write(entityID.toRfc4122()); + + packetList->writeString(method); + + quint16 paramCount = params.length(); + packetList->writePrimitive(paramCount); + + foreach(const QString& param, params) { + packetList->writeString(param); + } + + nodeList->sendPacketList(std::move(packetList), *targetClient); + } +} MessageID EntityScriptClient::getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback) { auto nodeList = DependencyManager::get(); diff --git a/libraries/networking/src/EntityScriptClient.h b/libraries/networking/src/EntityScriptClient.h index 6f1a0376ea..4cfb03dca7 100644 --- a/libraries/networking/src/EntityScriptClient.h +++ b/libraries/networking/src/EntityScriptClient.h @@ -74,4 +74,11 @@ private: void forceFailureOfPendingRequests(SharedNodePointer node); }; + +class EntityScriptServerServices : public QObject, public Dependency { + Q_OBJECT +public: + void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params); +}; + #endif diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index efb38eede1..ef2768b0af 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -29,9 +29,9 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_STROKE_COLOR_PROPERTY; case PacketType::EntityPhysics: - return VERSION_ENTITIES_HAZE; + return static_cast(EntityVersion::StrokeColorProperty); + case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::JSONFilterWithFamilyTree); case PacketType::AvatarIdentity: @@ -62,6 +62,9 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::DomainServerAddedNode: return static_cast(DomainServerAddedNodeVersion::PermissionsGrid); + case PacketType::EntityScriptCallMethod: + return static_cast(EntityScriptCallMethodVersion::ClientCallable); + case PacketType::MixedAudio: case PacketType::SilentAudioFrame: case PacketType::InjectAudio: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 9e2eb51fdd..9443ee570d 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -194,85 +194,14 @@ void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debuggin uint qHash(const PacketType& key, uint seed); QDebug operator<<(QDebug debug, const PacketType& type); -const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; -const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1; -const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2; -const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3; -const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU; -const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4; -const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5; -const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6; -const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7; -const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8; -const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = 9; -const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10; -const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11; -const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12; -const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED = 13; -const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14; -const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15; -const PacketVersion VERSION_ENTITIES_HAVE_UUIDS = 16; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 17; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE = 18; -const PacketVersion VERSION_ENTITIES_HAVE_NAMES = 19; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_ATMOSPHERE = 20; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_SKYBOX = 21; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_STAGE_HAS_AUTOMATIC_HOURDAY = 22; -const PacketVersion VERSION_ENTITIES_PARTICLE_ENTITIES_HAVE_TEXTURES = 23; -const PacketVersion VERSION_ENTITIES_HAVE_LINE_TYPE = 24; -const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25; -const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26; -const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27; -const PacketVersion VERSION_ENTITIES_PARTICLE_FIX = 28; -const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29; -const PacketVersion VERSION_ENTITIES_FACE_CAMERA = 30; -const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 31; -const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32; -const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE = 33; -const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35; -const PacketVersion VERSION_POLYVOX_TEXTURES = 36; -const PacketVersion VERSION_ENTITIES_POLYLINE = 37; -const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38; -const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39; -const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40; -const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES = 41; -const PacketVersion VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES = 42; -const PacketVersion VERSION_ENTITIES_PROTOCOL_HEADER_SWAP = 43; -const PacketVersion VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER = 44; -const PacketVersion VERSION_ENTITIES_PROTOCOL_CHANNELS = 45; -const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46; -const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47; -const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; -const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; -const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; -const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; -const PacketVersion VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52; -const PacketVersion VERSION_MODEL_ENTITIES_JOINTS_ON_WIRE = 53; -const PacketVersion VERSION_ENTITITES_HAVE_QUERY_BOX = 54; -const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55; -const PacketVersion VERSION_ATMOSPHERE_REMOVED = 56; -const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57; -const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58; -const PacketVersion VERSION_ENTITIES_MORE_SHAPES = 59; -const PacketVersion VERSION_ENTITIES_PROPERLY_ENCODE_SHAPE_EDITS = 60; -const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_STATIC_MESH = 61; -const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SIMPLE_HULLS = 62; -const PacketVersion VERSION_WEB_ENTITIES_SUPPORT_DPI = 63; -const PacketVersion VERSION_ENTITIES_ARROW_ACTION = 64; -const PacketVersion VERSION_ENTITIES_LAST_EDITED_BY = 65; -const PacketVersion VERSION_ENTITIES_SERVER_SCRIPTS = 66; -const PacketVersion VERSION_ENTITIES_PHYSICS_PACKET = 67; -const PacketVersion VERSION_ENTITIES_ZONE_FILTERS = 68; -const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69; -const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70; -const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71; -const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72; -const PacketVersion VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES = 73; -const PacketVersion VERSION_ENTITIES_HAS_CERTIFICATE_PROPERTIES = 74; -const PacketVersion VERSION_ENTITIES_HAZE = 75; -const PacketVersion VERSION_ENTITIES_UV_MODE_PROPERTY = 76; -const PacketVersion VERSION_ENTITIES_STROKE_COLOR_PROPERTY = 77; +enum class EntityVersion : PacketVersion { + StrokeColorProperty = 77 +}; +enum class EntityScriptCallMethodVersion : PacketVersion { + ServerCallable = 18, + ClientCallable = 19 +}; enum class EntityQueryPacketVersion: PacketVersion { JSONFilter = 18, diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index ad16a97bf6..7563122290 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1721,8 +1721,8 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con device->ungetChar(firstChar); if (firstChar == (char) PacketType::EntityData) { - qCDebug(octree) << "Reading from binary SVO Stream length:" << streamLength; - return readSVOFromStream(streamLength, inputStream); + qCWarning(octree) << "Reading from binary SVO no longer supported"; + return false; } else { qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; return readJSONFromStream(streamLength, inputStream, marketplaceID); @@ -1730,137 +1730,6 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con } -bool Octree::readSVOFromStream(uint64_t streamLength, QDataStream& inputStream) { - qWarning() << "SVO file format depricated. Support for reading SVO files is no longer support and will be removed soon."; - - bool fileOk = false; - - PacketVersion gotVersion = 0; - - uint64_t headerLength = 0; // bytes in the header - - bool wantImportProgress = true; - - PacketType expectedType = expectedDataPacketType(); - PacketVersion expectedVersion = versionForPacketType(expectedType); - bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); - - // before reading the file, check to see if this version of the Octree supports file versions - if (getWantSVOfileVersions()) { - - // read just enough of the file to parse the header... - const uint64_t HEADER_LENGTH = sizeof(int) + sizeof(PacketVersion); - unsigned char fileHeader[HEADER_LENGTH]; - inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH); - - headerLength = HEADER_LENGTH; // we need this later to skip to the data - - unsigned char* dataAt = (unsigned char*)&fileHeader; - uint64_t dataLength = HEADER_LENGTH; - - // if so, read the first byte of the file and see if it matches the expected version code - int intPacketType; - memcpy(&intPacketType, dataAt, sizeof(intPacketType)); - PacketType gotType = (PacketType) intPacketType; - - dataAt += sizeof(expectedType); - dataLength -= sizeof(expectedType); - gotVersion = *dataAt; - - if (gotType == expectedType) { - if (canProcessVersion(gotVersion)) { - dataAt += sizeof(gotVersion); - dataLength -= sizeof(gotVersion); - fileOk = true; - qCDebug(octree, "SVO file version match. Expected: %d Got: %d", - versionForPacketType(expectedDataPacketType()), gotVersion); - - hasBufferBreaks = versionHasSVOfileBreaks(gotVersion); - } else { - qCDebug(octree, "SVO file version mismatch. Expected: %d Got: %d", - versionForPacketType(expectedDataPacketType()), gotVersion); - } - } else { - qCDebug(octree) << "SVO file type mismatch. Expected: " << expectedType - << " Got: " << gotType; - } - - } else { - qCDebug(octree) << " NOTE: this file type does not include type and version information."; - fileOk = true; // assume the file is ok - } - - if (hasBufferBreaks) { - qCDebug(octree) << " this version includes buffer breaks"; - } else { - qCDebug(octree) << " this version does not include buffer breaks"; - } - - if (fileOk) { - - // if this version of the file does not include buffer breaks, then we need to load the entire file at once - if (!hasBufferBreaks) { - - // read the entire file into a buffer, WHAT!? Why not. - uint64_t dataLength = streamLength - headerLength; - unsigned char* entireFileDataSection = new unsigned char[dataLength]; - inputStream.readRawData((char*)entireFileDataSection, dataLength); - - unsigned char* dataAt = entireFileDataSection; - - ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, - SharedNodePointer(), wantImportProgress, gotVersion); - - readBitstreamToTree(dataAt, dataLength, args); - delete[] entireFileDataSection; - - } else { - - - uint64_t dataLength = streamLength - headerLength; - uint64_t remainingLength = dataLength; - const uint64_t MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2; - unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH]; - - while (remainingLength > 0) { - quint16 chunkLength = 0; - - inputStream.readRawData((char*)&chunkLength, sizeof(chunkLength)); - remainingLength -= sizeof(chunkLength); - - if (chunkLength > remainingLength) { - qCDebug(octree) << "UNEXPECTED chunk size of:" << chunkLength - << "greater than remaining length:" << remainingLength; - break; - } - - if (chunkLength > MAX_CHUNK_LENGTH) { - qCDebug(octree) << "UNEXPECTED chunk size of:" << chunkLength - << "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH; - break; - } - - inputStream.readRawData((char*)fileChunk, chunkLength); - - remainingLength -= chunkLength; - - unsigned char* dataAt = fileChunk; - uint64_t dataLength = chunkLength; - - ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, - SharedNodePointer(), wantImportProgress, gotVersion); - - readBitstreamToTree(dataAt, dataLength, args); - } - - delete[] fileChunk; - } - } - - - return fileOk; -} - // hack to get the marketplace id into the entities. We will create a way to get this from a hash of // the entity later, but this helps us move things along for now QJsonDocument addMarketplaceIDToDocumentEntities(QJsonDocument& doc, const QString& marketplaceID) { diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index a2df5f44e5..a252011ba0 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -208,8 +208,6 @@ public: // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const { return false; } virtual PacketType expectedDataPacketType() const { return PacketType::Unknown; } - virtual bool canProcessVersion(PacketVersion thisVersion) const { - return thisVersion == versionForPacketType(expectedDataPacketType()); } virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); } virtual bool handlesEditPacketType(PacketType packetType) const { return false; } virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, @@ -222,11 +220,6 @@ public: virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { } virtual bool mustIncludeAllChildData() const { return true; } - /// some versions of the SVO file will include breaks with buffer lengths between each buffer chunk in the SVO - /// file. If the Octree subclass expects this for this particular version of the file, it should override this - /// method and return true. - virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const { return false; } - virtual void update() { } // nothing to do by default OctreeElementPointer getRoot() { return _rootElement; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 7c84017758..6884482074 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -491,6 +491,10 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) { return true; } + if (_entity->shouldSuppressLocationEdits()) { + return false; + } + if (!isLocallyOwned()) { // we don't own the simulation @@ -577,7 +581,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } if (properties.transformChanged()) { - if (_entity->checkAndMaybeUpdateQueryAACube()) { + if (_entity->updateQueryAACube()) { // due to parenting, the server may not know where something is in world-space, so include the bounding cube. properties.setQueryAACube(_entity->getQueryAACube()); } @@ -644,7 +648,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _entity->forEachDescendant([&](SpatiallyNestablePointer descendant) { if (descendant->getNestableType() == NestableType::Entity) { EntityItemPointer entityDescendant = std::static_pointer_cast(descendant); - if (descendant->checkAndMaybeUpdateQueryAACube()) { + if (descendant->updateQueryAACube()) { EntityItemProperties newQueryCubeProperties; newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube()); newQueryCubeProperties.setLastEdited(properties.getLastEdited()); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 81bfbc72b4..0b91ede574 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -66,7 +66,7 @@ class PhysicsEngine; class ObjectMotionState : public btMotionState { public: - // These poroperties of the PhysicsEngine are "global" within the context of all ObjectMotionStates + // These properties of the PhysicsEngine are "global" within the context of all ObjectMotionStates // (assuming just one PhysicsEngine). They are cached as statics for fast calculations in the // ObjectMotionState context. static void setWorldOffset(const glm::vec3& offset); diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 18dfd2317e..cd0fba848a 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -314,6 +314,7 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) shape = new btCylinderShapeZ(btHalfExtents); } break; + case SHAPE_TYPE_CIRCLE: case SHAPE_TYPE_CYLINDER_Y: { const glm::vec3 halfExtents = info.getHalfExtents(); const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); diff --git a/libraries/plugins/src/plugins/DisplayPlugin.cpp b/libraries/plugins/src/plugins/DisplayPlugin.cpp index e43d5e76f3..2a8a72f594 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.cpp +++ b/libraries/plugins/src/plugins/DisplayPlugin.cpp @@ -35,8 +35,8 @@ void DisplayPlugin::waitForPresent() { } } -std::function DisplayPlugin::getHUDOperator() { - std::function hudOperator; +std::function DisplayPlugin::getHUDOperator() { + std::function hudOperator; { QMutexLocker locker(&_presentMutex); hudOperator = _hudOperator; diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 11ca6f754a..efce158864 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -204,7 +204,7 @@ public: void waitForPresent(); - std::function getHUDOperator(); + std::function getHUDOperator(); static const QString& MENU_PATH(); @@ -218,7 +218,7 @@ protected: gpu::ContextPointer _gpuContext; - std::function _hudOperator { std::function() }; + std::function _hudOperator { std::function() }; private: QMutex _presentMutex; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 44e2bd290b..d334a53fa1 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -435,7 +435,7 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I auto lightStage = renderContext->_scene->getStage(); assert(lightStage); assert(lightStage->getNumLights() > 0); - auto lightAndShadow = lightStage->getLightAndShadow(0); + auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; if (globalShadow) { batch.setResourceTexture(Shadow, globalShadow->map); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e6a33a9911..2187cb70b1 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -498,7 +498,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, auto lightStage = renderContext->_scene->getStage(); assert(lightStage); assert(lightStage->getNumLights() > 0); - auto lightAndShadow = lightStage->getLightAndShadow(0); + auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; // Bind the shadow buffer @@ -509,14 +509,21 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, auto& program = deferredLightingEffect->_directionalSkyboxLight; LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations; - auto keyLight = lightStage->getLight(0); + auto keyLight = lightAndShadow.first; + + model::LightPointer keyAmbientLight; + if (lightStage && lightStage->_currentFrame._ambientLights.size()) { + keyAmbientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front()); + } + bool hasAmbientMap = (keyAmbientLight != nullptr); // Setup the global directional pass pipeline { if (deferredLightingEffect->_shadowMapEnabled) { + // If the keylight has an ambient Map then use the Skybox version of the pass // otherwise use the ambient sphere version - if (keyLight->getAmbientMap()) { + if (hasAmbientMap) { program = deferredLightingEffect->_directionalSkyboxLightShadow; locations = deferredLightingEffect->_directionalSkyboxLightShadowLocations; } else { @@ -526,7 +533,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, } else { // If the keylight has an ambient Map then use the Skybox version of the pass // otherwise use the ambient sphere version - if (keyLight->getAmbientMap()) { + if (hasAmbientMap) { program = deferredLightingEffect->_directionalSkyboxLight; locations = deferredLightingEffect->_directionalSkyboxLightLocations; } else { diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index cf8e268681..f35fb9f830 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -52,6 +52,46 @@ //#define WANT_DEBUG +// @note: Originally size entity::NUM_SHAPES +// As of Commit b93e91b9, render-utils no longer retains knowledge of +// entity lib, and thus doesn't know about entity::NUM_SHAPES. Should +// the enumerations be altered, this will need to be updated. +// @see ShapeEntityItem.h +static std::array MAPPING{ { + GeometryCache::Triangle, + GeometryCache::Quad, + GeometryCache::Hexagon, + GeometryCache::Octagon, + GeometryCache::Circle, + GeometryCache::Cube, + GeometryCache::Sphere, + GeometryCache::Tetrahedron, + GeometryCache::Octahedron, + GeometryCache::Dodecahedron, + GeometryCache::Icosahedron, + GeometryCache::Torus, + GeometryCache::Cone, + GeometryCache::Cylinder, +} }; + +static const std::array GEOCACHE_SHAPE_STRINGS{ { + "Line", + "Triangle", + "Quad", + "Hexagon", + "Octagon", + "Circle", + "Cube", + "Sphere", + "Tetrahedron", + "Octahedron", + "Dodecahedron", + "Icosahedron", + "Torus", + "Cone", + "Cylinder" + } }; + const int GeometryCache::UNKNOWN_ID = -1; @@ -69,6 +109,51 @@ static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT; static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3); +void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector &outPointList) { + + auto geometryCache = DependencyManager::get(); + const GeometryCache::Shape geometryShape = GeometryCache::getShapeForEntityShape( entityShape ); + const GeometryCache::ShapeData * shapeData = geometryCache->getShapeData( geometryShape ); + if (!shapeData){ + //--EARLY EXIT--( data isn't ready for some reason... ) + return; + } + + const gpu::BufferView & shapeVerts = shapeData->_positionView; + const gpu::BufferView::Size numItems = shapeVerts.getNumElements(); + + outPointList.reserve((int)numItems); + QVector uniqueVerts; + uniqueVerts.reserve((int)numItems); + + const float MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED = 1.0e-6f; //< 1mm^2 + for (gpu::BufferView::Index i = 0; i < (gpu::BufferView::Index)numItems; ++i) { + const int numUniquePoints = (int)uniqueVerts.size(); + const geometry::Vec &curVert = shapeVerts.get(i); + bool isUniquePoint = true; + + for (int uniqueIndex = 0; uniqueIndex < numUniquePoints; ++uniqueIndex) { + const geometry::Vec knownVert = uniqueVerts[uniqueIndex]; + const float distToKnownPoint = glm::length2(knownVert - curVert); + + if (distToKnownPoint <= MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED) { + isUniquePoint = false; + break; + } + } + + if (!isUniquePoint) { + + //--EARLY ITERATION EXIT-- + continue; + } + + + uniqueVerts.push_back(curVert); + outPointList.push_back(curVert * entityExtents); + } +} + template std::vector polygon() { std::vector result; @@ -85,7 +170,7 @@ void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, c gpu::Buffer::Size offset = vertexBuffer->getSize(); vertexBuffer->append(vertices); - gpu::Buffer::Size viewSize = vertices.size() * 2 * sizeof(glm::vec3); + gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3); _positionView = gpu::BufferView(vertexBuffer, offset, viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT); @@ -441,12 +526,46 @@ void GeometryCache::buildShapes() { extrudePolygon<64>(_shapes[Cone], _shapeVertices, _shapeIndices, true); //Circle drawCircle(_shapes[Circle], _shapeVertices, _shapeIndices); - // Not implememented yet: + // Not implemented yet: //Quad, //Torus, } +const GeometryCache::ShapeData * GeometryCache::getShapeData(const Shape shape) const { + if (((int)shape < 0) || ((int)shape >= (int)_shapes.size())) { + qCWarning(renderutils) << "GeometryCache::getShapeData - Invalid shape " << shape << " specified. Returning default fallback."; + + //--EARLY EXIT--( No valid shape data for shape ) + return nullptr; + } + + return &_shapes[shape]; +} + +GeometryCache::Shape GeometryCache::getShapeForEntityShape(int entityShape) { + if ((entityShape < 0) || (entityShape >= (int)MAPPING.size())) { + qCWarning(renderutils) << "GeometryCache::getShapeForEntityShape - Invalid shape " << entityShape << " specified. Returning default fallback."; + + //--EARLY EXIT--( fall back to default assumption ) + return GeometryCache::Sphere; + } + + return MAPPING[entityShape]; +} + +QString GeometryCache::stringFromShape(GeometryCache::Shape geoShape) +{ + if (((int)geoShape < 0) || ((int)geoShape >= (int)GeometryCache::NUM_SHAPES)) { + qCWarning(renderutils) << "GeometryCache::stringFromShape - Invalid shape " << geoShape << " specified."; + + //--EARLY EXIT-- + return "INVALID_GEOCACHE_SHAPE"; + } + + return GEOCACHE_SHAPE_STRINGS[geoShape]; +} + gpu::Stream::FormatPointer& getSolidStreamFormat() { if (!SOLID_STREAM_FORMAT) { SOLID_STREAM_FORMAT = std::make_shared(); // 1 for everyone diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 5a437cf5e9..cd8c43f1df 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -147,6 +147,16 @@ public: NUM_SHAPES, }; + /// @param entityShapeEnum: The entity::Shape enumeration for the shape + /// whose GeometryCache::Shape is desired. + /// @return GeometryCache::NUM_SHAPES in the event of an error; otherwise, + /// the GeometryCache::Shape enum which aligns with the + /// specified entityShapeEnum + static GeometryCache::Shape getShapeForEntityShape(int entityShapeEnum); + static QString stringFromShape(GeometryCache::Shape geoShape); + + static void computeSimpleHullPointListForShape(int entityShape, const glm::vec3 &entityExtents, QVector &outPointList); + static uint8_t CUSTOM_PIPELINE_NUMBER; static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key); static void registerShapePipeline() { @@ -355,15 +365,21 @@ public: using VShape = std::array; - VShape _shapes; + /// returns ShapeData associated with the specified shape, + /// otherwise nullptr in the event of an error. + const ShapeData * getShapeData(Shape shape) const; private: + GeometryCache(); virtual ~GeometryCache(); void buildShapes(); typedef QPair IntPair; typedef QPair VerticesIndices; + + + VShape _shapes; gpu::PipelinePointer _standardDrawPipeline; gpu::PipelinePointer _standardDrawPipelineNoBlend; diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index f9eca755f2..77c820e093 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -138,7 +138,8 @@ void main(void) { } // Mix with background at far range - if (distance > 32000.0) { + const float BLEND_DISTANCE = 27000.0; + if (distance > BLEND_DISTANCE) { outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlendValue); } else { outFragColor = potentialFragColor; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index d0e9f2467e..079c63f367 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -142,6 +142,11 @@ LightStage::LightPointer LightStage::removeLight(Index index) { LightPointer removed = _lights.freeElement(index); if (removed) { + auto shadowId = _descs[index].shadowId; + // Remove shadow if one exists for this light + if (shadowId != INVALID_INDEX) { + _shadows.freeElement(shadowId); + } _lightMap.erase(removed); _descs[index] = Desc(); } diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index f946cf699e..66d73c9a6e 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -116,6 +116,30 @@ public: return LightAndShadow(getLight(lightId), getShadow(lightId)); } + LightPointer getCurrentKeyLight() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return _lights.get(keyLightId); + } + + ShadowPointer getCurrentKeyShadow() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return getShadow(keyLightId); + } + + LightAndShadow getCurrentKeyLightAndShadow() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return LightAndShadow(getLight(keyLightId), getShadow(keyLightId)); + } + LightStage(); Lights _lights; LightMap _lightMap; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 964a1961d6..97f62a3ce0 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -235,7 +235,6 @@ void Model::updateRenderItems() { self->updateClusterMatrices(); Transform modelTransform = self->getTransform(); - Transform physicsTransform = modelTransform; modelTransform.setScale(glm::vec3(1.0f)); uint32_t deleteGeometryCounter = self->_deleteGeometryCounter; @@ -259,13 +258,12 @@ void Model::updateRenderItems() { }); } - // collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset Transform collisionMeshOffset; collisionMeshOffset.setIdentity(); foreach(auto itemID, self->_collisionRenderItemsMap.keys()) { - transaction.updateItem(itemID, [physicsTransform, collisionMeshOffset](MeshPartPayload& data) { + transaction.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { // update the model transform for this render item. - data.updateTransform(physicsTransform, collisionMeshOffset); + data.updateTransform(modelTransform, collisionMeshOffset); }); } diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index ca67347ecf..e3f4ff2b7f 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -31,6 +31,8 @@ using namespace render; +#define OUTLINE_USE_SCISSOR false + OutlineRessources::OutlineRessources() { } @@ -122,6 +124,15 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con outputs = expandRect(outlinedRect, blurPixelWidth+1, framebufferSize); outlinedRect = expandRect(outputs, blurPixelWidth+1, framebufferSize); + // Clear the framebuffer without stereo + // Needs to be distinct from the other batch because using the clear call + // while stereo is enabled triggers a warning + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + batch.setFramebuffer(ressources->getDepthFramebuffer()); + batch.clearDepthFramebuffer(1.0f); + }); + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -133,9 +144,10 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con args->getViewFrustum().evalProjectionMatrix(projMat); args->getViewFrustum().evalViewTransform(viewMat); +#if OUTLINE_USE_SCISSOR batch.setStateScissorRect(outlinedRect); +#endif batch.setFramebuffer(ressources->getDepthFramebuffer()); - batch.clearDepthFramebuffer(1.0f, true); // Setup camera, projection and viewport for all items batch.setViewportTransform(args->_viewport); @@ -282,7 +294,6 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - batch.enableStereo(false); batch.setFramebuffer(destinationFrameBuffer); batch.setViewportTransform(args->_viewport); @@ -290,7 +301,9 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I batch.resetViewTransform(); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); batch.setPipeline(pipeline); +#if OUTLINE_USE_SCISSOR batch.setStateScissorRect(outlineRect); +#endif batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); @@ -307,7 +320,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(gpu::State::DepthTest(false, false)); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - state->setScissorEnable(true); + state->setScissorEnable(OUTLINE_USE_SCISSOR); auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto ps = gpu::Shader::createPixel(std::string(Outline_frag)); @@ -355,9 +368,10 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - batch.enableStereo(false); batch.setViewportTransform(args->_viewport); +#if OUTLINE_USE_SCISSOR batch.setStateScissorRect(outlineRect); +#endif const auto geometryBuffer = DependencyManager::get(); @@ -392,7 +406,7 @@ void DebugOutline::initializePipelines() { auto state = std::make_shared(); state->setDepthTest(gpu::State::DepthTest(false)); - state->setScissorEnable(true); + state->setScissorEnable(OUTLINE_USE_SCISSOR); const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); @@ -448,7 +462,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); - state->setScissorEnable(true); + state->setScissorEnable(OUTLINE_USE_SCISSOR); initMaskPipelines(*shapePlumber, state); } auto sharedParameters = std::make_shared(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 55e2d06d15..63936b0809 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -458,7 +458,7 @@ void CompositeHUD::run(const RenderContextPointer& renderContext) { // Grab the HUD texture gpu::doInBatch(renderContext->args->_context, [&](gpu::Batch& batch) { if (renderContext->args->_hudOperator) { - renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture); + renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture, renderContext->args->_renderMode == RenderArgs::RenderMode::MIRROR_RENDER_MODE); } }); } diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index d32857bc65..7171543abc 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -33,10 +33,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, auto lightStage = renderContext->_scene->getStage(); assert(lightStage); - LightStage::Index globalLightIndex { 0 }; - const auto globalLight = lightStage->getLight(globalLightIndex); - const auto shadow = lightStage->getShadow(globalLightIndex); + const auto shadow = lightStage->getCurrentKeyShadow(); if (!shadow) return; const auto& fbo = shadow->framebuffer; @@ -128,20 +126,22 @@ void RenderShadowTask::configure(const Config& configuration) { void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) { auto lightStage = renderContext->_scene->getStage(); assert(lightStage); - const auto globalShadow = lightStage->getShadow(0); - // Cache old render args - RenderArgs* args = renderContext->args; - output = args->_renderMode; + const auto globalShadow = lightStage->getCurrentKeyShadow(); + if (globalShadow) { + // Cache old render args + RenderArgs* args = renderContext->args; + output = args->_renderMode; - auto nearClip = args->getViewFrustum().getNearClip(); - float nearDepth = -args->_boomOffset.z; - const int SHADOW_FAR_DEPTH = 20; - globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH); + auto nearClip = args->getViewFrustum().getNearClip(); + float nearDepth = -args->_boomOffset.z; + const int SHADOW_FAR_DEPTH = 20; + globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH); - // Set the keylight render args - args->pushViewFrustum(*(globalShadow->getFrustum())); - args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; + // Set the keylight render args + args->pushViewFrustum(*(globalShadow->getFrustum())); + args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; + } } void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) { diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index a76b60ffe6..627d4f17b2 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -122,7 +122,7 @@ namespace render { render::ScenePointer _scene; int8_t _cameraMode { -1 }; - std::function _hudOperator; + std::function _hudOperator; gpu::TexturePointer _hudTexture; }; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 98846c5213..6fbcd6a794 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -97,7 +97,6 @@ static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) int functionSignatureMetaID = qRegisterMetaType(); -Q_DECLARE_METATYPE(ScriptEnginePointer) int scriptEnginePointerMetaID = qRegisterMetaType(); Q_LOGGING_CATEGORY(scriptengineScript, "hifi.scriptengine.script") diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index db159e7265..17c0e0713a 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -55,6 +55,8 @@ static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900; class ScriptEngines; +Q_DECLARE_METATYPE(ScriptEnginePointer) + class CallbackData { public: QScriptValue function; diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index a556548b25..36ce38335a 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -15,9 +15,38 @@ #include "NumericalConstants.h" // for MILLIMETERS_PER_METER +// Originally within EntityItemProperties.cpp +const char* shapeTypeNames[] = { + "none", + "box", + "sphere", + "capsule-x", + "capsule-y", + "capsule-z", + "cylinder-x", + "cylinder-y", + "cylinder-z", + "hull", + "plane", + "compound", + "simple-hull", + "simple-compound", + "static-mesh" +}; + +static const size_t SHAPETYPE_NAME_COUNT = (sizeof(shapeTypeNames) / sizeof((shapeTypeNames)[0])); + // Bullet doesn't support arbitrarily small shapes const float MIN_HALF_EXTENT = 0.005f; // 0.5 cm +QString ShapeInfo::getNameForShapeType(ShapeType type) { + if (((int)type <= 0) || ((int)type >= (int)SHAPETYPE_NAME_COUNT)) { + type = (ShapeType)0; + } + + return shapeTypeNames[(int)type]; +} + void ShapeInfo::clear() { _url.clear(); _pointCollection.clear(); @@ -29,7 +58,6 @@ void ShapeInfo::clear() { } void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { - //TODO WL21389: Does this need additional cases and handling added? _url = ""; _type = type; setHalfExtents(halfExtents); @@ -38,6 +66,7 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString _halfExtents = glm::vec3(0.0f); break; case SHAPE_TYPE_BOX: + case SHAPE_TYPE_HULL: break; case SHAPE_TYPE_SPHERE: { float radius = glm::length(halfExtents) / SQUARE_ROOT_OF_3; @@ -45,7 +74,13 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString _halfExtents = glm::vec3(radius); } break; + case SHAPE_TYPE_CIRCLE: { + _halfExtents = glm::vec3(_halfExtents.x, MIN_HALF_EXTENT, _halfExtents.z); + } + break; case SHAPE_TYPE_COMPOUND: + case SHAPE_TYPE_SIMPLE_HULL: + case SHAPE_TYPE_SIMPLE_COMPOUND: case SHAPE_TYPE_STATIC_MESH: _url = QUrl(url); break; @@ -56,9 +91,6 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString } void ShapeInfo::setBox(const glm::vec3& halfExtents) { - //TODO WL21389: Should this pointlist clearance added in case - // this is a re-purposed instance? - // See https://github.com/highfidelity/hifi/pull/11024#discussion_r128885491 _url = ""; _type = SHAPE_TYPE_BOX; setHalfExtents(halfExtents); @@ -66,7 +98,6 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) { } void ShapeInfo::setSphere(float radius) { - //TODO WL21389: See comment in setBox regarding clearance _url = ""; _type = SHAPE_TYPE_SPHERE; radius = glm::max(radius, MIN_HALF_EXTENT); @@ -75,14 +106,11 @@ void ShapeInfo::setSphere(float radius) { } void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) { - //TODO WL21389: May need to skip resetting type here. _pointCollection = pointCollection; - _type = (_pointCollection.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; _doubleHashKey.clear(); } void ShapeInfo::setCapsuleY(float radius, float halfHeight) { - //TODO WL21389: See comment in setBox regarding clearance _url = ""; _type = SHAPE_TYPE_CAPSULE_Y; radius = glm::max(radius, MIN_HALF_EXTENT); @@ -123,8 +151,15 @@ int ShapeInfo::getLargestSubshapePointCount() const { return numPoints; } +float computeCylinderVolume(const float radius, const float height) { + return PI * radius * radius * 2.0f * height; +} + +float computeCapsuleVolume(const float radius, const float cylinderHeight) { + return PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f); +} + float ShapeInfo::computeVolume() const { - //TODO WL21389: Add support for other ShapeTypes( CYLINDER_X, CYLINDER_Y, etc). const float DEFAULT_VOLUME = 1.0f; float volume = DEFAULT_VOLUME; switch(_type) { @@ -137,17 +172,37 @@ float ShapeInfo::computeVolume() const { volume = 4.0f * PI * _halfExtents.x * _halfExtents.y * _halfExtents.z / 3.0f; break; } + case SHAPE_TYPE_CYLINDER_X: { + volume = computeCylinderVolume(_halfExtents.y, _halfExtents.x); + break; + } case SHAPE_TYPE_CYLINDER_Y: { - float radius = _halfExtents.x; - volume = PI * radius * radius * 2.0f * _halfExtents.y; + volume = computeCylinderVolume(_halfExtents.x, _halfExtents.y); + break; + } + case SHAPE_TYPE_CYLINDER_Z: { + volume = computeCylinderVolume(_halfExtents.x, _halfExtents.z); + break; + } + case SHAPE_TYPE_CAPSULE_X: { + // Need to offset halfExtents.x by y to account for the system treating + // the x extent of the capsule as the cylindrical height + spherical radius. + const float cylinderHeight = 2.0f * (_halfExtents.x - _halfExtents.y); + volume = computeCapsuleVolume(_halfExtents.y, cylinderHeight); break; } case SHAPE_TYPE_CAPSULE_Y: { - float radius = _halfExtents.x; // Need to offset halfExtents.y by x to account for the system treating // the y extent of the capsule as the cylindrical height + spherical radius. - float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x); - volume = PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f); + const float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x); + volume = computeCapsuleVolume(_halfExtents.x, cylinderHeight); + break; + } + case SHAPE_TYPE_CAPSULE_Z: { + // Need to offset halfExtents.z by x to account for the system treating + // the z extent of the capsule as the cylindrical height + spherical radius. + const float cylinderHeight = 2.0f * (_halfExtents.z - _halfExtents.x); + volume = computeCapsuleVolume(_halfExtents.x, cylinderHeight); break; } default: @@ -158,7 +213,6 @@ float ShapeInfo::computeVolume() const { } bool ShapeInfo::contains(const glm::vec3& point) const { - //TODO WL21389: Add support for other ShapeTypes like Ellipsoid/Compound. switch(_type) { case SHAPE_TYPE_SPHERE: return glm::length(point) <= _halfExtents.x; @@ -203,7 +257,6 @@ bool ShapeInfo::contains(const glm::vec3& point) const { } const DoubleHashKey& ShapeInfo::getHash() const { - //TODO WL21389: Need to include the pointlist for SIMPLE_HULL in hash // NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance. if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) { bool useOffset = glm::length2(_offset) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET; @@ -214,52 +267,103 @@ const DoubleHashKey& ShapeInfo::getHash() const { uint32_t primeIndex = 0; _doubleHashKey.computeHash((uint32_t)_type, primeIndex++); - // compute hash1 - uint32_t hash = _doubleHashKey.getHash(); - for (int j = 0; j < 3; ++j) { - // NOTE: 0.49f is used to bump the float up almost half a millimeter - // so the cast to int produces a round() effect rather than a floor() - hash ^= DoubleHashKey::hashFunction( + if (_type != SHAPE_TYPE_SIMPLE_HULL) { + // compute hash1 + uint32_t hash = _doubleHashKey.getHash(); + for (int j = 0; j < 3; ++j) { + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + hash ^= DoubleHashKey::hashFunction( (uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f), primeIndex++); - if (useOffset) { - hash ^= DoubleHashKey::hashFunction( + if (useOffset) { + hash ^= DoubleHashKey::hashFunction( (uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f), primeIndex++); + } } - } - _doubleHashKey.setHash(hash); + _doubleHashKey.setHash(hash); - // compute hash2 - hash = _doubleHashKey.getHash2(); - for (int j = 0; j < 3; ++j) { - // NOTE: 0.49f is used to bump the float up almost half a millimeter - // so the cast to int produces a round() effect rather than a floor() - uint32_t floatHash = DoubleHashKey::hashFunction2( + // compute hash2 + hash = _doubleHashKey.getHash2(); + for (int j = 0; j < 3; ++j) { + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + uint32_t floatHash = DoubleHashKey::hashFunction2( (uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f)); - if (useOffset) { - floatHash ^= DoubleHashKey::hashFunction2( + if (useOffset) { + floatHash ^= DoubleHashKey::hashFunction2( (uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f)); + } + hash += ~(floatHash << 17); + hash ^= (floatHash >> 11); + hash += (floatHash << 4); + hash ^= (floatHash >> 7); + hash += ~(floatHash << 10); + hash = (hash << 16) | (hash >> 16); } - hash += ~(floatHash << 17); - hash ^= (floatHash >> 11); - hash += (floatHash << 4); - hash ^= (floatHash >> 7); - hash += ~(floatHash << 10); - hash = (hash << 16) | (hash >> 16); - } - _doubleHashKey.setHash2(hash); + _doubleHashKey.setHash2(hash); + } else { - if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_STATIC_MESH) { - QString url = _url.toString(); - if (!url.isEmpty()) { - // fold the urlHash into both parts - QByteArray baUrl = url.toLocal8Bit(); - const char *cUrl = baUrl.data(); - uint32_t urlHash = qChecksum(cUrl, baUrl.count()); - _doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash); - _doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash); + assert(_pointCollection.size() == (size_t)1); + const PointList & points = _pointCollection.back(); + const int numPoints = (int)points.size(); + uint32_t hash = _doubleHashKey.getHash(); + uint32_t hash2 = _doubleHashKey.getHash2(); + + for (int pointIndex = 0; pointIndex < numPoints; ++pointIndex) { + // compute hash1 & 2 + const glm::vec3 &curPoint = points[pointIndex]; + for (int vecCompIndex = 0; vecCompIndex < 3; ++vecCompIndex) { + + // NOTE: 0.49f is used to bump the float up almost half a millimeter + // so the cast to int produces a round() effect rather than a floor() + uint32_t valueToHash = (uint32_t)(curPoint[vecCompIndex] * MILLIMETERS_PER_METER + copysignf(1.0f, curPoint[vecCompIndex]) * 0.49f); + + hash ^= DoubleHashKey::hashFunction(valueToHash, primeIndex++); + uint32_t floatHash = DoubleHashKey::hashFunction2(valueToHash); + + if (useOffset) { + + const uint32_t offsetValToHash = (uint32_t)(_offset[vecCompIndex] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[vecCompIndex])* 0.49f); + + hash ^= DoubleHashKey::hashFunction(offsetValToHash, primeIndex++); + floatHash ^= DoubleHashKey::hashFunction2(offsetValToHash); + } + + hash2 += ~(floatHash << 17); + hash2 ^= (floatHash >> 11); + hash2 += (floatHash << 4); + hash2 ^= (floatHash >> 7); + hash2 += ~(floatHash << 10); + hash2 = (hash2 << 16) | (hash2 >> 16); + } } + + _doubleHashKey.setHash(hash); + _doubleHashKey.setHash2(hash2); + } + + QString url = _url.toString(); + if (!url.isEmpty()) { + // fold the urlHash into both parts + QByteArray baUrl = url.toLocal8Bit(); + uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size()); + _doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash); + _doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash); + } + + uint32_t numHulls = 0; + if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) { + numHulls = (uint32_t)_pointCollection.size(); + } else if (_type == SHAPE_TYPE_SIMPLE_HULL) { + numHulls = 1; + } + if (numHulls > 0) { + uint32_t hash = DoubleHashKey::hashFunction(numHulls, primeIndex++); + _doubleHashKey.setHash(_doubleHashKey.getHash() ^ hash); + hash = DoubleHashKey::hashFunction2(numHulls); + _doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ hash); } } return _doubleHashKey; diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 0ffdf1310d..d658b936a3 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -46,7 +46,8 @@ enum ShapeType { SHAPE_TYPE_SIMPLE_HULL, SHAPE_TYPE_SIMPLE_COMPOUND, SHAPE_TYPE_STATIC_MESH, - SHAPE_TYPE_ELLIPSOID + SHAPE_TYPE_ELLIPSOID, + SHAPE_TYPE_CIRCLE }; class ShapeInfo { @@ -57,6 +58,8 @@ public: using PointCollection = QVector; using TriangleIndices = QVector; + static QString getNameForShapeType(ShapeType type); + void clear(); void setParams(ShapeType type, const glm::vec3& halfExtents, QString url=""); @@ -66,7 +69,7 @@ public: void setCapsuleY(float radius, float halfHeight); void setOffset(const glm::vec3& offset); - int getType() const { return _type; } + ShapeType getType() const { return _type; } const glm::vec3& getHalfExtents() const { return _halfExtents; } const glm::vec3& getOffset() const { return _offset; } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 8c43632456..8dbd2dd5e0 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -963,35 +963,41 @@ AACube SpatiallyNestable::getMaximumAACube(bool& success) const { const float PARENTED_EXPANSION_FACTOR = 3.0f; -bool SpatiallyNestable::checkAndMaybeUpdateQueryAACube() { - bool success = false; - AACube maxAACube = getMaximumAACube(success); - if (success) { - // maybe update _queryAACube - if (!_queryAACubeSet || (_parentID.isNull() && _children.size() == 0) || !_queryAACube.contains(maxAACube)) { - if (_parentJointIndex != INVALID_JOINT_INDEX || _children.size() > 0 ) { - // make an expanded AACube centered on the object - float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale(); - _queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale); - } else { - _queryAACube = maxAACube; - } - - forEachDescendant([&](const SpatiallyNestablePointer& descendant) { - bool childSuccess; - AACube descendantAACube = descendant->getQueryAACube(childSuccess); - if (childSuccess) { - if (_queryAACube.contains(descendantAACube)) { - return ; - } - _queryAACube += descendantAACube.getMinimumPoint(); - _queryAACube += descendantAACube.getMaximumPoint(); - } - }); - _queryAACubeSet = true; - } +bool SpatiallyNestable::updateQueryAACube() { + if (!queryAACubeNeedsUpdate()) { + return false; } - return success; + + bool success; + AACube maxAACube = getMaximumAACube(success); + if (!success) { + return false; + } + + if (shouldPuffQueryAACube()) { + // make an expanded AACube centered on the object + float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale(); + _queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale); + _queryAACubeIsPuffed = true; + } else { + _queryAACube = maxAACube; + _queryAACubeIsPuffed = false; + } + + forEachDescendant([&](const SpatiallyNestablePointer& descendant) { + bool childSuccess; + AACube descendantAACube = descendant->getQueryAACube(childSuccess); + if (childSuccess) { + if (_queryAACube.contains(descendantAACube)) { + return; // from lambda + } + _queryAACube += descendantAACube.getMinimumPoint(); + _queryAACube += descendantAACube.getMaximumPoint(); + } + }); + + _queryAACubeSet = true; + return true; } void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) { @@ -1008,6 +1014,16 @@ bool SpatiallyNestable::queryAACubeNeedsUpdate() const { return true; } + bool success; + AACube maxAACube = getMaximumAACube(success); + if (success && !_queryAACube.contains(maxAACube)) { + return true; + } + + if (shouldPuffQueryAACube() != _queryAACubeIsPuffed) { + return true; + } + // make sure children are still in their boxes, also. bool childNeedsUpdate = false; forEachDescendantTest([&](const SpatiallyNestablePointer& descendant) { @@ -1021,31 +1037,6 @@ bool SpatiallyNestable::queryAACubeNeedsUpdate() const { return childNeedsUpdate; } -void SpatiallyNestable::updateQueryAACube() { - bool success; - AACube maxAACube = getMaximumAACube(success); - if (_parentJointIndex != INVALID_JOINT_INDEX || _children.size() > 0 ) { - // make an expanded AACube centered on the object - float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale(); - _queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale); - } else { - _queryAACube = maxAACube; - } - - forEachDescendant([&](const SpatiallyNestablePointer& descendant) { - bool success; - AACube descendantAACube = descendant->getQueryAACube(success); - if (success) { - if (_queryAACube.contains(descendantAACube)) { - return; - } - _queryAACube += descendantAACube.getMinimumPoint(); - _queryAACube += descendantAACube.getMaximumPoint(); - } - }); - _queryAACubeSet = true; -} - AACube SpatiallyNestable::getQueryAACube(bool& success) const { if (_queryAACubeSet) { success = true; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index b6be4dc056..37f6cfdfd9 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -106,11 +106,11 @@ public: virtual glm::vec3 getParentAngularVelocity(bool& success) const; virtual AACube getMaximumAACube(bool& success) const; - bool checkAndMaybeUpdateQueryAACube(); - void updateQueryAACube(); virtual void setQueryAACube(const AACube& queryAACube); virtual bool queryAACubeNeedsUpdate() const; + virtual bool shouldPuffQueryAACube() const { return false; } + bool updateQueryAACube(); void forceQueryAACubeUpdate() { _queryAACubeSet = false; } virtual AACube getQueryAACube(bool& success) const; virtual AACube getQueryAACube() const; @@ -234,6 +234,7 @@ private: glm::vec3 _angularVelocity; mutable bool _parentKnowsMe { false }; bool _isDead { false }; + bool _queryAACubeIsPuffed { false }; }; diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp index 68c99a9753..ce7dd18921 100644 --- a/libraries/shared/src/TriangleSet.cpp +++ b/libraries/shared/src/TriangleSet.cpp @@ -104,8 +104,9 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersectionInternal(const glm::vec if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) { // if our bounding box intersects at a distance greater than the current known - // best distance, than we can safely not check any of our triangles - if (boxDistance > bestDistance) { + // best distance, and our origin isn't inside the boounds, then we can safely + // not check any of our triangles + if (boxDistance > bestDistance && !_bounds.contains(origin)) { return false; } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 8646bee3ca..ecd07a5874 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -1082,37 +1082,7 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid } } -static void forEachKeyboard(QQuickItem* parent, std::function function) { - if (!function) { - return; - } - - auto keyboards = parent->findChildren("keyboard"); - - for (auto keyboardObject : keyboards) { - auto keyboard = qobject_cast(keyboardObject); - if (keyboard) { - function(keyboard); - } - } -} - -static const int TEXTINPUT_PASSWORD = 2; - -static QQuickItem* getTopmostParent(QQuickItem* item) { - QObject* itemObject = item; - while (itemObject) { - if (itemObject->parent()) { - itemObject = itemObject->parent(); - } else { - break; - } - } - - return qobject_cast (itemObject); -} - -void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) { +void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric, bool passwordField) { #if Q_OS_ANDROID return; #endif @@ -1128,21 +1098,6 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n return; } - auto echoMode = item->property("echoMode"); - bool isPasswordField = echoMode.isValid() && echoMode.toInt() == TEXTINPUT_PASSWORD; - - // we need to somehow pass 'isPasswordField' to visible keyboard so it will change its 'mirror text' to asterixes - // the issue in some cases there might be more than one keyboard in object tree and it is hard to understand which one is being used at the moment - // unfortunately attempts to check for visibility failed becuase visibility is not updated yet. So... I don't see other way than just update properties for all the keyboards - - auto topmostParent = getTopmostParent(item); - if (topmostParent) { - forEachKeyboard(topmostParent, [&](QQuickItem* keyboard) { - keyboard->setProperty("mirroredText", QVariant::fromValue(QString(""))); - keyboard->setProperty("password", isPasswordField); - }); - } - // for future probably makes sense to consider one of the following: // 1. make keyboard a singleton, which will be dynamically re-parented before showing // 2. track currently visible keyboard somewhere, allow to subscribe for this signal @@ -1153,15 +1108,15 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox"; if (item->property("keyboardRaised").isValid()) { - forEachKeyboard(item, [&](QQuickItem* keyboard) { - keyboard->setProperty("mirroredText", QVariant::fromValue(QString(""))); - keyboard->setProperty("password", isPasswordField); - }); // FIXME - HMD only: Possibly set value of "keyboardEnabled" per isHMDMode() for use in WebView.qml. if (item->property("punctuationMode").isValid()) { item->setProperty("punctuationMode", QVariant(numeric)); } + if (item->property("passwordField").isValid()) { + item->setProperty("passwordField", QVariant(passwordField)); + } + item->setProperty("keyboardRaised", QVariant(raised)); return; } @@ -1186,9 +1141,13 @@ void OffscreenQmlSurface::emitWebEvent(const QVariant& message) { const QString RAISE_KEYBOARD = "_RAISE_KEYBOARD"; const QString RAISE_KEYBOARD_NUMERIC = "_RAISE_KEYBOARD_NUMERIC"; const QString LOWER_KEYBOARD = "_LOWER_KEYBOARD"; + const QString RAISE_KEYBOARD_NUMERIC_PASSWORD = "_RAISE_KEYBOARD_NUMERIC_PASSWORD"; + const QString RAISE_KEYBOARD_PASSWORD = "_RAISE_KEYBOARD_PASSWORD"; QString messageString = message.type() == QVariant::String ? message.toString() : ""; if (messageString.left(RAISE_KEYBOARD.length()) == RAISE_KEYBOARD) { - setKeyboardRaised(_currentFocusItem, true, messageString == RAISE_KEYBOARD_NUMERIC); + bool numeric = (messageString == RAISE_KEYBOARD_NUMERIC || messageString == RAISE_KEYBOARD_NUMERIC_PASSWORD); + bool passwordField = (messageString == RAISE_KEYBOARD_PASSWORD || messageString == RAISE_KEYBOARD_NUMERIC_PASSWORD); + setKeyboardRaised(_currentFocusItem, true, numeric, passwordField); } else if (messageString == LOWER_KEYBOARD) { setKeyboardRaised(_currentFocusItem, false); } else { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 74eafe9f13..12ee9e59a1 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -82,7 +82,7 @@ public: QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget); bool eventFilter(QObject* originalDestination, QEvent* event) override; - void setKeyboardRaised(QObject* object, bool raised, bool numeric = false); + void setKeyboardRaised(QObject* object, bool raised, bool numeric = false, bool passwordField = false); Q_INVOKABLE void synthesizeKeyPress(QString key, QObject* targetOverride = nullptr); using TextureAndFence = std::pair; diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index ee2db6f6e0..e34855d521 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -119,6 +119,7 @@ Script.include("/~/system/libraries/controllers.js"); this.actionID = null; // action this script created... this.entityWithContextOverlay = false; this.contextOverlayTimer = false; + this.previousCollisionStatus = false; this.reticleMinX = MARGIN; this.reticleMaxX; this.reticleMinY = MARGIN; @@ -342,7 +343,9 @@ Script.include("/~/system/libraries/controllers.js"); if (this.madeDynamic) { var props = {}; props.dynamic = false; + props.collisionless = this.previousCollisionStatus; props.localVelocity = {x: 0, y: 0, z: 0}; + props.localRotation = {x: 0, y: 0, z: 0}; Entities.editEntity(this.grabbedThingID, props); this.madeDynamic = false; } @@ -507,10 +510,12 @@ Script.include("/~/system/libraries/controllers.js"); if (entityIsGrabbable(targetProps)) { if (!entityIsDistanceGrabbable(targetProps)) { targetProps.dynamic = true; + this.previousCollisionStatus = targetProps.collisionless; + targetProps.collisionless = true; Entities.editEntity(entityID, targetProps); this.madeDynamic = true; } - + if (!this.distanceRotating) { this.grabbedThingID = entityID; this.grabbedDistance = rayPickInfo.distance; diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index b1e5599dc6..a015eed714 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1373,7 +1373,7 @@ function loaded() { elShape.addEventListener('change', createEmitTextPropertyUpdateFunction('shape')); elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl')); - elWebDPI.addEventListener('change', createEmitNumberPropertyUpdateFunction('dpi')); + elWebDPI.addEventListener('change', createEmitNumberPropertyUpdateFunction('dpi', 0)); elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL')); elShapeType.addEventListener('change', createEmitTextPropertyUpdateFunction('shapeType')); diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 88d1e627c3..3a422bcb8a 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -3,7 +3,7 @@ // examples // // Created by Brad hefta-Gaub on 10/1/14. -// Modified by Daniela Fontes @DanielaFifo and Tiago Andrade @TagoWill on 4/7/2017 +// Modified by Daniela Fontes * @DanielaFifo and Tiago Andrade @TagoWill on 4/7/2017 // Copyright 2014 High Fidelity, Inc. // // This script implements a class useful for building tools for editing entities. @@ -203,6 +203,7 @@ SelectionManager = (function() { print("ERROR: entitySelectionTool.update got exception: " + JSON.stringify(e)); } } + }; return that; @@ -1422,11 +1423,11 @@ SelectionDisplay = (function() { Overlays.editOverlay(rollHandle, { scale: handleSize }); - var pos = Vec3.sum(grabberMoveUpPosition, { - x: 0, - y: Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3, - z: 0 - }); + var upDiff = Vec3.multiply(( + Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3), + Quat.getUp(MyAvatar.orientation) + ); + var pos = Vec3.sum(grabberMoveUpPosition, upDiff); Overlays.editOverlay(grabberMoveUp, { position: pos, scale: handleSize / 1.25 @@ -2099,10 +2100,11 @@ SelectionDisplay = (function() { }); var grabberMoveUpOffset = 0.1; + var upVec = Quat.getUp(MyAvatar.orientation); grabberMoveUpPosition = { - x: position.x, - y: position.y + worldTop + grabberMoveUpOffset, - z: position.z + x: position.x + (grabberMoveUpOffset + worldTop) * upVec.x , + y: position.y+ (grabberMoveUpOffset + worldTop) * upVec.y, + z: position.z + (grabberMoveUpOffset + worldTop) * upVec.z }; Overlays.editOverlay(grabberMoveUp, { visible: (!activeTool) || isActiveTool(grabberMoveUp) @@ -2416,9 +2418,6 @@ SelectionDisplay = (function() { mode: "TRANSLATE_UP_DOWN", onBegin: function(event, pickRay, pickResult) { upDownPickNormal = Quat.getForward(lastCameraOrientation); - // Remove y component so the y-axis lies along the plane we're picking on - this will - // give movements that follow the mouse. - upDownPickNormal.y = 0; lastXYPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal); SelectionManager.saveProperties(); @@ -2455,11 +2454,17 @@ SelectionDisplay = (function() { var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal); var vector = Vec3.subtract(newIntersection, lastXYPick); + + // project vector onto avatar up vector + // we want the avatar referential not the camera. + var avatarUpVector = Quat.getUp(MyAvatar.orientation); + var dotVectorUp = Vec3.dot(vector, avatarUpVector); + vector = Vec3.multiply(dotVectorUp, avatarUpVector); + + vector = grid.snapToGrid(vector); - // we only care about the Y axis - vector.x = 0; - vector.z = 0; + var wantDebug = false; if (wantDebug) { diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 6880d10c18..3bf6435a25 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -74,8 +74,8 @@ itemName: 'Test Flaregun', itemPrice: (debugError ? 10 : 17), itemHref: 'http://mpassets.highfidelity.com/0d90d21c-ce7a-4990-ad18-e9d2cf991027-v1/flaregun.json', - }, - canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified + categories: ["Wearables", "Miscellaneous"] + } }); } } @@ -115,7 +115,6 @@ if (url === MARKETPLACE_PURCHASES_QML_PATH) { tablet.sendToQml({ method: 'updatePurchases', - canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified, referrerURL: referrerURL, filterText: filterText }); @@ -136,9 +135,10 @@ function setCertificateInfo(currentEntityWithContextOverlay, itemCertificateId) { wireEventBridge(true); + var certificateId = itemCertificateId || (Entities.getEntityProperties(currentEntityWithContextOverlay, ['certificateID']).certificateID + "\n"); tablet.sendToQml({ method: 'inspectionCertificate_setCertificateId', - certificateId: itemCertificateId || Entities.getEntityProperties(currentEntityWithContextOverlay, ['certificateID']).certificateID + certificateId: certificateId }); } @@ -203,8 +203,7 @@ tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); tablet.sendToQml({ method: 'updateCheckoutQML', - params: parsedJsonMessage, - canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified + params: parsedJsonMessage }); } else if (parsedJsonMessage.type === "REQUEST_SETTING") { sendCommerceSettings(); diff --git a/tests/gpu-test/src/TestInstancedShapes.cpp b/tests/gpu-test/src/TestInstancedShapes.cpp index 6a98ee58b9..da50f8521f 100644 --- a/tests/gpu-test/src/TestInstancedShapes.cpp +++ b/tests/gpu-test/src/TestInstancedShapes.cpp @@ -10,18 +10,18 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat(); -static const size_t TYPE_COUNT = 4; -static const size_t ITEM_COUNT = 50; -static const float SHAPE_INTERVAL = (PI * 2.0f) / ITEM_COUNT; -static const float ITEM_INTERVAL = SHAPE_INTERVAL / TYPE_COUNT; - -static GeometryCache::Shape SHAPE[TYPE_COUNT] = { +static GeometryCache::Shape SHAPE[] = { GeometryCache::Icosahedron, GeometryCache::Cube, GeometryCache::Sphere, GeometryCache::Tetrahedron, }; +static const size_t TYPE_COUNT = (sizeof(SHAPE) / sizeof((SHAPE)[0])); +static const size_t ITEM_COUNT = 50; +static const float SHAPE_INTERVAL = (PI * 2.0f) / ITEM_COUNT; +static const float ITEM_INTERVAL = SHAPE_INTERVAL / TYPE_COUNT; + const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA }; @@ -34,8 +34,6 @@ TestInstancedShapes::TestInstancedShapes() { static const float ITEM_RADIUS = 20; static const vec3 ITEM_TRANSLATION { 0, 0, -ITEM_RADIUS }; for (size_t i = 0; i < TYPE_COUNT; ++i) { - GeometryCache::Shape shape = SHAPE[i]; - GeometryCache::ShapeData shapeData = geometryCache->_shapes[shape]; //indirectCommand._count float startingInterval = ITEM_INTERVAL * i; std::vector typeTransforms; @@ -62,7 +60,12 @@ void TestInstancedShapes::renderTest(size_t testId, RenderArgs* args) { batch.setInputFormat(getInstancedSolidStreamFormat()); for (size_t i = 0; i < TYPE_COUNT; ++i) { GeometryCache::Shape shape = SHAPE[i]; - GeometryCache::ShapeData shapeData = geometryCache->_shapes[shape]; + const GeometryCache::ShapeData *shapeData = geometryCache->getShapeData( shape ); + if (!shapeData) { + + //--EARLY ITERATION EXIT--( didn't have shape data yet ) + continue; + } std::string namedCall = __FUNCTION__ + std::to_string(i); @@ -71,13 +74,13 @@ void TestInstancedShapes::renderTest(size_t testId, RenderArgs* args) { batch.setModelTransform(transforms[i][j]); batch.setupNamedCalls(namedCall, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData&) { batch.setInputBuffer(gpu::Stream::COLOR, gpu::BufferView(colorBuffer, i * ITEM_COUNT * 4, colorBuffer->getSize(), COLOR_ELEMENT)); - shapeData.drawInstances(batch, ITEM_COUNT); + shapeData->drawInstances(batch, ITEM_COUNT); }); } //for (size_t j = 0; j < ITEM_COUNT; ++j) { // batch.setModelTransform(transforms[j + i * ITEM_COUNT]); - // shapeData.draw(batch); + // shapeData->draw(batch); //} } } diff --git a/unpublishedScripts/marketplace/stopwatch/models/Stopwatch-min-hand.fbx b/unpublishedScripts/marketplace/stopwatch/models/Stopwatch-min-hand.fbx deleted file mode 100644 index b504da13bd..0000000000 Binary files a/unpublishedScripts/marketplace/stopwatch/models/Stopwatch-min-hand.fbx and /dev/null differ diff --git a/unpublishedScripts/marketplace/stopwatch/models/Stopwatch-sec-hand.fbx b/unpublishedScripts/marketplace/stopwatch/models/Stopwatch-sec-hand.fbx deleted file mode 100644 index 12aa85f126..0000000000 Binary files a/unpublishedScripts/marketplace/stopwatch/models/Stopwatch-sec-hand.fbx and /dev/null differ diff --git a/unpublishedScripts/marketplace/stopwatch/models/Stopwatch.fbx b/unpublishedScripts/marketplace/stopwatch/models/Stopwatch.fbx deleted file mode 100644 index 073544875e..0000000000 Binary files a/unpublishedScripts/marketplace/stopwatch/models/Stopwatch.fbx and /dev/null differ diff --git a/unpublishedScripts/marketplace/stopwatch/models/transparent-box.fbx b/unpublishedScripts/marketplace/stopwatch/models/transparent-box.fbx deleted file mode 100644 index b1df7d962c..0000000000 Binary files a/unpublishedScripts/marketplace/stopwatch/models/transparent-box.fbx and /dev/null differ diff --git a/unpublishedScripts/marketplace/stopwatch/sounds/chime.wav b/unpublishedScripts/marketplace/stopwatch/sounds/chime.wav deleted file mode 100644 index cd7143eeeb..0000000000 Binary files a/unpublishedScripts/marketplace/stopwatch/sounds/chime.wav and /dev/null differ diff --git a/unpublishedScripts/marketplace/stopwatch/sounds/tick.wav b/unpublishedScripts/marketplace/stopwatch/sounds/tick.wav deleted file mode 100644 index 21781f8ce4..0000000000 Binary files a/unpublishedScripts/marketplace/stopwatch/sounds/tick.wav and /dev/null differ diff --git a/unpublishedScripts/marketplace/stopwatch/spawnStopwatch.js b/unpublishedScripts/marketplace/stopwatch/spawnStopwatch.js deleted file mode 100644 index 3a0a8a506b..0000000000 --- a/unpublishedScripts/marketplace/stopwatch/spawnStopwatch.js +++ /dev/null @@ -1,89 +0,0 @@ -// -// spawnStopwatch.js -// -// Created by Ryan Huffman on 1/20/17. -// Copyright 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 -// - -var forward = Quat.getFront(MyAvatar.orientation); -Vec3.print("Forward: ", forward); -var positionToSpawn = Vec3.sum(MyAvatar.position, Vec3.multiply(3, forward)); -var scale = 0.5; -positionToSpawn.y += 0.5; - -var stopwatchID = Entities.addEntity({ - type: "Model", - name: "stopwatch/base", - position: positionToSpawn, - modelURL: Script.resolvePath("models/Stopwatch.fbx"), - dimensions: Vec3.multiply(scale, {"x":4.129462242126465,"y":1.058512806892395,"z":5.773681640625}), - rotation: Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)) -}); - -var secondHandID = Entities.addEntity({ - type: "Model", - name: "stopwatch/seconds", - parentID: stopwatchID, - localPosition: Vec3.multiply(scale, {"x":-0.004985813982784748,"y":0.39391064643859863,"z":0.8312804698944092}), - dimensions: Vec3.multiply(scale, {"x":0.14095762372016907,"y":0.02546107769012451,"z":1.6077008247375488}), - registrationPoint: {"x":0.5,"y":0.5,"z":1}, - modelURL: Script.resolvePath("models/Stopwatch-sec-hand.fbx"), -}); - -var minuteHandID = Entities.addEntity({ - type: "Model", - name: "stopwatch/minutes", - parentID: stopwatchID, - localPosition: Vec3.multiply(scale, {"x":-0.0023056098725646734,"y":0.3308190703392029,"z":0.21810021996498108}), - dimensions: Vec3.multiply(scale, {"x":0.045471154153347015,"y":0.015412690117955208,"z":0.22930574417114258}), - registrationPoint: {"x":0.5,"y":0.5,"z":1}, - modelURL: Script.resolvePath("models/Stopwatch-min-hand.fbx"), -}); - -var startStopButtonID = Entities.addEntity({ - type: "Model", - name: "stopwatch/startStop", - parentID: stopwatchID, - dimensions: Vec3.multiply(scale, { x: 0.8, y: 0.8, z: 1.0 }), - localPosition: Vec3.multiply(scale, { x: 0, y: -0.1, z: -2.06 }), - modelURL: Script.resolvePath("models/transparent-box.fbx") -}); - -var resetButtonID = Entities.addEntity({ - type: "Model", - name: "stopwatch/startStop", - parentID: stopwatchID, - dimensions: Vec3.multiply(scale, { x: 0.6, y: 0.6, z: 0.8 }), - localPosition: Vec3.multiply(scale, { x: -1.5, y: -0.1, z: -1.2 }), - localRotation: Quat.fromVec3Degrees({ x: 0, y: 36, z: 0 }), - modelURL: Script.resolvePath("models/transparent-box.fbx") -}); - -Entities.editEntity(stopwatchID, { - userData: JSON.stringify({ - secondHandID: secondHandID, - minuteHandID: minuteHandID - }), - serverScripts: Script.resolvePath("stopwatchServer.js") -}); - -Entities.editEntity(startStopButtonID, { - userData: JSON.stringify({ - stopwatchID: stopwatchID, - grabbableKey: { wantsTrigger: true } - }), - script: Script.resolvePath("stopwatchStartStop.js") -}); - -Entities.editEntity(resetButtonID, { - userData: JSON.stringify({ - stopwatchID: stopwatchID, - grabbableKey: { wantsTrigger: true } - }), - script: Script.resolvePath("stopwatchReset.js") -}); - -Script.stop() diff --git a/unpublishedScripts/marketplace/stopwatch/stopwatchReset.js b/unpublishedScripts/marketplace/stopwatch/stopwatchReset.js deleted file mode 100644 index b65c1e7340..0000000000 --- a/unpublishedScripts/marketplace/stopwatch/stopwatchReset.js +++ /dev/null @@ -1,22 +0,0 @@ -// -// stopwatchReset.js -// -// Created by David Rowe on 26 May 2017. -// Copyright 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 -// - -(function () { - this.preload = function (entityID) { - var properties = Entities.getEntityProperties(entityID, "userData"); - this.messageChannel = "STOPWATCH-" + JSON.parse(properties.userData).stopwatchID; - }; - function click() { - Messages.sendMessage(this.messageChannel, "reset"); - } - this.startNearTrigger = click; - this.startFarTrigger = click; - this.clickDownOnEntity = click; -}); diff --git a/unpublishedScripts/marketplace/stopwatch/stopwatchServer.js b/unpublishedScripts/marketplace/stopwatch/stopwatchServer.js deleted file mode 100644 index 6ae1b69087..0000000000 --- a/unpublishedScripts/marketplace/stopwatch/stopwatchServer.js +++ /dev/null @@ -1,132 +0,0 @@ -// -// stopwatchServer.js -// -// Created by Ryan Huffman on 1/20/17. -// Copyright 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 -// - -(function() { - var self = this; - - self.equipped = false; - self.isActive = false; - self.seconds = 0; - - self.secondHandID = null; - self.minuteHandID = null; - - self.tickSound = SoundCache.getSound(Script.resolvePath("sounds/tick.wav")); - self.tickInjector = null; - self.tickIntervalID = null; - - self.chimeSound = SoundCache.getSound(Script.resolvePath("sounds/chime.wav")); - - self.preload = function(entityID) { - print("Preloading stopwatch: ", entityID); - self.entityID = entityID; - self.messageChannel = "STOPWATCH-" + entityID; - - var userData = Entities.getEntityProperties(self.entityID, 'userData').userData; - var data = JSON.parse(userData); - self.secondHandID = data.secondHandID; - self.minuteHandID = data.minuteHandID; - - self.resetTimer(); - - Messages.subscribe(self.messageChannel); - Messages.messageReceived.connect(this, self.messageReceived); - }; - self.unload = function() { - print("Unloading stopwatch:", self.entityID); - self.resetTimer(); - Messages.unsubscribe(self.messageChannel); - Messages.messageReceived.disconnect(this, self.messageReceived); - }; - self.messageReceived = function(channel, message, sender) { - print("Message received", channel, sender, message); - if (channel === self.messageChannel) { - switch (message) { - case "startStop": - if (self.isActive) { - self.stopTimer(); - } else { - self.startTimer(); - } - break; - case "reset": - self.stopTimer(); - self.resetTimer(); - break; - } - } - }; - self.getStopwatchPosition = function() { - return Entities.getEntityProperties(self.entityID, "position").position; - }; - self.resetTimer = function() { - print("Resetting stopwatch"); - Entities.editEntity(self.secondHandID, { - localRotation: Quat.fromPitchYawRollDegrees(0, 0, 0), - angularVelocity: { x: 0, y: 0, z: 0 }, - }); - Entities.editEntity(self.minuteHandID, { - localRotation: Quat.fromPitchYawRollDegrees(0, 0, 0), - angularVelocity: { x: 0, y: 0, z: 0 }, - }); - self.seconds = 0; - }; - self.startTimer = function() { - print("Starting stopwatch"); - if (!self.tickInjector) { - self.tickInjector = Audio.playSound(self.tickSound, { - position: self.getStopwatchPosition(), - volume: 0.7, - loop: true - }); - } else { - self.tickInjector.restart(); - } - - self.tickIntervalID = Script.setInterval(function() { - if (self.tickInjector) { - self.tickInjector.setOptions({ - position: self.getStopwatchPosition(), - volume: 0.7, - loop: true - }); - } - self.seconds++; - const degreesPerTick = -360 / 60; - Entities.editEntity(self.secondHandID, { - localRotation: Quat.fromPitchYawRollDegrees(0, self.seconds * degreesPerTick, 0), - }); - - if (self.seconds % 60 == 0) { - Entities.editEntity(self.minuteHandID, { - localRotation: Quat.fromPitchYawRollDegrees(0, (self.seconds / 60) * degreesPerTick, 0), - }); - Audio.playSound(self.chimeSound, { - position: self.getStopwatchPosition(), - volume: 1.0, - loop: false - }); - } - }, 1000); - - self.isActive = true; - }; - self.stopTimer = function () { - print("Stopping stopwatch"); - if (self.tickInjector) { - self.tickInjector.stop(); - } - if (self.tickIntervalID !== null) { - Script.clearInterval(self.tickIntervalID); - self.tickIntervalID = null; - } - self.isActive = false; - }; -}); diff --git a/unpublishedScripts/marketplace/stopwatch/stopwatchStartStop.js b/unpublishedScripts/marketplace/stopwatch/stopwatchStartStop.js deleted file mode 100644 index 88c037ee36..0000000000 --- a/unpublishedScripts/marketplace/stopwatch/stopwatchStartStop.js +++ /dev/null @@ -1,23 +0,0 @@ -// -// stopwatchStartStop.js -// -// Created by David Rowe on 26 May 2017. -// Copyright 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 -// - -(function () { - var messageChannel; - this.preload = function (entityID) { - var properties = Entities.getEntityProperties(entityID, "userData"); - this.messageChannel = "STOPWATCH-" + JSON.parse(properties.userData).stopwatchID; - }; - function click() { - Messages.sendMessage(this.messageChannel, "startStop"); - } - this.startNearTrigger = click; - this.startFarTrigger = click; - this.clickDownOnEntity = click; -});