From 754f55e091358cd715c3fc6bcf56a5542cfd253f Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 23 Jan 2019 20:33:05 -0800 Subject: [PATCH 01/23] Include your own NFS items in marketplace listings, so you can stock up. --- scripts/system/html/js/marketplacesInject.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index f1931192e4..aafdc65606 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -402,11 +402,15 @@ purchaseButton.attr('href', '#'); var cost = $('.item-cost').text(); var costInt = parseInt(cost, 10); + // One of 'invalidated', 'not for sale', 'sold out', or 'available' var availability = $.trim($('.item-availability').text()); if (limitedCommerce && (costInt > 0)) { availability = ''; } - if (availability === 'available') { + var isUpdating = window.location.href.indexOf('edition=') > -1; + // NFS only shows for artist stocking inventory + var isBuyEnabled = ('available' === availability) || isUpdating || ('not for sale' === availability); + if (isBuyEnabled) { purchaseButton.css({ "background": "linear-gradient(#00b4ef, #0093C5)", "color": "#FFF", @@ -422,11 +426,11 @@ }); } - var type = $('.item-type').text(); - var isUpdating = window.location.href.indexOf('edition=') > -1; var urlParams = new URLSearchParams(window.location.search); if (isUpdating) { purchaseButton.html('UPDATE FOR FREE'); + } else if (availability == 'not for sale') { + purchaseButton.html("Free artist's stock to inventory"); } else if (availability !== 'available') { purchaseButton.html('UNAVAILABLE ' + (availability ? ('(' + availability + ')') : '')); } else if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) { @@ -435,7 +439,7 @@ } purchaseButton.on('click', function () { - if ('available' === availability || isUpdating) { + if (isBuyEnabled) { buyButtonClicked(window.location.pathname.split("/")[3], "itemPage", urlParams.get('edition')); From bede1d9b00b214f890c8cd1c389a31a32c33dbd4 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 25 Jan 2019 11:50:46 -0800 Subject: [PATCH 02/23] make nfs label fit in button --- scripts/system/html/js/marketplacesInject.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index aafdc65606..d27387c6e8 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -258,12 +258,13 @@ priceElement.text() === 'not for sale') { available = false; priceElement.css({ - "padding": "3px 5px 10px 5px", + "padding": "3px 5px", "height": "40px", + "width": "100px", "background": "linear-gradient(#a2a2a2, #fefefe)", "color": "#000", "font-weight": "600", - "line-height": "34px" + "line-height": "20px" }); } else { priceElement.css({ From 52a43ca4cdfbb4dcbfca484beff662413edae5ce Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 25 Jan 2019 14:09:00 -0800 Subject: [PATCH 03/23] support artist's stocking to inventory --- .../qml/hifi/commerce/checkout/Checkout.qml | 55 ++++++++++++------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index c76f5a428a..2c2d23964b 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -33,15 +33,19 @@ Rectangle { property bool balanceReceived: false; property bool availableUpdatesReceived: false; property bool itemInfoReceived: false; + property bool dataReady: itemInfoReceived && ownershipStatusReceived && balanceReceived && availableUpdatesReceived; property string baseItemName: ""; property string itemName; property string itemId; property string itemHref; property string itemAuthor; property int itemEdition: -1; + property bool hasSomethingToTradeIn: alreadyOwned && (itemEdition > 0); // i.e., don't trade in your artist's proof + property bool isTradingIn: isUpdating && hasSomethingToTradeIn; + property bool isStocking: availability === 'not for sale' && creator === Account.username; property string certificateId; property double balanceAfterPurchase; - property bool alreadyOwned: false; + property bool alreadyOwned: false; // Including proofs property int itemPrice: -1; property bool isCertified; property string itemType: "unknown"; @@ -56,6 +60,8 @@ Rectangle { property string referrer; property bool isInstalled; property bool isUpdating; + property string availability: "available"; + property string creator: ""; property string baseAppURL; property int currentUpdatesPage: 1; // Style @@ -454,10 +460,10 @@ Rectangle { height: 30; width: itemPriceTextLabel.width + itemPriceText.width + 20; - // "HFC" balance label + // "HFC" label HiFiGlyphs { id: itemPriceTextLabel; - visible: !(root.isUpdating && root.itemEdition > 0) && (root.itemPrice > 0); + visible: !isTradingIn && (root.itemPrice > 0); text: hifi.glyphs.hfc; // Size size: 30; @@ -473,9 +479,11 @@ Rectangle { } FiraSansSemiBold { id: itemPriceText; - text: (root.isUpdating && root.itemEdition > 0) ? "FREE\nUPDATE" : ((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE")); + text: isTradingIn ? "FREE\nUPDATE" : + (isStocking ? "Free for creator" : + ((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE"))); // Text size - size: (root.isUpdating && root.itemEdition > 0) ? 20 : 26; + size: isTradingIn ? 20 : 26; // Anchors anchors.top: parent.top; anchors.right: parent.right; @@ -571,7 +579,7 @@ Rectangle { // "View in Inventory" button HifiControlsUit.Button { id: viewInMyPurchasesButton; - visible: false; + visible: isCertified && dataReady && (isUpdating ? !hasSomethingToTradeIn : alreadyOwned); color: hifi.buttons.blue; colorScheme: hifi.colorSchemes.light; anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top; @@ -592,8 +600,8 @@ Rectangle { // "Buy" button HifiControlsUit.Button { id: buyButton; - visible: !((root.itemType === "avatar" || root.itemType === "app") && viewInMyPurchasesButton.visible) - enabled: (root.balanceAfterPurchase >= 0 && ownershipStatusReceived && balanceReceived && availableUpdatesReceived) || (!root.isCertified) || root.isUpdating; + visible: isTradingIn || !alreadyOwned || isStocking || !(root.itemType === "avatar" || root.itemType === "app"); + enabled: (root.balanceAfterPurchase >= 0 && dataReady) || (!root.isCertified) || root.isUpdating; color: viewInMyPurchasesButton.visible ? hifi.buttons.white : hifi.buttons.blue; colorScheme: hifi.colorSchemes.light; anchors.top: viewInMyPurchasesButton.visible ? viewInMyPurchasesButton.bottom : @@ -602,10 +610,15 @@ Rectangle { height: 50; anchors.left: parent.left; anchors.right: parent.right; - text: (root.isUpdating && root.itemEdition > 0) ? "CONFIRM UPDATE" : (((root.isCertified) ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ? - ((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") : "--") : "Get Item")); + text: isTradingIn ? + "CONFIRM UPDATE" : + (((root.isCertified) ? + (dataReady ? + ((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") : + "--") : + "Get Item")); onClicked: { - if (root.isUpdating && root.itemEdition > 0) { + if (isTradingIn) { // If we're updating an app, the existing app needs to be uninstalled. // This call will fail/return `false` if the app isn't installed, but that's OK. if (root.itemType === "app") { @@ -1063,7 +1076,11 @@ Rectangle { buyButton.color = hifi.buttons.red; root.shouldBuyWithControlledFailure = true; } else { - buyButton.text = (root.isCertified ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ? (root.alreadyOwned ? "Buy Another" : "Buy"): "--") : "Get Item"); + buyButton.text = (root.isCertified ? + (dataReady ? + (root.alreadyOwned ? "Buy Another" : "Buy") : + "--") : + "Get Item"); buyButton.color = hifi.buttons.blue; root.shouldBuyWithControlledFailure = false; } @@ -1091,6 +1108,8 @@ Rectangle { root.itemPrice = result.data.cost; root.itemAuthor = result.data.creator; root.itemType = result.data.item_type || "unknown"; + root.availability = result.data.availability; + root.creator = result.data.creator; if (root.itemType === "unknown") { root.itemHref = result.data.review_url; } else { @@ -1139,7 +1158,7 @@ Rectangle { signal sendToScript(var message); function canBuyAgain() { - return (root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet" || root.itemType === "unknown"); + return root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet" || root.itemType === "unknown" || isStocking; } function handleContentSets() { @@ -1185,29 +1204,23 @@ Rectangle { function refreshBuyUI() { if (root.isCertified) { - if (root.ownershipStatusReceived && root.balanceReceived && root.availableUpdatesReceived) { + if (dataReady) { buyText.text = ""; // If the user IS on the checkout page for the updated version of an owned item... if (root.isUpdating) { // If the user HAS already selected a specific edition to update... - if (root.itemEdition > 0) { + if (hasSomethingToTradeIn) { buyText.text = "By pressing \"Confirm Update\", you agree to trade in your old item for the updated item that replaces it."; buyTextContainer.color = "#FFFFFF"; buyTextContainer.border.color = "#FFFFFF"; // Else if the user HAS NOT selected a specific edition to update... } else { - viewInMyPurchasesButton.visible = true; - handleBuyAgainLogic(); } // If the user IS NOT on the checkout page for the updated verison of an owned item... // (i.e. they are checking out an item "normally") } else { - if (root.alreadyOwned) { - viewInMyPurchasesButton.visible = true; - } - handleBuyAgainLogic(); } } else { From 49a3a13d5721f38777f1685ccc828fe42d76fa80 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 25 Jan 2019 14:13:58 -0800 Subject: [PATCH 04/23] use space a bit better --- .../resources/qml/hifi/commerce/checkout/Checkout.qml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 2c2d23964b..700459032f 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -440,7 +440,7 @@ Rectangle { anchors.top: parent.top; anchors.left: itemPreviewImage.right; anchors.leftMargin: 12; - anchors.right: itemPriceContainer.left; + anchors.right: parent.right; anchors.rightMargin: 8; height: 30; // Style @@ -455,10 +455,11 @@ Rectangle { Item { id: itemPriceContainer; // Anchors - anchors.top: parent.top; - anchors.right: parent.right; + anchors.top: itemNameText.bottom; + anchors.topMargin: 8; + anchors.left: itemNameText.left; height: 30; - width: itemPriceTextLabel.width + itemPriceText.width + 20; + width: itemPriceText.width + 20; // "HFC" label HiFiGlyphs { From 3026fd625a5f0242fc8b129071e4374f59e289a8 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 14 Feb 2019 18:52:50 +0100 Subject: [PATCH 05/23] Avatar Doctor --- .../avatarPackager/AvatarDoctorDiagnose.qml | 125 ++++++++++++++++++ .../AvatarDoctorErrorReport.qml | 112 ++++++++++++++++ .../hifi/avatarPackager/AvatarPackagerApp.qml | 32 ++++- .../avatarPackager/AvatarPackagerState.qml | 2 + .../hifi/avatarPackager/AvatarProjectCard.qml | 17 ++- interface/src/avatar/AvatarDoctor.cpp | 101 ++++++++++++++ interface/src/avatar/AvatarDoctor.h | 50 +++++++ interface/src/avatar/AvatarPackager.cpp | 11 +- interface/src/avatar/AvatarPackager.h | 11 +- interface/src/avatar/AvatarProject.cpp | 6 + interface/src/avatar/AvatarProject.h | 9 ++ 11 files changed, 468 insertions(+), 8 deletions(-) create mode 100644 interface/resources/qml/hifi/avatarPackager/AvatarDoctorDiagnose.qml create mode 100644 interface/resources/qml/hifi/avatarPackager/AvatarDoctorErrorReport.qml create mode 100644 interface/src/avatar/AvatarDoctor.cpp create mode 100644 interface/src/avatar/AvatarDoctor.h diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarDoctorDiagnose.qml b/interface/resources/qml/hifi/avatarPackager/AvatarDoctorDiagnose.qml new file mode 100644 index 0000000000..d329b903bd --- /dev/null +++ b/interface/resources/qml/hifi/avatarPackager/AvatarDoctorDiagnose.qml @@ -0,0 +1,125 @@ +import QtQuick 2.0 + +import "../../controlsUit" 1.0 as HifiControls +import "../../stylesUit" 1.0 + +Item { + id: diagnosingScreen + + visible: false + + property var avatarDoctor: null + property var errors: [] + + signal doneDiagnosing + + onVisibleChanged: { + if (!diagnosingScreen.visible) { + //if (debugDelay.running) { + // debugDelay.stop(); + //} + return; + } + //debugDelay.start(); + avatarDoctor = AvatarPackagerCore.currentAvatarProject.diagnose(); + avatarDoctor.complete.connect(function(errors) { + console.warn("avatarDoctor.complete " + JSON.stringify(errors)); + diagnosingScreen.errors = errors; + AvatarPackagerCore.currentAvatarProject.hasErrors = errors.length > 0; + AvatarPackagerCore.addCurrentProjectToRecentProjects(); + + // FIXME: can't seem to change state here so do it with a timer instead + doneTimer.start(); + }); + avatarDoctor.startDiagnosing(); + } + + Timer { + id: doneTimer + interval: 1 + repeat: false + running: false + onTriggered: { + doneDiagnosing(); + } + } + +/* + Timer { + id: debugDelay + interval: 5000 + repeat: false + running: false + onTriggered: { + if (Math.random() > 0.5) { + // ERROR + avatarPackager.state = AvatarPackagerState.avatarDoctorErrorReport; + } else { + // SUCCESS + avatarPackager.state = AvatarPackagerState.project; + } + } + } +*/ + + property var footer: Item { + anchors.fill: parent + anchors.rightMargin: 17 + HifiControls.Button { + id: cancelButton + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + height: 30 + width: 133 + text: qsTr("Cancel") + onClicked: { + avatarPackager.state = AvatarPackagerState.main; + } + } + } + + LoadingCircle { + id: loadingCircle + anchors { + top: parent.top + topMargin: 46 + horizontalCenter: parent.horizontalCenter + } + width: 163 + height: 163 + } + + RalewayRegular { + id: testingPackageTitle + + anchors { + horizontalCenter: parent.horizontalCenter + top: loadingCircle.bottom + topMargin: 5 + } + + text: "Testing package for errors" + size: 28 + color: "white" + } + + RalewayRegular { + id: testingPackageText + + anchors { + top: testingPackageTitle.bottom + topMargin: 26 + left: parent.left + leftMargin: 21 + right: parent.right + rightMargin: 16 + } + + text: "We are trying to find errors in your project so you can quickly understand and resolve them." + size: 21 + color: "white" + lineHeight: 33 + lineHeightMode: Text.FixedHeight + wrapMode: Text.Wrap + } +} diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarDoctorErrorReport.qml b/interface/resources/qml/hifi/avatarPackager/AvatarDoctorErrorReport.qml new file mode 100644 index 0000000000..8811ba48a3 --- /dev/null +++ b/interface/resources/qml/hifi/avatarPackager/AvatarDoctorErrorReport.qml @@ -0,0 +1,112 @@ +import QtQuick 2.0 + +import "../../controlsUit" 1.0 as HifiControls +import "../../stylesUit" 1.0 + +Item { + id: errorReport + + visible: false + + property alias errors: errorRepeater.model + + property var footer: Item { + anchors.fill: parent + anchors.rightMargin: 17 + HifiControls.Button { + id: tryAgainButton + anchors.verticalCenter: parent.verticalCenter + anchors.right: continueButton.left + anchors.rightMargin: 22 + height: 40 + width: 134 + text: qsTr("Try Again") + // colorScheme: root.colorScheme + onClicked: { + avatarPackager.state = AvatarPackagerState.avatarDoctorDiagnose; + } + } + + HifiControls.Button { + id: continueButton + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + height: 40 + width: 133 + text: qsTr("Continue") + color: hifi.buttons.blue + colorScheme: root.colorScheme + onClicked: { + avatarPackager.state = AvatarPackagerState.project; + } + } + } + + HiFiGlyphs { + id: errorReportIcon + text: hifi.glyphs.alert + size: 315 + color: "#EA4C5F" + anchors { + top: parent.top + //topMargin: 73 + horizontalCenter: parent.horizontalCenter + } + } + + Column { + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + top: errorReportIcon.bottom + topMargin: 27 + leftMargin: 13 + rightMargin: 13 + } + spacing: 7 + + Repeater { + id: errorRepeater + /*model: [ + {message: "Rig is not Hifi compatible", url: "http://www.highfidelity.com/"}, + {message: "Bone limit exceeds 256", url: "http://www.highfidelity.com/2"}, + {message: "Unsupported Texture", url: "http://www.highfidelity.com/texture"}, + {message: "Rig is not Hifi compatible", url: "http://www.highfidelity.com/"}, + {message: "Bone limit exceeds 256", url: "http://www.highfidelity.com/2"}, + {message: "Unsupported Texture", url: "http://www.highfidelity.com/texture"} + ]*/ + + Item { + height: 37 + width: parent.width + + HiFiGlyphs { + id: errorIcon + text: hifi.glyphs.alert + size: 56 + color: "#EA4C5F" + anchors { + top: parent.top + left: parent.left + } + } + + RalewayRegular { + id: errorLink + anchors { + top: parent.top + left: errorIcon.right + right: parent.right + } + linkColor: "#00B4EF"// style.colors.blueHighlight + size: 28 + text: "" + modelData.message + "" + onLinkActivated: Qt.openUrlExternally(modelData.url) + } + } + } + } + + +} diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml index b4293d5eee..8afc60fd90 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml @@ -143,6 +143,18 @@ Item { PropertyChanges { target: createAvatarProject; visible: true } PropertyChanges { target: avatarPackagerFooter; content: createAvatarProject.footer } }, + State { + name: AvatarPackagerState.avatarDoctorDiagnose + PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name } + PropertyChanges { target: avatarDoctorDiagnose; visible: true } + PropertyChanges { target: avatarPackagerFooter; content: avatarDoctorDiagnose.footer } + }, + State { + name: AvatarPackagerState.avatarDoctorErrorReport + PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name } + PropertyChanges { target: avatarDoctorErrorReport; visible: true } + PropertyChanges { target: avatarPackagerFooter; content: avatarDoctorErrorReport.footer } + }, State { name: AvatarPackagerState.project PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name; canRename: true } @@ -168,7 +180,7 @@ Item { return status; } avatarProject.reset(); - avatarPackager.state = AvatarPackagerState.project; + avatarPackager.state = AvatarPackagerState.avatarDoctorDiagnose; return status; } @@ -242,6 +254,23 @@ Item { color: "#404040" } + AvatarDoctorDiagnose { + id: avatarDoctorDiagnose + anchors.fill: parent + onErrorsChanged: { + avatarDoctorErrorReport.errors = avatarDoctorDiagnose.errors; + } + onDoneDiagnosing: { + avatarPackager.state = avatarDoctorDiagnose.errors.length > 0 ? AvatarPackagerState.avatarDoctorErrorReport + : AvatarPackagerState.project; + } + } + + AvatarDoctorErrorReport { + id: avatarDoctorErrorReport + anchors.fill: parent + } + AvatarProject { id: avatarProject colorScheme: root.colorScheme @@ -383,6 +412,7 @@ Item { title: modelData.name path: modelData.projectPath onOpen: avatarPackager.openProject(modelData.path) + hasError: modelData.hadErrors } } } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerState.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerState.qml index c81173a080..4a5abbb04b 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerState.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerState.qml @@ -7,4 +7,6 @@ Item { readonly property string project: "project" readonly property string createProject: "createProject" readonly property string projectUpload: "projectUpload" + readonly property string avatarDoctorDiagnose: "avatarDoctorDiagnose" + readonly property string avatarDoctorErrorReport: "avatarDoctorErrorReport" } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml index 25222c814c..21d0683fb1 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml @@ -12,6 +12,7 @@ Item { property alias title: title.text property alias path: path.text + property alias hasError: errorIcon.visible property color textColor: "#E3E3E3" property color hoverTextColor: "#121212" @@ -54,7 +55,7 @@ Item { RalewayBold { id: title - elide: "ElideRight" + elide: Text.ElideRight anchors { top: parent.top topMargin: 13 @@ -76,12 +77,24 @@ Item { right: background.right rightMargin: 16 } - elide: "ElideLeft" + elide: Text.ElideLeft horizontalAlignment: Text.AlignRight text: "" size: 20 } + HiFiGlyphs { + id: errorIcon + visible: false + text: hifi.glyphs.alert + size: 56 + color: "#EA4C5F" + anchors { + top: parent.top + right: parent.right + } + } + MouseArea { id: mouseArea anchors.fill: parent diff --git a/interface/src/avatar/AvatarDoctor.cpp b/interface/src/avatar/AvatarDoctor.cpp new file mode 100644 index 0000000000..d2397ed21f --- /dev/null +++ b/interface/src/avatar/AvatarDoctor.cpp @@ -0,0 +1,101 @@ +// +// AvatarDoctor.cpp +// +// +// Created by Thijs Wenker on 2/12/2019. +// Copyright 2019 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 "AvatarDoctor.h" +#include + +AvatarDoctor::AvatarDoctor(QUrl avatarFSTFileUrl) : + _avatarFSTFileUrl(std::move(avatarFSTFileUrl)) { +} + +void AvatarDoctor::startDiagnosing() { + _errors.clear(); + const auto resource = DependencyManager::get()->getGeometryResource(_avatarFSTFileUrl); + const auto resourceLoaded = [this, resource](bool success) { + // MODEL + if (!success) { + _errors.push_back({ "Model file cannot be opened", QUrl("http://www.highfidelity.com/docs") }); + emit complete(getErrors()); + return; + } + const auto avatarModel = resource.data()->getHFMModel(); + if (!avatarModel.originalURL.endsWith(".fbx")) { + _errors.push_back({ "Unsupported avatar model format", QUrl("http://www.highfidelity.com/docs") }); + emit complete(getErrors()); + return; + } + + // RIG + if (avatarModel.joints.isEmpty()) { + _errors.push_back({ "Avatar has no rig", QUrl("http://www.highfidelity.com/docs") }); + } + else { + if (avatarModel.joints.length() > 256) { + _errors.push_back({ "Avatar has over 256 bones", QUrl("http://www.highfidelity.com/docs") }); + } + // Avatar does not have Hips bone mapped + if (!avatarModel.getJointNames().contains("Hips")) { + _errors.push_back({ "Hips are not mapped", QUrl("http://www.highfidelity.com/docs") }); + } + if (!avatarModel.getJointNames().contains("Spine")) { + _errors.push_back({ "Spine is not mapped", QUrl("http://www.highfidelity.com/docs") }); + } + if (!avatarModel.getJointNames().contains("Head")) { + _errors.push_back({ "Head is not mapped", QUrl("http://www.highfidelity.com/docs") }); + } + } + + // SCALE + const float DEFAULT_HEIGHT = 1.75f; + const float RECOMMENDED_MIN_HEIGHT = DEFAULT_HEIGHT * 0.25; + const float RECOMMENDED_MAX_HEIGHT = DEFAULT_HEIGHT * 1.5; + + float avatarHeight = avatarModel.getMeshExtents().largestDimension(); + + qWarning() << "avatarHeight" << avatarHeight; + if (avatarHeight < RECOMMENDED_MIN_HEIGHT) { + _errors.push_back({ "Avatar is possibly smaller then expected.", QUrl("http://www.highfidelity.com/docs") }); + } + else if (avatarHeight > RECOMMENDED_MAX_HEIGHT) { + _errors.push_back({ "Avatar is possibly larger then expected.", QUrl("http://www.highfidelity.com/docs") }); + } + + // BLENDSHAPES + + // TEXTURES + //avatarModel.materials. + + + emit complete(getErrors()); + }; + + if (resource) { + if (resource->isLoaded()) { + resourceLoaded(!resource->isFailed()); + } else { + connect(resource.data(), &GeometryResource::finished, this, resourceLoaded); + } + } else { + _errors.push_back({ "Model file cannot be opened", QUrl("http://www.highfidelity.com/docs") }); + emit complete(getErrors()); + } +} + +QVariantList AvatarDoctor::getErrors() const { + QVariantList result; + for (const auto& error : _errors) { + QVariantMap errorVariant; + errorVariant.insert("message", error.message); + errorVariant.insert("url", error.url); + result.append(errorVariant); + } + return result; +} diff --git a/interface/src/avatar/AvatarDoctor.h b/interface/src/avatar/AvatarDoctor.h new file mode 100644 index 0000000000..65a184af71 --- /dev/null +++ b/interface/src/avatar/AvatarDoctor.h @@ -0,0 +1,50 @@ +// +// AvatarDoctor.h +// +// +// Created by Thijs Wenker on 02/12/2019. +// Copyright 2019 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 +// + +#pragma once +#ifndef hifi_AvatarDoctor_h +#define hifi_AvatarDoctor_h + +#include +#include +#include +#include + +struct AvatarDiagnosticResult { + +//public: + // AvatarDiagnosticResult() {} + // AvatarDiagnosticResult(QString message, QUrl url) : _message(std::move(message)), _url(std::move(url)) { } +//private: + QString message; + QUrl url; +}; +Q_DECLARE_METATYPE(AvatarDiagnosticResult) +Q_DECLARE_METATYPE(QVector) + +class AvatarDoctor : public QObject { + Q_OBJECT +public: + AvatarDoctor(QUrl avatarFSTFileUrl); + + Q_INVOKABLE void startDiagnosing(); + + Q_INVOKABLE QVariantList getErrors() const; + +signals: + void complete(QVariantList errors); + +private: + QUrl _avatarFSTFileUrl; + QVector _errors; +}; + +#endif // hifi_AvatarDoctor_h diff --git a/interface/src/avatar/AvatarPackager.cpp b/interface/src/avatar/AvatarPackager.cpp index fa70eee374..24f31cac9c 100644 --- a/interface/src/avatar/AvatarPackager.cpp +++ b/interface/src/avatar/AvatarPackager.cpp @@ -31,6 +31,9 @@ AvatarPackager::AvatarPackager() { qmlRegisterType(); qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType>(); qRegisterMetaType(); qmlRegisterUncreatableMetaObject( AvatarProjectStatus::staticMetaObject, @@ -84,7 +87,7 @@ void AvatarPackager::addCurrentProjectToRecentProjects() { _recentProjects.removeOne(removeProject); } - const auto newRecentProject = RecentAvatarProject(_currentAvatarProject->getProjectName(), fstPath); + const auto newRecentProject = RecentAvatarProject(_currentAvatarProject->getProjectName(), fstPath, _currentAvatarProject->getHasErrors()); _recentProjects.prepend(newRecentProject); while (_recentProjects.size() > MAX_RECENT_PROJECTS) { @@ -101,6 +104,7 @@ QVariantList AvatarPackager::recentProjectsToVariantList(bool includeProjectPath QVariantMap projectVariant; projectVariant.insert("name", project.getProjectName()); projectVariant.insert("path", project.getProjectFSTPath()); + projectVariant.insert("hadErrors", project.getHadErrors()); if (includeProjectPaths) { projectVariant.insert("projectPath", project.getProjectPath()); } @@ -113,7 +117,10 @@ void AvatarPackager::recentProjectsFromVariantList(QVariantList projectsVariant) _recentProjects.clear(); for (const auto& projectVariant : projectsVariant) { auto map = projectVariant.toMap(); - _recentProjects.append(RecentAvatarProject(map.value("name").toString(), map.value("path").toString())); + _recentProjects.append(RecentAvatarProject( + map.value("name").toString(), + map.value("path").toString(), + map.value("hadErrors", false).toBool())); } } diff --git a/interface/src/avatar/AvatarPackager.h b/interface/src/avatar/AvatarPackager.h index ec954a60d7..13f62cb471 100644 --- a/interface/src/avatar/AvatarPackager.h +++ b/interface/src/avatar/AvatarPackager.h @@ -26,19 +26,23 @@ public: RecentAvatarProject() = default; - RecentAvatarProject(QString projectName, QString projectFSTPath) { + RecentAvatarProject(QString projectName, QString projectFSTPath, bool hadErrors) { _projectName = projectName; _projectFSTPath = projectFSTPath; + _hadErrors = hadErrors; } RecentAvatarProject(const RecentAvatarProject& other) { _projectName = other._projectName; _projectFSTPath = other._projectFSTPath; + _hadErrors = other._hadErrors; } QString getProjectName() const { return _projectName; } QString getProjectFSTPath() const { return _projectFSTPath; } + bool getHadErrors() const { return _hadErrors; } + QString getProjectPath() const { return QFileInfo(_projectFSTPath).absoluteDir().absolutePath(); } @@ -50,6 +54,7 @@ public: private: QString _projectName; QString _projectFSTPath; + bool _hadErrors; }; @@ -73,6 +78,8 @@ public: return AvatarProject::isValidNewProjectName(projectPath, projectName); } + Q_INVOKABLE void addCurrentProjectToRecentProjects(); + signals: void avatarProjectChanged(); void recentProjectsChanged(); @@ -84,8 +91,6 @@ private: void setAvatarProject(AvatarProject* avatarProject); - void addCurrentProjectToRecentProjects(); - AvatarProject* _currentAvatarProject { nullptr }; QVector _recentProjects; diff --git a/interface/src/avatar/AvatarProject.cpp b/interface/src/avatar/AvatarProject.cpp index 728917e673..74edabd1f5 100644 --- a/interface/src/avatar/AvatarProject.cpp +++ b/interface/src/avatar/AvatarProject.cpp @@ -243,6 +243,12 @@ MarketplaceItemUploader* AvatarProject::upload(bool updateExisting) { return uploader; } +AvatarDoctor* AvatarProject::diagnose() { + auto avatarDoctor = new AvatarDoctor(QUrl(getFSTPath())); + + return avatarDoctor; +} + void AvatarProject::openInInventory() const { constexpr int TIME_TO_WAIT_FOR_INVENTORY_TO_OPEN_MS { 1000 }; diff --git a/interface/src/avatar/AvatarProject.h b/interface/src/avatar/AvatarProject.h index 1710282a3e..f11547bdca 100644 --- a/interface/src/avatar/AvatarProject.h +++ b/interface/src/avatar/AvatarProject.h @@ -14,6 +14,7 @@ #define hifi_AvatarProject_h #include "MarketplaceItemUploader.h" +#include "AvatarDoctor.h" #include "ProjectFile.h" #include "FST.h" @@ -53,11 +54,14 @@ class AvatarProject : public QObject { Q_PROPERTY(QString projectFSTPath READ getFSTPath CONSTANT) Q_PROPERTY(QString projectFBXPath READ getFBXPath CONSTANT) Q_PROPERTY(QString name READ getProjectName WRITE setProjectName NOTIFY nameChanged) + Q_PROPERTY(bool hasErrors READ getHasErrors WRITE setHasErrors NOTIFY hasErrorsChanged) public: Q_INVOKABLE MarketplaceItemUploader* upload(bool updateExisting); Q_INVOKABLE void openInInventory() const; Q_INVOKABLE QStringList getProjectFiles() const; + Q_INVOKABLE AvatarDoctor* diagnose(); + Q_INVOKABLE QString getProjectName() const { return _fst->getName(); } Q_INVOKABLE void setProjectName(const QString& newProjectName) { @@ -72,6 +76,8 @@ public: Q_INVOKABLE QString getFBXPath() const { return QDir::cleanPath(QDir(_projectPath).absoluteFilePath(_fst->getModelPath())); } + Q_INVOKABLE bool getHasErrors() const { return _hasErrors; } + Q_INVOKABLE void setHasErrors(bool hasErrors) { _hasErrors = hasErrors; } /** * returns the AvatarProject or a nullptr on failure. @@ -92,6 +98,7 @@ public: signals: void nameChanged(); void projectFilesChanged(); + void hasErrorsChanged(); private: AvatarProject(const QString& fstPath, const QByteArray& data); @@ -110,6 +117,8 @@ private: QDir _directory; QList _projectFiles{}; QString _projectPath; + + bool _hasErrors { false }; }; #endif // hifi_AvatarProject_h From bed2732d342eb0d09310fae2bfdcbc788aad43be Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 14 Feb 2019 12:59:16 -0800 Subject: [PATCH 06/23] start moving materials to rendering only --- interface/src/Application.cpp | 39 +-- .../src/EntityTreeRenderer.cpp | 33 +++ .../src/EntityTreeRenderer.h | 15 + .../src/RenderableEntityItem.cpp | 1 - .../src/RenderableMaterialEntityItem.cpp | 146 ++++++++-- .../src/RenderableMaterialEntityItem.h | 32 ++- libraries/entities/src/EntityItem.cpp | 19 -- libraries/entities/src/EntityItem.h | 10 - libraries/entities/src/EntityTree.cpp | 49 ---- libraries/entities/src/EntityTree.h | 22 -- libraries/entities/src/MaterialEntityItem.cpp | 262 +++++------------- libraries/entities/src/MaterialEntityItem.h | 50 +--- 12 files changed, 285 insertions(+), 393 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1029398794..ca7678c233 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1926,46 +1926,32 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - EntityTree::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + EntityTreeRenderer::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { if (_aboutToQuit) { return false; } - // try to find the renderable auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { renderable->addMaterial(material, parentMaterialName); } - // even if we don't find it, try to find the entity - auto entity = getEntities()->getEntity(entityID); - if (entity) { - entity->addMaterial(material, parentMaterialName); - return true; - } return false; }); - EntityTree::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + EntityTreeRenderer::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { if (_aboutToQuit) { return false; } - // try to find the renderable auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { renderable->removeMaterial(material, parentMaterialName); } - // even if we don't find it, try to find the entity - auto entity = getEntities()->getEntity(entityID); - if (entity) { - entity->removeMaterial(material, parentMaterialName); - return true; - } return false; }); - EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + EntityTreeRenderer::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { @@ -1974,7 +1960,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } return false; }); - EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + EntityTreeRenderer::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { @@ -1984,23 +1970,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return false; }); - EntityTree::setAddMaterialToOverlayOperator([this](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - auto overlay = _overlays.getOverlay(overlayID); - if (overlay) { - overlay->addMaterial(material, parentMaterialName); - return true; - } - return false; - }); - EntityTree::setRemoveMaterialFromOverlayOperator([this](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - auto overlay = _overlays.getOverlay(overlayID); - if (overlay) { - overlay->removeMaterial(material, parentMaterialName); - return true; - } - return false; - }); - // Keyboard focus handling for Web overlays. auto overlays = &(qApp->getOverlays()); connect(overlays, &Overlays::overlayDeleted, [this](const OverlayID& overlayID) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 2b3a915235..c0774c795c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1360,3 +1360,36 @@ EntityEditPacketSender* EntityTreeRenderer::getPacketSender() { EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr; return packetSender; } + +std::function EntityTreeRenderer::_addMaterialToEntityOperator = nullptr; +std::function EntityTreeRenderer::_removeMaterialFromEntityOperator = nullptr; +std::function EntityTreeRenderer::_addMaterialToAvatarOperator = nullptr; +std::function EntityTreeRenderer::_removeMaterialFromAvatarOperator = nullptr; + +bool EntityTreeRenderer::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + if (_addMaterialToEntityOperator) { + return _addMaterialToEntityOperator(entityID, material, parentMaterialName); + } + return false; +} + +bool EntityTreeRenderer::removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + if (_removeMaterialFromEntityOperator) { + return _removeMaterialFromEntityOperator(entityID, material, parentMaterialName); + } + return false; +} + +bool EntityTreeRenderer::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + if (_addMaterialToAvatarOperator) { + return _addMaterialToAvatarOperator(avatarID, material, parentMaterialName); + } + return false; +} + +bool EntityTreeRenderer::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + if (_removeMaterialFromAvatarOperator) { + return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName); + } + return false; +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 725416e2cc..00a78bf9e4 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -123,6 +123,16 @@ public: EntityEditPacketSender* getPacketSender(); + static void setAddMaterialToEntityOperator(std::function addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; } + static void setRemoveMaterialFromEntityOperator(std::function removeMaterialFromEntityOperator) { _removeMaterialFromEntityOperator = removeMaterialFromEntityOperator; } + static bool addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName); + static bool removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName); + + static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } + static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } + static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName); + static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName); + signals: void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); @@ -259,6 +269,11 @@ private: workload::Transaction::Updates _spaceUpdates; static std::function _getAvatarUpOperator; + + static std::function _addMaterialToEntityOperator; + static std::function _removeMaterialFromEntityOperator; + static std::function _addMaterialToAvatarOperator; + static std::function _removeMaterialFromAvatarOperator; }; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 83f0bdcff3..5c73b9576d 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -146,7 +146,6 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _created(entit _needsRenderUpdate = true; emit requestRenderUpdate(); }); - _materials = entity->getMaterials(); } EntityRenderer::~EntityRenderer() { } diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 483f9ffe1c..6cc342f68a 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -14,23 +14,54 @@ using namespace render; using namespace render::entities; -bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { - if (entity->getMaterial() != _drawMaterial) { - return true; - } - if (entity->getParentID() != _parentID) { - return true; - } - if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) { +bool MaterialEntityRenderer::needsRenderUpdate() const { + if (_retryApply) { return true; } if (!_texturesLoaded) { return true; } + return Parent::needsRenderUpdate(); +} + +bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { + // Could require material re-apply + if (entity->getMaterialURL() != _materialURL) { + return true; + } + if (entity->getMaterialData() != _materialData) { + return true; + } + if (entity->getParentMaterialName() != _parentMaterialName) { + return true; + } + if (entity->getParentID() != _parentID) { + return true; + } + if (entity->getPriority() != _priority) { + return true; + } + + // Won't cause material re-apply + if (entity->getMaterialMappingMode() != _materialMappingMode) { + return true; + } + if (entity->getMaterialRepeat() != _materialRepeat) { + return true; + } + if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) { + return true; + } + if (entity->getTransform() != _transform) { + return true; + } + if (entity->getUnscaledDimensions() != _dimensions) { + return true; + } return false; } -void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { +void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { withWriteLock([&] { if (_drawMaterial != entity->getMaterial()) { _texturesLoaded = false; @@ -61,8 +92,9 @@ ItemKey MaterialEntityRenderer::getKey() { builder.withInvisible(); } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); + const auto& drawMaterial = getMaterial(); + if (drawMaterial) { + auto matKey = drawMaterial->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); } @@ -73,8 +105,9 @@ ItemKey MaterialEntityRenderer::getKey() { ShapeKey MaterialEntityRenderer::getShapeKey() { graphics::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); + const auto& drawMaterial = getMaterial(); + if (drawMaterial) { + drawMaterialKey = drawMaterial->getKey(); } bool isTranslucent = drawMaterialKey.isTranslucent(); @@ -112,18 +145,24 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { // Don't render if our parent is set or our material is null QUuid parentID; + withReadLock([&] { + parentID = _parentID; + }); + if (!parentID.isNull()) { + return; + } + Transform renderTransform; graphics::MaterialPointer drawMaterial; Transform textureTransform; withReadLock([&] { - parentID = _parentID; renderTransform = _renderTransform; - drawMaterial = _drawMaterial; + drawMaterial = getMaterial(); textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0)); textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot))); textureTransform.setScale(glm::vec3(_materialMappingScale, 1)); }); - if (!parentID.isNull() || !drawMaterial) { + if (!drawMaterial) { return; } @@ -142,3 +181,78 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { args->_details._trianglesRendered += (int)DependencyManager::get()->getSphereTriangleCount(); } + +void MaterialEntityRenderer::setCurrentMaterialName(const std::string& currentMaterialName) { + if (_parsedMaterials.networkMaterials.find(currentMaterialName) != _parsedMaterials.networkMaterials.end()) { + _currentMaterialName = currentMaterialName; + } else if (_parsedMaterials.names.size() > 0) { + _currentMaterialName = _parsedMaterials.names[0]; + } +} + +std::shared_ptr MaterialEntityRenderer::getMaterial() const { + auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName); + if (material != _parsedMaterials.networkMaterials.end()) { + return material->second; + } else { + return nullptr; + } +} + +void MaterialEntityRenderer::deleteMaterial() { + std::shared_ptr material = getMaterial(); + if (!material) { + return; + } + QUuid parentID = _parentID; + if (parentID.isNull()) { + return; + } + + // Our parent could be an entity or an avatar + if (EntityTreeRenderer::removeMaterialFromEntity(parentID, material, _parentMaterialName.toStdString())) { + return; + } + + if (EntityTreeRenderer::removeMaterialFromAvatar(parentID, material, _parentMaterialName.toStdString())) { + return; + } + + // if a remove fails, our parent is gone, so we don't need to retry +} + +void MaterialEntityRenderer::applyMaterial() { + _retryApply = false; + std::shared_ptr material = getMaterial(); + QUuid parentID = _parentID; + if (!material || parentID.isNull()) { + return; + } + + Transform textureTransform; + if (_materialMappingMode == MaterialMappingMode::UV) { + textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f)); + textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot))); + textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f)); + } else if (_materialMappingMode == MaterialMappingMode::PROJECTED) { + textureTransform = _transform; + textureTransform.postScale(_dimensions); + // Pass the inverse transform here so we don't need to compute it in the shaders + textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix()); + } + material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat); + + graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, _priority); + + // Our parent could be an entity or an avatar + if (EntityTreeRenderer::addMaterialToEntity(parentID, materialLayer, _parentMaterialName.toStdString())) { + return; + } + + if (EntityTreeRenderer::addMaterialToAvatar(parentID, materialLayer, _parentMaterialName.toStdString())) { + return; + } + + // if we've reached this point, we couldn't find our parent, so we need to try again later + _retryApply = true; +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index c90048ecf5..5ccbb33312 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -13,6 +13,9 @@ #include +#include +#include + class NetworkMaterial; namespace render { namespace entities { @@ -22,22 +25,45 @@ class MaterialEntityRenderer : public TypedEntityRenderer { using Pointer = std::shared_ptr; public: MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {} + ~MaterialEntityRenderer() { deleteMaterial(); } private: + virtual bool needsRenderUpdate() const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; - virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; virtual void doRender(RenderArgs* args) override; ItemKey getKey() override; ShapeKey getShapeKey() override; + QString _materialURL; + QString _materialData; + QString _parentMaterialName; + quint16 _priority; QUuid _parentID; + + MaterialMappingMode _materialMappingMode; + bool _materialRepeat; glm::vec2 _materialMappingPos; glm::vec2 _materialMappingScale; float _materialMappingRot; - bool _texturesLoaded { false }; + Transform _transform; + glm::vec3 _dimensions; + + bool _texturesLoaded { false }; + bool _retryApply { false }; + + std::shared_ptr getMaterial() const; + void setMaterialURL(const QString& materialURLString, bool materialDataChanged = false); + void setCurrentMaterialName(const std::string& currentMaterialName); + + void applyMaterial(); + void deleteMaterial(); + + NetworkMaterialResourcePointer _networkMaterial; + NetworkMaterialResource::ParsedMaterials _parsedMaterials; + std::string _currentMaterialName; - std::shared_ptr _drawMaterial; }; } } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7e5be384a7..ad9acb3775 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3234,25 +3234,6 @@ void EntityItem::setSpaceIndex(int32_t index) { void EntityItem::preDelete() { } -void EntityItem::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) { - std::lock_guard lock(_materialsLock); - _materials[parentMaterialName].push(material); -} - -void EntityItem::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) { - std::lock_guard lock(_materialsLock); - _materials[parentMaterialName].remove(material); -} - -std::unordered_map EntityItem::getMaterials() { - std::unordered_map toReturn; - { - std::lock_guard lock(_materialsLock); - toReturn = _materials; - } - return toReturn; -} - bool EntityItem::getCloneable() const { bool result; withReadLock([&] { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 27b207b6f3..75fa30b3a3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -37,8 +37,6 @@ #include "EntityDynamicInterface.h" #include "GrabPropertyGroup.h" -#include "graphics/Material.h" - class EntitySimulation; class EntityTreeElement; class EntityTreeElementExtraEncodeData; @@ -542,10 +540,6 @@ public: virtual void preDelete(); virtual void postParentFixup() {} - void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); - void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName); - std::unordered_map getMaterials(); - void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; } uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } @@ -750,10 +744,6 @@ protected: QHash _grabActions; -private: - std::unordered_map _materials; - std::mutex _materialsLock; - }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 954462a9f2..bf91d71050 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2953,55 +2953,6 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { return entity->getJointNames(); } -std::function EntityTree::_addMaterialToEntityOperator = nullptr; -std::function EntityTree::_removeMaterialFromEntityOperator = nullptr; -std::function EntityTree::_addMaterialToAvatarOperator = nullptr; -std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; -std::function EntityTree::_addMaterialToOverlayOperator = nullptr; -std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; - -bool EntityTree::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - if (_addMaterialToEntityOperator) { - return _addMaterialToEntityOperator(entityID, material, parentMaterialName); - } - return false; -} - -bool EntityTree::removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - if (_removeMaterialFromEntityOperator) { - return _removeMaterialFromEntityOperator(entityID, material, parentMaterialName); - } - return false; -} - -bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - if (_addMaterialToAvatarOperator) { - return _addMaterialToAvatarOperator(avatarID, material, parentMaterialName); - } - return false; -} - -bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - if (_removeMaterialFromAvatarOperator) { - return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName); - } - return false; -} - -bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - if (_addMaterialToOverlayOperator) { - return _addMaterialToOverlayOperator(overlayID, material, parentMaterialName); - } - return false; -} - -bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - if (_removeMaterialFromOverlayOperator) { - return _removeMaterialFromOverlayOperator(overlayID, material, parentMaterialName); - } - return false; -} - void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, MovingEntitiesOperator& moveOperator, bool force, bool tellServer) { // if the queryBox has changed, tell the entity-server diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index f9b7b8d67f..367af7ba1e 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -262,21 +262,6 @@ public: void setIsServerlessMode(bool value) { _serverlessDomain = value; } bool isServerlessMode() const { return _serverlessDomain; } - static void setAddMaterialToEntityOperator(std::function addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; } - static void setRemoveMaterialFromEntityOperator(std::function removeMaterialFromEntityOperator) { _removeMaterialFromEntityOperator = removeMaterialFromEntityOperator; } - static bool addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName); - static bool removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName); - - static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } - static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } - static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName); - static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName); - - static void setAddMaterialToOverlayOperator(std::function addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } - static void setRemoveMaterialFromOverlayOperator(std::function removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } - static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName); - static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName); - std::map getNamedPaths() const { return _namedPaths; } void updateEntityQueryAACube(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, @@ -385,13 +370,6 @@ private: std::shared_ptr _myAvatar{ nullptr }; - static std::function _addMaterialToEntityOperator; - static std::function _removeMaterialFromEntityOperator; - static std::function _addMaterialToAvatarOperator; - static std::function _removeMaterialFromAvatarOperator; - static std::function _addMaterialToOverlayOperator; - static std::function _removeMaterialFromOverlayOperator; - std::vector _staleProxies; bool _serverlessDomain { false }; diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index cec602a5e1..3a363f2e83 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -16,9 +16,6 @@ EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); - // When you reload content, setProperties doesn't have any of the propertiesChanged flags set, so it won't trigger a material add - entity->removeMaterial(); - entity->applyMaterial(); return entity; } @@ -27,10 +24,6 @@ MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : Entit _type = EntityTypes::Material; } -MaterialEntityItem::~MaterialEntityItem() { - removeMaterial(); -} - EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL); @@ -131,7 +124,6 @@ void MaterialEntityItem::debugDump() const { qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " name:" << _name; qCDebug(entities) << " material url:" << _materialURL; - qCDebug(entities) << " current material name:" << _currentMaterialName.c_str(); qCDebug(entities) << " material mapping mode:" << _materialMappingMode; qCDebug(entities) << " material repeat:" << _materialRepeat; qCDebug(entities) << " priority:" << _priority; @@ -154,216 +146,101 @@ void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) { } } -std::shared_ptr MaterialEntityItem::getMaterial() const { - auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName); - if (material != _parsedMaterials.networkMaterials.end()) { - return material->second; - } else { - return nullptr; - } +QString MaterialEntityItem::getMaterialURL() const { + return resultWithReadLock([&] { + return _materialURL; + }); } -void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool materialDataChanged) { - bool usingMaterialData = materialDataChanged || materialURLString.startsWith("materialData"); - if (_materialURL != materialURLString || (usingMaterialData && materialDataChanged)) { - removeMaterial(); - _materialURL = materialURLString; - - if (materialURLString.contains("?")) { - auto split = materialURLString.split("?"); - _currentMaterialName = split.last().toStdString(); - } - - if (usingMaterialData) { - _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getMaterialData().toUtf8()), materialURLString); - - // Since our material changed, the current name might not be valid anymore, so we need to update - setCurrentMaterialName(_currentMaterialName); - applyMaterial(); - } else { - _networkMaterial = MaterialCache::instance().getMaterial(materialURLString); - auto onMaterialRequestFinished = [&](bool success) { - if (success) { - _parsedMaterials = _networkMaterial->parsedMaterials; - - setCurrentMaterialName(_currentMaterialName); - applyMaterial(); - } - }; - if (_networkMaterial) { - if (_networkMaterial->isLoaded()) { - onMaterialRequestFinished(!_networkMaterial->isFailed()); - } else { - connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished); - } - } - } - } +void MaterialEntityItem::setMaterialURL(const QString& materialURL) { + withWriteLock([&] { + _materialURL = materialURL; + }); } -void MaterialEntityItem::setCurrentMaterialName(const std::string& currentMaterialName) { - if (_parsedMaterials.networkMaterials.find(currentMaterialName) != _parsedMaterials.networkMaterials.end()) { - _currentMaterialName = currentMaterialName; - } else if (_parsedMaterials.names.size() > 0) { - _currentMaterialName = _parsedMaterials.names[0]; - } +QString MaterialEntityItem::getMaterialData() const { + return resultWithReadLock([&] { + return _materialData; + }); } void MaterialEntityItem::setMaterialData(const QString& materialData) { - if (_materialData != materialData) { + withWriteLock([&] { _materialData = materialData; - if (_materialURL.startsWith("materialData")) { - // Trigger material update when material data changes - setMaterialURL(_materialURL, true); - } - } + }); +} + +MaterialMappingMode MaterialEntityItem::getMaterialMappingMode() const { + return resultWithReadLock([&] { + return _materialMappingMode; + }); } void MaterialEntityItem::setMaterialMappingMode(MaterialMappingMode mode) { - if (_materialMappingMode != mode) { - removeMaterial(); + withWriteLock([&] { _materialMappingMode = mode; - setUnscaledDimensions(_desiredDimensions); - applyMaterial(); - } + }); + setUnscaledDimensions(_desiredDimensions); } -void MaterialEntityItem::setMaterialRepeat(bool repeat) { - if (_materialRepeat != repeat) { - removeMaterial(); - _materialRepeat = repeat; - applyMaterial(); - } -} - -void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) { - if (_materialMappingPos != materialMappingPos) { - removeMaterial(); - _materialMappingPos = materialMappingPos; - applyMaterial(); - } -} - -void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) { - if (_materialMappingScale != materialMappingScale) { - removeMaterial(); - _materialMappingScale = materialMappingScale; - applyMaterial(); - } -} - -void MaterialEntityItem::setMaterialMappingRot(const float& materialMappingRot) { - if (_materialMappingRot != materialMappingRot) { - removeMaterial(); - _materialMappingRot = materialMappingRot; - applyMaterial(); - } +quint16 MaterialEntityItem::getPriority() const { + return resultWithReadLock([&] { + return _priority; + }); } void MaterialEntityItem::setPriority(quint16 priority) { - if (_priority != priority) { - removeMaterial(); + withWriteLock([&] { _priority = priority; - applyMaterial(); - } + }); +} + +QString MaterialEntityItem::getParentMaterialName() const { + return resultWithReadLock([&] { + return _parentMaterialName; + }); } void MaterialEntityItem::setParentMaterialName(const QString& parentMaterialName) { - if (_parentMaterialName != parentMaterialName) { - removeMaterial(); + withWriteLock([&] { _parentMaterialName = parentMaterialName; - applyMaterial(); - } + }); } -void MaterialEntityItem::setParentID(const QUuid& parentID) { - if (getParentID() != parentID) { - removeMaterial(); - EntityItem::setParentID(parentID); - applyMaterial(); - } +glm::vec2 MaterialEntityItem::getMaterialMappingPos() const { + return resultWithReadLock([&] { + return _materialMappingPos; + }); } -void MaterialEntityItem::locationChanged(bool tellPhysics) { - EntityItem::locationChanged(); - if (_materialMappingMode == MaterialMappingMode::PROJECTED) { - removeMaterial(); - applyMaterial(); - } +void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) { + withWriteLock([&] { + _materialMappingPos = materialMappingPos; + }); } -void MaterialEntityItem::dimensionsChanged() { - EntityItem::dimensionsChanged(); - if (_materialMappingMode == MaterialMappingMode::PROJECTED) { - removeMaterial(); - applyMaterial(); - } +glm::vec2 MaterialEntityItem::getMaterialMappingScale() const { + return resultWithReadLock([&] { + return _materialMappingScale; + }); } -void MaterialEntityItem::removeMaterial() { - graphics::MaterialPointer material = getMaterial(); - if (!material) { - return; - } - QUuid parentID = getParentID(); - if (parentID.isNull()) { - return; - } - - // Our parent could be an entity, an avatar, or an overlay - if (EntityTree::removeMaterialFromEntity(parentID, material, getParentMaterialName().toStdString())) { - return; - } - - if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialName().toStdString())) { - return; - } - - if (EntityTree::removeMaterialFromOverlay(parentID, material, getParentMaterialName().toStdString())) { - return; - } - - // if a remove fails, our parent is gone, so we don't need to retry +void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) { + withWriteLock([&] { + _materialMappingScale = materialMappingScale; + }); } -void MaterialEntityItem::applyMaterial() { - _retryApply = false; - graphics::MaterialPointer material = getMaterial(); - QUuid parentID = getParentID(); - if (!material || parentID.isNull()) { - return; - } +float MaterialEntityItem::getMaterialMappingRot() const { + return resultWithReadLock([&] { + return _materialMappingRot; + }); +} - Transform textureTransform; - if (_materialMappingMode == MaterialMappingMode::UV) { - textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f)); - textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot))); - textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f)); - } else if (_materialMappingMode == MaterialMappingMode::PROJECTED) { - textureTransform = getTransform(); - textureTransform.postScale(getUnscaledDimensions()); - // Pass the inverse transform here so we don't need to compute it in the shaders - textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix()); - } - material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat); - - graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, getPriority()); - - // Our parent could be an entity, an avatar, or an overlay - if (EntityTree::addMaterialToEntity(parentID, materialLayer, getParentMaterialName().toStdString())) { - return; - } - - if (EntityTree::addMaterialToAvatar(parentID, materialLayer, getParentMaterialName().toStdString())) { - return; - } - - if (EntityTree::addMaterialToOverlay(parentID, materialLayer, getParentMaterialName().toStdString())) { - return; - } - - // if we've reached this point, we couldn't find our parent, so we need to try again later - _retryApply = true; +void MaterialEntityItem::setMaterialMappingRot(float materialMappingRot) { + withWriteLock([&] { + _materialMappingRot = materialMappingRot; + }); } AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) { @@ -380,18 +257,3 @@ AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) { } return aaCube; } - -void MaterialEntityItem::postParentFixup() { - removeMaterial(); - _queryAACubeSet = false; // force an update so we contain our parent - updateQueryAACube(); - applyMaterial(); -} - -void MaterialEntityItem::update(const quint64& now) { - if (_retryApply) { - applyMaterial(); - } - - EntityItem::update(now); -} diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index ba142d7719..b9e83a7fe5 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -12,8 +12,6 @@ #include "EntityItem.h" #include "MaterialMappingMode.h" -#include -#include class MaterialEntityItem : public EntityItem { using Pointer = std::shared_ptr; @@ -21,13 +19,9 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); MaterialEntityItem(const EntityItemID& entityItemID); - ~MaterialEntityItem(); ALLOW_INSTANTIATION // This class can be instantiated - void update(const quint64& now) override; - bool needsToCallUpdate() const override { return true; } - // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; virtual bool setProperties(const EntityItemProperties& properties) override; @@ -52,44 +46,30 @@ public: virtual void setUnscaledDimensions(const glm::vec3& value) override; - QString getMaterialURL() const { return _materialURL; } - void setMaterialURL(const QString& materialURLString, bool materialDataChanged = false); + QString getMaterialURL() const; + void setMaterialURL(const QString& materialURL); - void setCurrentMaterialName(const std::string& currentMaterialName); + QString getMaterialData() const; + void setMaterialData(const QString& materialData); - MaterialMappingMode getMaterialMappingMode() const { return _materialMappingMode; } + MaterialMappingMode getMaterialMappingMode() const; void setMaterialMappingMode(MaterialMappingMode mode); bool getMaterialRepeat() const { return _materialRepeat; } - void setMaterialRepeat(bool repeat); + void setMaterialRepeat(bool repeat) { _materialRepeat = repeat; } - quint16 getPriority() const { return _priority; } + quint16 getPriority() const; void setPriority(quint16 priority); - QString getParentMaterialName() const { return _parentMaterialName; } + QString getParentMaterialName() const; void setParentMaterialName(const QString& parentMaterialName); - glm::vec2 getMaterialMappingPos() const { return _materialMappingPos; } + glm::vec2 getMaterialMappingPos() const; void setMaterialMappingPos(const glm::vec2& materialMappingPos); - glm::vec2 getMaterialMappingScale() const { return _materialMappingScale; } + glm::vec2 getMaterialMappingScale() const; void setMaterialMappingScale(const glm::vec2& materialMappingScale); - float getMaterialMappingRot() const { return _materialMappingRot; } - void setMaterialMappingRot(const float& materialMappingRot); - - QString getMaterialData() const { return _materialData; } - void setMaterialData(const QString& materialData); - - std::shared_ptr getMaterial() const; - - void setParentID(const QUuid& parentID) override; - - void locationChanged(bool tellPhysics) override; - void dimensionsChanged() override; - - void applyMaterial(); - void removeMaterial(); - - void postParentFixup() override; + float getMaterialMappingRot() const; + void setMaterialMappingRot(float materialMappingRot); AACube calculateInitialQueryAACube(bool& success) override; @@ -128,12 +108,6 @@ private: float _materialMappingRot { 0 }; QString _materialData; - NetworkMaterialResourcePointer _networkMaterial; - NetworkMaterialResource::ParsedMaterials _parsedMaterials; - std::string _currentMaterialName; - - bool _retryApply { false }; - }; #endif // hifi_MaterialEntityItem_h From 490ef3542eaa398c69f105e7c71b1aefb3ceeb6d Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 15 Feb 2019 10:58:09 -0800 Subject: [PATCH 07/23] update for marketplace-in-qml, and make specific to username --- .../qml/hifi/commerce/marketplace/Marketplace.qml | 8 ++++---- .../hifi/commerce/marketplace/MarketplaceItem.qml | 14 ++++++++++---- .../commerce/marketplace/MarketplaceListItem.qml | 14 +++++++++++--- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml index 0d42cb599e..b7d3a22e44 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml @@ -120,7 +120,7 @@ Rectangle { marketplaceItem.description = result.data.description; marketplaceItem.attributions = result.data.attributions; marketplaceItem.license = result.data.license; - marketplaceItem.available = result.data.availability === "available"; + marketplaceItem.availability = result.data.availability; marketplaceItem.created_at = result.data.created_at; marketplaceItemScrollView.contentHeight = marketplaceItemContent.height; itemsList.visible = false; @@ -532,7 +532,7 @@ Rectangle { creator: model.creator category: model.primary_category price: model.cost - available: model.availability === "available" + availability: model.availability isLoggedIn: root.isLoggedIn; onShowItem: { @@ -704,7 +704,7 @@ Rectangle { topMargin: 10; leftMargin: 15; } - height: visible ? childrenRect.height : 0 + height: visible ? 36 : 0 RalewayRegular { id: sortText @@ -727,7 +727,7 @@ Rectangle { leftMargin: 20 } width: root.isLoggedIn ? 322 : 242 - height: 36 + height: parent.height radius: 4 border.width: 1 diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml index 0a57e56099..bbf9be908a 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml @@ -33,11 +33,11 @@ Rectangle { property string creator: "" property var categories: [] property int price: 0 + property string availability: "unknown" property var attributions: [] property string description: "" property string license: "" property string posted: "" - property bool available: false property string created_at: "" property bool isLoggedIn: false; property int edition: -1; @@ -264,9 +264,15 @@ Rectangle { } height: 50 - text: root.edition >= 0 ? "UPGRADE FOR FREE" : (root.available ? (root.price ? root.price : "FREE") : "UNAVAILABLE (not for sale)") - enabled: root.edition >= 0 || root.available - buttonGlyph: root.available ? (root.price ? hifi.glyphs.hfc : "") : "" + property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS + property bool isMine: creator === Account.username + property bool isUpgrade: root.edition >= 0 + property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price + property bool isAvailable: costToMe >= 0 + + text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : ("UNAVAILABLE (" + availibility + ")")) + enabled: isAvailable + buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : "" color: hifi.buttons.blue onClicked: root.buy(); diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml index 2f37637e40..fd3b960002 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml @@ -34,7 +34,7 @@ Rectangle { property string creator: "" property string category: "" property int price: 0 - property bool available: false + property string availability: "unknown" property bool isLoggedIn: false; signal buy() @@ -299,8 +299,16 @@ Rectangle { bottomMargin: 10 } - text: root.price ? root.price : "FREE" - buttonGlyph: root.price ? hifi.glyphs.hfc : "" + property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS + property bool isMine: creator === Account.username + property bool isUpgrade: root.edition >= 0 + property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price + property bool isAvailable: costToMe >= 0 + + text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : ("UNAVAILABLE (" + availibility + ")")) + enabled: isAvailable + buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : "" + color: hifi.buttons.blue; onClicked: root.buy(); From 87ab255115bc8e4bbc25e07d00a28da1f0723b46 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Feb 2019 11:49:20 -0800 Subject: [PATCH 08/23] finish moving materials to rendering --- interface/src/Application.cpp | 8 -- .../src/RenderableMaterialEntityItem.cpp | 132 +++++++++++++----- .../src/RenderableMaterialEntityItem.h | 4 +- 3 files changed, 100 insertions(+), 44 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b8fb05daf4..e7910ddfae 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1970,14 +1970,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return renderable->textSize(text); } } - }); - - // Keyboard focus handling for Web overlays. - auto overlays = &(qApp->getOverlays()); - connect(overlays, &Overlays::overlayDeleted, [this](const OverlayID& overlayID) { - if (overlayID == _keyboardFocusedOverlay.get()) { - setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); - } return QSizeF(0.0f, 0.0f); }); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index b986702f5a..31b862000b 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -105,45 +105,106 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo } } - auto& material = getMaterial(); - // Update the old material regardless of if it's going to change - if (transformChanged && material && !_parentID.isNull()) { - Transform textureTransform; - if (_materialMappingMode == MaterialMappingMode::UV) { - textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f)); - textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot))); - textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f)); - } else if (_materialMappingMode == MaterialMappingMode::PROJECTED) { - textureTransform = _transform; - textureTransform.postScale(_dimensions); - // Pass the inverse transform here so we don't need to compute it in the shaders - textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix()); + { + auto& material = getMaterial(); + // Update the old material regardless of if it's going to change + if (transformChanged && material && !_parentID.isNull()) { + applyTextureTransform(material); } - material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat); } bool deleteNeeded = false; bool addNeeded = _retryApply; + bool urlChanged = false; { QString materialURL = entity->getMaterialURL(); if (materialURL != _materialURL) { _materialURL = materialURL; + if (_materialURL.contains("?")) { + auto split = _materialURL.split("?"); + _currentMaterialName = split.last().toStdString(); + } + urlChanged = true; + } + } + + bool usingMaterialData = _materialURL.startsWith("materialData"); + { + QString materialData = entity->getMaterialData(); + if (materialData != _materialData) { + _materialData = materialData; + if (usingMaterialData) { + _texturesLoaded = false; + deleteNeeded = true; + addNeeded = true; + _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL); + // Since our material changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(_currentMaterialName); + } + } + } + { + QString parentMaterialName = entity->getParentMaterialName(); + if (parentMaterialName != _parentMaterialName) { + _parentMaterialName = parentMaterialName; + deleteNeeded = true; + addNeeded = true; + } + } + QUuid oldParentID = _parentID; + { + QUuid parentID = entity->getParentID(); + if (parentID != _parentID) { + _parentID = parentID; + deleteNeeded = true; + addNeeded = true; + } + } + { + quint16 priority = entity->getPriority(); + if (priority != _priority) { + _priority = priority; deleteNeeded = true; addNeeded = true; } } - if (_drawMaterial != entity->getMaterial()) { - _texturesLoaded = false; - _drawMaterial = entity->getMaterial(); + if (urlChanged && !usingMaterialData) { + _networkMaterial = MaterialCache::instance().getMaterial(_materialURL); + auto onMaterialRequestFinished = [&, oldParentID](bool success) { + if (success) { + _texturesLoaded = false; + _parsedMaterials = _networkMaterial->parsedMaterials; + setCurrentMaterialName(_currentMaterialName); + deleteMaterial(oldParentID); + applyMaterial(); + } + }; + if (_networkMaterial) { + if (_networkMaterial->isLoaded()) { + onMaterialRequestFinished(!_networkMaterial->isFailed()); + } else { + connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished); + } + } + } else { + if (deleteNeeded) { + deleteMaterial(oldParentID); + } + if (addNeeded) { + applyMaterial(); + } } - bool newTexturesLoaded = _drawMaterial ? !_drawMaterial->isMissingTexture() : false; - if (!_texturesLoaded && newTexturesLoaded) { - _drawMaterial->checkResetOpacityMap(); + { + auto& material = getMaterial(); + bool newTexturesLoaded = material ? !material->isMissingTexture() : false; + if (!_texturesLoaded && newTexturesLoaded) { + material->checkResetOpacityMap(); + } + _texturesLoaded = newTexturesLoaded; } - _texturesLoaded = newTexturesLoaded; _renderTransform = getModelTransform(); const float MATERIAL_ENTITY_SCALE = 0.5f; @@ -267,36 +328,28 @@ std::shared_ptr MaterialEntityRenderer::getMaterial() const { } } -void MaterialEntityRenderer::deleteMaterial() { +void MaterialEntityRenderer::deleteMaterial(const QUuid& oldParentID) { std::shared_ptr material = getMaterial(); if (!material) { return; } - QUuid parentID = _parentID; - if (parentID.isNull()) { + if (oldParentID.isNull()) { return; } // Our parent could be an entity or an avatar - if (EntityTreeRenderer::removeMaterialFromEntity(parentID, material, _parentMaterialName.toStdString())) { + if (EntityTreeRenderer::removeMaterialFromEntity(oldParentID, material, _parentMaterialName.toStdString())) { return; } - if (EntityTreeRenderer::removeMaterialFromAvatar(parentID, material, _parentMaterialName.toStdString())) { + if (EntityTreeRenderer::removeMaterialFromAvatar(oldParentID, material, _parentMaterialName.toStdString())) { return; } // if a remove fails, our parent is gone, so we don't need to retry } -void MaterialEntityRenderer::applyMaterial() { - _retryApply = false; - std::shared_ptr material = getMaterial(); - QUuid parentID = _parentID; - if (!material || parentID.isNull()) { - return; - } - +void MaterialEntityRenderer::applyTextureTransform(std::shared_ptr& material) { Transform textureTransform; if (_materialMappingMode == MaterialMappingMode::UV) { textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f)); @@ -309,6 +362,17 @@ void MaterialEntityRenderer::applyMaterial() { textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix()); } material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat); +} + +void MaterialEntityRenderer::applyMaterial() { + _retryApply = false; + std::shared_ptr& material = getMaterial(); + QUuid parentID = _parentID; + if (!material || parentID.isNull()) { + return; + } + + applyTextureTransform(material); graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, _priority); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index 5ccbb33312..639cc6c9fe 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -54,11 +54,11 @@ private: bool _retryApply { false }; std::shared_ptr getMaterial() const; - void setMaterialURL(const QString& materialURLString, bool materialDataChanged = false); void setCurrentMaterialName(const std::string& currentMaterialName); + void applyTextureTransform(std::shared_ptr& material); void applyMaterial(); - void deleteMaterial(); + void deleteMaterial(const QUuid& oldParentID); NetworkMaterialResourcePointer _networkMaterial; NetworkMaterialResource::ParsedMaterials _parsedMaterials; From 556a55ff160bc936ef2db2fc58edc9f9bf2b7bbc Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 15 Feb 2019 20:55:27 +0100 Subject: [PATCH 09/23] Better scale and texture checks --- .../avatarPackager/AvatarDoctorDiagnose.qml | 64 +++++---- .../avatarPackager/CreateAvatarProject.qml | 2 +- interface/src/avatar/AvatarDoctor.cpp | 134 +++++++++++++++--- interface/src/avatar/AvatarDoctor.h | 5 + interface/src/avatar/AvatarProject.cpp | 4 +- 5 files changed, 151 insertions(+), 58 deletions(-) diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarDoctorDiagnose.qml b/interface/resources/qml/hifi/avatarPackager/AvatarDoctorDiagnose.qml index d329b903bd..302930dee0 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarDoctorDiagnose.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarDoctorDiagnose.qml @@ -4,39 +4,59 @@ import "../../controlsUit" 1.0 as HifiControls import "../../stylesUit" 1.0 Item { - id: diagnosingScreen + id: root visible: false property var avatarDoctor: null property var errors: [] + property int minimumDiagnoseTimeMS: 1000 + signal doneDiagnosing onVisibleChanged: { - if (!diagnosingScreen.visible) { - //if (debugDelay.running) { - // debugDelay.stop(); - //} + if (root.avatarDoctor !== null) { + root.avatarDoctor.complete.disconnect(_private.avatarDoctorComplete); + root.avatarDoctor = null; + } + if (doneTimer.running) { + doneTimer.stop(); + } + + if (!root.visible) { return; } - //debugDelay.start(); - avatarDoctor = AvatarPackagerCore.currentAvatarProject.diagnose(); - avatarDoctor.complete.connect(function(errors) { + + root.avatarDoctor = AvatarPackagerCore.currentAvatarProject.diagnose(); + root.avatarDoctor.complete.connect(this, _private.avatarDoctorComplete); + _private.startTime = Date.now(); + root.avatarDoctor.startDiagnosing(); + } + + QtObject { + id: _private + property real startTime: 0 + + function avatarDoctorComplete(errors) { + if (!root.visible) { + return; + } + console.warn("avatarDoctor.complete " + JSON.stringify(errors)); - diagnosingScreen.errors = errors; + root.errors = errors; AvatarPackagerCore.currentAvatarProject.hasErrors = errors.length > 0; AvatarPackagerCore.addCurrentProjectToRecentProjects(); - // FIXME: can't seem to change state here so do it with a timer instead + let timeSpendDiagnosingMS = Date.now() - _private.startTime; + let timeLeftMS = root.minimumDiagnoseTimeMS - timeSpendDiagnosingMS; + doneTimer.interval = timeLeftMS < 0 ? 0 : timeLeftMS; doneTimer.start(); - }); - avatarDoctor.startDiagnosing(); + } } Timer { id: doneTimer - interval: 1 repeat: false running: false onTriggered: { @@ -44,24 +64,6 @@ Item { } } -/* - Timer { - id: debugDelay - interval: 5000 - repeat: false - running: false - onTriggered: { - if (Math.random() > 0.5) { - // ERROR - avatarPackager.state = AvatarPackagerState.avatarDoctorErrorReport; - } else { - // SUCCESS - avatarPackager.state = AvatarPackagerState.project; - } - } - } -*/ - property var footer: Item { anchors.fill: parent anchors.rightMargin: 17 diff --git a/interface/resources/qml/hifi/avatarPackager/CreateAvatarProject.qml b/interface/resources/qml/hifi/avatarPackager/CreateAvatarProject.qml index c299417c27..a0149b118f 100644 --- a/interface/resources/qml/hifi/avatarPackager/CreateAvatarProject.qml +++ b/interface/resources/qml/hifi/avatarPackager/CreateAvatarProject.qml @@ -32,7 +32,7 @@ Item { return; } avatarProject.reset(); - avatarPackager.state = AvatarPackagerState.project; + avatarPackager.state = AvatarPackagerState.avatarDoctorDiagnose; } } } diff --git a/interface/src/avatar/AvatarDoctor.cpp b/interface/src/avatar/AvatarDoctor.cpp index d2397ed21f..c8f5d52336 100644 --- a/interface/src/avatar/AvatarDoctor.cpp +++ b/interface/src/avatar/AvatarDoctor.cpp @@ -11,6 +11,8 @@ #include "AvatarDoctor.h" #include +#include +#include AvatarDoctor::AvatarDoctor(QUrl avatarFSTFileUrl) : _avatarFSTFileUrl(std::move(avatarFSTFileUrl)) { @@ -18,63 +20,149 @@ AvatarDoctor::AvatarDoctor(QUrl avatarFSTFileUrl) : void AvatarDoctor::startDiagnosing() { _errors.clear(); + + _externalTextureCount = 0; + _checkedTextureCount = 0; + _missingTextureCount = 0; + _unsupportedTextureCount = 0; + const auto resource = DependencyManager::get()->getGeometryResource(_avatarFSTFileUrl); - const auto resourceLoaded = [this, resource](bool success) { + resource->refresh(); + const QUrl DEFAULT_URL = QUrl("https://docs.highfidelity.com/create/avatars/create-avatars.html#create-your-own-avatar"); + const auto resourceLoaded = [this, resource, DEFAULT_URL](bool success) { // MODEL if (!success) { - _errors.push_back({ "Model file cannot be opened", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Model file cannot be opened", DEFAULT_URL }); emit complete(getErrors()); return; } + const auto model = resource.data(); const auto avatarModel = resource.data()->getHFMModel(); if (!avatarModel.originalURL.endsWith(".fbx")) { - _errors.push_back({ "Unsupported avatar model format", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Unsupported avatar model format", DEFAULT_URL }); emit complete(getErrors()); return; } // RIG if (avatarModel.joints.isEmpty()) { - _errors.push_back({ "Avatar has no rig", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Avatar has no rig", DEFAULT_URL }); } else { if (avatarModel.joints.length() > 256) { - _errors.push_back({ "Avatar has over 256 bones", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Avatar has over 256 bones", DEFAULT_URL }); } // Avatar does not have Hips bone mapped if (!avatarModel.getJointNames().contains("Hips")) { - _errors.push_back({ "Hips are not mapped", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Hips are not mapped", DEFAULT_URL }); } if (!avatarModel.getJointNames().contains("Spine")) { - _errors.push_back({ "Spine is not mapped", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Spine is not mapped", DEFAULT_URL }); } if (!avatarModel.getJointNames().contains("Head")) { - _errors.push_back({ "Head is not mapped", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Head is not mapped", DEFAULT_URL }); } } // SCALE - const float DEFAULT_HEIGHT = 1.75f; - const float RECOMMENDED_MIN_HEIGHT = DEFAULT_HEIGHT * 0.25; - const float RECOMMENDED_MAX_HEIGHT = DEFAULT_HEIGHT * 1.5; + const float RECOMMENDED_MIN_HEIGHT = DEFAULT_AVATAR_HEIGHT * 0.25f; + const float RECOMMENDED_MAX_HEIGHT = DEFAULT_AVATAR_HEIGHT * 1.5f; + + const float avatarHeight = avatarModel.bindExtents.largestDimension(); - float avatarHeight = avatarModel.getMeshExtents().largestDimension(); - - qWarning() << "avatarHeight" << avatarHeight; + qDebug() << "avatarHeight" << avatarHeight; + qDebug() << "defined Scale =" << model->getMapping()["scale"].toFloat(); if (avatarHeight < RECOMMENDED_MIN_HEIGHT) { - _errors.push_back({ "Avatar is possibly smaller then expected.", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Avatar is possibly smaller then expected.", DEFAULT_URL }); + } else if (avatarHeight > RECOMMENDED_MAX_HEIGHT) { + _errors.push_back({ "Avatar is possibly larger then expected.", DEFAULT_URL }); } - else if (avatarHeight > RECOMMENDED_MAX_HEIGHT) { - _errors.push_back({ "Avatar is possibly larger then expected.", QUrl("http://www.highfidelity.com/docs") }); - } - - // BLENDSHAPES // TEXTURES - //avatarModel.materials. + QStringList externalTextures{}; + QSet textureNames{}; + auto addTextureToList = [&externalTextures](hfm::Texture texture) mutable { + if (!texture.filename.isEmpty() && texture.content.isEmpty() && !externalTextures.contains(texture.name)) { + externalTextures << texture.name; + } + }; + + foreach(const HFMMaterial material, avatarModel.materials) { + addTextureToList(material.normalTexture); + addTextureToList(material.albedoTexture); + addTextureToList(material.opacityTexture); + addTextureToList(material.glossTexture); + addTextureToList(material.roughnessTexture); + addTextureToList(material.specularTexture); + addTextureToList(material.metallicTexture); + addTextureToList(material.emissiveTexture); + addTextureToList(material.occlusionTexture); + addTextureToList(material.scatteringTexture); + addTextureToList(material.lightmapTexture); + } + if (!externalTextures.empty()) { + // Check External Textures: + auto modelTexturesURLs = model->getTextures(); + _externalTextureCount = externalTextures.length(); + foreach(const QString textureKey, externalTextures) { + if (!modelTexturesURLs.contains(textureKey)) { + _missingTextureCount++; + _checkedTextureCount++; + continue; + } - emit complete(getErrors()); + const QUrl textureURL = modelTexturesURLs[textureKey].toUrl(); + + auto textureResource = DependencyManager::get()->getTexture(textureURL); + auto checkTextureLoadingComplete = [this, DEFAULT_URL] () mutable { + qDebug() << "checkTextureLoadingComplete" << _checkedTextureCount << "/" << _externalTextureCount; + + if (_checkedTextureCount == _externalTextureCount) { + if (_missingTextureCount == 1) { + _errors.push_back({ tr("Missing %n texture(s).","", _missingTextureCount), DEFAULT_URL }); + } + if (_unsupportedTextureCount > 0) { + _errors.push_back({ tr("%n unsupported texture(s) found.", "", _unsupportedTextureCount), DEFAULT_URL }); + } + emit complete(getErrors()); + } + }; + + auto textureLoaded = [this, textureResource, checkTextureLoadingComplete] (bool success) mutable { + if (!success) { + auto normalizedURL = DependencyManager::get()->normalizeURL(textureResource->getURL()); + if (normalizedURL.isLocalFile()) { + QFile textureFile(normalizedURL.toLocalFile()); + if (textureFile.exists()) { + _unsupportedTextureCount++; + } else { + _missingTextureCount++; + } + } else { + _missingTextureCount++; + } + } + _checkedTextureCount++; + checkTextureLoadingComplete(); + }; + + if (textureResource) { + textureResource->refresh(); + if (textureResource->isLoaded()) { + textureLoaded(!textureResource->isFailed()); + } else { + connect(textureResource.data(), &NetworkTexture::finished, this, textureLoaded); + } + } else { + _missingTextureCount++; + _checkedTextureCount++; + checkTextureLoadingComplete(); + } + } + } else { + emit complete(getErrors()); + } }; if (resource) { @@ -84,7 +172,7 @@ void AvatarDoctor::startDiagnosing() { connect(resource.data(), &GeometryResource::finished, this, resourceLoaded); } } else { - _errors.push_back({ "Model file cannot be opened", QUrl("http://www.highfidelity.com/docs") }); + _errors.push_back({ "Model file cannot be opened", DEFAULT_URL }); emit complete(getErrors()); } } diff --git a/interface/src/avatar/AvatarDoctor.h b/interface/src/avatar/AvatarDoctor.h index 65a184af71..f11bc7377c 100644 --- a/interface/src/avatar/AvatarDoctor.h +++ b/interface/src/avatar/AvatarDoctor.h @@ -45,6 +45,11 @@ signals: private: QUrl _avatarFSTFileUrl; QVector _errors; + + int _externalTextureCount = 0; + int _checkedTextureCount = 0; + int _missingTextureCount = 0; + int _unsupportedTextureCount = 0; }; #endif // hifi_AvatarDoctor_h diff --git a/interface/src/avatar/AvatarProject.cpp b/interface/src/avatar/AvatarProject.cpp index 74edabd1f5..b020cdb627 100644 --- a/interface/src/avatar/AvatarProject.cpp +++ b/interface/src/avatar/AvatarProject.cpp @@ -244,9 +244,7 @@ MarketplaceItemUploader* AvatarProject::upload(bool updateExisting) { } AvatarDoctor* AvatarProject::diagnose() { - auto avatarDoctor = new AvatarDoctor(QUrl(getFSTPath())); - - return avatarDoctor; + return new AvatarDoctor(QUrl(getFSTPath())); } void AvatarProject::openInInventory() const { From 3df231f1e06cf48bdcadf21d217354465c10715d Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Feb 2019 14:43:22 -0800 Subject: [PATCH 10/23] it's working! --- interface/src/Application.cpp | 2 + .../src/RenderableMaterialEntityItem.cpp | 58 ++++++++++++------- .../src/RenderableMaterialEntityItem.h | 5 +- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7691e06b5d..1bbe7a814d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1919,6 +1919,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { renderable->addMaterial(material, parentMaterialName); + return true; } return false; @@ -1931,6 +1932,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { renderable->removeMaterial(material, parentMaterialName); + return true; } return false; diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 31b862000b..8f11bdc31f 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -117,30 +117,29 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo bool addNeeded = _retryApply; bool urlChanged = false; + std::string newCurrentMaterialName = _currentMaterialName; { QString materialURL = entity->getMaterialURL(); if (materialURL != _materialURL) { _materialURL = materialURL; if (_materialURL.contains("?")) { auto split = _materialURL.split("?"); - _currentMaterialName = split.last().toStdString(); + newCurrentMaterialName = split.last().toStdString(); } urlChanged = true; } } bool usingMaterialData = _materialURL.startsWith("materialData"); + bool materialDataChanged = false; + QUuid oldParentID = _parentID; + QString oldParentMaterialName = _parentMaterialName; { QString materialData = entity->getMaterialData(); if (materialData != _materialData) { _materialData = materialData; if (usingMaterialData) { - _texturesLoaded = false; - deleteNeeded = true; - addNeeded = true; - _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL); - // Since our material changed, the current name might not be valid anymore, so we need to update - setCurrentMaterialName(_currentMaterialName); + materialDataChanged = true; } } } @@ -152,7 +151,6 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo addNeeded = true; } } - QUuid oldParentID = _parentID; { QUuid parentID = entity->getParentID(); if (parentID != _parentID) { @@ -172,13 +170,17 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo if (urlChanged && !usingMaterialData) { _networkMaterial = MaterialCache::instance().getMaterial(_materialURL); - auto onMaterialRequestFinished = [&, oldParentID](bool success) { + auto onMaterialRequestFinished = [&, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) { if (success) { + deleteMaterial(oldParentID, oldParentMaterialName); _texturesLoaded = false; _parsedMaterials = _networkMaterial->parsedMaterials; - setCurrentMaterialName(_currentMaterialName); - deleteMaterial(oldParentID); + setCurrentMaterialName(newCurrentMaterialName); applyMaterial(); + } else { + deleteMaterial(oldParentID, oldParentMaterialName); + _retryApply = false; + _texturesLoaded = true; } }; if (_networkMaterial) { @@ -188,9 +190,16 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished); } } + } else if (materialDataChanged && usingMaterialData) { + deleteMaterial(oldParentID, oldParentMaterialName); + _texturesLoaded = false; + _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL); + // Since our material changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(newCurrentMaterialName); + applyMaterial(); } else { if (deleteNeeded) { - deleteMaterial(oldParentID); + deleteMaterial(oldParentID, oldParentMaterialName); } if (addNeeded) { applyMaterial(); @@ -328,21 +337,21 @@ std::shared_ptr MaterialEntityRenderer::getMaterial() const { } } -void MaterialEntityRenderer::deleteMaterial(const QUuid& oldParentID) { - std::shared_ptr material = getMaterial(); - if (!material) { - return; - } - if (oldParentID.isNull()) { +void MaterialEntityRenderer::deleteMaterial(const QUuid& oldParentID, const QString& oldParentMaterialName) { + std::shared_ptr material = _appliedMaterial; + if (!material || oldParentID.isNull()) { return; } // Our parent could be an entity or an avatar - if (EntityTreeRenderer::removeMaterialFromEntity(oldParentID, material, _parentMaterialName.toStdString())) { + std::string oldParentMaterialNameStd = oldParentMaterialName.toStdString(); + if (EntityTreeRenderer::removeMaterialFromEntity(oldParentID, material, oldParentMaterialNameStd)) { + _appliedMaterial = nullptr; return; } - if (EntityTreeRenderer::removeMaterialFromAvatar(oldParentID, material, _parentMaterialName.toStdString())) { + if (EntityTreeRenderer::removeMaterialFromAvatar(oldParentID, material, oldParentMaterialNameStd)) { + _appliedMaterial = nullptr; return; } @@ -366,9 +375,11 @@ void MaterialEntityRenderer::applyTextureTransform(std::shared_ptr& material = getMaterial(); QUuid parentID = _parentID; if (!material || parentID.isNull()) { + _appliedMaterial = nullptr; return; } @@ -377,11 +388,14 @@ void MaterialEntityRenderer::applyMaterial() { graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, _priority); // Our parent could be an entity or an avatar - if (EntityTreeRenderer::addMaterialToEntity(parentID, materialLayer, _parentMaterialName.toStdString())) { + std::string parentMaterialName = _parentMaterialName.toStdString(); + if (EntityTreeRenderer::addMaterialToEntity(parentID, materialLayer, parentMaterialName)) { + _appliedMaterial = material; return; } - if (EntityTreeRenderer::addMaterialToAvatar(parentID, materialLayer, _parentMaterialName.toStdString())) { + if (EntityTreeRenderer::addMaterialToAvatar(parentID, materialLayer, parentMaterialName)) { + _appliedMaterial = material; return; } diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index b68aee9d48..d714727c7a 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -24,7 +24,7 @@ class MaterialEntityRenderer : public TypedEntityRenderer { using Pointer = std::shared_ptr; public: MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {} - ~MaterialEntityRenderer() { deleteMaterial(_parentID); } + ~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); } private: virtual bool needsRenderUpdate() const override; @@ -57,10 +57,11 @@ private: void applyTextureTransform(std::shared_ptr& material); void applyMaterial(); - void deleteMaterial(const QUuid& oldParentID); + void deleteMaterial(const QUuid& oldParentID, const QString& oldParentMaterialName); NetworkMaterialResourcePointer _networkMaterial; NetworkMaterialResource::ParsedMaterials _parsedMaterials; + std::shared_ptr _appliedMaterial; std::string _currentMaterialName; }; From bb123cfe3bb46216adb5f06c0dd146be325873bc Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 15 Feb 2019 11:14:49 -0800 Subject: [PATCH 11/23] Fix GLTF materials --- .../src/material-networking/TextureCache.cpp | 11 ++++++----- .../src/material-networking/TextureCache.h | 2 +- .../src/model-networking/ModelCache.cpp | 4 ++-- libraries/networking/src/ResourceCache.cpp | 4 ++-- libraries/networking/src/ResourceCache.h | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/libraries/material-networking/src/material-networking/TextureCache.cpp b/libraries/material-networking/src/material-networking/TextureCache.cpp index ee3c88f02c..9a9720c87d 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.cpp +++ b/libraries/material-networking/src/material-networking/TextureCache.cpp @@ -368,16 +368,17 @@ static bool isLocalUrl(const QUrl& url) { return (scheme == HIFI_URL_SCHEME_FILE || scheme == URL_SCHEME_QRC || scheme == RESOURCE_SCHEME); } -void NetworkTexture::setExtra(void* extra) { +void NetworkTexture::setExtra(void* extra, bool isNewExtra) { const TextureExtra* textureExtra = static_cast(extra); _type = textureExtra ? textureExtra->type : image::TextureUsage::DEFAULT_TEXTURE; _maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS; _sourceChannel = textureExtra ? textureExtra->sourceChannel : image::ColorChannel::NONE; - if (_textureSource) { - _textureSource->setUrl(_url); - _textureSource->setType((int)_type); - } else { + if (isNewExtra && !_loaded) { + _startedLoading = false; + } + + if (!_textureSource || isNewExtra) { _textureSource = std::make_shared(_url, (int)_type); } _lowestRequestedMipLevel = 0; diff --git a/libraries/material-networking/src/material-networking/TextureCache.h b/libraries/material-networking/src/material-networking/TextureCache.h index acca916acc..a8b152c40e 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.h +++ b/libraries/material-networking/src/material-networking/TextureCache.h @@ -64,7 +64,7 @@ public: Q_INVOKABLE void setOriginalDescriptor(ktx::KTXDescriptor* descriptor) { _originalKtxDescriptor.reset(descriptor); } - void setExtra(void* extra) override; + void setExtra(void* extra, bool isNewExtra) override; signals: void networkTextureCreated(const QWeakPointer& self); diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 581196b2cc..b2645d20c8 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -309,7 +309,7 @@ public: virtual void downloadFinished(const QByteArray& data) override; - void setExtra(void* extra) override; + void setExtra(void* extra, bool isNewExtra) override; protected: Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel, QVariantHash mapping); @@ -320,7 +320,7 @@ private: bool _combineParts; }; -void GeometryDefinitionResource::setExtra(void* extra) { +void GeometryDefinitionResource::setExtra(void* extra, bool isNewExtra) { const GeometryExtra* geometryExtra = static_cast(extra); _mapping = geometryExtra ? geometryExtra->mapping : QVariantHash(); _textureBaseUrl = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl(); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 7345081380..8ad1b41020 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -355,7 +355,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& } else if (resourcesWithExtraHash.size() > 0.0f) { // We haven't seen this extra info before, but we've already downloaded the resource. We need a new copy of this object (with any old hash). resource = createResourceCopy(resourcesWithExtraHash.begin().value().lock()); - resource->setExtra(extra); + resource->setExtra(extra, true); resource->setExtraHash(extraHash); resource->setSelf(resource); resource->setCache(this); @@ -375,7 +375,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& if (!resource) { resource = createResource(url); - resource->setExtra(extra); + resource->setExtra(extra, false); resource->setExtraHash(extraHash); resource->setSelf(resource); resource->setCache(this); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 2096213273..62800a6ac2 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -417,7 +417,7 @@ public: unsigned int getDownloadAttempts() { return _attempts; } unsigned int getDownloadAttemptsRemaining() { return _attemptsRemaining; } - virtual void setExtra(void* extra) {}; + virtual void setExtra(void* extra, bool isNewExtra) {}; void setExtraHash(size_t extraHash) { _extraHash = extraHash; } size_t getExtraHash() const { return _extraHash; } From e900d3784be72a9f9576ac9d835b4878e895fe2d Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 15 Feb 2019 23:58:42 +0100 Subject: [PATCH 12/23] fixes --- .../AvatarDoctorErrorReport.qml | 22 ++++++---------- interface/src/avatar/AvatarDoctor.cpp | 25 ++++++++++++------- interface/src/avatar/AvatarDoctor.h | 8 ++---- interface/src/avatar/AvatarPackager.cpp | 2 -- 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarDoctorErrorReport.qml b/interface/resources/qml/hifi/avatarPackager/AvatarDoctorErrorReport.qml index 8811ba48a3..73c5e34d13 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarDoctorErrorReport.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarDoctorErrorReport.qml @@ -21,7 +21,6 @@ Item { height: 40 width: 134 text: qsTr("Try Again") - // colorScheme: root.colorScheme onClicked: { avatarPackager.state = AvatarPackagerState.avatarDoctorDiagnose; } @@ -49,7 +48,7 @@ Item { color: "#EA4C5F" anchors { top: parent.top - //topMargin: 73 + topMargin: -20 horizontalCenter: parent.horizontalCenter } } @@ -60,7 +59,7 @@ Item { right: parent.right bottom: parent.bottom top: errorReportIcon.bottom - topMargin: 27 + topMargin: -40 leftMargin: 13 rightMargin: 13 } @@ -68,15 +67,6 @@ Item { Repeater { id: errorRepeater - /*model: [ - {message: "Rig is not Hifi compatible", url: "http://www.highfidelity.com/"}, - {message: "Bone limit exceeds 256", url: "http://www.highfidelity.com/2"}, - {message: "Unsupported Texture", url: "http://www.highfidelity.com/texture"}, - {message: "Rig is not Hifi compatible", url: "http://www.highfidelity.com/"}, - {message: "Bone limit exceeds 256", url: "http://www.highfidelity.com/2"}, - {message: "Unsupported Texture", url: "http://www.highfidelity.com/texture"} - ]*/ - Item { height: 37 width: parent.width @@ -89,6 +79,7 @@ Item { anchors { top: parent.top left: parent.left + leftMargin: -5 } } @@ -96,17 +87,18 @@ Item { id: errorLink anchors { top: parent.top + topMargin: 5 left: errorIcon.right right: parent.right } - linkColor: "#00B4EF"// style.colors.blueHighlight + color: "#00B4EF" + linkColor: "#00B4EF" size: 28 text: "" + modelData.message + "" onLinkActivated: Qt.openUrlExternally(modelData.url) + elide: Text.ElideRight } } } } - - } diff --git a/interface/src/avatar/AvatarDoctor.cpp b/interface/src/avatar/AvatarDoctor.cpp index c8f5d52336..b528441be7 100644 --- a/interface/src/avatar/AvatarDoctor.cpp +++ b/interface/src/avatar/AvatarDoctor.cpp @@ -14,11 +14,22 @@ #include #include + AvatarDoctor::AvatarDoctor(QUrl avatarFSTFileUrl) : - _avatarFSTFileUrl(std::move(avatarFSTFileUrl)) { + _avatarFSTFileUrl(avatarFSTFileUrl) { + + connect(this, &AvatarDoctor::complete, this, [this](QVariantList errors) { + _isDiagnosing = false; + }); } void AvatarDoctor::startDiagnosing() { + if (_isDiagnosing) { + // One diagnose at a time for now + return; + } + _isDiagnosing = true; + _errors.clear(); _externalTextureCount = 0; @@ -47,8 +58,7 @@ void AvatarDoctor::startDiagnosing() { // RIG if (avatarModel.joints.isEmpty()) { _errors.push_back({ "Avatar has no rig", DEFAULT_URL }); - } - else { + } else { if (avatarModel.joints.length() > 256) { _errors.push_back({ "Avatar has over 256 bones", DEFAULT_URL }); } @@ -69,13 +79,10 @@ void AvatarDoctor::startDiagnosing() { const float RECOMMENDED_MAX_HEIGHT = DEFAULT_AVATAR_HEIGHT * 1.5f; const float avatarHeight = avatarModel.bindExtents.largestDimension(); - - qDebug() << "avatarHeight" << avatarHeight; - qDebug() << "defined Scale =" << model->getMapping()["scale"].toFloat(); if (avatarHeight < RECOMMENDED_MIN_HEIGHT) { - _errors.push_back({ "Avatar is possibly smaller then expected.", DEFAULT_URL }); + _errors.push_back({ "Avatar is possibly too small.", DEFAULT_URL }); } else if (avatarHeight > RECOMMENDED_MAX_HEIGHT) { - _errors.push_back({ "Avatar is possibly larger then expected.", DEFAULT_URL }); + _errors.push_back({ "Avatar is possibly too large.", DEFAULT_URL }); } // TEXTURES @@ -119,7 +126,7 @@ void AvatarDoctor::startDiagnosing() { qDebug() << "checkTextureLoadingComplete" << _checkedTextureCount << "/" << _externalTextureCount; if (_checkedTextureCount == _externalTextureCount) { - if (_missingTextureCount == 1) { + if (_missingTextureCount > 0) { _errors.push_back({ tr("Missing %n texture(s).","", _missingTextureCount), DEFAULT_URL }); } if (_unsupportedTextureCount > 0) { diff --git a/interface/src/avatar/AvatarDoctor.h b/interface/src/avatar/AvatarDoctor.h index f11bc7377c..bebec32542 100644 --- a/interface/src/avatar/AvatarDoctor.h +++ b/interface/src/avatar/AvatarDoctor.h @@ -13,17 +13,11 @@ #ifndef hifi_AvatarDoctor_h #define hifi_AvatarDoctor_h -#include #include #include #include struct AvatarDiagnosticResult { - -//public: - // AvatarDiagnosticResult() {} - // AvatarDiagnosticResult(QString message, QUrl url) : _message(std::move(message)), _url(std::move(url)) { } -//private: QString message; QUrl url; }; @@ -50,6 +44,8 @@ private: int _checkedTextureCount = 0; int _missingTextureCount = 0; int _unsupportedTextureCount = 0; + + bool _isDiagnosing = false; }; #endif // hifi_AvatarDoctor_h diff --git a/interface/src/avatar/AvatarPackager.cpp b/interface/src/avatar/AvatarPackager.cpp index 24f31cac9c..90def7ad43 100644 --- a/interface/src/avatar/AvatarPackager.cpp +++ b/interface/src/avatar/AvatarPackager.cpp @@ -32,8 +32,6 @@ AvatarPackager::AvatarPackager() { qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType>(); qRegisterMetaType(); qmlRegisterUncreatableMetaObject( AvatarProjectStatus::staticMetaObject, From 6bf154528598efa3ed8509a8f4be0903c9da0367 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Feb 2019 16:44:28 -0800 Subject: [PATCH 13/23] fix build error --- .../src/RenderableMaterialEntityItem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 8f11bdc31f..57d8fd76f7 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -106,7 +106,7 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo } { - auto& material = getMaterial(); + auto material = getMaterial(); // Update the old material regardless of if it's going to change if (transformChanged && material && !_parentID.isNull()) { applyTextureTransform(material); @@ -207,7 +207,7 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo } { - auto& material = getMaterial(); + auto material = getMaterial(); bool newTexturesLoaded = material ? !material->isMissingTexture() : false; if (!_texturesLoaded && newTexturesLoaded) { material->checkResetOpacityMap(); @@ -230,7 +230,7 @@ ItemKey MaterialEntityRenderer::getKey() { builder.withInvisible(); } - const auto& drawMaterial = getMaterial(); + const auto drawMaterial = getMaterial(); if (drawMaterial) { auto matKey = drawMaterial->getKey(); if (matKey.isTranslucent()) { @@ -243,7 +243,7 @@ ItemKey MaterialEntityRenderer::getKey() { ShapeKey MaterialEntityRenderer::getShapeKey() { graphics::MaterialKey drawMaterialKey; - const auto& drawMaterial = getMaterial(); + const auto drawMaterial = getMaterial(); if (drawMaterial) { drawMaterialKey = drawMaterial->getKey(); } @@ -376,7 +376,7 @@ void MaterialEntityRenderer::applyTextureTransform(std::shared_ptr& material = getMaterial(); + std::shared_ptr material = getMaterial(); QUuid parentID = _parentID; if (!material || parentID.isNull()) { _appliedMaterial = nullptr; From e9b323a8078cfaac63b746d50899bbedbd738220 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 15 Feb 2019 16:56:31 -0800 Subject: [PATCH 14/23] fix HFC symbol location at checkout, and the display of unavailable items --- .../resources/qml/hifi/commerce/checkout/Checkout.qml | 8 ++++---- .../qml/hifi/commerce/marketplace/MarketplaceItem.qml | 2 +- .../qml/hifi/commerce/marketplace/MarketplaceListItem.qml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 5ea9b2d4b4..9589c842e6 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -469,8 +469,8 @@ Rectangle { // Size size: 30; // Anchors - anchors.right: itemPriceText.left; - anchors.rightMargin: 4; + anchors.right: parent.right; + //anchors.rightMargin: 4; anchors.top: parent.top; anchors.topMargin: 0; width: paintedWidth; @@ -487,8 +487,8 @@ Rectangle { size: isTradingIn ? 20 : 26; // Anchors anchors.top: parent.top; - anchors.right: parent.right; - anchors.rightMargin: 16; + anchors.left: itemPriceTextLabel.visible ? itemPriceTextLabel.right : parent.left; + anchors.leftMargin: 4; width: paintedWidth; height: paintedHeight; // Style diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml index 45ed213660..97e5c10a6b 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml @@ -270,7 +270,7 @@ Rectangle { property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price property bool isAvailable: costToMe >= 0 - text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : ("UNAVAILABLE (" + availibility + ")")) + text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : availability) enabled: isAvailable buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : "" color: hifi.buttons.blue diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml index fd3b960002..587d71da28 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml @@ -305,7 +305,7 @@ Rectangle { property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price property bool isAvailable: costToMe >= 0 - text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : ("UNAVAILABLE (" + availibility + ")")) + text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : availability) enabled: isAvailable buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : "" From 3e3bd2ffd85be7b474a0ab4b35cd050cc0c838db Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Feb 2019 16:57:29 -0800 Subject: [PATCH 15/23] fix transform properties not changing --- .../src/RenderableMaterialEntityItem.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 57d8fd76f7..2eb877b0e1 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -26,7 +26,6 @@ bool MaterialEntityRenderer::needsRenderUpdate() const { bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { if (resultWithReadLock([&] { - // Won't cause material re-apply if (entity->getMaterialMappingMode() != _materialMappingMode) { return true; } @@ -43,7 +42,6 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP return true; } - // Could require material re-apply if (entity->getMaterialURL() != _materialURL) { return true; } @@ -69,6 +67,8 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { withWriteLock([&] { + bool deleteNeeded = false; + bool addNeeded = _retryApply; bool transformChanged = false; { MaterialMappingMode mode = entity->getMaterialMappingMode(); @@ -109,14 +109,13 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo auto material = getMaterial(); // Update the old material regardless of if it's going to change if (transformChanged && material && !_parentID.isNull()) { + deleteNeeded = true; + addNeeded = true; applyTextureTransform(material); } } - bool deleteNeeded = false; - bool addNeeded = _retryApply; bool urlChanged = false; - std::string newCurrentMaterialName = _currentMaterialName; { QString materialURL = entity->getMaterialURL(); From d50904dd4a209c0da209095133a336b7118d4362 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 15 Feb 2019 17:08:24 -0800 Subject: [PATCH 16/23] fix avatar deadlock --- libraries/avatars/src/AvatarHashMap.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 5f30d98ed6..c16d65506a 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -208,16 +208,16 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe avatar->setSessionUUID(sessionUUID); avatar->setOwningAvatarMixer(mixerWeakPointer); - // addAvatar is only called from newOrExistingAvatar, which already locks _hashLock - _avatarHash.insert(sessionUUID, avatar); + { + QWriteLocker locker(&_hashLock); + _avatarHash.insert(sessionUUID, avatar); + } emit avatarAddedEvent(sessionUUID); return avatar; } -AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer, - bool& isNew) { - QWriteLocker locker(&_hashLock); - auto avatar = _avatarHash.value(sessionUUID); +AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer, bool& isNew) { + auto avatar = findAvatar(sessionUUID); if (!avatar) { avatar = addAvatar(sessionUUID, mixerWeakPointer); isNew = true; From c8ab7ac37f5ff6624c1b8ad6cb74cb02a2357304 Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Sat, 16 Feb 2019 18:08:05 -0800 Subject: [PATCH 17/23] fix bad copy --- libraries/entities-renderer/src/EntityTreeRenderer.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 154ad08811..def17ac835 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -265,8 +265,6 @@ private: workload::SpacePointer _space{ new workload::Space() }; workload::Transaction::Updates _spaceUpdates; - static std::function _getAvatarUpOperator; - static std::function _addMaterialToEntityOperator; static std::function _removeMaterialFromEntityOperator; static std::function _addMaterialToAvatarOperator; From 71653f95d7b51a6677d5bbab7f85023162842795 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Sat, 16 Feb 2019 20:08:36 -0800 Subject: [PATCH 18/23] working on overlay bugs --- interface/src/Application.cpp | 2 +- .../ui/overlays/ContextOverlayInterface.cpp | 19 +++++++---------- .../src/ui/overlays/ContextOverlayInterface.h | 1 - interface/src/ui/overlays/Overlays.cpp | 21 +++++++------------ interface/src/ui/overlays/Overlays.h | 1 - .../src/EntityTreeRenderer.h | 1 + .../controllers/controllerModules/teleport.js | 2 +- scripts/system/pal.js | 3 ++- 8 files changed, 19 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b65f39ffd7..fc53253b00 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2282,7 +2282,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Setup the mouse ray pick and related operators { - auto mouseRayPick = std::make_shared(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES()), 0.0f, true); + auto mouseRayPick = std::make_shared(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_LOCAL_ENTITIES()), 0.0f, true); mouseRayPick->parentTransform = std::make_shared(); mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE); auto mouseRayPickID = DependencyManager::get()->addPick(PickQuery::Ray, mouseRayPick); diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index c382c3de43..24c0986d09 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -70,7 +70,6 @@ ContextOverlayInterface::ContextOverlayInterface() { } }); connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity); - connect(&qApp->getOverlays(), &Overlays::mousePressOnOverlay, this, &ContextOverlayInterface::contextOverlays_mousePressOnOverlay); connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay); connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay); @@ -103,10 +102,14 @@ void ContextOverlayInterface::setEnabled(bool enabled) { } } -void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { - if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID)) { - _mouseDownEntity = entityItemID; +void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& id, const PointerEvent& event) { + if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(id)) { + _mouseDownEntity = id; _mouseDownEntityTimestamp = usecTimestampNow(); + } else if (id == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) { + qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "ID:" << id; + emit contextOverlayClicked(_currentEntityWithContextOverlay); + _contextOverlayJustClicked = true; } else { if (!_currentEntityWithContextOverlay.isNull()) { disableEntityHighlight(_currentEntityWithContextOverlay); @@ -249,14 +252,6 @@ bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityIt return ContextOverlayInterface::destroyContextOverlay(entityItemID, PointerEvent()); } -void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const QUuid& id, const PointerEvent& event) { - if (id == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) { - qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "ID:" << id; - emit contextOverlayClicked(_currentEntityWithContextOverlay); - _contextOverlayJustClicked = true; - } -} - void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event) { if (_contextOverlayID != UNKNOWN_ENTITY_ID) { qCDebug(context_overlay) << "Started hovering over Context Overlay. ID:" << id; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index b87535acf2..57fc8ebe6e 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -65,7 +65,6 @@ public slots: bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); bool destroyContextOverlay(const EntityItemID& entityItemID); - void contextOverlays_mousePressOnOverlay(const QUuid& id, const PointerEvent& event); void contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event); void contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event); void contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index e1708c14fe..2ec67070ba 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -63,13 +63,6 @@ Overlays::Overlays() { ADD_TYPE_MAP(PolyLine, line3d); ADD_TYPE_MAP(Grid, grid); ADD_TYPE_MAP(Gizmo, circle3d); - - auto mouseRayPick = std::make_shared(Vectors::ZERO, Vectors::UP, - PickFilter(PickFilter::getBitMask(PickFilter::FlagBit::LOCAL_ENTITIES) | - PickFilter::getBitMask(PickFilter::FlagBit::VISIBLE)), 0.0f, true); - mouseRayPick->parentTransform = std::make_shared(); - mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE); - _mouseRayPickID = DependencyManager::get()->addPick(PickQuery::Ray, mouseRayPick); } void Overlays::cleanupAllOverlays() { @@ -1228,12 +1221,12 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) { } } -RayToOverlayIntersectionResult getPrevPickResult(unsigned int mouseRayPickID) { +RayToOverlayIntersectionResult getPrevPickResult() { RayToOverlayIntersectionResult overlayResult; overlayResult.intersects = false; - auto pickResult = DependencyManager::get()->getPrevPickResultTyped(mouseRayPickID); + auto pickResult = DependencyManager::get()->getPrevPickResultTyped(DependencyManager::get()->getMouseRayPickID()); if (pickResult) { - overlayResult.intersects = pickResult->type != IntersectionType::NONE; + overlayResult.intersects = pickResult->type == IntersectionType::LOCAL_ENTITY; if (overlayResult.intersects) { overlayResult.intersection = pickResult->intersection; overlayResult.distance = pickResult->distance; @@ -1281,7 +1274,7 @@ std::pair Overlays::mousePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mousePressEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID); + RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); if (rayPickResult.intersects) { _currentClickingOnOverlayID = rayPickResult.overlayID; @@ -1305,7 +1298,7 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID); + RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); if (rayPickResult.intersects) { _currentClickingOnOverlayID = rayPickResult.overlayID; @@ -1321,7 +1314,7 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseReleaseEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID); + RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); if (rayPickResult.intersects) { auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release); mouseReleasePointerEvent(rayPickResult.overlayID, pointerEvent); @@ -1343,7 +1336,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseMoveEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID); + RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); if (rayPickResult.intersects) { auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move); mouseMovePointerEvent(rayPickResult.overlayID, pointerEvent); diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 7612779099..838a38eb54 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -719,7 +719,6 @@ private: PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult, QMouseEvent* event, PointerEvent::EventType eventType); - unsigned int _mouseRayPickID; QUuid _currentClickingOnOverlayID; QUuid _currentHoverOverOverlayID; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 204dc50c45..50e74f7cea 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -73,6 +73,7 @@ public: static void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { _calculateEntityLoadingPriorityFunc = fn; } void setMouseRayPickID(unsigned int rayPickID) { _mouseRayPickID = rayPickID; } + unsigned int getMouseRayPickID() { return _mouseRayPickID; } void setMouseRayPickResultOperator(std::function getPrevRayPickResultOperator) { _getPrevRayPickResultOperator = getPrevRayPickResultOperator; } void setSetPrecisionPickingOperator(std::function setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; } diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 8770ae8dde..48b23d834e 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -578,7 +578,7 @@ Script.include("/~/system/libraries/controllers.js"); } } _this.teleportedFadeTimer = null; - Selection.disableListHighlight(this.teleporterSelectionName); + Selection.disableListHighlight(_this.teleporterSelectionName); } }; diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 141ea03330..0c4338b31d 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -161,7 +161,8 @@ ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId // hit(overlay) on the one overlay intersected by pickRay, if any. // noHit() if no ExtendedOverlay was intersected (helps with hover) ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) { - var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones. + // TODO: this could just include the necessary overlays for better performance + var pickedOverlay = Overlays.findRayIntersection(pickRay, true); // Depends on nearer coverOverlays to extend closer to us than farther ones. if (!pickedOverlay.intersects) { if (noHit) { return noHit(); From 7677e3bf4444a63fc2533087fd83ef875aca5757 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Sat, 16 Feb 2019 20:41:57 -0800 Subject: [PATCH 19/23] just in case --- .../controllers/controllerModules/teleport.js | 174 +++++++++--------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 48b23d834e..23457cdd85 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -196,14 +196,14 @@ Script.include("/~/system/libraries/controllers.js"); var playAreaOverlayProperties = { dimensions: - Vec3.multiply(this.teleportScaleFactor * avatarScale, { - x: this.playArea.width, - y: this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y, - z: this.playArea.height + Vec3.multiply(_this.teleportScaleFactor * avatarScale, { + x: _this.playArea.width, + y: _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y, + z: _this.playArea.height }) }; - if (this.teleportScaleFactor < 1) { + if (_this.teleportScaleFactor < 1) { // Adjust position of playAreOverlay so that its base is at correct height. // Always parenting to teleport target is good enough for this. var sensorToWorldMatrix = MyAvatar.sensorToWorldMatrix; @@ -212,37 +212,37 @@ Script.include("/~/system/libraries/controllers.js"); var avatarSensorPosition = Mat4.transformPoint(worldToSensorMatrix, MyAvatar.position); avatarSensorPosition.y = 0; - var targetRotation = Overlays.getProperty(this.targetOverlayID, "rotation"); + var targetRotation = Overlays.getProperty(_this.targetOverlayID, "rotation"); var relativePlayAreaCenterOffset = - Vec3.sum(this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); + Vec3.sum(_this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); var localPosition = Vec3.multiplyQbyV(Quat.inverse(targetRotation), Vec3.multiplyQbyV(sensorToWorldRotation, Vec3.multiply(avatarScale, Vec3.subtract(relativePlayAreaCenterOffset, avatarSensorPosition)))); - localPosition.y = this.teleportScaleFactor * localPosition.y; + localPosition.y = _this.teleportScaleFactor * localPosition.y; - playAreaOverlayProperties.parentID = this.targetOverlayID; + playAreaOverlayProperties.parentID = _this.targetOverlayID; playAreaOverlayProperties.localPosition = localPosition; } - Overlays.editOverlay(this.playAreaOverlay, playAreaOverlayProperties); + Overlays.editOverlay(_this.playAreaOverlay, playAreaOverlayProperties); - for (var i = 0; i < this.playAreaSensorPositionOverlays.length; i++) { - localPosition = this.playAreaSensorPositions[i]; + for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { + localPosition = _this.playAreaSensorPositions[i]; localPosition = Vec3.multiply(avatarScale, localPosition); // Position relative to the play area. - localPosition.y = avatarScale * (this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2 - - this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2); - Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], { - dimensions: Vec3.multiply(this.teleportScaleFactor * avatarScale, this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS), - parentID: this.playAreaOverlay, + localPosition.y = avatarScale * (_this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2 + - _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2); + Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { + dimensions: Vec3.multiply(_this.teleportScaleFactor * avatarScale, _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS), + parentID: _this.playAreaOverlay, localPosition: localPosition }); } }; this.updatePlayAreaScale = function () { - if (this.isPlayAreaAvailable) { - this.setPlayAreaDimensions(); + if (_this.isPlayAreaAvailable) { + _this.setPlayAreaDimensions(); } }; @@ -265,7 +265,7 @@ Script.include("/~/system/libraries/controllers.js"); for (var i = 0, length = teleportRenderStates.length; i < length; i++) { var state = properties.renderStates[teleportRenderStates[i].name]; if (state && state.end) { - Selection.addToSelectedItemsList(this.teleporterSelectionName, "overlay", state.end); + Selection.addToSelectedItemsList(_this.teleporterSelectionName, "overlay", state.end); } } }; @@ -448,34 +448,34 @@ Script.include("/~/system/libraries/controllers.js"); this.translateZAction = Controller.findAction("TranslateZ"); this.setPlayAreaVisible = function (visible, targetOverlayID, fade) { - if (!this.isPlayAreaAvailable || this.isPlayAreaVisible === visible) { + if (!_this.isPlayAreaAvailable || _this.isPlayAreaVisible === visible) { return; } - this.wasPlayAreaVisible = this.isPlayAreaVisible; - this.isPlayAreaVisible = visible; - this.targetOverlayID = targetOverlayID; + _this.wasPlayAreaVisible = _this.isPlayAreaVisible; + _this.isPlayAreaVisible = visible; + _this.targetOverlayID = targetOverlayID; - if (this.teleportedFadeTimer !== null) { - Script.clearTimeout(this.teleportedFadeTimer); - this.teleportedFadeTimer = null; + if (_this.teleportedFadeTimer !== null) { + Script.clearTimeout(_this.teleportedFadeTimer); + _this.teleportedFadeTimer = null; } if (visible || !fade) { // Immediately make visible or invisible. - this.isPlayAreaVisible = visible; - Overlays.editOverlay(this.playAreaOverlay, { + _this.isPlayAreaVisible = visible; + Overlays.editOverlay(_this.playAreaOverlay, { dimensions: Vec3.ZERO, - alpha: this.PLAY_AREA_BOX_ALPHA, + alpha: _this.PLAY_AREA_BOX_ALPHA, visible: visible }); - for (var i = 0; i < this.playAreaSensorPositionOverlays.length; i++) { - Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], { + for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { + Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { dimensions: Vec3.ZERO, - alpha: this.PLAY_AREA_SENSOR_ALPHA, + alpha: _this.PLAY_AREA_SENSOR_ALPHA, visible: visible }); } - Overlays.editOverlay(this.teleportedTargetOverlay, { visible: false }); + Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false }); } else { // Fading out of overlays is initiated in setTeleportVisible(). } @@ -494,22 +494,22 @@ Script.include("/~/system/libraries/controllers.js"); var MIN_PARENTING_DISTANCE = 0.2; // Parenting under this distance results in the play area's rotation jittering. if (Vec3.distance(targetXZPosition, avatarXZPosition) < MIN_PARENTING_DISTANCE) { // Set play area position and rotation in world coordinates with no parenting. - Overlays.editOverlay(this.playAreaOverlay, { + Overlays.editOverlay(_this.playAreaOverlay, { parentID: Uuid.NULL, position: Vec3.sum(position, Vec3.multiplyQbyV(sensorToWorldRotation, Vec3.multiply(MyAvatar.sensorToWorldScale, - Vec3.subtract(this.playAreaCenterOffset, avatarSensorPosition)))), + Vec3.subtract(_this.playAreaCenterOffset, avatarSensorPosition)))), rotation: sensorToWorldRotation }); } else { // Set play area position and rotation in local coordinates with parenting. - var targetRotation = Overlays.getProperty(this.targetOverlayID, "rotation"); + var targetRotation = Overlays.getProperty(_this.targetOverlayID, "rotation"); var sensorToTargetRotation = Quat.multiply(Quat.inverse(targetRotation), sensorToWorldRotation); var relativePlayAreaCenterOffset = - Vec3.sum(this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); - Overlays.editOverlay(this.playAreaOverlay, { - parentID: this.targetOverlayID, + Vec3.sum(_this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); + Overlays.editOverlay(_this.playAreaOverlay, { + parentID: _this.targetOverlayID, localPosition: Vec3.multiplyQbyV(Quat.inverse(targetRotation), Vec3.multiplyQbyV(sensorToWorldRotation, Vec3.multiply(MyAvatar.sensorToWorldScale, @@ -585,26 +585,26 @@ Script.include("/~/system/libraries/controllers.js"); this.cancelFade = function () { // Other hand may call this to immediately hide fading overlays. var i, length; - if (this.teleportedFadeTimer) { - Overlays.editOverlay(this.teleportedTargetOverlay, { visible: false }); - if (this.wasPlayAreaVisible) { - Overlays.editOverlay(this.playAreaOverlay, { visible: false }); - for (i = 0, length = this.playAreaSensorPositionOverlays.length; i < length; i++) { - Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], { visible: false }); + if (_this.teleportedFadeTimer) { + Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false }); + if (_this.wasPlayAreaVisible) { + Overlays.editOverlay(_this.playAreaOverlay, { visible: false }); + for (i = 0, length = _this.playAreaSensorPositionOverlays.length; i < length; i++) { + Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { visible: false }); } } - this.teleportedFadeTimer = null; + _this.teleportedFadeTimer = null; } }; this.setTeleportVisible = function (visible, mode, fade) { // Scales in teleport target and play area when start displaying them. - if (visible === this.isTeleportVisible) { + if (visible === _this.isTeleportVisible) { return; } if (visible) { - this.teleportScaleMode = mode; + _this.teleportScaleMode = mode; Pointers.editRenderState( mode === "head" ? _this.teleportParabolaHeadVisuals : _this.teleportParabolaHandVisuals, "teleport", @@ -613,42 +613,42 @@ Script.include("/~/system/libraries/controllers.js"); end: { dimensions: Vec3.ZERO } } ); - this.getOtherModule().cancelFade(); - this.teleportScaleStart = Date.now(); - this.teleportScaleFactor = 0; - this.scaleInTeleport(); - Selection.enableListHighlight(this.teleporterSelectionName, this.TELEPORTER_SELECTION_STYLE); + _this.getOtherModule().cancelFade(); + _this.teleportScaleStart = Date.now(); + _this.teleportScaleFactor = 0; + _this.scaleInTeleport(); + Selection.enableListHighlight(_this.teleporterSelectionName, _this.TELEPORTER_SELECTION_STYLE); } else { - if (this.teleportScaleTimer !== null) { - Script.clearTimeout(this.teleportScaleTimer); - this.teleportScaleTimer = null; + if (_this.teleportScaleTimer !== null) { + Script.clearTimeout(_this.teleportScaleTimer); + _this.teleportScaleTimer = null; } if (fade) { // Copy of target at teleported position for fading. var avatarScale = MyAvatar.sensorToWorldScale; - Overlays.editOverlay(this.teleportedTargetOverlay, { - position: Vec3.sum(this.teleportedPosition, { + Overlays.editOverlay(_this.teleportedTargetOverlay, { + position: Vec3.sum(_this.teleportedPosition, { x: 0, y: -getAvatarFootOffset() + avatarScale * TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }), - rotation: Quat.multiply(this.TELEPORTED_TARGET_ROTATION, MyAvatar.orientation), + rotation: Quat.multiply(_this.TELEPORTED_TARGET_ROTATION, MyAvatar.orientation), dimensions: Vec3.multiply(avatarScale, TARGET_MODEL_DIMENSIONS), - alpha: this.TELEPORTED_TARGET_ALPHA, + alpha: _this.TELEPORTED_TARGET_ALPHA, visible: true }); // Fade out over time. - this.teleportedFadeDelayFactor = 1.0; - this.teleportedFadeFactor = 1.0; - this.teleportedFadeTimer = Script.setTimeout(this.fadeOutTeleport, this.TELEPORTED_FADE_DELAY); + _this.teleportedFadeDelayFactor = 1.0; + _this.teleportedFadeFactor = 1.0; + _this.teleportedFadeTimer = Script.setTimeout(_this.fadeOutTeleport, _this.TELEPORTED_FADE_DELAY); } else { - Selection.disableListHighlight(this.teleporterSelectionName); + Selection.disableListHighlight(_this.teleporterSelectionName); } } - this.isTeleportVisible = visible; + _this.isTeleportVisible = visible; }; @@ -697,7 +697,7 @@ Script.include("/~/system/libraries/controllers.js"); 100); this.enterTeleport = function() { - this.state = TELEPORTER_STATES.TARGETTING; + _this.state = TELEPORTER_STATES.TARGETTING; }; this.isReady = function(controllerData, deltaTime) { @@ -761,23 +761,23 @@ Script.include("/~/system/libraries/controllers.js"); if (teleportLocationType === TARGET.NONE) { // Use the cancel default state - this.setTeleportState(mode, "cancel", ""); + _this.setTeleportState(mode, "cancel", ""); } else if (teleportLocationType === TARGET.INVALID) { - this.setTeleportState(mode, "", "cancel"); + _this.setTeleportState(mode, "", "cancel"); } else if (teleportLocationType === TARGET.COLLIDES) { - this.setTeleportState(mode, "cancel", "collision"); + _this.setTeleportState(mode, "cancel", "collision"); } else if (teleportLocationType === TARGET.SURFACE || teleportLocationType === TARGET.DISCREPANCY) { - this.setTeleportState(mode, "teleport", "collision"); - this.updatePlayArea(result.intersection); + _this.setTeleportState(mode, "teleport", "collision"); + _this.updatePlayArea(result.intersection); } else if (teleportLocationType === TARGET.SEAT) { - this.setTeleportState(mode, "collision", "seat"); + _this.setTeleportState(mode, "collision", "seat"); } - return this.teleport(result, teleportLocationType); + return _this.teleport(result, teleportLocationType); }; this.teleport = function(newResult, target) { var result = newResult; - this.teleportedPosition = newResult.intersection; + _this.teleportedPosition = newResult.intersection; if (_this.buttonValue !== 0) { return makeRunningValues(true, [], []); } @@ -795,14 +795,14 @@ Script.include("/~/system/libraries/controllers.js"); MyAvatar.centerBody(); } - this.disableLasers(); - this.active = false; + _this.disableLasers(); + _this.active = false; return makeRunningValues(false, [], []); }; this.disableLasers = function() { - this.setPlayAreaVisible(false, null, true); - this.setTeleportVisible(false, null, true); + _this.setPlayAreaVisible(false, null, true); + _this.setTeleportVisible(false, null, true); Pointers.disablePointer(_this.teleportParabolaHandVisuals); Pointers.disablePointer(_this.teleportParabolaHandCollisions); Pointers.disablePointer(_this.teleportParabolaHeadVisuals); @@ -815,10 +815,10 @@ Script.include("/~/system/libraries/controllers.js"); this.setTeleportState = function (mode, visibleState, invisibleState) { var teleportState = mode + visibleState + invisibleState; - if (teleportState === this.teleportState) { + if (teleportState === _this.teleportState) { return; } - this.teleportState = teleportState; + _this.teleportState = teleportState; var pointerID; if (mode === 'head') { @@ -831,16 +831,16 @@ Script.include("/~/system/libraries/controllers.js"); pointerID = _this.teleportParabolaHandVisuals; } var visible = visibleState === "teleport"; - this.setPlayAreaVisible(visible && MyAvatar.showPlayArea, + _this.setPlayAreaVisible(visible && MyAvatar.showPlayArea, Pointers.getPointerProperties(pointerID).renderStates.teleport.end, false); - this.setTeleportVisible(visible, mode, false); + _this.setTeleportVisible(visible, mode, false); }; this.setIgnoreEntities = function(entitiesToIgnore) { - Pointers.setIgnoreItems(this.teleportParabolaHandVisuals, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHandCollisions, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHeadVisuals, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHeadCollisions, entitiesToIgnore); + Pointers.setIgnoreItems(_this.teleportParabolaHandVisuals, entitiesToIgnore); + Pointers.setIgnoreItems(_this.teleportParabolaHandCollisions, entitiesToIgnore); + Pointers.setIgnoreItems(_this.teleportParabolaHeadVisuals, entitiesToIgnore); + Pointers.setIgnoreItems(_this.teleportParabolaHeadCollisions, entitiesToIgnore); Picks.setIgnoreItems(_this.teleportHeadCollisionPick, entitiesToIgnore); Picks.setIgnoreItems(_this.teleportHandCollisionPick, entitiesToIgnore); }; From 85421cd6eef37c214d464fb89949c0bca7d03dfc Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Sat, 16 Feb 2019 21:16:46 -0800 Subject: [PATCH 20/23] speed up stylus picks --- interface/src/raypick/StylusPick.cpp | 29 +++++++++++----------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/interface/src/raypick/StylusPick.cpp b/interface/src/raypick/StylusPick.cpp index 0e95959566..9c3ffb972f 100644 --- a/interface/src/raypick/StylusPick.cpp +++ b/interface/src/raypick/StylusPick.cpp @@ -137,7 +137,7 @@ PickResultPointer StylusPick::getDefaultResult(const QVariantMap& pickVariant) c } PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) { - std::vector results; + StylusPickResult nearestTarget(pick.toVariantMap()); for (const auto& target : getIncludeItems()) { if (target.isNull()) { continue; @@ -157,28 +157,21 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) { glm::vec3 normal = entityRotation * Vectors::UNIT_Z; float distance = glm::dot(pick.position - entityPosition, normal); - glm::vec3 intersection = pick.position - (normal * distance); - - glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false); - if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) { - IntersectionType type = IntersectionType::ENTITY; - if (getFilter().doesPickLocalEntities()) { - EntityPropertyFlags desiredProperties; - desiredProperties += PROP_ENTITY_HOST_TYPE; - if (DependencyManager::get()->getEntityProperties(target, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) { - type = IntersectionType::LOCAL_ENTITY; + if (distance < nearestTarget.distance) { + glm::vec3 intersection = pick.position - (normal * distance); + glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false); + if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) { + IntersectionType type = IntersectionType::ENTITY; + if (getFilter().doesPickLocalEntities()) { + if (entity->getEntityHostType() == entity::HostType::LOCAL) { + type = IntersectionType::LOCAL_ENTITY; + } } + nearestTarget = StylusPickResult(type, target, distance, intersection, pick, normal); } - results.push_back(StylusPickResult(type, target, distance, intersection, pick, normal)); } } - StylusPickResult nearestTarget(pick.toVariantMap()); - for (const auto& result : results) { - if (result.distance < nearestTarget.distance) { - nearestTarget = result; - } - } return std::make_shared(nearestTarget); } From 1163cbea706447338e1267ffcba4d536acdf424a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Sat, 16 Feb 2019 22:03:55 -0800 Subject: [PATCH 21/23] improving web surface interaction and tablet hiding --- interface/src/ui/overlays/Overlays.cpp | 10 +--------- .../src/EntityTreeRenderer.cpp | 6 +++--- scripts/system/away.js | 3 ++- scripts/system/tablet-ui/tabletUI.js | 17 ++++++++--------- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 2ec67070ba..a7e7681b74 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -79,15 +79,7 @@ void Overlays::cleanupAllOverlays() { cleanupOverlaysToDelete(); } -void Overlays::init() { - auto entityScriptingInterface = DependencyManager::get(); - connect(this, &Overlays::hoverEnterOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity); - connect(this, &Overlays::hoverOverOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity); - connect(this, &Overlays::hoverLeaveOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity); - connect(this, &Overlays::mousePressOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity); - connect(this, &Overlays::mouseMoveOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity); - connect(this, &Overlays::mouseReleaseOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity); -} +void Overlays::init() {} void Overlays::update(float deltatime) { cleanupOverlaysToDelete(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 319acc750f..673957a9d8 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -86,7 +86,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf auto handlePointerEvent = [&](const QUuid& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); - if (entity && entity->getType() == EntityTypes::Web) { + if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) { thisEntity = std::static_pointer_cast(renderableForEntityId(entityID)); } if (thisEntity) { @@ -99,7 +99,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); - if (entity && entity->getType() == EntityTypes::Web) { + if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) { thisEntity = std::static_pointer_cast(renderableForEntityId(entityID)); } if (thisEntity) { @@ -110,7 +110,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); - if (entity && entity->getType() == EntityTypes::Web) { + if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) { thisEntity = std::static_pointer_cast(renderableForEntityId(entityID)); } if (thisEntity) { diff --git a/scripts/system/away.js b/scripts/system/away.js index a2e73ae63c..45b6f43b73 100644 --- a/scripts/system/away.js +++ b/scripts/system/away.js @@ -45,7 +45,8 @@ var OVERLAY_DATA_HMD = { emissive: true, drawInFront: true, parentID: MyAvatar.SELF_ID, - parentJointIndex: CAMERA_MATRIX + parentJointIndex: CAMERA_MATRIX, + ignorePickIntersection: true }; var AWAY_INTRO = { diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index f9e9165f2e..60848224bb 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -137,11 +137,11 @@ UIWebTablet.calculateTabletAttachmentProperties(activeHand, true, tabletProperties); } tabletProperties.visible = true; + tabletProperties.ignorePickIntersection = false; Overlays.editOverlay(HMD.tabletID, tabletProperties); - Overlays.editOverlay(HMD.homeButtonID, { visible: true }); - Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: true }); - Overlays.editOverlay(HMD.tabletScreenID, { visible: true }); - Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 }); + Overlays.editOverlay(HMD.homeButtonID, { visible: true, ignorePickIntersection: false }); + Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: true, ignorePickIntersection: false }); + Overlays.editOverlay(HMD.tabletScreenID, { visible: true, ignorePickIntersection: false, maxFPS: 90 }); updateTabletWidthFromSettings(true); } gTablet.tabletShown = true; @@ -158,11 +158,10 @@ print("TABLET hide"); } - Overlays.editOverlay(HMD.tabletID, { visible: false }); - Overlays.editOverlay(HMD.homeButtonID, { visible: false }); - Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: false }); - Overlays.editOverlay(HMD.tabletScreenID, { visible: false }); - Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 1 }); + Overlays.editOverlay(HMD.tabletID, { visible: false, ignorePickIntersection: true }); + Overlays.editOverlay(HMD.homeButtonID, { visible: false, ignorePickIntersection: true }); + Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: false, ignorePickIntersection: true }); + Overlays.editOverlay(HMD.tabletScreenID, { visible: false, ignorePickIntersection: true, maxFPS: 1 }); } function closeTabletUI() { From 27f05db8253e0bb61e0ce6e8608dd291c35c6382 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 18 Feb 2019 01:10:19 -0800 Subject: [PATCH 22/23] fix ao --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 2 +- libraries/render-utils/src/LightingModel.h | 8 +++----- scripts/developer/utilities/render/deferredLighting.qml | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index b1ca24de1f..ee53347158 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -205,7 +205,7 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { } AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : - render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), + render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion"), perspectiveScale{ 1.0f }, edgeSharpness{ 1.0f }, blurRadius{ 4 }, diff --git a/libraries/render-utils/src/LightingModel.h b/libraries/render-utils/src/LightingModel.h index 571eadb60b..f6bd6dcd46 100644 --- a/libraries/render-utils/src/LightingModel.h +++ b/libraries/render-utils/src/LightingModel.h @@ -118,7 +118,7 @@ protected: float enableSkinning{ 1.0f }; float enableBlendshape{ 1.0f }; - float enableAmbientOcclusion{ 0.0f }; + float enableAmbientOcclusion{ 0.0f }; // false by default float enableShadow{ 1.0f }; float spare1{ 1.0f }; float spare2{ 1.0f }; @@ -196,15 +196,13 @@ public: bool enableSkinning{ true }; bool enableBlendshape{ true }; - bool enableAmbientOcclusion{ true }; + bool enableAmbientOcclusion{ false }; // false by default bool enableShadow{ true }; void setAmbientOcclusion(bool enable) { enableAmbientOcclusion = enable; emit dirty();} bool isAmbientOcclusionEnabled() const { return enableAmbientOcclusion; } - void setShadow(bool enable) { - enableShadow = enable; emit dirty(); - } + void setShadow(bool enable) { enableShadow = enable; emit dirty(); } bool isShadowEnabled() const { return enableShadow; } signals: diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 6d98e96780..f5c0b8c5da 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -47,7 +47,7 @@ Rectangle { "Lightmap:LightingModel:enableLightmap", "Background:LightingModel:enableBackground", "Haze:LightingModel:enableHaze", - "ssao:LightingModel:enableAmbientOcclusion", + "AO:LightingModel:enableAmbientOcclusion", "Textures:LightingModel:enableMaterialTexturing" ] HifiControls.CheckBox { From 927e824610331c560117a6bfe73660257baf5dc4 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 18 Feb 2019 16:14:07 -0800 Subject: [PATCH 23/23] fix missing color for text overlays --- interface/src/ui/overlays/Overlays.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index e1708c14fe..6fb0c99c90 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -375,6 +375,8 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove RENAME_PROP(animationSettings, animation); } else if (type == "Image") { RENAME_PROP(url, imageURL); + } else if (type == "Text") { + RENAME_PROP(color, textColor); } else if (type == "Web") { RENAME_PROP(url, sourceUrl); RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "Mouse" ? "mouse" : "touch"; }); @@ -675,6 +677,8 @@ QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemPropertie RENAME_PROP(animation, animationSettings); } else if (type == "Image") { RENAME_PROP(imageURL, url); + } else if (type == "Text") { + RENAME_PROP(textColor, color); } else if (type == "Web") { RENAME_PROP(sourceUrl, url); RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "mouse" ? "Mouse" : "Touch"; });