From 0f07d0b49378ae578fd653876d2e48e00b2baada Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Tue, 23 Jan 2018 11:43:29 -0300 Subject: [PATCH 01/61] Add bottom bar and address dialog (Android) --- android/app/build.gradle | 2 +- .../resources/icons/+android/backward.svg | 70 ++ .../resources/icons/+android/forward.svg | 71 ++ interface/resources/icons/+android/go-a.svg | 40 + interface/resources/icons/+android/go-i.svg | 40 + interface/resources/icons/+android/goto-a.svg | 28 + interface/resources/icons/+android/goto-i.svg | 28 + interface/resources/icons/+android/hide.svg | 947 ++++++++++++++++++ interface/resources/icons/+android/home.svg | 82 ++ .../resources/icons/+android/show-up.svg | 8 + .../qml/+android/AddressBarDialog.qml | 230 +++++ .../qml/hifi/+android/HifiConstants.qml | 54 + .../qml/hifi/+android/WindowHeader.qml | 113 +++ .../qml/hifi/+android/bottomHudOptions.qml | 89 ++ .../resources/qml/hifi/+android/bottombar.qml | 135 +++ .../resources/qml/hifi/+android/button.qml | 230 +++++ interface/src/Application.cpp | 2 + libraries/ui/src/QmlFragmentClass.cpp | 88 ++ libraries/ui/src/QmlFragmentClass.h | 45 + libraries/ui/src/ui/OffscreenQmlSurface.cpp | 13 +- scripts/+android/defaultScripts.js | 3 +- scripts/system/bottombar.js | 159 +++ scripts/system/goto-android.js | 96 ++ 23 files changed, 2570 insertions(+), 3 deletions(-) create mode 100644 interface/resources/icons/+android/backward.svg create mode 100644 interface/resources/icons/+android/forward.svg create mode 100755 interface/resources/icons/+android/go-a.svg create mode 100644 interface/resources/icons/+android/go-i.svg create mode 100755 interface/resources/icons/+android/goto-a.svg create mode 100644 interface/resources/icons/+android/goto-i.svg create mode 100644 interface/resources/icons/+android/hide.svg create mode 100644 interface/resources/icons/+android/home.svg create mode 100644 interface/resources/icons/+android/show-up.svg create mode 100644 interface/resources/qml/+android/AddressBarDialog.qml create mode 100644 interface/resources/qml/hifi/+android/HifiConstants.qml create mode 100644 interface/resources/qml/hifi/+android/WindowHeader.qml create mode 100644 interface/resources/qml/hifi/+android/bottomHudOptions.qml create mode 100644 interface/resources/qml/hifi/+android/bottombar.qml create mode 100644 interface/resources/qml/hifi/+android/button.qml create mode 100644 libraries/ui/src/QmlFragmentClass.cpp create mode 100644 libraries/ui/src/QmlFragmentClass.h create mode 100644 scripts/system/bottombar.js create mode 100644 scripts/system/goto-android.js diff --git a/android/app/build.gradle b/android/app/build.gradle index a2f008beef..97267258e2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -23,7 +23,7 @@ android { '-DRELEASE_NUMBER=' + RELEASE_NUMBER, '-DRELEASE_TYPE=' + RELEASE_TYPE, '-DBUILD_BRANCH=' + BUILD_BRANCH, - '-DDISABLE_QML=ON', + '-DDISABLE_QML=OFF', '-DDISABLE_KTX_CACHE=OFF' } } diff --git a/interface/resources/icons/+android/backward.svg b/interface/resources/icons/+android/backward.svg new file mode 100644 index 0000000000..ae0893fc66 --- /dev/null +++ b/interface/resources/icons/+android/backward.svg @@ -0,0 +1,70 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/icons/+android/forward.svg b/interface/resources/icons/+android/forward.svg new file mode 100644 index 0000000000..d03c4097d7 --- /dev/null +++ b/interface/resources/icons/+android/forward.svg @@ -0,0 +1,71 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/icons/+android/go-a.svg b/interface/resources/icons/+android/go-a.svg new file mode 100755 index 0000000000..faecb15292 --- /dev/null +++ b/interface/resources/icons/+android/go-a.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/go-i.svg b/interface/resources/icons/+android/go-i.svg new file mode 100644 index 0000000000..0f1298d573 --- /dev/null +++ b/interface/resources/icons/+android/go-i.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/goto-a.svg b/interface/resources/icons/+android/goto-a.svg new file mode 100755 index 0000000000..5fb3e52e4c --- /dev/null +++ b/interface/resources/icons/+android/goto-a.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/goto-i.svg b/interface/resources/icons/+android/goto-i.svg new file mode 100644 index 0000000000..7613beb9e7 --- /dev/null +++ b/interface/resources/icons/+android/goto-i.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/hide.svg b/interface/resources/icons/+android/hide.svg new file mode 100644 index 0000000000..e09d517b08 --- /dev/null +++ b/interface/resources/icons/+android/hide.svg @@ -0,0 +1,947 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/home.svg b/interface/resources/icons/+android/home.svg new file mode 100644 index 0000000000..414c179e79 --- /dev/null +++ b/interface/resources/icons/+android/home.svg @@ -0,0 +1,82 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/icons/+android/show-up.svg b/interface/resources/icons/+android/show-up.svg new file mode 100644 index 0000000000..0736b9a794 --- /dev/null +++ b/interface/resources/icons/+android/show-up.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/interface/resources/qml/+android/AddressBarDialog.qml b/interface/resources/qml/+android/AddressBarDialog.qml new file mode 100644 index 0000000000..e07af24b8d --- /dev/null +++ b/interface/resources/qml/+android/AddressBarDialog.qml @@ -0,0 +1,230 @@ +// +// AddressBarDialog.qml +// +// Created by Austin Davis on 2015/04/14 +// Copyright 2015 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 +// + +import Hifi 1.0 +import QtQuick 2.4 +import "../controls" +import "../styles" +import "../hifi" as QmlHifi +import "../hifi/toolbars" +import "../styles-uit" as HifiStyles +import "../controls-uit" as HifiControls + +Item { + QmlHifi.HifiConstants { id: android } + + width: parent ? parent.width - android.dimen.windowLessWidth : 0 + height: parent ? parent.height - android.dimen.windowLessHeight : 0 + z: android.dimen.windowZ + anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom } + + id: bar + property bool isCursorVisible: false // Override default cursor visibility. + property bool shown: true + + onShownChanged: { + bar.visible = shown; + sendToScript({method: 'shownChanged', params: { shown: shown }}); + if (shown) { + updateLocationText(false); + } + } + + function hide() { + shown = false; + sendToScript ({ type: "hide" }); + } + + Component.onCompleted: { + updateLocationText(false); + } + + HifiConstants { id: hifi } + HifiStyles.HifiConstants { id: hifiStyleConstants } + + signal sendToScript(var message); + + AddressBarDialog { + id: addressBarDialog + } + + + Rectangle { + id: background + gradient: Gradient { + GradientStop { position: 0.0; color: android.color.gradientTop } + GradientStop { position: 1.0; color: android.color.gradientBottom } + } + anchors { + fill: parent + } + + QmlHifi.WindowHeader { + id: header + iconSource: "../../../icons/goto-i.svg" + titleText: "GO TO" + } + + HifiStyles.RalewayRegular { + id: notice + text: "YOUR LOCATION" + font.pixelSize: hifi.fonts.pixelSize * 2.15; + color: "#2CD7FF" + anchors { + bottom: addressBackground.top + bottomMargin: 45 + left: addressBackground.left + leftMargin: 60 + } + + } + + property int inputAreaHeight: 210 + property int inputAreaStep: (height - inputAreaHeight) / 2 + + ToolbarButton { + id: homeButton + y: 280 + imageURL: "../../icons/home.svg" + onClicked: { + addressBarDialog.loadHome(); + bar.shown = false; + } + anchors { + leftMargin: 75 + left: parent.left + } + size: 150 + } + + ToolbarButton { + id: backArrow; + imageURL: "../../icons/backward.svg"; + onClicked: addressBarDialog.loadBack(); + anchors { + left: homeButton.right + leftMargin: 70 + verticalCenter: homeButton.verticalCenter + } + size: 150 + } + ToolbarButton { + id: forwardArrow; + imageURL: "../../icons/forward.svg"; + onClicked: addressBarDialog.loadForward(); + anchors { + left: backArrow.right + leftMargin: 60 + verticalCenter: homeButton.verticalCenter + } + size: 150 + } + + HifiStyles.FiraSansRegular { + id: location; + font.pixelSize: addressLine.font.pixelSize; + color: "gray"; + clip: true; + anchors.fill: addressLine; + visible: addressLine.text.length === 0 + z: 1 + } + + Rectangle { + id: addressBackground + x: 780 + y: 280 + width: 1440 + height: 150 + color: "#FFFFFF" + } + + TextInput { + id: addressLine + focus: true + x: 870 + y: 450 + width: 1350 + height: 120 + inputMethodHints: Qt.ImhNoPredictiveText + //helperText: "Hint is here" + anchors { + verticalCenter: homeButton.verticalCenter + } + font.pixelSize: hifi.fonts.pixelSize * 3.75 + onTextChanged: { + //filterChoicesByText(); + updateLocationText(addressLine.text.length > 0); + if (!isCursorVisible && text.length > 0) { + isCursorVisible = true; + cursorVisible = true; + } + } + + onActiveFocusChanged: { + //cursorVisible = isCursorVisible && focus; + } + } + + + + function toggleOrGo() { + if (addressLine.text !== "") { + addressBarDialog.loadAddress(addressLine.text); + } + bar.shown = false; + } + + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + clearAddressLineTimer.start(); + event.accepted = true + bar.shown = false; + break + case Qt.Key_Enter: + case Qt.Key_Return: + toggleOrGo(); + clearAddressLineTimer.start(); + event.accepted = true + break + } + } + + } + + Timer { + // Delay clearing address line so as to avoid flicker of "not connected" being displayed after entering an address. + id: clearAddressLineTimer + running: false + interval: 100 // ms + repeat: false + onTriggered: { + addressLine.text = ""; + isCursorVisible = false; + } + } + + function updateLocationText(enteringAddress) { + if (enteringAddress) { + notice.text = "Go to a place, @user, path or network address"; + notice.color = "#ffffff"; // hifiStyleConstants.colors.baseGrayHighlight; + location.visible = false; + } else { + notice.text = AddressManager.isConnected ? "YOUR LOCATION:" : "NOT CONNECTED"; + notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.turquoise : hifiStyleConstants.colors.redHighlight; + // Display hostname, which includes ip address, localhost, and other non-placenames. + location.text = (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''); + location.visible = true; + } + } + +} \ No newline at end of file diff --git a/interface/resources/qml/hifi/+android/HifiConstants.qml b/interface/resources/qml/hifi/+android/HifiConstants.qml new file mode 100644 index 0000000000..ee6d92ed38 --- /dev/null +++ b/interface/resources/qml/hifi/+android/HifiConstants.qml @@ -0,0 +1,54 @@ +// +// HifiAndroidConstants.qml +// interface/resources/qml/+android +// +// Created by Gabriel Calero & Cristian Duarte on 23 Oct 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 +// + +import QtQuick 2.4 + +Item { + + id: android + + readonly property alias dimen: dimen + readonly property alias color: color + + Item { + id: dimen + readonly property real windowLessWidth: 126 + readonly property real windowLessHeight: 64 + + readonly property real windowZ: 100 + + readonly property real headerHeight: 276 + + readonly property real headerIconPosX: 90 + readonly property real headerIconPosY: 108 + readonly property real headerIconWidth: 111 + readonly property real headerIconHeight: 111 + readonly property real headerIconTitleDistance: 151 + + readonly property real headerHideWidth: 150 + readonly property real headerHideHeight: 150 + readonly property real headerHideRightMargin: 110 + readonly property real headerHideTopMargin: 90 + readonly property real headerHideIconWidth: 70 + readonly property real headerHideIconHeight: 45 + readonly property real headerHideTextTopMargin: 36 + + readonly property real botomHudWidth: 366 + readonly property real botomHudHeight: 180 + + } + + Item { + id: color + readonly property color gradientTop: "#4E4E4E" + readonly property color gradientBottom: "#242424" + } +} diff --git a/interface/resources/qml/hifi/+android/WindowHeader.qml b/interface/resources/qml/hifi/+android/WindowHeader.qml new file mode 100644 index 0000000000..4ec0a0c6e6 --- /dev/null +++ b/interface/resources/qml/hifi/+android/WindowHeader.qml @@ -0,0 +1,113 @@ +// +// WindowHeader.qml +// interface/resources/qml/android +// +// Created by Gabriel Calero & Cristian Duarte on 23 Oct 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 +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import Qt.labs.settings 1.0 +import "." +import "../styles" as HifiStyles +import "../styles-uit" +import "../controls-uit" as HifiControlsUit +import "../controls" as HifiControls +import ".." + + +// header +Rectangle { + id: header + + // properties + property string iconSource: "" + property string titleText: "" + property var extraItemInCenter: Item {} + + HifiStyles.HifiConstants { id: hifiStylesConstants } + + /*property var mockRectangle: Rectangle { + anchors.fill: parent + color: "#44FFFF00" + }*/ + color: "#00000000" + //color: "#55FF0000" + width: parent.width + height: android.dimen.headerHeight + anchors.top : parent.top + + Image { + id: windowIcon + source: iconSource + x: android.dimen.headerIconPosX + y: android.dimen.headerIconPosY + width: android.dimen.headerIconWidth + height: android.dimen.headerIconHeight + } + + /*HifiStylesUit.*/FiraSansSemiBold { + id: windowTitle + x: windowIcon.x + android.dimen.headerIconTitleDistance + anchors.verticalCenter: windowIcon.verticalCenter + text: titleText + color: "#FFFFFF" + font.letterSpacing: 2 + font.pixelSize: hifiStylesConstants.fonts.headerPixelSize * 2.15 + } + Item { + height: 60 + anchors { + left: windowTitle.right + right: hideButton.left + verticalCenter: windowIcon.verticalCenter + } + children: [ extraItemInCenter/*, mockRectangle */] + } + + Rectangle { + id: hideButton + height: android.dimen.headerHideWidth + width: android.dimen.headerHideHeight + color: "#00000000" + //color: "#CC00FF00" + anchors { + top: parent.top + right: parent.right + rightMargin: android.dimen.headerHideRightMargin + topMargin: android.dimen.headerHideTopMargin + } + Image { + id: hideIcon + source: "../../../icons/hide.svg" + width: android.dimen.headerHideIconWidth + height: android.dimen.headerHideIconHeight + anchors { + horizontalCenter: parent.horizontalCenter + } + } + /*HifiStyles.*/FiraSansRegular { + anchors { + top: hideIcon.bottom + horizontalCenter: hideIcon.horizontalCenter + topMargin: android.dimen.headerHideTextTopMargin + } + text: "HIDE" + color: "#FFFFFF" + font.pixelSize: hifiStylesConstants.fonts.pixelSize * 2.15 + } + + MouseArea { + anchors.fill: parent + onClicked: { + hide(); + } + } + } +} \ No newline at end of file diff --git a/interface/resources/qml/hifi/+android/bottomHudOptions.qml b/interface/resources/qml/hifi/+android/bottomHudOptions.qml new file mode 100644 index 0000000000..860298149f --- /dev/null +++ b/interface/resources/qml/hifi/+android/bottomHudOptions.qml @@ -0,0 +1,89 @@ +// +// bottomHudOptions.qml +// interface/resources/qml/android +// +// Created by Cristian Duarte & Gabriel Calero on 24 Nov 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 +// + +import Hifi 1.0 +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import Qt.labs.settings 1.0 +import "../../styles" as HifiStyles +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit +import "../../controls" as HifiControls +import ".." +import "." + +Item { + id: bottomHud + + property bool shown: false + + signal sendToScript(var message); + + HifiConstants { id: android } + + onShownChanged: { + bottomHud.visible = shown; + } + + function hide() { + shown = false; + } + + Rectangle { + anchors.fill : parent + color: "transparent" + Flow { + id: flowMain + spacing: 0 + flow: Flow.LeftToRight + layoutDirection: Flow.LeftToRight + anchors.fill: parent + anchors.margins: 12 + + Rectangle { + id: hideButton + height: android.dimen.headerHideWidth + width: android.dimen.headerHideHeight + color: "#00000000" + anchors { + horizontalCenter: parent.horizontalCenter + } + Image { + id: hideIcon + source: "../../../icons/show-up.svg" + width: android.dimen.headerHideIconWidth + height: android.dimen.headerHideIconHeight + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + sendToScript ({ method: "showUpBar" }); + } + } + } + } + } + + Component.onCompleted: { + width = android.dimen.botomHudWidth; + height = android.dimen.botomHudHeight; + x=Window.innerWidth - width; + y=Window.innerHeight - height; + } + +} diff --git a/interface/resources/qml/hifi/+android/bottombar.qml b/interface/resources/qml/hifi/+android/bottombar.qml new file mode 100644 index 0000000000..2a34b7fe19 --- /dev/null +++ b/interface/resources/qml/hifi/+android/bottombar.qml @@ -0,0 +1,135 @@ +// +// bottomHudOptions.qml +// interface/resources/qml/android +// +// Created by Gabriel Calero & Cristian Duarte on 19 Jan 2018 +// Copyright 2018 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 +// + +import Hifi 1.0 +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import Qt.labs.settings 1.0 +import "../../styles" as Styles +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit +import "../../controls" as HifiControls +import ".." +import "." + +Item { + id: bar + x:0 + + property bool shown: true + + signal sendToScript(var message); + + onShownChanged: { + bar.visible = shown; + } + + function hide() { + //shown = false; + sendToScript({ method: "hide" }); + } + + Styles.HifiConstants { id: hifi } + HifiConstants { id: android } + + Rectangle { + id: background + anchors.fill : parent + color: "#FF000000" + border.color: "#FFFFFF" + anchors.bottomMargin: -1 + anchors.leftMargin: -1 + anchors.rightMargin: -1 + Flow { + id: flowMain + spacing: 10 + anchors.fill: parent + anchors.topMargin: 12 + anchors.bottomMargin: 12 + anchors.rightMargin: 12 + anchors.leftMargin: 72 + } + + + Rectangle { + id: hideButton + height: android.dimen.headerHideWidth + width: android.dimen.headerHideHeight + color: "#00000000" + anchors { + right: parent.right + rightMargin: android.dimen.headerHideRightMargin + top: parent.top + topMargin: android.dimen.headerHideTopMargin + } + + Image { + id: hideIcon + source: "../../../icons/hide.svg" + width: android.dimen.headerHideIconWidth + height: android.dimen.headerHideIconHeight + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + } + } + FiraSansRegular { + anchors { + top: hideIcon.bottom + horizontalCenter: hideIcon.horizontalCenter + topMargin: 12 + } + text: "HIDE" + color: "#FFFFFF" + font.pixelSize: hifi.fonts.pixelSize * 2.5; + } + + MouseArea { + anchors.fill: parent + onClicked: { + hide(); + } + } + } + } + + Component.onCompleted: { + // put on bottom + width = Window.innerWidth; + height = 255; + y = Window.innerHeight - height; + } + + function addButton(properties) { + var component = Qt.createComponent("button.qml"); + if (component.status == Component.Ready) { + var button = component.createObject(flowMain); + // copy all properites to button + var keys = Object.keys(properties).forEach(function (key) { + button[key] = properties[key]; + }); + return button; + } else if( component.status == Component.Error) { + console.log("Load button errors " + component.errorString()); + } + } + + function urlHelper(src) { + if (src.match(/\bhttp/)) { + return src; + } else { + return "../../../" + src; + } + } + +} diff --git a/interface/resources/qml/hifi/+android/button.qml b/interface/resources/qml/hifi/+android/button.qml new file mode 100644 index 0000000000..ec7af2ab92 --- /dev/null +++ b/interface/resources/qml/hifi/+android/button.qml @@ -0,0 +1,230 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 + +Item { + id: button + property string icon: "icons/edit-icon.svg" + property string hoverIcon: button.icon + property string activeIcon: button.icon + property string activeHoverIcon: button.activeIcon + property int stableOrder: 0 + + property int iconSize: 165 + property string text: "." + property string hoverText: button.text + property string activeText: button.text + property string activeHoverText: button.activeText + + property string bgColor: "#ffffff" + property string hoverBgColor: button.bgColor + property string activeBgColor: button.bgColor + property string activeHoverBgColor: button.bgColor + + property real bgOpacity: 0 + property real hoverBgOpacity: 1 + property real activeBgOpacity: 0.5 + property real activeHoverBgOpacity: 1 + + property string textColor: "#ffffff" + property int textSize: 54 + property string hoverTextColor: "#ffffff" + property string activeTextColor: "#ffffff" + property string activeHoverTextColor: "#ffffff" + property int bottomMargin: 30 + + property bool isEntered: false + property double sortOrder: 100 + + property bool isActive: false + + signal clicked() + + onIsActiveChanged: { + if (button.isEntered) { + button.state = (button.isActive) ? "hover active state" : "hover state"; + } else { + button.state = (button.isActive) ? "active state" : "base state"; + } + } + + function editProperties(props) { + for (var prop in props) { + button[prop] = props[prop]; + } + } + + + width: 300 + height: 300 + + Rectangle { + id: buttonBg + color: bgColor + opacity: bgOpacity + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: parent.top + anchors.topMargin: 0 + } + Image { + id: icon + width: iconSize + height: iconSize + anchors.bottom: text.top + anchors.bottomMargin: 6 + anchors.horizontalCenter: parent.horizontalCenter + fillMode: Image.Stretch + source: urlHelper(button.icon) + } + FontLoader { + id: firaSans + source: "../../../fonts/FiraSans-Regular.ttf" + } + Text { + id: text + color: "#ffffff" + text: button.text + font.family: "FiraSans" + //font.bold: true + font.pixelSize: textSize + anchors.bottom: parent.bottom + anchors.bottomMargin: bottomMargin + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + } + MouseArea { + anchors.fill: parent + hoverEnabled: true + enabled: true + onClicked: { + console.log("Bottom bar button clicked!!"); + /*if (tabletButton.inDebugMode) { + if (tabletButton.isActive) { + tabletButton.isActive = false; + } else { + tabletButton.isActive = true; + } + }*/ + button.clicked(); + /*if (tabletRoot) { + tabletRoot.playButtonClickSound(); + }*/ + } + onEntered: { + button.isEntered = true; + if (button.isActive) { + button.state = "hover active state"; + } else { + button.state = "hover state"; + } + } + onExited: { + button.isEntered = false; + if (button.isActive) { + button.state = "active state"; + } else { + button.state = "base state"; + } + } + } + states: [ + State { + name: "hover state" + + PropertyChanges { + target: buttonBg + //color: "#cfcfcf" + //opacity: 1 + color: button.hoverBgColor + opacity: button.hoverBgOpacity + } + + PropertyChanges { + target: text + //color: "#ffffff" + color: button.hoverTextColor + text: button.hoverText + } + + PropertyChanges { + target: icon + source: urlHelper(button.hoverIcon) + } + }, + State { + name: "active state" + + PropertyChanges { + target: buttonBg + //color: "#1fc6a6" + //opacity: 1 + color: button.activeBgColor + opacity: button.activeBgOpacity + } + + PropertyChanges { + target: text + //color: "#333333" + color: button.activeTextColor + text: button.activeText + } + + PropertyChanges { + target: icon + source: urlHelper(button.activeIcon) + } + }, + State { + name: "hover active state" + + PropertyChanges { + target: buttonBg + //color: "#ff0000" + //opacity: 1 + color: button.activeHoverBgColor + opacity: button.activeHoverBgOpacity + } + + PropertyChanges { + target: text + //color: "#333333" + color: button.activeHoverTextColor + text: button.activeHoverText + } + + PropertyChanges { + target: icon + source: urlHelper(button.activeHoverIcon) + } + }, + State { + name: "base state" + + PropertyChanges { + target: buttonBg + //color: "#9A9A9A" + //opacity: 0.1 + color: button.bgColor + opacity: button.bgOpacity + } + + PropertyChanges { + target: text + //color: "#ffffff" + color: button.textColor + text: button.text + } + + PropertyChanges { + target: icon + source: urlHelper(button.icon) + } + } + ] +} \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 48c15439ab..00c0dd8387 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -138,6 +138,7 @@ #include #include #include +#include #include #include #include @@ -5863,6 +5864,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor); #endif scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor); + scriptEngine->registerFunction("QmlFragment", QmlFragmentClass::constructor); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get().data()); diff --git a/libraries/ui/src/QmlFragmentClass.cpp b/libraries/ui/src/QmlFragmentClass.cpp new file mode 100644 index 0000000000..ff67022305 --- /dev/null +++ b/libraries/ui/src/QmlFragmentClass.cpp @@ -0,0 +1,88 @@ +// +// Created by Gabriel Calero & Cristian Duarte on Aug 25, 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 +// + +#include "QmlFragmentClass.h" + +#include +#include +#include + +#include + +#include "OffscreenUi.h" + + +std::mutex QmlFragmentClass::_mutex; +std::map QmlFragmentClass::_fragments; + +QmlFragmentClass::QmlFragmentClass(QString id) : + qml(id) { +} +// Method called by Qt scripts to create a new bottom menu bar in Android +QScriptValue QmlFragmentClass::constructor(QScriptContext* context, QScriptEngine* engine) { + + std::lock_guard guard(_mutex); + auto qml = context->argument(0).toVariant().toMap().value("qml"); + if (qml.isValid()) { + // look up tabletId in the map. + auto iter = _fragments.find(qml.toString()); + if (iter != _fragments.end()) { + //qDebug() << "[QML-ANDROID] QmlFragmentClass menu already exists"; + return iter->second; + } + } else { + qWarning() << "QmlFragmentClass could not build instance " << qml; + return QScriptValue(); + } + + auto properties = parseArguments(context); + auto offscreenUi = DependencyManager::get(); + QmlFragmentClass* retVal = new QmlFragmentClass(qml.toString()); + Q_ASSERT(retVal); + if (QThread::currentThread() != qApp->thread()) { + retVal->moveToThread(qApp->thread()); + BLOCKING_INVOKE_METHOD(retVal, "initQml", Q_ARG(QVariantMap, properties)); + } else { + retVal->initQml(properties); + } + connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); + QScriptValue scriptObject = engine->newQObject(retVal); + _fragments[qml.toString()] = scriptObject; + return scriptObject; +} + +void QmlFragmentClass::close() { + QmlWindowClass::close(); + _fragments.erase(qml); +} + +QObject* QmlFragmentClass::addButton(const QVariant& properties) { + QVariant resultVar; + Qt::ConnectionType connectionType = Qt::AutoConnection; + + if (QThread::currentThread() != _qmlWindow->thread()) { + connectionType = Qt::BlockingQueuedConnection; + } + bool hasResult = QMetaObject::invokeMethod(_qmlWindow, "addButton", connectionType, + Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, properties)); + if (!hasResult) { + qWarning() << "QmlFragmentClass addButton has no result"; + return NULL; + } + + QObject* qmlButton = qvariant_cast(resultVar); + if (!qmlButton) { + qWarning() << "QmlFragmentClass addButton result not a QObject"; + return NULL; + } + + return qmlButton; +} + +void QmlFragmentClass::removeButton(QObject* button) { +} diff --git a/libraries/ui/src/QmlFragmentClass.h b/libraries/ui/src/QmlFragmentClass.h new file mode 100644 index 0000000000..87c18a49ad --- /dev/null +++ b/libraries/ui/src/QmlFragmentClass.h @@ -0,0 +1,45 @@ +// +// Created by Gabriel Calero & Cristian Duarte on Aug 25, 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 +// + +#ifndef hifi_ui_QmlFragmentClass_h +#define hifi_ui_QmlFragmentClass_h + +#include "QmlWindowClass.h" + +class QmlFragmentClass : public QmlWindowClass { + Q_OBJECT +public: + QmlFragmentClass(QString id); + static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + + /**jsdoc + * Creates a new button, adds it to this and returns it. + * @function QmlFragmentClass#addButton + * @param properties {Object} button properties + * @returns {TabletButtonProxy} + */ + Q_INVOKABLE QObject* addButton(const QVariant& properties); + + /* + * TODO - not yet implemented + */ + Q_INVOKABLE void removeButton(QObject* tabletButtonProxy); +public slots: + Q_INVOKABLE void close(); + +protected: + QString qmlSource() const override { return qml; } + + static std::mutex _mutex; + static std::map _fragments; +private: + QString qml; + +}; + +#endif diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index db3df34dc5..a22a5e5a5f 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -28,7 +28,7 @@ #include #include #include - +#include #include #include #include @@ -1136,6 +1136,17 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even } break; } + case QEvent::InputMethod: + case QEvent::InputMethodQuery: { + if (_quickWindow && _quickWindow->activeFocusItem()) { + event->ignore(); + if (QCoreApplication::sendEvent(_quickWindow->activeFocusItem(), event)) { + return event->isAccepted(); + } + return false; + } + break; + } #endif default: break; diff --git a/scripts/+android/defaultScripts.js b/scripts/+android/defaultScripts.js index 54c899d1da..a85b7e2208 100644 --- a/scripts/+android/defaultScripts.js +++ b/scripts/+android/defaultScripts.js @@ -13,7 +13,8 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/progress.js", - "system/touchscreenvirtualpad.js"/*, + "system/touchscreenvirtualpad.js", + "system/bottombar.js"/*, "system/away.js", "system/controllers/controllerDisplayManager.js", "system/controllers/handControllerGrabAndroid.js", diff --git a/scripts/system/bottombar.js b/scripts/system/bottombar.js new file mode 100644 index 0000000000..064025f392 --- /dev/null +++ b/scripts/system/bottombar.js @@ -0,0 +1,159 @@ +"use strict"; +// +// bottombar.js +// scripts/system/ +// +// Created by Gabriel Calero & Cristian Duarte on Jan 18, 2018 +// Copyright 2018 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() { // BEGIN LOCAL_SCOPE + +var bottombar; +var bottomHudOptionsBar; +var gotoBtn; + +var gotoScript = Script.require('./goto-android.js'); + +var logEnabled = false; + +function printd(str) { + if (logEnabled) { + print("[bottombar.js] " + str); + } +} + +function init() { + gotoScript.init(); + gotoScript.setOnShownChange(function (shown) { + if (shown) { + showAddressBar(); + } else { + hideAddressBar(); + } + }); + + setupBottomBar(); + setupBottomHudOptionsBar(); + + raiseBottomBar(); + +} + +function shutdown() { +} + +function setupBottomBar() { + bottombar = new QmlFragment({ + qml: "hifi/bottombar.qml" + }); + + bottombar.fromQml.connect(function(message) { + switch (message.method) { + case 'hide': + lowerBottomBar(); + break; + default: + print('[bottombar.js] Unrecognized message from bottomHud.qml:', JSON.stringify(message)); + } + }); + + + gotoBtn = bottombar.addButton({ + icon: "icons/goto-i.svg", + activeIcon: "icons/goto-a.svg", + bgOpacity: 0, + hoverBgOpacity: 0, + activeBgOpacity: 0, + activeHoverBgOpacity: 0, + height: 240, + width: 300, + iconSize: 108, + textSize: 45, + text: "GO TO" + }); + + gotoBtn.clicked.connect(function() { + if (!gotoScript.isVisible()) { + showAddressBar(); + } else { + hideAddressBar(); + } + }); + + // TODO: setup all the buttons or provide a dynamic interface + + raiseBottomBar(); + + +} + +var setupBottomHudOptionsBar = function() { + var bottomHud = new QmlFragment({ + qml: "hifi/bottomHudOptions.qml" + }); + + bottomHudOptionsBar = { + show: function() { + bottomHud.setVisible(true); + }, + hide: function() { + bottomHud.setVisible(false); + }, + qmlFragment: bottomHud + }; + bottomHud.fromQml.connect( + function(message) { + switch (message.method) { + case 'showUpBar': + printd('[bottombar.js] showUpBar message from bottomHudOptions.qml: ', JSON.stringify(message)); + raiseBottomBar(); + break; + default: + print('[bottombar.js] Unrecognized message from bottomHudOptions.qml:', JSON.stringify(message)); + } + } + ); +} + +function lowerBottomBar() { + if (bottombar) { + bottombar.setVisible(false); + } + if (bottomHudOptionsBar) { + bottomHudOptionsBar.show(); + } +} + +function raiseBottomBar() { + print('[bottombar.js] raiseBottomBar begin'); + if (bottombar) { + bottombar.setVisible(true); + } + if (bottomHudOptionsBar) { + bottomHudOptionsBar.hide(); + } + print('[bottombar.js] raiseBottomBar end'); +} + +function showAddressBar() { + gotoScript.show(); + gotoBtn.isActive = true; +} + +function hideAddressBar() { + gotoScript.hide(); + gotoBtn.isActive = false; +} + + + +Script.scriptEnding.connect(function () { + shutdown(); +}); + +init(); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/goto-android.js b/scripts/system/goto-android.js new file mode 100644 index 0000000000..e917455128 --- /dev/null +++ b/scripts/system/goto-android.js @@ -0,0 +1,96 @@ +"use strict"; +// +// goto-android.js +// scripts/system/ +// +// Created by Gabriel Calero & Cristian Duarte on 12 Sep 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 +// + +var window; + + +var logEnabled = false; +function printd(str) { + if (logEnabled) + print("[goto-android.js] " + str); +} + +function init() { +} + +function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. + switch (message.method) { + case 'shownChanged': + if (notifyShownChange) { + notifyShownChange(message.params.shown); + } ; + break; + case 'hide': + module.exports.hide(); + module.exports.onHidden(); + break; + default: + print('[goto-android.js] Unrecognized message from AddressBarDialog.qml:', JSON.stringify(message)); + } +} + +function sendToQml(message) { + window.sendToQml(message); +} + +var isVisible = false; +var notifyShownChange; +module.exports = { + init: function() { + window = new QmlFragment({ + qml: "AddressBarDialog.qml", + visible: false + }); + }, + show: function() { + Controller.setVPadEnabled(false); + if (window) { + window.fromQml.connect(fromQml); + window.setVisible(true); + isVisible = true; + } + }, + hide: function() { + Controller.setVPadEnabled(true); + if (window) { + window.fromQml.disconnect(fromQml); + window.setVisible(false); + } + isVisible = false; + }, + destroy: function() { + if (window) { + window.close(); + window = null; + } + }, + isVisible: function() { + return isVisible; + }, + width: function() { + return window ? window.size.x : 0; + }, + height: function() { + return window ? window.size.y : 0; + }, + position: function() { + return window && isVisible ? window.position : null; + }, + setOnShownChange: function(f) { + notifyShownChange = f; + }, + onHidden: function() { } + + +}; + +init(); From a7c77a5247987b93de35f683e63eafa4d693a80f Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Thu, 25 Jan 2018 12:36:56 -0300 Subject: [PATCH 02/61] Fix undefined color in address bar --- interface/resources/qml/+android/AddressBarDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/+android/AddressBarDialog.qml b/interface/resources/qml/+android/AddressBarDialog.qml index e07af24b8d..0b12301561 100644 --- a/interface/resources/qml/+android/AddressBarDialog.qml +++ b/interface/resources/qml/+android/AddressBarDialog.qml @@ -220,7 +220,7 @@ Item { location.visible = false; } else { notice.text = AddressManager.isConnected ? "YOUR LOCATION:" : "NOT CONNECTED"; - notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.turquoise : hifiStyleConstants.colors.redHighlight; + notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.blueHighlight : hifiStyleConstants.colors.redHighlight; // Display hostname, which includes ip address, localhost, and other non-placenames. location.text = (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''); location.visible = true; From 8093ed7c5ca92954f51d66f4e08b5d70cad644cc Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Fri, 26 Jan 2018 17:49:08 -0300 Subject: [PATCH 03/61] Add audio bar to mute/unmute the mic --- .../resources/icons/+android/mic-mute-a.svg | 18 +++++ .../resources/icons/+android/mic-mute-i.svg | 21 ++++++ .../resources/icons/+android/mic-unmute-a.svg | 70 ++++++++++++++++++ .../resources/icons/+android/mic-unmute-i.svg | 22 ++++++ .../resources/qml/hifi/+android/AudioBar.qml | 71 +++++++++++++++++++ scripts/+android/defaultScripts.js | 5 +- scripts/system/+android/audio.js | 67 +++++++++++++++++ scripts/system/{ => +android}/bottombar.js | 2 +- .../{goto-android.js => +android/goto.js} | 0 .../{ => +android}/touchscreenvirtualpad.js | 2 +- 10 files changed, 274 insertions(+), 4 deletions(-) create mode 100644 interface/resources/icons/+android/mic-mute-a.svg create mode 100644 interface/resources/icons/+android/mic-mute-i.svg create mode 100644 interface/resources/icons/+android/mic-unmute-a.svg create mode 100644 interface/resources/icons/+android/mic-unmute-i.svg create mode 100644 interface/resources/qml/hifi/+android/AudioBar.qml create mode 100644 scripts/system/+android/audio.js rename scripts/system/{ => +android}/bottombar.js (98%) rename scripts/system/{goto-android.js => +android/goto.js} (100%) rename scripts/system/{ => +android}/touchscreenvirtualpad.js (93%) diff --git a/interface/resources/icons/+android/mic-mute-a.svg b/interface/resources/icons/+android/mic-mute-a.svg new file mode 100644 index 0000000000..73555ce21b --- /dev/null +++ b/interface/resources/icons/+android/mic-mute-a.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/mic-mute-i.svg b/interface/resources/icons/+android/mic-mute-i.svg new file mode 100644 index 0000000000..56e33eab6b --- /dev/null +++ b/interface/resources/icons/+android/mic-mute-i.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/mic-unmute-a.svg b/interface/resources/icons/+android/mic-unmute-a.svg new file mode 100644 index 0000000000..bb28dc0f2b --- /dev/null +++ b/interface/resources/icons/+android/mic-unmute-a.svg @@ -0,0 +1,70 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/icons/+android/mic-unmute-i.svg b/interface/resources/icons/+android/mic-unmute-i.svg new file mode 100644 index 0000000000..76f98d7f0c --- /dev/null +++ b/interface/resources/icons/+android/mic-unmute-i.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/interface/resources/qml/hifi/+android/AudioBar.qml b/interface/resources/qml/hifi/+android/AudioBar.qml new file mode 100644 index 0000000000..f524595ef5 --- /dev/null +++ b/interface/resources/qml/hifi/+android/AudioBar.qml @@ -0,0 +1,71 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import Qt.labs.settings 1.0 +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit +import "../../controls" as HifiControls +import ".." + +Item { + id: bar + x:0 + y:0 + width: 300 + height: 300 + z: -1 + + signal sendToScript(var message); + signal windowClosed(); + + property bool shown: true + + onShownChanged: { + bar.visible = shown; + } + + Rectangle { + anchors.fill : parent + color: "transparent" + Flow { + id: flowMain + spacing: 10 + flow: Flow.TopToBottom + layoutDirection: Flow.TopToBottom + anchors.fill: parent + anchors.margins: 4 + } + } + + Component.onCompleted: { + // put on bottom + x = 0; + y = 0; + width = 300; + height = 300; + } + + function addButton(properties) { + var component = Qt.createComponent("button.qml"); + if (component.status == Component.Ready) { + var button = component.createObject(flowMain); + // copy all properites to button + var keys = Object.keys(properties).forEach(function (key) { + button[key] = properties[key]; + }); + return button; + } else if( component.status == Component.Error) { + console.log("Load button errors " + component.errorString()); + } + } + + function urlHelper(src) { + if (src.match(/\bhttp/)) { + return src; + } else { + return "../../../" + src; + } + } + +} diff --git a/scripts/+android/defaultScripts.js b/scripts/+android/defaultScripts.js index a85b7e2208..2a4af9afbf 100644 --- a/scripts/+android/defaultScripts.js +++ b/scripts/+android/defaultScripts.js @@ -13,8 +13,9 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/progress.js", - "system/touchscreenvirtualpad.js", - "system/bottombar.js"/*, + "system/+android/touchscreenvirtualpad.js", + "system/+android/bottombar.js", + "system/+android/audio.js" /*, "system/away.js", "system/controllers/controllerDisplayManager.js", "system/controllers/handControllerGrabAndroid.js", diff --git a/scripts/system/+android/audio.js b/scripts/system/+android/audio.js new file mode 100644 index 0000000000..b4f156d4bf --- /dev/null +++ b/scripts/system/+android/audio.js @@ -0,0 +1,67 @@ +"use strict"; +// +// audio.js +// scripts/system/ +// +// Created by Gabriel Calero & Cristian Duarte on Jan 16, 2018 +// Copyright 2018 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() { // BEGIN LOCAL_SCOPE + +var audiobar; +var audioButton; + +var logEnabled = true; + +function printd(str) { + if (logEnabled) + print("[audio.js] " + str); +} + +function init() { + audiobar = new QmlFragment({ + qml: "hifi/AudioBar.qml" + }); + + audioButton = audiobar.addButton({ + icon: "icons/mic-unmute-a.svg", + activeIcon: "icons/mic-mute-a.svg", + text: "", + bgOpacity: 0.0, + activeBgOpacity: 0.0, + bgColor: "#FFFFFF" + }); + + onMuteToggled(); + + audioButton.clicked.connect(onMuteClicked); + Audio.mutedChanged.connect(onMuteToggled); +} + +function onMuteClicked() { + printd("On Mute Clicked"); + //Menu.setIsOptionChecked("Mute Microphone", !Menu.isOptionChecked("Mute Microphone")); + Audio.muted = !Audio.muted; + onMuteToggled(); +} + +function onMuteToggled() { + printd("On Mute Toggled"); + audioButton.isActive = Audio.muted; // Menu.isOptionChecked("Mute Microphone") + printd("Audio button is active: " + audioButton.isActive); +} + +Script.scriptEnding.connect(function () { + if(audioButton) { + audioButton.clicked.disconnect(onMuteClicked); + Audio.mutedChanged.connect(onMuteToggled); + } +}); + +init(); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/bottombar.js b/scripts/system/+android/bottombar.js similarity index 98% rename from scripts/system/bottombar.js rename to scripts/system/+android/bottombar.js index 064025f392..e58840ad6f 100644 --- a/scripts/system/bottombar.js +++ b/scripts/system/+android/bottombar.js @@ -15,7 +15,7 @@ var bottombar; var bottomHudOptionsBar; var gotoBtn; -var gotoScript = Script.require('./goto-android.js'); +var gotoScript = Script.require('./goto.js'); var logEnabled = false; diff --git a/scripts/system/goto-android.js b/scripts/system/+android/goto.js similarity index 100% rename from scripts/system/goto-android.js rename to scripts/system/+android/goto.js diff --git a/scripts/system/touchscreenvirtualpad.js b/scripts/system/+android/touchscreenvirtualpad.js similarity index 93% rename from scripts/system/touchscreenvirtualpad.js rename to scripts/system/+android/touchscreenvirtualpad.js index e6f9204d4d..fa41a2b5e0 100644 --- a/scripts/system/touchscreenvirtualpad.js +++ b/scripts/system/+android/touchscreenvirtualpad.js @@ -1,6 +1,6 @@ "use strict"; // -// android.js +// touchscreenvirtualpad.js // scripts/system/ // // Created by Gabriel Calero & Cristian Duarte on Jan 16, 2018 From 917cbd73b19622933ae7cc16ca871d4f90b4c75a Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Fri, 26 Jan 2018 17:50:16 -0300 Subject: [PATCH 04/61] Don't show help on android. Hide menu bar --- interface/src/Application.cpp | 2 ++ .../src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 00c0dd8387..6fec6f1d72 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2826,7 +2826,9 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { // If this is a first run we short-circuit the address passed in if (firstRun.get()) { +#if !defined(Q_OS_ANDROID) showHelp(); +#endif if (sandboxIsRunning) { qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home."; DependencyManager::get()->goToLocalSandbox(); diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index f1fefc9425..1a1714ad56 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -72,6 +72,9 @@ void Basic2DWindowOpenGLDisplayPlugin::uncustomizeContext() { bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() { _framerateActions.clear(); +#if defined(Q_OS_ANDROID) + _container->setFullscreen(nullptr, true); +#endif _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), FULLSCREEN, [this](bool clicked) { if (clicked) { From d5e101c2e8f4ae35c52f75a410a3932521fdb646 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Wed, 24 Jan 2018 12:29:58 -0300 Subject: [PATCH 05/61] Add mode selector (my view / radar), not finished --- .../resources/icons/+android/myview-a.svg | 56 ++++++ .../resources/icons/+android/myview-hover.svg | 54 +++++ .../resources/icons/+android/myview-i.svg | 56 ++++++ .../resources/icons/+android/radar-a.svg | 1 + .../resources/icons/+android/radar-hover.svg | 1 + .../resources/icons/+android/radar-i.svg | 1 + .../resources/qml/hifi/+android/modesbar.qml | 73 +++++++ scripts/+android/defaultScripts.js | 3 +- scripts/system/+android/modes.js | 187 ++++++++++++++++++ 9 files changed, 431 insertions(+), 1 deletion(-) create mode 100755 interface/resources/icons/+android/myview-a.svg create mode 100755 interface/resources/icons/+android/myview-hover.svg create mode 100755 interface/resources/icons/+android/myview-i.svg create mode 100755 interface/resources/icons/+android/radar-a.svg create mode 100755 interface/resources/icons/+android/radar-hover.svg create mode 100755 interface/resources/icons/+android/radar-i.svg create mode 100644 interface/resources/qml/hifi/+android/modesbar.qml create mode 100644 scripts/system/+android/modes.js diff --git a/interface/resources/icons/+android/myview-a.svg b/interface/resources/icons/+android/myview-a.svg new file mode 100755 index 0000000000..307b559c95 --- /dev/null +++ b/interface/resources/icons/+android/myview-a.svg @@ -0,0 +1,56 @@ + + + +image/svg+xmlAsset 3 \ No newline at end of file diff --git a/interface/resources/icons/+android/myview-hover.svg b/interface/resources/icons/+android/myview-hover.svg new file mode 100755 index 0000000000..49656ad294 --- /dev/null +++ b/interface/resources/icons/+android/myview-hover.svg @@ -0,0 +1,54 @@ + + + +image/svg+xmlAsset 3 \ No newline at end of file diff --git a/interface/resources/icons/+android/myview-i.svg b/interface/resources/icons/+android/myview-i.svg new file mode 100755 index 0000000000..574f51c615 --- /dev/null +++ b/interface/resources/icons/+android/myview-i.svg @@ -0,0 +1,56 @@ + + + +image/svg+xmlAsset 3 \ No newline at end of file diff --git a/interface/resources/icons/+android/radar-a.svg b/interface/resources/icons/+android/radar-a.svg new file mode 100755 index 0000000000..e4b157f827 --- /dev/null +++ b/interface/resources/icons/+android/radar-a.svg @@ -0,0 +1 @@ +Asset 1 \ No newline at end of file diff --git a/interface/resources/icons/+android/radar-hover.svg b/interface/resources/icons/+android/radar-hover.svg new file mode 100755 index 0000000000..e4b157f827 --- /dev/null +++ b/interface/resources/icons/+android/radar-hover.svg @@ -0,0 +1 @@ +Asset 1 \ No newline at end of file diff --git a/interface/resources/icons/+android/radar-i.svg b/interface/resources/icons/+android/radar-i.svg new file mode 100755 index 0000000000..3994a775d3 --- /dev/null +++ b/interface/resources/icons/+android/radar-i.svg @@ -0,0 +1 @@ +Asset 1 \ No newline at end of file diff --git a/interface/resources/qml/hifi/+android/modesbar.qml b/interface/resources/qml/hifi/+android/modesbar.qml new file mode 100644 index 0000000000..8ce455c2c1 --- /dev/null +++ b/interface/resources/qml/hifi/+android/modesbar.qml @@ -0,0 +1,73 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import Qt.labs.settings 1.0 +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit +import "../../controls" as HifiControls +import ".." + +Item { + id: modesbar + y:60 + Rectangle { + anchors.fill : parent + color: "transparent" + Flow { + id: flowMain + spacing: 0 + flow: Flow.TopToBottom + layoutDirection: Flow.TopToBottom + anchors.fill: parent + anchors.margins: 4 + } + } + + Component.onCompleted: { + width = 330; + height = 330; + x=Window.innerWidth - width; + } + + function addButton(properties) { + var component = Qt.createComponent("button.qml"); + console.log("load button"); + if (component.status == Component.Ready) { + console.log("load button 2"); + var button = component.createObject(flowMain); + // copy all properites to button + var keys = Object.keys(properties).forEach(function (key) { + button[key] = properties[key]; + }); + return button; + } else if( component.status == Component.Error) { + console.log("Load button errors " + component.errorString()); + } + } + + function removeButton(name) { + } + + function urlHelper(src) { + if (src.match(/\bhttp/)) { + return src; + } else { + return "../../../" + src; + } + } + + function fromScript(message) { + switch (message.type) { + case "allButtonsShown": + modesbar.height = flowMain.children.length * 100 + 10; + break; + case "inactiveButtonsHidden": + modesbar.height = 100 + 10; + break; + default: + break; + } + } + +} diff --git a/scripts/+android/defaultScripts.js b/scripts/+android/defaultScripts.js index 2a4af9afbf..a61c205980 100644 --- a/scripts/+android/defaultScripts.js +++ b/scripts/+android/defaultScripts.js @@ -15,7 +15,8 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/progress.js", "system/+android/touchscreenvirtualpad.js", "system/+android/bottombar.js", - "system/+android/audio.js" /*, + "system/+android/audio.js" /, + "system/+android/modes.js"*, "system/away.js", "system/controllers/controllerDisplayManager.js", "system/controllers/handControllerGrabAndroid.js", diff --git a/scripts/system/+android/modes.js b/scripts/system/+android/modes.js new file mode 100644 index 0000000000..0be53c2fc4 --- /dev/null +++ b/scripts/system/+android/modes.js @@ -0,0 +1,187 @@ +"use strict"; +// +// modes.js +// scripts/system/ +// +// Created by Gabriel Calero & Cristian Duarte on Jan 23, 2018 +// Copyright 2018 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() { // BEGIN LOCAL_SCOPE + +var modesbar; +var modesButtons; +var currentSelectedBtn; + +var SETTING_CURRENT_MODE_KEY = 'Android/Mode'; +var MODE_VR = "VR", MODE_RADAR = "RADAR", MODE_MY_VIEW = "MY VIEW"; +var DEFAULT_MODE = MODE_RADAR; +var logEnabled = true; + +function printd(str) { + if (logEnabled) { + print("[modes.js] " + str); + } +} + +function init() { + setupModesBar(); +} + +function shutdown() { + +} + +function setupModesBar() { + + var bar = new QmlFragment({ + qml: "hifi/modesbar.qml" + }); + var buttonRadarMode = bar.addButton({ + icon: "icons/radar-i.svg", + activeIcon: "icons/radar-a.svg", + hoverIcon: "icons/radar-a.svg", + activeBgOpacity: 0.0, + hoverBgOpacity: 0.0, + activeHoverBgOpacity: 0.0, + text: "RADAR", + height:240, + bottomMargin: 6, + textSize: 45 + }); + var buttonMyViewMode = bar.addButton({ + icon: "icons/myview-i.svg", + activeIcon: "icons/myview-a.svg", + hoverIcon: "icons/myview-a.svg", + activeBgOpacity: 0.0, + hoverBgOpacity: 0.0, + activeHoverBgOpacity: 0.0, + text: "MY VIEW", + height: 240, + bottomMargin: 6, + textSize: 45 + }); + + modesButtons = [buttonRadarMode, buttonMyViewMode]; + + var mode = getCurrentModeSetting(); + + var buttonsRevealed = false; + bar.sendToQml({type: "inactiveButtonsHidden"}); + + modesbar = { + restoreMyViewButton: function() { + switchModeButtons(buttonMyViewMode); + saveCurrentModeSetting(MODE_MY_VIEW); + }, + sendToQml: function(o) { bar.sendToQml(o); }, + qmlFragment: bar + }; + + buttonRadarMode.clicked.connect(function() { + //if (connections.isVisible()) return; + saveCurrentModeSetting(MODE_RADAR); + printd("Radar clicked"); + onButtonClicked(buttonRadarMode, function() { + //radar.startRadarMode(); + }); + }); + buttonMyViewMode.clicked.connect(function() { + //if (connections.isVisible()) return; + saveCurrentModeSetting(MODE_MY_VIEW); + printd("My View clicked"); + onButtonClicked(buttonMyViewMode, function() { + if (currentSelectedBtn == buttonRadarMode) { + //radar.endRadarMode(); + } + }); + }); + + var savedButton; + if (mode == MODE_MY_VIEW) { + savedButton = buttonMyViewMode; + } else { + savedButton = buttonRadarMode; + } + printd("[MODE] previous mode " + mode); + + savedButton.clicked(); +} + +function saveCurrentModeSetting(mode) { + Settings.setValue(SETTING_CURRENT_MODE_KEY, mode); +} + +function getCurrentModeSetting(mode) { + return Settings.getValue(SETTING_CURRENT_MODE_KEY, DEFAULT_MODE); +} + +function showAllButtons() { + for (var i=0; i Date: Wed, 31 Jan 2018 15:12:44 -0300 Subject: [PATCH 06/61] Fix +android/defaultScripts array of filenames. --- scripts/+android/defaultScripts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/+android/defaultScripts.js b/scripts/+android/defaultScripts.js index a61c205980..a8f6bf42a1 100644 --- a/scripts/+android/defaultScripts.js +++ b/scripts/+android/defaultScripts.js @@ -15,8 +15,8 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/progress.js", "system/+android/touchscreenvirtualpad.js", "system/+android/bottombar.js", - "system/+android/audio.js" /, - "system/+android/modes.js"*, + "system/+android/audio.js" , + "system/+android/modes.js"/*, "system/away.js", "system/controllers/controllerDisplayManager.js", "system/controllers/handControllerGrabAndroid.js", From b6ce3409d8619615907d1c2c9a37377f4752e6cf Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Wed, 31 Jan 2018 15:33:14 -0300 Subject: [PATCH 07/61] Android - Make it possible to use the touchpad for walk/fly (and orientate/see) when not in independent camera mode (allowing first person and third person). --- .../resources/controllers/touchscreenvirtualpad.json | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/interface/resources/controllers/touchscreenvirtualpad.json b/interface/resources/controllers/touchscreenvirtualpad.json index 9f65994e98..8c21044c3b 100644 --- a/interface/resources/controllers/touchscreenvirtualpad.json +++ b/interface/resources/controllers/touchscreenvirtualpad.json @@ -1,15 +1,12 @@ { "name": "TouchscreenVirtualPad to Actions", "channels": [ - { "from": "TouchscreenVirtualPad.LY", "when": "Application.CameraFirstPerson", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateZ" }, - { "from": "TouchscreenVirtualPad.LX", "when": "Application.CameraFirstPerson", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateX" }, + { "from": "TouchscreenVirtualPad.LY", "when": "!Application.CameraIndependent", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateZ" }, + { "from": "TouchscreenVirtualPad.LX", "when": "!Application.CameraIndependent", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateX" }, - { "from": "TouchscreenVirtualPad.RX", "when": "Application.CameraFirstPerson", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.Yaw" }, + { "from": "TouchscreenVirtualPad.RX", "when": "!Application.CameraIndependent", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.Yaw" }, - { "from": "TouchscreenVirtualPad.RY", - "when": "Application.CameraFirstPerson", - "to": "Actions.Pitch" - } + { "from": "TouchscreenVirtualPad.RY", "when": "!Application.CameraIndependent", "to": "Actions.Pitch" } ] } From e8312c72be21906f833a0a29f3fec71139223f34 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Fri, 2 Feb 2018 12:57:41 -0300 Subject: [PATCH 08/61] Android - Radar mode implemented. --- scripts/system/+android/modes.js | 37 +- scripts/system/+android/radar.js | 1212 ++++++++++++++++++++++++ scripts/system/+android/uniqueColor.js | 46 + 3 files changed, 1293 insertions(+), 2 deletions(-) create mode 100644 scripts/system/+android/radar.js create mode 100644 scripts/system/+android/uniqueColor.js diff --git a/scripts/system/+android/modes.js b/scripts/system/+android/modes.js index 0be53c2fc4..b29548094f 100644 --- a/scripts/system/+android/modes.js +++ b/scripts/system/+android/modes.js @@ -20,6 +20,9 @@ var MODE_VR = "VR", MODE_RADAR = "RADAR", MODE_MY_VIEW = "MY VIEW"; var DEFAULT_MODE = MODE_RADAR; var logEnabled = true; +var radar = Script.require('./radar.js'); +var uniqueColor = Script.require('./uniqueColor.js'); + function printd(str) { if (logEnabled) { print("[modes.js] " + str); @@ -27,7 +30,10 @@ function printd(str) { } function init() { + radar.setUniqueColor(uniqueColor); + radar.init(); setupModesBar(); + radar.isTouchValid = isRadarModeValidTouch; } function shutdown() { @@ -85,7 +91,7 @@ function setupModesBar() { saveCurrentModeSetting(MODE_RADAR); printd("Radar clicked"); onButtonClicked(buttonRadarMode, function() { - //radar.startRadarMode(); + radar.startRadarMode(); }); }); buttonMyViewMode.clicked.connect(function() { @@ -94,7 +100,7 @@ function setupModesBar() { printd("My View clicked"); onButtonClicked(buttonMyViewMode, function() { if (currentSelectedBtn == buttonRadarMode) { - //radar.endRadarMode(); + radar.endRadarMode(); } }); }); @@ -177,6 +183,33 @@ function onButtonClicked(clickedButton, whatToDo, hideAllAfter) { } } +function isRadarModeValidTouch(coords) { + var qmlFragments = [modesbar.qmlFragment]; + var windows = []; + for (var i=0; i < qmlFragments.length; i++) { + var aQmlFrag = qmlFragments[i]; + if (aQmlFrag != null && aQmlFrag.isVisible() && + coords.x >= aQmlFrag.position.x * 3 && coords.x <= aQmlFrag.position.x * 3 + aQmlFrag.size.x * 3 && + coords.y >= aQmlFrag.position.y * 3 && coords.y <= aQmlFrag.position.y * 3 + aQmlFrag.size.y * 3 + ) { + printd("godViewModeTouchValid- false because of qmlFragments!? idx " + i); + return false; + } + } + + for (var i=0; i < windows.length; i++) { + var aWin = windows[i]; + if (aWin != null && aWin.position() != null && + coords.x >= aWin.position().x * 3 && coords.x <= aWin.position().x * 3 + aWin.width() * 3 && + coords.y >= aWin.position().y * 3 && coords.y <= aWin.position().y * 3 + aWin.height() * 3 + ) { + printd("godViewModeTouchValid- false because of windows!?"); + return false; + } + } + printd("godViewModeTouchValid- true by default "); + return true; +} Script.scriptEnding.connect(function () { shutdown(); diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js new file mode 100644 index 0000000000..9fa07178f6 --- /dev/null +++ b/scripts/system/+android/radar.js @@ -0,0 +1,1212 @@ +"use strict"; +// +// radar.js +// scripts/system/+android/ +// +// Created by Cristian Duarte & Gabriel Calero on 31 Jan 2018 +// Copyright 2018 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 radarModeInterface = {}; + +var logEnabled = true; +function printd(str) { + if (logEnabled) + print("[radar.js] " + str); +} + +var radar = false; +var radarHeight = 10; // camera position meters above the avatar +var tablet; + +var RADAR_CAMERA_OFFSET = -1; // 1 meter below the avatar +var ABOVE_GROUND_DROP = 2; +var MOVE_BY = 1; + +// Swipe/Drag vars +var PINCH_INCREMENT_FIRST = 0.4; // 0.1 meters zoom in - out +var PINCH_INCREMENT = 0.4; // 0.1 meters zoom in - out +var RADAR_HEIGHT_MAX_PLUS_AVATAR = 40; +var RADAR_HEIGHT_MIN_PLUS_AVATAR = 2; +var RADAR_CAMERA_DISTANCE_TO_ICONS = 0.5; // Icons are near the camera to prevent the LOD manager dismissing them +var RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE = 1; // How much above the avatar base should the icon appear +var AVATAR_DISPLAY_NAME_HEIGHT = 38; +var AVATAR_DISPLAY_NAME_CHAR_WIDTH = 18; +var lastDragAt; +var lastDeltaDrag; + +var uniqueColor; + +function moveTo(position) { + if (radar) { + MyAvatar.position = position; + Camera.position = Vec3.sum(MyAvatar.position, {x:0, y: radarHeight, z: 0}); + } +} + +function keyPressEvent(event) { + if (radar) { + switch(event.text) { + case "UP": + moveTo(Vec3.sum(MyAvatar.position, {x:0.0, y: 0, z: -1 * MOVE_BY})); + break; + case "DOWN": + moveTo(Vec3.sum(MyAvatar.position, {x:0, y: 0, z: MOVE_BY})); + break; + case "LEFT": + moveTo(Vec3.sum(MyAvatar.position, {x:-1 * MOVE_BY, y: 0, z: 0})); + break; + case "RIGHT": + moveTo(Vec3.sum(MyAvatar.position, {x:MOVE_BY, y: 0, z: 0})); + break; + } + } +} + +function actionOnObjectFromEvent(event) { + var rayIntersection = findRayIntersection(Camera.computePickRay(event.x, event.y)); + if (rayIntersection && rayIntersection.intersects && rayIntersection.overlayID) { + printd("found overlayID touched " + rayIntersection.overlayID); + if (entitiesByOverlayID[rayIntersection.overlayID]) { + var entity = Entities.getEntityProperties(entitiesByOverlayID[rayIntersection.overlayID], ["sourceUrl"]); + App.openUrl(entity.sourceUrl); + return true; + } + } + if (rayIntersection && rayIntersection.intersects && rayIntersection.entityID && rayIntersection.properties) { + printd("found " + rayIntersection.entityID + " of type " + rayIntersection.properties.type) ; + if (rayIntersection.properties.type == "Web") { + printd("found web element to " + rayIntersection.properties.sourceUrl); + App.openUrl(rayIntersection.properties.sourceUrl); + return true; + } + } + return false; +} + +function mousePress(event) { + if (!isTouchValid(coords)) { + currentTouchIsValid = false; + return; + } else { + currentTouchIsValid = true; + } + mousePressOrTouchEnd(event); +} + +function mousePressOrTouchEnd(event) { + if (!currentTouchIsValid) { + return; + } + if (radar) { + if (actionOnObjectFromEvent(event)) return; + } +} + +function toggleRadarMode() { + if (radar) { + endRadar(); + } else { + startRadar(); + } +} + +function fakeDoubleTap(event) { + // CLD - temporarily disable toggling mode through double tap + // * As we have a new UI for toggling between modes, it may be discarded completely in the future. + // toggleRadarMode(); + teleporter.dragTeleportUpdate(event); + teleporter.dragTeleportRelease(event); +} + +var currentTouchIsValid = false; // Currently used to know if touch hasn't started on a UI overlay + +var DOUBLE_TAP_TIME = 300; +var fakeDoubleTapStart = Date.now(); +var touchEndCount = 0; + +/* Counts touchEnds and if there were 2 in the DOUBLE_TAP_TIME lapse, it triggers a fakeDoubleTap and returns true. + Otherwise, returns false (no double tap yet) */ +function analyzeDoubleTap(event) { + var fakeDoubleTapEnd = Date.now(); + var elapsed = fakeDoubleTapEnd - fakeDoubleTapStart; + if (elapsed > DOUBLE_TAP_TIME) { + touchEndCount = 0; + } + + // if this is our first "up" then record time so we can + // later determine if second "up" is a double tap + if (touchEndCount == 0) { + fakeDoubleTapStart = Date.now(); + } + touchEndCount++; + + if (touchEndCount >= 2) { + var fakeDoubleTapEnd = Date.now(); + var elapsed = fakeDoubleTapEnd - fakeDoubleTapStart; + printd("-- fakeDoubleTapEnd:" + fakeDoubleTapEnd + "-- elapsed:" + elapsed) + if (elapsed <= DOUBLE_TAP_TIME) { + touchEndCount = 0; + fakeDoubleTap(event); + return true; // don't do the normal touch end processing + } + + touchEndCount = 0; + } + return false; +} + +function touchEnd(event) { + printd("touchEnd received " + JSON.stringify(event)); + // Clean up touch variables + lastDragAt = null; + lastDeltaDrag = null; + touchStartingCoordinates = null; // maybe in special cases it should be setup later? + startedDraggingCamera = false; + prevTouchPinchRadius = null; + draggingCamera = false; + + if (movingCamera) { + // if camera was indeed moving, we should not further process, it was just dragging + movingCamera = false; + dragModeFunc = null; + return; + } + + // teleport release analysis + if (teleporter && teleporter.dragTeleportUpdate == dragModeFunc) { + teleporter.dragTeleportRelease(event); + dragModeFunc = null; + return; + } + dragModeFunc = null; + + // if pinching or moving is still detected, cancel + if (event.isPinching) { printd("touchEnd fail because isPinching");return;} + if (event.isPinchOpening) { printd("touchEnd fail because isPinchingOpening");return;} + if (event.isMoved) { printd("touchEnd fail because isMoved");return;} + + // if touch is invalid, cancel + if (!currentTouchIsValid) { printd("touchEnd fail because !currentTouchIsValid");return;} + + if (analyzeDoubleTap(event)) return; // double tap detected, finish + + if (radar) { + mousePressOrTouchEnd(event); + } +} + +/** +* Polyfill for sign(x) +*/ +if (!Math.sign) { + Math.sign = function(x) { + // If x is NaN, the result is NaN. + // If x is -0, the result is -0. + // If x is +0, the result is +0. + // If x is negative and not -0, the result is -1. + // If x is positive and not +0, the result is +1. + x = +x; // convert to a number + if (x === 0 || isNaN(x)) { + return Number(x); + } + return x > 0 ? 1 : -1; + }; +} + +/******************************************************************************************************** + * Line and Plane intersection methods + ********************************************************************************************************/ + +/** +* findLinePlaneIntersection +* Given points p {x: y: z:} and q that define a line, and the plane +* of formula ax+by+cz+d = 0, returns the intersection point or null if none. +*/ +function findLinePlaneIntersection(p, q, a, b, c, d) { + return findLinePlaneIntersectionCoords(p.x, p.y, p.z, q.x, q.y, q.z, a, b, c, d); +} + +/** +* findLineToHeightIntersection +* Given points p {x: y: z:} and q that define a line, and a planeY +* value that defines a plane paralel to 'the floor' xz plane, +* returns the intersection to that plane or null if none. +*/ +function findLineToHeightIntersection(p, q, planeY) { + return findLinePlaneIntersection(p, q, 0, 1, 0, -planeY); +} + +/** +* findLinePlaneIntersectionCoords (to avoid requiring unnecessary instantiation) +* Given points p with px py pz and q that define a line, and the plane +* of formula ax+by+cz+d = 0, returns the intersection point or null if none. +*/ +function findLinePlaneIntersectionCoords(px, py, pz, qx, qy, qz, a, b, c, d) { + var tDenom = a*(qx-px) + b*(qy-py) + c*(qz-pz); + if (tDenom == 0) return null; + + var t = - ( a*px + b*py + c*pz + d ) / tDenom; + + return { + x: (px+t*(qx-px)), + y: (py+t*(qy-py)), + z: (pz+t*(qz-pz)) + }; +} + +/** +* findLineToHeightIntersection +* Given points p with px py pz and q that define a line, and a planeY +* value that defines a plane paralel to 'the floor' xz plane, +* returns the intersection to that plane or null if none. +*/ +function findLineToHeightIntersectionCoords(px, py, pz, qx, qy, qz, planeY) { + return findLinePlaneIntersectionCoords(px, py, pz, qx, qy, qz, 0, 1, 0, -planeY); +} + +function findRayIntersection(pickRay) { + // Check 3D overlays and entities. Argument is an object with origin and direction. + var result = Overlays.findRayIntersection(pickRay); + if (!result.intersects) { + result = Entities.findRayIntersection(pickRay, true); + } + return result; +} + +/** + * Given a 2d point (x,y) this function returns the intersection (x, y, z) + * of the computedPickRay for that point with the plane y = py + */ +function computePointAtPlaneY(x,y,py) { + var ray = Camera.computePickRay(x, y); + var p1=ray.origin; + var p2=Vec3.sum(p1, Vec3.multiply(ray.direction, 1)); + return findLineToHeightIntersectionCoords(p1.x, p1.y, p1.z, + p2.x, p2.y, p2.z, py); +} + +/******************************************************************************************************** + * + ********************************************************************************************************/ + +function isTouchValid(coords) { + // TODO: Extend to the detection of touches on new menu bars + var radarModeTouchValid = radarModeInterface.isTouchValid(coords); + + // getItemAtPoint does not exist anymore, look for another way to know if we are touching buttons + // is it still needed? + return /*!tablet.getItemAtPoint(coords) && */radarModeTouchValid; +} + +/******************************************************************************************************** + * + ********************************************************************************************************/ + +var touchStartingCoordinates = null; + +var KEEP_PRESSED_FOR_TELEPORT_MODE_TIME = 750; +var touchBeginTime; + +function touchBegin(event) { + var coords = { x: event.x, y: event.y }; + if (!isTouchValid(coords) ) { + printd("analyze touch - RADAR_TOUCH - INVALID"); + currentTouchIsValid = false; + touchStartingCoordinates = null; + } else { + printd("analyze touch - RADAR_TOUCH - ok"); + currentTouchIsValid = true; + touchStartingCoordinates = coords; + touchBeginTime = Date.now(); + } +} + +var startedDraggingCamera = false; // first time +var draggingCamera = false; // is trying +var movingCamera = false; // definitive + +var MIN_DRAG_DISTANCE_TO_CONSIDER = 100; // distance by axis, not real distance + +var prevTouchPinchRadius = null; + +function pinchUpdate(event) { + if (!event.isMoved) return; + if (event.radius <= 0) return; + + // pinch management + var avatarY = MyAvatar.position.y; + var pinchIncrement; + if (!!prevTouchPinchRadius) { + // no prev value + pinchIncrement = PINCH_INCREMENT * Math.abs(event.radius - prevTouchPinchRadius) * 0.1; + } else { + pinchIncrement = PINCH_INCREMENT_FIRST; + } + + if (event.isPinching) { + if (radarHeight + pinchIncrement > RADAR_HEIGHT_MAX_PLUS_AVATAR + avatarY) { + radarHeight = RADAR_HEIGHT_MAX_PLUS_AVATAR + avatarY; + } else { + radarHeight += pinchIncrement; + } + } else if (event.isPinchOpening) { + if (radarHeight - pinchIncrement < RADAR_HEIGHT_MIN_PLUS_AVATAR + avatarY) { + radarHeight = RADAR_HEIGHT_MIN_PLUS_AVATAR + avatarY; + } else { + radarHeight -= pinchIncrement; + } + } + var deltaHeight = avatarY + radarHeight - Camera.position.y; + Camera.position = Vec3.sum(Camera.position, {x:0, y: deltaHeight, z: 0}); + if (!draggingCamera) { + startedDraggingCamera = true; + draggingCamera = true; + } + + prevTouchPinchRadius = event.radius; +} + +function isInsideSquare(coords0, coords1, halfside) { + return Math.abs(coords0.x-coords1.x) <= halfside && Math.abs(coords0.y-coords1.y) <= halfside; +} + +function dragScrollUpdate(event) { + if (!event.isMoved) return; + + // drag management + var pickRay = Camera.computePickRay(event.x, event.y); + var dragAt = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, radarHeight)); + + if (lastDragAt === undefined || lastDragAt === null) { + lastDragAt = dragAt; + return; + } + + var deltaDrag = {x: (lastDragAt.x - dragAt.x), y: 0, z: (lastDragAt.z-dragAt.z)}; + + lastDragAt = dragAt; + if (lastDeltaDrag === undefined || lastDeltaDrag === null) { + lastDeltaDrag = deltaDrag; + return; + } + + if (!draggingCamera) { + startedDraggingCamera = true; + draggingCamera = true; + } else { + if (!movingCamera) { + if (!isInsideSquare(touchStartingCoordinates, event, MIN_DRAG_DISTANCE_TO_CONSIDER)) { + movingCamera = true; + } + } + + if (movingCamera) { + if (Math.sign(deltaDrag.x) == Math.sign(lastDeltaDrag.x) && Math.sign(deltaDrag.z) == Math.sign(lastDeltaDrag.z)) { + // Process movement if direction of the movement is the same than the previous frame + // process delta + var moveCameraTo = Vec3.sum(Camera.position, deltaDrag); + // move camera + Camera.position = moveCameraTo; + } else { + // Do not move camera if it's changing direction in this case, wait until the next direction confirmation.. + } + lastDeltaDrag = deltaDrag; // save last + } + } +} + +/******************************************************************************************************** + * Teleport feature + ********************************************************************************************************/ + +function Teleporter() { + + var SURFACE_DETECTION_FOR_TELEPORT = true; // true if uses teleport.js similar logic to detect surfaces. false if uses plain teleport to avatar same height. + + var TELEPORT_TARGET_MODEL_URL = Script.resolvePath("../assets/models/teleport-destination.fbx"); + var TELEPORT_TOO_CLOSE_MODEL_URL = Script.resolvePath("../assets/models/teleport-cancel.fbx"); + + var TELEPORT_MODEL_DEFAULT_DIMENSIONS = { + x: 0.10, + y: 0.00001, + z: 0.10 + }; + + var teleportOverlay = Overlays.addOverlay("model", { + url: TELEPORT_TARGET_MODEL_URL, + dimensions: TELEPORT_MODEL_DEFAULT_DIMENSIONS, + orientation: Quat.fromPitchYawRollDegrees(0,180,0), + visible: false + }); + + var teleportCancelOverlay = Overlays.addOverlay("model", { + url: TELEPORT_TOO_CLOSE_MODEL_URL, + dimensions: TELEPORT_MODEL_DEFAULT_DIMENSIONS, + orientation: Quat.fromPitchYawRollDegrees(0,180,0), + visible: false + }); + + var TELEPORT_COLOR = { red: 0, green: 255, blue: 255}; + var TELEPORT_CANCEL_COLOR = { red: 255, green: 255, blue: 0}; + + var teleportLine = Overlays.addOverlay("line3d", { + start: { x: 0, y: 0, z:0 }, + end: { x: 0, y: 0, z: 0 }, + color: TELEPORT_COLOR, + alpha: 1, + lineWidth: 2, + dashed: false, + visible: false + }); + + // code from teleport.js + var TELEPORT_TARGET = { + NONE: 'none', // Not currently targetting anything + INVISIBLE: 'invisible', // The current target is an invvsible surface + INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) + SURFACE: 'surface', // The current target is a valid surface + SEAT: 'seat', // The current target is a seat + } + + var TELEPORT_CANCEL_RANGE = 1; + var teleportTargetType = TELEPORT_TARGET.NONE; + + function parseJSON(json) { + try { + return JSON.parse(json); + } catch (e) { + return undefined; + } + } + + /* + * Enhanced with intersection with terrain instead of using current avatar y position if SURFACE_DETECTION_FOR_TELEPORT is true + */ + function computeDestination(touchEventPos, avatarPosition, cameraPosition, radarH) { + if (SURFACE_DETECTION_FOR_TELEPORT) { + var pickRay = Camera.computePickRay(touchEventPos.x, touchEventPos.y); + printd("newTeleportDetect - pickRay " + JSON.stringify(pickRay)); + var destination = Entities.findRayIntersection(pickRay, true, [], [], false, true); + printd("newTeleportDetect - destination " + JSON.stringify(destination)); + return destination; + } else { + var pickRay = Camera.computePickRay(touchEventPos.x, touchEventPos.y); + var pointingAt = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, radarH)); + var destination = { x: pointingAt.x, y: avatarPosition.y, z: pointingAt.z }; + return destination; + } + } + + function renderTeleportOverlays(destination) { + var overlayPosition = findLineToHeightIntersection(destination, Camera.position, Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS); + printd("[newTeleport] TELEPORT ! render overlay at " + JSON.stringify(overlayPosition)); + + // CLD note Oct 11, 2017 + // Version of teleport.js 3c109f294f88ba7573bd1221f907f2605893c509 doesn't allow invisible surfaces, let's allow it for now + if (teleportTargetType == TELEPORT_TARGET.SURFACE || teleportTargetType == TELEPORT_TARGET.INVISIBLE) { + Overlays.editOverlay(teleportOverlay, { visible: true, position: overlayPosition }); + Overlays.editOverlay(teleportCancelOverlay, { visible: false }); + Overlays.editOverlay(teleportLine, { start: MyAvatar.position, end: destination, color: TELEPORT_COLOR, visible: true }); + } else if (teleportTargetType == TELEPORT_TARGET.INVALID) { + Overlays.editOverlay(teleportOverlay, { visible: false}); + Overlays.editOverlay(teleportCancelOverlay, { visible: true, position: overlayPosition }); + Overlays.editOverlay(teleportLine, { start: MyAvatar.position, end: destination, color: TELEPORT_CANCEL_COLOR, visible: true }); + } else { // TELEPORT_TARGET:NONE? + Overlays.editOverlay(teleportOverlay, { visible: false }); + Overlays.editOverlay(teleportCancelOverlay, { visible: false }); + Overlays.editOverlay(teleportLine, { visible: false }); + } + } + + var BORDER_DISTANCE_PX = 100; + var border_top = 0; + var border_left = 0; + var border_right = Window.innerWidth; + var border_bottom = Window.innerHeight; + + function moveOnBorders(event) { + var xDelta = 0; + var zDelta = 0; + + if (event.y <= border_top + BORDER_DISTANCE_PX) { + zDelta = -0.1; + } else if (event.y >= border_bottom - BORDER_DISTANCE_PX) { + zDelta = 0.1; + } + if (event.x <= border_left + BORDER_DISTANCE_PX) { + xDelta = -0.1; + } else if (event.x >= border_right - BORDER_DISTANCE_PX) { + xDelta = 0.1; + } + if (xDelta == 0 && zDelta == 0) { + draggingCamera = false; + return; + } + + Camera.position = Vec3.sum(Camera.position, {x:xDelta, y: 0, z: zDelta}); + draggingCamera = true; + } + + // When determininig whether you can teleport to a location, the normal of the + // point that is being intersected with is looked at. If this normal is more + // than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from <0, 1, 0> (straight up), then + // you can't teleport there. + const MAX_ANGLE_FROM_UP_TO_TELEPORT = 70; + function getTeleportTargetType(intersection) { + if (SURFACE_DETECTION_FOR_TELEPORT) { + if (!intersection.intersects) { + return TELEPORT_TARGET.NONE; + } + var props = Entities.getEntityProperties(intersection.entityID, ['userData', 'visible']); + var data = parseJSON(props.userData); + if (data !== undefined && data.seat !== undefined) { + return TELEPORT_TARGET.SEAT; + } + + if (!props.visible) { + return TELEPORT_TARGET.INVISIBLE; + } + + var surfaceNormal = intersection.surfaceNormal; + var adj = Math.sqrt(surfaceNormal.x * surfaceNormal.x + surfaceNormal.z * surfaceNormal.z); + var angleUp = Math.atan2(surfaceNormal.y, adj) * (180 / Math.PI); + + if (angleUp < (90 - MAX_ANGLE_FROM_UP_TO_TELEPORT) || + angleUp > (90 + MAX_ANGLE_FROM_UP_TO_TELEPORT) || + Vec3.distance(MyAvatar.position, intersection.intersection) <= TELEPORT_CANCEL_RANGE) { + return TELEPORT_TARGET.INVALID; + } else { + return TELEPORT_TARGET.SURFACE; + } + } else { + var destination = intersection; + if (Vec3.distance(MyAvatar.position, destination) <= TELEPORT_CANCEL_RANGE) { + return TELEPORT_TARGET.INVALID; + } else { + return TELEPORT_TARGET.SURFACE; + } + } + }; + + function moveToFromEvent(event) { + var destination = computeDestination(event, MyAvatar.position, Camera.position, radarHeight); + moveTo(SURFACE_DETECTION_FOR_TELEPORT? + Vec3.sum(destination.intersection, {y: 1}) + :destination); + return true; + } + + return { + dragTeleportBegin : function(event) { + printd("[newTeleport] TELEPORT began"); + var overlayDimensions = entityIconModelDimensions(); + //var destination = computeDestination(event, MyAvatar.position, Camera.position, radarHeight); + // Dimension teleport and cancel overlays (not show them yet) + Overlays.editOverlay(teleportOverlay, { dimensions: overlayDimensions }); + Overlays.editOverlay(teleportCancelOverlay, { dimensions: overlayDimensions }); + // Position line + Overlays.editOverlay(teleportLine, { visible: true, start: 0, end: 0 }); + }, + + dragTeleportUpdate : function(event) { + // if in border, move camera + moveOnBorders(event); + + var destination = computeDestination(event, MyAvatar.position, Camera.position, radarHeight); + + teleportTargetType = getTeleportTargetType(destination); + renderTeleportOverlays( SURFACE_DETECTION_FOR_TELEPORT? + destination.intersection: + destination); + }, + + dragTeleportRelease : function (event) { + printd("[newTeleport] TELEPORT released at " + JSON.stringify(event)); + // CLD note Oct 11, 2017 + // Version of teleport.js 3c109f294f88ba7573bd1221f907f2605893c509 doesn't allow invisible surfaces, let's allow it for now + if (teleportTargetType == TELEPORT_TARGET.SURFACE || teleportTargetType == TELEPORT_TARGET.INVISIBLE) { + moveToFromEvent(event); + } + teleportTargetType = TELEPORT_TARGET.NONE; + + Overlays.editOverlay(teleportOverlay, { visible: false }); + Overlays.editOverlay(teleportLine, { visible: false }); + Overlays.editOverlay(teleportCancelOverlay, { visible: false }); + } + }; + +} + +var teleporter = Teleporter(); + +/******************************************************************************************************** + * + ********************************************************************************************************/ + +var dragModeFunc = null; // by default is nothing + +function oneFingerTouchUpdate(event) { + if (dragModeFunc) { + dragModeFunc(event); + } else { + if (!isInsideSquare(touchStartingCoordinates, event, MIN_DRAG_DISTANCE_TO_CONSIDER)) { + dragModeFunc = dragScrollUpdate; + dragModeFunc(event); + } else { + var now = Date.now(); // check time + if (now - touchBeginTime >= KEEP_PRESSED_FOR_TELEPORT_MODE_TIME) { + teleporter.dragTeleportBegin(event); + dragModeFunc = teleporter.dragTeleportUpdate; + dragModeFunc(event); + } else { + // not defined yet, let's wait for time or movement to happen + } + } + } +} + +function touchUpdate(event) { + if (!currentTouchIsValid) { + return; // avoid moving and zooming when tap is over UI entities + } + if (event.isPinching || event.isPinchOpening) { + pinchUpdate(event); + } else { + oneFingerTouchUpdate(event); + } +} + +/******************************************************************************************************** + * Avatar cache structure for showing avatars markers + ********************************************************************************************************/ + +// by QUuid +var avatarsData = {}; +var avatarsIcons = []; // a parallel list of icons (overlays) to easily run through +var avatarsNames = []; // a parallel list of names (overlays) to easily run through + +function getAvatarIconForUser(uid) { + var color = uniqueColor.getColor(uid); + if (color.charAt(0) == '#' ) { + color = color.substring(1, color.length); + } + // FIXME: this is a temporary solution until we can use circle3d with lineWidth + return Script.resolvePath("assets/images/circle-"+color+".svg"); +} + +var avatarIconDimensionsVal = { x: 0, y: 0, z: 0.00001}; +function avatarIconPlaneDimensions() { + // given the current height, give a size + var xy = -0.003531 * radarHeight + 0.1; + avatarIconDimensionsVal.x = Math.abs(xy); + avatarIconDimensionsVal.y = Math.abs(xy); + // reuse object + return avatarIconDimensionsVal; +} + +function currentOverlayIconForAvatar(QUuid) { + if (avatarsData[QUuid] != undefined) { + return avatarsData[QUuid].icon; + } else { + return null; + } +} + +function currentOverlayNameForAvatar(QUuid) { + if (avatarsData[QUuid] != undefined) { + return avatarsData[QUuid].name; + } else { + return null; + } +} + +function saveAvatarData(QUuid) { + if (QUuid == null) return; + var avat = AvatarList.getAvatar(QUuid); + printd("avatar added save avatar " + QUuid); + + if (!avat) return; + + if (avatarsData[QUuid] != undefined) { + avatarsData[QUuid].position = avat.position; + } else { + var avatarIcon = Overlays.addOverlay("image3d", { + subImage: { x: 0, y: 0, width: 150, height: 142}, + url: getAvatarIconForUser(QUuid), + dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, + visible: false, + ignoreRayIntersection: false, + orientation: Quat.fromPitchYawRollDegrees(-90,0,0) + }); + + var needRefresh = !avat || !avat.displayName; + var displayName = avat && avat.displayName ? avat.displayName : "Unknown"; + var textWidth = displayName.length * AVATAR_DISPLAY_NAME_CHAR_WIDTH; + var avatarName = Overlays.addOverlay("text", { + width: textWidth, + height: AVATAR_DISPLAY_NAME_HEIGHT, + color: { red: 255, green: 255, blue: 255}, + backgroundAlpha: 0.0, + textRaiseColor: { red: 0, green: 0, blue: 0}, + font: {size: 68, bold: true}, + visible: false, + text: displayName, + textAlignCenter: true + }); + avatarsIcons.push(avatarIcon); + avatarsNames.push(avatarName); + avatarsData[QUuid] = { position: avat.position, icon: avatarIcon, name: avatarName, textWidth: textWidth, needRefresh: needRefresh }; + } +} + +function removeAvatarData(QUuid) { + if (QUuid == null) return; + + var itsOverlay = currentOverlayIconForAvatar(QUuid); + if (itsOverlay != null) { + Overlays.deleteOverlay(itsOverlay); + } + var itsNameOverlay = currentOverlayNameForAvatar(QUuid); + if (itsNameOverlay != null) { + Overlays.deleteOverlay(itsNameOverlay); + } + + var idx = avatarsIcons.indexOf(itsOverlay); + avatarsIcons.splice(idx, 1); + idx = avatarsNames.indexOf(itsNameOverlay); + avatarsNames.splice(idx, 1); + + delete avatarsData[QUuid]; +} + +function saveAllOthersAvatarsData() { + var avatarIds = AvatarList.getAvatarIdentifiers(); + var len = avatarIds.length; + for (var i = 0; i < len; i++) { + if (avatarIds[i]) { + saveAvatarData(avatarIds[i]); + } + } +} + + +function avatarAdded(QUuid) { + printd("avatar added " + QUuid);// + " at " + JSON.stringify(AvatarList.getAvatar(QUuid).position)); + saveAvatarData(QUuid); +} + +function avatarRemoved(QUuid) { + printd("avatar removed " + QUuid); + removeAvatarData(QUuid); +} + +/******************************************************************************************************** + * Avatar Icon/Markers rendering + ********************************************************************************************************/ +var myAvatarIcon; +var myAvatarName; + +function renderMyAvatarIcon() { + var iconPos = findLineToHeightIntersectionCoords( MyAvatar.position.x, + MyAvatar.position.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, + MyAvatar.position.z, + Camera.position.x, Camera.position.y, Camera.position.z, + Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS); + if (!iconPos) { printd("avatarmy icon pos null"); return;} + var iconDimensions = avatarIconPlaneDimensions(); + + var avatarPos = MyAvatar.position; + var cameraPos = Camera.position; + var commonY = Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS; + var borderPoints = [ + computePointAtPlaneY(0, 0, commonY), + computePointAtPlaneY(Window.innerWidth, Window.innerHeight, commonY) + ]; + + var p1 = findLineToHeightIntersectionCoords(avatarPos.x, avatarPos.y, avatarPos.z, + cameraPos.x, cameraPos.y, cameraPos.z, + commonY); + var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) / (borderPoints[1].x - borderPoints[0].x); + var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); + + if (!myAvatarIcon && MyAvatar.sessionUUID) { + myAvatarIcon = Overlays.addOverlay("image3d", { + subImage: { x: 0, y: 0, width: 150, height: 142}, + url: getAvatarIconForUser(MyAvatar.sessionUUID), + dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, + visible: false, + ignoreRayIntersection: false, + orientation: Quat.fromPitchYawRollDegrees(-90,0,0) + }); + } + + if (!myAvatarName) { + myAvatarName = Overlays.addOverlay("text", { + width: 40, + height: AVATAR_DISPLAY_NAME_HEIGHT, + textAlignCenter: true, + color: { red: 255, green: 255, blue: 255}, + backgroundAlpha: 0.0, + font: {size: 68, bold: true}, + textRaiseColor: { red: 0, green: 0, blue: 0}, + visible: false, + text: "Me" + }); + } + + if (myAvatarIcon) { + Overlays.editOverlay(myAvatarIcon, { + visible: true, + dimensions: iconDimensions, + position: iconPos + }); + + } + var textSize = (14 + (iconDimensions.y - 0.03) * 15 / 0.06); + + Overlays.editOverlay(myAvatarName, { + visible: true, + x: x - 18 + (iconDimensions.y - 0.03) * 2 / 0.06, + y: y + iconDimensions.y * 550, + font: {size: textSize, bold: true}, + }); + + +} + +function hideAllAvatarIcons() { + var len = avatarsIcons.length; + for (var i = 0; i < len; i++) { + Overlays.editOverlay(avatarsIcons[i], {visible: false}); + } + len = avatarsNames.length; + for (var j = 0; j < len; j++) { + Overlays.editOverlay(avatarsNames[j], {visible: false}); + } + if (myAvatarIcon) { + Overlays.editOverlay(myAvatarIcon, {visible: false}); + } + Overlays.editOverlay(myAvatarName, {visible: false}) +} + +function renderAllOthersAvatarIcons() { + var avatarPos; + var iconDimensions = avatarIconPlaneDimensions(); + var commonY = Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS; + var borderPoints = [ + computePointAtPlaneY(0, 0, commonY), + computePointAtPlaneY(Window.innerWidth, Window.innerHeight, commonY) + ]; + + for (var QUuid in avatarsData) { + if (avatarsData.hasOwnProperty(QUuid)) { + if (AvatarList.getAvatar(QUuid) != null) { + avatarPos = AvatarList.getAvatar(QUuid).position; + + var cameraPos = Camera.position; + var p1 = findLineToHeightIntersectionCoords(avatarPos.x, avatarPos.y, avatarPos.z, + cameraPos.x, cameraPos.y, cameraPos.z, + commonY); + + var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) / (borderPoints[1].x - borderPoints[0].x); + var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); + + if (avatarsData[QUuid].icon != undefined) { + var iconPos = findLineToHeightIntersectionCoords( avatarPos.x, avatarPos.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, avatarPos.z, + Camera.position.x, Camera.position.y, Camera.position.z, + Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS); + if (!iconPos) { print ("avatar icon pos bad for " + QUuid); continue; } + if (avatarsData[QUuid].needRefresh) { + var avat = AvatarList.getAvatar(QUuid); + if (avat && avat.displayName) { + Overlays.editOverlay(avatarsData[QUuid].name, { + width: avat.displayName.length * AVATAR_DISPLAY_NAME_CHAR_WIDTH, + text: avat.displayName, + textAlignCenter: true + }); + avatarsData[QUuid].needRefresh = false; + } + } + var textSize = (14 + (iconDimensions.y - 0.03) * 15 / 0.06); + Overlays.editOverlay(avatarsData[QUuid].icon, { + visible: true, + dimensions: iconDimensions, + position: iconPos + }); + Overlays.editOverlay(avatarsData[QUuid].name, { + visible: true, + x: x - avatarsData[QUuid].textWidth * 0.5, + y: y + iconDimensions.y * 550, + font: {size: textSize, bold: true} + }); + } + } + } + } +} + +function entityAdded(entityID) { + printd ("Entity added " + entityID); + var props = Entities.getEntityProperties(entityID, ["type"]); + printd ("Entity added " + entityID + " PROPS " + JSON.stringify(props)); + if (props && props.type == "Web") { + printd ("Entity Web added " + entityID); + saveEntityData(entityID, true); + } +} + +function entityRemoved(entityID) { + printd ("Entity removed " + entityID); + var props = Entities.getEntityProperties(entityID, ["type"]); + if (props && props.type == "Web") { + print ("Entity Web removed " + entityID); + removeEntityData(entityID); + } +} + +/******************************************************************************************************** + * Entities (to remark) cache structure for showing entities markers + ********************************************************************************************************/ + +var entitiesData = {}; // by entityID +var entitiesByOverlayID = {}; // by overlayID +var entitiesIcons = []; // a parallel list of icons (overlays) to easily run through + +var ICON_ENTITY_WEB_MODEL_URL = Script.resolvePath("../assets/images/web.svg"); +var ICON_ENTITY_IMG_MODEL_URL = Script.resolvePath("../assets/models/teleport-cancel.fbx"); // FIXME - use correct model&texture +var ICON_ENTITY_DEFAULT_DIMENSIONS = { + x: 0.10, + y: 0.00001, + z: 0.10 +}; + +var entityIconModelDimensionsVal = { x: 0, y: 0.00001, z: 0}; +function entityIconModelDimensions() { + // given the current height, give a size + var xz = -0.002831 * radarHeight + 0.1; + entityIconModelDimensionsVal.x = xz; + entityIconModelDimensionsVal.z = xz; + // reuse object + return entityIconModelDimensionsVal; +} +/* + * entityIconPlaneDimensions: similar to entityIconModelDimensions but using xy plane + */ +function entityIconPlaneDimensions() { + var dim = entityIconModelDimensions(); + var z = dim.z; + dim.z = dim.y; + dim.y = z; + return dim; +} + +function currentOverlayForEntity(QUuid) { + if (entitiesData[QUuid] != undefined) { + return entitiesData[QUuid].icon; + } else { + return null; + } +} + +function saveEntityData(QUuid, planar) { + if (QUuid == null) return; + var entity = Entities.getEntityProperties(QUuid, ["position"]); + printd("entity added save entity " + QUuid); + if (entitiesData[QUuid] != undefined) { + entitiesData[QUuid].position = entity.position; + } else { + var entityIcon = Overlays.addOverlay("image3d", { + subImage: { x: 0, y: 0, width: 150, height: 150}, + url: ICON_ENTITY_WEB_MODEL_URL, + dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, + visible: false, + ignoreRayIntersection: false, + orientation: Quat.fromPitchYawRollDegrees(-90,0,0) + }); + + + entitiesIcons.push(entityIcon); + entitiesData[QUuid] = { position: entity.position, icon: entityIcon}; + entitiesByOverlayID[entityIcon] = QUuid; + } +} + +function removeEntityData(QUuid) { + if (QUuid == null) return; + + var itsOverlay = currentOverlayForEntity(QUuid); + if (itsOverlay != null) { + Overlays.deleteOverlay(itsOverlay); + delete entitiesByOverlayID[itsOverlay]; + } + var idx = entitiesIcons.indexOf(itsOverlay); + entitiesIcons.splice(idx, 1); + + delete entitiesData[QUuid]; +} + +/******************************************************************************************************** + * Entities to remark Icon/Markers rendering + ********************************************************************************************************/ + +function hideAllEntitiesIcons() { + var len = entitiesIcons.length; + for (var i = 0; i < len; i++) { + Overlays.editOverlay(entitiesIcons[i], {visible: false}); + } +} + +function renderAllEntitiesIcons() { + var entityPos; + var entityProps; + var iconDimensions = entityIconModelDimensions(); + var planeDimensions = entityIconPlaneDimensions(); // plane overlays uses xy instead of xz + for (var QUuid in entitiesData) { + if (entitiesData.hasOwnProperty(QUuid)) { + entityProps = Entities.getEntityProperties(QUuid, ["position","visible"]); + if (entityProps != null) { + entityPos = entityProps.position; + if (entitiesData[QUuid].icon != undefined && entityPos) { + var iconPos = findLineToHeightIntersectionCoords( entityPos.x, entityPos.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, entityPos.z, + Camera.position.x, Camera.position.y, Camera.position.z, + Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS); + if (!iconPos) { printd ("entity icon pos bad for " + QUuid); continue; } + var dimensions = entitiesData[QUuid].planar? planeDimensions : iconDimensions; + Overlays.editOverlay(entitiesData[QUuid].icon, { + visible: entityProps.visible, + dimensions: dimensions, + position: iconPos + }); + } + } + } + } +} + +/******************************************************************************************************** + * + ********************************************************************************************************/ + +function startRadar() { + printd("avatar added my avatar is " + MyAvatar.sessionUUID); + saveAllOthersAvatarsData(); + Camera.mode = "independent"; + + Camera.position = Vec3.sum(MyAvatar.position, {x:0, y: radarHeight, z: 0}); + Camera.orientation = Quat.fromPitchYawRollDegrees(-90,0,0); + radar = true; + + connectRadarModeEvents(); +} + +function endRadar() { + printd("-- endRadar"); + Camera.mode = "first person"; + radar = false; + + disconnectRadarModeEvents(); + hideAllEntitiesIcons(); + hideAllAvatarIcons(); +} + +function onRadarModeClicked() { + startRadar(); +} + +function onMyViewModeClicked() { + endRadar(); +} + +radarModeInterface.startRadarMode = function () { + startRadar(); +}; + +radarModeInterface.endRadarMode = function () { + endRadar(); +}; + +radarModeInterface.init = function() { + init(); +} + +radarModeInterface.setUniqueColor = function(c) { + uniqueColor = c; +}; + +module.exports = radarModeInterface; + +function updateRadar() { + // Update avatar icons + if (startedDraggingCamera) { + hideAllAvatarIcons(); + hideAllEntitiesIcons(); + startedDraggingCamera = false; + } else if (!draggingCamera) { + renderMyAvatarIcon(); + renderAllOthersAvatarIcons(); + renderAllEntitiesIcons(); + } +} + +function valueIfDefined(value) { + return value !== undefined ? value : ""; +} + +function entitiesAnalysis() { + var ids = Entities.findEntitiesInFrustum(Camera.frustum); + var entities = []; + for (var i = 0; i < ids.length; i++) { + var id = ids[i]; + var properties = Entities.getEntityProperties(id); + entities.push({ + id: id, + name: properties.name, + type: properties.type, + url: properties.type == "Model" ? properties.modelURL : "", + sourceUrl: properties.sourceUrl, + locked: properties.locked, + visible: properties.visible, + drawCalls: valueIfDefined(properties.renderInfo.drawCalls), + hasScript: properties.script !== "" + }); + } +} + +function connectRadarModeEvents() { + Script.update.connect(updateRadar); // 60Hz loop + Controller.keyPressEvent.connect(keyPressEvent); + Controller.mousePressEvent.connect(mousePress); // single click/touch + Controller.touchUpdateEvent.connect(touchUpdate); + MyAvatar.positionGoneTo.connect(positionGoneTo); +} + +function positionGoneTo() { + Camera.position = Vec3.sum(MyAvatar.position, {x:0, y: radarHeight, z: 0}); +} + +function disconnectRadarModeEvents() { + Script.update.disconnect(updateRadar); + Controller.keyPressEvent.disconnect(keyPressEvent); + Controller.mousePressEvent.disconnect(mousePress); + Controller.touchUpdateEvent.disconnect(touchUpdate); + MyAvatar.positionGoneTo.disconnect(positionGoneTo); +} + +function init() { + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + + Controller.touchBeginEvent.connect(touchBegin); + Controller.touchEndEvent.connect(touchEnd); + + AvatarList.avatarAddedEvent.connect(avatarAdded); + AvatarList.avatarRemovedEvent.connect(avatarRemoved); + + Entities.addingEntity.connect(entityAdded); + Entities.deletingEntity.connect(entityRemoved); +} + + diff --git a/scripts/system/+android/uniqueColor.js b/scripts/system/+android/uniqueColor.js new file mode 100644 index 0000000000..c296b6c87d --- /dev/null +++ b/scripts/system/+android/uniqueColor.js @@ -0,0 +1,46 @@ +"use strict"; +// +// uniqueColor.js +// scripts/system/ +// +// Created by Gabriel Calero & Cristian Duarte on 17 Oct 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 +// + +var colorsMap = {}; +var colorsCount = 0; + // 'red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'magenta' +var baseColors = [ '#EB3345', '#F0851F', '#FFCD29', '#94C338', '#11A6C5', '#294C9F', '#C01D84' ]; + +function getNextColor(n) { + var N = baseColors.length; + /*if (n < baseColors.length) { + return baseColors[n]; + } else { + var baseColor = baseColors[n % N]; + var d = (n / N) % 10; + var c2 = "" + Qt.lighter(baseColor, 1 + d / 10); + return c2; + }*/ + return baseColors[n%N]; +} + +function getColorForId(uuid) { + if (colorsMap == undefined) { + colorsMap = {}; + } + if (!colorsMap.hasOwnProperty(uuid)) { + colorsMap[uuid] = getNextColor(colorsCount); + colorsCount = colorsCount + 1; + } + return colorsMap[uuid]; +} + +module.exports = { + getColor: function(id) { + return getColorForId(id); + } +}; From bb4f57f982e41eefeb27320ae3c885462fd842a8 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Mon, 5 Feb 2018 20:51:26 -0300 Subject: [PATCH 09/61] Android - Avatar selection window accessible from the bottom bar. Only hardcoded avatars, no marketplace. --- .../resources/icons/+android/avatar-a.svg | 38 + .../resources/icons/+android/avatar-i.svg | 38 + .../resources/icons/+android/button-a.svg | 949 +++++++++++++++++ interface/resources/icons/+android/button.svg | 949 +++++++++++++++++ interface/resources/icons/+android/tick.svg | 950 ++++++++++++++++++ .../qml/controls-uit/+android/ImageButton.qml | 82 ++ .../qml/hifi/+android/AvatarOption.qml | 117 +++ .../qml/hifi/+android/HifiConstants.qml | 4 +- .../qml/hifi/+android/avatarSelection.qml | 175 ++++ interface/src/Application.cpp | 2 + interface/src/Application.h | 2 + scripts/system/+android/avatarSelection.js | 159 +++ scripts/system/+android/bottombar.js | 47 +- 13 files changed, 3509 insertions(+), 3 deletions(-) create mode 100755 interface/resources/icons/+android/avatar-a.svg create mode 100755 interface/resources/icons/+android/avatar-i.svg create mode 100644 interface/resources/icons/+android/button-a.svg create mode 100644 interface/resources/icons/+android/button.svg create mode 100644 interface/resources/icons/+android/tick.svg create mode 100644 interface/resources/qml/controls-uit/+android/ImageButton.qml create mode 100644 interface/resources/qml/hifi/+android/AvatarOption.qml create mode 100644 interface/resources/qml/hifi/+android/avatarSelection.qml create mode 100644 scripts/system/+android/avatarSelection.js diff --git a/interface/resources/icons/+android/avatar-a.svg b/interface/resources/icons/+android/avatar-a.svg new file mode 100755 index 0000000000..165b39943e --- /dev/null +++ b/interface/resources/icons/+android/avatar-a.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + diff --git a/interface/resources/icons/+android/avatar-i.svg b/interface/resources/icons/+android/avatar-i.svg new file mode 100755 index 0000000000..c1557487ea --- /dev/null +++ b/interface/resources/icons/+android/avatar-i.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + diff --git a/interface/resources/icons/+android/button-a.svg b/interface/resources/icons/+android/button-a.svg new file mode 100644 index 0000000000..d469154775 --- /dev/null +++ b/interface/resources/icons/+android/button-a.svg @@ -0,0 +1,949 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/button.svg b/interface/resources/icons/+android/button.svg new file mode 100644 index 0000000000..8c19332064 --- /dev/null +++ b/interface/resources/icons/+android/button.svg @@ -0,0 +1,949 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/tick.svg b/interface/resources/icons/+android/tick.svg new file mode 100644 index 0000000000..2c451c0994 --- /dev/null +++ b/interface/resources/icons/+android/tick.svg @@ -0,0 +1,950 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/controls-uit/+android/ImageButton.qml b/interface/resources/qml/controls-uit/+android/ImageButton.qml new file mode 100644 index 0000000000..5ebf7cd3e9 --- /dev/null +++ b/interface/resources/qml/controls-uit/+android/ImageButton.qml @@ -0,0 +1,82 @@ +// +// ImageButton.qml +// interface/resources/qml/controls-uit +// +// Created by Gabriel Calero & Cristian Duarte on 12 Oct 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 +// + +import QtQuick 2.5 +import QtQuick.Layouts 1.3 +import "../styles-uit" as HifiStyles + +Item { + id: button + + property string text: "" + property string source : "" + property string hoverSource : "" + property real fontSize: 10 + property string fontColor: "#FFFFFF" + property string hoverFontColor: "#000000" + + signal clicked(); + + Rectangle { + color: "transparent" + anchors.fill: parent + Image { + id: image + anchors.fill: parent + source: button.source + } + + HifiStyles.FiraSansRegular { + id: buttonText + anchors.centerIn: parent + text: button.text + color: button.fontColor + font.pixelSize: button.fontSize + } + + MouseArea { + anchors.fill: parent + onClicked: button.clicked(); + onEntered: { + button.state = "hover state"; + } + onExited: { + button.state = "base state"; + } + } + + + } + states: [ + State { + name: "hover state" + PropertyChanges { + target: image + source: button.hoverSource + } + PropertyChanges { + target: buttonText + color: button.hoverFontColor + } + }, + State { + name: "base state" + PropertyChanges { + target: image + source: button.source + } + PropertyChanges { + target: buttonText + color: button.fontColor + } + } + ] +} \ No newline at end of file diff --git a/interface/resources/qml/hifi/+android/AvatarOption.qml b/interface/resources/qml/hifi/+android/AvatarOption.qml new file mode 100644 index 0000000000..e7056baa36 --- /dev/null +++ b/interface/resources/qml/hifi/+android/AvatarOption.qml @@ -0,0 +1,117 @@ +// +// AvatarOption.qml +// interface/resources/qml/hifi/android +// +// Created by Cristian Duarte & Gabriel Calero on 12 Oct 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 +// + +import QtQuick.Layouts 1.3 +import QtQuick 2.5 +import "../controls-uit" as HifiControlsUit + +ColumnLayout { + id: itemRoot + + property string type: ""; + + property string thumbnailUrl: ""; + property string avatarUrl: ""; + property string avatarName: ""; + property bool avatarSelected: false; + + property string methodName: ""; + property string actionText: ""; + + spacing: 4*3 + signal sendToParentQml(var message); + + Image { + id: itemImage + Layout.preferredWidth: 250*3 + Layout.preferredHeight: 140*3 + source: thumbnailUrl + asynchronous: true + fillMode: Image.PreserveAspectFit + + MouseArea { + id: itemArea + anchors.fill: parent + hoverEnabled: true + enabled: true + onClicked: { + if (type=="avatar") { + if (!avatarSelected) sendToParentQml({ method: "selectAvatar", params: { avatarUrl: avatarUrl } }); + } else { + sendToParentQml({ method: methodName, params: { } }); + } + } + } + + } + + Text { + id: itemName + text: avatarName + color: "#FFFFFF" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.horizontalCenter: itemImage.horizontalCenter + font.pointSize: 5*3 + wrapMode: Text.WordWrap + width: parent + MouseArea { + id: itemNameArea + anchors.fill: parent + hoverEnabled: true + enabled: true + onClicked: { + if (type=="avatar") { + if (!avatarSelected) sendToParentQml({ method: "selectAvatar", params: { avatarUrl: avatarUrl } }); + } else { + sendToParentQml({ method: methodName, params: { } }); + } + } + } + } + + HifiControlsUit.ImageButton { + width: 140*3 + height: 35*3 + text: type=="extra"? actionText: "CHOOSE" + source: "../../../../icons/button.svg" + hoverSource: "../../../../icons/button-a.svg" + fontSize: 18*3 + fontColor: "#2CD8FF" + hoverFontColor: "#FFFFFF" + anchors { + horizontalCenter: itemName.horizontalCenter + } + visible: !avatarSelected + onClicked: { + if (type=="avatar") { + if (!avatarSelected) sendToParentQml({ method: "selectAvatar", params: { avatarUrl: avatarUrl } }); + } else { + sendToParentQml({ method: methodName, params: { } }); + } + } + } + + Image { + id: tickImage + width: 35*3 + height: 35*3 + source: "../../../icons/tick.svg" + anchors { + horizontalCenter: itemName.horizontalCenter + } + visible: avatarSelected + } + + Component.onCompleted:{ + sendToParentQml.connect(sendToScript); + } +} \ No newline at end of file diff --git a/interface/resources/qml/hifi/+android/HifiConstants.qml b/interface/resources/qml/hifi/+android/HifiConstants.qml index ee6d92ed38..f74cc554aa 100644 --- a/interface/resources/qml/hifi/+android/HifiConstants.qml +++ b/interface/resources/qml/hifi/+android/HifiConstants.qml @@ -20,8 +20,8 @@ Item { Item { id: dimen - readonly property real windowLessWidth: 126 - readonly property real windowLessHeight: 64 + readonly property real windowLessWidth: 126*3 + readonly property real windowLessHeight: 64*3 readonly property real windowZ: 100 diff --git a/interface/resources/qml/hifi/+android/avatarSelection.qml b/interface/resources/qml/hifi/+android/avatarSelection.qml new file mode 100644 index 0000000000..3090204308 --- /dev/null +++ b/interface/resources/qml/hifi/+android/avatarSelection.qml @@ -0,0 +1,175 @@ +// +// avatarSelection.qml +// interface/resources/qml/android +// +// Created by Gabriel Calero & Cristian Duarte on 21 Sep 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 +// +import QtQuick 2.5 +import QtQuick.Layouts 1.3 +import Hifi 1.0 + +import "../../styles" +import "." +import ".." +import ".." as QmlHifi +import "../../styles-uit" as HifiStyles + + +Item { + + id: top + + HifiConstants { id: android } + width: parent ? parent.width - android.dimen.windowLessWidth : 0 + height: parent ? parent.height - android.dimen.windowLessHeight : 0 + z: android.dimen.windowZ + anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom } + + signal sendToScript(var message); + + property bool shown: true + + onShownChanged: { + top.visible = shown; + } + + + HifiConstants { id: hifi } + HifiStyles.HifiConstants { id: hifiStyleConstants } + + property int cardWidth: 250 *3; + property int cardHeight: 240 *3; + property int gap: 14 *3; + + property var avatarsArray: []; + property var extraOptionsArray: []; + + function hide() { + shown = false; + sendToScript ({ method: "hide" }); + } + + Rectangle { + + width: parent ? parent.width : 0 + height: parent ? parent.height : 0 + + gradient: Gradient { + GradientStop { position: 0.0; color: android.color.gradientTop } + GradientStop { position: 1.0; color: android.color.gradientBottom } + } + + QmlHifi.WindowHeader { + id: header + iconSource: "../../../../icons/avatar-i.svg" + titleText: "AVATAR" + } + + ListModel { id: avatars } + + ListView { + id: scroll + height: 250*3 + property int stackedCardShadowHeight: 10*3; + spacing: gap; + clip: true; + anchors { + left: parent.left + right: parent.right + top: header.bottom + topMargin: gap + leftMargin: gap + rightMargin: gap + } + model: avatars; + orientation: ListView.Horizontal; + delegate: QmlHifi.AvatarOption { + type: model.type; + thumbnailUrl: model.thumbnailUrl; + avatarUrl: model.avatarUrl; + avatarName: model.avatarName; + avatarSelected: model.avatarSelected; + methodName: model.methodName; + actionText: model.actionText; + } + highlightMoveDuration: -1; + highlightMoveVelocity: -1; + } + + } + + function escapeRegExp(str) { + return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); + } + function replaceAll(str, find, replace) { + return str.replace(new RegExp(escapeRegExp(find), 'g'), replace); + } + + function refreshSelected(selectedAvatarUrl) { + // URL as ID? + avatarsArray.forEach(function (avatarData) { + avatarData.avatarSelected = (selectedAvatarUrl == avatarData.avatarUrl); + console.log('[avatarSelection] avatar : ', avatarData.avatarName, ' is selected? ' , avatarData.avatarSelected); + }); + } + + function addAvatar(name, thumbnailUrl, avatarUrl) { + avatarsArray.push({ + type: "avatar", + thumbnailUrl: thumbnailUrl, + avatarUrl: avatarUrl, + avatarName: name, + avatarSelected: false, + methodName: "", + actionText: "" + }); + } + + function showAvatars() { + avatars.clear(); + avatarsArray.forEach(function (avatarData) { + avatars.append(avatarData); + console.log('[avatarSelection] adding avatar to model: ', JSON.stringify(avatarData)); + }); + extraOptionsArray.forEach(function (extraData) { + avatars.append(extraData); + console.log('[avatarSelection] adding extra option to model: ', JSON.stringify(extraData)); + }); + } + + function addExtraOption(showName, thumbnailUrl, methodNameWhenClicked, actionText) { + extraOptionsArray.push({ + type: "extra", + thumbnailUrl: thumbnailUrl, + avatarUrl: "", + avatarName: showName, + avatarSelected: false, + methodName: methodNameWhenClicked, + actionText: actionText + }); + } + + function fromScript(message) { + //console.log("[CHAT] fromScript " + JSON.stringify(message)); + switch (message.type) { + case "addAvatar": + addAvatar(message.name, message.thumbnailUrl, message.avatarUrl); + break; + case "addExtraOption": + //(showName, thumbnailUrl, methodNameWhenClicked, actionText) + addExtraOption(message.showName, message.thumbnailUrl, message.methodNameWhenClicked, message.actionText); + break; + case "refreshSelected": + refreshSelected(message.selectedAvatarUrl); + break; + case "showAvatars": + showAvatars(); + break; + default: + } + } +} \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6fec6f1d72..cbcd08c667 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5939,6 +5939,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Wallet", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("App", this); + qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); DependencyManager::get()->registerMetaTypes(scriptEngine.data()); diff --git a/interface/src/Application.h b/interface/src/Application.h index 8f0690bda1..5161c62a65 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -389,6 +389,8 @@ public slots: const QString getPreferredCursor() const { return _preferredCursor.get(); } void setPreferredCursor(const QString& cursor); + Q_INVOKABLE bool askBeforeSetAvatarUrl(const QString& avatarUrl) { return askToSetAvatarUrl(avatarUrl); } + private slots: void showDesktop(); void clearDomainOctreeDetails(); diff --git a/scripts/system/+android/avatarSelection.js b/scripts/system/+android/avatarSelection.js new file mode 100644 index 0000000000..fd938236fb --- /dev/null +++ b/scripts/system/+android/avatarSelection.js @@ -0,0 +1,159 @@ +"use strict"; +// +// avatarSelection.js +// scripts/system/ +// +// Created by Gabriel Calero & Cristian Duarte on 21 Sep 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 +// + +var window; + +var logEnabled = true; +var isVisible = false; + +function printd(str) { + if (logEnabled) + print("[avatarSelection.js] " + str); +} + +function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. + var data; + printd("fromQml " + JSON.stringify(message)); + switch (message.method) { + case 'selectAvatar': + // use this message.params.avatarUrl + printd("Selected Avatar: [" + message.params.avatarUrl + "]"); + App.askBeforeSetAvatarUrl(message.params.avatarUrl); + break; + case 'openAvatarMarket': + // good + App.openUrl("https://metaverse.highfidelity.com/marketplace?category=avatars"); + break; + case 'hide': + module.exports.onHidden(); + break; + default: + print('[avatarSelection.js] Unrecognized message from avatarSelection.qml:', JSON.stringify(message)); + } +} + +function sendToQml(message) { + if (!window) { + print("[avatarSelection.js] There is no window object"); + return; + } + window.sendToQml(message); +} + +function refreshSelected(currentAvatarURL) { + sendToQml({ + type: "refreshSelected", + selectedAvatarUrl: currentAvatarURL + }); + + sendToQml({ + type: "showAvatars" + }); +} + +function init() { + if (!window) { + print("[avatarSelection.js] There is no window object for init()"); + return; + } + var DEFAULT_AVATAR_URL = "http://mpassets.highfidelity.com/f14bf7c9-49a1-4249-988a-0a577ed78957-v1/beingOfLight.fst"; + sendToQml({ + type: "addAvatar", + name: "Being of Light Avatar", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/f14bf7c9-49a1-4249-988a-0a577ed78957/thumbnail/hifi-mp-f14bf7c9-49a1-4249-988a-0a577ed78957.jpg", + avatarUrl: DEFAULT_AVATAR_URL + }); + sendToQml({ + type: "addAvatar", + name: "Cody", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53/thumbnail/hifi-mp-8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53.jpg", + avatarUrl: "http://mpassets.highfidelity.com/8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53-v1/cody.fst" + }); + sendToQml({ + type: "addAvatar", + name: "Mixamo Will", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73/thumbnail/hifi-mp-d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73.jpg", + avatarUrl: "http://mpassets.highfidelity.com/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73-v1/4618d52e711fbb34df442b414da767bb.fst" + }); + sendToQml({ + type: "addAvatar", + name: "Albert", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/1e57c395-612e-4acd-9561-e79dbda0bc49/thumbnail/hifi-mp-1e57c395-612e-4acd-9561-e79dbda0bc49.jpg", + avatarUrl: "http://mpassets.highfidelity.com/1e57c395-612e-4acd-9561-e79dbda0bc49-v1/albert.fst" + }); + /* We need to implement the wallet, so let's skip this for the moment + sendToQml({ + type: "addExtraOption", + showName: "More choices", + thumbnailUrl: "../../../images/moreAvatars.png", + methodNameWhenClicked: "openAvatarMarket", + actionText: "MARKETPLACE" + }); + */ + var currentAvatarURL = Settings.getValue('Avatar/fullAvatarURL', DEFAULT_AVATAR_URL); + printd("Default Avatar: [" + DEFAULT_AVATAR_URL + "]"); + printd("Current Avatar: [" + currentAvatarURL + "]"); + if (!currentAvatarURL || 0 === currentAvatarURL.length) { + currentAvatarURL = DEFAULT_AVATAR_URL; + } + refreshSelected(currentAvatarURL); +} + +module.exports = { + init: function() { + window = new QmlFragment({ + qml: "hifi/avatarSelection.qml", + visible: false + }); + /*, + visible: false*/ + if (window) { + window.fromQml.connect(fromQml); + } + init(); + }, + show: function() { + if (window) { + window.setVisible(true); + isVisible = true; + } + }, + hide: function() { + if (window) { + window.setVisible(false); + } + isVisible = false; + }, + destroy: function() { + if (window) { + window.fromQml.disconnect(fromQml); + window.close(); + window = null; + } + }, + isVisible: function() { + return isVisible; + }, + width: function() { + return window ? window.size.x : 0; + }, + height: function() { + return window ? window.size.y : 0; + }, + position: function() { + return window && isVisible ? window.position : null; + }, + refreshSelectedAvatar: function(currentAvatarURL) { + refreshSelected(currentAvatarURL); + }, + onHidden: function() { } +}; diff --git a/scripts/system/+android/bottombar.js b/scripts/system/+android/bottombar.js index e58840ad6f..db05b88b04 100644 --- a/scripts/system/+android/bottombar.js +++ b/scripts/system/+android/bottombar.js @@ -14,8 +14,10 @@ var bottombar; var bottomHudOptionsBar; var gotoBtn; +var avatarBtn; var gotoScript = Script.require('./goto.js'); +var avatarSelection = Script.require('./avatarSelection.js'); var logEnabled = false; @@ -34,6 +36,8 @@ function init() { hideAddressBar(); } }); + avatarSelection.init(); + App.fullAvatarURLChanged.connect(processedNewAvatar); setupBottomBar(); setupBottomHudOptionsBar(); @@ -43,6 +47,7 @@ function init() { } function shutdown() { + App.fullAvatarURLChanged.disconnect(processedNewAvatar); } function setupBottomBar() { @@ -60,6 +65,32 @@ function setupBottomBar() { } }); + avatarBtn = bottombar.addButton({ + icon: "icons/avatar-i.svg", + activeIcon: "icons/avatar-a.svg", + bgOpacity: 0, + height: 240, + width: 294, + hoverBgOpacity: 0, + activeBgOpacity: 0, + activeHoverBgOpacity: 0, + iconSize: 108, + textSize: 45, + text: "AVATAR" + }); + avatarBtn.clicked.connect(function() { + printd("Avatar button clicked"); + if (!avatarSelection.isVisible()) { + showAvatarSelection(); + } else { + hideAvatarSelection(); + } + }); + avatarSelection.onHidden = function() { + if (avatarBtn) { + avatarBtn.isActive = false; + } + }; gotoBtn = bottombar.addButton({ icon: "icons/goto-i.svg", @@ -69,7 +100,7 @@ function setupBottomBar() { activeBgOpacity: 0, activeHoverBgOpacity: 0, height: 240, - width: 300, + width: 294, iconSize: 108, textSize: 45, text: "GO TO" @@ -148,7 +179,21 @@ function hideAddressBar() { gotoBtn.isActive = false; } +function showAvatarSelection() { + avatarSelection.show(); + avatarBtn.isActive = true; +} +function hideAvatarSelection() { + avatarSelection.hide(); + avatarBtn.isActive = false; +} + +// TODO: Move to avatarSelection.js and make it possible to hide the window from there AND switch the button state here too +function processedNewAvatar(url, modelName) { + avatarSelection.refreshSelectedAvatar(url); + hideAvatarSelection(); +} Script.scriptEnding.connect(function () { shutdown(); From fe5075bff2695559cc7a4269ed50685824012cc9 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Tue, 6 Feb 2018 18:25:06 -0300 Subject: [PATCH 10/61] Android - Use the Wooden Mannequin avatar instead of being of light in the Avatar window --- scripts/system/+android/avatarSelection.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/system/+android/avatarSelection.js b/scripts/system/+android/avatarSelection.js index fd938236fb..be58f61ac2 100644 --- a/scripts/system/+android/avatarSelection.js +++ b/scripts/system/+android/avatarSelection.js @@ -65,11 +65,11 @@ function init() { print("[avatarSelection.js] There is no window object for init()"); return; } - var DEFAULT_AVATAR_URL = "http://mpassets.highfidelity.com/f14bf7c9-49a1-4249-988a-0a577ed78957-v1/beingOfLight.fst"; + var DEFAULT_AVATAR_URL = "http://mpassets.highfidelity.com/7fe80a1e-f445-4800-9e89-40e677b03bee-v3/mannequin.fst"; sendToQml({ type: "addAvatar", - name: "Being of Light Avatar", - thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/f14bf7c9-49a1-4249-988a-0a577ed78957/thumbnail/hifi-mp-f14bf7c9-49a1-4249-988a-0a577ed78957.jpg", + name: "Wooden Mannequin", + thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/7fe80a1e-f445-4800-9e89-40e677b03bee/thumbnail/hifi-mp-7fe80a1e-f445-4800-9e89-40e677b03bee.jpg", avatarUrl: DEFAULT_AVATAR_URL }); sendToQml({ From 8d6d078ea2c46e20f34ccb0de5962e91e8d10ade Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Tue, 6 Feb 2018 22:52:29 -0300 Subject: [PATCH 11/61] Android - Make radar turn of the virtual pad --- scripts/system/+android/radar.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 9fa07178f6..baf4441749 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -1100,6 +1100,8 @@ function startRadar() { Camera.orientation = Quat.fromPitchYawRollDegrees(-90,0,0); radar = true; + Controller.setVPadEnabled(false); // this was done before in CompositeExtra in the DisplayPlugin (Checking for camera not independent, not radar mode) + connectRadarModeEvents(); } @@ -1108,6 +1110,8 @@ function endRadar() { Camera.mode = "first person"; radar = false; + Controller.setVPadEnabled(true); + disconnectRadarModeEvents(); hideAllEntitiesIcons(); hideAllAvatarIcons(); From 8c1a1eba02aa635e6085d2e5289cbef89de9fdae Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Wed, 7 Feb 2018 16:26:46 -0300 Subject: [PATCH 12/61] Android - Fix modes bar layout when expanded --- interface/resources/qml/hifi/+android/modesbar.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/+android/modesbar.qml b/interface/resources/qml/hifi/+android/modesbar.qml index 8ce455c2c1..fe71314ece 100644 --- a/interface/resources/qml/hifi/+android/modesbar.qml +++ b/interface/resources/qml/hifi/+android/modesbar.qml @@ -25,8 +25,8 @@ Item { } Component.onCompleted: { - width = 330; - height = 330; + width = 300 + 30; // That 30 is extra regardless the qty of items shown + height = 300 + 30; x=Window.innerWidth - width; } @@ -60,10 +60,10 @@ Item { function fromScript(message) { switch (message.type) { case "allButtonsShown": - modesbar.height = flowMain.children.length * 100 + 10; + modesbar.height = flowMain.children.length * 300 + 30; // That 30 is extra regardless the qty of items shown break; case "inactiveButtonsHidden": - modesbar.height = 100 + 10; + modesbar.height = 300 + 30; break; default: break; From 017f99837a7de2a728b72965489a9ae4495eee11 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Fri, 9 Feb 2018 17:27:55 -0300 Subject: [PATCH 13/61] Android - Sign in, Sign up and Sign out. Note: It's still desktop scaled, being some components small for a phone --- .../resources/icons/+android/login-a.svg | 990 ++++++++++++++++++ .../resources/icons/+android/login-i.svg | 990 ++++++++++++++++++ .../resources/qml/+android/LoginDialog.qml | 95 ++ .../LoginDialog/+android/LinkAccountBody.qml | 330 ++++++ .../qml/LoginDialog/+android/SignUpBody.qml | 297 ++++++ scripts/system/+android/bottombar.js | 39 + 6 files changed, 2741 insertions(+) create mode 100755 interface/resources/icons/+android/login-a.svg create mode 100755 interface/resources/icons/+android/login-i.svg create mode 100644 interface/resources/qml/+android/LoginDialog.qml create mode 100644 interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml create mode 100644 interface/resources/qml/LoginDialog/+android/SignUpBody.qml diff --git a/interface/resources/icons/+android/login-a.svg b/interface/resources/icons/+android/login-a.svg new file mode 100755 index 0000000000..8a7f097ed7 --- /dev/null +++ b/interface/resources/icons/+android/login-a.svg @@ -0,0 +1,990 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/login-i.svg b/interface/resources/icons/+android/login-i.svg new file mode 100755 index 0000000000..6f011e1d13 --- /dev/null +++ b/interface/resources/icons/+android/login-i.svg @@ -0,0 +1,990 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/+android/LoginDialog.qml b/interface/resources/qml/+android/LoginDialog.qml new file mode 100644 index 0000000000..4badd555fb --- /dev/null +++ b/interface/resources/qml/+android/LoginDialog.qml @@ -0,0 +1,95 @@ +// +// LoginDialog.qml +// +// Created by David Rowe on 3 Jun 2015 +// Copyright 2015 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 +// + +import Hifi 1.0 +import QtQuick 2.4 + +import "controls-uit" +import "styles-uit" +import "windows" + +import "LoginDialog" + +ModalWindow { + id: root + HifiConstants { id: hifi } + + property int scale: 3 + + objectName: "LoginDialog" + implicitWidth: 520 *scale + implicitHeight: 150 *scale + y:0 + destroyOnCloseButton: true + destroyOnHidden: true + visible: true + + property string iconText: "" + property int iconSize: 35 *scale + + property string title: "" + property int titleWidth: 0 + + keyboardOverride: true // Disable ModalWindow's keyboard. + + function tryDestroy() { + root.destroy() + } + + LoginDialog { + id: loginDialog + + Loader { + id: bodyLoader + source: loginDialog.isSteamRunning() ? "LoginDialog/+android/SignInBody.qml" : "LoginDialog/+android/LinkAccountBody.qml" + } + } + + Component.onCompleted: { + this.anchors.centerIn = undefined; + this.y=50 *scale; + this.x=150 *scale; + } + + Keys.onPressed: { + if (!visible) { + return + } + + if (event.modifiers === Qt.ControlModifier) + switch (event.key) { + case Qt.Key_A: + event.accepted = true + detailedText.selectAll() + break + case Qt.Key_C: + event.accepted = true + detailedText.copy() + break + case Qt.Key_Period: + if (Qt.platform.os === "osx") { + event.accepted = true + content.reject() + } + break + } else switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + event.accepted = true + destroy() + break + + case Qt.Key_Enter: + case Qt.Key_Return: + event.accepted = true + break + } + } +} diff --git a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml new file mode 100644 index 0000000000..3d8bcedb38 --- /dev/null +++ b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml @@ -0,0 +1,330 @@ +// +// LinkAccountBody.qml +// +// Created by Clement on 7/18/16 +// Copyright 2015 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 +// + +import Hifi 1.0 +import QtQuick 2.4 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 as OriginalStyles + +import "../../controls-uit" +import "../../styles-uit" + +Item { + id: linkAccountBody + + property int scale: 3 + + clip: true + height: 100 *scale + width: root.pane.width + property bool failAfterSignUp: false + function login() { + mainTextContainer.visible = false + toggleLoading(true) + loginDialog.login(usernameField.text, passwordField.text) + } + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + onKeyboardRaisedChanged: d.resize(); + + QtObject { + id: d + readonly property int minWidth: 480 *scale + readonly property int maxWidth: 1280 *scale + readonly property int minHeight: 50 *scale + readonly property int maxHeight: 220 *scale + + function resize() { + var targetWidth = Math.max(titleWidth, form.contentWidth); + var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height + + 4 * hifi.dimensions.contentSpacing.y + form.height + + hifi.dimensions.contentSpacing.y + buttons.height; + + if (additionalInformation.visible) { + targetWidth = Math.max(targetWidth, additionalInformation.width); + targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height + } + + parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth)); + parent.height = 140 *scale; + /*root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)) + + (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);*/ + } + } + + function toggleLoading(isLoading) { + linkAccountSpinner.visible = isLoading + form.visible = !isLoading + + if (loginDialog.isSteamRunning()) { + additionalInformation.visible = !isLoading + } + + leftButton.visible = !isLoading + buttons.visible = !isLoading + } + + BusyIndicator { + id: linkAccountSpinner + + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + topMargin: hifi.dimensions.contentSpacing.y + } + + visible: false + running: true + + width: 48 *scale + height: 48 *scale + } + + ShortcutText { + id: mainTextContainer + anchors { + top: parent.top + left: parent.left + margins: 0 + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + + visible: false + + text: qsTr("Username or password incorrect.") + wrapMode: Text.WordWrap + color: hifi.colors.redAccent + lineHeight: 1 *scale + lineHeightMode: Text.ProportionalHeight + horizontalAlignment: Text.AlignHCenter + } + + Column { + id: form + anchors { + top: mainTextContainer.bottom + left: parent.left + margins: 0 + topMargin: 0 // hifi.dimensions.contentSpacing.y + } + spacing: hifi.dimensions.contentSpacing.y / 2 + + Row { + spacing: hifi.dimensions.contentSpacing.x + + TextField { + id: usernameField + anchors { + verticalCenter: parent.verticalCenter + } + width: 350 *scale + + placeholderText: qsTr("Username or Email") + } + + ShortcutText { + anchors { + verticalCenter: parent.verticalCenter + } + + text: "Forgot Username?" + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + linkColor: hifi.colors.blueAccent + + onLinkActivated: loginDialog.openUrl(link) + } + } + Row { + spacing: hifi.dimensions.contentSpacing.x + + TextField { + id: passwordField + anchors { + verticalCenter: parent.verticalCenter + } + width: 350 *scale + + placeholderText: qsTr("Password") + echoMode: TextInput.Password + } + + ShortcutText { + anchors { + verticalCenter: parent.verticalCenter + } + + text: "Forgot Password?" + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + linkColor: hifi.colors.blueAccent + + onLinkActivated: loginDialog.openUrl(link) + } + } + + } + + InfoItem { + id: additionalInformation + anchors { + top: form.bottom + left: parent.left + margins: 0 + topMargin: hifi.dimensions.contentSpacing.y + } + + visible: loginDialog.isSteamRunning() + + text: qsTr("Your steam account informations will not be exposed to other users.") + wrapMode: Text.WordWrap + color: hifi.colors.baseGrayHighlight + lineHeight: 1 *scale + lineHeightMode: Text.ProportionalHeight + horizontalAlignment: Text.AlignHCenter + } + + // 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: buttons.top + bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0 + } + } + + Row { + id: leftButton + anchors { + left: parent.left + top: form.bottom + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + + Button { + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Sign Up") + visible: !loginDialog.isSteamRunning() + + onClicked: { + bodyLoader.setSource("SignUpBody.qml") + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + } + } + + Row { + id: buttons + anchors { + right: parent.right + top: form.bottom + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + + Button { + id: linkAccountButton + anchors.verticalCenter: parent.verticalCenter + width: 200 *scale + + text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login") + color: hifi.buttons.blue + + onClicked: { + Qt.inputMethod.hide(); + linkAccountBody.login(); + } + } + + Button { + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Cancel Pepe") + + onClicked: { + Qt.inputMethod.hide(); + root.destroy(); + } + } + } + + Component.onCompleted: { + root.title = qsTr("Sign Into High Fidelity") + root.iconText = "<" + keyboardEnabled = HMD.active; + d.resize(); + + if (failAfterSignUp) { + mainTextContainer.text = "Account created successfully." + mainTextContainer.visible = true + } + + //usernameField.forceActiveFocus(); + } + + Connections { + target: loginDialog + onHandleLoginCompleted: { + console.log("Login Succeeded, linking steam account") + + if (loginDialog.isSteamRunning()) { + loginDialog.linkSteam() + } else { + bodyLoader.setSource("../WelcomeBody.qml", { "welcomeBack" : true }) + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + } + onHandleLoginFailed: { + console.log("Login Failed") + mainTextContainer.visible = true + toggleLoading(false) + } + onHandleLinkCompleted: { + console.log("Link Succeeded") + + bodyLoader.setSource("../WelcomeBody.qml", { "welcomeBack" : true }) + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + onHandleLinkFailed: { + console.log("Link Failed") + toggleLoading(false) + } + } + + Keys.onPressed: { + if (!visible) { + return + } + + switch (event.key) { + case Qt.Key_Enter: + case Qt.Key_Return: + event.accepted = true + linkAccountBody.login() + break + } + } +} diff --git a/interface/resources/qml/LoginDialog/+android/SignUpBody.qml b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml new file mode 100644 index 0000000000..b9f36c7ad7 --- /dev/null +++ b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml @@ -0,0 +1,297 @@ +// +// SignUpBody.qml +// +// Created by Stephen Birarda on 7 Dec 2016 +// Copyright 2016 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 +// + +import Hifi 1.0 +import QtQuick 2.4 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 as OriginalStyles + +import "../../controls-uit" +import "../../styles-uit" + +Item { + id: signupBody + clip: true + height: root.pane.height + width: root.pane.width + + function signup() { + mainTextContainer.visible = false + toggleLoading(true) + loginDialog.signup(emailField.text, usernameField.text, passwordField.text) + } + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + onKeyboardRaisedChanged: d.resize(); + + QtObject { + id: d + readonly property int minWidth: 480 + readonly property int maxWidth: 1280 + readonly property int minHeight: 100 + readonly property int maxHeight: 200 + + function resize() { + var targetWidth = Math.max(titleWidth, form.contentWidth); + var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height + + 4 * hifi.dimensions.contentSpacing.y + form.height + + hifi.dimensions.contentSpacing.y + buttons.height; + + parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth)); + //parent.height = 650; + parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)); + + } + } + + function toggleLoading(isLoading) { + linkAccountSpinner.visible = isLoading + form.visible = !isLoading + + leftButton.visible = !isLoading + buttons.visible = !isLoading + } + + BusyIndicator { + id: linkAccountSpinner + + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + topMargin: hifi.dimensions.contentSpacing.y + } + + visible: false + running: true + + width: 48 + height: 48 + } + + ShortcutText { + id: mainTextContainer + anchors { + top: parent.top + left: parent.left + margins: 0 + topMargin: hifi.dimensions.contentSpacing.y + } + + visible: false + + text: qsTr("There was an unknown error while creating your account.") + wrapMode: Text.WordWrap + color: hifi.colors.redAccent + horizontalAlignment: Text.AlignLeft + } + + Column { + id: form + anchors { + top: mainTextContainer.bottom + left: parent.left + margins: 0 + topMargin: 0; // 2 * hifi.dimensions.contentSpacing.y + } + spacing: hifi.dimensions.contentSpacing.y / 2 + + Row { + spacing: hifi.dimensions.contentSpacing.x + + TextField { + id: emailField + anchors { + verticalCenter: parent.verticalCenter + } + width: 350 + + placeholderText: "Email" + } + } + + Row { + spacing: hifi.dimensions.contentSpacing.x + + TextField { + id: usernameField + anchors { + verticalCenter: parent.verticalCenter + } + width: 350 + + placeholderText: "Username" + } + + ShortcutText { + anchors { + verticalCenter: parent.verticalCenter + } + + text: qsTr("No spaces / special chars.") + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + color: hifi.colors.blueAccent + } + } + + Row { + spacing: hifi.dimensions.contentSpacing.x + + TextField { + id: passwordField + anchors { + verticalCenter: parent.verticalCenter + } + width: 350 + + placeholderText: "Password" + echoMode: TextInput.Password + } + + ShortcutText { + anchors { + verticalCenter: parent.verticalCenter + } + + text: qsTr("At least 6 characters") + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + color: hifi.colors.blueAccent + } + } + + } + + // 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: buttons.top + bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0 + } + } + + Row { + id: leftButton + anchors { + left: parent.left + top: form.bottom + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + + Button { + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Existing User") + + onClicked: { + bodyLoader.setSource("LinkAccountBody-android.qml") + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + } + } + + Row { + id: buttons + anchors { + right: parent.right + top: form.bottom + topMargin: hifi.dimensions.contentSpacing.y / 2 + } + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + + Button { + id: linkAccountButton + anchors.verticalCenter: parent.verticalCenter + width: 200 + + text: qsTr("Sign Up") + color: hifi.buttons.blue + + onClicked: signupBody.signup() + } + + Button { + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Cancel") + + onClicked: root.destroy() + } + } + + Component.onCompleted: { + root.title = qsTr("Create an Account") + root.iconText = "<" + keyboardEnabled = HMD.active; + d.resize(); + + emailField.forceActiveFocus(); + } + + Connections { + target: loginDialog + onHandleSignupCompleted: { + console.log("Sign Up Succeeded"); + + // now that we have an account, login with that username and password + loginDialog.login(usernameField.text, passwordField.text) + } + onHandleSignupFailed: { + console.log("Sign Up Failed") + toggleLoading(false) + + mainTextContainer.text = errorString + mainTextContainer.visible = true + + d.resize(); + } + onHandleLoginCompleted: { + bodyLoader.setSource("../WelcomeBody.qml", { "welcomeBack": false }) + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + onHandleLoginFailed: { + // we failed to login, show the LoginDialog so the user will try again + bodyLoader.setSource("LinkAccountBody.qml", { "failAfterSignUp": true }) + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } + } + + Keys.onPressed: { + if (!visible) { + return + } + + switch (event.key) { + case Qt.Key_Enter: + case Qt.Key_Return: + event.accepted = true + signupBody.signup() + break + } + } +} diff --git a/scripts/system/+android/bottombar.js b/scripts/system/+android/bottombar.js index db05b88b04..72ba1c1e50 100644 --- a/scripts/system/+android/bottombar.js +++ b/scripts/system/+android/bottombar.js @@ -15,6 +15,7 @@ var bottombar; var bottomHudOptionsBar; var gotoBtn; var avatarBtn; +var loginBtn; var gotoScript = Script.require('./goto.js'); var avatarSelection = Script.require('./avatarSelection.js'); @@ -44,6 +45,8 @@ function init() { raiseBottomBar(); + GlobalServices.connected.connect(handleLogin); + GlobalServices.disconnected.connect(handleLogout); } function shutdown() { @@ -114,6 +117,23 @@ function setupBottomBar() { } }); + loginBtn = bottombar.addButton({ + icon: "icons/login-i.svg", + activeIcon: "icons/login-a.svg", + height: 240, + width: 294, + iconSize: 108, + textSize: 45, + text: Account.isLoggedIn() ? "LOG OUT" : "LOG IN" + }); + loginBtn.clicked.connect(function() { + if (!Account.isLoggedIn()) { + Account.checkAndSignalForAccessToken(); + } else { + Menu.triggerOption("Login / Sign Up"); + } + }); + // TODO: setup all the buttons or provide a dynamic interface raiseBottomBar(); @@ -195,8 +215,27 @@ function processedNewAvatar(url, modelName) { hideAvatarSelection(); } +function handleLogin() { + Script.setTimeout(function() { + if (Account.isLoggedIn()) { + MyAvatar.displayName=Account.getUsername(); + } + }, 2000); + if (loginBtn) { + loginBtn.editProperties({text: "LOG OUT"}); + } +} +function handleLogout() { + MyAvatar.displayName=""; + if (loginBtn) { + loginBtn.editProperties({text: "LOG IN"}); + } +} + Script.scriptEnding.connect(function () { shutdown(); + GlobalServices.connected.disconnect(handleLogin); + GlobalServices.disconnected.disconnect(handleLogout); }); init(); From 674af54a821b4b620ca48b18fad7934c7cab20cf Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Wed, 14 Feb 2018 16:57:24 -0300 Subject: [PATCH 14/61] Android - Scale up Sign In and Sign Up windows. --- .../resources/qml/+android/LoginDialog.qml | 12 +- .../LoginDialog/+android/LinkAccountBody.qml | 45 +-- .../qml/LoginDialog/+android/SignUpBody.qml | 20 +- .../resources/qml/controls-uit/Button.qml | 2 +- .../qml/styles-uit/+android/HifiConstants.qml | 358 ++++++++++++++++++ .../qml/styles-uit/HifiConstants.qml | 1 + 6 files changed, 396 insertions(+), 42 deletions(-) create mode 100644 interface/resources/qml/styles-uit/+android/HifiConstants.qml diff --git a/interface/resources/qml/+android/LoginDialog.qml b/interface/resources/qml/+android/LoginDialog.qml index 4badd555fb..c60864cd1d 100644 --- a/interface/resources/qml/+android/LoginDialog.qml +++ b/interface/resources/qml/+android/LoginDialog.qml @@ -21,18 +21,16 @@ ModalWindow { id: root HifiConstants { id: hifi } - property int scale: 3 - objectName: "LoginDialog" - implicitWidth: 520 *scale - implicitHeight: 150 *scale + implicitWidth: 1560 + implicitHeight: 450 y:0 destroyOnCloseButton: true destroyOnHidden: true visible: true property string iconText: "" - property int iconSize: 35 *scale + property int iconSize: 105 property string title: "" property int titleWidth: 0 @@ -54,8 +52,8 @@ ModalWindow { Component.onCompleted: { this.anchors.centerIn = undefined; - this.y=50 *scale; - this.x=150 *scale; + this.y=150; + this.x=450; } Keys.onPressed: { diff --git a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml index 3d8bcedb38..8f76c6ed99 100644 --- a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml @@ -19,10 +19,8 @@ import "../../styles-uit" Item { id: linkAccountBody - property int scale: 3 - clip: true - height: 100 *scale + height: 300 width: root.pane.width property bool failAfterSignUp: false function login() { @@ -39,10 +37,10 @@ Item { QtObject { id: d - readonly property int minWidth: 480 *scale - readonly property int maxWidth: 1280 *scale - readonly property int minHeight: 50 *scale - readonly property int maxHeight: 220 *scale + readonly property int minWidth: 1440 + readonly property int maxWidth: 3840 + readonly property int minHeight: 150 + readonly property int maxHeight: 660 function resize() { var targetWidth = Math.max(titleWidth, form.contentWidth); @@ -56,7 +54,7 @@ Item { } parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth)); - parent.height = 140 *scale; + parent.height = 420; /*root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)) + (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);*/ } @@ -86,8 +84,8 @@ Item { visible: false running: true - width: 48 *scale - height: 48 *scale + width: 144 + height: 144 } ShortcutText { @@ -104,7 +102,7 @@ Item { text: qsTr("Username or password incorrect.") wrapMode: Text.WordWrap color: hifi.colors.redAccent - lineHeight: 1 *scale + lineHeight: 1 lineHeightMode: Text.ProportionalHeight horizontalAlignment: Text.AlignHCenter } @@ -127,7 +125,7 @@ Item { anchors { verticalCenter: parent.verticalCenter } - width: 350 *scale + width: 780 placeholderText: qsTr("Username or Email") } @@ -154,7 +152,7 @@ Item { anchors { verticalCenter: parent.verticalCenter } - width: 350 *scale + width: 780 placeholderText: qsTr("Password") echoMode: TextInput.Password @@ -191,7 +189,7 @@ Item { text: qsTr("Your steam account informations will not be exposed to other users.") wrapMode: Text.WordWrap color: hifi.colors.baseGrayHighlight - lineHeight: 1 *scale + lineHeight: 3 lineHeightMode: Text.ProportionalHeight horizontalAlignment: Text.AlignHCenter } @@ -220,16 +218,16 @@ Item { onHeightChanged: d.resize(); onWidthChanged: d.resize(); Button { - anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenter: parent.verticalCenter - text: qsTr("Sign Up") - visible: !loginDialog.isSteamRunning() + text: qsTr("Sign Up") + visible: !loginDialog.isSteamRunning() - onClicked: { - bodyLoader.setSource("SignUpBody.qml") - bodyLoader.item.width = root.pane.width - bodyLoader.item.height = root.pane.height - } + onClicked: { + bodyLoader.setSource("SignUpBody.qml") + bodyLoader.item.width = root.pane.width + bodyLoader.item.height = root.pane.height + } } } @@ -246,7 +244,6 @@ Item { Button { id: linkAccountButton anchors.verticalCenter: parent.verticalCenter - width: 200 *scale text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login") color: hifi.buttons.blue @@ -260,7 +257,7 @@ Item { Button { anchors.verticalCenter: parent.verticalCenter - text: qsTr("Cancel Pepe") + text: qsTr("Cancel") onClicked: { Qt.inputMethod.hide(); diff --git a/interface/resources/qml/LoginDialog/+android/SignUpBody.qml b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml index b9f36c7ad7..3a44a8d741 100644 --- a/interface/resources/qml/LoginDialog/+android/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml @@ -18,6 +18,7 @@ import "../../styles-uit" Item { id: signupBody + clip: true height: root.pane.height width: root.pane.width @@ -36,10 +37,10 @@ Item { QtObject { id: d - readonly property int minWidth: 480 - readonly property int maxWidth: 1280 - readonly property int minHeight: 100 - readonly property int maxHeight: 200 + readonly property int minWidth: 960 + readonly property int maxWidth: 2560 + readonly property int minHeight: 240 + readonly property int maxHeight: 1480 function resize() { var targetWidth = Math.max(titleWidth, form.contentWidth); @@ -113,7 +114,7 @@ Item { anchors { verticalCenter: parent.verticalCenter } - width: 350 + width: 780 placeholderText: "Email" } @@ -127,7 +128,7 @@ Item { anchors { verticalCenter: parent.verticalCenter } - width: 350 + width: 780 placeholderText: "Username" } @@ -154,7 +155,7 @@ Item { anchors { verticalCenter: parent.verticalCenter } - width: 350 + width: 780 placeholderText: "Password" echoMode: TextInput.Password @@ -193,7 +194,7 @@ Item { anchors { left: parent.left top: form.bottom - topMargin: hifi.dimensions.contentSpacing.y / 2 + topMargin: hifi.dimensions.contentSpacing.y// / 2 } spacing: hifi.dimensions.contentSpacing.x @@ -205,7 +206,7 @@ Item { text: qsTr("Existing User") onClicked: { - bodyLoader.setSource("LinkAccountBody-android.qml") + bodyLoader.setSource("LinkAccountBody.qml") bodyLoader.item.width = root.pane.width bodyLoader.item.height = root.pane.height } @@ -225,7 +226,6 @@ Item { Button { id: linkAccountButton anchors.verticalCenter: parent.verticalCenter - width: 200 text: qsTr("Sign Up") color: hifi.buttons.blue diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index 02c6181952..ba604a0404 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -22,7 +22,7 @@ Original.Button { property int colorScheme: hifi.colorSchemes.light property string buttonGlyph: ""; - width: 120 + width: hifi.dimensions.buttonWidth height: hifi.dimensions.controlLineHeight HifiConstants { id: hifi } diff --git a/interface/resources/qml/styles-uit/+android/HifiConstants.qml b/interface/resources/qml/styles-uit/+android/HifiConstants.qml new file mode 100644 index 0000000000..d5fab57501 --- /dev/null +++ b/interface/resources/qml/styles-uit/+android/HifiConstants.qml @@ -0,0 +1,358 @@ +// +// HiFiConstants.qml +// +// Created by Bradley Austin Davis on 28 Apr 2015 +// Copyright 2015 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 +// + +import QtQuick 2.5 +import QtQuick.Window 2.2 + +Item { + readonly property alias colors: colors + readonly property alias colorSchemes: colorSchemes + readonly property alias dimensions: dimensions + readonly property alias fontSizes: fontSizes + readonly property alias glyphs: glyphs + readonly property alias icons: icons + readonly property alias buttons: buttons + readonly property alias effects: effects + + function glyphForIcon(icon) { + // Translates icon enum to glyph char. + var glyph; + switch (icon) { + case hifi.icons.information: + glyph = hifi.glyphs.info; + break; + case hifi.icons.question: + glyph = hifi.glyphs.question; + break; + case hifi.icons.warning: + glyph = hifi.glyphs.alert; + break; + case hifi.icons.critical: + glyph = hifi.glyphs.error; + break; + case hifi.icons.placemark: + glyph = hifi.glyphs.placemark; + break; + default: + glyph = hifi.glyphs.noIcon; + } + return glyph; + } + + Item { + id: colors + + // Base colors + readonly property color baseGray: "#393939" + readonly property color darkGray: "#121212" + readonly property color baseGrayShadow: "#252525" + readonly property color baseGrayHighlight: "#575757" + readonly property color lightGray: "#6a6a6a" + readonly property color lightGrayText: "#afafaf" + readonly property color faintGray: "#e3e3e3" + readonly property color primaryHighlight: "#00b4ef" + readonly property color blueHighlight: "#00b4ef" + readonly property color blueAccent: "#0093C5" + readonly property color redHighlight: "#EA4C5F" + readonly property color redAccent: "#C62147" + readonly property color greenHighlight: "#1ac567" + readonly property color greenShadow: "#359D85" + readonly property color orangeHighlight: "#FFC49C" + readonly property color orangeAccent: "#FF6309" + readonly property color indigoHighlight: "#C0D2FF" + readonly property color indigoAccent: "#9495FF" + readonly property color magentaHighlight: "#EF93D1" + readonly property color magentaAccent: "#A2277C" + readonly property color checkboxCheckedRed: "#FF0000" + readonly property color checkboxCheckedBorderRed: "#D00000" + readonly property color lightBlueHighlight: "#d6f6ff" + + // Semitransparent + readonly property color darkGray30: "#4d121212" + readonly property color darkGray0: "#00121212" + readonly property color baseGrayShadow60: "#99252525" + readonly property color baseGrayShadow50: "#80252525" + readonly property color baseGrayShadow25: "#40252525" + readonly property color baseGrayHighlight40: "#66575757" + readonly property color baseGrayHighlight15: "#26575757" + readonly property color lightGray50: "#806a6a6a" + readonly property color lightGrayText80: "#ccafafaf" + readonly property color faintGray80: "#cce3e3e3" + readonly property color faintGray50: "#80e3e3e3" + + // Other colors + readonly property color white: "#ffffff" + readonly property color gray: "#808080" + readonly property color black: "#000000" + readonly property color locked: "#252525" + // Semitransparent + readonly property color white50: "#80ffffff" + readonly property color white30: "#4dffffff" + readonly property color white25: "#40ffffff" + readonly property color transparent: "#00ffffff" + + // Control specific colors + readonly property color tableRowLightOdd: "#fafafa" + readonly property color tableRowLightEven: "#eeeeee" // Equivavlent to "#1a575757" over #e3e3e3 background + readonly property color tableRowDarkOdd: "#2e2e2e" // Equivalent to "#80393939" over #404040 background + readonly property color tableRowDarkEven: "#1c1c1c" // Equivalent to "#a6181818" over #404040 background + readonly property color tableBackgroundLight: tableRowLightEven + readonly property color tableBackgroundDark: tableRowDarkEven + readonly property color tableScrollHandleLight: "#DDDDDD" + readonly property color tableScrollHandleDark: "#707070" + readonly property color tableScrollBackgroundLight: tableRowLightOdd + readonly property color tableScrollBackgroundDark: "#323232" + readonly property color checkboxLightStart: "#ffffff" + readonly property color checkboxLightFinish: "#afafaf" + readonly property color checkboxDarkStart: "#7d7d7d" + readonly property color checkboxDarkFinish: "#6b6a6b" + readonly property color checkboxChecked: primaryHighlight + readonly property color checkboxCheckedBorder: "#36cdff" + readonly property color sliderGutterLight: "#d4d4d4" + readonly property color sliderGutterDark: "#252525" + readonly property color sliderBorderLight: "#afafaf" + readonly property color sliderBorderDark: "#7d7d7d" + readonly property color sliderLightStart: "#ffffff" + readonly property color sliderLightFinish: "#afafaf" + readonly property color sliderDarkStart: "#7d7d7d" + readonly property color sliderDarkFinish: "#6b6a6b" + readonly property color dropDownPressedLight: "#d4d4d4" + readonly property color dropDownPressedDark: "#afafaf" + readonly property color dropDownLightStart: "#ffffff" + readonly property color dropDownLightFinish: "#afafaf" + readonly property color dropDownDarkStart: "#7d7d7d" + readonly property color dropDownDarkFinish: "#6b6a6b" + readonly property color textFieldLightBackground: "#d4d4d4" + readonly property color tabBackgroundDark: "#252525" + readonly property color tabBackgroundLight: "#d4d4d4" + } + + Item { + id: colorSchemes + readonly property int light: 0 + readonly property int dark: 1 + readonly property int faintGray: 2 + } + + Item { + id: dimensions + readonly property bool largeScreen: Screen.width >= 1920 && Screen.height >= 1080 + readonly property real borderRadius: largeScreen ? 7.5 : 5.0 + readonly property real borderWidth: largeScreen ? 2 : 1 + readonly property vector2d contentMargin: Qt.vector2d(21, 21) + readonly property vector2d contentSpacing: Qt.vector2d(11, 14) + readonly property real labelPadding: 40 + readonly property real textPadding: 8 + readonly property real sliderHandleSize: 18 + readonly property real sliderGrooveHeight: 8 + readonly property real frameIconSize: 22 + readonly property real spinnerSize: 50 + readonly property real tablePadding: 12 + readonly property real tableRowHeight: largeScreen ? 26 : 23 + readonly property real tableHeaderHeight: 29 + readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30) + readonly property real modalDialogTitleHeight: 120 + readonly property real controlLineHeight: 84 // Height of spinbox control on 1920 x 1080 monitor + readonly property real controlInterlineHeight: 21 // 75% of controlLineHeight + readonly property vector2d menuPadding: Qt.vector2d(14, 102) + readonly property real scrollbarBackgroundWidth: 20 + readonly property real scrollbarHandleWidth: scrollbarBackgroundWidth - 2 + readonly property real tabletMenuHeader: 90 + readonly property real buttonWidth: 360 + } + + Item { + id: fontSizes // In pixels + readonly property real overlayTitle: dimensions.largeScreen ? 54 : 42 + readonly property real tabName: dimensions.largeScreen ? 12 : 10 + readonly property real sectionName: dimensions.largeScreen ? 36 : 30 + readonly property real inputLabel: dimensions.largeScreen ? 14 : 10 + readonly property real textFieldInput: dimensions.largeScreen ? 48 : 36 + readonly property real textFieldInputLabel: dimensions.largeScreen ? 13 : 9 + readonly property real textFieldSearchIcon: dimensions.largeScreen ? 30 : 24 + readonly property real tableHeading: dimensions.largeScreen ? 12 : 10 + readonly property real tableHeadingIcon: dimensions.largeScreen ? 60 : 33 + readonly property real tableText: dimensions.largeScreen ? 15 : 12 + readonly property real buttonLabel: dimensions.largeScreen ? 42 : 27 + readonly property real iconButton: dimensions.largeScreen ? 13 : 9 + readonly property real listItem: dimensions.largeScreen ? 15 : 11 + readonly property real tabularData: dimensions.largeScreen ? 15 : 11 + readonly property real logs: dimensions.largeScreen ? 16 : 12 + readonly property real code: dimensions.largeScreen ? 16 : 12 + readonly property real rootMenu: dimensions.largeScreen ? 15 : 11 + readonly property real rootMenuDisclosure: dimensions.largeScreen ? 20 : 16 + readonly property real menuItem: dimensions.largeScreen ? 45 : 33 + readonly property real shortcutText: dimensions.largeScreen ? 39 : 27 + readonly property real carat: dimensions.largeScreen ? 38 : 30 + readonly property real disclosureButton: dimensions.largeScreen ? 30 : 22 + } + + Item { + id: icons + // Values per OffscreenUi::Icon + readonly property int none: 0 + readonly property int question: 1 + readonly property int information: 2 + readonly property int warning: 3 + readonly property int critical: 4 + readonly property int placemark: 5 + } + + Item { + id: buttons + readonly property int white: 0 + readonly property int blue: 1 + readonly property int red: 2 + readonly property int black: 3 + readonly property int none: 4 + readonly property int noneBorderless: 5 + readonly property int noneBorderlessWhite: 6 + readonly property int noneBorderlessGray: 7 + readonly property var textColor: [ colors.darkGray, colors.white, colors.white, colors.white, colors.white, colors.blueAccent, colors.white, colors.darkGray ] + readonly property var colorStart: [ colors.white, colors.primaryHighlight, "#d42043", "#343434", Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0) ] + readonly property var colorFinish: [ colors.lightGrayText, colors.blueAccent, "#94132e", colors.black, Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0) ] + readonly property var hoveredColor: [ colorStart[white], colorStart[blue], colorStart[red], colorFinish[black], colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ] + readonly property var pressedColor: [ colorFinish[white], colorFinish[blue], colorFinish[red], colorStart[black], colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ] + readonly property var disabledColorStart: [ colorStart[white], colors.baseGrayHighlight] + readonly property var disabledColorFinish: [ colorFinish[white], colors.baseGrayShadow] + readonly property var disabledTextColor: [ colors.lightGrayText, colors.baseGrayShadow] + readonly property int radius: 15 + } + + QtObject { + id: effects + readonly property int fadeInDuration: 300 + } + Item { + id: glyphs + readonly property string noIcon: "" + readonly property string hmd: "b" + readonly property string screen: "c" + readonly property string keyboard: "d" + readonly property string handControllers: "e" + readonly property string headphonesMic: "f" + readonly property string gamepad: "g" + readonly property string headphones: "h" + readonly property string mic: "i" + readonly property string upload: "j" + readonly property string script: "k" + readonly property string text: "l" + readonly property string cube: "m" + readonly property string sphere: "n" + readonly property string zone: "o" + readonly property string light: "p" + readonly property string web: "q" + readonly property string web2: "r" + readonly property string edit: "s" + readonly property string market: "t" + readonly property string directory: "u" + readonly property string menu: "v" + readonly property string close: "w" + readonly property string closeInverted: "x" + readonly property string pin: "y" + readonly property string pinInverted: "z" + readonly property string resizeHandle: "A" + readonly property string disclosureExpand: "B" + readonly property string reloadSmall: "a" + readonly property string closeSmall: "C" + readonly property string forward: "D" + readonly property string backward: "E" + readonly property string reload: "F" + readonly property string unmuted: "G" + readonly property string muted: "H" + readonly property string minimize: "I" + readonly property string maximize: "J" + readonly property string maximizeInverted: "K" + readonly property string disclosureButtonExpand: "L" + readonly property string disclosureButtonCollapse: "M" + readonly property string scriptStop: "N" + readonly property string scriptReload: "O" + readonly property string scriptRun: "P" + readonly property string scriptNew: "Q" + readonly property string hifiForum: "2" + readonly property string hifiLogoSmall: "S" + readonly property string avatar1: "T" + readonly property string placemark: "U" + readonly property string box: "V" + readonly property string community: "0" + readonly property string grabHandle: "X" + readonly property string search: "Y" + readonly property string disclosureCollapse: "Z" + readonly property string scriptUpload: "R" + readonly property string code: "W" + readonly property string avatar: "<" + readonly property string arrowsH: ":" + readonly property string arrowsV: ";" + readonly property string arrows: "`" + readonly property string compress: "!" + readonly property string expand: "\"" + readonly property string placemark1: "#" + readonly property string circle: "$" + readonly property string handPointer: "9" + readonly property string plusSquareO: "%" + readonly property string sliders: "&" + readonly property string square: "'" + readonly property string alignCenter: "8" + readonly property string alignJustify: ")" + readonly property string alignLeft: "*" + readonly property string alignRight: "^" + readonly property string bars: "7" + readonly property string circleSlash: "," + readonly property string sync: "()" + readonly property string key: "-" + readonly property string link: "." + readonly property string location: "/" + readonly property string caratR: "3" + readonly property string caratL: "4" + readonly property string caratDn: "5" + readonly property string caratUp: "6" + readonly property string folderLg: ">" + readonly property string folderSm: "?" + readonly property string levelUp: "1" + readonly property string info: "[" + readonly property string question: "]" + readonly property string alert: "+" + readonly property string home: "_" + readonly property string error: "=" + readonly property string settings: "@" + readonly property string trash: "{" + readonly property string objectGroup: "\ue000" + readonly property string cm: "}" + readonly property string msvg79: "~" + readonly property string deg: "\\" + readonly property string px: "|" + readonly property string editPencil: "\ue00d" + readonly property string vol_0: "\ue00e" + readonly property string vol_1: "\ue00f" + readonly property string vol_2: "\ue010" + readonly property string vol_3: "\ue011" + readonly property string vol_4: "\ue012" + readonly property string vol_x_0: "\ue013" + readonly property string vol_x_1: "\ue014" + readonly property string vol_x_2: "\ue015" + readonly property string vol_x_3: "\ue016" + readonly property string vol_x_4: "\ue017" + readonly property string source: "\ue01c" + readonly property string playback_play: "\ue01d" + readonly property string stop_square: "\ue01e" + readonly property string avatarTPose: "\ue01f" + readonly property string lock: "\ue006" + readonly property string checkmark: "\ue020" + readonly property string leftRightArrows: "\ue021" + readonly property string hfc: "\ue022" + readonly property string home2: "\ue023" + readonly property string walletKey: "\ue024" + readonly property string lightning: "\ue025" + readonly property string securityImage: "\ue026" + readonly property string wallet: "\ue027" + readonly property string paperPlane: "\ue028" + readonly property string passphrase: "\ue029" + } +} diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index cf800cb62e..d676f032b7 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -165,6 +165,7 @@ Item { readonly property real scrollbarBackgroundWidth: 20 readonly property real scrollbarHandleWidth: scrollbarBackgroundWidth - 2 readonly property real tabletMenuHeader: 90 + readonly property real buttonWidth: 120 } Item { From 28c7ed761ef1d1e35b3cfbcc3dc7e039576832bc Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Thu, 15 Feb 2018 12:17:13 -0300 Subject: [PATCH 15/61] Add precision qualifier in fragment shaders for struct fields --- libraries/graphics/src/graphics/Light.slh | 10 ++++++- .../src/graphics/LightIrradiance.shared.slh | 12 ++++++--- .../src/graphics/LightVolume.shared.slh | 12 +++++++-- libraries/graphics/src/graphics/Material.slh | 17 +++++------- .../graphics/SphericalHarmonics.shared.slh | 26 ++++++++++++------- 5 files changed, 52 insertions(+), 25 deletions(-) diff --git a/libraries/graphics/src/graphics/Light.slh b/libraries/graphics/src/graphics/Light.slh index e1202ed6a0..cda19aadfb 100644 --- a/libraries/graphics/src/graphics/Light.slh +++ b/libraries/graphics/src/graphics/Light.slh @@ -32,8 +32,16 @@ vec3 getLightIrradiance(Light l) { return lightIrradiance_getIrradiance(l.irradi // AMbient lighting needs extra info provided from a different Buffer <@include graphics/SphericalHarmonics.shared.slh@> // Light Ambient +#ifndef PRECISIONQ +#ifdef GL_ES +#define PRECISIONQ highp +#else +#define PRECISIONQ +#endif +#endif + struct LightAmbient { - vec4 _ambient; + PRECISIONQ vec4 _ambient; SphericalHarmonics _ambientSphere; }; diff --git a/libraries/graphics/src/graphics/LightIrradiance.shared.slh b/libraries/graphics/src/graphics/LightIrradiance.shared.slh index 13d6cf4b93..ff42f57fd9 100644 --- a/libraries/graphics/src/graphics/LightIrradiance.shared.slh +++ b/libraries/graphics/src/graphics/LightIrradiance.shared.slh @@ -12,11 +12,17 @@ #define LightIrradianceConstRef LightIrradiance - +#ifndef PRECISIONQ +#ifdef GL_ES +#define PRECISIONQ highp +#else +#define PRECISIONQ +#endif +#endif struct LightIrradiance { - vec4 colorIntensity; + PRECISIONQ vec4 colorIntensity; // falloffRadius, cutoffRadius, falloffSpot, spare - vec4 attenuation; + PRECISIONQ vec4 attenuation; }; diff --git a/libraries/graphics/src/graphics/LightVolume.shared.slh b/libraries/graphics/src/graphics/LightVolume.shared.slh index 3f0cb135f5..48249e766f 100644 --- a/libraries/graphics/src/graphics/LightVolume.shared.slh +++ b/libraries/graphics/src/graphics/LightVolume.shared.slh @@ -15,9 +15,17 @@ #define LightVolumeConstRef LightVolume +#ifndef PRECISIONQ +#ifdef GL_ES +#define PRECISIONQ highp +#else +#define PRECISIONQ +#endif +#endif + struct LightVolume { - vec4 positionRadius; - vec4 directionSpotCos; + PRECISIONQ vec4 positionRadius; + PRECISIONQ vec4 directionSpotCos; }; bool lightVolume_isPoint(LightVolume lv) { return bool(lv.directionSpotCos.w < 0.f); } diff --git a/libraries/graphics/src/graphics/Material.slh b/libraries/graphics/src/graphics/Material.slh index 36bee3fb71..bdb87ff014 100644 --- a/libraries/graphics/src/graphics/Material.slh +++ b/libraries/graphics/src/graphics/Material.slh @@ -14,17 +14,17 @@ // The material values (at least the material key) must be precisely bitwise accurate // to what is provided by the uniform buffer, or the material key has the wrong bits #ifdef GL_ES -precision highp float; #define BITFIELD highp int +#define PRECISIONQ highp #else #define BITFIELD int +#define PRECISIONQ #endif - -struct Material { - vec4 _emissiveOpacity; - vec4 _albedoRoughness; - vec4 _fresnelMetallic; - vec4 _scatteringSpare2Key; +struct Material { + PRECISIONQ vec4 _emissiveOpacity; + PRECISIONQ vec4 _albedoRoughness; + PRECISIONQ vec4 _fresnelMetallic; + PRECISIONQ vec4 _scatteringSpare2Key; }; uniform materialBuffer { @@ -70,8 +70,5 @@ const BITFIELD OCCLUSION_MAP_BIT = 0x00004000; const BITFIELD LIGHTMAP_MAP_BIT = 0x00008000; const BITFIELD SCATTERING_MAP_BIT = 0x00010000; -#ifdef GL_ES -precision lowp float; -#endif <@endif@> diff --git a/libraries/graphics/src/graphics/SphericalHarmonics.shared.slh b/libraries/graphics/src/graphics/SphericalHarmonics.shared.slh index 312824c5a3..72a505fa25 100644 --- a/libraries/graphics/src/graphics/SphericalHarmonics.shared.slh +++ b/libraries/graphics/src/graphics/SphericalHarmonics.shared.slh @@ -15,16 +15,24 @@ #define SphericalHarmonicsConstRef SphericalHarmonics +#ifndef PRECISIONQ +#ifdef GL_ES +#define PRECISIONQ highp +#else +#define PRECISIONQ +#endif +#endif + struct SphericalHarmonics { - vec4 L00; - vec4 L1m1; - vec4 L10; - vec4 L11; - vec4 L2m2; - vec4 L2m1; - vec4 L20; - vec4 L21; - vec4 L22; + PRECISIONQ vec4 L00; + PRECISIONQ vec4 L1m1; + PRECISIONQ vec4 L10; + PRECISIONQ vec4 L11; + PRECISIONQ vec4 L2m2; + PRECISIONQ vec4 L2m1; + PRECISIONQ vec4 L20; + PRECISIONQ vec4 L21; + PRECISIONQ vec4 L22; }; vec4 sphericalHarmonics_evalSphericalLight(SphericalHarmonicsConstRef sh, vec3 direction) { From 1b08ce6ac209bb1240d5bfb6189d4bf805c879b7 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Thu, 15 Feb 2018 15:31:02 -0300 Subject: [PATCH 16/61] Set default location to pikachu/160.45,-2.45,159.106 for non-stable branches --- libraries/networking/src/AddressManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 322ca7167a..65a5e0c837 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -32,7 +32,7 @@ #if USE_STABLE_GLOBAL_SERVICES const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome/hello"; #else -const QString DEFAULT_HIFI_ADDRESS = "hifi://dev-welcome/hello"; +const QString DEFAULT_HIFI_ADDRESS = "hifi://pikachu/160.45,-2.45,159.106"; #endif const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; From 82f9416b3f071b2a07e3b49ca7c9939e34f9a593 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Thu, 15 Feb 2018 17:39:01 -0300 Subject: [PATCH 17/61] Restore default precision qualifier (needed for pixel) --- libraries/graphics/src/graphics/Material.slh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/graphics/src/graphics/Material.slh b/libraries/graphics/src/graphics/Material.slh index bdb87ff014..f9f4144748 100644 --- a/libraries/graphics/src/graphics/Material.slh +++ b/libraries/graphics/src/graphics/Material.slh @@ -14,6 +14,7 @@ // The material values (at least the material key) must be precisely bitwise accurate // to what is provided by the uniform buffer, or the material key has the wrong bits #ifdef GL_ES +precision highp float; #define BITFIELD highp int #define PRECISIONQ highp #else @@ -70,5 +71,7 @@ const BITFIELD OCCLUSION_MAP_BIT = 0x00004000; const BITFIELD LIGHTMAP_MAP_BIT = 0x00008000; const BITFIELD SCATTERING_MAP_BIT = 0x00010000; - +#ifdef GL_ES +precision lowp float; +#endif <@endif@> From 5f1fc37684d1cc0da70a11deab3831195cba98ef Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Fri, 16 Feb 2018 18:29:22 -0300 Subject: [PATCH 18/61] Android - Support display with smaller resolution than 1440p for Go To window --- .../qml/+android/AddressBarDialog.qml | 40 +++++++++---------- .../qml/hifi/+android/HifiConstants.qml | 32 ++++++++------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/interface/resources/qml/+android/AddressBarDialog.qml b/interface/resources/qml/+android/AddressBarDialog.qml index 0b12301561..8033840f6c 100644 --- a/interface/resources/qml/+android/AddressBarDialog.qml +++ b/interface/resources/qml/+android/AddressBarDialog.qml @@ -75,33 +75,33 @@ Item { HifiStyles.RalewayRegular { id: notice text: "YOUR LOCATION" - font.pixelSize: hifi.fonts.pixelSize * 2.15; + font.pixelSize: (hifi.fonts.pixelSize * 2.15)*(android.dimen.atLeast1440p?1:.75); color: "#2CD7FF" anchors { bottom: addressBackground.top - bottomMargin: 45 + bottomMargin: android.dimen.atLeast1440p?45:34 left: addressBackground.left - leftMargin: 60 + leftMargin: android.dimen.atLeast1440p?60:45 } } - property int inputAreaHeight: 210 + property int inputAreaHeight: android.dimen.atLeast1440p?210:156 property int inputAreaStep: (height - inputAreaHeight) / 2 ToolbarButton { id: homeButton - y: 280 + y: android.dimen.atLeast1440p?280:210 imageURL: "../../icons/home.svg" onClicked: { addressBarDialog.loadHome(); bar.shown = false; } anchors { - leftMargin: 75 + leftMargin: android.dimen.atLeast1440p?75:56 left: parent.left } - size: 150 + size: android.dimen.atLeast1440p?150:150//112 } ToolbarButton { @@ -110,10 +110,10 @@ Item { onClicked: addressBarDialog.loadBack(); anchors { left: homeButton.right - leftMargin: 70 + leftMargin: android.dimen.atLeast1440p?70:52 verticalCenter: homeButton.verticalCenter } - size: 150 + size: android.dimen.atLeast1440p?150:150 } ToolbarButton { id: forwardArrow; @@ -121,10 +121,10 @@ Item { onClicked: addressBarDialog.loadForward(); anchors { left: backArrow.right - leftMargin: 60 + leftMargin: android.dimen.atLeast1440p?60:45 verticalCenter: homeButton.verticalCenter } - size: 150 + size: android.dimen.atLeast1440p?150:150 } HifiStyles.FiraSansRegular { @@ -139,24 +139,24 @@ Item { Rectangle { id: addressBackground - x: 780 - y: 280 - width: 1440 - height: 150 + x: android.dimen.atLeast1440p?780:585 + y: android.dimen.atLeast1440p?280:235 // tweaking by hand + width: android.dimen.atLeast1440p?1270:952 + height: android.dimen.atLeast1440p?150:112 color: "#FFFFFF" } TextInput { id: addressLine focus: true - x: 870 - y: 450 - width: 1350 - height: 120 + x: android.dimen.atLeast1440p?870:652 + y: android.dimen.atLeast1440p?300:245 // tweaking by hand + width: android.dimen.atLeast1440p?1200:900 + height: android.dimen.atLeast1440p?120:90 inputMethodHints: Qt.ImhNoPredictiveText //helperText: "Hint is here" anchors { - verticalCenter: homeButton.verticalCenter + //verticalCenter: addressBackground.verticalCenter } font.pixelSize: hifi.fonts.pixelSize * 3.75 onTextChanged: { diff --git a/interface/resources/qml/hifi/+android/HifiConstants.qml b/interface/resources/qml/hifi/+android/HifiConstants.qml index f74cc554aa..fbdf60dcb0 100644 --- a/interface/resources/qml/hifi/+android/HifiConstants.qml +++ b/interface/resources/qml/hifi/+android/HifiConstants.qml @@ -10,6 +10,7 @@ // import QtQuick 2.4 +import QtQuick.Window 2.2 Item { @@ -20,26 +21,27 @@ Item { Item { id: dimen - readonly property real windowLessWidth: 126*3 - readonly property real windowLessHeight: 64*3 + readonly property bool atLeast1440p: Screen.width >= 2560 && Screen.height >= 1440 + readonly property real windowLessWidth: atLeast1440p?378:284 + readonly property real windowLessHeight: atLeast1440p?192:144 readonly property real windowZ: 100 - readonly property real headerHeight: 276 + readonly property real headerHeight: atLeast1440p?276:207 - readonly property real headerIconPosX: 90 - readonly property real headerIconPosY: 108 - readonly property real headerIconWidth: 111 - readonly property real headerIconHeight: 111 - readonly property real headerIconTitleDistance: 151 + readonly property real headerIconPosX: atLeast1440p?90:67 + readonly property real headerIconPosY: atLeast1440p?108:81 + readonly property real headerIconWidth: atLeast1440p?111:83 + readonly property real headerIconHeight: atLeast1440p?111:83 + readonly property real headerIconTitleDistance: atLeast1440p?151:113 - readonly property real headerHideWidth: 150 - readonly property real headerHideHeight: 150 - readonly property real headerHideRightMargin: 110 - readonly property real headerHideTopMargin: 90 - readonly property real headerHideIconWidth: 70 - readonly property real headerHideIconHeight: 45 - readonly property real headerHideTextTopMargin: 36 + readonly property real headerHideWidth: atLeast1440p?150:112 + readonly property real headerHideHeight: atLeast1440p?150:112 + readonly property real headerHideRightMargin: atLeast1440p?110:82 + readonly property real headerHideTopMargin: atLeast1440p?90:67 + readonly property real headerHideIconWidth: atLeast1440p?70:52 + readonly property real headerHideIconHeight: atLeast1440p?45:33 + readonly property real headerHideTextTopMargin: atLeast1440p?36:27 readonly property real botomHudWidth: 366 readonly property real botomHudHeight: 180 From 779e45aae749185b350c60a4bb011a75f644299d Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 19 Feb 2018 16:12:41 -0300 Subject: [PATCH 19/61] Restore avatar overlays --- .../render-utils/src/RenderForwardTask.cpp | 2 + scripts/system/+android/radar.js | 51 ++++++++++--------- scripts/system/+android/uniqueColor.js | 10 +++- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index f587cccd1a..fa3c9c86ab 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -37,6 +37,7 @@ using namespace render; extern void initForwardPipelines(ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); +extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest = false); void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { auto items = input.get(); @@ -45,6 +46,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); initForwardPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + initOverlay3DPipelines(*shapePlumber); // Extract opaques / transparents / lights / metas / overlays / background const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE]; diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index baf4441749..9682962eda 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -31,10 +31,11 @@ var PINCH_INCREMENT_FIRST = 0.4; // 0.1 meters zoom in - out var PINCH_INCREMENT = 0.4; // 0.1 meters zoom in - out var RADAR_HEIGHT_MAX_PLUS_AVATAR = 40; var RADAR_HEIGHT_MIN_PLUS_AVATAR = 2; -var RADAR_CAMERA_DISTANCE_TO_ICONS = 0.5; // Icons are near the camera to prevent the LOD manager dismissing them +var RADAR_CAMERA_DISTANCE_TO_ICONS = 1.5; // Icons are near the camera to prevent the LOD manager dismissing them var RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE = 1; // How much above the avatar base should the icon appear var AVATAR_DISPLAY_NAME_HEIGHT = 38; var AVATAR_DISPLAY_NAME_CHAR_WIDTH = 18; +var AVATAR_DISPLAY_NAME_FONT_SIZE = 350; var lastDragAt; var lastDeltaDrag; @@ -734,14 +735,15 @@ function saveAvatarData(QUuid) { if (avatarsData[QUuid] != undefined) { avatarsData[QUuid].position = avat.position; } else { - var avatarIcon = Overlays.addOverlay("image3d", { - subImage: { x: 0, y: 0, width: 150, height: 142}, - url: getAvatarIconForUser(QUuid), - dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, - visible: false, - ignoreRayIntersection: false, - orientation: Quat.fromPitchYawRollDegrees(-90,0,0) - }); + var avatarIcon = Overlays.addOverlay("circle3d", { + color: uniqueColor.convertHexToRGB(uniqueColor.getColor(QUuid)), + dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + innerRadius: 1.6, + outerRadius: 2, + isSolid: true, + visible: false + }); var needRefresh = !avat || !avat.displayName; var displayName = avat && avat.displayName ? avat.displayName : "Unknown"; @@ -752,7 +754,7 @@ function saveAvatarData(QUuid) { color: { red: 255, green: 255, blue: 255}, backgroundAlpha: 0.0, textRaiseColor: { red: 0, green: 0, blue: 0}, - font: {size: 68, bold: true}, + font: {size: AVATAR_DISPLAY_NAME_FONT_SIZE, bold: true}, visible: false, text: displayName, textAlignCenter: true @@ -833,15 +835,16 @@ function renderMyAvatarIcon() { var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) / (borderPoints[1].x - borderPoints[0].x); var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); - if (!myAvatarIcon && MyAvatar.sessionUUID) { - myAvatarIcon = Overlays.addOverlay("image3d", { - subImage: { x: 0, y: 0, width: 150, height: 142}, - url: getAvatarIconForUser(MyAvatar.sessionUUID), - dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, - visible: false, - ignoreRayIntersection: false, - orientation: Quat.fromPitchYawRollDegrees(-90,0,0) - }); + if (!myAvatarIcon && MyAvatar.SELF_ID) { + myAvatarIcon = Overlays.addOverlay("circle3d", { + color: uniqueColor.convertHexToRGB(uniqueColor.getColor(MyAvatar.SELF_ID)), + dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + innerRadius: 1.6, + outerRadius: 2, + isSolid: true, + visible: false + }); } if (!myAvatarName) { @@ -851,7 +854,7 @@ function renderMyAvatarIcon() { textAlignCenter: true, color: { red: 255, green: 255, blue: 255}, backgroundAlpha: 0.0, - font: {size: 68, bold: true}, + font: {size: AVATAR_DISPLAY_NAME_FONT_SIZE, bold: true}, textRaiseColor: { red: 0, green: 0, blue: 0}, visible: false, text: "Me" @@ -907,13 +910,13 @@ function renderAllOthersAvatarIcons() { if (AvatarList.getAvatar(QUuid) != null) { avatarPos = AvatarList.getAvatar(QUuid).position; - var cameraPos = Camera.position; - var p1 = findLineToHeightIntersectionCoords(avatarPos.x, avatarPos.y, avatarPos.z, + var cameraPos = Camera.position; + var p1 = findLineToHeightIntersectionCoords(avatarPos.x, avatarPos.y, avatarPos.z, cameraPos.x, cameraPos.y, cameraPos.z, commonY); - var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) / (borderPoints[1].x - borderPoints[0].x); - var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); + var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) / (borderPoints[1].x - borderPoints[0].x); + var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); if (avatarsData[QUuid].icon != undefined) { var iconPos = findLineToHeightIntersectionCoords( avatarPos.x, avatarPos.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, avatarPos.z, diff --git a/scripts/system/+android/uniqueColor.js b/scripts/system/+android/uniqueColor.js index c296b6c87d..a2741642d2 100644 --- a/scripts/system/+android/uniqueColor.js +++ b/scripts/system/+android/uniqueColor.js @@ -41,6 +41,14 @@ function getColorForId(uuid) { module.exports = { getColor: function(id) { - return getColorForId(id); + return getColorForId(id); + }, + convertHexToRGB: function(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + red: parseInt(result[1], 16), + green: parseInt(result[2], 16), + blue: parseInt(result[3], 16) + } : null; } }; From 94a8aad7128957950f75ba31ad019adacf6638fc Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 19 Feb 2018 16:52:51 -0300 Subject: [PATCH 20/61] Avoid keyboard appearing on startup --- .../qml/desktop/+android/FocusHack.qml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 interface/resources/qml/desktop/+android/FocusHack.qml diff --git a/interface/resources/qml/desktop/+android/FocusHack.qml b/interface/resources/qml/desktop/+android/FocusHack.qml new file mode 100644 index 0000000000..db703bab52 --- /dev/null +++ b/interface/resources/qml/desktop/+android/FocusHack.qml @@ -0,0 +1,24 @@ +// +// FocusHack.qml +// +// Created by Bradley Austin Davis on 21 Jan 2015 +// Copyright 2016 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 +// + +import QtQuick 2.5 + +FocusScope { + id: root + objectName: "FocusHack" + + TextInput { + id: textInput; + focus: true + width: 10; height: 10 + onActiveFocusChanged: root.destroy() + } + +} From 12770142fa44cd26cbd56078d8c001d676c7b55d Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 12 Feb 2018 16:45:44 -0300 Subject: [PATCH 21/61] Add bubble button to android bottombar --- .../resources/icons/+android/bubble-a.svg | 1022 +++++++++++++++++ .../resources/icons/+android/bubble-i.svg | 1022 +++++++++++++++++ scripts/system/+android/bottombar.js | 20 + 3 files changed, 2064 insertions(+) create mode 100644 interface/resources/icons/+android/bubble-a.svg create mode 100644 interface/resources/icons/+android/bubble-i.svg diff --git a/interface/resources/icons/+android/bubble-a.svg b/interface/resources/icons/+android/bubble-a.svg new file mode 100644 index 0000000000..fccc9c07ff --- /dev/null +++ b/interface/resources/icons/+android/bubble-a.svg @@ -0,0 +1,1022 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/interface/resources/icons/+android/bubble-i.svg b/interface/resources/icons/+android/bubble-i.svg new file mode 100644 index 0000000000..80c97d2704 --- /dev/null +++ b/interface/resources/icons/+android/bubble-i.svg @@ -0,0 +1,1022 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scripts/system/+android/bottombar.js b/scripts/system/+android/bottombar.js index 72ba1c1e50..5f82886c8a 100644 --- a/scripts/system/+android/bottombar.js +++ b/scripts/system/+android/bottombar.js @@ -15,6 +15,7 @@ var bottombar; var bottomHudOptionsBar; var gotoBtn; var avatarBtn; +var bubbleBtn; var loginBtn; var gotoScript = Script.require('./goto.js'); @@ -117,6 +118,25 @@ function setupBottomBar() { } }); + bubbleBtn = bottombar.addButton({ + icon: "icons/bubble-i.svg", + activeIcon: "icons/bubble-a.svg", + bgOpacity: 0, + hoverBgOpacity: 0, + activeBgOpacity: 0, + activeHoverBgOpacity: 0, + height: 240, + width: 294, + iconSize: 108, + textSize: 45, + text: "BUBBLE" + }); + + bubbleBtn.clicked.connect(function() { + Users.toggleIgnoreRadius(); + bubbleBtn.editProperties({isActive: Users.getIgnoreRadiusEnabled()}); + }); + loginBtn = bottombar.addButton({ icon: "icons/login-i.svg", activeIcon: "icons/login-a.svg", From c19664e3ca8010113a28d450e0326c85775c0a70 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Tue, 20 Feb 2018 12:01:10 -0300 Subject: [PATCH 22/61] Remove the shrink cap in radar mode --- scripts/system/+android/radar.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 9682962eda..bd2299f27d 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -29,7 +29,7 @@ var MOVE_BY = 1; // Swipe/Drag vars var PINCH_INCREMENT_FIRST = 0.4; // 0.1 meters zoom in - out var PINCH_INCREMENT = 0.4; // 0.1 meters zoom in - out -var RADAR_HEIGHT_MAX_PLUS_AVATAR = 40; +var RADAR_HEIGHT_MAX_PLUS_AVATAR = 80; var RADAR_HEIGHT_MIN_PLUS_AVATAR = 2; var RADAR_CAMERA_DISTANCE_TO_ICONS = 1.5; // Icons are near the camera to prevent the LOD manager dismissing them var RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE = 1; // How much above the avatar base should the icon appear @@ -811,19 +811,23 @@ function avatarRemoved(QUuid) { ********************************************************************************************************/ var myAvatarIcon; var myAvatarName; - +function distanceForCameraHeight(h) { + if (h < 10) return 1; + if (h < 50) return 2; + return 5; +} function renderMyAvatarIcon() { + var commonY = Camera.position.y - distanceForCameraHeight(Camera.position.y); var iconPos = findLineToHeightIntersectionCoords( MyAvatar.position.x, MyAvatar.position.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, MyAvatar.position.z, Camera.position.x, Camera.position.y, Camera.position.z, - Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS); + commonY); if (!iconPos) { printd("avatarmy icon pos null"); return;} var iconDimensions = avatarIconPlaneDimensions(); var avatarPos = MyAvatar.position; var cameraPos = Camera.position; - var commonY = Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS; var borderPoints = [ computePointAtPlaneY(0, 0, commonY), computePointAtPlaneY(Window.innerWidth, Window.innerHeight, commonY) @@ -899,7 +903,7 @@ function hideAllAvatarIcons() { function renderAllOthersAvatarIcons() { var avatarPos; var iconDimensions = avatarIconPlaneDimensions(); - var commonY = Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS; + var commonY = Camera.position.y - distanceForCameraHeight(Camera.position.y); var borderPoints = [ computePointAtPlaneY(0, 0, commonY), computePointAtPlaneY(Window.innerWidth, Window.innerHeight, commonY) @@ -921,7 +925,7 @@ function renderAllOthersAvatarIcons() { if (avatarsData[QUuid].icon != undefined) { var iconPos = findLineToHeightIntersectionCoords( avatarPos.x, avatarPos.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, avatarPos.z, Camera.position.x, Camera.position.y, Camera.position.z, - Camera.position.y - RADAR_CAMERA_DISTANCE_TO_ICONS); + commonY); if (!iconPos) { print ("avatar icon pos bad for " + QUuid); continue; } if (avatarsData[QUuid].needRefresh) { var avat = AvatarList.getAvatar(QUuid); From 4839a8c72049a8968c13814ed42c8b61b9b27164 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Tue, 20 Feb 2018 12:59:06 -0300 Subject: [PATCH 23/61] Remove Forgot labels in login dialog --- .../LoginDialog/+android/LinkAccountBody.qml | 45 ++----------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml index 8f76c6ed99..7eced0c751 100644 --- a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml @@ -117,62 +117,25 @@ Item { } spacing: hifi.dimensions.contentSpacing.y / 2 - Row { - spacing: hifi.dimensions.contentSpacing.x - TextField { id: usernameField anchors { - verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter } - width: 780 - + width: 1080 placeholderText: qsTr("Username or Email") } - ShortcutText { - anchors { - verticalCenter: parent.verticalCenter - } - - text: "Forgot Username?" - - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - linkColor: hifi.colors.blueAccent - - onLinkActivated: loginDialog.openUrl(link) - } - } - Row { - spacing: hifi.dimensions.contentSpacing.x - TextField { id: passwordField anchors { - verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter } - width: 780 + width: 1080 placeholderText: qsTr("Password") echoMode: TextInput.Password } - - ShortcutText { - anchors { - verticalCenter: parent.verticalCenter - } - - text: "Forgot Password?" - - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - linkColor: hifi.colors.blueAccent - - onLinkActivated: loginDialog.openUrl(link) - } - } - } InfoItem { From 5e3ad3fe9a3b05cb3e43a0f621c9f3d77d8510f8 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Tue, 20 Feb 2018 17:20:48 -0300 Subject: [PATCH 24/61] Disable VPAD on bottom bar tapping and modes bar tapping --- .../resources/qml/hifi/+android/bottombar.qml | 9 +++++++++ .../resources/qml/hifi/+android/button.qml | 4 ++++ .../resources/qml/hifi/+android/modesbar.qml | 6 ++++++ .../TouchscreenVirtualPadDevice.cpp | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/interface/resources/qml/hifi/+android/bottombar.qml b/interface/resources/qml/hifi/+android/bottombar.qml index 2a34b7fe19..e861d441d9 100644 --- a/interface/resources/qml/hifi/+android/bottombar.qml +++ b/interface/resources/qml/hifi/+android/bottombar.qml @@ -41,6 +41,15 @@ Item { Styles.HifiConstants { id: hifi } HifiConstants { id: android } + MouseArea { + anchors.fill: parent + onEntered: { + Controller.setVPadEnabled(false); + } + onExited: { + Controller.setVPadEnabled(true); + } + } Rectangle { id: background diff --git a/interface/resources/qml/hifi/+android/button.qml b/interface/resources/qml/hifi/+android/button.qml index ec7af2ab92..4822b6bf33 100644 --- a/interface/resources/qml/hifi/+android/button.qml +++ b/interface/resources/qml/hifi/+android/button.qml @@ -40,6 +40,8 @@ Item { property bool isActive: false signal clicked() + signal entered() + signal exited() onIsActiveChanged: { if (button.isEntered) { @@ -118,6 +120,7 @@ Item { } onEntered: { button.isEntered = true; + button.entered(); if (button.isActive) { button.state = "hover active state"; } else { @@ -126,6 +129,7 @@ Item { } onExited: { button.isEntered = false; + button.exited() if (button.isActive) { button.state = "active state"; } else { diff --git a/interface/resources/qml/hifi/+android/modesbar.qml b/interface/resources/qml/hifi/+android/modesbar.qml index fe71314ece..552ca80778 100644 --- a/interface/resources/qml/hifi/+android/modesbar.qml +++ b/interface/resources/qml/hifi/+android/modesbar.qml @@ -40,6 +40,12 @@ Item { var keys = Object.keys(properties).forEach(function (key) { button[key] = properties[key]; }); + button.entered.connect(function() { + Controller.setVPadEnabled(false); + }); + button.exited.connect(function() { + Controller.setVPadEnabled(true); + }); return button; } else if( component.status == Component.Error) { console.log("Load button errors " + component.errorString()); diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 8e1e6c2fba..53683870df 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -127,6 +127,10 @@ void TouchscreenVirtualPadDevice::debugPoints(const QTouchEvent* event, QString void TouchscreenVirtualPadDevice::touchBeginEvent(const QTouchEvent* event) { // touch begin here is a big begin -> begins both pads? maybe it does nothing debugPoints(event, " BEGIN ++++++++++++++++"); + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (!virtualPadManager.isEnabled()) { + return; + } KeyboardMouseDevice::enableTouch(false); QScreen* eventScreen = event->window()->screen(); _screenWidthCenter = eventScreen->size().width() / 2; @@ -138,6 +142,10 @@ void TouchscreenVirtualPadDevice::touchBeginEvent(const QTouchEvent* event) { } void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (!virtualPadManager.isEnabled()) { + return; + } // touch end here is a big reset -> resets both pads _touchPointCount = 0; KeyboardMouseDevice::enableTouch(true); @@ -148,6 +156,12 @@ void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { } void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (!virtualPadManager.isEnabled()) { + touchLeftEnd(); + touchRightEnd(); + return; + } _touchPointCount = event->touchPoints().count(); const QList& tPoints = event->touchPoints(); @@ -224,6 +238,10 @@ void TouchscreenVirtualPadDevice::touchRightEnd() { } void TouchscreenVirtualPadDevice::touchGestureEvent(const QGestureEvent* event) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (!virtualPadManager.isEnabled()) { + return; + } if (QGesture* gesture = event->gesture(Qt::PinchGesture)) { QPinchGesture* pinch = static_cast(gesture); _pinchScale = pinch->totalScaleFactor(); From bd9d8ac4f99b4ad8f8a8656d98745fec43958fbb Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Tue, 20 Feb 2018 19:07:41 -0300 Subject: [PATCH 25/61] Tune radar styles --- libraries/networking/src/AddressManager.cpp | 2 +- scripts/system/+android/radar.js | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 65a5e0c837..30ed20de68 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -107,7 +107,7 @@ void AddressManager::loadSettings(const QString& lookupString) { #if defined(USE_GLES) && defined(Q_OS_WIN) handleUrl(QUrl("hifi://127.0.0.0"), LookupTrigger::StartupFromSettings); #elif defined(Q_OS_ANDROID) - handleUrl(QUrl("hifi://dev-android"), LookupTrigger::StartupFromSettings); + handleUrl(QUrl(DEFAULT_HIFI_ADDRESS), LookupTrigger::StartupFromSettings); #else if (lookupString.isEmpty()) { handleUrl(currentAddressHandle.get(), LookupTrigger::StartupFromSettings); diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index bd2299f27d..54e1e51945 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -33,9 +33,9 @@ var RADAR_HEIGHT_MAX_PLUS_AVATAR = 80; var RADAR_HEIGHT_MIN_PLUS_AVATAR = 2; var RADAR_CAMERA_DISTANCE_TO_ICONS = 1.5; // Icons are near the camera to prevent the LOD manager dismissing them var RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE = 1; // How much above the avatar base should the icon appear -var AVATAR_DISPLAY_NAME_HEIGHT = 38; -var AVATAR_DISPLAY_NAME_CHAR_WIDTH = 18; -var AVATAR_DISPLAY_NAME_FONT_SIZE = 350; +var AVATAR_DISPLAY_NAME_HEIGHT = 106; +var AVATAR_DISPLAY_NAME_CHAR_WIDTH = 48; +var AVATAR_DISPLAY_NAME_FONT_SIZE = 50; var lastDragAt; var lastDeltaDrag; @@ -739,7 +739,7 @@ function saveAvatarData(QUuid) { color: uniqueColor.convertHexToRGB(uniqueColor.getColor(QUuid)), dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), - innerRadius: 1.6, + innerRadius: 1.8, outerRadius: 2, isSolid: true, visible: false @@ -812,8 +812,9 @@ function avatarRemoved(QUuid) { var myAvatarIcon; var myAvatarName; function distanceForCameraHeight(h) { - if (h < 10) return 1; - if (h < 50) return 2; + if (h < 30) return 1; + if (h < 40) return 2; + if (h < 50) return 2.5; return 5; } function renderMyAvatarIcon() { @@ -844,7 +845,7 @@ function renderMyAvatarIcon() { color: uniqueColor.convertHexToRGB(uniqueColor.getColor(MyAvatar.SELF_ID)), dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), - innerRadius: 1.6, + innerRadius: 1.8, outerRadius: 2, isSolid: true, visible: false @@ -853,7 +854,7 @@ function renderMyAvatarIcon() { if (!myAvatarName) { myAvatarName = Overlays.addOverlay("text", { - width: 40, + width: 100, height: AVATAR_DISPLAY_NAME_HEIGHT, textAlignCenter: true, color: { red: 255, green: 255, blue: 255}, From 00958965bc2da6e56a86cc8608daf8140d41af2e Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Tue, 20 Feb 2018 19:25:41 -0300 Subject: [PATCH 26/61] Android- Center login dialog in both big (Pixel XL, Huawei Mate 9 Pro) and smaller screens (Pixel) --- interface/resources/qml/+android/LoginDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/+android/LoginDialog.qml b/interface/resources/qml/+android/LoginDialog.qml index c60864cd1d..9eb2c74147 100644 --- a/interface/resources/qml/+android/LoginDialog.qml +++ b/interface/resources/qml/+android/LoginDialog.qml @@ -53,7 +53,7 @@ ModalWindow { Component.onCompleted: { this.anchors.centerIn = undefined; this.y=150; - this.x=450; + this.x=(parent.width - this.width)/2; } Keys.onPressed: { From 6411d1b35b009ac97385fe78f5229259d5910d35 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Wed, 21 Feb 2018 16:52:57 -0300 Subject: [PATCH 27/61] Android - Avoid overlapping between hint and input in Go To by clearing text when closing the window --- interface/resources/qml/+android/AddressBarDialog.qml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/+android/AddressBarDialog.qml b/interface/resources/qml/+android/AddressBarDialog.qml index 8033840f6c..50552f0d3b 100644 --- a/interface/resources/qml/+android/AddressBarDialog.qml +++ b/interface/resources/qml/+android/AddressBarDialog.qml @@ -33,7 +33,8 @@ Item { bar.visible = shown; sendToScript({method: 'shownChanged', params: { shown: shown }}); if (shown) { - updateLocationText(false); + addressLine.text=""; + updateLocationText(addressLine.text.length > 0); } } @@ -43,7 +44,7 @@ Item { } Component.onCompleted: { - updateLocationText(false); + updateLocationText(addressLine.text.length > 0); } HifiConstants { id: hifi } @@ -130,7 +131,7 @@ Item { HifiStyles.FiraSansRegular { id: location; font.pixelSize: addressLine.font.pixelSize; - color: "gray"; + color: "lightgray"; clip: true; anchors.fill: addressLine; visible: addressLine.text.length === 0 From 2a597eb7154d99679da744c7282e2326371d1afc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 20 Feb 2018 17:00:28 -0800 Subject: [PATCH 28/61] use QCoreApplication for oven when headless version is used --- tools/oven/src/BakerCLI.cpp | 19 +++++--- tools/oven/src/BakerCLI.h | 6 +-- tools/oven/src/DomainBaker.cpp | 6 +-- tools/oven/src/Oven.cpp | 62 +++++++------------------- tools/oven/src/Oven.h | 23 +++------- tools/oven/src/OvenCLIApplication.cpp | 49 ++++++++++++++++++++ tools/oven/src/OvenCLIApplication.h | 27 +++++++++++ tools/oven/src/OvenGUIApplication.cpp | 19 ++++++++ tools/oven/src/OvenGUIApplication.h | 33 ++++++++++++++ tools/oven/src/main.cpp | 13 ++++-- tools/oven/src/ui/BakeWidget.cpp | 5 +-- tools/oven/src/ui/DomainBakeWidget.cpp | 11 +++-- tools/oven/src/ui/ModelBakeWidget.cpp | 11 +++-- tools/oven/src/ui/SkyboxBakeWidget.cpp | 9 ++-- 14 files changed, 193 insertions(+), 100 deletions(-) create mode 100644 tools/oven/src/OvenCLIApplication.cpp create mode 100644 tools/oven/src/OvenCLIApplication.h create mode 100644 tools/oven/src/OvenGUIApplication.cpp create mode 100644 tools/oven/src/OvenGUIApplication.h diff --git a/tools/oven/src/BakerCLI.cpp b/tools/oven/src/BakerCLI.cpp index 5af65c4dc0..f5af5455fb 100644 --- a/tools/oven/src/BakerCLI.cpp +++ b/tools/oven/src/BakerCLI.cpp @@ -14,13 +14,14 @@ #include #include +#include "OvenCLIApplication.h" #include "ModelBakingLoggingCategory.h" -#include "Oven.h" #include "BakerCLI.h" #include "FBXBaker.h" #include "TextureBaker.h" -BakerCLI::BakerCLI(Oven* parent) : QObject(parent) { +BakerCLI::BakerCLI(OvenCLIApplication* parent) : QObject(parent) { + } void BakerCLI::bakeFile(QUrl inputUrl, const QString& outputPath, const QString& type) { @@ -50,14 +51,18 @@ void BakerCLI::bakeFile(QUrl inputUrl, const QString& outputPath, const QString& // create our appropiate baker if (isFBX) { - _baker = std::unique_ptr { new FBXBaker(inputUrl, []() -> QThread* { return qApp->getNextWorkerThread(); }, outputPath) }; - _baker->moveToThread(qApp->getNextWorkerThread()); + _baker = std::unique_ptr { + new FBXBaker(inputUrl, + []() -> QThread* { return Oven::instance().getNextWorkerThread(); }, + outputPath) + }; + _baker->moveToThread(Oven::instance().getNextWorkerThread()); } else if (isSupportedImage) { _baker = std::unique_ptr { new TextureBaker(inputUrl, image::TextureUsage::CUBE_TEXTURE, outputPath) }; - _baker->moveToThread(qApp->getNextWorkerThread()); + _baker->moveToThread(Oven::instance().getNextWorkerThread()); } else { qCDebug(model_baking) << "Failed to determine baker type for file" << inputUrl; - QApplication::exit(OVEN_STATUS_CODE_FAIL); + QCoreApplication::exit(OVEN_STATUS_CODE_FAIL); } // invoke the bake method on the baker thread @@ -81,5 +86,5 @@ void BakerCLI::handleFinishedBaker() { errorFile.close(); } } - QApplication::exit(exitCode); + QCoreApplication::exit(exitCode); } diff --git a/tools/oven/src/BakerCLI.h b/tools/oven/src/BakerCLI.h index 7d362eb898..4f5b6607b0 100644 --- a/tools/oven/src/BakerCLI.h +++ b/tools/oven/src/BakerCLI.h @@ -18,7 +18,7 @@ #include #include "Baker.h" -#include "Oven.h" +#include "OvenCLIApplication.h" static const int OVEN_STATUS_CODE_SUCCESS { 0 }; static const int OVEN_STATUS_CODE_FAIL { 1 }; @@ -27,10 +27,10 @@ static const int OVEN_STATUS_CODE_ABORT { 2 }; static const QString OVEN_ERROR_FILENAME = "errors.txt"; class BakerCLI : public QObject { - Q_OBJECT + Q_OBJECT public: - BakerCLI(Oven* parent); + BakerCLI(OvenCLIApplication* parent); void bakeFile(QUrl inputUrl, const QString& outputPath, const QString& type = QString::null); private slots: diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index edc2492e82..28ede982a0 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -201,7 +201,7 @@ void DomainBaker::enumerateEntities() { } QSharedPointer baker { new FBXBaker(modelURL, []() -> QThread* { - return qApp->getNextWorkerThread(); + return Oven::instance().getNextWorkerThread(); }, _contentOutputPath + subDirName + "/baked", _contentOutputPath + subDirName + "/original"), &FBXBaker::deleteLater }; @@ -214,7 +214,7 @@ void DomainBaker::enumerateEntities() { // move the baker to the baker thread // and kickoff the bake - baker->moveToThread(qApp->getNextWorkerThread()); + baker->moveToThread(Oven::instance().getNextWorkerThread()); QMetaObject::invokeMethod(baker.data(), "bake"); // keep track of the total number of baking entities @@ -285,7 +285,7 @@ void DomainBaker::bakeSkybox(QUrl skyboxURL, QJsonValueRef entity) { _skyboxBakers.insert(skyboxURL, skyboxBaker); // move the baker to a worker thread and kickoff the bake - skyboxBaker->moveToThread(qApp->getNextWorkerThread()); + skyboxBaker->moveToThread(Oven::instance().getNextWorkerThread()); QMetaObject::invokeMethod(skyboxBaker.data(), "bake"); // keep track of the total number of baking entities diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index 69d2ef84ce..e8d4c01f63 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -11,33 +11,15 @@ #include #include -#include #include -#include "ui/OvenMainWindow.h" #include "Oven.h" -#include "BakerCLI.h" -static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/export"; +Oven* Oven::_staticInstance { nullptr }; -static const QString CLI_INPUT_PARAMETER = "i"; -static const QString CLI_OUTPUT_PARAMETER = "o"; -static const QString CLI_TYPE_PARAMETER = "t"; - -Oven::Oven(int argc, char* argv[]) : - QApplication(argc, argv) -{ - // parse the command line parameters - QCommandLineParser parser; - - parser.addOptions({ - { CLI_INPUT_PARAMETER, "Path to file that you would like to bake.", "input" }, - { CLI_OUTPUT_PARAMETER, "Path to folder that will be used as output.", "output" }, - { CLI_TYPE_PARAMETER, "Type of asset.", "type" } - }); - parser.addHelpOption(); - parser.process(*this); +Oven::Oven() { + _staticInstance = this; // enable compression in image library image::setColorTexturesCompressionEnabled(true); @@ -47,41 +29,27 @@ Oven::Oven(int argc, char* argv[]) : // setup our worker threads setupWorkerThreads(QThread::idealThreadCount()); - - // check if we were passed any command line arguments that would tell us just to run without the GUI - if (parser.isSet(CLI_INPUT_PARAMETER) || parser.isSet(CLI_OUTPUT_PARAMETER)) { - if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) { - BakerCLI* cli = new BakerCLI(this); - QUrl inputUrl(QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER))); - QUrl outputUrl(QDir::fromNativeSeparators(parser.value(CLI_OUTPUT_PARAMETER))); - QString type = parser.isSet(CLI_TYPE_PARAMETER) ? parser.value(CLI_TYPE_PARAMETER) : QString::null; - cli->bakeFile(inputUrl, outputUrl.toString(), type); - } else { - parser.showHelp(); - QApplication::quit(); - } - } else { - // setup the GUI - _mainWindow = new OvenMainWindow; - _mainWindow->show(); - } } Oven::~Oven() { - // cleanup the worker threads - for (auto i = 0; i < _workerThreads.size(); ++i) { - _workerThreads[i]->quit(); - _workerThreads[i]->wait(); + // quit and wait on the worker threads + for (auto& thread : _workerThreads) { + thread->quit(); + thread->wait(); } + + _staticInstance = nullptr; } void Oven::setupWorkerThreads(int numWorkerThreads) { + _workerThreads.reserve(numWorkerThreads); + for (auto i = 0; i < numWorkerThreads; ++i) { // setup a worker thread yet and add it to our concurrent vector - auto newThread = new QThread(this); + auto newThread = std::unique_ptr { new QThread }; newThread->setObjectName("Oven Worker Thread " + QString::number(i + 1)); - _workerThreads.push_back(newThread); + _workerThreads.push_back(std::move(newThread)); } } @@ -92,13 +60,13 @@ QThread* Oven::getNextWorkerThread() { // (for the FBX Baker Thread to have room), and cycle through them to hand a usable running thread back to our callers. auto nextIndex = ++_nextWorkerThreadIndex; - auto nextThread = _workerThreads[nextIndex % _workerThreads.size()]; + auto& nextThread = _workerThreads[nextIndex % _workerThreads.size()]; // start the thread if it isn't running yet if (!nextThread->isRunning()) { nextThread->start(); } - return nextThread; + return nextThread.get(); } diff --git a/tools/oven/src/Oven.h b/tools/oven/src/Oven.h index 928ba4eb11..443def5cb1 100644 --- a/tools/oven/src/Oven.h +++ b/tools/oven/src/Oven.h @@ -12,27 +12,15 @@ #ifndef hifi_Oven_h #define hifi_Oven_h -#include - -#include - #include -#if defined(qApp) -#undef qApp -#endif -#define qApp (static_cast(QCoreApplication::instance())) - -class OvenMainWindow; - -class Oven : public QApplication { - Q_OBJECT +class Oven { public: - Oven(int argc, char* argv[]); + Oven(); ~Oven(); - OvenMainWindow* getMainWindow() const { return _mainWindow; } + static Oven& instance() { return *_staticInstance; } QThread* getNextWorkerThread(); @@ -40,11 +28,12 @@ private: void setupWorkerThreads(int numWorkerThreads); void setupFBXBakerThread(); - OvenMainWindow* _mainWindow; - QList _workerThreads; + std::vector> _workerThreads; std::atomic _nextWorkerThreadIndex; int _numWorkerThreads; + + static Oven* _staticInstance; }; diff --git a/tools/oven/src/OvenCLIApplication.cpp b/tools/oven/src/OvenCLIApplication.cpp new file mode 100644 index 0000000000..38d9963eeb --- /dev/null +++ b/tools/oven/src/OvenCLIApplication.cpp @@ -0,0 +1,49 @@ +// +// OvenCLIApplication.cpp +// tools/oven/src +// +// Created by Stephen Birarda on 2/20/18. +// Copyright 2018 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 +#include + +#include "BakerCLI.h" + +#include "OvenCLIApplication.h" + +static const QString CLI_INPUT_PARAMETER = "i"; +static const QString CLI_OUTPUT_PARAMETER = "o"; +static const QString CLI_TYPE_PARAMETER = "t"; + +OvenCLIApplication::OvenCLIApplication(int argc, char* argv[]) : + QCoreApplication(argc, argv) +{ + // parse the command line parameters + QCommandLineParser parser; + + parser.addOptions({ + { CLI_INPUT_PARAMETER, "Path to file that you would like to bake.", "input" }, + { CLI_OUTPUT_PARAMETER, "Path to folder that will be used as output.", "output" }, + { CLI_TYPE_PARAMETER, "Type of asset.", "type" } + }); + + parser.addHelpOption(); + parser.process(*this); + + if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) { + BakerCLI* cli = new BakerCLI(this); + QUrl inputUrl(QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER))); + QUrl outputUrl(QDir::fromNativeSeparators(parser.value(CLI_OUTPUT_PARAMETER))); + QString type = parser.isSet(CLI_TYPE_PARAMETER) ? parser.value(CLI_TYPE_PARAMETER) : QString::null; + cli->bakeFile(inputUrl, outputUrl.toString(), type); + } else { + parser.showHelp(); + QCoreApplication::quit(); + } + +} diff --git a/tools/oven/src/OvenCLIApplication.h b/tools/oven/src/OvenCLIApplication.h new file mode 100644 index 0000000000..5d81166f69 --- /dev/null +++ b/tools/oven/src/OvenCLIApplication.h @@ -0,0 +1,27 @@ +// +// OvenCLIApplication.h +// tools/oven/src +// +// Created by Stephen Birarda on 2/20/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_OvenCLIApplication_h +#define hifi_OvenCLIApplication_h + +#include + +#include "Oven.h" + +class OvenCLIApplication : public QCoreApplication, public Oven { + Q_OBJECT +public: + OvenCLIApplication(int argc, char* argv[]); + + static OvenCLIApplication* instance() { return dynamic_cast(QCoreApplication::instance()); } +}; + +#endif // hifi_OvenCLIApplication_h diff --git a/tools/oven/src/OvenGUIApplication.cpp b/tools/oven/src/OvenGUIApplication.cpp new file mode 100644 index 0000000000..33dc375634 --- /dev/null +++ b/tools/oven/src/OvenGUIApplication.cpp @@ -0,0 +1,19 @@ +// +// OvenGUIApplication.cpp +// tools/src/oven +// +// Created by Stephen Birarda on 2/20/18. +// Copyright 2018 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 "OvenGUIApplication.h" + +OvenGUIApplication::OvenGUIApplication(int argc, char* argv[]) : + QApplication(argc, argv) +{ + // setup the GUI + _mainWindow.show(); +} diff --git a/tools/oven/src/OvenGUIApplication.h b/tools/oven/src/OvenGUIApplication.h new file mode 100644 index 0000000000..7f5bbf3eaf --- /dev/null +++ b/tools/oven/src/OvenGUIApplication.h @@ -0,0 +1,33 @@ +// +// OvenGUIApplication.h +// tools/oven/src +// +// Created by Stephen Birarda on 2/20/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_OvenGUIApplication_h +#define hifi_OvenGUIApplication_h + +#include + +#include "ui/OvenMainWindow.h" + +#include "Oven.h" + +class OvenGUIApplication : public QApplication, public Oven { + Q_OBJECT +public: + OvenGUIApplication(int argc, char* argv[]); + + static OvenGUIApplication* instance() { return dynamic_cast(QApplication::instance()); } + + OvenMainWindow* getMainWindow() { return &_mainWindow; } +private: + OvenMainWindow _mainWindow; +}; + +#endif // hifi_OvenGUIApplication_h diff --git a/tools/oven/src/main.cpp b/tools/oven/src/main.cpp index 788470b75e..062cc63a0d 100644 --- a/tools/oven/src/main.cpp +++ b/tools/oven/src/main.cpp @@ -8,7 +8,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -#include "Oven.h" +#include "OvenCLIApplication.h" +#include "OvenGUIApplication.h" #include @@ -19,6 +20,12 @@ int main (int argc, char** argv) { // init the settings interface so we can save and load settings Setting::init(); - Oven app(argc, argv); - return app.exec(); + // figure out if we're launching our GUI application or just the simple command line interface + if (argc > 1) { + OvenCLIApplication app { argc, argv }; + return app.exec(); + } else { + OvenGUIApplication app { argc, argv }; + return app.exec(); + } } diff --git a/tools/oven/src/ui/BakeWidget.cpp b/tools/oven/src/ui/BakeWidget.cpp index 9fb8f2f880..22e1b1aaf9 100644 --- a/tools/oven/src/ui/BakeWidget.cpp +++ b/tools/oven/src/ui/BakeWidget.cpp @@ -11,8 +11,7 @@ #include -#include "../Oven.h" -#include "OvenMainWindow.h" +#include "../OvenGUIApplication.h" #include "BakeWidget.h" @@ -28,7 +27,7 @@ BakeWidget::~BakeWidget() { auto it = _bakers.begin(); while (it != _bakers.end()) { auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); resultsWindow->changeStatusForRow(resultRow, "Cancelled"); diff --git a/tools/oven/src/ui/DomainBakeWidget.cpp b/tools/oven/src/ui/DomainBakeWidget.cpp index 41452c7283..bf79319458 100644 --- a/tools/oven/src/ui/DomainBakeWidget.cpp +++ b/tools/oven/src/ui/DomainBakeWidget.cpp @@ -21,8 +21,7 @@ #include #include -#include "../Oven.h" -#include "OvenMainWindow.h" +#include "../OvenGUIApplication.h" #include "DomainBakeWidget.h" @@ -223,14 +222,14 @@ void DomainBakeWidget::bakeButtonClicked() { connect(domainBaker.get(), &DomainBaker::bakeProgress, this, &DomainBakeWidget::handleBakerProgress); // move the baker to the next available Oven worker thread - auto nextThread = qApp->getNextWorkerThread(); + auto nextThread = Oven::instance().getNextWorkerThread(); domainBaker->moveToThread(nextThread); // kickoff the domain baker on its thread QMetaObject::invokeMethod(domainBaker.get(), "bake"); // add a pending row to the results window to show that this bake is in process - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); auto resultsRowName = _domainNameLineEdit->text().isEmpty() ? fileToBakeURL.fileName() : _domainNameLineEdit->text(); auto resultsRow = resultsWindow->addPendingResultRow(resultsRowName, outputDirectory); @@ -250,7 +249,7 @@ void DomainBakeWidget::handleBakerProgress(int baked, int total) { auto resultRow = it->second; // grab the results window, don't force it to be brought to the top - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(false); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(false); int percentage = roundf(float(baked) / float(total) * 100.0f); @@ -269,7 +268,7 @@ void DomainBakeWidget::handleFinishedBaker() { if (it != _bakers.end()) { auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); if (baker->hasErrors()) { auto errors = baker->getErrors(); diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index 7963b3f3c4..61eea55917 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -21,8 +21,7 @@ #include #include -#include "../Oven.h" -#include "OvenMainWindow.h" +#include "../OvenGUIApplication.h" #include "ModelBakeWidget.h" @@ -208,12 +207,12 @@ void ModelBakeWidget::bakeButtonClicked() { // everything seems to be in place, kick off a bake for this model now auto baker = std::unique_ptr { new FBXBaker(modelToBakeURL, []() -> QThread* { - return qApp->getNextWorkerThread(); + return Oven::instance().getNextWorkerThread(); }, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath()) }; // move the baker to the FBX baker thread - baker->moveToThread(qApp->getNextWorkerThread()); + baker->moveToThread(Oven::instance().getNextWorkerThread()); // invoke the bake method on the baker thread QMetaObject::invokeMethod(baker.get(), "bake"); @@ -222,7 +221,7 @@ void ModelBakeWidget::bakeButtonClicked() { connect(baker.get(), &FBXBaker::finished, this, &ModelBakeWidget::handleFinishedBaker); // add a pending row to the results window to show that this bake is in process - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); auto resultsRow = resultsWindow->addPendingResultRow(modelToBakeURL.fileName(), outputDirectory); // keep a unique_ptr to this baker @@ -244,7 +243,7 @@ void ModelBakeWidget::handleFinishedBaker() { if (it != _bakers.end()) { auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); if (baker->hasErrors()) { resultsWindow->changeStatusForRow(resultRow, baker->getErrors().join("\n")); diff --git a/tools/oven/src/ui/SkyboxBakeWidget.cpp b/tools/oven/src/ui/SkyboxBakeWidget.cpp index cbaaa5ec0a..369b06c39f 100644 --- a/tools/oven/src/ui/SkyboxBakeWidget.cpp +++ b/tools/oven/src/ui/SkyboxBakeWidget.cpp @@ -21,8 +21,7 @@ #include #include -#include "../Oven.h" -#include "OvenMainWindow.h" +#include "../OvenGUIApplication.h" #include "SkyboxBakeWidget.h" @@ -184,7 +183,7 @@ void SkyboxBakeWidget::bakeButtonClicked() { }; // move the baker to a worker thread - baker->moveToThread(qApp->getNextWorkerThread()); + baker->moveToThread(Oven::instance().getNextWorkerThread()); // invoke the bake method on the baker thread QMetaObject::invokeMethod(baker.get(), "bake"); @@ -193,7 +192,7 @@ void SkyboxBakeWidget::bakeButtonClicked() { connect(baker.get(), &TextureBaker::finished, this, &SkyboxBakeWidget::handleFinishedBaker); // add a pending row to the results window to show that this bake is in process - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); auto resultsRow = resultsWindow->addPendingResultRow(skyboxToBakeURL.fileName(), outputDirectory); // keep a unique_ptr to this baker @@ -211,7 +210,7 @@ void SkyboxBakeWidget::handleFinishedBaker() { if (it != _bakers.end()) { auto resultRow = it->second; - auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); if (baker->hasErrors()) { resultsWindow->changeStatusForRow(resultRow, baker->getErrors().join("\n")); From d4061c172ef8cb795b4b8409312ae1d41865686b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 20 Feb 2018 17:27:40 -0800 Subject: [PATCH 29/61] quit all threads before waiting on them (CR) --- tools/oven/src/Oven.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index e8d4c01f63..650683e1f0 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -32,9 +32,12 @@ Oven::Oven() { } Oven::~Oven() { - // quit and wait on the worker threads + // quit all worker threads and wait on them for (auto& thread : _workerThreads) { thread->quit(); + } + + for (auto& thread: _workerThreads) { thread->wait(); } From 79f5d0cee21161054b12d220b28d1d4bac546887 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 20 Feb 2018 18:49:38 -0800 Subject: [PATCH 30/61] include memory for unique_ptr in Oven --- tools/oven/src/Oven.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/oven/src/Oven.h b/tools/oven/src/Oven.h index 443def5cb1..effebb472e 100644 --- a/tools/oven/src/Oven.h +++ b/tools/oven/src/Oven.h @@ -13,6 +13,7 @@ #define hifi_Oven_h #include +#include class Oven { From f2ce3d026874b2ae28f9fcc426e07c0ad9c5f6a3 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Wed, 21 Feb 2018 20:10:03 -0300 Subject: [PATCH 31/61] Fix focus hack. Add QML debug info --- interface/resources/qml/desktop/+android/FocusHack.qml | 2 ++ interface/resources/qml/windows/Frame.qml | 2 +- libraries/ui/src/OffscreenUi.cpp | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/desktop/+android/FocusHack.qml b/interface/resources/qml/desktop/+android/FocusHack.qml index db703bab52..38253fdec1 100644 --- a/interface/resources/qml/desktop/+android/FocusHack.qml +++ b/interface/resources/qml/desktop/+android/FocusHack.qml @@ -21,4 +21,6 @@ FocusScope { onActiveFocusChanged: root.destroy() } + function start() { + } } diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml index c3b8399e01..52ca53b818 100644 --- a/interface/resources/qml/windows/Frame.qml +++ b/interface/resources/qml/windows/Frame.qml @@ -43,7 +43,7 @@ Item { Text { id: debugZ visible: DebugQML - text: window ? "Z: " + window.z : "" + text: (window ? "Z: " + window.z : "") + DebugQMLFile y: window ? window.height + 4 : 0 } diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 221f5013bf..287978bbd3 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -658,8 +658,10 @@ void OffscreenUi::createDesktop(const QUrl& url) { #ifdef DEBUG getSurfaceContext()->setContextProperty("DebugQML", QVariant(true)); + getSurfaceContext()->setContextProperty("DebugQMLFile", QVariant(url.toString())); #else getSurfaceContext()->setContextProperty("DebugQML", QVariant(false)); + getSurfaceContext()->setContextProperty("DebugQMLFile", QVariant("")); #endif load(url, [=](QQmlContext* context, QObject* newObject) { From 2d4bb3bad39c10f95590a9f25fc003df4bb035d8 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Wed, 21 Feb 2018 20:23:54 -0300 Subject: [PATCH 32/61] Change color to QML debug info --- interface/resources/qml/windows/Frame.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml index 52ca53b818..4391c902ed 100644 --- a/interface/resources/qml/windows/Frame.qml +++ b/interface/resources/qml/windows/Frame.qml @@ -43,6 +43,7 @@ Item { Text { id: debugZ visible: DebugQML + color: "red" text: (window ? "Z: " + window.z : "") + DebugQMLFile y: window ? window.height + 4 : 0 } From 63e2084395a1de52bcd83264598cd3dea71ceb61 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 22 Feb 2018 17:29:06 -0800 Subject: [PATCH 33/61] Add a Q_DECLARE_METATYPE in TextureCache. There was a missing declaration that was causing an assert in the Qt meta-object system on startup in debug builds: Q_DECLARE_METATYPE(QWeakPointer) Bug fixed by Clement. --- libraries/model-networking/src/model-networking/TextureCache.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index ffa3150b43..f817c5eff9 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -133,6 +133,8 @@ private: using NetworkTexturePointer = QSharedPointer; +Q_DECLARE_METATYPE(QWeakPointer) + /// Stores cached textures, including render-to-texture targets. class TextureCache : public ResourceCache, public Dependency { Q_OBJECT From b56f755034bcd578cf4c2e6419531d6ef24a317c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 23 Feb 2018 15:10:49 -0800 Subject: [PATCH 34/61] material reflection --- interface/src/ui/overlays/ModelOverlay.cpp | 4 + .../src/avatars-renderer/Avatar.cpp | 4 + .../src/RenderableModelEntityItem.cpp | 4 + .../src/RenderableShapeEntityItem.cpp | 8 +- libraries/gpu/src/gpu/Texture.cpp | 10 -- libraries/gpu/src/gpu/Texture.h | 7 +- libraries/graphics-scripting/CMakeLists.txt | 2 +- .../src/graphics-scripting/Forward.h | 43 +++++- .../src/graphics-scripting/ScriptableMesh.cpp | 58 ++++++++ .../graphics-scripting/ScriptableModel.cpp | 124 ++++++++++++++++++ .../src/graphics-scripting/ScriptableModel.h | 7 +- libraries/graphics/src/graphics/Material.h | 1 + .../src/model-networking/MaterialCache.cpp | 7 + .../src/model-networking/TextureCache.cpp | 4 +- .../render-utils/src/CauterizedModel.cpp | 2 + libraries/render-utils/src/Model.cpp | 8 ++ 16 files changed, 272 insertions(+), 21 deletions(-) diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index ffcc18032c..47dd8f45f9 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -671,5 +671,9 @@ scriptable::ScriptableModelBase ModelOverlay::getScriptableModel() { } auto result = _model->getScriptableModel(); result.objectID = getID(); + { + std::lock_guard lock(_materialsLock); + result.appendMaterials(_materials); + } return result; } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 25ddfba670..db20f9144d 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1801,5 +1801,9 @@ scriptable::ScriptableModelBase Avatar::getScriptableModel() { } auto result = _skeletonModel->getScriptableModel(); result.objectID = getSessionUUID(); + { + std::lock_guard lock(_materialsLock); + result.appendMaterials(_materials); + } return result; } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f3c99cde2d..5c95d1e556 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -970,6 +970,10 @@ scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScript auto result = _model->getScriptableModel(); result.objectID = getEntity()->getID(); + { + std::lock_guard lock(_materialsLock); + result.appendMaterials(_materials); + } return result; } diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 22cd98b08a..e5cbfdb59d 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -169,8 +169,12 @@ scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() { auto geometryCache = DependencyManager::get(); auto geometryShape = geometryCache->getShapeForEntityShape(_shape); glm::vec3 vertexColor; - if (_materials["0"].top().material) { - vertexColor = _materials["0"].top().material->getAlbedo(); + { + std::lock_guard lock(_materialsLock); + result.appendMaterials(_materials); + if (_materials["0"].top().material) { + vertexColor = _materials["0"].top().material->getAlbedo(); + } } if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) { result.objectID = getEntity()->getID(); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 4a588c3c84..ed9505766b 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -868,16 +868,6 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture) { // TextureSource -TextureSource::TextureSource() { -} - -TextureSource::~TextureSource() { -} - -void TextureSource::reset(const QUrl& url) { - _imageUrl = url; -} - void TextureSource::resetTexture(gpu::TexturePointer texture) { _gpuTexture = texture; } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index ad3dc5fada..a03b894e0d 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -647,13 +647,11 @@ typedef std::vector TextureViews; // It provides the mechanism to create a texture using a customizable TextureLoader class TextureSource { public: - TextureSource(); - ~TextureSource(); + TextureSource(const QUrl& url, int type = 0) : _imageUrl(url), _type(type) {} const QUrl& getUrl() const { return _imageUrl; } const gpu::TexturePointer getGPUTexture() const { return _gpuTexture; } - - void reset(const QUrl& url); + int getType() const { return _type; } void resetTexture(gpu::TexturePointer texture); @@ -662,6 +660,7 @@ public: protected: gpu::TexturePointer _gpuTexture; QUrl _imageUrl; + int _type { 0 }; }; typedef std::shared_ptr< TextureSource > TextureSourcePointer; diff --git a/libraries/graphics-scripting/CMakeLists.txt b/libraries/graphics-scripting/CMakeLists.txt index ad8055b647..0f59fb41f8 100644 --- a/libraries/graphics-scripting/CMakeLists.txt +++ b/libraries/graphics-scripting/CMakeLists.txt @@ -1,4 +1,4 @@ set(TARGET_NAME graphics-scripting) setup_hifi_library() -link_hifi_libraries(shared networking graphics fbx model-networking script-engine) +link_hifi_libraries(shared networking graphics fbx image model-networking script-engine) include_hifi_library_headers(gpu) diff --git a/libraries/graphics-scripting/src/graphics-scripting/Forward.h b/libraries/graphics-scripting/src/graphics-scripting/Forward.h index 94a96446a0..b07c25ee02 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/Forward.h +++ b/libraries/graphics-scripting/src/graphics-scripting/Forward.h @@ -6,9 +6,14 @@ #include #include #include +#include #include #include + +#include "graphics/Material.h" +#include "graphics/TextureMap.h" + namespace graphics { class Mesh; } @@ -31,6 +36,38 @@ namespace scriptable { using ModelProviderPointer = std::shared_ptr; using WeakModelProviderPointer = std::weak_ptr; + class ScriptableMaterial { + public: + ScriptableMaterial() {} + ScriptableMaterial(const graphics::MaterialLayer& materialLayer); + ScriptableMaterial(const ScriptableMaterial& material) { *this = material; } + ScriptableMaterial& operator=(const ScriptableMaterial& material); + + QString name; + QString model; + float opacity; + float roughness; + float metallic; + float scattering; + bool unlit; + glm::vec3 emissive; + glm::vec3 albedo; + QString emissiveMap; + QString albedoMap; + QString opacityMap; + QString metallicMap; + QString specularMap; + QString roughnessMap; + QString glossMap; + QString normalMap; + QString bumpMap; + QString occlusionMap; + QString lightmapMap; + QString scatteringMap; + quint16 priority; + }; + typedef QHash> MultiMaterialMap; + class ScriptableMeshBase : public QObject { Q_OBJECT public: @@ -55,6 +92,8 @@ namespace scriptable { WeakModelProviderPointer provider; QUuid objectID; // spatially nestable ID QVector meshes; + MultiMaterialMap materials; + QVector materialNames; ScriptableModelBase(QObject* parent = nullptr) : QObject(parent) {} ScriptableModelBase(const ScriptableModelBase& other) : QObject(other.parent()) { *this = other; } @@ -63,9 +102,11 @@ namespace scriptable { void append(const ScriptableMeshBase& mesh); void append(scriptable::WeakMeshPointer mesh); + void appendMaterial(const graphics::MaterialLayer& material, int shapeID, std::string materialName); + void appendMaterials(const std::unordered_map& materialsToAppend); + void appendMaterialNames(const std::vector& names); // TODO: in future containers for these could go here // QVariantMap shapes; - // QVariantMap materials; // QVariantMap armature; }; diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp index 76741947fd..7da69fcad2 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp @@ -554,6 +554,57 @@ namespace { qScriptValueToSequence(array, result); } + QScriptValue qVectorScriptableMaterialToScriptValue(QScriptEngine* engine, const QVector& vector) { + return qScriptValueFromSequence(engine, vector); + } + + void qVectorScriptableMaterialFromScriptValue(const QScriptValue& array, QVector& result) { + qScriptValueToSequence(array, result); + } + + QScriptValue scriptableMaterialToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterial &material) { + QScriptValue obj = engine->newObject(); + obj.setProperty("name", material.name); + obj.setProperty("model", material.model); + obj.setProperty("opacity", material.opacity); + obj.setProperty("roughness", material.roughness); + obj.setProperty("metallic", material.metallic); + obj.setProperty("scattering", material.scattering); + obj.setProperty("unlit", material.unlit); + obj.setProperty("emissive", vec3toScriptValue(engine, material.emissive)); + obj.setProperty("albedo", vec3toScriptValue(engine, material.albedo)); + obj.setProperty("emissiveMap", material.emissiveMap); + obj.setProperty("albedoMap", material.albedoMap); + obj.setProperty("opacityMap", material.opacityMap); + obj.setProperty("metallicMap", material.metallicMap); + obj.setProperty("specularMap", material.specularMap); + obj.setProperty("roughnessMap", material.roughnessMap); + obj.setProperty("glossMap", material.glossMap); + obj.setProperty("normalMap", material.normalMap); + obj.setProperty("bumpMap", material.bumpMap); + obj.setProperty("occlusionMap", material.occlusionMap); + obj.setProperty("lightmapMap", material.lightmapMap); + obj.setProperty("scatteringMap", material.scatteringMap); + obj.setProperty("priority", material.priority); + return obj; + } + + void scriptableMaterialFromScriptValue(const QScriptValue &object, scriptable::ScriptableMaterial& material) { + // No need to convert from QScriptValue to ScriptableMaterial + } + + QScriptValue multiMaterialMapToScriptValue(QScriptEngine* engine, const scriptable::MultiMaterialMap& map) { + QScriptValue obj = engine->newObject(); + for (auto key : map.keys()) { + obj.setProperty(key, qVectorScriptableMaterialToScriptValue(engine, map[key])); + } + return obj; + } + + void multiMaterialMapFromScriptValue(const QScriptValue& map, scriptable::MultiMaterialMap& result) { + // No need to convert from QScriptValue to MultiMaterialMap + } + QVector metaTypeIds{ qRegisterMetaType("uint32"), qRegisterMetaType("scriptable::uint32"), @@ -562,6 +613,9 @@ namespace { qRegisterMetaType(), qRegisterMetaType(), qRegisterMetaType(), + qRegisterMetaType(), + qRegisterMetaType>(), + qRegisterMetaType() }; } @@ -570,11 +624,15 @@ namespace scriptable { qScriptRegisterSequenceMetaType>(engine); qScriptRegisterSequenceMetaType>(engine); qScriptRegisterSequenceMetaType>(engine); + qScriptRegisterSequenceMetaType>(engine); qScriptRegisterMetaType(engine, qVectorUInt32ToScriptValue, qVectorUInt32FromScriptValue); qScriptRegisterMetaType(engine, modelPointerToScriptValue, modelPointerFromScriptValue); qScriptRegisterMetaType(engine, meshPointerToScriptValue, meshPointerFromScriptValue); qScriptRegisterMetaType(engine, meshPartPointerToScriptValue, meshPartPointerFromScriptValue); + qScriptRegisterMetaType(engine, scriptableMaterialToScriptValue, scriptableMaterialFromScriptValue); + qScriptRegisterMetaType(engine, qVectorScriptableMaterialToScriptValue, qVectorScriptableMaterialFromScriptValue); + qScriptRegisterMetaType(engine, multiMaterialMapToScriptValue, multiMaterialMapFromScriptValue); return metaTypeIds.size(); } diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp index 8ceb7de6a2..9a4bfe60b6 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -14,14 +14,115 @@ #include +#include "graphics/Material.h" + +#include "image/Image.h" + // #define SCRIPTABLE_MESH_DEBUG 1 +scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const scriptable::ScriptableMaterial& material) { + name = material.name; + model = material.model; + opacity = material.opacity; + roughness = material.roughness; + metallic = material.metallic; + scattering = material.scattering; + unlit = material.unlit; + emissive = material.emissive; + albedo = material.albedo; + emissiveMap = material.emissiveMap; + albedoMap = material.albedoMap; + opacityMap = material.opacityMap; + metallicMap = material.metallicMap; + specularMap = material.specularMap; + roughnessMap = material.roughnessMap; + glossMap = material.glossMap; + normalMap = material.normalMap; + bumpMap = material.bumpMap; + occlusionMap = material.occlusionMap; + lightmapMap = material.lightmapMap; + scatteringMap = material.scatteringMap; + priority = material.priority; + + return *this; +} + +scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer& materialLayer) : + name(materialLayer.material->getName().c_str()), + model(materialLayer.material->getModel().c_str()), + opacity(materialLayer.material->getOpacity()), + roughness(materialLayer.material->getRoughness()), + metallic(materialLayer.material->getMetallic()), + scattering(materialLayer.material->getScattering()), + unlit(materialLayer.material->isUnlit()), + emissive(materialLayer.material->getEmissive()), + albedo(materialLayer.material->getAlbedo()), + priority(materialLayer.priority) +{ + auto map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP); + if (map && map->getTextureSource()) { + emissiveMap = map->getTextureSource()->getUrl().toString(); + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP); + if (map && map->getTextureSource()) { + albedoMap = map->getTextureSource()->getUrl().toString(); + if (map->useAlphaChannel()) { + opacityMap = albedoMap; + } + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP); + if (map && map->getTextureSource()) { + if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) { + metallicMap = map->getTextureSource()->getUrl().toString(); + } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::SPECULAR_TEXTURE) { + specularMap = map->getTextureSource()->getUrl().toString(); + } + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP); + if (map && map->getTextureSource()) { + if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) { + roughnessMap = map->getTextureSource()->getUrl().toString(); + } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::GLOSS_TEXTURE) { + glossMap = map->getTextureSource()->getUrl().toString(); + } + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP); + if (map && map->getTextureSource()) { + if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) { + normalMap = map->getTextureSource()->getUrl().toString(); + } else if (map->getTextureSource()->getType() == image::TextureUsage::Type::BUMP_TEXTURE) { + bumpMap = map->getTextureSource()->getUrl().toString(); + } + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP); + if (map && map->getTextureSource()) { + occlusionMap = map->getTextureSource()->getUrl().toString(); + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP); + if (map && map->getTextureSource()) { + lightmapMap = map->getTextureSource()->getUrl().toString(); + } + + map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP); + if (map && map->getTextureSource()) { + scatteringMap = map->getTextureSource()->getUrl().toString(); + } +} + scriptable::ScriptableModelBase& scriptable::ScriptableModelBase::operator=(const scriptable::ScriptableModelBase& other) { provider = other.provider; objectID = other.objectID; for (const auto& mesh : other.meshes) { append(mesh); } + materials = other.materials; + materialNames = other.materialNames; return *this; } @@ -34,6 +135,8 @@ scriptable::ScriptableModelBase::~ScriptableModelBase() { m.strongMesh.reset(); } meshes.clear(); + materials.clear(); + materialNames.clear(); } void scriptable::ScriptableModelBase::append(scriptable::WeakMeshPointer mesh) { @@ -47,6 +150,27 @@ void scriptable::ScriptableModelBase::append(const ScriptableMeshBase& mesh) { meshes << mesh; } +void scriptable::ScriptableModelBase::appendMaterial(const graphics::MaterialLayer& material, int shapeID, std::string materialName) { + materials[QString::number(shapeID)].push_back(ScriptableMaterial(material)); + materials["mat::" + QString::fromStdString(materialName)].push_back(ScriptableMaterial(material)); +} + +void scriptable::ScriptableModelBase::appendMaterials(const std::unordered_map& materialsToAppend) { + auto materialsToAppendCopy = materialsToAppend; + for (auto& multiMaterial : materialsToAppendCopy) { + while (!multiMaterial.second.empty()) { + materials[QString(multiMaterial.first.c_str())].push_back(ScriptableMaterial(multiMaterial.second.top())); + multiMaterial.second.pop(); + } + } +} + +void scriptable::ScriptableModelBase::appendMaterialNames(const std::vector& names) { + for (auto& name : names) { + materialNames.append(QString::fromStdString(name)); + } +} + QString scriptable::ScriptableModel::toString() const { return QString("[ScriptableModel%1%2 numMeshes=%3]") .arg(objectID.isNull() ? "" : " objectID="+objectID.toString()) diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index 4ed1cc9554..9dc4c6f1ca 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -19,6 +19,8 @@ namespace scriptable { Q_PROPERTY(QUuid objectID MEMBER objectID CONSTANT) Q_PROPERTY(uint32 numMeshes READ getNumMeshes) Q_PROPERTY(QVector meshes READ getMeshes) + Q_PROPERTY(scriptable::MultiMaterialMap materials READ getMaterials) + Q_PROPERTY(QVector materialNames READ getMaterialNames) ScriptableModel(QObject* parent = nullptr) : ScriptableModelBase(parent) {} ScriptableModel(const ScriptableModel& other) : ScriptableModelBase(other) {} @@ -28,7 +30,6 @@ namespace scriptable { Q_INVOKABLE scriptable::ScriptableModelPointer cloneModel(const QVariantMap& options = QVariantMap()); // TODO: in future accessors for these could go here // QVariantMap shapes; - // QVariantMap materials; // QVariantMap armature; QVector getMeshes(); @@ -37,6 +38,8 @@ namespace scriptable { return QPointer(qobject_cast(this)); } + scriptable::MultiMaterialMap getMaterials() { return materials; } + QVector getMaterialNames() { return materialNames; } // QScriptEngine-specific wrappers Q_INVOKABLE uint32 mapAttributeValues(QScriptValue callback); @@ -51,3 +54,5 @@ Q_DECLARE_METATYPE(scriptable::WeakMeshPointer) Q_DECLARE_METATYPE(scriptable::ScriptableModelPointer) Q_DECLARE_METATYPE(scriptable::ScriptableModelBase) Q_DECLARE_METATYPE(scriptable::ScriptableModelBasePointer) +Q_DECLARE_METATYPE(scriptable::ScriptableMaterial) +Q_DECLARE_METATYPE(scriptable::MultiMaterialMap) diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 632cf99391..f34f68c04a 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -358,6 +358,7 @@ public: const std::string& getName() { return _name; } + const std::string& getModel() { return _model; } void setModel(const std::string& model) { _model = model; } protected: diff --git a/libraries/model-networking/src/model-networking/MaterialCache.cpp b/libraries/model-networking/src/model-networking/MaterialCache.cpp index 8d9d6571f8..85f2f43652 100644 --- a/libraries/model-networking/src/model-networking/MaterialCache.cpp +++ b/libraries/model-networking/src/model-networking/MaterialCache.cpp @@ -11,6 +11,8 @@ #include "QJsonDocument" #include "QJsonArray" +#include "RegisteredMetaTypes.h" + NetworkMaterialResource::NetworkMaterialResource(const QUrl& url) : Resource(url) {} @@ -39,6 +41,11 @@ bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble()); return true; } + } else if (array.isObject()) { + bool toReturn; + isSRGB = true; + color = vec3FromVariant(array.toObject(), toReturn); + return toReturn; } return false; } diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3a29139ee7..9b12c34f87 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -291,7 +291,7 @@ _type(), _sourceIsKTX(false), _maxNumPixels(100) { - _textureSource = std::make_shared(); + _textureSource = std::make_shared(url); _lowestRequestedMipLevel = 0; _loaded = true; } @@ -303,7 +303,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type, _sourceIsKTX(url.path().endsWith(".ktx")), _maxNumPixels(maxNumPixels) { - _textureSource = std::make_shared(); + _textureSource = std::make_shared(url, (int)type); _lowestRequestedMipLevel = 0; _shouldFailOnRedirect = !_sourceIsKTX; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 54dfd96a00..5685a85349 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -57,6 +57,7 @@ void CauterizedModel::createVisibleRenderItemSet() { Q_ASSERT(_modelMeshRenderItems.isEmpty()); _modelMeshRenderItems.clear(); + _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); Transform transform; @@ -81,6 +82,7 @@ void CauterizedModel::createVisibleRenderItemSet() { for (int partIndex = 0; partIndex < numParts; partIndex++) { auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::static_pointer_cast(ptr); + _modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName()); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6d735497c0..f55b3c598d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -629,12 +629,20 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { const FBXGeometry& geometry = getFBXGeometry(); int numberOfMeshes = geometry.meshes.size(); + int shapeID = 0; for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& fbxMesh = geometry.meshes.at(i); if (auto mesh = fbxMesh._mesh) { result.append(mesh); + + int numParts = (int)mesh->getNumParts(); + for (int partIndex = 0; partIndex < numParts; partIndex++) { + result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, _modelMeshMaterialNames[shapeID]); + shapeID++; + } } } + result.appendMaterialNames(_modelMeshMaterialNames); return result; } From 7982d8da58246836394fcd5278f68d4e198e170e Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 26 Feb 2018 13:06:22 -0300 Subject: [PATCH 35/61] Set bubble default state off for android. --- libraries/networking/src/NodeList.h | 4 ++++ scripts/system/+android/bottombar.js | 2 ++ 2 files changed, 6 insertions(+) diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 2dd9d3c869..b419deba2f 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -172,7 +172,11 @@ private: tbb::concurrent_unordered_map _avatarGainMap; void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode); +#if defined(Q_OS_ANDROID) + Setting::Handle _ignoreRadiusEnabled { "IgnoreRadiusEnabled", false }; +#else Setting::Handle _ignoreRadiusEnabled { "IgnoreRadiusEnabled", true }; +#endif #if (PR_BUILD || DEV_BUILD) bool _shouldSendNewerVersion { false }; diff --git a/scripts/system/+android/bottombar.js b/scripts/system/+android/bottombar.js index 5f82886c8a..51453ce9dd 100644 --- a/scripts/system/+android/bottombar.js +++ b/scripts/system/+android/bottombar.js @@ -132,6 +132,8 @@ function setupBottomBar() { text: "BUBBLE" }); + bubbleBtn.editProperties({isActive: Users.getIgnoreRadiusEnabled()}); + bubbleBtn.clicked.connect(function() { Users.toggleIgnoreRadius(); bubbleBtn.editProperties({isActive: Users.getIgnoreRadiusEnabled()}); From 3e552e5739058255262a2288597c1d76916e20ce Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 23 Feb 2018 13:29:03 -0800 Subject: [PATCH 36/61] Fix warnings --- .../src/scripting/AssetMappingsScriptingInterface.cpp | 8 ++++---- libraries/networking/src/BaseAssetScriptingInterface.cpp | 2 +- libraries/render-utils/src/AnimDebugDraw.cpp | 1 - libraries/script-engine/src/AssetScriptingInterface.cpp | 8 ++++---- libraries/shared/src/shared/MiniPromises.h | 4 ++-- tools/ktx-tool/src/main.cpp | 7 ------- 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index dc227c21ba..4bc8ec0bd3 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -140,7 +140,7 @@ void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue auto assetClient = DependencyManager::get(); auto request = assetClient->createDeleteMappingsRequest(paths); - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + connect(request, &DeleteMappingsRequest::finished, this, [callback](DeleteMappingsRequest* request) mutable { if (callback.isCallable()) { QJSValueList args { request->getErrorString() }; callback.call(args); @@ -156,7 +156,7 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + connect(request, &GetAllMappingsRequest::finished, this, [callback](GetAllMappingsRequest* request) mutable { auto mappings = request->getMappings(); auto map = callback.engine()->newObject(); @@ -179,7 +179,7 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new auto assetClient = DependencyManager::get(); auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + connect(request, &RenameMappingRequest::finished, this, [callback](RenameMappingRequest* request) mutable { if (callback.isCallable()) { QJSValueList args{ request->getErrorString() }; callback.call(args); @@ -195,7 +195,7 @@ void AssetMappingsScriptingInterface::setBakingEnabled(QStringList paths, bool e auto assetClient = DependencyManager::get(); auto request = assetClient->createSetBakingEnabledRequest(paths, enabled); - connect(request, &SetBakingEnabledRequest::finished, this, [this, callback](SetBakingEnabledRequest* request) mutable { + connect(request, &SetBakingEnabledRequest::finished, this, [callback](SetBakingEnabledRequest* request) mutable { if (callback.isCallable()) { QJSValueList args{ request->getErrorString() }; callback.call(args); diff --git a/libraries/networking/src/BaseAssetScriptingInterface.cpp b/libraries/networking/src/BaseAssetScriptingInterface.cpp index 3149bbc768..066331f927 100644 --- a/libraries/networking/src/BaseAssetScriptingInterface.cpp +++ b/libraries/networking/src/BaseAssetScriptingInterface.cpp @@ -233,7 +233,7 @@ Promise BaseAssetScriptingInterface::downloadBytes(QString hash) { QPointer assetRequest = assetClient()->createRequest(hash); Promise deferred = makePromise(__FUNCTION__); - QObject::connect(assetRequest, &AssetRequest::finished, assetRequest, [this, deferred](AssetRequest* request) { + QObject::connect(assetRequest, &AssetRequest::finished, assetRequest, [deferred](AssetRequest* request) { // note: we are now on the "Resource Manager" thread Q_ASSERT(QThread::currentThread() == request->thread()); Q_ASSERT(request->getState() == AssetRequest::Finished); diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 12e8a97fb7..67d1e2e36e 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -9,7 +9,6 @@ #include "AnimDebugDraw.h" -#include #include #include diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index 1c811573fb..1a88fbe959 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -50,7 +50,7 @@ void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { jsCallback(handler, url, hash); }); - connect(upload, &AssetUpload::finished, upload, [this, deferred](AssetUpload* upload, const QString& hash) { + connect(upload, &AssetUpload::finished, upload, [deferred](AssetUpload* upload, const QString& hash) { // we are now on the "Resource Manager" thread (and "hash" being a *reference* makes it unsafe to use directly) Q_ASSERT(QThread::currentThread() == upload->thread()); deferred->resolve({ @@ -70,7 +70,7 @@ void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValu jsCallback(handler, error, result); }); - connect(setMappingRequest, &SetMappingRequest::finished, setMappingRequest, [this, deferred](SetMappingRequest* request) { + connect(setMappingRequest, &SetMappingRequest::finished, setMappingRequest, [deferred](SetMappingRequest* request) { Q_ASSERT(QThread::currentThread() == request->thread()); // we are now on the "Resource Manager" thread QString error = request->getErrorString(); @@ -102,7 +102,7 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb jsCallback(handler, result.value("data").toString(), { { "errorMessage", error } }); }); - connect(assetRequest, &AssetRequest::finished, assetRequest, [this, deferred](AssetRequest* request) { + connect(assetRequest, &AssetRequest::finished, assetRequest, [deferred](AssetRequest* request) { Q_ASSERT(QThread::currentThread() == request->thread()); // we are now on the "Resource Manager" thread Q_ASSERT(request->getState() == AssetRequest::Finished); @@ -128,7 +128,7 @@ void AssetScriptingInterface::setBakingEnabled(QString path, bool enabled, QScri Promise deferred = jsPromiseReady(makePromise(__FUNCTION__), thisObject(), callback); - connect(setBakingEnabledRequest, &SetBakingEnabledRequest::finished, setBakingEnabledRequest, [this, deferred](SetBakingEnabledRequest* request) { + connect(setBakingEnabledRequest, &SetBakingEnabledRequest::finished, setBakingEnabledRequest, [deferred](SetBakingEnabledRequest* request) { Q_ASSERT(QThread::currentThread() == request->thread()); // we are now on the "Resource Manager" thread diff --git a/libraries/shared/src/shared/MiniPromises.h b/libraries/shared/src/shared/MiniPromises.h index 5983f135b7..30b57ad7b8 100644 --- a/libraries/shared/src/shared/MiniPromises.h +++ b/libraries/shared/src/shared/MiniPromises.h @@ -103,7 +103,7 @@ public: return self(); } Promise fail(ErrorFunction errorOnly) { - return fail([this, errorOnly](QString error, QVariantMap result) { + return fail([errorOnly](QString error, QVariantMap result) { errorOnly(error); }); } @@ -122,7 +122,7 @@ public: } Promise then(SuccessFunction successOnly) { - return then([this, successOnly](QString error, QVariantMap result) { + return then([successOnly](QString error, QVariantMap result) { successOnly(result); }); } diff --git a/tools/ktx-tool/src/main.cpp b/tools/ktx-tool/src/main.cpp index f0996523b3..1ef03ba80b 100644 --- a/tools/ktx-tool/src/main.cpp +++ b/tools/ktx-tool/src/main.cpp @@ -70,13 +70,6 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt std::cout << message.toStdString() << std::endl; } -static inline glm::uvec2 evalMipDimension(uint32_t mipLevel, const glm::uvec2& dims) { - return glm::uvec2{ - std::max(dims.x >> mipLevel, 1U), - std::max(dims.y >> mipLevel, 1U), - }; -} - void processKtxFile(const QFileInfo& inputFileInfo) { const QString inputFileName = inputFileInfo.absoluteFilePath(); const QString compressedFileName = DEST_FOLDER.absoluteFilePath(inputFileInfo.fileName()); From 1dfdc0ce1b8ce3f3d37ebf12a03080a7b408f811 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Tue, 27 Feb 2018 16:25:04 -0300 Subject: [PATCH 37/61] Hide the selection cursor (android only) --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 32b68cd696..23a63c8f2a 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -1157,7 +1157,14 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even if (_quickWindow && _quickWindow->activeFocusItem()) { event->ignore(); if (QCoreApplication::sendEvent(_quickWindow->activeFocusItem(), event)) { - return event->isAccepted(); + bool eventAccepted = event->isAccepted(); + QInputMethodQueryEvent* imqEvent = static_cast(event); + // this block disables the selection cursor in android which appears in + // the top-left corner of the screen + if (imqEvent->queries() & Qt::ImEnabled) { + imqEvent->setValue(Qt::ImEnabled, QVariant(false)); + } + return eventAccepted; } return false; } From 428f4b7b9d625f2af340fc10a38acbe8ce6dbe38 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Tue, 27 Feb 2018 21:24:21 -0300 Subject: [PATCH 38/61] Android - Make the virtual pad (joystick) position fixed. Change assets. --- interface/resources/images/analog_stick.png | Bin 2713 -> 5098 bytes .../resources/images/analog_stick_base.png | Bin 2020 -> 11853 bytes .../Basic2DWindowOpenGLDisplayPlugin.cpp | 13 ++++- .../Basic2DWindowOpenGLDisplayPlugin.h | 1 + .../src/display-plugins/CompositorHelper.cpp | 5 +- .../src/display-plugins/CompositorHelper.h | 2 +- .../TouchscreenVirtualPadDevice.cpp | 52 +++++++++++++----- .../TouchscreenVirtualPadDevice.h | 6 ++ 8 files changed, 59 insertions(+), 20 deletions(-) diff --git a/interface/resources/images/analog_stick.png b/interface/resources/images/analog_stick.png index e9457c730798ae0a77d6b50c2de30494515b3c61..238c2c74f44532e9561d63dba428bcbaecbdfd9c 100644 GIT binary patch literal 5098 zcmeHL`#03v`+weVgNZOY!cojPI$d0%t5ab{LN2*iPLe?+j!W*Bm{G^&AUdT?C6tg( zH+ONEsg%Moxs+TQw~83I3^SOS_jlFj`@?6g&o7@p;PYB*uf6tq*0Z1eJo~lxdhPv( zgPo#42w@9OI6y4+Vfx|he}@vQZF z9L&@g?mbz4wRz*JvblCHn`^?}vwmeDO!Kw>)tQ@EF#`X?e}lbcv-pA&_V)HOT^{zG z`Iak>qV&c3t-J-}eqO}vW2~=;IY`FJU3I68&JchuP7~g`n}5ek+$Em;W$lXQ0g^yV zGFhgGrd56xLg>B-MC_LTv#YFb)lq;~jZp(|cBP&$Idp0fAyy zUSSD##==-sttG*9GXxa6Pw)!g#|TBsM-u?<%wgw8BB$3#v$GvBs>(%%A$0D1|>0Ll<6ln zD$4SF(MJ#1CrttRR#_U4M+<73%W}N0C6>;BarYIkHi8g8bJVLUK-xz_?Mc z;?_i)nM-F9gVx^H6f`Y9UDq#d3iN>y;=EAhAA$VL6MOT78!~704d)ta|1?0Kl`qBa z8)h_x)mEDT4*Z8aPmcrT!)d@1OwufmY z`J1yhVuSc!L7!fX(rEId*sdDz?F{4-%h}RfQ?4%p`1Bp zUp3CuT+NGj3H|-PPRXis04e5yD#j{WIUml(FU}2kw-m8=NhsDmoKgaWzNB2>TB~d( zj#nT5A*nf{<`GRf-lITCb_*@+H31K8kA`@=KGGQd%x##knEkT_>V;OOpiHP(k91$5*c%Bbn68i9>GI_0JFKjp1J+F(fHW9`~dF9@sYcpnt*_| zp1gbDd__dtDLE7}DoMG;=L&j)cNYAvb5vFfDC!MQ?bU_j0b!!UXT@c^hi;!Iih2(M z3K{$yno5}XNK#L)y!FiTKb#UCygOpN2NM4^79^RapBL}tI{8}QAMSebB9JvaGa2KIB(!)M^H#IIhA%zKfTA)mp4lUGf+1 z>Q@oNbP^7t>lu8usOWSD@rh9Dd8R zkyY$^$<)QGVNbfZSH%&4Q8i#jJI;Gf2$BlolfWTjhI~Xc#$924;J>WS+aQsF9;k2q zH7fK{9~lqhBCKGIPPt~364lUQMH->|$6;rztlRy^-TK9<(Mr^uJu)E^#S|Ry#I(Qp z!Tm(klV%&rDKT{D7em{>BhF~!F`Id|5LH$bdJ2_exNFkL;~r>aqOB^K8d*2FBm#s!XKk2Yjs5 zZkjK@9A|$~=7R#Skq)f8A9a7*j(~#2gE|gKCVK`Xn&eJ98`{ zKb>~B*PT5hi-!!$y%??cYyUr(b4Byj!5Z5cIXtwL^NAWpCceL*)Nj|Wm7j6`6IWdg zV-x=?y$KH_C{Pfaj9sf($s1fp0M!fm#}e{~X~jdg#`sb=uqa$mretNV^6SsMDM<&` zZ`ZI>?Njf!0uCmw#M~*}0>wj~1$=27OjNq+M&_Y?+wjm`IwfSPgY9c?_KX4^KYfXm zQi0X|QRuZYH0Std?xMedh|o{}s;gY~xO9r+s|DS60^>dueIsiIy1}v-xohfQVrk4I zlE5I=V|!!IPS_`cp5ibdy2R%ET(xG^Af?N7R~X&!ZvI0LCuhgL3Qp@R|xxNF}xpF7_=)3zD3#zkYe zj;aO>4{e9rM@j^r0`$OaFPke`C$}qzLTOutxTL97Tv5k1!iiI%uWMizU=MV9r)r1`2scx>Qm>3R`1l-!q*$yYGc-jU>|8H}K%>?X>#-A; zLd&pE@m$ACj>1CG$LXcPT}Q-Pz`9|HjO6(KA?eI?RiLzv5T`!ppyY|Z3p6~;dTWxZ zZ9Z+qXUMwUmoB)_+MN(O(7%`hFxB*|bb#Z0UpmB-K<-@0TD-Jxh8dtMGz0p(LMRKl z*CafhyC!<#kFUui#Hl+6sDGEuDj@K6KZT30)t@cYmH8O=g4uMN8Is?phlh)$O)eDO ziDg~f?1d5R$?L(H;Bg`XGMQ+T!^Gi4;=ai*8LTBNm-- zFZJNE4HfH}e4GL|Wb!ZkAhtd<-(-T>q>BkaHEO88G%qkrj@s0*d*nEFDaX{j13TG4 zM8S3+u4&|o|F9J@KoQaWPq-%+C^C@ z@&9a;7N}P&)p+bn zB9A-zq}c!~Z>Ci)B@kffkym$5HY?!8cx!I*t*#33o3L@2WT7e0kIFjp_Iq0oout!* zo)1_Xp0m<#4>k{o1Ez0~Q-lwm0|Md-*NB*w0k=S>j=pZ!N+-s#B7-WmS&tW|FOYz; zs}RAI5R$U|%X3xr+qNFJk=6Fr92{nU!i%eT%cekom!$W(R9{L%PVi`C@!~U6+_@AJ z<*K5jxEZHg9>vW33~n!DQW}A@wGAeAg*wCA*0NG~W3AZKgUsuX+_V%Vu}|1;Upr46 z0%_8T+YZUjMkTM90=@k_rN^*yE;7gqhd`_XT4q8jmb#i}F>||wXeJ8y_6#QAloBXF z=bWc-qq36Dy~Ag#gb8boES?AOmPebn;B#Zudf%1K)>lg7;O<8J>WJP$Q^&93P_W&& zdi}$C^$A^J*}j3Kp}LaBoW4b*b6J`1dB%R>&9c$j@NSee@$c(|W>?*9NX@lJgJ literal 2713 zcmb7GZBSI#8Gg>$ySsOn1@6knZt6Ph;z!gX(WXPT2@@6u1T-p2A~6uS8UbyVdW|;0 z#=zktIF3m$(KNBpiutn5hio(L4pRso(lXXIp_w$JYwgqv7^k+j1A%EYFxa_w*|3DB zNq+2{+2?)F^PcTx1aM5|)z>wEqHKJs`$-}~ zxiIlmZg@@0)7HT~7a8El z%F%i3RF6pP;k3JH*_2xCx(#w--@`hMUSY`W@mcE3cp=L>zm{OwRBq5%%pPB1FXbP{ z4@l+UI~vZT2keh2?JIh~cGFH$OSBz(MA+==wP)WgfivazSqFOO@ff7nD@(E=@8B1j z4ZW0i`QF*{k8hJ6sGpdtlLfR0?GJX{uws}j82DwUFhVujof4c@C1{6JOd;N35jKPR z=0dC#+3g#WrjnQ)KRRB2Ge>9V$!;hrX=C8oX1{^L>f$B~T$w0c1Vx4a zIq+;lU>$|o##dY5N<-;lZJ60hCVw)8*%EkAgv-raJQ~{3PW-n}-arC7MVO5|7)B2h zzl-ud1b!&OO!*ayrh|@V;y(^f5NOaVFRei7Qj8el?LF1m_DLQx8PzJYBUB;P-Jx>c(1O#eydy@W_caK`*fBQRDMW@jxIxRvkpB= z2ciZyx=fAio@@UX0)a z`T-zeYvwW%@<+0c4llFtM`NNK;Ku#~g8bV^{i0`1E<|a1lu=wB`>CC+b3~cQCpS)s zJQ&RZ2J!L>x$yVQHX7!u`<}qheIXSPeDrjZRUV5}o#RO_Hr2;l<%utif0dohv5x=a zDzid!&61^UNFnTB(G8g8qVn>o3Lv8*((f7feD3;NMJT;(cDnn;iZ~J&{es^$-dJqM z#pt$wG}xVrw%N#CQLl!*ow-`3!R=5 zfJg%g39RPxY1$sy-8^<#kPn5Y=~iUiuMcVil^>715~;5^k-eX!kLN20J)m!_w6dqe z(9aRttV6F_Sa!~9#dXJa|0Kn>Ll;57?ePLwXu z(ML>vCxuzmEn^X{(#=6Lk|YXqOkks^nM{TUuJ59)S$7{h<$Z=gwy4SJZfcB^9~Tgp z%HFrbdlqz9k>B6V)!l8qi)NpoJ>0 zS=0(LvUBBR3{gghjWAGew+Nd>eQ(~`5==f?w0|+u>v|x|s7@g41Zgi!y>4Z@%x6ld zPHqyF|44AA@?#IJ>7{C?`D`R$Re~dwo!7o*4%i&3ZP18L!VaYnCc%-_-d_TzSIHQm zC^zu_R=|VwIsqb4MvI#+5x%nV`0gIC^H4??!Y67Qk%O{H5fW90^1&qDA5U>=e%UIv zHbp?WQU9;8Nch$K@6SRzsrq3)SP3bcbc4Tv^d}^^P0H0Ku=S27-O6AS*cHb?r-s1s zln%ggczQj$RJowx$EMf6o%r?D`a9h4IVa`Vn`4F}U9GG3Tk*krLknk#`tu9TEOYp> v3)MGFpE0Me#XgfhV^04In{&JKo>|KXOnYOW8Mq_81^^24*5{teksJRDyY64- diff --git a/interface/resources/images/analog_stick_base.png b/interface/resources/images/analog_stick_base.png index 3b7b8aa8a9a6d8a83847680423a18d86ff182b84..ac8c1b9ae8baa098468a38411a5270fd17e3b187 100644 GIT binary patch literal 11853 zcmZX4c|27A7x%d{V{9WrB4ws+O2i;bB{LE#v}hyA*els0B+L~>qO>Ae65lAH6e1Zl zmLf}uWFHkFOQDIGxzB6-p69P;?rZ)z=e*zVbI#{;?|t2S&*go4EM=sYNdbV&uAMt< z0dOGtOArBII;3q508|3a?E(+@dISbLpK%9MH(wWb$}VqbPj_2)XSZ|y@7#?6Hcsr? zVR|s+>sSx{;Bv#iwNn@WjQS;b9Wz@ovaf1-{Ab#hykA?Ur>9@(=k4-7bs+U?oAAkU z?`PTr%>~&htvfR&HZLFJXjbS2PaBt)mmk#xU<8kq5g6fNm@wS;-!DhL7w=E?S8Ne0 z;?J<y5LP`-k6lRMcPv4X(znlWQZY9PVCd){L zV5DBCBG(8X@*H=Qo1cF5p7i9s-bDDTC8-R|^kV*G&I#GP=()($$(&3%66`A+CKrDA z{j19I2`e!}EpcVYT+}MtmouxQB-={jzayat#0p#T$(%p`S{tXQj?Q%480~m^ zmHX=f#xMIc(E2sw{DuNIA{zi77hzXNzwGqnvhY;l+}yj+QZtEvgulP?-Xxi% zs$KXt=`KP8MtVrJz3^vNg1&$W(@8wzFV;dJAdnbh=Xs0mDV}8-yygtRopKPi! zlk<7dEbUa2)G>2CiUttDX3=|Rim;hm_{QXd?4|y`Xzyt3&~hmvJR!Ya=U?m8m3h93 z$}=QXZ8h_I#d!TRwY)t*f=5cizx(-K%9<}c%=5k!Jedis zmpG=2V*-PB*<@}LJ|2`Ia3kMz45Q2?*OU0Kk|T~tuLdIYNMP5beqPiMZ=15tKSlhn z_vaf46k*(a!yI4;%3{ve)074wK7L!`-q3&aKmYpL^Mib)yV#pzgV~@rUA+9wUO)n>#^fiiVtVDz zqaGTH1UwU#g{L`fkPn%&Uw;0lO*kl{d&E-{$1xh0xq8N~uklaMSJvDrg#(|9H~+9b zM*BXLZbO7$vRbB-%}RsbHmmqEJ=oBl^Vt{Y4RH6BhTaG~q2&j9W|{acosWX(s@L=6 z^0x5M@4^^OcH!0C_byiH$Y5+%w3DX1(S%6KFV%H!pSjdu*T3SA^!EjhRCU>#VL^xZMA(`B)X)aBx{UJ{e`J*ab zYgBo_07V#UqXfSA=DA<86At_o^j}T2@~_IbA(Q)!X^{M5C5ue{eP2R$_F^D;$`j|I zs^Dx-)08H?6yw=$btb}K`FtNSELR`DQfSR^n9>PUD5^-7NnGm&wEigL!28W-@69-L ztrj``pDnGsdJ}Qo9!bNaDkiT!3OE^(!>c_m9ao}VX2QOZMDnBCg{w_3(-m4g`J{7- zWryF8K*~7VxfXNIOsYzd%{#l5+f0~Nv7Glm<8QR@n4LTm5+|99Qhp!#X30NtY-yYh zmD#JK?{+4gBkSX0Zhr`xRJw)@%&3@2Ba`Ty zG@jY=$(iwWLe>@RtCt=^BkDl%WVN(9w({%0OD}}iJOms}eaaIzX>CB6UZ#>|z!;N?YIdxyzUZx0%qN5~BRbfNi@5k0KrOXMd~`I$WkJpq^ak+@=R3IAyeeoPWRl zYxb8|)(xH>60(wd$>{tJN5Hpyf2(Ng<$2Mm-M)uIci^YMD>(&A9qR53lh6Vuz_&D* zDXL|DoS%P^w;1E%H5AZwE-txub4K06?p3@YF&bo>KAZ(8hvu$gH#+k_V;WskGFYxwKh1Nj5JNacL z8v?b3%jV^=QJ2z1t%tyM!uI*gtQUH# zsZhwV{8{Lb$PY?Ox(x}(u^ z5&nv@y1jM{fd<7&teAgt7?qPD$yU;_Jre^8Y-qIQ>z7f4HnkE8=wjDsNhWx#6_)&4 zjQx;VrGUz~X15ubQc)!NB2Tq3mi0+Qm^E}sk_oZ&Sh@mGA+=~!-ncvRsV$)L^ap#mmtSm+WuP9;<2S0*B0TqJrM#>*OB=Oe*^f;EO(!F7l#y zddP{lgnPCAE1DgBlQK_)-ry;)xb)sX9-A|Jl+|A@&z!nTVi!jS?ckg8-El3asr_cl zhpK_^#l&v^5B`qAC7!nkTq0 z1c#YS*~sbrjKwUjwgPIZhme>4`*7i~&a$m*jWTxz=AhK9)Y^iKCr}kM=Lw zQOAxl5jjO3nXvYePizd^fqKhBx)QwJ=}M9knM zNG%aODVhKIyW=%Gnz~wDCM}jFp!OdxF3{q-p7mjjhx8oU&kP`D?rSAaOr6TtlPG*L7K@>cZ3F z13tkIt)kACM&m7yZ=i-!gojelB#%(Tsfes*UVV?+7xRZ~kE?jCw%VDaHS{}A1E2F} z|NI{Pwc7M$iRQu2;a{&@VpaNSDDnkQU+v9sygxoTX!awz=wHdiRv8(>%OUf=jrsF< zh86L;)+>gF6}%i3(wkDLLTITUn=PE;53VX)U-UB+?Nmj#j|wwRFTtTdtl8m>xNj|| zx3TkO*uVc9Tk7YT)Gm!=+AGM_{_W0U7v~z180P$vdX2e?%Ux9fzwV;6rlIH3y;nlt z!a?16S?`E|c7fTcoi%iruKu^`$>302RC|+jat;#fAUxw6okfS?b<#x}q#6gpt)5)) z^aO7E)$W7wdsxttA-TR)eX{iMQL$znyqt${bB(g$*C-sLluC)mHqXHP6+USbK9M#r zyW;B}z2k4n=|Cw}>)$l87*D&wi@9YrzPM_rU4UfHYqHHE-}T45)D~-0$0w%FmG+UL zNEdl2Ks>4xY0~(8lo^(16&?DoOG=a{9*{E`%|SD{v-_0|AHK;ZA|NXEV#syGq&-7)XRuwzk-q6X(N7m& z^h){uc3sb|j5azjtDmoltTe`zo^Y>9b93(azvQX;JzN5)jR6&>j z9n5tCcAGugt+wfq8)BgkDaF`%O92ix=pd%oY?B^5uE)ivA@z3!(wl){-nd1Yb{DC? zC+O4aX-}}j!@*l(66JwgJ2ctJDro+ls_incZ)LIfV&gbuJ#D^YS{(MdD)s+4Rt&E0 z&?rRU87y%}h=$;S0obE+&%o6U&NP`C%!|YGbTOk8u8iy{(A~?|n-_=aM6u*=+3fpz zuz8&@MSzFUdYttc+x`|J`zsw7N=&25{ALKlgxkWB+ujh1S-{w9j|y^AZQLMVfCo3^ zQpbl-68mG#@{Lt1k{2unKPV$Z`Feou;=epELg4MuwwpLiuYF$A2VBgeT#H$NYO>px zU;C_lB9_D$Symfv?4$zdOHZUg?-@K$#4mCN+diWyad^JtQ9*(&$*v7J8%gR3EVVmM zM_k09MefM{z7lue_>GY{dXVSK^YHW>GR+4#x^m>}hx*VhuMxZQ+eN=7Xj64dFa(aS zIn=i(MvJJKg4Ca!Kd)^8Amf2tczvi-IhTlM{vtz*Zr&EdVO_>zeByro(h^}$tPC*T z+M}5P>M7%5%|QK90-$OnHnRp@s|$JFEMG+ofl$hbf!Wmj+N*LEEO^W{m3tbe4zMag!b@qYt7pt_#J1 znUI%+l<0y=C3cw(;6DAdz7x7Uz}7Klnhx-NT4$>??GlnG6o-CE-D!Vg{G?$1Z{pnE zU7N##t{@O{M^V8~?(Df+B=&ypgeWZY)gHC){Eyxw#>g!FCkx>HsN3NqqHP%*is50> zc>lTsS0&U;7KkRTY|AmniWdN+tfcdsyAZ<NJy7+p10W9^Q|O+fX3Cm6c{zFC|efw)6;eZ8>>7s zn2#l~l(*9_7S}jA7|yl}&*utX9pA#XIwHxyyY|d~FTGjwb@A^8Ov$5c<%jT|}`-pI`Si&w;fjaD}hEU_G z-W?}kK6;vHlw!ck0nwGdhqtl7&{&Vs|wpr0i6($cFu zJSZgE#HA}WKz4WZcn2mOS9SP3{ID1=t08>*c``zVVIdaUp@LrEl0VWrxMX%?+10_N z3N#xcQ$x_Z(P-W&&C{Cyr**9~dn|Ua-8?dBq?h0}{Ij+rKN}e~5IEWKo0ANC$H?qs z7d7IYhO8NjiH^jOCRh(^guo_PH)LK!*Xlt}j%bI{5d4j-$3Ioj_$%Fqh^Q#Lea=Lt z>k8He{G`E@Met38B0|Oc{jxoKcJ+$B54*_utu_c{N*t)n9YhU6*n7yH2HtM|0$a_l z){cb0u)ir+DmH$2_&)^&zl@OZ8zgiEaLAC1Zc+A>WG@1)ELbxRkxCT${fU&b;*6W# zUJDEgP7e=;haYMVKJbxv?Zg>z5GiHK6YYs1r(sqhVpqUch!rKifL&w|ySA^dEkQIyqglF-;I-_o8l}0T??LGdNi!NZ3 zB{9rZqE-c-`Pu7p3T%@PsWL@OY-<~af2E@##CQl7GVm~3u8XH#3HTpW&k(7Z2{M%W zcAT4#D_p+N7k0M|<5BPH?1{%Dc7;+@v?$3IJ1Wzmx6%V_bIT!d!ICVw{!vAR7rD1_ zp^O%#LM>#|pU8zaTC@9>zY+zHD>4@9c}vaA9Um__^Jl@Wi*%`?_N<*;SzzMQzkObd z8cJ#(HJ2614|53F!{ezPB(|NeNIDsn3JfmM7p-2)NouAOp20`JnxTTHrQU?gbU-D) zB)?s$3lA~~JNXE#NJX>CD^mS+EH~oT2mwvEVVvwqGnWx9Bn@%T>jgO$fI>@(XlDU6 zQ}6%sc@mlD7XQ6W2j(RzGXtp~+%_c+jV**%p77BV8^EQ@v4BmoVee|wAyOiPIb@)@ zDopw;$_Os4J|AMkM?i&|DJ^rd6{4pbF4Kr`+N$lE)~0L={A3Q>D~yQ)kmO?bgLfxEA4#1JIMloa#)} zOKV6B8WL;`z_j493?DW-&1eA?fWhCo39JE7UhpYM27sx;dWa9_E>-{-w&z=o`s^Y0 zKUoO4X0gA=Q3dUK*}a1b&~l&m@XXd7L{t($4olJPdW$Z=GiqUMui!@t0K<|?-?_NI zbn`NiP)lng-8{Ie(gQrw+C>#5Tw!epE>uA~-x2_()(KN@y28~33UWeLc^5|>6aYAV zjo7Z^j<}E$>dMIg6d?z54{x@|8M)yAIIK-^BjfKO?4*v-f-|j&zqIh@ypQ7h7>;U@ z)BHM59H6{rNB)7C*|p)#Jw#s6qUtvyxr~2}Rb{;es%Y1ps7sOnT>62jz2Acl;1k~r z+$$i6lv)3AosRi-$gn%qF2ssL`rhTtm**j6dqbx1R8iSnx{S z5u@Zkx1ASsqi-!k6J*$>(M$VM&nN02z~HNX@3J6LW^fyQ+giH|DP1o_HV&L`!ZiTp=X!el5Ev7mylj%sopDK)n)X9i+BX0b*J1*~4RxLyxb*PnNu3 zx``x@?1*dfNkewN^o!X@T)V(7ZyPxK*=xUxB&C~EsZ?mRP#Smi)}z9%jfmSZcJLFT z`hsoyjp?&Dy`H7sFbKI2btmffLV=5;vat+3P+t|?6566Gs$dBeHx}o?|WA5Q|mLN>a|QW1DIRM=dbDd13YWv*`M&;%_zJxYzW< z0x-Ec2#k}EFGk^$u~EGjQWrug>gDBAXG5DH>^j0+=%g0D=xIb!BP^d?Hnu>IDCa}b zb7c6DoF7xcul>|{cd)s_QZ8+ZWnK45dGzock$J9_zD~#u-X_j6RghC#We*TAxaO)8 zhn~@fV<*g%#gNAMTmDygNuOGERnQPU+vw4j zN(~pB&~FABJZAbVKC+uG$#|i~fjzXP@#7 z2k!4Pl3*4L9@}XivjYWbm?1sOsraJe;((jHOVfA&CbP%7 z$KZ9vK$VsM(h&eqK5TfPcv@8zRSbTb;h(Mp&?7f*h4pwN4d9~6`FW=}gr_$Z{AG~@FwUj%^@frbr6Cgh zZ@oC!cWhnVJKzLeRriw71%O+h-&J($xdoN-|L*#HsjrIVi33>w@S5Svs`J6wPA60V z&@*#J1xRd{jIHgW1xRb%y!^v=<5a$N+~}8L5&)aN!_m5P1M2|y??Yv@?e*I`2ta*D zO_zLCm=|7duekM3sr7gOM!J@X+r5veX^4a!5rA?%?-RC}NO>{e((JPp;9V%sGtV&5 z4bI#_?#TcQhs}}${XR~!_7EwFb5u<{K&Z#FAM_j&;du66)=v_nf5X(!Gy!0G$D?sanJJIm%ILRWXdHq-TB9(k_s~;8VKVZivs2Ov z^28PHNk{`jJbR?armb^>9z>2_*Oma-ri{{KLe0!c?2l;#eBwt1h7JWXPwK{DYFV$_ zy+F4ZLU8~`|GQg>nW>;{8*0pIP(Up_G1I<9mhGSYWf&eh{pX!=a3b+wc*TlGJl|Ln zgYr@@)Aa%Z2_J+9t_eQ0emY5FSm-dzcAi22Hu^7{@pd3?6sm5(Ck`GxElF5-m~>2- z`f-T{dA`P{B}KP};&mhTry}QPlqa5+A+hGtdEU}X@HjY1In?ZPNlU1zi;~{Kp5N=uzxg2JtTLK&{@*M9ozTGhngGnEY^4`{=7M{LNbI*w#2aD&jsCOb>BsMD z=?_%UvWqLvt}s&qpjq0^j7G#iVY#{kE{|-X1kmzn3=19myY)FD@iRV#lW|)NV4611 zvWvebBzKGM;orj6+XFCUi?PSKNjC0)+k8?+WN0YHY7~pH{UpZe6PZc?%vp@H=3HDS zW~YL(b2I_iV^z5(?YdHM%ss&3*z@1YtW zv5A$B&5OJv0gbGom(Gqot8La7y-CU{T03blRTuEr1qYMMHeY0w?jKS{k?!jk7{K0F zjAd$Xc08f&B{+RZ8O_-`_iCr_qUVWX03@UNz2CQtsN#zvt#&_2B#A|a;sJIy38MBCbdmpZt1nh1~`#~M$^QtwJ*r<#HA=H#wCvB-fR z;c~Tr5==Bd9>5Nz%^F(a<)qi0Y2SM_No(A0IUY)q1>!yRtydeqN@G6~5eX_~Oros8 z-~SE{KsAo#Gt1K&X+Qnt311*cpDG^k5K{9IP@U{rwQVNj@evYR!5&RS>irJ}i2)o> z6$~8~IGIs*HJyqp7dL_8d>;|Hb8WuzhNixlOG^yMIy zb@`Hiv5lZv2fxonoyodyMSA9nSP9l(n9 zLFfB#oj>kPcTD~I_XAqMp~ugArfC21AJ4-!d%|Iv3ujh*@f|@RQ*}!F>017ot1_&+ zy3k4>;1dH@x8Z?7|5h;HXWn!2Qcp@1R-~ACGj4M`8Q^Y)AjaRsv!{ylQ4hb*NLnsV z=S=f)k>~3YjKY7ZP2mO>`<#yQ&~i5eY0-I)<~aWkC&h+IYv4+OoW8Hzx?q0Xk zzwF*;qM5F(B!z!t{`eNEb;wJ7Pi z!B5=py9dZb)3AfC(@yVaFU}7uPeu%`KEf|NPn)ZdiTJNO6h-$$hBql2R1R6Qr@2*< zF<&Esmy*|R5$IQr_dQ2q)vNlJo)aK%8o4*K*acq>x1^xuH7qfF%ib`)a_Q1@XPNZr z2T3^(l=R^7;p&$)Vb%;f-tx({BGzCxMCT~Tvux|zbbda-gnAu+So<*)};u~Hz zJ6>MvO3eINUAbdFlRe8WQNKRtiW`x~Z2vBqsogow$$y+xrKSftaX6Vt?|}X6HF4L= zIhb?nyC5x{8;$3hRkC`Ho1D-bU+;{YmN=nj67gK%hPx||Ii1Cw*0tC@Hsf@e)uEEr zlWubQ{+`Ikzap&}=coMZ2%FXl+l5_pdlQxV;uIxtZ$1x zT)%dOpN42CWWJM7U=!q6B-PdP7de>LRc!b(aL!g=6C?7-LpGyI^#l7h&3oM`1><>8Fl_@*Xj(CGI^PSrHQ9b>09hRw6c(xKEipb zW7zZN)5f(S29&qxAs42>i5IG?PvK(eBcWGgt4NH++vjpQ%m>~@){LYS;9k34gZT_h zTdJTJs_oC%yr+1`jZzgDe4R*MS9lE^^u=i%{BK#~(FOk6dX*_p2-QPAH2xMf&RTgj zCj&`-B3X8f_$x=Ff$-b~7fUyYz5chscj7V~&nD#Bx#O1UEabK`FYOQ~136Jk=;oLn zr|2QYn?&~bl$9n|7h)w&P%{@RF!;{-ZV)Onwy);sh8%Zr!+E&lV(Av~0(9*GVrDr- z`(=T9YG$OLlBoSry!9_WT;u6MPcn+Gz*#e1P*L9CZQgqOpL_W#s68Rvuj1j_C=(BS z{#hO5vuI(Kx;&VEcB21%UIdAKObxvuqlI(!DhdQ z=5#oUOcZ^^Q@iu_jrNKliDNI{ShM9s5h-O7Thp4Ps>ZzUwaKxFnVsSf0}D}fEkeyK zlcWekJXRgp@||2%mw^obSh=CnjN(TY4>Q-ZW|WA$tEg99tjCr{oV+b0F@j}3`G+OX zN>x2~#91@i!HPe%!}?aiZ>O4=-7I3}sHrf?ypzjDYfY^gH$-SfS+h;E_6hr|uE-KI z|B9c^)qfF_EVGYNPdM#{i>0g8yghkuCaKBxk-ZB{4m+!^s!`f!-#~aJ+H`6*yDxot z`rOVg%MB*Sq6`l@vdxzBe2=+P`=3fugrY%_T+d8$mKKFFQ%m4qlcWgkQfFkJDykIq zHUqOE=IONm-BJ9DuRx{vIj*mb#a_9d%6%a`6u-IY9>RDNbxuBkEhqcKJMepu)U-D) zmR04ixPfn0GUb<9R#sG%fiQ$jdfN>~$j(B=?=*x{Rl$?g6Ml;1TE5Rf7}YUn>(@qp z#-G2xQe1(-Pra7%!066$(zHf4Uj<0hlZ#%i=^t>%#a8XwvB!GnKRr<9nW{a~>zIqm z-$5&q)TC7MSdX_hJw&)+Be+31Aeeu*ZVAcy^{<+S`1)@*kr6XE8fxs|F#^!~z^ zS7kQ`_mxUggnuqa35+%ysZ4fs*V$KvFo8Dk_VrTo?59Z22yTchtRFv23scDxp zAM7NY*IqY2bpZn6$M~a034Hrl-_koyCydWK3nQDk| zs)X}l%P+E6{Z8)f&A>3|XO$&HT~IMSPepkhSiE>K%V@GtchnOos%(is(J~Ggj(S2% zERa6$PF{SXnIOk{Q+Qh&kJb_s@25u6aDPOsz5^YEc!cpbYFDnLgqT^~YQb)c%-8c+ zx6n_ZHn&8`SU+6phpE7{PFei^HT4p0=P)y+e$gzLOIoSJz>#m_#LQ3C9`&nDGgMD& z%`67tjAr_d0dm8wty0TLXr$+@lKXpAB1bPaT^OG4bT~V{Rb@YKsdU3OCQP27E!#R% zcK2epa(qkP&qXhcT-63ot1lwK@#Xhw_m~&R?m1E}oi*S&YShG&wG@87)5`|tJ&C#nJVcPTJe^i zI?aa67EO<_?bUVmk*P+R@1!z+41L=aClv1RHH#!G!={r2T(EyofNM~cRQl!0^*mFa zEHz9cnoNRn9o&_RYjM_pN!BUcb$lkUC3YO{lEmDIw4!0`xiV{BZ9p6k7N`oNE^9BZ z8Zu9s|7gxTK@5-Dld=vxHwsUvFp8QRt9Qt+ z@mk-zHEt?&U#r6>T~!izY%43!#fjgpd_gO_bSJm;8NR3Kx9o$-i6gU06IsKf-Qq;B zA(cC43YxRhpN|}f8h%U~sn>@_aLQWA%es{L$Vdu@Y1Ot?ycc8Dcq@jVjG)1=iAK?eW!RJDyQtD(i<#pOQ>*QZi z2$a-I<%i}^7*1YqPcW@lG+sYDS78*W-84L;H9ZS9Ln$>s9N~a1n_RIeLZNu;VT6rvoSGZ9;5`p(uc6&duuQQMwwQ$z|6n0uZ zZdr`w_SY_~sj8He2QTR4pg^bR=|nux@RT{x?5{I%(F2t)!RGst=hx4b?jVb1ZdHt8 zEhu3t%2w_CrWGel&=02po8QQ&Cq~cw%-{xFiG^HE{3<)MWMI0!`O)8M0B;ZR!%tjV z4NLb=fB0Pukfw6sP!Q9{@q6MrUg;bSNHFZg_NqrsvMk{#4_O+pyW^`L z<%|y+lvfs?@_ZFxCx2fw6nrvZ(&K}i@!60)(){qU*1KO~3VnB|F#(Ld<=@!8so-_g zHArdTpEf1d4$QXpRn>IP#T_a)k&ByD>o$e|@0Y2FX|o|QnZAb@w$)bT-etaLN5OXH Gh5rLpcxJKy literal 2020 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelajGNS3%plmzFem6RtIr7}3C zG&JWf&Pa7#JMDHZce=Ff=eQFt9K%C@?TEFftI3B2hWQ5~55; zC`Y&nn;3>W9pux$F|XL#_hZKC6^whXRnpAK=VIS!B6HJr*%Iv2A8;N>U|h3fwJqllwgXT36Y`ZAcmx~% z_A(gQFnrqq3Z#ZCmIHR;3~j6o)v*i`LJV)p!2wpv(O|0&3cUqfj2qswLW9zvX?-)p zn_8qGeei$Jf94zinMe+GXc!P1Nf<#k+@c$iI#5%>XaIo<5IlKwG=N4(0I6M+VQlyd zE|j1}y3XPE3`oV1&S_(YhFW;3^&DJkT~TECwwu8~h2h3)rUM%o66SM*>WLL@3~ve< z6Dk-s>}PFIWIAx~-GdUA_3bZTny?lVZ}F}z7 +#include #include #include #include @@ -25,10 +26,14 @@ static const QString FULLSCREEN = "Fullscreen"; void Basic2DWindowOpenGLDisplayPlugin::customizeContext() { auto iconPath = PathUtils::resourcesPath() + "images/analog_stick.png"; auto image = QImage(iconPath); + qreal dpi = getFullscreenTarget()->physicalDotsPerInch(); + _virtualPadPixelSize = dpi * 512 / 534; // 534 dpi for Pixel XL and Mate 9 Pro + if (image.format() != QImage::Format_ARGB32) { image = image.convertToFormat(QImage::Format_ARGB32); } if ((image.width() > 0) && (image.height() > 0)) { + image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio); _virtualPadStickTexture = gpu::Texture::createStrict( gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), @@ -49,6 +54,8 @@ void Basic2DWindowOpenGLDisplayPlugin::customizeContext() { image = image.convertToFormat(QImage::Format_ARGB32); } if ((image.width() > 0) && (image.height() > 0)) { + image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio); + _virtualPadStickBaseTexture = gpu::Texture::createStrict( gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.width(), image.height(), @@ -91,7 +98,8 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() { auto& virtualPadManager = VirtualPad::Manager::instance(); if(virtualPadManager.getLeftVirtualPad()->isBeingTouched()) { // render stick base - auto stickBaseTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getFirstTouch()); + auto stickBaseTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getFirstTouch(), + _virtualPadPixelSize, _virtualPadPixelSize); render([&](gpu::Batch& batch) { batch.enableStereo(false); batch.setProjectionTransform(mat4()); @@ -103,7 +111,8 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() { batch.draw(gpu::TRIANGLE_STRIP, 4); }); // render stick head - auto stickTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getCurrentTouch()); + auto stickTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getCurrentTouch(), + _virtualPadPixelSize, _virtualPadPixelSize); render([&](gpu::Batch& batch) { batch.enableStereo(false); batch.setProjectionTransform(mat4()); diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index d9b942bd97..04568dcb27 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -44,4 +44,5 @@ private: gpu::TexturePointer _virtualPadStickTexture; gpu::TexturePointer _virtualPadStickBaseTexture; + qreal _virtualPadPixelSize; }; diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp index 74225b5b39..fb53ca253f 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp @@ -458,9 +458,8 @@ glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const return result; } -glm::mat4 CompositorHelper::getPoint2DTransform(const glm::vec2& point) const { +glm::mat4 CompositorHelper::getPoint2DTransform(const glm::vec2& point, float sizeX, float sizeY) const { glm::mat4 result; - static const float PIXEL_SIZE = 512.0f; const auto canvasSize = vec2(toGlm(_renderingWidget->size()));; QPoint qPoint(point.x,point.y); vec2 position = toGlm(_renderingWidget->mapFromGlobal(qPoint)); @@ -469,7 +468,7 @@ glm::mat4 CompositorHelper::getPoint2DTransform(const glm::vec2& point) const { position -= 1.0; position.y *= -1.0f; - vec2 size = PIXEL_SIZE / canvasSize; + vec2 size = vec2(sizeX / canvasSize.x, sizeY / canvasSize.y); result = glm::scale(glm::translate(glm::mat4(), vec3(position, 0.0f)), vec3(size, 1.0f)); return result; } diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h index 5b65315f45..234818c740 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h @@ -90,7 +90,7 @@ public: glm::vec2 getReticleMaximumPosition() const; glm::mat4 getReticleTransform(const glm::mat4& eyePose = glm::mat4(), const glm::vec3& headPosition = glm::vec3()) const; - glm::mat4 getPoint2DTransform(const glm::vec2& point = glm::vec2()) const; + glm::mat4 getPoint2DTransform(const glm::vec2& point = glm::vec2(), float sizeX = 512.0f, float sizeY = 512.0f) const; ReticleInterface* getReticleInterface() { return _reticleInterface; } diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 53683870df..40bc341fe2 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -22,6 +22,8 @@ #include #include "VirtualPadManager.h" +#include + const char* TouchscreenVirtualPadDevice::NAME = "TouchscreenVirtualPad"; bool TouchscreenVirtualPadDevice::isSupported() const { @@ -37,6 +39,21 @@ bool TouchscreenVirtualPadDevice::isSupported() const { return false; } +void TouchscreenVirtualPadDevice::initFromEvent(const QTouchEvent* event) { + QScreen* eventScreen = event->window()->screen(); + if (_screenDPI != eventScreen->physicalDotsPerInch()) { + _screenWidthCenter = eventScreen->size().width() / 2; + _screenDPIScale.x = (float)eventScreen->physicalDotsPerInchX(); + _screenDPIScale.y = (float)eventScreen->physicalDotsPerInchY(); + _screenDPI = eventScreen->physicalDotsPerInch(); + + _fixedPosition = true; // This should be config + _fixedRadius = _screenDPI * 256 / 534; + qreal margin = _screenDPI * 59 / 534; // 59px is for our 'base' of 534dpi (Pixel XL or Huawei Mate 9 Pro) + _fixedCenterPosition = glm::vec2( _fixedRadius + margin, eventScreen->size().height() - margin - _fixedRadius ); + } +} + float clip(float n, float lower, float upper) { return std::max(lower, std::min(n, upper)); } @@ -132,13 +149,7 @@ void TouchscreenVirtualPadDevice::touchBeginEvent(const QTouchEvent* event) { return; } KeyboardMouseDevice::enableTouch(false); - QScreen* eventScreen = event->window()->screen(); - _screenWidthCenter = eventScreen->size().width() / 2; - if (_screenDPI != eventScreen->physicalDotsPerInch()) { - _screenDPIScale.x = (float)eventScreen->physicalDotsPerInchX(); - _screenDPIScale.y = (float)eventScreen->physicalDotsPerInchY(); - _screenDPI = eventScreen->physicalDotsPerInch(); - } + initFromEvent(event); } void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { @@ -169,14 +180,13 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { bool rightTouchFound = false; for (int i = 0; i < _touchPointCount; ++i) { glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); - if (thisPoint.x < _screenWidthCenter) { + if (_validTouchLeft) { + leftTouchFound = true; + touchLeftUpdate(thisPoint); + } else if (touchLeftBeginPointIsValid(thisPoint)) { if (!leftTouchFound) { leftTouchFound = true; - if (!_validTouchLeft) { - touchLeftBegin(thisPoint); - } else { - touchLeftUpdate(thisPoint); - } + touchLeftBegin(thisPoint); } } else { if (!rightTouchFound) { @@ -197,10 +207,24 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { } } +bool TouchscreenVirtualPadDevice::touchLeftBeginPointIsValid(glm::vec2 touchPoint) { + if (_fixedPosition) { + // inside circle + return pow(touchPoint.x - _fixedCenterPosition.x,2.0) + pow(touchPoint.y - _fixedCenterPosition.y, 2.0) < pow(_fixedRadius, 2.0); + } else { + // left side + return touchPoint.x < _screenWidthCenter; + } +} + void TouchscreenVirtualPadDevice::touchLeftBegin(glm::vec2 touchPoint) { auto& virtualPadManager = VirtualPad::Manager::instance(); if (virtualPadManager.isEnabled()) { - _firstTouchLeftPoint = touchPoint; + if (_fixedPosition) { + _firstTouchLeftPoint = _fixedCenterPosition; + } else { + _firstTouchLeftPoint = touchPoint; + } _validTouchLeft = true; } } diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index fd74009ee8..fd2342bfec 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -74,15 +74,21 @@ protected: int _screenWidthCenter; std::shared_ptr _inputDevice { std::make_shared() }; + bool _fixedPosition; + glm::vec2 _fixedCenterPosition; + qreal _fixedRadius; + void touchLeftBegin(glm::vec2 touchPoint); void touchLeftUpdate(glm::vec2 touchPoint); void touchLeftEnd(); + bool touchLeftBeginPointIsValid(glm::vec2 touchPoint); void touchRightBegin(glm::vec2 touchPoint); void touchRightUpdate(glm::vec2 touchPoint); void touchRightEnd(); // just for debug private: void debugPoints(const QTouchEvent* event, QString who); + void initFromEvent(const QTouchEvent* event); }; From 55d52f92df2e2df7ee2d4169c07bb36baf06b9b1 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Wed, 28 Feb 2018 15:55:50 -0300 Subject: [PATCH 39/61] Android - Make Joystick appear always when possible (not in radar mode and when not hidden by some windows) --- .../resources/qml/hifi/+android/modesbar.qml | 6 ----- .../ControllerScriptingInterface.cpp | 5 ++++ .../scripting/ControllerScriptingInterface.h | 1 + .../Basic2DWindowOpenGLDisplayPlugin.cpp | 2 +- .../TouchscreenVirtualPadDevice.cpp | 27 +++++++++++++++---- .../TouchscreenVirtualPadDevice.h | 2 +- libraries/ui/src/VirtualPadManager.cpp | 16 +++++++++++ libraries/ui/src/VirtualPadManager.h | 6 +++++ scripts/system/+android/goto.js | 4 +-- .../system/+android/touchscreenvirtualpad.js | 1 + 10 files changed, 55 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/hifi/+android/modesbar.qml b/interface/resources/qml/hifi/+android/modesbar.qml index 552ca80778..fe71314ece 100644 --- a/interface/resources/qml/hifi/+android/modesbar.qml +++ b/interface/resources/qml/hifi/+android/modesbar.qml @@ -40,12 +40,6 @@ Item { var keys = Object.keys(properties).forEach(function (key) { button[key] = properties[key]; }); - button.entered.connect(function() { - Controller.setVPadEnabled(false); - }); - button.exited.connect(function() { - Controller.setVPadEnabled(true); - }); return button; } else if( component.status == Component.Error) { console.log("Load button errors " + component.errorString()); diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 95be7b29e9..38d5306a1c 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -89,6 +89,11 @@ void ControllerScriptingInterface::setVPadEnabled(const bool enable) { virtualPadManager.enable(enable); } +void ControllerScriptingInterface::setVPadHidden(const bool hidden) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + virtualPadManager.hide(hidden); +} + void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 1f223814a3..bb5615f996 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -65,6 +65,7 @@ public slots: virtual glm::vec2 getViewportDimensions() const; virtual QVariant getRecommendedHUDRect() const; + virtual void setVPadHidden(bool hidden); // Call it when a window should hide it virtual void setVPadEnabled(bool enable); signals: diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 010572fcf2..85300833d8 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -96,7 +96,7 @@ bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() { void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() { auto& virtualPadManager = VirtualPad::Manager::instance(); - if(virtualPadManager.getLeftVirtualPad()->isBeingTouched()) { + if(virtualPadManager.getLeftVirtualPad()->isShown()) { // render stick base auto stickBaseTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getFirstTouch(), _virtualPadPixelSize, _virtualPadPixelSize); diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 40bc341fe2..848174eb76 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -39,19 +39,28 @@ bool TouchscreenVirtualPadDevice::isSupported() const { return false; } -void TouchscreenVirtualPadDevice::initFromEvent(const QTouchEvent* event) { - QScreen* eventScreen = event->window()->screen(); +void TouchscreenVirtualPadDevice::init() { + _fixedPosition = true; // This should be config + + + QScreen* eventScreen = qApp->primaryScreen(); if (_screenDPI != eventScreen->physicalDotsPerInch()) { _screenWidthCenter = eventScreen->size().width() / 2; _screenDPIScale.x = (float)eventScreen->physicalDotsPerInchX(); _screenDPIScale.y = (float)eventScreen->physicalDotsPerInchY(); _screenDPI = eventScreen->physicalDotsPerInch(); - _fixedPosition = true; // This should be config _fixedRadius = _screenDPI * 256 / 534; qreal margin = _screenDPI * 59 / 534; // 59px is for our 'base' of 534dpi (Pixel XL or Huawei Mate 9 Pro) _fixedCenterPosition = glm::vec2( _fixedRadius + margin, eventScreen->size().height() - margin - _fixedRadius ); } + + if (_fixedPosition) { + _firstTouchLeftPoint = _fixedCenterPosition; + auto& virtualPadManager = VirtualPad::Manager::instance(); + virtualPadManager.getLeftVirtualPad()->setShown(virtualPadManager.isEnabled() && !virtualPadManager.isHidden()); // Show whenever it's enabled + virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); + } } float clip(float n, float lower, float upper) { @@ -82,14 +91,21 @@ void TouchscreenVirtualPadDevice::pluginUpdate(float deltaTime, const controller /* Shared variables for stick rendering (clipped to the stick radius)*/ // Prevent this for being done when not in first person view - virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); virtualPadManager.getLeftVirtualPad()->setCurrentTouch( glm::vec2(clip(_currentTouchLeftPoint.x, -STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x, STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x), clip(_currentTouchLeftPoint.y, -STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y, STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y)) ); + virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); + virtualPadManager.getLeftVirtualPad()->setShown(true); // If touched, show in any mode (fixed joystick position or non-fixed) } else { virtualPadManager.getLeftVirtualPad()->setBeingTouched(false); + if (_fixedPosition) { + virtualPadManager.getLeftVirtualPad()->setCurrentTouch(_fixedCenterPosition); // reset to the center + virtualPadManager.getLeftVirtualPad()->setShown(virtualPadManager.isEnabled() && !virtualPadManager.isHidden()); // Show whenever it's enabled + } else { + virtualPadManager.getLeftVirtualPad()->setShown(false); + } } if (_validTouchRight) { @@ -149,12 +165,13 @@ void TouchscreenVirtualPadDevice::touchBeginEvent(const QTouchEvent* event) { return; } KeyboardMouseDevice::enableTouch(false); - initFromEvent(event); } void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { auto& virtualPadManager = VirtualPad::Manager::instance(); if (!virtualPadManager.isEnabled()) { + touchLeftEnd(); + touchRightEnd(); return; } // touch end here is a big reset -> resets both pads diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index fd2342bfec..43c5612c82 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -26,6 +26,7 @@ Q_OBJECT public: // Plugin functions + virtual void init() override; virtual bool isSupported() const override; virtual const QString getName() const override { return NAME; } @@ -88,7 +89,6 @@ protected: // just for debug private: void debugPoints(const QTouchEvent* event, QString who); - void initFromEvent(const QTouchEvent* event); }; diff --git a/libraries/ui/src/VirtualPadManager.cpp b/libraries/ui/src/VirtualPadManager.cpp index 4c3e6ff728..441c491168 100644 --- a/libraries/ui/src/VirtualPadManager.cpp +++ b/libraries/ui/src/VirtualPadManager.cpp @@ -51,8 +51,24 @@ namespace VirtualPad { return _enabled; } + void Manager::hide(bool hidden) { + _hidden = hidden; + } + + bool Manager::isHidden() { + return _hidden; + } + Instance* Manager::getLeftVirtualPad() { return &_leftVPadInstance; } + bool Instance::isShown() { + return _shown; + } + + void Instance::setShown(bool show) { + _shown = show; + } + } diff --git a/libraries/ui/src/VirtualPadManager.h b/libraries/ui/src/VirtualPadManager.h index 599954989f..48a78ca09b 100644 --- a/libraries/ui/src/VirtualPadManager.h +++ b/libraries/ui/src/VirtualPadManager.h @@ -21,10 +21,13 @@ namespace VirtualPad { virtual glm::vec2 getFirstTouch(); virtual void setCurrentTouch(glm::vec2 point); virtual glm::vec2 getCurrentTouch(); + virtual bool isShown(); + virtual void setShown(bool show); private: bool _isBeingTouched; glm::vec2 _firstTouch; glm::vec2 _currentTouch; + bool _shown; }; class Manager : public QObject, public Dependency { @@ -37,9 +40,12 @@ namespace VirtualPad { Instance* getLeftVirtualPad(); bool isEnabled(); void enable(bool enable); + bool isHidden(); + void hide(bool hide); private: Instance _leftVPadInstance; bool _enabled; + bool _hidden; }; } diff --git a/scripts/system/+android/goto.js b/scripts/system/+android/goto.js index e917455128..2019af9077 100644 --- a/scripts/system/+android/goto.js +++ b/scripts/system/+android/goto.js @@ -52,7 +52,7 @@ module.exports = { }); }, show: function() { - Controller.setVPadEnabled(false); + Controller.setVPadHidden(true); if (window) { window.fromQml.connect(fromQml); window.setVisible(true); @@ -60,7 +60,7 @@ module.exports = { } }, hide: function() { - Controller.setVPadEnabled(true); + Controller.setVPadHidden(false); if (window) { window.fromQml.disconnect(fromQml); window.setVisible(false); diff --git a/scripts/system/+android/touchscreenvirtualpad.js b/scripts/system/+android/touchscreenvirtualpad.js index fa41a2b5e0..d48b623e03 100644 --- a/scripts/system/+android/touchscreenvirtualpad.js +++ b/scripts/system/+android/touchscreenvirtualpad.js @@ -14,6 +14,7 @@ function init() { Controller.setVPadEnabled(true); + Controller.setVPadHidden(false); } init(); From 9acb83632c4efcc1e709359a5f7b0a2898de0847 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Wed, 28 Feb 2018 18:52:13 -0300 Subject: [PATCH 40/61] Android - Make joystick move up when showing the bottom bar --- .../resources/qml/hifi/+android/bottombar.qml | 6 ----- .../ControllerScriptingInterface.cpp | 5 ++++ .../scripting/ControllerScriptingInterface.h | 3 ++- .../TouchscreenVirtualPadDevice.cpp | 26 ++++++++++++++----- .../TouchscreenVirtualPadDevice.h | 3 +++ libraries/ui/src/VirtualPadManager.cpp | 8 ++++++ libraries/ui/src/VirtualPadManager.h | 3 +++ scripts/system/+android/bottombar.js | 2 ++ 8 files changed, 43 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/hifi/+android/bottombar.qml b/interface/resources/qml/hifi/+android/bottombar.qml index e861d441d9..e31dc9453f 100644 --- a/interface/resources/qml/hifi/+android/bottombar.qml +++ b/interface/resources/qml/hifi/+android/bottombar.qml @@ -43,12 +43,6 @@ Item { HifiConstants { id: android } MouseArea { anchors.fill: parent - onEntered: { - Controller.setVPadEnabled(false); - } - onExited: { - Controller.setVPadEnabled(true); - } } Rectangle { diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 38d5306a1c..49ecc4774d 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -94,6 +94,11 @@ void ControllerScriptingInterface::setVPadHidden(const bool hidden) { virtualPadManager.hide(hidden); } +void ControllerScriptingInterface::setVPadExtraBottomMargin(const int margin) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + virtualPadManager.setExtraBottomMargin(margin); +} + void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index bb5615f996..9b24e2a06e 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -65,8 +65,9 @@ public slots: virtual glm::vec2 getViewportDimensions() const; virtual QVariant getRecommendedHUDRect() const; - virtual void setVPadHidden(bool hidden); // Call it when a window should hide it virtual void setVPadEnabled(bool enable); + virtual void setVPadHidden(bool hidden); // Call it when a window should hide it + virtual void setVPadExtraBottomMargin(int margin); signals: void keyPressEvent(const KeyEvent& event); diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 848174eb76..90a78b3231 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -42,7 +42,6 @@ bool TouchscreenVirtualPadDevice::isSupported() const { void TouchscreenVirtualPadDevice::init() { _fixedPosition = true; // This should be config - QScreen* eventScreen = qApp->primaryScreen(); if (_screenDPI != eventScreen->physicalDotsPerInch()) { _screenWidthCenter = eventScreen->size().width() / 2; @@ -51,18 +50,31 @@ void TouchscreenVirtualPadDevice::init() { _screenDPI = eventScreen->physicalDotsPerInch(); _fixedRadius = _screenDPI * 256 / 534; - qreal margin = _screenDPI * 59 / 534; // 59px is for our 'base' of 534dpi (Pixel XL or Huawei Mate 9 Pro) - _fixedCenterPosition = glm::vec2( _fixedRadius + margin, eventScreen->size().height() - margin - _fixedRadius ); } + auto& virtualPadManager = VirtualPad::Manager::instance(); + setupFixedCenter(virtualPadManager, true); + if (_fixedPosition) { - _firstTouchLeftPoint = _fixedCenterPosition; - auto& virtualPadManager = VirtualPad::Manager::instance(); virtualPadManager.getLeftVirtualPad()->setShown(virtualPadManager.isEnabled() && !virtualPadManager.isHidden()); // Show whenever it's enabled - virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); } } +void TouchscreenVirtualPadDevice::setupFixedCenter(VirtualPad::Manager& virtualPadManager, bool force) { + if (!_fixedPosition) return; + + //auto& virtualPadManager = VirtualPad::Manager::instance(); + if (_extraBottomMargin == virtualPadManager.extraBottomMargin() && !force) return; // Our only criteria to decide a center change is the bottom margin + + _extraBottomMargin = virtualPadManager.extraBottomMargin(); + qreal margin = _screenDPI * 59 / 534; // 59px is for our 'base' of 534dpi (Pixel XL or Huawei Mate 9 Pro) + QScreen* eventScreen = qApp->primaryScreen(); // do not call every time + _fixedCenterPosition = glm::vec2( _fixedRadius + margin, eventScreen->size().height() - margin - _fixedRadius - _extraBottomMargin); + + _firstTouchLeftPoint = _fixedCenterPosition; + virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); +} + float clip(float n, float lower, float upper) { return std::max(lower, std::min(n, upper)); } @@ -74,6 +86,8 @@ void TouchscreenVirtualPadDevice::pluginUpdate(float deltaTime, const controller }); auto& virtualPadManager = VirtualPad::Manager::instance(); + setupFixedCenter(virtualPadManager); + if (_validTouchLeft) { float leftDistanceScaleX, leftDistanceScaleY; leftDistanceScaleX = (_currentTouchLeftPoint.x - _firstTouchLeftPoint.x) / _screenDPIScale.x; diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index 43c5612c82..6e65ef7ab2 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -15,6 +15,7 @@ #include #include "InputPlugin.h" #include +#include "VirtualPadManager.h" class QTouchEvent; class QGestureEvent; @@ -78,6 +79,7 @@ protected: bool _fixedPosition; glm::vec2 _fixedCenterPosition; qreal _fixedRadius; + int _extraBottomMargin {0}; void touchLeftBegin(glm::vec2 touchPoint); void touchLeftUpdate(glm::vec2 touchPoint); @@ -86,6 +88,7 @@ protected: void touchRightBegin(glm::vec2 touchPoint); void touchRightUpdate(glm::vec2 touchPoint); void touchRightEnd(); + void setupFixedCenter(VirtualPad::Manager& virtualPadManager, bool force = false); // just for debug private: void debugPoints(const QTouchEvent* event, QString who); diff --git a/libraries/ui/src/VirtualPadManager.cpp b/libraries/ui/src/VirtualPadManager.cpp index 441c491168..486a6c2c71 100644 --- a/libraries/ui/src/VirtualPadManager.cpp +++ b/libraries/ui/src/VirtualPadManager.cpp @@ -59,6 +59,14 @@ namespace VirtualPad { return _hidden; } + int Manager::extraBottomMargin() { + return _extraBottomMargin; + } + + void Manager::setExtraBottomMargin(int margin) { + _extraBottomMargin = margin; + } + Instance* Manager::getLeftVirtualPad() { return &_leftVPadInstance; } diff --git a/libraries/ui/src/VirtualPadManager.h b/libraries/ui/src/VirtualPadManager.h index 48a78ca09b..3563d333f8 100644 --- a/libraries/ui/src/VirtualPadManager.h +++ b/libraries/ui/src/VirtualPadManager.h @@ -42,10 +42,13 @@ namespace VirtualPad { void enable(bool enable); bool isHidden(); void hide(bool hide); + int extraBottomMargin(); + void setExtraBottomMargin(int margin); private: Instance _leftVPadInstance; bool _enabled; bool _hidden; + int _extraBottomMargin {0}; }; } diff --git a/scripts/system/+android/bottombar.js b/scripts/system/+android/bottombar.js index 5f82886c8a..27ef39c914 100644 --- a/scripts/system/+android/bottombar.js +++ b/scripts/system/+android/bottombar.js @@ -196,6 +196,7 @@ function lowerBottomBar() { if (bottomHudOptionsBar) { bottomHudOptionsBar.show(); } + Controller.setVPadExtraBottomMargin(0); } function raiseBottomBar() { @@ -206,6 +207,7 @@ function raiseBottomBar() { if (bottomHudOptionsBar) { bottomHudOptionsBar.hide(); } + Controller.setVPadExtraBottomMargin(255); // Height in bottombar.qml print('[bottombar.js] raiseBottomBar end'); } From b5c3b78d57ee6e85bf3deefdab5533e1e4111655 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Thu, 1 Mar 2018 17:58:23 -0300 Subject: [PATCH 41/61] Android - Virtual Pad - Limit joystick inside base circle. --- .../TouchscreenVirtualPadDevice.cpp | 98 ++++++++++++++----- .../TouchscreenVirtualPadDevice.h | 5 + 2 files changed, 80 insertions(+), 23 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 90a78b3231..1774bbb4d3 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -50,6 +50,7 @@ void TouchscreenVirtualPadDevice::init() { _screenDPI = eventScreen->physicalDotsPerInch(); _fixedRadius = _screenDPI * 256 / 534; + _fixedRadiusForCalc = _fixedRadius - _screenDPI * 105 / 534; // 105 is the radius of the stick circle } auto& virtualPadManager = VirtualPad::Manager::instance(); @@ -79,6 +80,79 @@ float clip(float n, float lower, float upper) { return std::max(lower, std::min(n, upper)); } +glm::vec2 TouchscreenVirtualPadDevice::clippedPointInCircle(float radius, glm::vec2 origin, glm::vec2 touchPoint) { + float deltaX = touchPoint.x-origin.x; + float deltaY = touchPoint.y-origin.y; + + float distance = sqrt(pow(deltaX,2)+pow(deltaY,2)); + + // First case, inside the boundaires, just use the distance + if (distance <= radius) { + return touchPoint; + } + + // Second case, purely vertical (avoid division by zero) + if (deltaX == 0.0f) { + return vec2(touchPoint.x, clip(touchPoint.y, origin.y-radius, origin.y+radius) ); + } + + // Third case, calculate point in circumference + // line formula + float m = deltaY/deltaX; + float b = touchPoint.y - m * touchPoint.x; + + // quadtratic coefs of circumference and line intersection + float qa = pow(m,2)+1; + float qb = 2 * ( m * b - origin.x - origin.y * m ); + float qc = pow(origin.x, 2) - pow(radius,2) + b * b - 2 * b * origin.y + pow(origin.y, 2); + + float discr = qb * qb - 4 * qa * qc; + float discrSign = deltaX>0?1.0:-1.0; + + float finalX = (- qb + discrSign * sqrt(discr)) / (2 * qa); + float finalY = m * finalX + b; + + return vec2(finalX, finalY); +} + +void TouchscreenVirtualPadDevice::processInputUseCircleMethod(VirtualPad::Manager& virtualPadManager) { + vec2 clippedPoint = clippedPointInCircle(_fixedRadiusForCalc, _firstTouchLeftPoint, _currentTouchLeftPoint); + + _inputDevice->_axisStateMap[controller::LX] = (clippedPoint.x - _firstTouchLeftPoint.x) / _fixedRadiusForCalc; + _inputDevice->_axisStateMap[controller::LY] = (clippedPoint.y - _firstTouchLeftPoint.y) / _fixedRadiusForCalc; + + virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); + virtualPadManager.getLeftVirtualPad()->setCurrentTouch(clippedPoint); + virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); + virtualPadManager.getLeftVirtualPad()->setShown(true); // If touched, show in any mode (fixed joystick position or non-fixed) +} + +void TouchscreenVirtualPadDevice::processInputUseSquareMethod(VirtualPad::Manager& virtualPadManager) { + float leftDistanceScaleX, leftDistanceScaleY; + leftDistanceScaleX = (_currentTouchLeftPoint.x - _firstTouchLeftPoint.x) / _screenDPIScale.x; + leftDistanceScaleY = (_currentTouchLeftPoint.y - _firstTouchLeftPoint.y) / _screenDPIScale.y; + + leftDistanceScaleX = clip(leftDistanceScaleX, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); + leftDistanceScaleY = clip(leftDistanceScaleY, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); + + // NOW BETWEEN -1 1 + leftDistanceScaleX /= STICK_RADIUS_INCHES; + leftDistanceScaleY /= STICK_RADIUS_INCHES; + + _inputDevice->_axisStateMap[controller::LX] = leftDistanceScaleX; + _inputDevice->_axisStateMap[controller::LY] = leftDistanceScaleY; + + /* Shared variables for stick rendering (clipped to the stick radius)*/ + // Prevent this for being done when not in first person view + virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); + virtualPadManager.getLeftVirtualPad()->setCurrentTouch( + glm::vec2(clip(_currentTouchLeftPoint.x, -STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x, STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x), + clip(_currentTouchLeftPoint.y, -STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y, STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y)) + ); + virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); + virtualPadManager.getLeftVirtualPad()->setShown(true); // If touched, show in any mode (fixed joystick position or non-fixed) +} + void TouchscreenVirtualPadDevice::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { auto userInputMapper = DependencyManager::get(); userInputMapper->withLock([&, this]() { @@ -89,29 +163,7 @@ void TouchscreenVirtualPadDevice::pluginUpdate(float deltaTime, const controller setupFixedCenter(virtualPadManager); if (_validTouchLeft) { - float leftDistanceScaleX, leftDistanceScaleY; - leftDistanceScaleX = (_currentTouchLeftPoint.x - _firstTouchLeftPoint.x) / _screenDPIScale.x; - leftDistanceScaleY = (_currentTouchLeftPoint.y - _firstTouchLeftPoint.y) / _screenDPIScale.y; - - leftDistanceScaleX = clip(leftDistanceScaleX, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); - leftDistanceScaleY = clip(leftDistanceScaleY, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); - - // NOW BETWEEN -1 1 - leftDistanceScaleX /= STICK_RADIUS_INCHES; - leftDistanceScaleY /= STICK_RADIUS_INCHES; - - _inputDevice->_axisStateMap[controller::LX] = leftDistanceScaleX; - _inputDevice->_axisStateMap[controller::LY] = leftDistanceScaleY; - - /* Shared variables for stick rendering (clipped to the stick radius)*/ - // Prevent this for being done when not in first person view - virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); - virtualPadManager.getLeftVirtualPad()->setCurrentTouch( - glm::vec2(clip(_currentTouchLeftPoint.x, -STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x, STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x), - clip(_currentTouchLeftPoint.y, -STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y, STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y)) - ); - virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); - virtualPadManager.getLeftVirtualPad()->setShown(true); // If touched, show in any mode (fixed joystick position or non-fixed) + processInputUseCircleMethod(virtualPadManager); } else { virtualPadManager.getLeftVirtualPad()->setBeingTouched(false); if (_fixedPosition) { diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index 6e65ef7ab2..f71490b0e3 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -79,6 +79,7 @@ protected: bool _fixedPosition; glm::vec2 _fixedCenterPosition; qreal _fixedRadius; + qreal _fixedRadiusForCalc; int _extraBottomMargin {0}; void touchLeftBegin(glm::vec2 touchPoint); @@ -89,6 +90,10 @@ protected: void touchRightUpdate(glm::vec2 touchPoint); void touchRightEnd(); void setupFixedCenter(VirtualPad::Manager& virtualPadManager, bool force = false); + + void processInputUseCircleMethod(VirtualPad::Manager& virtualPadManager); + void processInputUseSquareMethod(VirtualPad::Manager& virtualPadManager); + glm::vec2 clippedPointInCircle(float radius, glm::vec2 origin, glm::vec2 touchPoint); // just for debug private: void debugPoints(const QTouchEvent* event, QString who); From 0f2cf8ea85b32e2d5121a42b7cbe232ebe5575a5 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Mar 2018 14:24:20 -0800 Subject: [PATCH 42/61] Re-implemented shadow controls. --- .../dialogs/GraphicsPreferencesDialog.qml | 19 ------ interface/src/Menu.cpp | 16 +++-- interface/src/Menu.h | 2 + .../src/RenderableEntityItem.cpp | 8 ++- .../src/RenderableEntityItem.h | 1 + .../src/RenderableModelEntityItem.cpp | 4 ++ .../src/RenderableZoneEntityItem.cpp | 1 + libraries/entities/src/EntityItem.cpp | 27 ++++++++ libraries/entities/src/EntityItem.h | 5 ++ .../entities/src/EntityItemProperties.cpp | 13 ++++ libraries/entities/src/EntityItemProperties.h | 2 + .../src/EntityItemPropertiesDefaults.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 10 +-- .../entities/src/KeyLightPropertyGroup.cpp | 31 +++++++-- .../entities/src/KeyLightPropertyGroup.h | 2 + libraries/graphics/src/graphics/Light.cpp | 9 ++- libraries/graphics/src/graphics/Light.h | 5 ++ .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- .../render-utils/src/CauterizedModel.cpp | 5 +- .../src/DeferredLightingEffect.cpp | 18 ++++-- .../render-utils/src/DeferredLightingEffect.h | 2 +- .../render-utils/src/MeshPartPayload.cpp | 13 +++- libraries/render-utils/src/MeshPartPayload.h | 4 +- libraries/render-utils/src/Model.cpp | 63 +++++++++++++------ libraries/render-utils/src/Model.h | 6 ++ .../render-utils/src/RenderShadowTask.cpp | 14 ++++- libraries/render-utils/src/RenderShadowTask.h | 2 +- scripts/system/html/entityProperties.html | 44 ++++++------- scripts/system/html/js/entityProperties.js | 32 +++++++++- 30 files changed, 269 insertions(+), 95 deletions(-) delete mode 100644 interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml diff --git a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml deleted file mode 100644 index d95bafd0a9..0000000000 --- a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml +++ /dev/null @@ -1,19 +0,0 @@ -import QtQuick 2.5 -import Qt.labs.settings 1.0 - -import "../../dialogs" - -PreferencesDialog { - id: root - objectName: "GraphicsPreferencesDialog" - title: "Graphics Settings" - showCategories: ["Graphics"] - property var settings: Settings { - category: root.objectName - property alias x: root.x - property alias y: root.y - property alias width: root.width - property alias height: root.height - } -} - diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8c0ac584c5..ca6f7a31d1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -43,6 +43,7 @@ #include "ui/StandAloneJSConsole.h" #include "InterfaceLogging.h" #include "LocationBookmarks.h" +#include "DeferredLightingEffect.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" @@ -360,11 +361,16 @@ Menu::Menu() { // Developer menu ---------------------------------- MenuWrapper* developerMenu = addMenu("Developer", "Developer"); - // Developer > Graphics... - action = addActionToQMenuAndActionHash(developerMenu, "Graphics..."); - connect(action, &QAction::triggered, [] { - qApp->showDialog(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), - QString("hifi/tablet/TabletGraphicsPreferences.qml"), "GraphicsPreferencesDialog"); + // Developer > Graphics + MenuWrapper* graphicsOptionsMenu = developerMenu->addMenu("Render"); + action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::Shadows, 0, true); + connect(action, &QAction::triggered, [action] { + DependencyManager::get()->setShadowMapEnabled(action->isChecked()); + }); + + action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::AmbientOcclusion, 0, false); + connect(action, &QAction::triggered, [action] { + DependencyManager::get()->setAmbientOcclusionEnabled(action->isChecked()); }); // Developer > UI >>> diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 34588535ec..1d37b74ffe 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -204,6 +204,8 @@ namespace MenuOption { const QString WorldAxes = "World Axes"; const QString DesktopTabletToToolbar = "Desktop Tablet Becomes Toolbar"; const QString HMDTabletToToolbar = "HMD Tablet Becomes Toolbar"; + const QString Shadows = "Shadows"; + const QString AmbientOcclusion = "AmbientOcclusion"; } #endif // hifi_Menu_h diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index d3c9f3d4bd..c33b87e5cf 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -164,7 +164,12 @@ ItemKey EntityRenderer::getKey() { return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } - return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + // This allows shapes to cast shadows + if (_canCastShadow) { + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).withShadowCaster(); + } else { + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + } } uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { @@ -377,6 +382,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa _moving = entity->isMovingRelativeToParent(); _visible = entity->getVisible(); + _canCastShadow = entity->getCanCastShadow(); _cauterized = entity->getCauterized(); _needsRenderUpdate = false; }); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index d34a1127ae..ada57c8ab0 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -129,6 +129,7 @@ protected: bool _isFading{ _entitiesShouldFadeFunction() }; bool _prevIsTransparent { false }; bool _visible { false }; + bool _canCastShadow { false }; bool _cauterized { false }; bool _moving { false }; bool _needsRenderUpdate { false }; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 5f926d1bb9..b7c5caf8ee 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1395,6 +1395,10 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } // TODO? early exit here when not visible? + if (model->canCastShadow() != _canCastShadow) { + model->setCanCastShadow(_canCastShadow, scene, viewTaskBits, false); + } + if (_needsCollisionGeometryUpdate) { setCollisionMeshKey(entity->getCollisionMeshKey()); _needsCollisionGeometryUpdate = false; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 34703804cd..322c91e3d3 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -330,6 +330,7 @@ void ZoneEntityRenderer::updateKeySunFromEntity(const TypedEntityPointer& entity sunLight->setColor(ColorUtils::toVec3(_keyLightProperties.getColor())); sunLight->setIntensity(_keyLightProperties.getIntensity()); sunLight->setDirection(entity->getTransform().getRotation() * _keyLightProperties.getDirection()); + sunLight->setCastShadows(_keyLightProperties.getCastShadows()); } void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer& entity) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ec0bdbd2ae..f77d8a59c3 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -91,6 +91,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_REGISTRATION_POINT; requestedProperties += PROP_ANGULAR_DAMPING; requestedProperties += PROP_VISIBLE; + requestedProperties += PROP_CAN_CAST_SHADOW; requestedProperties += PROP_COLLISIONLESS; requestedProperties += PROP_COLLISION_MASK; requestedProperties += PROP_DYNAMIC; @@ -249,6 +250,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); + APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, getCanCastShadow()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONLESS, getCollisionless()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, getDynamic()); @@ -799,6 +801,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); + READ_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, setCollisionless); READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, setCollisionMask); READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, setDynamic); @@ -1234,6 +1237,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping); COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRenderAlpha, getLocalRenderAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(canCastShadow, getCanCastShadow); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionless, getCollisionless); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionMask, getCollisionMask); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dynamic, getDynamic); @@ -1346,6 +1350,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); // Certifiable Properties @@ -2723,6 +2728,28 @@ void EntityItem::setVisible(bool value) { } } +bool EntityItem::getCanCastShadow() const { + bool result; + withReadLock([&] { + result = _canCastShadow; + }); + return result; +} + +void EntityItem::setCanCastShadow(bool value) { + bool changed = false; + withWriteLock([&] { + if (_canCastShadow != value) { + changed = true; + _canCastShadow = value; + } + }); + + if (changed) { + emit requestRenderUpdate(); + } +} + bool EntityItem::isChildOfMyAvatar() const { QUuid ancestorID = findAncestorOfType(NestableType::Avatar); return !ancestorID.isNull() && (ancestorID == Physics::getSessionUUID() || ancestorID == AVATAR_SELF_ID); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index b12417c496..d08c5514e9 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -274,6 +274,10 @@ public: bool getVisible() const; void setVisible(bool value); + + bool getCanCastShadow() const; + void setCanCastShadow(bool value); + inline bool isVisible() const { return getVisible(); } inline bool isInvisible() const { return !getVisible(); } @@ -551,6 +555,7 @@ protected: glm::vec3 _registrationPoint { ENTITY_ITEM_DEFAULT_REGISTRATION_POINT }; float _angularDamping { ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING }; bool _visible { ENTITY_ITEM_DEFAULT_VISIBLE }; + bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW }; bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS }; uint8_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; bool _dynamic { ENTITY_ITEM_DEFAULT_DYNAMIC }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index a2724c4cbf..2eca612fc2 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -316,6 +316,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); + CHECK_PROPERTY_CHANGE(PROP_CAN_CAST_SHADOW, canCastShadow); CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); @@ -490,6 +491,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CAN_CAST_SHADOW, canCastShadow); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONLESS, collisionless); COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISIONLESS, collisionless, ignoreForCollisions, getCollisionless()); // legacy support COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask); @@ -751,6 +753,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity); COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping); COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); + COPY_PROPERTY_FROM_QSCRIPTVALUE(canCastShadow, bool, setCanCastShadow); COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor); COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, xColor, setColorStart); @@ -922,6 +925,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(angularVelocity); COPY_PROPERTY_IF_CHANGED(angularDamping); COPY_PROPERTY_IF_CHANGED(visible); + COPY_PROPERTY_IF_CHANGED(canCastShadow); COPY_PROPERTY_IF_CHANGED(color); COPY_PROPERTY_IF_CHANGED(colorSpread); COPY_PROPERTY_IF_CHANGED(colorStart); @@ -1094,6 +1098,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue std::call_once(initMap, [](){ ADD_PROPERTY_TO_MAP(PROP_VISIBLE, Visible, visible, bool); + ADD_PROPERTY_TO_MAP(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool); ADD_PROPERTY_TO_MAP(PROP_POSITION, Position, position, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_DIMENSIONS, Dimensions, dimensions, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_ROTATION, Rotation, rotation, glm::quat); @@ -1187,6 +1192,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_CAST_SHADOW, KeyLightCastShadows, keyLightCastShadows, bool); + ADD_PROPERTY_TO_MAP(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray); ADD_PROPERTY_TO_MAP(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t); @@ -1412,6 +1419,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, properties.getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, properties.getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible()); + APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, properties.getCanCastShadow()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONLESS, properties.getCollisionless()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, properties.getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, properties.getDynamic()); @@ -1784,6 +1792,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONLESS, bool, setCollisionless); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint8_t, setCollisionMask); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DYNAMIC, bool, setDynamic); @@ -2053,6 +2062,7 @@ void EntityItemProperties::markAllChanged() { _angularDampingChanged = true; _nameChanged = true; _visibleChanged = true; + _canCastShadowChanged = true; _colorChanged = true; _alphaChanged = true; _modelURLChanged = true; @@ -2250,6 +2260,9 @@ QList EntityItemProperties::listChangedProperties() { if (visibleChanged()) { out += "visible"; } + if (canCastShadowChanged()) { + out += "canCastShadow"; + } if (rotationChanged()) { out += "rotation"; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 36ca47291c..0838bb937a 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -117,6 +117,7 @@ public: // bool _fooChanged { false }; DEFINE_PROPERTY(PROP_VISIBLE, Visible, visible, bool, ENTITY_ITEM_DEFAULT_VISIBLE); + DEFINE_PROPERTY(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool, ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW); DEFINE_PROPERTY_REF_WITH_SETTER(PROP_POSITION, Position, position, glm::vec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_DIMENSIONS, Dimensions, dimensions, glm::vec3, ENTITY_ITEM_DEFAULT_DIMENSIONS); DEFINE_PROPERTY_REF(PROP_ROTATION, Rotation, rotation, glm::quat, ENTITY_ITEM_DEFAULT_ROTATION); @@ -426,6 +427,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Velocity, velocity, "in meters"); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Name, name, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Visible, visible, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, CanCastShadow, canCastShadow, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Rotation, rotation, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Density, density, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Gravity, gravity, ""); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index eb09a64628..0e0c2994cd 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -46,6 +46,7 @@ const quint32 ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION = 0; const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const bool ENTITY_ITEM_DEFAULT_VISIBLE = true; +const bool ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW { true }; const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString(""); const quint64 ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP = 0; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index b65d5d1a3f..07908fe6cf 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -20,6 +20,7 @@ enum EntityPropertyList { // these properties are supported by the EntityItem base class PROP_VISIBLE, + PROP_CAN_CAST_SHADOW, PROP_POSITION, PROP_DIMENSIONS, PROP_ROTATION, @@ -205,6 +206,11 @@ enum EntityPropertyList { PROP_HAZE_MODE, + PROP_KEYLIGHT_COLOR, + PROP_KEYLIGHT_INTENSITY, + PROP_KEYLIGHT_DIRECTION, + PROP_KEYLIGHT_CAST_SHADOW, + PROP_HAZE_RANGE, PROP_HAZE_COLOR, PROP_HAZE_GLARE_COLOR, @@ -254,10 +260,6 @@ enum EntityPropertyList { // Aliases/Piggyback properties for Zones. These properties intentionally reuse the enum values for // other properties which will never overlap with each other. We do this so that we don't have to expand // the size of the properties bitflags mask - PROP_KEYLIGHT_COLOR = PROP_COLOR, - PROP_KEYLIGHT_INTENSITY = PROP_INTENSITY, - PROP_KEYLIGHT_DIRECTION = PROP_EXPONENT, - PROP_SKYBOX_COLOR = PROP_ANIMATION_URL, PROP_SKYBOX_URL = PROP_ANIMATION_FPS, diff --git a/libraries/entities/src/KeyLightPropertyGroup.cpp b/libraries/entities/src/KeyLightPropertyGroup.cpp index c476b4c23c..e0b6ae6e96 100644 --- a/libraries/entities/src/KeyLightPropertyGroup.cpp +++ b/libraries/entities/src/KeyLightPropertyGroup.cpp @@ -21,6 +21,7 @@ const xColor KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR = { 255, 255, 255 }; const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY = 1.0f; const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY = 0.5f; const glm::vec3 KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION = { 0.0f, -1.0f, 0.0f }; +const bool KeyLightPropertyGroup::DEFAULT_KEYLIGHT_CAST_SHADOWS { false }; void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { @@ -28,23 +29,27 @@ void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desired COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_COLOR, KeyLight, keyLight, Color, color); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_INTENSITY, KeyLight, keyLight, Intensity, intensity); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_DIRECTION, KeyLight, keyLight, Direction, direction); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_CAST_SHADOW, KeyLight, keyLight, CastShadows, castShadows); } void KeyLightPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, color, xColor, setColor); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, intensity, float, setIntensity); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, direction, glmVec3, setDirection); - + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, castShadows, bool, setCastShadows); + // legacy property support COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightColor, xColor, setColor, getColor); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightIntensity, float, setIntensity, getIntensity); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightDirection, glmVec3, setDirection, getDirection); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightCastShadows, bool, setCastShadows, getCastShadows); } void KeyLightPropertyGroup::merge(const KeyLightPropertyGroup& other) { COPY_PROPERTY_IF_CHANGED(color); COPY_PROPERTY_IF_CHANGED(intensity); COPY_PROPERTY_IF_CHANGED(direction); + COPY_PROPERTY_IF_CHANGED(castShadows); } void KeyLightPropertyGroup::debugDump() const { @@ -52,6 +57,7 @@ void KeyLightPropertyGroup::debugDump() const { qCDebug(entities) << " color:" << getColor(); // << "," << getColor()[1] << "," << getColor()[2]; qCDebug(entities) << " intensity:" << getIntensity(); qCDebug(entities) << " direction:" << getDirection(); + qCDebug(entities) << " castShadows:" << getCastShadows(); } void KeyLightPropertyGroup::listChangedProperties(QList& out) { @@ -64,6 +70,9 @@ void KeyLightPropertyGroup::listChangedProperties(QList& out) { if (directionChanged()) { out << "keyLight-direction"; } + if (castShadowsChanged()) { + out << "keyLight-castShadows"; + } } bool KeyLightPropertyGroup::appendToEditPacket(OctreePacketData* packetData, @@ -78,12 +87,13 @@ bool KeyLightPropertyGroup::appendToEditPacket(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, getColor()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, getIntensity()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, getDirection()); - + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, getCastShadows()); + return true; } bool KeyLightPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt, - int& processedBytes) { + int& processedBytes) { int bytesRead = 0; bool overwriteLocalData = true; @@ -92,11 +102,13 @@ bool KeyLightPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFl READ_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, xColor, setColor); READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, setIntensity); READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, setDirection); - + READ_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, bool, setCastShadows); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_COLOR, Color); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_INTENSITY, Intensity); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_DIRECTION, Direction); - + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_CAST_SHADOW, CastShadows); + processedBytes += bytesRead; Q_UNUSED(somethingChanged); @@ -108,6 +120,7 @@ void KeyLightPropertyGroup::markAllChanged() { _colorChanged = true; _intensityChanged = true; _directionChanged = true; + _castShadowsChanged = true; } EntityPropertyFlags KeyLightPropertyGroup::getChangedProperties() const { @@ -116,7 +129,8 @@ EntityPropertyFlags KeyLightPropertyGroup::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_INTENSITY, intensity); CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, direction); - + CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_CAST_SHADOW, castShadows); + return changedProperties; } @@ -124,6 +138,7 @@ void KeyLightPropertyGroup::getProperties(EntityItemProperties& properties) cons COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Color, getColor); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Intensity, getIntensity); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Direction, getDirection); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, CastShadows, getCastShadows); } bool KeyLightPropertyGroup::setProperties(const EntityItemProperties& properties) { @@ -132,6 +147,7 @@ bool KeyLightPropertyGroup::setProperties(const EntityItemProperties& properties SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Color, color, setColor); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Intensity, intensity, setIntensity); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Direction, direction, setDirection); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, CastShadows, castShadows, setCastShadows); return somethingChanged; } @@ -142,6 +158,7 @@ EntityPropertyFlags KeyLightPropertyGroup::getEntityProperties(EncodeBitstreamPa requestedProperties += PROP_KEYLIGHT_COLOR; requestedProperties += PROP_KEYLIGHT_INTENSITY; requestedProperties += PROP_KEYLIGHT_DIRECTION; + requestedProperties += PROP_KEYLIGHT_CAST_SHADOW; return requestedProperties; } @@ -159,6 +176,7 @@ void KeyLightPropertyGroup::appendSubclassData(OctreePacketData* packetData, Enc APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, getColor()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, getIntensity()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, getDirection()); + APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, getCastShadows()); } int KeyLightPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, @@ -172,6 +190,7 @@ int KeyLightPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* READ_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, xColor, setColor); READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, setIntensity); READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, setDirection); + READ_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, bool, setCastShadows); return bytesRead; } diff --git a/libraries/entities/src/KeyLightPropertyGroup.h b/libraries/entities/src/KeyLightPropertyGroup.h index f33ebb282d..5e13a6afa6 100644 --- a/libraries/entities/src/KeyLightPropertyGroup.h +++ b/libraries/entities/src/KeyLightPropertyGroup.h @@ -78,10 +78,12 @@ public: static const float DEFAULT_KEYLIGHT_INTENSITY; static const float DEFAULT_KEYLIGHT_AMBIENT_INTENSITY; static const glm::vec3 DEFAULT_KEYLIGHT_DIRECTION; + static const bool DEFAULT_KEYLIGHT_CAST_SHADOWS; DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, Color, color, xColor, DEFAULT_KEYLIGHT_COLOR); DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, Intensity, intensity, float, DEFAULT_KEYLIGHT_INTENSITY); DEFINE_PROPERTY_REF(PROP_KEYLIGHT_DIRECTION, Direction, direction, glm::vec3, DEFAULT_KEYLIGHT_DIRECTION); + DEFINE_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, CastShadows, castShadows, bool, DEFAULT_KEYLIGHT_CAST_SHADOWS); }; #endif // hifi_KeyLightPropertyGroup_h diff --git a/libraries/graphics/src/graphics/Light.cpp b/libraries/graphics/src/graphics/Light.cpp index 9da14fec4f..76d8a6030a 100755 --- a/libraries/graphics/src/graphics/Light.cpp +++ b/libraries/graphics/src/graphics/Light.cpp @@ -65,6 +65,14 @@ const Vec3& Light::getDirection() const { return _lightSchemaBuffer->volume.direction; } +void Light::setCastShadows(const bool castShadows) { + _castShadows = castShadows; +} + +bool Light::getCastShadows() const { + return _castShadows; +} + void Light::setColor(const Color& color) { _lightSchemaBuffer.edit().irradiance.color = color; updateLightRadius(); @@ -132,7 +140,6 @@ void Light::setSpotExponent(float exponent) { _lightSchemaBuffer.edit().irradiance.falloffSpot = exponent; } - void Light::setAmbientIntensity(float intensity) { _ambientSchemaBuffer.edit().intensity = intensity; } diff --git a/libraries/graphics/src/graphics/Light.h b/libraries/graphics/src/graphics/Light.h index e6ef1e35c5..bb9fb3e5b9 100755 --- a/libraries/graphics/src/graphics/Light.h +++ b/libraries/graphics/src/graphics/Light.h @@ -103,6 +103,9 @@ public: void setDirection(const Vec3& direction); const Vec3& getDirection() const; + void setCastShadows(const bool castShadows); + bool getCastShadows() const; + void setOrientation(const Quat& orientation); const glm::quat& getOrientation() const { return _transform.getRotation(); } @@ -191,6 +194,8 @@ protected: void updateLightRadius(); + bool _castShadows{ false }; + }; typedef std::shared_ptr< Light > LightPointer; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 5c202fa70c..a83924ee58 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::MaterialEntities); + return static_cast(EntityVersion::ShadowControl); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e9fe232335..98a9087d37 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -230,7 +230,8 @@ enum class EntityVersion : PacketVersion { ZoneLightInheritModes = 82, ZoneStageRemoved, SoftEntities, - MaterialEntities + MaterialEntities, + ShadowControl }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 6806b41647..fdb57dace7 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -214,6 +214,7 @@ void CauterizedModel::updateRenderItems() { bool isWireframe = self->isWireframe(); bool isVisible = self->isVisible(); + bool canCastShadow = self->canCastShadow(); bool isLayeredInFront = self->isLayeredInFront(); bool isLayeredInHUD = self->isLayeredInHUD(); bool enableCauterization = self->getEnableCauterization(); @@ -231,7 +232,7 @@ void CauterizedModel::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, - isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) { + isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization](CauterizedMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions, cauterizedMeshState.clusterDualQuaternions); @@ -273,7 +274,7 @@ void CauterizedModel::updateRenderItems() { data.updateTransformForCauterizedMesh(renderTransform); data.setEnableCauterization(enableCauterization); - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::TAG_BITS_ALL); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); }); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e2c0073d2f..665e767c7c 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -537,15 +537,25 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, auto keyLight = lightAndShadow.first; - graphics::LightPointer keyAmbientLight; + graphics::LightPointer ambientLight; if (lightStage && lightStage->_currentFrame._ambientLights.size()) { - keyAmbientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front()); + ambientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front()); } - bool hasAmbientMap = (keyAmbientLight != nullptr); + bool hasAmbientMap = (ambientLight != nullptr); // Setup the global directional pass pipeline { - if (deferredLightingEffect->_shadowMapEnabled) { + // Check if keylight casts shadows + bool keyLightCastShadows { false }; + + if (lightStage && lightStage->_currentFrame._sunLights.size()) { + graphics::LightPointer keyLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front()); + if (keyLight) { + keyLightCastShadows = keyLight->getCastShadows(); + } + } + + if (deferredLightingEffect->_shadowMapEnabled && keyLightCastShadows) { // If the keylight has an ambient Map then use the Skybox version of the pass // otherwise use the ambient sphere version diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 1b776e6409..ce7ecacbbe 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -61,7 +61,7 @@ public: private: DeferredLightingEffect() = default; - bool _shadowMapEnabled{ false }; + bool _shadowMapEnabled{ true }; // note that this value is overwritten in the ::configure method bool _ambientOcclusionEnabled{ false }; graphics::MeshPointer _pointLightMesh; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2637d24d67..98ecc4c941 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -77,7 +77,7 @@ void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); } -void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled) { +void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) { ItemKey::Builder builder; builder.withTypeShape(); @@ -91,6 +91,10 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, builder.withLayered(); } + if (canCastShadow) { + builder.withShadowCaster(); + } + if (isGroupCulled) { builder.withSubMetaCulled(); } @@ -328,7 +332,8 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render _worldBound.transform(boundTransform); } -void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled) { +// Note that this method is called for models but not for shapes +void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) { ItemKey::Builder builder; builder.withTypeShape(); @@ -342,6 +347,10 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag builder.withLayered(); } + if (canCastShadow) { + builder.withShadowCaster(); + } + if (isGroupCulled) { builder.withSubMetaCulled(); } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 3ad222d90c..087550345d 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -32,7 +32,7 @@ public: typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - virtual void updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled = false); + virtual void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false); virtual void updateMeshPart(const std::shared_ptr& drawMesh, int partIndex); @@ -92,7 +92,7 @@ public: void notifyLocationChanged() override; - void updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled = false) override; + void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false) override; // matrix palette skinning void updateClusterBuffer(const std::vector& clusterMatrices); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 12d6659849..593780709a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -104,6 +104,7 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : _snappedToRegistrationPoint(false), _url(HTTP_INVALID_COM), _isVisible(true), + _canCastShadow(false), _blendNumber(0), _appliedBlendNumber(0), _isWireframe(false) @@ -270,6 +271,7 @@ void Model::updateRenderItems() { bool isWireframe = self->isWireframe(); bool isVisible = self->isVisible(); + bool canCastShadow = self->canCastShadow(); uint8_t viewTagBits = self->getViewTagBits(); bool isLayeredInFront = self->isLayeredInFront(); bool isLayeredInHUD = self->isLayeredInHUD(); @@ -288,7 +290,7 @@ void Model::updateRenderItems() { transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, invalidatePayloadShapeKey, isWireframe, isVisible, - viewTagBits, isLayeredInFront, + canCastShadow, viewTagBits, isLayeredInFront, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); @@ -313,7 +315,7 @@ void Model::updateRenderItems() { } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); }); @@ -773,46 +775,66 @@ void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, bool isLayeredInFront = _isLayeredInFront; bool isLayeredInHUD = _isLayeredInHUD; - + bool canCastShadow = _canCastShadow; render::Transaction transaction; foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); }); } scene->enqueueTransaction(transaction); } } +void Model::setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) { + if (_canCastShadow != canCastShadow) { + _canCastShadow = canCastShadow; + + bool isVisible = _isVisible; + bool isLayeredInFront = _isLayeredInFront; + bool isLayeredInHUD = _isLayeredInHUD; + + render::Transaction transaction; + foreach (auto item, _modelMeshRenderItemsMap.keys()) { + transaction.updateItem(item, + [isVisible, viewTagBits, canCastShadow, isLayeredInFront, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + data.updateKey(isVisible, viewTagBits, canCastShadow, isLayeredInFront || isLayeredInHUD, isGroupCulled); + }); + } + + scene->enqueueTransaction(transaction); + } +} void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) { if (_isLayeredInFront != isLayeredInFront) { _isLayeredInFront = isLayeredInFront; bool isVisible = _isVisible; + bool canCastShadow = _canCastShadow; uint8_t viewTagBits = _viewTagBits; bool isLayeredInHUD = _isLayeredInHUD; bool isGroupCulled = _isGroupCulled; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } @@ -825,22 +847,23 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce _isLayeredInHUD = isLayeredInHUD; bool isVisible = _isVisible; + bool canCastShadow = _canCastShadow; uint8_t viewTagBits = _viewTagBits; bool isLayeredInFront = _isLayeredInFront; bool isGroupCulled = _isGroupCulled; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } @@ -1650,15 +1673,16 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par uint8_t viewTagBits = getViewTagBits(); bool layeredInFront = isLayeredInFront(); bool layeredInHUD = isLayeredInHUD(); + bool canCastShadow = _canCastShadow; bool wireframe = isWireframe(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow, invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.addMaterial(material); // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits); data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning); }); } @@ -1676,15 +1700,16 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string uint8_t viewTagBits = getViewTagBits(); bool layeredInFront = isLayeredInFront(); bool layeredInHUD = isLayeredInHUD(); + bool canCastShadow = _canCastShadow; bool wireframe = isWireframe(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow, invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.removeMaterial(material); // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits); data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning); }); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 9c98ac2b8b..2b14a7c055 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -88,6 +88,10 @@ public: // new Scene/Engine rendering support void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled); + + bool canCastShadow() const { return _canCastShadow; } + void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled); + void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene); void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene); bool needsFixupInScene() const; @@ -403,6 +407,8 @@ protected: bool _isVisible; uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL }; + bool _canCastShadow; + gpu::Buffers _blendedVertexBuffers; QVector > > _dilatedTextures; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index e8963c2e4e..ce4bf01dcf 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -218,7 +218,10 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende const auto setupOutput = task.addJob("ShadowSetup"); const auto queryResolution = setupOutput.getN(2); // Fetch and cull the items from the scene - static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask); + + // Enable models to not cast shadows (otherwise, models will always cast shadows) + static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask).withShadowCaster(); + const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterFilter, queryResolution).asVarying(); const auto shadowSelection = task.addJob("FetchShadowTree", fetchInput); const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying(); @@ -297,8 +300,14 @@ void RenderShadowSetup::setSlopeBias(int cascadeIndex, float value) { } void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { + // Abort all jobs if not casting shadows auto lightStage = renderContext->_scene->getStage(); assert(lightStage); + if (!lightStage->getCurrentKeyLight() || !lightStage->getCurrentKeyLight()->getCastShadows()) { + renderContext->taskFlow.abortTask(); + return; + } + // Cache old render args RenderArgs* args = renderContext->args; @@ -378,12 +387,13 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { auto lightStage = renderContext->_scene->getStage(); assert(lightStage); + // Cache old render args RenderArgs* args = renderContext->args; const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow && _cascadeIndexgetCascadeCount()) { - output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask); + output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask).withShadowCaster(); // Set the keylight render args auto& cascade = globalShadow->getCascade(_cascadeIndex); diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 7f127a558c..98b70c0c9f 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -38,7 +38,7 @@ class RenderShadowTaskConfig : public render::Task::Config::Persistent { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty) public: - RenderShadowTaskConfig() : render::Task::Config::Persistent(QStringList() << "Render" << "Engine" << "Shadows", false) {} + RenderShadowTaskConfig() : render::Task::Config::Persistent(QStringList() << "Render" << "Engine" << "Shadows", true) {} signals: void dirty(); diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index c53a2fa5bd..d6710238fb 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -42,25 +42,28 @@ -
+
+ +
@@ -293,7 +296,6 @@
-
BehaviorM @@ -365,8 +367,6 @@
- -
LightM @@ -400,7 +400,6 @@
-
ModelM @@ -484,7 +483,6 @@
-
ZoneM @@ -532,6 +530,10 @@
+
+ + +
Skybox @@ -676,7 +678,7 @@ min="-1000" max="50000" step="10"> -
+
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 2b29fbf041..4db9bd00c6 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -616,6 +616,8 @@ function loaded() { var elShape = document.getElementById("property-shape"); + var elCanCastShadow = document.getElementById("property-can-cast-shadow"); + var elLightSpotLight = document.getElementById("property-light-spot-light"); var elLightColor = document.getElementById("property-light-color"); var elLightColorRed = document.getElementById("property-light-color-red"); @@ -687,6 +689,8 @@ function loaded() { var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x"); var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y"); + var elZoneKeyLightCastShadows = document.getElementById("property-zone-key-light-cast-shadows"); + // Skybox var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit"); var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled"); @@ -844,7 +848,6 @@ function loaded() { elLocked.checked = properties.locked; - elName.value = properties.name; elVisible.checked = properties.visible; @@ -1011,6 +1014,12 @@ function loaded() { properties.color.green + "," + properties.color.blue + ")"; } + if (properties.type === "Model" || + properties.type === "Shape" || properties.type === "Box" || properties.type === "Sphere") { + + elCanCastShadow.checked = properties.canCastShadow; + } + if (properties.type === "Model") { elModelURL.value = properties.modelURL; elShapeType.value = properties.shapeType; @@ -1060,7 +1069,6 @@ function loaded() { elLightFalloffRadius.value = properties.falloffRadius.toFixed(1); elLightExponent.value = properties.exponent.toFixed(2); elLightCutoff.value = properties.cutoff.toFixed(2); - } else if (properties.type === "Zone") { // Key light elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit'); @@ -1076,6 +1084,8 @@ function loaded() { elZoneKeyLightDirectionX.value = properties.keyLight.direction.x.toFixed(2); elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2); + elZoneKeyLightCastShadows.checked = properties.keyLight.castShadows; + // Skybox elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit'); elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled'); @@ -1139,13 +1149,15 @@ function loaded() { // Show/hide sections as required showElements(document.getElementsByClassName('skybox-section'), elZoneSkyboxModeEnabled.checked); + showElements(document.getElementsByClassName('keylight-section'), elZoneKeyLightModeEnabled.checked); + showElements(document.getElementsByClassName('ambient-section'), elZoneAmbientLightModeEnabled.checked); + showElements(document.getElementsByClassName('haze-section'), elZoneHazeModeEnabled.checked); - } else if (properties.type === "PolyVox") { elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); @@ -1176,6 +1188,15 @@ function loaded() { elMaterialMappingRot.value = properties.materialMappingRot.toFixed(2); } + // Only these types can cast a shadow + if (properties.type === "Model" || + properties.type === "Shape" || properties.type === "Box" || properties.type === "Sphere") { + + showElements(document.getElementsByClassName('can-cast-shadow-section'), true); + } else { + showElements(document.getElementsByClassName('can-cast-shadow-section'), false); + } + if (properties.locked) { disableProperties(); elLocked.removeAttribute('disabled'); @@ -1432,6 +1453,8 @@ function loaded() { elShape.addEventListener('change', createEmitTextPropertyUpdateFunction('shape')); + elCanCastShadow.addEventListener('change', createEmitCheckedPropertyUpdateFunction('canCastShadow')); + elImageURL.addEventListener('change', createImageURLUpdateFunction('textures')); elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl')); @@ -1590,6 +1613,9 @@ function loaded() { elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction); elZoneKeyLightDirectionY.addEventListener('change', zoneKeyLightDirectionChangeFunction); + elZoneKeyLightCastShadows.addEventListener('change', + createEmitGroupCheckedPropertyUpdateFunction('keyLight', 'castShadows')); + // Skybox var skyboxModeChanged = createZoneComponentModeChangedFunction('skyboxMode', elZoneSkyboxModeInherit, elZoneSkyboxModeDisabled, elZoneSkyboxModeEnabled); From a66125fbb781af8faf8fa1cef32628974291e5b0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 1 Mar 2018 16:56:51 -0800 Subject: [PATCH 43/61] scriptablematerial -> scriptablemateriallayer --- .../src/graphics-scripting/Forward.h | 17 ++++-- .../GraphicsScriptingInterface.cpp | 26 ++++++--- .../graphics-scripting/ScriptableModel.cpp | 57 ++++++++++--------- .../src/graphics-scripting/ScriptableModel.h | 5 +- libraries/graphics/src/graphics/Material.h | 4 +- 5 files changed, 68 insertions(+), 41 deletions(-) diff --git a/libraries/graphics-scripting/src/graphics-scripting/Forward.h b/libraries/graphics-scripting/src/graphics-scripting/Forward.h index 650e4104e7..3d710b41b4 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/Forward.h +++ b/libraries/graphics-scripting/src/graphics-scripting/Forward.h @@ -39,7 +39,7 @@ namespace scriptable { class ScriptableMaterial { public: ScriptableMaterial() {} - ScriptableMaterial(const graphics::MaterialLayer& materialLayer); + ScriptableMaterial(const graphics::MaterialPointer& material); ScriptableMaterial(const ScriptableMaterial& material) { *this = material; } ScriptableMaterial& operator=(const ScriptableMaterial& material); @@ -64,9 +64,18 @@ namespace scriptable { QString occlusionMap; QString lightmapMap; QString scatteringMap; + }; + class ScriptableMaterialLayer { + public: + ScriptableMaterialLayer() {} + ScriptableMaterialLayer(const graphics::MaterialLayer& materialLayer) : material(materialLayer.material), priority(materialLayer.priority) {} + ScriptableMaterialLayer(const ScriptableMaterialLayer& materialLayer) { *this = materialLayer; } + ScriptableMaterialLayer& operator=(const ScriptableMaterialLayer& materialLayer); + + ScriptableMaterial material; quint16 priority; }; - typedef QHash> MultiMaterialMap; + typedef QHash> MultiMaterialMap; class ScriptableMeshBase : public QObject { Q_OBJECT @@ -92,7 +101,7 @@ namespace scriptable { WeakModelProviderPointer provider; QUuid objectID; // spatially nestable ID QVector meshes; - MultiMaterialMap materials; + MultiMaterialMap materialLayers; QVector materialNames; ScriptableModelBase(QObject* parent = nullptr) : QObject(parent) {} @@ -102,7 +111,7 @@ namespace scriptable { void append(const ScriptableMeshBase& mesh); void append(scriptable::WeakMeshPointer mesh); - void appendMaterial(const graphics::MaterialLayer& material, int shapeID, std::string materialName); + void appendMaterial(const graphics::MaterialLayer& materialLayer, int shapeID, std::string materialName); void appendMaterials(const std::unordered_map& materialsToAppend); void appendMaterialNames(const std::vector& names); // TODO: in future containers for these could go here diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index ff0170f07d..20b54b02c9 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -298,7 +298,8 @@ namespace { qRegisterMetaType(), qRegisterMetaType(), qRegisterMetaType(), - qRegisterMetaType>(), + qRegisterMetaType(), + qRegisterMetaType>(), qRegisterMetaType(), qRegisterMetaType(), }; @@ -338,11 +339,11 @@ namespace scriptable { ); } - QScriptValue qVectorScriptableMaterialToScriptValue(QScriptEngine* engine, const QVector& vector) { + QScriptValue qVectorScriptableMaterialLayerToScriptValue(QScriptEngine* engine, const QVector& vector) { return qScriptValueFromSequence(engine, vector); } - void qVectorScriptableMaterialFromScriptValue(const QScriptValue& array, QVector& result) { + void qVectorScriptableMaterialLayerFromScriptValue(const QScriptValue& array, QVector& result) { qScriptValueToSequence(array, result); } @@ -369,7 +370,6 @@ namespace scriptable { obj.setProperty("occlusionMap", material.occlusionMap); obj.setProperty("lightmapMap", material.lightmapMap); obj.setProperty("scatteringMap", material.scatteringMap); - obj.setProperty("priority", material.priority); return obj; } @@ -377,10 +377,21 @@ namespace scriptable { // No need to convert from QScriptValue to ScriptableMaterial } + QScriptValue scriptableMaterialLayerToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) { + QScriptValue obj = engine->newObject(); + obj.setProperty("material", scriptableMaterialToScriptValue(engine, materialLayer.material)); + obj.setProperty("priority", materialLayer.priority); + return obj; + } + + void scriptableMaterialLayerFromScriptValue(const QScriptValue &object, scriptable::ScriptableMaterialLayer& materialLayer) { + // No need to convert from QScriptValue to ScriptableMaterialLayer + } + QScriptValue multiMaterialMapToScriptValue(QScriptEngine* engine, const scriptable::MultiMaterialMap& map) { QScriptValue obj = engine->newObject(); for (auto key : map.keys()) { - obj.setProperty(key, qVectorScriptableMaterialToScriptValue(engine, map[key])); + obj.setProperty(key, qVectorScriptableMaterialLayerToScriptValue(engine, map[key])); } return obj; } @@ -405,7 +416,7 @@ namespace scriptable { void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) { qScriptRegisterSequenceMetaType>(engine); - qScriptRegisterSequenceMetaType>(engine); + qScriptRegisterSequenceMetaType>(engine); scriptable::registerQPointerMetaType(engine); scriptable::registerQPointerMetaType(engine); @@ -417,7 +428,8 @@ void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) { scriptable::registerDebugEnum(engine, gpu::DIMENSIONS); qScriptRegisterMetaType(engine, scriptable::scriptableMaterialToScriptValue, scriptable::scriptableMaterialFromScriptValue); - qScriptRegisterMetaType(engine, scriptable::qVectorScriptableMaterialToScriptValue, scriptable::qVectorScriptableMaterialFromScriptValue); + qScriptRegisterMetaType(engine, scriptable::scriptableMaterialLayerToScriptValue, scriptable::scriptableMaterialLayerFromScriptValue); + qScriptRegisterMetaType(engine, scriptable::qVectorScriptableMaterialLayerToScriptValue, scriptable::qVectorScriptableMaterialLayerFromScriptValue); qScriptRegisterMetaType(engine, scriptable::multiMaterialMapToScriptValue, scriptable::multiMaterialMapFromScriptValue); Q_UNUSED(metaTypeIds); diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp index a713d42012..c65764a225 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -42,29 +42,27 @@ scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const occlusionMap = material.occlusionMap; lightmapMap = material.lightmapMap; scatteringMap = material.scatteringMap; - priority = material.priority; return *this; } -scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer& materialLayer) : - name(materialLayer.material->getName().c_str()), - model(materialLayer.material->getModel().c_str()), - opacity(materialLayer.material->getOpacity()), - roughness(materialLayer.material->getRoughness()), - metallic(materialLayer.material->getMetallic()), - scattering(materialLayer.material->getScattering()), - unlit(materialLayer.material->isUnlit()), - emissive(materialLayer.material->getEmissive()), - albedo(materialLayer.material->getAlbedo()), - priority(materialLayer.priority) +scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPointer& material) : + name(material->getName().c_str()), + model(material->getModel().c_str()), + opacity(material->getOpacity()), + roughness(material->getRoughness()), + metallic(material->getMetallic()), + scattering(material->getScattering()), + unlit(material->isUnlit()), + emissive(material->getEmissive()), + albedo(material->getAlbedo()) { - auto map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP); + auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP); if (map && map->getTextureSource()) { emissiveMap = map->getTextureSource()->getUrl().toString(); } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP); if (map && map->getTextureSource()) { albedoMap = map->getTextureSource()->getUrl().toString(); if (map->useAlphaChannel()) { @@ -72,7 +70,7 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer } } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP); if (map && map->getTextureSource()) { if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) { metallicMap = map->getTextureSource()->getUrl().toString(); @@ -81,7 +79,7 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer } } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP); if (map && map->getTextureSource()) { if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) { roughnessMap = map->getTextureSource()->getUrl().toString(); @@ -90,7 +88,7 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer } } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP); if (map && map->getTextureSource()) { if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) { normalMap = map->getTextureSource()->getUrl().toString(); @@ -99,29 +97,36 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialLayer } } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP); if (map && map->getTextureSource()) { occlusionMap = map->getTextureSource()->getUrl().toString(); } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP); if (map && map->getTextureSource()) { lightmapMap = map->getTextureSource()->getUrl().toString(); } - map = materialLayer.material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP); + map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP); if (map && map->getTextureSource()) { scatteringMap = map->getTextureSource()->getUrl().toString(); } } +scriptable::ScriptableMaterialLayer& scriptable::ScriptableMaterialLayer::operator=(const scriptable::ScriptableMaterialLayer& materialLayer) { + material = materialLayer.material; + priority = materialLayer.priority; + + return *this; +} + scriptable::ScriptableModelBase& scriptable::ScriptableModelBase::operator=(const scriptable::ScriptableModelBase& other) { provider = other.provider; objectID = other.objectID; for (const auto& mesh : other.meshes) { append(mesh); } - materials = other.materials; + materialLayers = other.materialLayers; materialNames = other.materialNames; return *this; } @@ -135,7 +140,7 @@ scriptable::ScriptableModelBase::~ScriptableModelBase() { m.strongMesh.reset(); } meshes.clear(); - materials.clear(); + materialLayers.clear(); materialNames.clear(); } @@ -150,16 +155,16 @@ void scriptable::ScriptableModelBase::append(const ScriptableMeshBase& mesh) { meshes << mesh; } -void scriptable::ScriptableModelBase::appendMaterial(const graphics::MaterialLayer& material, int shapeID, std::string materialName) { - materials[QString::number(shapeID)].push_back(ScriptableMaterial(material)); - materials["mat::" + QString::fromStdString(materialName)].push_back(ScriptableMaterial(material)); +void scriptable::ScriptableModelBase::appendMaterial(const graphics::MaterialLayer& materialLayer, int shapeID, std::string materialName) { + materialLayers[QString::number(shapeID)].push_back(ScriptableMaterialLayer(materialLayer)); + materialLayers["mat::" + QString::fromStdString(materialName)].push_back(ScriptableMaterialLayer(materialLayer)); } void scriptable::ScriptableModelBase::appendMaterials(const std::unordered_map& materialsToAppend) { auto materialsToAppendCopy = materialsToAppend; for (auto& multiMaterial : materialsToAppendCopy) { while (!multiMaterial.second.empty()) { - materials[QString(multiMaterial.first.c_str())].push_back(ScriptableMaterial(multiMaterial.second.top())); + materialLayers[QString(multiMaterial.first.c_str())].push_back(ScriptableMaterialLayer(multiMaterial.second.top())); multiMaterial.second.pop(); } } diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index b1fe29447f..a1278132ca 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -28,7 +28,7 @@ namespace scriptable { Q_PROPERTY(QUuid objectID MEMBER objectID CONSTANT) Q_PROPERTY(glm::uint32 numMeshes READ getNumMeshes) Q_PROPERTY(ScriptableMeshes meshes READ getMeshes) - Q_PROPERTY(scriptable::MultiMaterialMap materials READ getMaterials) + Q_PROPERTY(scriptable::MultiMaterialMap materialLayers READ getMaterialLayers) Q_PROPERTY(QVector materialNames READ getMaterialNames) public: @@ -43,7 +43,7 @@ namespace scriptable { ScriptableMeshes getMeshes(); const ScriptableMeshes getConstMeshes() const; - scriptable::MultiMaterialMap getMaterials() { return materials; } + scriptable::MultiMaterialMap getMaterialLayers() { return materialLayers; } QVector getMaterialNames() { return materialNames; } public slots: @@ -60,4 +60,5 @@ namespace scriptable { Q_DECLARE_METATYPE(scriptable::ScriptableModelPointer) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(scriptable::ScriptableMaterial) +Q_DECLARE_METATYPE(scriptable::ScriptableMaterialLayer) Q_DECLARE_METATYPE(scriptable::MultiMaterialMap) diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index f34f68c04a..f9e83a0324 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -356,9 +356,9 @@ public: void setTextureTransforms(const Transform& transform); - const std::string& getName() { return _name; } + const std::string& getName() const { return _name; } - const std::string& getModel() { return _model; } + const std::string& getModel() const { return _model; } void setModel(const std::string& model) { _model = model; } protected: From d64a6ecda7ae493e7e7469778e824d81cea4b795 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Fri, 2 Mar 2018 16:56:06 -0300 Subject: [PATCH 44/61] Fix keyboard in Samsung Note 8 --- android/app/src/main/AndroidManifest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index efb7abbb93..5e93bdffa3 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -44,7 +44,6 @@ android:label="@string/app_name" android:screenOrientation="landscape" android:launchMode="singleTop" - android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" > From 01699e26a583223bfb02b2dd2f79302248a6e11e Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Fri, 2 Mar 2018 18:04:36 -0300 Subject: [PATCH 45/61] Fix QML debug info: print last QML loaded file instead of Desktop.qml --- libraries/ui/src/OffscreenUi.cpp | 4 +--- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 287978bbd3..76ea10c0ac 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -658,10 +658,8 @@ void OffscreenUi::createDesktop(const QUrl& url) { #ifdef DEBUG getSurfaceContext()->setContextProperty("DebugQML", QVariant(true)); - getSurfaceContext()->setContextProperty("DebugQMLFile", QVariant(url.toString())); -#else +#else getSurfaceContext()->setContextProperty("DebugQML", QVariant(false)); - getSurfaceContext()->setContextProperty("DebugQMLFile", QVariant("")); #endif load(url, [=](QQmlContext* context, QObject* newObject) { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 23a63c8f2a..1047fd1c7e 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -909,6 +909,12 @@ void OffscreenQmlSurface::loadInternal(const QUrl& qmlSource, bool createNewCont finalQmlSource = _qmlContext->resolvedUrl(qmlSource); } +#ifdef DEBUG + getSurfaceContext()->setContextProperty("DebugQMLFile", QVariant(finalQmlSource.toString())); +#else + getSurfaceContext()->setContextProperty("DebugQMLFile", QVariant("")); +#endif + auto targetContext = contextForUrl(finalQmlSource, parent, createNewContext); auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); if (qmlComponent->isLoading()) { From 76e4a5bef2c4524d467236e14797e163c7f62ff3 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Fri, 2 Mar 2018 18:46:14 -0300 Subject: [PATCH 46/61] Android - Change for test, this cast should avoid crashes due to SIGSEV in ToneMappingDeferred::run inputs.get1(). --- libraries/render-utils/src/RenderForwardTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 144671fca8..8bf060751f 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -100,7 +100,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // Lighting Buffer ready for tone mapping // Forward rendering on GLES doesn't support tonemapping to and from the same FBO, so we specify // the output FBO as null, which causes the tonemapping to target the blit framebuffer - const auto toneMappingInputs = ToneMappingDeferred::Inputs(framebuffer, nullptr).asVarying(); + const auto toneMappingInputs = ToneMappingDeferred::Inputs(framebuffer, static_cast(nullptr) ).asVarying(); task.addJob("ToneMapping", toneMappingInputs); // Layered Overlays From c091bc0bb3d27258ab3d7538b757f573a0d80546 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Mon, 5 Mar 2018 17:08:38 -0300 Subject: [PATCH 47/61] Fix warnings regarding float to double conversion --- .../src/input-plugins/TouchscreenVirtualPadDevice.cpp | 6 +++--- .../src/input-plugins/TouchscreenVirtualPadDevice.h | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 1774bbb4d3..bbe6102d21 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -68,7 +68,7 @@ void TouchscreenVirtualPadDevice::setupFixedCenter(VirtualPad::Manager& virtualP if (_extraBottomMargin == virtualPadManager.extraBottomMargin() && !force) return; // Our only criteria to decide a center change is the bottom margin _extraBottomMargin = virtualPadManager.extraBottomMargin(); - qreal margin = _screenDPI * 59 / 534; // 59px is for our 'base' of 534dpi (Pixel XL or Huawei Mate 9 Pro) + float margin = _screenDPI * 59 / 534; // 59px is for our 'base' of 534dpi (Pixel XL or Huawei Mate 9 Pro) QScreen* eventScreen = qApp->primaryScreen(); // do not call every time _fixedCenterPosition = glm::vec2( _fixedRadius + margin, eventScreen->size().height() - margin - _fixedRadius - _extraBottomMargin); @@ -104,12 +104,12 @@ glm::vec2 TouchscreenVirtualPadDevice::clippedPointInCircle(float radius, glm::v // quadtratic coefs of circumference and line intersection float qa = pow(m,2)+1; float qb = 2 * ( m * b - origin.x - origin.y * m ); - float qc = pow(origin.x, 2) - pow(radius,2) + b * b - 2 * b * origin.y + pow(origin.y, 2); + float qc = powf(origin.x, 2) - powf(radius,2) + b * b - 2 * b * origin.y + powf(origin.y, 2); float discr = qb * qb - 4 * qa * qc; float discrSign = deltaX>0?1.0:-1.0; - float finalX = (- qb + discrSign * sqrt(discr)) / (2 * qa); + float finalX = (- qb + discrSign * sqrtf(discr)) / (2 * qa); float finalY = m * finalX + b; return vec2(finalX, finalY); diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index f71490b0e3..4b95f3fbaf 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -62,9 +62,9 @@ public: const std::shared_ptr& getInputDevice() const { return _inputDevice; } protected: - qreal _lastPinchScale; - qreal _pinchScale; - qreal _screenDPI; + float _lastPinchScale; + float _pinchScale; + float _screenDPI; glm::vec2 _screenDPIScale; bool _validTouchLeft; glm::vec2 _firstTouchLeftPoint; @@ -78,8 +78,8 @@ protected: bool _fixedPosition; glm::vec2 _fixedCenterPosition; - qreal _fixedRadius; - qreal _fixedRadiusForCalc; + float _fixedRadius; + float _fixedRadiusForCalc; int _extraBottomMargin {0}; void touchLeftBegin(glm::vec2 touchPoint); From 0bb56d837d01e8105671b8919e6d567b5e172ec1 Mon Sep 17 00:00:00 2001 From: Cristian Luis Duarte Date: Mon, 5 Mar 2018 18:08:06 -0300 Subject: [PATCH 48/61] Android - Use a different variable to save the reported dpi by qt in TouchscreenVirtualPadDevice --- .../src/input-plugins/TouchscreenVirtualPadDevice.cpp | 3 ++- .../src/input-plugins/TouchscreenVirtualPadDevice.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index bbe6102d21..e323ed8fbc 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -43,10 +43,11 @@ void TouchscreenVirtualPadDevice::init() { _fixedPosition = true; // This should be config QScreen* eventScreen = qApp->primaryScreen(); - if (_screenDPI != eventScreen->physicalDotsPerInch()) { + if (_screenDPIProvided != eventScreen->physicalDotsPerInch()) { _screenWidthCenter = eventScreen->size().width() / 2; _screenDPIScale.x = (float)eventScreen->physicalDotsPerInchX(); _screenDPIScale.y = (float)eventScreen->physicalDotsPerInchY(); + _screenDPIProvided = eventScreen->physicalDotsPerInch(); _screenDPI = eventScreen->physicalDotsPerInch(); _fixedRadius = _screenDPI * 256 / 534; diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index 4b95f3fbaf..d5019da805 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -65,6 +65,7 @@ protected: float _lastPinchScale; float _pinchScale; float _screenDPI; + qreal _screenDPIProvided; glm::vec2 _screenDPIScale; bool _validTouchLeft; glm::vec2 _firstTouchLeftPoint; From 6cc36136bdb3fa3954f05ef960cd7c08dd2cef10 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 6 Mar 2018 12:34:21 -0800 Subject: [PATCH 49/61] Fix assert on interaction with stats and avatarinputs during UI setup --- interface/src/Application.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 53c24ccd5c..719fbf4ae8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2681,7 +2681,6 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("Overlays", &_overlays); surfaceContext->setContextProperty("Window", DependencyManager::get().data()); surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); - surfaceContext->setContextProperty("Stats", Stats::getInstance()); surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get().data()); @@ -2711,7 +2710,6 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor()); - surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); surfaceContext->setContextProperty("Selection", DependencyManager::get().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get().data()); surfaceContext->setContextProperty("Wallet", DependencyManager::get().data()); @@ -2726,6 +2724,9 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { void Application::onDesktopRootItemCreated(QQuickItem* rootItem) { Stats::show(); AvatarInputs::show(); + auto surfaceContext = DependencyManager::get()->getSurfaceContext(); + surfaceContext->setContextProperty("Stats", Stats::getInstance()); + surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); } void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { From a23884d0e03407841616b4d0bfc6109cc961bcac Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 2 Mar 2018 17:33:28 -0800 Subject: [PATCH 50/61] Prevent crash during long backup web requests --- domain-server/src/DomainServer.cpp | 54 ++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d2ef1a4156..178345a144 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1937,6 +1937,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; + QPointer connectionPtr { connection }; + auto nodeList = DependencyManager::get(); auto getSetting = [this](QString keyPath, QVariant value) -> bool { @@ -2120,30 +2122,38 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return true; } else if (url.path() == URI_API_BACKUPS) { auto deferred = makePromise("getAllBackupsAndStatus"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonDocument docJSON(QJsonObject::fromVariantMap(result)); - connection->respond(HTTPConnection::StatusCode200, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); + connectionPtr->respond(HTTPConnection::StatusCode200, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); _contentManager->getAllBackupsAndStatus(deferred); return true; } else if (url.path().startsWith(URI_API_BACKUPS_ID)) { auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length()); auto deferred = makePromise("consolidateBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); if (success) { auto path = result["backupFilePath"].toString(); auto file { std::unique_ptr(new QFile(path)) }; if (file->open(QIODevice::ReadOnly)) { - connection->respond(HTTPConnection::StatusCode200, std::move(file)); + connectionPtr->respond(HTTPConnection::StatusCode200, std::move(file)); } else { qCritical(domain_server) << "Unable to load consolidated backup at:" << path << result; - connection->respond(HTTPConnection::StatusCode500, "Error opening backup"); + connectionPtr->respond(HTTPConnection::StatusCode500, "Error opening backup"); } } else { - connection->respond(HTTPConnection::StatusCode400); + connectionPtr->respond(HTTPConnection::StatusCode400); } }); _contentManager->consolidateBackup(deferred, id); @@ -2264,12 +2274,16 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } else if (uploadedFilename.endsWith(".zip", Qt::CaseInsensitive)) { auto deferred = makePromise("recoverFromUploadedBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); rootJSON["success"] = success; QJsonDocument docJSON(rootJSON); - connection->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), + connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); @@ -2297,12 +2311,16 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } auto deferred = makePromise("createManualBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); rootJSON["success"] = success; QJsonDocument docJSON(rootJSON); - connection->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), + connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); _contentManager->createManualBackup(deferred, it.value()); @@ -2322,12 +2340,16 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } else if (url.path().startsWith(URI_API_BACKUPS_RECOVER)) { auto id = url.path().mid(QString(URI_API_BACKUPS_RECOVER).length()); auto deferred = makePromise("recoverFromBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); rootJSON["success"] = success; QJsonDocument docJSON(rootJSON); - connection->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), + connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); _contentManager->recoverFromBackup(deferred, id); @@ -2423,12 +2445,16 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url if (url.path().startsWith(URI_API_BACKUPS_ID)) { auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length()); auto deferred = makePromise("deleteBackup"); - deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) { + deferred->then([connectionPtr, JSON_MIME_TYPE](QString error, QVariantMap result) { + if (!connectionPtr) { + return; + } + QJsonObject rootJSON; auto success = result["success"].toBool(); rootJSON["success"] = success; QJsonDocument docJSON(rootJSON); - connection->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), + connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); _contentManager->deleteBackup(deferred, id); From 48aa862c16799a054d5c8c3bd1ddb026990006e4 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Mar 2018 13:52:42 -0800 Subject: [PATCH 51/61] Show Connection instructions in Send Money when 0 connections --- .../commerce/wallet/sendMoney/SendMoney.qml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index 07c85a7f6a..5d03296823 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -398,6 +398,7 @@ Item { // Item { id: filterBarContainer; + visible: !connectionInstructions.visible; // Size height: 40; // Anchors @@ -495,6 +496,78 @@ Item { } } } + + // "Make a Connection" instructions + Rectangle { + id: connectionInstructions; + visible: connectionsModel.count === 0 && !connectionsLoading.visible; + anchors.fill: parent; + color: "white"; + + RalewayRegular { + id: makeAConnectionText; + // Properties + text: "Make a Connection"; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 20; + anchors.left: parent.left; + anchors.right: parent.right; + // Text Size + size: 24; + // Text Positioning + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter; + // Style + color: hifi.colors.darkGray; + } + + Image { + id: connectionImage; + source: "qrc:/icons/connection.svg"; + width: 150; + height: 150; + mipmap: true; + // Anchors + anchors.top: makeAConnectionText.bottom; + anchors.topMargin: 15; + anchors.horizontalCenter: parent.horizontalCenter; + } + + FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } + Text { + id: connectionHelpText; + // Anchors + anchors.top: connectionImage.bottom; + anchors.topMargin: 15; + anchors.left: parent.left + anchors.leftMargin: 40; + anchors.right: parent.right + anchors.rightMargin: 40; + // Text alignment + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHLeft + // Style + font.pixelSize: 18; + font.family: ralewayRegular.name + color: hifi.colors.darkGray + wrapMode: Text.Wrap + textFormat: Text.StyledText; + property string instructions: + "When you meet someone you want to remember later, you can connect with a handshake:

" + property string hmdMountedInstructions: + "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.
" + + "3. After about 3 seconds, you're connected!" + property string hmdNotMountedInstructions: + "1. Press and hold the 'x' key to extend your arm.
" + + "2. Once the other person puts their hand onto yours, you'll see your connection form.
" + + "3. After about 3 seconds, you're connected!"; + // Text + text: + HMD.mounted ? instructions + hmdMountedInstructions : instructions + hmdNotMountedInstructions + } + } } } } From a83b54e10dd63f312d143b6b9ac1b850410f7900 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 6 Mar 2018 13:52:41 -0800 Subject: [PATCH 52/61] fix for getSetting QVariant ref in DomainServer --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d2ef1a4156..cf99ca4344 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1939,7 +1939,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url auto nodeList = DependencyManager::get(); - auto getSetting = [this](QString keyPath, QVariant value) -> bool { + auto getSetting = [this](QString keyPath, QVariant& value) -> bool { value = _settingsManager.valueForKeyPath(keyPath); if (!value.isValid()) { From 05e9aa52c90fc07786aed06a2579da8634cdce9e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 6 Mar 2018 16:22:54 -0800 Subject: [PATCH 53/61] Moved can-cast-shadow checkbox to behaviour section. --- scripts/system/html/entityProperties.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index d6710238fb..7389442649 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -61,10 +61,6 @@ -
- - -
@@ -317,6 +313,10 @@
+
+ + +
From 17c12fde9c66ca0fd723b478eee7aa4b93fab588 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 6 Mar 2018 16:32:04 -0800 Subject: [PATCH 54/61] Fix for HandshakeRequest logic --- libraries/networking/src/udt/Connection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 77ed589e0b..b34c05106f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -578,6 +578,7 @@ void Connection::processControl(ControlPacketPointer controlPacket) { #ifdef UDT_CONNECTION_DEBUG qCDebug(networking) << "Got handshake request, stopping SendQueue"; #endif + _hasReceivedHandshakeACK = false; stopSendQueue(); } break; From 243e79df4aa44291f70d378bd668a7ff9ae60ecd Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Tue, 6 Mar 2018 21:59:59 -0300 Subject: [PATCH 55/61] Fix merge of radar.js --- scripts/system/+android/radar.js | 114 ------------------------------- 1 file changed, 114 deletions(-) diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 665ca26a12..84fb66403f 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -921,7 +921,6 @@ function saveAvatarData(QUuid) { if (avatarsData[QUuid] != undefined) { avatarsData[QUuid].position = avat.position; } else { -<<<<<<< HEAD var avatarIcon = Overlays.addOverlay("circle3d", { color: uniqueColor.convertHexToRGB(uniqueColor.getColor(QUuid)), dimensions: ICON_ENTITY_DEFAULT_DIMENSIONS, @@ -930,20 +929,6 @@ function saveAvatarData(QUuid) { outerRadius: 2, isSolid: true, visible: false -======= - var avatarIcon = Overlays.addOverlay("image3d", { - subImage : { - x : 0, - y : 0, - width : 150, - height : 142 - }, - url : getAvatarIconForUser(QUuid), - dimensions : ICON_ENTITY_DEFAULT_DIMENSIONS, - visible : false, - ignoreRayIntersection : false, - orientation : Quat.fromPitchYawRollDegrees(-90, 0, 0) ->>>>>>> upstream/master }); var needRefresh = !avat || !avat.displayName; @@ -951,7 +936,6 @@ function saveAvatarData(QUuid) { : "Unknown"; var textWidth = displayName.length * AVATAR_DISPLAY_NAME_CHAR_WIDTH; var avatarName = Overlays.addOverlay("text", { -<<<<<<< HEAD width: textWidth, height: AVATAR_DISPLAY_NAME_HEIGHT, color: { red: 255, green: 255, blue: 255}, @@ -961,28 +945,6 @@ function saveAvatarData(QUuid) { visible: false, text: displayName, textAlignCenter: true -======= - width : textWidth, - height : AVATAR_DISPLAY_NAME_HEIGHT, - color : { - red : 255, - green : 255, - blue : 255 - }, - backgroundAlpha : 0.0, - textRaiseColor : { - red : 0, - green : 0, - blue : 0 - }, - font : { - size : 68, - bold : true - }, - visible : false, - text : displayName, - textAlignCenter : true ->>>>>>> upstream/master }); avatarsIcons.push(avatarIcon); avatarsNames.push(avatarName); @@ -1050,7 +1012,6 @@ function distanceForCameraHeight(h) { return 5; } function renderMyAvatarIcon() { -<<<<<<< HEAD var commonY = Camera.position.y - distanceForCameraHeight(Camera.position.y); var iconPos = findLineToHeightIntersectionCoords( MyAvatar.position.x, MyAvatar.position.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, @@ -1058,17 +1019,6 @@ function renderMyAvatarIcon() { Camera.position.x, Camera.position.y, Camera.position.z, commonY); if (!iconPos) { printd("avatarmy icon pos null"); return;} -======= - var iconPos = findLineToHeightIntersectionCoords(MyAvatar.position.x, - MyAvatar.position.y + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, - MyAvatar.position.z, Camera.position.x, Camera.position.y, - Camera.position.z, Camera.position.y - - RADAR_CAMERA_DISTANCE_TO_ICONS); - if (!iconPos) { - printd("avatarmy icon pos null"); - return; - } ->>>>>>> upstream/master var iconDimensions = avatarIconPlaneDimensions(); var avatarPos = MyAvatar.position; @@ -1084,7 +1034,6 @@ function renderMyAvatarIcon() { var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) / (borderPoints[1].z - borderPoints[0].z); -<<<<<<< HEAD if (!myAvatarIcon && MyAvatar.SELF_ID) { myAvatarIcon = Overlays.addOverlay("circle3d", { color: uniqueColor.convertHexToRGB(uniqueColor.getColor(MyAvatar.SELF_ID)), @@ -1094,27 +1043,11 @@ function renderMyAvatarIcon() { outerRadius: 2, isSolid: true, visible: false -======= - if (!myAvatarIcon && MyAvatar.sessionUUID) { - myAvatarIcon = Overlays.addOverlay("image3d", { - subImage : { - x : 0, - y : 0, - width : 150, - height : 142 - }, - url : getAvatarIconForUser(MyAvatar.sessionUUID), - dimensions : ICON_ENTITY_DEFAULT_DIMENSIONS, - visible : false, - ignoreRayIntersection : false, - orientation : Quat.fromPitchYawRollDegrees(-90, 0, 0) ->>>>>>> upstream/master }); } if (!myAvatarName) { myAvatarName = Overlays.addOverlay("text", { -<<<<<<< HEAD width: 100, height: AVATAR_DISPLAY_NAME_HEIGHT, textAlignCenter: true, @@ -1125,29 +1058,6 @@ function renderMyAvatarIcon() { visible: false, text: "Me" }); -======= - width : 40, - height : AVATAR_DISPLAY_NAME_HEIGHT, - textAlignCenter : true, - color : { - red : 255, - green : 255, - blue : 255 - }, - backgroundAlpha : 0.0, - font : { - size : 68, - bold : true - }, - textRaiseColor : { - red : 0, - green : 0, - blue : 0 - }, - visible : false, - text : "Me" - }); ->>>>>>> upstream/master } if (myAvatarIcon) { @@ -1209,7 +1119,6 @@ function renderAllOthersAvatarIcons() { avatarPos = AvatarList.getAvatar(QUuid).position; var cameraPos = Camera.position; -<<<<<<< HEAD var p1 = findLineToHeightIntersectionCoords(avatarPos.x, avatarPos.y, avatarPos.z, cameraPos.x, cameraPos.y, cameraPos.z, commonY); @@ -1222,29 +1131,6 @@ function renderAllOthersAvatarIcons() { Camera.position.x, Camera.position.y, Camera.position.z, commonY); if (!iconPos) { print ("avatar icon pos bad for " + QUuid); continue; } -======= - var p1 = findLineToHeightIntersectionCoords(avatarPos.x, - avatarPos.y, avatarPos.z, cameraPos.x, cameraPos.y, - cameraPos.z, commonY); - - var x = (p1.x - borderPoints[0].x) * (Window.innerWidth) - / (borderPoints[1].x - borderPoints[0].x); - var y = (p1.z - borderPoints[0].z) * (Window.innerHeight) - / (borderPoints[1].z - borderPoints[0].z); - - if (avatarsData[QUuid].icon != undefined) { - var iconPos = findLineToHeightIntersectionCoords( - avatarPos.x, - avatarPos.y - + RADAR_ICONS_APPARENT_DISTANCE_TO_AVATAR_BASE, - avatarPos.z, Camera.position.x, Camera.position.y, - Camera.position.z, Camera.position.y - - RADAR_CAMERA_DISTANCE_TO_ICONS); - if (!iconPos) { - print("avatar icon pos bad for " + QUuid); - continue; - } ->>>>>>> upstream/master if (avatarsData[QUuid].needRefresh) { var avat = AvatarList.getAvatar(QUuid); if (avat && avat.displayName) { From 866bec0b34da3dc8da1c7ffd741d08e86ed919be Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 7 Mar 2018 02:36:07 +0100 Subject: [PATCH 56/61] rule -> role --- interface/src/avatar/MyAvatar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fa5206e128..d48d059bed 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -346,7 +346,7 @@ public: * restoreRoleAnimation() is used to restore a specified animation role's default animation clip. If you have not specified an override animation * for the specified role, this function will have no effect. * @function MyAvatar.restoreRoleAnimation - * @param rule {string} The animation role clip to restore + * @param role {string} The animation role clip to restore */ Q_INVOKABLE void restoreRoleAnimation(const QString& role); From 923c81ae2863f7154270f85a08369b4dff4e6c7c Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Mar 2018 17:38:27 -0800 Subject: [PATCH 57/61] Swap order of the ZoneRendererJob with DrawLocalLights to fix the local lights --- libraries/render-utils/src/RenderDeferredTask.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f262307944..50620bfcce 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -142,13 +142,12 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN(0); const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN(1); - + // Clear Light, Haze and Skybox Stages and render zones from the general metas bucket + const auto zones = task.addJob("ZoneRenderer", metas); + // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. task.addJob("DrawLight", lights); - // Filter zones from the general metas bucket - const auto zones = task.addJob("ZoneRenderer", metas); - // Light Clustering // Create the cluster grid of lights, cpu job for now const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).asVarying(); From 2d448d7208ae90a8bdea3ba45d30865b78f80864 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 7 Mar 2018 10:02:35 -0800 Subject: [PATCH 58/61] tablet scale and position changes --- interface/src/Application.cpp | 2 +- scripts/system/libraries/WebTablet.js | 5 +++-- scripts/system/libraries/utils.js | 4 ++-- scripts/system/tablet-ui/tabletUI.js | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 35b7de7284..36c661f8be 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -891,7 +891,7 @@ Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); Setting::Handle sessionRunTime{ "sessionRunTime", 0 }; -const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 100.0f; +const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 70.0f; const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f; const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true; const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false; diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index a34191b951..511bb6989e 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -46,8 +46,9 @@ function calcSpawnInfo(hand, landscape) { var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position; var headRot = (HMD.active && Camera.mode === "first person") ? HMD.orientation : Camera.orientation; - - var forward = Quat.getForward(Quat.cancelOutRollAndPitch(headRot)); + var dominantHandRotation = MyAvatar.getDominantHand() === "right" ? -20 : 20; + var offsetRotation = Quat.fromPitchYawRollDegrees(0, dominantHandRotation, 0); + var forward = Vec3.multiplyQbyV(offsetRotation, Quat.getForward(Quat.cancelOutRollAndPitch(headRot))); var FORWARD_OFFSET = 0.5 * MyAvatar.sensorToWorldScale; finalPosition = Vec3.sum(headPos, Vec3.multiply(FORWARD_OFFSET, forward)); var orientation = Quat.lookAt({x: 0, y: 0, z: 0}, forward, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.UNIT_Y)); diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index 442a9f6d24..6afde85c29 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -356,7 +356,7 @@ getTabletWidthFromSettings = function () { var DEFAULT_TABLET_WIDTH = 0.4375; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var toolbarMode = tablet.toolbarMode; - var DEFAULT_TABLET_SCALE = 100; + var DEFAULT_TABLET_SCALE = 70; var tabletScalePercentage = DEFAULT_TABLET_SCALE; if (!toolbarMode) { if (HMD.active) { @@ -441,4 +441,4 @@ getMainTabletIDs = function () { tabletIDs.push(HMD.homeButtonID); } return tabletIDs; -}; \ No newline at end of file +}; diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 100d0e82ee..ee3dab7308 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -19,11 +19,11 @@ var tabletRezzed = false; var activeHand = null; var DEFAULT_WIDTH = 0.4375; - var DEFAULT_TABLET_SCALE = 100; + var DEFAULT_TABLET_SCALE = 70; var preMakeTime = Date.now(); var validCheckTime = Date.now(); var debugTablet = false; - var tabletScalePercentage = 100.0; + var tabletScalePercentage = 70.0; UIWebTablet = null; var MSECS_PER_SEC = 1000.0; var MUTE_MICROPHONE_MENU_ITEM = "Mute Microphone"; From 0aacdcd5580f4d63530023d694d2c9a8ec5c72a0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 7 Mar 2018 13:33:39 -0800 Subject: [PATCH 59/61] docs --- .../graphics-scripting/src/graphics-scripting/Forward.h | 6 ++++++ .../src/graphics-scripting/ScriptableModel.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/libraries/graphics-scripting/src/graphics-scripting/Forward.h b/libraries/graphics-scripting/src/graphics-scripting/Forward.h index 3d710b41b4..ed8e96a12f 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/Forward.h +++ b/libraries/graphics-scripting/src/graphics-scripting/Forward.h @@ -65,6 +65,12 @@ namespace scriptable { QString lightmapMap; QString scatteringMap; }; + + /**jsdoc + * @typedef {object} Graphics.MaterialLayer + * @property {Material} material - This layer's material. + * @property {number} priority - The priority of this layer. If multiple materials are applied to a mesh part, only the highest priority layer is used. + */ class ScriptableMaterialLayer { public: ScriptableMaterialLayer() {} diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index a1278132ca..ac0b7b9623 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -21,6 +21,8 @@ namespace scriptable { * @property {Uuid} objectID - UUID of corresponding inworld object (if model is associated) * @property {number} numMeshes - The number of submeshes contained in the model. * @property {Graphics.Mesh[]} meshes - Array of submesh references. + * @property {Object.} materialLayers - Map of materials layer lists. You can look up a material layer list by mesh part number or by material name. + * @property {string[]} materialNames - Array of all the material names used by the mesh parts of this model, in order (e.g. materialNames[0] is the name of the first mesh part's material). */ class ScriptableModel : public ScriptableModelBase { From d1b87b31167019342a0388849e1c85686a5d3ad4 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Mar 2018 12:14:42 -0800 Subject: [PATCH 60/61] Added missing avatar shadows. --- interface/src/avatar/MyAvatar.cpp | 12 ++++++------ interface/src/avatar/MyAvatar.h | 2 -- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b6fa3fde96..a5e24b8707 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1115,6 +1115,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { void MyAvatar::setEnableMeshVisible(bool isEnabled) { _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + _skeletonModel->setCanCastShadow(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { @@ -1467,6 +1468,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { int skeletonModelChangeCount = _skeletonModelChangeCount; Avatar::setSkeletonModelURL(skeletonModelURL); _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + _skeletonModel->setCanCastShadow(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); _headBoneSet.clear(); _cauterizationNeedsUpdate = true; @@ -1848,12 +1850,6 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved); } -void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) { - if (model->isActive() && model->isRenderable()) { - model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE, true); - } -} - void MyAvatar::initHeadBones() { int neckJointIndex = -1; if (_skeletonModel->isLoaded()) { @@ -2043,8 +2039,12 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { _attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) { + _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + + _attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(), + render::ItemKey::TAG_BITS_NONE, true); } } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fa5206e128..2615f8fa0f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -681,8 +681,6 @@ private: // These are made private for MyAvatar so that you will use the "use" methods instead virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; - void setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visiblity); - virtual void updatePalms() override {} void lateUpdatePalms(); From a703b5a3b54dd658be2d15bf18ffe6e66165448e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Mar 2018 12:15:26 -0800 Subject: [PATCH 61/61] Added check to correct crashing when selecting ambient occlusion from menu. --- libraries/render-utils/src/DeferredLightingEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 665e767c7c..78bc3ba195 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -492,7 +492,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, deferredFramebuffer->getPrimaryDepthTexture()); // FIXME: Different render modes should have different tasks - if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && deferredLightingEffect->isAmbientOcclusionEnabled()) { + if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && deferredLightingEffect->isAmbientOcclusionEnabled() && ambientOcclusionFramebuffer) { batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, ambientOcclusionFramebuffer->getOcclusionTexture()); } else { // need to assign the white texture if ao is off