diff --git a/interface/resources/qml/TabletBrowser.qml b/interface/resources/qml/TabletBrowser.qml index 85fff59207..2650102b27 100644 --- a/interface/resources/qml/TabletBrowser.qml +++ b/interface/resources/qml/TabletBrowser.qml @@ -1,5 +1,5 @@ import QtQuick 2.5 -import QtQuick.Controls 1.2 +import QtQuick.Controls 1.4 import QtWebChannel 1.0 import QtWebEngine 1.2 @@ -7,7 +7,7 @@ import "controls" import "styles" as HifiStyles import "styles-uit" import "windows" -import HFWebEngineProfile 1.0 +import HFTabletWebEngineProfile 1.0 Item { id: root @@ -27,138 +27,103 @@ Item { x: 0 y: 0 - - function goBack() { - webview.goBack(); - } - - function goForward() { - webview.goForward(); - } - - function gotoPage(url) { - webview.url = url; - } function setProfile(profile) { webview.profile = profile; } - function reloadPage() { - webview.reloadAndBypassCache(); - webview.setActiveFocusOnPress(true); - webview.setEnabled(true); + QtObject { + id: eventBridgeWrapper + WebChannel.id: "eventBridgeWrapper" + property var eventBridge; } - Item { - id:item + WebEngineView { + id: webview + objectName: "webEngineView" + x: 0 + y: 0 width: parent.width - implicitHeight: parent.height + height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height - - QtObject { - id: eventBridgeWrapper - WebChannel.id: "eventBridgeWrapper" - property var eventBridge; + profile: HFTabletWebEngineProfile { + id: webviewTabletProfile + storageName: "qmlTabletWebEngine" } - WebEngineView { - id: webview - objectName: "webEngineView" - x: 0 - y: 0 - width: parent.width - height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height - - profile: HFWebEngineProfile { - id: webviewProfile - storageName: "qmlWebEngine" - } + property string userScriptUrl: "" - property string userScriptUrl: "" - - // creates a global EventBridge object. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // detects when to raise and lower virtual keyboard - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - // User script. - WebEngineScript { - id: userScript - sourceUrl: webview.userScriptUrl - injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. - worldId: WebEngineScript.MainWorld - } + // creates a global EventBridge object. + WebEngineScript { + id: createGlobalEventBridge + sourceCode: eventBridgeJavaScriptToInject + injectionPoint: WebEngineScript.DocumentCreation + worldId: WebEngineScript.MainWorld + } - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] - - property string newUrl: "" - - webChannel.registeredObjects: [eventBridgeWrapper] + // detects when to raise and lower virtual keyboard + WebEngineScript { + id: raiseAndLowerKeyboard + injectionPoint: WebEngineScript.Deferred + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" + worldId: WebEngineScript.MainWorld + } - Component.onCompleted: { - // Ensure the JS from the web-engine makes it to our logging - webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { - console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); - }); - - webview.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface"; - web.address = url; - } - - onFeaturePermissionRequested: { - grantFeaturePermission(securityOrigin, feature, true); - } + // User script. + WebEngineScript { + id: userScript + sourceUrl: webview.userScriptUrl + injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. + worldId: WebEngineScript.MainWorld + } - onLoadingChanged: { - keyboardRaised = false; - punctuationMode = false; - keyboard.resetShiftMode(false); - - // Required to support clicking on "hifi://" links - if (WebEngineView.LoadStartedStatus == loadRequest.status) { - var url = loadRequest.url.toString(); - if (urlHandler.canHandleUrl(url)) { - if (urlHandler.handleUrl(url)) { - root.stop(); - } + userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] + + property string newUrl: "" + + webChannel.registeredObjects: [eventBridgeWrapper] + + Component.onCompleted: { + // Ensure the JS from the web-engine makes it to our logging + webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { + console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); + }); + + webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36"; + web.address = url; + } + + onFeaturePermissionRequested: { + grantFeaturePermission(securityOrigin, feature, true); + } + + onLoadingChanged: { + keyboardRaised = false; + punctuationMode = false; + keyboard.resetShiftMode(false); + + // Required to support clicking on "hifi://" links + if (WebEngineView.LoadStartedStatus == loadRequest.status) { + var url = loadRequest.url.toString(); + if (urlHandler.canHandleUrl(url)) { + if (urlHandler.handleUrl(url)) { + root.stop(); } } } + } - onNewViewRequested: { - var component = Qt.createComponent("./TabletBrowser.qml"); - - if (component.status != Component.Ready) { - if (component.status == Component.Error) { - console.log("Error: " + component.errorString()); - } - return; - } - var newWindow = component.createObject(); - newWindow.setProfile(webview.profile); - request.openIn(newWindow.webView); - newWindow.eventBridge = web.eventBridge; - stackRoot.push(newWindow); - newWindow.webView.forceActiveFocus(); - + onNavigationRequested: { + if (request.navigationType == WebEngineNavigationRequest.LinkClickedNavigation) { + pagesModel.append({webUrl: request.url.toString()}) } } - - } // item - - + + onNewViewRequested: { + request.openIn(webView); + } + } + Keys.onPressed: { switch(event.key) { case Qt.Key_L: @@ -171,4 +136,4 @@ Item { } } - } // dialog +} diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index 742ab2d333..50d6e1c504 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import QtWebEngine 1.1 +import QtWebEngine 1.2 import QtWebChannel 1.0 import "../controls-uit" as HiFiControls import "../styles" as HifiStyles @@ -14,17 +14,20 @@ Item { height: parent.height property var parentStackItem: null property int headerHeight: 38 - property alias url: root.url - property string address: url - property alias scriptURL: root.userScriptUrl + property string url + property string address: url //for compatibility + property string scriptURL property alias eventBridge: eventBridgeWrapper.eventBridge property bool keyboardEnabled: HMD.active property bool keyboardRaised: false property bool punctuationMode: false property bool isDesktop: false - property WebEngineView view: root + property WebEngineView view: loader.currentView + property int currentPage: -1 // used as a model for repeater + property alias pagesModel: pagesModel + Row { id: buttons HifiConstants { id: hifi } @@ -37,29 +40,29 @@ Item { anchors.leftMargin: 8 HiFiGlyphs { id: back; - enabled: true; + enabled: currentPage > 0 text: hifi.glyphs.backward color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText size: 48 - MouseArea { anchors.fill: parent; onClicked: stackRoot.goBack() } + MouseArea { anchors.fill: parent; onClicked: goBack() } } HiFiGlyphs { id: forward; - enabled: stackRoot.currentItem.canGoForward; + enabled: currentPage < pagesModel.count - 1 text: hifi.glyphs.forward color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText size: 48 - MouseArea { anchors.fill: parent; onClicked: stackRoot.currentItem.goForward() } + MouseArea { anchors.fill: parent; onClicked: goForward() } } HiFiGlyphs { id: reload; - enabled: true; - text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload + enabled: view != null; + text: (view !== null && view.loading) ? hifi.glyphs.close : hifi.glyphs.reload color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText size: 48 - MouseArea { anchors.fill: parent; onClicked: stackRoot.currentItem.reloadPage(); } + MouseArea { anchors.fill: parent; onClicked: reloadPage(); } } } @@ -86,7 +89,7 @@ Item { } //root.hidePermissionsBar(); web.keyboardRaised = false; - stackRoot.currentItem.gotoPage(text); + gotoPage(text); break; @@ -94,157 +97,78 @@ Item { } } + ListModel { + id: pagesModel + onCountChanged: { + currentPage = count - 1 + } + } + function goBack() { + if (currentPage > 0) { + currentPage--; + } + } + + function goForward() { + if (currentPage < pagesModel.count - 1) { + currentPage++; + } + } + + function gotoPage(url) { + pagesModel.append({webUrl: url}) + } + + function reloadPage() { + view.reloadAndBypassCache() + view.setActiveFocusOnPress(true); + view.setEnabled(true); + } + + onCurrentPageChanged: { + if (currentPage >= 0 && currentPage < pagesModel.count && loader.item !== null) { + loader.item.url = pagesModel.get(currentPage).webUrl + } + } + + onUrlChanged: { + gotoPage(url) + } + + QtObject { + id: eventBridgeWrapper + WebChannel.id: "eventBridgeWrapper" + property var eventBridge; + } + + Loader { + id: loader + + property WebEngineView currentView: null - StackView { - id: stackRoot width: parent.width height: parent.height - web.headerHeight + asynchronous: true anchors.top: buttons.bottom - //property var goBack: currentItem.goBack(); - property WebEngineView view: root - - initialItem: root; - - function goBack() { - if (depth > 1 ) { - if (currentItem.canGoBack) { - currentItem.goBack(); - } else { - stackRoot.pop(); - currentItem.webView.focus = true; - currentItem.webView.forceActiveFocus(); - web.address = currentItem.webView.url; - } - } else { - if (currentItem.canGoBack) { - currentItem.goBack(); - } else if (parentStackItem) { - web.parentStackItem.pop(); + active: false + source: "../TabletBrowser.qml" + onStatusChanged: { + if (loader.status === Loader.Ready) { + currentView = item.webView + item.webView.userScriptUrl = web.scriptURL + if (currentPage >= 0) { + //we got something to load already + item.url = pagesModel.get(currentPage).webUrl } } } - - QtObject { - id: eventBridgeWrapper - WebChannel.id: "eventBridgeWrapper" - property var eventBridge; - } - - WebEngineView { - id: root - objectName: "webEngineView" - x: 0 - y: 0 - width: parent.width - height: keyboardEnabled && keyboardRaised ? (parent.height - keyboard.height) : parent.height - profile: HFTabletWebEngineProfile { - id: webviewTabletProfile - storageName: "qmlTabletWebEngine" - } - - property WebEngineView webView: root - function reloadPage() { - root.reload(); - } - - function gotoPage(url) { - root.url = url; - } - - property string userScriptUrl: "" - - // creates a global EventBridge object. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // detects when to raise and lower virtual keyboard - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - // User script. - WebEngineScript { - id: userScript - sourceUrl: root.userScriptUrl - injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] - - property string newUrl: "" - - webChannel.registeredObjects: [eventBridgeWrapper] - - Component.onCompleted: { - // Ensure the JS from the web-engine makes it to our logging - root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { - console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); - }); - - root.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36" - - } - - onFeaturePermissionRequested: { - grantFeaturePermission(securityOrigin, feature, true); - } - - onLoadingChanged: { - keyboardRaised = false; - punctuationMode = false; - keyboard.resetShiftMode(false); - // Required to support clicking on "hifi://" links - if (WebEngineView.LoadStartedStatus == loadRequest.status) { - var url = loadRequest.url.toString(); - if (urlHandler.canHandleUrl(url)) { - if (urlHandler.handleUrl(url)) { - root.stop(); - } - } - } - } - - onNewViewRequested:{ - var component = Qt.createComponent("../TabletBrowser.qml"); - if (component.status != Component.Ready) { - if (component.status == Component.Error) { - console.log("Error: " + component.errorString()); - } - return; - } - var newWindow = component.createObject(); - newWindow.setProfile(root.profile); - request.openIn(newWindow.webView); - newWindow.eventBridge = web.eventBridge; - stackRoot.push(newWindow); - } - } - - HiFiControls.Keyboard { - id: keyboard - raised: web.keyboardEnabled && web.keyboardRaised - numeric: web.punctuationMode - anchors { - left: parent.left - right: parent.right - bottom: parent.bottom - } - } - } Component.onCompleted: { web.isDesktop = (typeof desktop !== "undefined"); address = url; + loader.active = true } Keys.onPressed: { diff --git a/interface/resources/qml/hifi/Audio.qml b/interface/resources/qml/hifi/Audio.qml index deb44b9bd5..d0c3122100 100644 --- a/interface/resources/qml/hifi/Audio.qml +++ b/interface/resources/qml/hifi/Audio.qml @@ -127,7 +127,7 @@ Rectangle { text: hifi.glyphs.mic color: hifi.colors.primaryHighlight anchors.verticalCenter: parent.verticalCenter - font.pointSize: 27 + size: 32 } RalewayRegular { anchors.verticalCenter: parent.verticalCenter @@ -182,7 +182,7 @@ Rectangle { text: hifi.glyphs.unmuted color: hifi.colors.primaryHighlight anchors.verticalCenter: parent.verticalCenter - font.pointSize: 27 + size: 32 } RalewayRegular { anchors.verticalCenter: parent.verticalCenter diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 86cc0218a4..3343cec26f 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -14,6 +14,7 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 import "../styles-uit" +import "../controls-uit" as HifiControls import "toolbars" // references Users, UserActivityLogger, MyAvatar, Vec3, Quat, AddressManager from root context @@ -42,8 +43,9 @@ Item { property bool selected: false property bool isAdmin: false property bool isPresent: true + property string placeName: "" property string profilePicBorderColor: (connectionStatus == "connection" ? hifi.colors.indigoAccent : (connectionStatus == "friend" ? hifi.colors.greenHighlight : "transparent")) - + property alias avImage: avatarImage Item { id: avatarImage visible: profileUrl !== "" && userName !== ""; @@ -79,25 +81,6 @@ Item { anchors.fill: parent; visible: userImage.status != Image.Ready; } - StateImage { - id: infoHoverImage; - visible: false; - imageURL: "../../images/info-icon-2-state.svg"; - size: 32; - buttonState: 1; - anchors.centerIn: parent; - } - MouseArea { - anchors.fill: parent - enabled: selected || isMyCard; - hoverEnabled: enabled - onClicked: { - userInfoViewer.url = defaultBaseUrl + "/users/" + userName; - userInfoViewer.visible = true; - } - onEntered: infoHoverImage.visible = true; - onExited: infoHoverImage.visible = false; - } } // Colored border around avatarImage @@ -316,9 +299,10 @@ Item { visible: thisNameCard.userName !== ""; // Size width: parent.width - height: pal.activeTab == "nearbyTab" || isMyCard ? usernameTextPixelSize + 4 : parent.height; + height: usernameTextPixelSize + 4 // Anchors - anchors.top: isMyCard ? myDisplayName.bottom : (pal.activeTab == "nearbyTab" ? displayNameContainer.bottom : parent.top); + anchors.top: isMyCard ? myDisplayName.bottom : pal.activeTab == "nearbyTab" ? displayNameContainer.bottom : undefined //(parent.height - displayNameTextPixelSize/2)); + anchors.verticalCenter: pal.activeTab == "connectionsTab" ? avatarImage.verticalCenter : undefined anchors.left: avatarImage.right; anchors.leftMargin: avatarImage.visible ? 5 : 0; anchors.rightMargin: 5; @@ -346,6 +330,92 @@ Item { } } } + StateImage { + id: nameCardConnectionInfoImage + visible: selected && !isMyCard && pal.activeTab == "connectionsTab" + imageURL: "../../images/info-icon-2-state.svg" // PLACEHOLDER!!! + size: 32; + buttonState: 0; + anchors.left: avatarImage.right + anchors.bottom: parent.bottom + } + MouseArea { + anchors.fill:nameCardConnectionInfoImage + enabled: selected + hoverEnabled: true + onClicked: { + userInfoViewer.url = defaultBaseUrl + "/users/" + userName; + userInfoViewer.visible = true; + } + onEntered: { + nameCardConnectionInfoImage.buttonState = 1; + } + onExited: { + nameCardConnectionInfoImage.buttonState = 0; + } + } + FiraSansRegular { + id: nameCardConnectionInfoText + visible: selected && !isMyCard && pal.activeTab == "connectionsTab" && !isMyCard + width: parent.width + height: displayNameTextPixelSize + size: displayNameTextPixelSize - 4 + anchors.left: nameCardConnectionInfoImage.right + anchors.verticalCenter: nameCardConnectionInfoImage.verticalCenter + anchors.leftMargin: 5 + verticalAlignment: Text.AlignVCenter + text: "Info" + color: hifi.colors.baseGray + } + HiFiGlyphs { + id: nameCardRemoveConnectionImage + visible: selected && !isMyCard && pal.activeTab == "connectionsTab" + text: hifi.glyphs.close + size: 28; + x: 120 + anchors.verticalCenter: nameCardConnectionInfoImage.verticalCenter + } + MouseArea { + anchors.fill:nameCardRemoveConnectionImage + enabled: selected + hoverEnabled: true + onClicked: { + // send message to pal.js to forgetConnection + pal.sendToScript({method: 'removeConnection', params: thisNameCard.userName}); + } + onEntered: { + nameCardRemoveConnectionImage.text = hifi.glyphs.closeInverted; + } + onExited: { + nameCardRemoveConnectionImage.text = hifi.glyphs.close; + } + } + FiraSansRegular { + id: nameCardRemoveConnectionText + visible: selected && !isMyCard && pal.activeTab == "connectionsTab" && !isMyCard + width: parent.width + height: displayNameTextPixelSize + size: displayNameTextPixelSize - 4 + anchors.left: nameCardRemoveConnectionImage.right + anchors.verticalCenter: nameCardRemoveConnectionImage.verticalCenter + anchors.leftMargin: 5 + verticalAlignment: Text.AlignVCenter + text: "Forget" + color: hifi.colors.baseGray + } + HifiControls.Button { + id: visitConnectionButton + visible: selected && !isMyCard && pal.activeTab == "connectionsTab" && !isMyCard + text: "Visit" + enabled: thisNameCard.placeName !== "" + anchors.verticalCenter: nameCardRemoveConnectionImage.verticalCenter + x: 240 + onClicked: { + AddressManager.goToUser(thisNameCard.userName); + UserActivityLogger.palAction("go_to_user", thisNameCard.userName); + } + } + // VU Meter Rectangle { id: nameCardVUMeter @@ -484,7 +554,7 @@ Item { } } } - + function updateGainFromQML(avatarUuid, sliderValue, isReleased) { Users.setAvatarGain(avatarUuid, sliderValue); if (isReleased) { diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 66803621ec..d627fb54f9 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -52,6 +52,13 @@ Rectangle { id: letterboxMessage; z: 999; // Force the popup on top of everything else } + Connections { + target: GlobalServices + onMyUsernameChanged: { + myData.userName = Account.username; + myDataChanged(); // Setting a property within an object isn't enough to update dependencies. This will do it. + } + } // The ComboDialog used for setting availability ComboDialog { id: comboDialog; @@ -763,7 +770,7 @@ Rectangle { // This Rectangle refers to each Row in the connectionsTable. rowDelegate: Rectangle { // Size - height: rowHeight; + height: rowHeight + (styleData.selected ? 15 : 0); color: rowColor(styleData.selected, styleData.alternate); } @@ -779,6 +786,7 @@ Rectangle { profileUrl: (model && model.profileUrl) || ""; displayName: ""; userName: model ? model.userName : ""; + placeName: model ? model.placeName : "" connectionStatus : model ? model.connection : ""; selected: styleData.selected; // Size @@ -797,12 +805,16 @@ Rectangle { elide: Text.ElideRight; // Size width: parent.width; - // Anchors - anchors.fill: parent; + // you would think that this would work: + // anchors.verticalCenter: connectionsNameCard.avImage.verticalCenter + // but no! you cannot anchor to a non-sibling or parent. So I will + // align with the friends checkbox, where I did the manual alignment + anchors.verticalCenter: friendsCheckBox.verticalCenter // Text Size size: 16; // Text Positioning verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter // Style color: hifi.colors.blueAccent; font.underline: true; @@ -822,8 +834,12 @@ Rectangle { // "Friends" checkbox HifiControlsUit.CheckBox { id: friendsCheckBox; - visible: styleData.role === "friends" && model.userName !== myData.userName; - anchors.centerIn: parent; + visible: styleData.role === "friends" && model && model.userName !== myData.userName; + // you would think that this would work: + // anchors.verticalCenter: connectionsNameCard.avImage.verticalCenter + // but no! you cannot anchor to a non-sibling or parent. So: + x: parent.width/2 - boxSize/2 + y: connectionsNameCard.avImage.y + connectionsNameCard.avImage.height/2 - boxSize/2 checked: model ? (model["connection"] === "friend" ? true : false) : false; boxSize: 24; onClicked: { @@ -901,7 +917,7 @@ Rectangle { wrapMode: Text.WordWrap textFormat: Text.StyledText; // Text - text: HMD.active ? + text: HMD.isMounted ? "When you meet someone you want to remember later, you can connect with a handshake:

" + "1. Put your hand out onto their hand and squeeze your controller's grip button on its side.
" + "2. Once the other person puts their hand onto yours, you'll see your connection form.
" + @@ -960,7 +976,6 @@ Rectangle { // Text size size: hifi.fontSizes.tabularData; // Anchors - anchors.top: myCard.top; anchors.left: parent.left; // Style color: hifi.colors.baseGrayHighlight; diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 2460fc39d5..85f8a2f59e 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -21,6 +21,9 @@ Rectangle { id: root objectName: "AssetServer" + property string title: "Asset Browser" + property bool keyboardRaised: false + property var eventBridge; signal sendToScript(var message); property bool isHMD: false @@ -415,7 +418,6 @@ Rectangle { Column { width: parent.width - y: hifi.dimensions.tabletMenuHeader //-bgNavBar spacing: 10 HifiControls.TabletContentSection { diff --git a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml index dee0d0e21f..d826b40ad1 100644 --- a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml @@ -20,7 +20,7 @@ import "../../windows" Rectangle { id: root objectName: "RunningScripts" - property var title: "Running Scripts" + property string title: "Running Scripts" HifiConstants { id: hifi } signal sendToScript(var message); property var eventBridge; @@ -81,9 +81,9 @@ Rectangle { Flickable { id: flickable - width: parent.width + width: tabletRoot.width height: parent.height - (keyboard.raised ? keyboard.raisedHeight : 0) - contentWidth: parent.width + contentWidth: column.width contentHeight: column.childrenRect.height clip: true @@ -121,9 +121,8 @@ Rectangle { model: runningScriptsModel id: table height: 185 + width: parent.width colorScheme: hifi.colorSchemes.dark - anchors.left: parent.left - anchors.right: parent.right expandSelectedRow: true itemDelegate: Item { diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 3fb70f9cca..8ad6339d88 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -202,7 +202,7 @@ Item { RalewaySemiBold { id: usernameText - text: tablet.parent.parent.username + text: tabletRoot.username anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 20 diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index fbb78d2694..396f03a1c9 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -25,6 +25,8 @@ StackView { HifiConstants { id: hifi } HifiStyles.HifiConstants { id: hifiStyleConstants } initialItem: addressBarDialog + width: parent !== null ? parent.width : undefined + height: parent !== null ? parent.height : undefined property var eventBridge; property var allStories: []; property int cardWidth: 460; @@ -116,6 +118,7 @@ StackView { imageURL: "../../../images/home.svg" onClicked: { addressBarDialog.loadHome(); + tabletRoot.shown = false; } anchors { left: parent.left @@ -150,7 +153,9 @@ StackView { anchors { top: navBar.bottom right: parent.right + rightMargin: 16 left: parent.left + leftMargin: 16 } property int inputAreaHeight: 70 @@ -554,20 +559,21 @@ StackView { if (addressLine.text !== "") { addressBarDialog.loadAddress(addressLine.text, fromSuggestions) } - + if (root.desktop) { tablet.gotoHomeScreen(); } else { HMD.closeTablet(); } + tabletRoot.shown = false; } Keys.onPressed: { switch (event.key) { case Qt.Key_Escape: case Qt.Key_Back: - root.shown = false + tabletRoot.shown = false clearAddressLineTimer.start(); event.accepted = true break diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index 8037c1280e..f5144e698f 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -13,6 +13,7 @@ Item { property var openMessage: null; property string subMenu: "" signal showDesktop(); + property bool shown: true function setOption(value) { option = value; diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 5d197f5ddc..7700874d9a 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -76,8 +76,8 @@ void JSConsole::setScriptEngine(ScriptEngine* scriptEngine) { return; } if (_scriptEngine != NULL) { - disconnect(_scriptEngine, SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&))); - disconnect(_scriptEngine, SIGNAL(errorMessage(const QString&)), this, SLOT(handleError(const QString&))); + disconnect(_scriptEngine, &ScriptEngine::printedMessage, this, &JSConsole::handlePrint); + disconnect(_scriptEngine, &ScriptEngine::errorMessage, this, &JSConsole::handleError); if (_ownScriptEngine) { _scriptEngine->deleteLater(); } @@ -87,8 +87,8 @@ void JSConsole::setScriptEngine(ScriptEngine* scriptEngine) { _ownScriptEngine = scriptEngine == NULL; _scriptEngine = _ownScriptEngine ? DependencyManager::get()->loadScript(QString(), false) : scriptEngine; - connect(_scriptEngine, SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&))); - connect(_scriptEngine, SIGNAL(errorMessage(const QString&)), this, SLOT(handleError(const QString&))); + connect(_scriptEngine, &ScriptEngine::printedMessage, this, &JSConsole::handlePrint); + connect(_scriptEngine, &ScriptEngine::errorMessage, this, &JSConsole::handleError); } void JSConsole::executeCommand(const QString& command) { @@ -134,11 +134,13 @@ void JSConsole::commandFinished() { resetCurrentCommandHistory(); } -void JSConsole::handleError(const QString& message) { +void JSConsole::handleError(const QString& scriptName, const QString& message) { + Q_UNUSED(scriptName); appendMessage(GUTTER_ERROR, "" + message.toHtmlEscaped() + ""); } -void JSConsole::handlePrint(const QString& message) { +void JSConsole::handlePrint(const QString& scriptName, const QString& message) { + Q_UNUSED(scriptName); appendMessage("", message); } diff --git a/interface/src/ui/JSConsole.h b/interface/src/ui/JSConsole.h index 47878fea99..d5f5aff301 100644 --- a/interface/src/ui/JSConsole.h +++ b/interface/src/ui/JSConsole.h @@ -47,8 +47,8 @@ protected: protected slots: void scrollToBottom(); void resizeTextInput(); - void handlePrint(const QString& message); - void handleError(const QString& message); + void handlePrint(const QString& scriptName, const QString& message); + void handleError(const QString& scriptName, const QString& message); void commandFinished(); private: diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h index c21d8a2f6e..f521ab81cf 100644 --- a/libraries/controllers/src/controllers/StandardControls.h +++ b/libraries/controllers/src/controllers/StandardControls.h @@ -158,6 +158,22 @@ namespace controller { LEFT_HAND_PINKY2, LEFT_HAND_PINKY3, LEFT_HAND_PINKY4, + TRACKED_OBJECT_00, + TRACKED_OBJECT_01, + TRACKED_OBJECT_02, + TRACKED_OBJECT_03, + TRACKED_OBJECT_04, + TRACKED_OBJECT_05, + TRACKED_OBJECT_06, + TRACKED_OBJECT_07, + TRACKED_OBJECT_08, + TRACKED_OBJECT_09, + TRACKED_OBJECT_10, + TRACKED_OBJECT_11, + TRACKED_OBJECT_12, + TRACKED_OBJECT_13, + TRACKED_OBJECT_14, + TRACKED_OBJECT_15, NUM_STANDARD_POSES }; diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index e54846196b..e5c630d97e 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -60,6 +60,7 @@ bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) { bool OffscreenGLCanvas::makeCurrent() { bool result = _context->makeCurrent(_offscreenSurface); Q_ASSERT(result); + std::call_once(_reportOnce, [this]{ qCDebug(glLogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); qCDebug(glLogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 9e6c18bb96..16e32ab42e 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -278,11 +278,9 @@ void OffscreenQmlSurface::cleanup() { } void OffscreenQmlSurface::render() { - #ifdef HIFI_ENABLE_NSIGHT_DEBUG return; #endif - if (_paused) { return; } @@ -614,7 +612,11 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::functionmetaObject()->indexOfSignal("sendToScript"); + if (sendToScriptIndex != -1) { + connect(newItem, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(QVariant))); + } // The root item is ready. Associate it with the window. _rootItem = newItem; diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp index c8a7b61aa7..9c29e87f16 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp @@ -61,6 +61,16 @@ void UserActivityLoggerScriptingInterface::palOpened(float secondsOpened) { }); } +void UserActivityLoggerScriptingInterface::makeUserConnection(QString otherID, bool success, QString detailsString) { + QJsonObject payload; + payload["otherUser"] = otherID; + payload["success"] = success; + if (detailsString.length() > 0) { + payload["details"] = detailsString; + } + logAction("makeUserConnection", payload); +} + void UserActivityLoggerScriptingInterface::logAction(QString action, QJsonObject details) { QMetaObject::invokeMethod(&UserActivityLogger::getInstance(), "logAction", Q_ARG(QString, action), diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.h b/libraries/networking/src/UserActivityLoggerScriptingInterface.h index cf38450891..b68c7beb95 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.h +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.h @@ -29,6 +29,7 @@ public: float tutorialElapsedTime, QString tutorialRunID = "", int tutorialVersion = 0, QString controllerType = ""); Q_INVOKABLE void palAction(QString action, QString target); Q_INVOKABLE void palOpened(float secondsOpen); + Q_INVOKABLE void makeUserConnection(QString otherUser, bool success, QString details=""); private: void logAction(QString action, QJsonObject details = {}); }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 414bcf0d63..da264cbf7d 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -28,6 +28,12 @@ #include "skin_model_shadow_vert.h" #include "skin_model_normal_map_vert.h" +#include "simple_vert.h" +#include "simple_textured_frag.h" +#include "simple_textured_unlit_frag.h" +#include "simple_transparent_textured_frag.h" +#include "simple_transparent_textured_unlit_frag.h" + #include "model_frag.h" #include "model_unlit_frag.h" #include "model_shadow_frag.h" @@ -135,6 +141,7 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { void initDeferredPipelines(render::ShapePlumber& plumber) { // Vertex shaders + auto simpleVertex = gpu::Shader::createVertex(std::string(simple_vert)); auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); @@ -145,6 +152,10 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); // Pixel shaders + auto simplePixel = gpu::Shader::createPixel(std::string(simple_textured_frag)); + auto simpleUnlitPixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag)); + auto simpleTranslucentPixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_frag)); + auto simpleTranslucentUnlitPixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_unlit_frag)); auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); auto modelUnlitPixel = gpu::Shader::createPixel(std::string(model_unlit_frag)); auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); @@ -167,13 +178,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { modelVertex, modelPixel); addPipeline( Key::Builder(), - modelVertex, modelPixel); + simpleVertex, simplePixel); addPipeline( Key::Builder().withMaterial().withUnlit(), modelVertex, modelUnlitPixel); addPipeline( Key::Builder().withUnlit(), - modelVertex, modelUnlitPixel); + simpleVertex, simpleUnlitPixel); addPipeline( Key::Builder().withMaterial().withTangents(), modelNormalMapVertex, modelNormalMapPixel); @@ -189,13 +200,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { modelVertex, modelTranslucentPixel); addPipeline( Key::Builder().withTranslucent(), - modelVertex, modelTranslucentPixel); + simpleVertex, simpleTranslucentPixel); addPipeline( Key::Builder().withMaterial().withTranslucent().withUnlit(), modelVertex, modelTranslucentUnlitPixel); addPipeline( Key::Builder().withTranslucent().withUnlit(), - modelVertex, modelTranslucentUnlitPixel); + simpleVertex, simpleTranslucentUnlitPixel); addPipeline( Key::Builder().withMaterial().withTranslucent().withTangents(), modelNormalMapVertex, modelTranslucentPixel); diff --git a/libraries/render-utils/src/simple_textured.slf b/libraries/render-utils/src/simple_textured.slf index 6067c81a1b..550f6546fd 100644 --- a/libraries/render-utils/src/simple_textured.slf +++ b/libraries/render-utils/src/simple_textured.slf @@ -26,15 +26,17 @@ in vec2 _texCoord0; void main(void) { vec4 texel = texture(originalTexture, _texCoord0); + float colorAlpha = _color.a; if (_color.a <= 0.0) { texel = colorToLinearRGBA(texel); + colorAlpha = -_color.a; } const float ALPHA_THRESHOLD = 0.999; - if (_color.a * texel.a < ALPHA_THRESHOLD) { + if (colorAlpha * texel.a < ALPHA_THRESHOLD) { packDeferredFragmentTranslucent( normalize(_normal), - _color.a * texel.a, + colorAlpha * texel.a, _color.rgb * texel.rgb, DEFAULT_FRESNEL, DEFAULT_ROUGHNESS); diff --git a/libraries/render-utils/src/simple_textured_unlit.slf b/libraries/render-utils/src/simple_textured_unlit.slf index 4f02140825..d261fb343a 100644 --- a/libraries/render-utils/src/simple_textured_unlit.slf +++ b/libraries/render-utils/src/simple_textured_unlit.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// simple.frag +// simple_textured_unlit.frag // fragment shader // // Created by Clément Brisset on 5/29/15. @@ -25,15 +25,17 @@ in vec2 _texCoord0; void main(void) { vec4 texel = texture(originalTexture, _texCoord0.st); + float colorAlpha = _color.a; if (_color.a <= 0.0) { texel = colorToLinearRGBA(texel); + colorAlpha = -_color.a; } const float ALPHA_THRESHOLD = 0.999; - if (_color.a * texel.a < ALPHA_THRESHOLD) { - packDeferredFragmentTranslucent( + if (colorAlpha * texel.a < ALPHA_THRESHOLD) { + packDeferredFragmentTranslucent( normalize(_normal), - _color.a * texel.a, + colorAlpha * texel.a, _color.rgb * texel.rgb, DEFAULT_FRESNEL, DEFAULT_ROUGHNESS); diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf new file mode 100644 index 0000000000..b9eb921e9d --- /dev/null +++ b/libraries/render-utils/src/simple_transparent_textured.slf @@ -0,0 +1,62 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_transparent_textured.slf +// fragment shader +// +// Created by Sam Gateau on 4/3/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 +// + +<@include gpu/Color.slh@> + +<@include DeferredBufferWrite.slh@> +<@include DeferredGlobalLight.slh@> +<$declareEvalGlobalLightingAlphaBlended()$> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +// the albedo texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec4 _position; +in vec3 _normal; +in vec4 _color; +in vec2 _texCoord0; + +void main(void) { + vec4 texel = texture(originalTexture, _texCoord0.st); + float opacity = _color.a; + if (_color.a <= 0.0) { + texel = colorToLinearRGBA(texel); + opacity = -_color.a; + } + opacity *= texel.a; + vec3 albedo = _color.rgb * texel.rgb; + + vec3 fragPosition = _position.xyz; + vec3 fragNormal = normalize(_normal); + + TransformCamera cam = getTransformCamera(); + + _fragColor0 = vec4(evalGlobalLightingAlphaBlended( + cam._viewInverse, + 1.0, + 1.0, + fragPosition, + fragNormal, + albedo, + DEFAULT_FRESNEL, + 0.0, + vec3(0.0f), + DEFAULT_ROUGHNESS, + opacity), + opacity); + +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple_transparent_textured_unlit.slf b/libraries/render-utils/src/simple_transparent_textured_unlit.slf new file mode 100644 index 0000000000..693d7be2db --- /dev/null +++ b/libraries/render-utils/src/simple_transparent_textured_unlit.slf @@ -0,0 +1,36 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_transparent_textured_unlit.slf +// fragment shader +// +// Created by Sam Gateau on 4/3/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 +// + +<@include gpu/Color.slh@> + +// the albedo texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec3 _normal; +in vec4 _color; +in vec2 _texCoord0; + + +layout(location = 0) out vec4 _fragColor0; + +void main(void) { + vec4 texel = texture(originalTexture, _texCoord0.st); + float colorAlpha = _color.a; + if (_color.a <= 0.0) { + texel = colorToLinearRGBA(texel); + colorAlpha = -_color.a; + } + _fragColor0 = vec4(_color.rgb * texel.rgb, colorAlpha * texel.a); +} \ No newline at end of file diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index c60e4fa698..c0e94058ae 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -122,12 +122,15 @@ void QmlWindowClass::initQml(QVariantMap properties) { object->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, visible); object->setProperty(SOURCE_PROPERTY, _source); + const QMetaObject *metaObject = _qmlWindow->metaObject(); // Forward messages received from QML on to the script connect(_qmlWindow, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), Qt::QueuedConnection); connect(_qmlWindow, SIGNAL(visibleChanged()), this, SIGNAL(visibleChanged()), Qt::QueuedConnection); - connect(_qmlWindow, SIGNAL(resized(QSizeF)), this, SIGNAL(resized(QSizeF)), Qt::QueuedConnection); - connect(_qmlWindow, SIGNAL(moved(QVector2D)), this, SLOT(hasMoved(QVector2D)), Qt::QueuedConnection); + if (metaObject->indexOfSignal("resized") >= 0) + connect(_qmlWindow, SIGNAL(resized(QSizeF)), this, SIGNAL(resized(QSizeF)), Qt::QueuedConnection); + if (metaObject->indexOfSignal("moved") >= 0) + connect(_qmlWindow, SIGNAL(moved(QVector2D)), this, SLOT(hasMoved(QVector2D)), Qt::QueuedConnection); connect(_qmlWindow, SIGNAL(windowClosed()), this, SLOT(hasClosed()), Qt::QueuedConnection); }); } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 2e930c0fdc..8cedee2d8f 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -63,59 +63,6 @@ bool ViveControllerManager::activate() { enableOpenVrKeyboard(_container); - // OpenVR provides 3d mesh representations of the controllers - // Disabled controller rendering code - /* - auto renderModels = vr::VRRenderModels(); - - vr::RenderModel_t model; - if (!_system->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { - qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING); - } else { - model::Mesh* mesh = new model::Mesh(); - model::MeshPointer meshPtr(mesh); - _modelGeometry.setMesh(meshPtr); - - auto indexBuffer = new gpu::Buffer(3 * model.unTriangleCount * sizeof(uint16_t), (gpu::Byte*)model.rIndexData); - auto indexBufferPtr = gpu::BufferPointer(indexBuffer); - auto indexBufferView = new gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT16, gpu::RAW)); - mesh->setIndexBuffer(*indexBufferView); - - auto vertexBuffer = new gpu::Buffer(model.unVertexCount * sizeof(vr::RenderModel_Vertex_t), - (gpu::Byte*)model.rVertexData); - auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer); - auto vertexBufferView = new gpu::BufferView(vertexBufferPtr, - 0, - vertexBufferPtr->getSize() - sizeof(float) * 3, - sizeof(vr::RenderModel_Vertex_t), - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)); - mesh->setVertexBuffer(*vertexBufferView); - mesh->addAttribute(gpu::Stream::NORMAL, - gpu::BufferView(vertexBufferPtr, - sizeof(float) * 3, - vertexBufferPtr->getSize() - sizeof(float) * 3, - sizeof(vr::RenderModel_Vertex_t), - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW))); - //mesh->addAttribute(gpu::Stream::TEXCOORD, - // gpu::BufferView(vertexBufferPtr, - // 2 * sizeof(float) * 3, - // vertexBufferPtr->getSize() - sizeof(float) * 2, - // sizeof(vr::RenderModel_Vertex_t), - // gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::RAW))); - - gpu::Element formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - gpu::Element formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - _texture = gpu::TexturePointer( - gpu::Texture::create2D(formatGPU, model.diffuseTexture.unWidth, model.diffuseTexture.unHeight, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); - _texture->assignStoredMip(0, formatMip, model.diffuseTexture.unWidth * model.diffuseTexture.unHeight * 4 * sizeof(uint8_t), model.diffuseTexture.rubTextureMapData); - _texture->autoGenerateMips(-1); - - _modelLoaded = true; - _renderControllers = true; - } - */ - // register with UserInputMapper auto userInputMapper = DependencyManager::get(); userInputMapper->registerDevice(_inputDevice); @@ -145,70 +92,6 @@ void ViveControllerManager::deactivate() { _registeredWithInputMapper = false; } -void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges) { - PerformanceTimer perfTimer("ViveControllerManager::updateRendering"); - - /* - if (_modelLoaded) { - //auto controllerPayload = new render::Payload(this); - //auto controllerPayloadPointer = ViveControllerManager::PayloadPointer(controllerPayload); - //if (_leftHandRenderID == 0) { - // _leftHandRenderID = scene->allocateID(); - // pendingChanges.resetItem(_leftHandRenderID, controllerPayloadPointer); - //} - //pendingChanges.updateItem(_leftHandRenderID, ); - - - controller::Pose leftHand = _inputDevice->_poseStateMap[controller::StandardPoseChannel::LEFT_HAND]; - controller::Pose rightHand = _inputDevice->_poseStateMap[controller::StandardPoseChannel::RIGHT_HAND]; - - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - auto geometryCache = DependencyManager::get(); - geometryCache->useSimpleDrawPipeline(batch); - DependencyManager::get()->bindSimpleProgram(batch, true); - - auto mesh = _modelGeometry.getMesh(); - batch.setInputFormat(mesh->getVertexFormat()); - //batch._glBindTexture(GL_TEXTURE_2D, _uexture); - - if (leftHand.isValid()) { - renderHand(leftHand, batch, 1); - } - if (rightHand.isValid()) { - renderHand(rightHand, batch, -1); - } - }); - } - */ -} - -void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign) { - /* - auto userInputMapper = DependencyManager::get(); - Transform transform(userInputMapper->getSensorToWorldMat()); - transform.postTranslate(pose.getTranslation() + pose.getRotation() * glm::vec3(0, 0, CONTROLLER_LENGTH_OFFSET)); - - glm::quat rotation = pose.getRotation() * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(sign * PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); - transform.postRotate(rotation); - - batch.setModelTransform(transform); - - auto mesh = _modelGeometry.getMesh(); - batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer()); - batch.setInputBuffer(gpu::Stream::NORMAL, - mesh->getVertexBuffer()._buffer, - sizeof(float) * 3, - mesh->getVertexBuffer()._stride); - //batch.setInputBuffer(gpu::Stream::TEXCOORD, - // mesh->getVertexBuffer()._buffer, - // 2 * 3 * sizeof(float), - // mesh->getVertexBuffer()._stride); - batch.setIndexBuffer(gpu::UINT16, mesh->getIndexBuffer()._buffer, 0); - batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); - */ -} - - void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { if (!_system) { @@ -257,6 +140,11 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle handleHandController(deltaTime, leftHandDeviceIndex, inputCalibrationData, true); handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false); + // collect raw poses + for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { + handleTrackedObject(i, inputCalibrationData); + } + // handle haptics { Locker locker(_lock); @@ -278,6 +166,30 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle _trackedControllers = numTrackedControllers; } +void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) { + + uint32_t poseIndex = controller::TRACKED_OBJECT_00 + deviceIndex; + + if (_system->IsTrackedDeviceConnected(deviceIndex) && + _nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid && + poseIndex <= controller::TRACKED_OBJECT_15) { + + // process pose + const mat4& mat = _nextSimPoseData.poses[deviceIndex]; + const vec3 linearVelocity = _nextSimPoseData.linearVelocities[deviceIndex]; + const vec3 angularVelocity = _nextSimPoseData.angularVelocities[deviceIndex]; + + controller::Pose pose(extractTranslation(mat), glmExtractRotation(mat), linearVelocity, angularVelocity); + + // transform into avatar frame + glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; + _poseStateMap[poseIndex] = pose.transform(controllerToAvatar); + } else { + controller::Pose invalidPose; + _poseStateMap[poseIndex] = invalidPose; + } +} + void ViveControllerManager::InputDevice::handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) { if (_system->IsTrackedDeviceConnected(deviceIndex) && @@ -492,6 +404,24 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI makePair(LEFT_HAND, "LeftHand"), makePair(RIGHT_HAND, "RightHand"), + // 16 tracked poses + makePair(TRACKED_OBJECT_00, "TrackedObject00"), + makePair(TRACKED_OBJECT_01, "TrackedObject01"), + makePair(TRACKED_OBJECT_02, "TrackedObject02"), + makePair(TRACKED_OBJECT_03, "TrackedObject03"), + makePair(TRACKED_OBJECT_04, "TrackedObject04"), + makePair(TRACKED_OBJECT_05, "TrackedObject05"), + makePair(TRACKED_OBJECT_06, "TrackedObject06"), + makePair(TRACKED_OBJECT_07, "TrackedObject07"), + makePair(TRACKED_OBJECT_08, "TrackedObject08"), + makePair(TRACKED_OBJECT_09, "TrackedObject09"), + makePair(TRACKED_OBJECT_10, "TrackedObject10"), + makePair(TRACKED_OBJECT_11, "TrackedObject11"), + makePair(TRACKED_OBJECT_12, "TrackedObject12"), + makePair(TRACKED_OBJECT_13, "TrackedObject13"), + makePair(TRACKED_OBJECT_14, "TrackedObject14"), + makePair(TRACKED_OBJECT_15, "TrackedObject15"), + // app button above trackpad. Input::NamedPair(Input(_deviceID, LEFT_APP_MENU, ChannelType::BUTTON), "LeftApplicationMenu"), Input::NamedPair(Input(_deviceID, RIGHT_APP_MENU, ChannelType::BUTTON), "RightApplicationMenu"), diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 3fb166c842..dc1883d5e4 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -43,8 +43,6 @@ public: void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; - void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges); - void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; } private: @@ -62,6 +60,7 @@ private: void hapticsHelper(float deltaTime, bool leftHand); void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); + void handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData); void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool touched, bool isLeftHand); void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand); void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, diff --git a/scripts/developer/debugging/debugWindow.qml b/scripts/developer/debugging/debugWindow.qml index f046a949ef..20fa24358d 100644 --- a/scripts/developer/debugging/debugWindow.qml +++ b/scripts/developer/debugging/debugWindow.qml @@ -18,6 +18,9 @@ Rectangle { width: parent ? parent.width : 100 height: parent ? parent.height : 100 + signal moved(vector2d position); + signal resized(size size); + property var channel; TextArea { diff --git a/scripts/developer/tests/viveTrackedObjects.js b/scripts/developer/tests/viveTrackedObjects.js new file mode 100644 index 0000000000..78911538e4 --- /dev/null +++ b/scripts/developer/tests/viveTrackedObjects.js @@ -0,0 +1,36 @@ + +var TRACKED_OBJECT_POSES = [ + "TrackedObject00", "TrackedObject01", "TrackedObject02", "TrackedObject03", + "TrackedObject04", "TrackedObject05", "TrackedObject06", "TrackedObject07", + "TrackedObject08", "TrackedObject09", "TrackedObject10", "TrackedObject11", + "TrackedObject12", "TrackedObject13", "TrackedObject14", "TrackedObject15" +]; + +function init() { + Script.update.connect(update); +} + +function shutdown() { + Script.update.disconnect(update); + + TRACKED_OBJECT_POSES.forEach(function (key) { + DebugDraw.removeMyAvatarMarker(key); + }); +} + +var WHITE = {x: 1, y: 1, z: 1, w: 1}; + +function update(dt) { + if (Controller.Hardware.Vive) { + TRACKED_OBJECT_POSES.forEach(function (key) { + var pose = Controller.getPoseValue(Controller.Hardware.Vive[key]); + if (pose.valid) { + DebugDraw.addMyAvatarMarker(key, pose.rotation, pose.translation, WHITE); + } else { + DebugDraw.removeMyAvatarMarker(key); + } + }); + } +} + +init(); diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index 90f8ccb368..33c0b3116e 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -297,8 +297,9 @@ function Teleporter() { } else if (teleportLocationType === TARGET.SURFACE) { var offset = getAvatarFootOffset(); intersection.intersection.y += offset; - MyAvatar.position = intersection.intersection; + MyAvatar.goToLocation(intersection.intersection, false, {x: 0, y: 0, z: 0, w: 1}, false); HMD.centerUI(); + MyAvatar.centerBody(); } } }; diff --git a/scripts/system/makeUserConnection.js b/scripts/system/makeUserConnection.js index e70e0a2ea2..0a781a5bb8 100644 --- a/scripts/system/makeUserConnection.js +++ b/scripts/system/makeUserConnection.js @@ -543,12 +543,14 @@ function connectionRequestCompleted() { // Final result is in. Do effects. // don't change state (so animation continues while gripped) // but do send a notification, by calling the slot that emits the signal for it Window.makeConnection(true, result.connection.new_connection ? "You and " + result.connection.username + " are now connected!" : result.connection.username); + UserActivityLogger.makeUserConnection(connectingId, true, result.connection.new_connection ? "new connection" : "already connected"); return; } // failed endHandshake(); debug("failing with result data", result); // IWBNI we also did some fail sound/visual effect. Window.makeConnection(false, result.connection); + UserActivityLogger.makeUserConnection(connectingId, false, result.connection); } var POLL_INTERVAL_MS = 200, POLL_LIMIT = 5; function handleConnectionResponseAndMaybeRepeat(error, response) { @@ -573,6 +575,7 @@ function handleConnectionResponseAndMaybeRepeat(error, response) { } else if (error || (response.status !== 'success')) { debug('server fail', error, response.status); result = error ? {status: 'error', connection: error} : response; + UserActivityLogger.makeUserConnection(connectingId, false, error || response); connectionRequestCompleted(); } else { debug('server success', result); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index b39c993894..5fbea90025 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -269,13 +269,26 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See getConnectionData(); UserActivityLogger.palAction("refresh_connections", ""); break; + case 'removeConnection': + connectionUserName = message.params; + request({ + uri: METAVERSE_BASE + '/api/v1/user/connections/' + connectionUserName, + method: 'DELETE' + }, function (error, response) { + if (error || (response.status !== 'success')) { + print("Error: unable to remove connection", connectionUserName, error || response.status); + return; + } + getConnectionData(); + }); + break + case 'removeFriend': friendUserName = message.params; request({ uri: METAVERSE_BASE + '/api/v1/user/friends/' + friendUserName, method: 'DELETE' }, function (error, response) { - print(JSON.stringify(response)); if (error || (response.status !== 'success')) { print("Error: unable to unfriend", friendUserName, error || response.status); return;