mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 18:16:45 +02:00
Merge remote-tracking branch 'upstream/master' into pal
This commit is contained in:
commit
2986ca20c5
46 changed files with 1227 additions and 587 deletions
|
@ -0,0 +1,127 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
|
||||||
|
import "../../controlsUit" 1.0 as HifiControls
|
||||||
|
import "../../stylesUit" 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
property var avatarDoctor: null
|
||||||
|
property var errors: []
|
||||||
|
|
||||||
|
property int minimumDiagnoseTimeMS: 1000
|
||||||
|
|
||||||
|
signal doneDiagnosing
|
||||||
|
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (root.avatarDoctor !== null) {
|
||||||
|
root.avatarDoctor.complete.disconnect(_private.avatarDoctorComplete);
|
||||||
|
root.avatarDoctor = null;
|
||||||
|
}
|
||||||
|
if (doneTimer.running) {
|
||||||
|
doneTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!root.visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
root.errors = errors;
|
||||||
|
AvatarPackagerCore.currentAvatarProject.hasErrors = errors.length > 0;
|
||||||
|
AvatarPackagerCore.addCurrentProjectToRecentProjects();
|
||||||
|
|
||||||
|
let timeSpendDiagnosingMS = Date.now() - _private.startTime;
|
||||||
|
let timeLeftMS = root.minimumDiagnoseTimeMS - timeSpendDiagnosingMS;
|
||||||
|
doneTimer.interval = timeLeftMS < 0 ? 0 : timeLeftMS;
|
||||||
|
doneTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: doneTimer
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
onTriggered: {
|
||||||
|
doneDiagnosing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
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")
|
||||||
|
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: -20
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
top: errorReportIcon.bottom
|
||||||
|
topMargin: -40
|
||||||
|
leftMargin: 13
|
||||||
|
rightMargin: 13
|
||||||
|
}
|
||||||
|
spacing: 7
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: errorRepeater
|
||||||
|
Item {
|
||||||
|
height: 37
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
HiFiGlyphs {
|
||||||
|
id: errorIcon
|
||||||
|
text: hifi.glyphs.alert
|
||||||
|
size: 56
|
||||||
|
color: "#EA4C5F"
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: -5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RalewayRegular {
|
||||||
|
id: errorLink
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 5
|
||||||
|
left: errorIcon.right
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
color: "#00B4EF"
|
||||||
|
linkColor: "#00B4EF"
|
||||||
|
size: 28
|
||||||
|
text: "<a href='javascript:void'>" + modelData.message + "</a>"
|
||||||
|
onLinkActivated: Qt.openUrlExternally(modelData.url)
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -143,6 +143,18 @@ Item {
|
||||||
PropertyChanges { target: createAvatarProject; visible: true }
|
PropertyChanges { target: createAvatarProject; visible: true }
|
||||||
PropertyChanges { target: avatarPackagerFooter; content: createAvatarProject.footer }
|
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 {
|
State {
|
||||||
name: AvatarPackagerState.project
|
name: AvatarPackagerState.project
|
||||||
PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name; canRename: true }
|
PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name; canRename: true }
|
||||||
|
@ -168,7 +180,7 @@ Item {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
avatarProject.reset();
|
avatarProject.reset();
|
||||||
avatarPackager.state = AvatarPackagerState.project;
|
avatarPackager.state = AvatarPackagerState.avatarDoctorDiagnose;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,6 +254,23 @@ Item {
|
||||||
color: "#404040"
|
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 {
|
AvatarProject {
|
||||||
id: avatarProject
|
id: avatarProject
|
||||||
colorScheme: root.colorScheme
|
colorScheme: root.colorScheme
|
||||||
|
@ -383,6 +412,7 @@ Item {
|
||||||
title: modelData.name
|
title: modelData.name
|
||||||
path: modelData.projectPath
|
path: modelData.projectPath
|
||||||
onOpen: avatarPackager.openProject(modelData.path)
|
onOpen: avatarPackager.openProject(modelData.path)
|
||||||
|
hasError: modelData.hadErrors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,4 +7,6 @@ Item {
|
||||||
readonly property string project: "project"
|
readonly property string project: "project"
|
||||||
readonly property string createProject: "createProject"
|
readonly property string createProject: "createProject"
|
||||||
readonly property string projectUpload: "projectUpload"
|
readonly property string projectUpload: "projectUpload"
|
||||||
|
readonly property string avatarDoctorDiagnose: "avatarDoctorDiagnose"
|
||||||
|
readonly property string avatarDoctorErrorReport: "avatarDoctorErrorReport"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ Item {
|
||||||
|
|
||||||
property alias title: title.text
|
property alias title: title.text
|
||||||
property alias path: path.text
|
property alias path: path.text
|
||||||
|
property alias hasError: errorIcon.visible
|
||||||
|
|
||||||
property color textColor: "#E3E3E3"
|
property color textColor: "#E3E3E3"
|
||||||
property color hoverTextColor: "#121212"
|
property color hoverTextColor: "#121212"
|
||||||
|
@ -54,7 +55,7 @@ Item {
|
||||||
|
|
||||||
RalewayBold {
|
RalewayBold {
|
||||||
id: title
|
id: title
|
||||||
elide: "ElideRight"
|
elide: Text.ElideRight
|
||||||
anchors {
|
anchors {
|
||||||
top: parent.top
|
top: parent.top
|
||||||
topMargin: 13
|
topMargin: 13
|
||||||
|
@ -76,12 +77,24 @@ Item {
|
||||||
right: background.right
|
right: background.right
|
||||||
rightMargin: 16
|
rightMargin: 16
|
||||||
}
|
}
|
||||||
elide: "ElideLeft"
|
elide: Text.ElideLeft
|
||||||
horizontalAlignment: Text.AlignRight
|
horizontalAlignment: Text.AlignRight
|
||||||
text: "<path missing>"
|
text: "<path missing>"
|
||||||
size: 20
|
size: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HiFiGlyphs {
|
||||||
|
id: errorIcon
|
||||||
|
visible: false
|
||||||
|
text: hifi.glyphs.alert
|
||||||
|
size: 56
|
||||||
|
color: "#EA4C5F"
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
@ -32,7 +32,7 @@ Item {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
avatarProject.reset();
|
avatarProject.reset();
|
||||||
avatarPackager.state = AvatarPackagerState.project;
|
avatarPackager.state = AvatarPackagerState.avatarDoctorDiagnose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,15 +33,19 @@ Rectangle {
|
||||||
property bool balanceReceived: false;
|
property bool balanceReceived: false;
|
||||||
property bool availableUpdatesReceived: false;
|
property bool availableUpdatesReceived: false;
|
||||||
property bool itemInfoReceived: false;
|
property bool itemInfoReceived: false;
|
||||||
|
property bool dataReady: itemInfoReceived && ownershipStatusReceived && balanceReceived && availableUpdatesReceived;
|
||||||
property string baseItemName: "";
|
property string baseItemName: "";
|
||||||
property string itemName;
|
property string itemName;
|
||||||
property string itemId;
|
property string itemId;
|
||||||
property string itemHref;
|
property string itemHref;
|
||||||
property string itemAuthor;
|
property string itemAuthor;
|
||||||
property int itemEdition: -1;
|
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 string certificateId;
|
||||||
property double balanceAfterPurchase;
|
property double balanceAfterPurchase;
|
||||||
property bool alreadyOwned: false;
|
property bool alreadyOwned: false; // Including proofs
|
||||||
property int itemPrice: -1;
|
property int itemPrice: -1;
|
||||||
property bool isCertified;
|
property bool isCertified;
|
||||||
property string itemType: "unknown";
|
property string itemType: "unknown";
|
||||||
|
@ -56,6 +60,8 @@ Rectangle {
|
||||||
property string referrer;
|
property string referrer;
|
||||||
property bool isInstalled;
|
property bool isInstalled;
|
||||||
property bool isUpdating;
|
property bool isUpdating;
|
||||||
|
property string availability: "available";
|
||||||
|
property string creator: "";
|
||||||
property string baseAppURL;
|
property string baseAppURL;
|
||||||
property int currentUpdatesPage: 1;
|
property int currentUpdatesPage: 1;
|
||||||
// Style
|
// Style
|
||||||
|
@ -434,7 +440,7 @@ Rectangle {
|
||||||
anchors.top: parent.top;
|
anchors.top: parent.top;
|
||||||
anchors.left: itemPreviewImage.right;
|
anchors.left: itemPreviewImage.right;
|
||||||
anchors.leftMargin: 12;
|
anchors.leftMargin: 12;
|
||||||
anchors.right: itemPriceContainer.left;
|
anchors.right: parent.right;
|
||||||
anchors.rightMargin: 8;
|
anchors.rightMargin: 8;
|
||||||
height: 30;
|
height: 30;
|
||||||
// Style
|
// Style
|
||||||
|
@ -449,21 +455,22 @@ Rectangle {
|
||||||
Item {
|
Item {
|
||||||
id: itemPriceContainer;
|
id: itemPriceContainer;
|
||||||
// Anchors
|
// Anchors
|
||||||
anchors.top: parent.top;
|
anchors.top: itemNameText.bottom;
|
||||||
anchors.right: parent.right;
|
anchors.topMargin: 8;
|
||||||
|
anchors.left: itemNameText.left;
|
||||||
height: 30;
|
height: 30;
|
||||||
width: itemPriceTextLabel.width + itemPriceText.width + 20;
|
width: itemPriceText.width + 20;
|
||||||
|
|
||||||
// "HFC" balance label
|
// "HFC" label
|
||||||
HiFiGlyphs {
|
HiFiGlyphs {
|
||||||
id: itemPriceTextLabel;
|
id: itemPriceTextLabel;
|
||||||
visible: !(root.isUpdating && root.itemEdition > 0) && (root.itemPrice > 0);
|
visible: !isTradingIn && (root.itemPrice > 0);
|
||||||
text: hifi.glyphs.hfc;
|
text: hifi.glyphs.hfc;
|
||||||
// Size
|
// Size
|
||||||
size: 30;
|
size: 30;
|
||||||
// Anchors
|
// Anchors
|
||||||
anchors.right: itemPriceText.left;
|
anchors.right: parent.right;
|
||||||
anchors.rightMargin: 4;
|
//anchors.rightMargin: 4;
|
||||||
anchors.top: parent.top;
|
anchors.top: parent.top;
|
||||||
anchors.topMargin: 0;
|
anchors.topMargin: 0;
|
||||||
width: paintedWidth;
|
width: paintedWidth;
|
||||||
|
@ -473,13 +480,15 @@ Rectangle {
|
||||||
}
|
}
|
||||||
FiraSansSemiBold {
|
FiraSansSemiBold {
|
||||||
id: itemPriceText;
|
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
|
// Text size
|
||||||
size: (root.isUpdating && root.itemEdition > 0) ? 20 : 26;
|
size: isTradingIn ? 20 : 26;
|
||||||
// Anchors
|
// Anchors
|
||||||
anchors.top: parent.top;
|
anchors.top: parent.top;
|
||||||
anchors.right: parent.right;
|
anchors.left: itemPriceTextLabel.visible ? itemPriceTextLabel.right : parent.left;
|
||||||
anchors.rightMargin: 16;
|
anchors.leftMargin: 4;
|
||||||
width: paintedWidth;
|
width: paintedWidth;
|
||||||
height: paintedHeight;
|
height: paintedHeight;
|
||||||
// Style
|
// Style
|
||||||
|
@ -571,7 +580,7 @@ Rectangle {
|
||||||
// "View in Inventory" button
|
// "View in Inventory" button
|
||||||
HifiControlsUit.Button {
|
HifiControlsUit.Button {
|
||||||
id: viewInMyPurchasesButton;
|
id: viewInMyPurchasesButton;
|
||||||
visible: false;
|
visible: isCertified && dataReady && (isUpdating ? !hasSomethingToTradeIn : alreadyOwned);
|
||||||
color: hifi.buttons.blue;
|
color: hifi.buttons.blue;
|
||||||
colorScheme: hifi.colorSchemes.light;
|
colorScheme: hifi.colorSchemes.light;
|
||||||
anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top;
|
anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top;
|
||||||
|
@ -592,8 +601,8 @@ Rectangle {
|
||||||
// "Buy" button
|
// "Buy" button
|
||||||
HifiControlsUit.Button {
|
HifiControlsUit.Button {
|
||||||
id: buyButton;
|
id: buyButton;
|
||||||
visible: !((root.itemType === "avatar" || root.itemType === "app") && viewInMyPurchasesButton.visible)
|
visible: isTradingIn || !alreadyOwned || isStocking || !(root.itemType === "avatar" || root.itemType === "app");
|
||||||
enabled: (root.balanceAfterPurchase >= 0 && ownershipStatusReceived && balanceReceived && availableUpdatesReceived) || (!root.isCertified) || root.isUpdating;
|
enabled: (root.balanceAfterPurchase >= 0 && dataReady) || (!root.isCertified) || root.isUpdating;
|
||||||
color: viewInMyPurchasesButton.visible ? hifi.buttons.white : hifi.buttons.blue;
|
color: viewInMyPurchasesButton.visible ? hifi.buttons.white : hifi.buttons.blue;
|
||||||
colorScheme: hifi.colorSchemes.light;
|
colorScheme: hifi.colorSchemes.light;
|
||||||
anchors.top: viewInMyPurchasesButton.visible ? viewInMyPurchasesButton.bottom :
|
anchors.top: viewInMyPurchasesButton.visible ? viewInMyPurchasesButton.bottom :
|
||||||
|
@ -602,10 +611,15 @@ Rectangle {
|
||||||
height: 50;
|
height: 50;
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
text: (root.isUpdating && root.itemEdition > 0) ? "CONFIRM UPDATE" : (((root.isCertified) ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ?
|
text: isTradingIn ?
|
||||||
((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") : "--") : "Get Item"));
|
"CONFIRM UPDATE" :
|
||||||
|
(((root.isCertified) ?
|
||||||
|
(dataReady ?
|
||||||
|
((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") :
|
||||||
|
"--") :
|
||||||
|
"Get Item"));
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.isUpdating && root.itemEdition > 0) {
|
if (isTradingIn) {
|
||||||
// If we're updating an app, the existing app needs to be uninstalled.
|
// 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.
|
// This call will fail/return `false` if the app isn't installed, but that's OK.
|
||||||
if (root.itemType === "app") {
|
if (root.itemType === "app") {
|
||||||
|
@ -1063,7 +1077,11 @@ Rectangle {
|
||||||
buyButton.color = hifi.buttons.red;
|
buyButton.color = hifi.buttons.red;
|
||||||
root.shouldBuyWithControlledFailure = true;
|
root.shouldBuyWithControlledFailure = true;
|
||||||
} else {
|
} 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;
|
buyButton.color = hifi.buttons.blue;
|
||||||
root.shouldBuyWithControlledFailure = false;
|
root.shouldBuyWithControlledFailure = false;
|
||||||
}
|
}
|
||||||
|
@ -1091,6 +1109,8 @@ Rectangle {
|
||||||
root.itemPrice = result.data.cost;
|
root.itemPrice = result.data.cost;
|
||||||
root.itemAuthor = result.data.creator;
|
root.itemAuthor = result.data.creator;
|
||||||
root.itemType = result.data.item_type || "unknown";
|
root.itemType = result.data.item_type || "unknown";
|
||||||
|
root.availability = result.data.availability;
|
||||||
|
root.creator = result.data.creator;
|
||||||
if (root.itemType === "unknown") {
|
if (root.itemType === "unknown") {
|
||||||
root.itemHref = result.data.review_url;
|
root.itemHref = result.data.review_url;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1139,7 +1159,7 @@ Rectangle {
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
function canBuyAgain() {
|
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() {
|
function handleContentSets() {
|
||||||
|
@ -1185,29 +1205,23 @@ Rectangle {
|
||||||
|
|
||||||
function refreshBuyUI() {
|
function refreshBuyUI() {
|
||||||
if (root.isCertified) {
|
if (root.isCertified) {
|
||||||
if (root.ownershipStatusReceived && root.balanceReceived && root.availableUpdatesReceived) {
|
if (dataReady) {
|
||||||
buyText.text = "";
|
buyText.text = "";
|
||||||
|
|
||||||
// If the user IS on the checkout page for the updated version of an owned item...
|
// If the user IS on the checkout page for the updated version of an owned item...
|
||||||
if (root.isUpdating) {
|
if (root.isUpdating) {
|
||||||
// If the user HAS already selected a specific edition to update...
|
// 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.";
|
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.color = "#FFFFFF";
|
||||||
buyTextContainer.border.color = "#FFFFFF";
|
buyTextContainer.border.color = "#FFFFFF";
|
||||||
// Else if the user HAS NOT selected a specific edition to update...
|
// Else if the user HAS NOT selected a specific edition to update...
|
||||||
} else {
|
} else {
|
||||||
viewInMyPurchasesButton.visible = true;
|
|
||||||
|
|
||||||
handleBuyAgainLogic();
|
handleBuyAgainLogic();
|
||||||
}
|
}
|
||||||
// If the user IS NOT on the checkout page for the updated verison of an owned item...
|
// 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")
|
// (i.e. they are checking out an item "normally")
|
||||||
} else {
|
} else {
|
||||||
if (root.alreadyOwned) {
|
|
||||||
viewInMyPurchasesButton.visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBuyAgainLogic();
|
handleBuyAgainLogic();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -121,7 +121,7 @@ Rectangle {
|
||||||
marketplaceItem.description = result.data.description;
|
marketplaceItem.description = result.data.description;
|
||||||
marketplaceItem.attributions = result.data.attributions;
|
marketplaceItem.attributions = result.data.attributions;
|
||||||
marketplaceItem.license = result.data.license;
|
marketplaceItem.license = result.data.license;
|
||||||
marketplaceItem.available = result.data.availability === "available";
|
marketplaceItem.availability = result.data.availability;
|
||||||
marketplaceItem.created_at = result.data.created_at;
|
marketplaceItem.created_at = result.data.created_at;
|
||||||
marketplaceItemScrollView.contentHeight = marketplaceItemContent.height;
|
marketplaceItemScrollView.contentHeight = marketplaceItemContent.height;
|
||||||
itemsList.visible = false;
|
itemsList.visible = false;
|
||||||
|
@ -539,7 +539,7 @@ Rectangle {
|
||||||
creator: model.creator
|
creator: model.creator
|
||||||
category: model.primary_category
|
category: model.primary_category
|
||||||
price: model.cost
|
price: model.cost
|
||||||
available: model.availability === "available"
|
availability: model.availability
|
||||||
isLoggedIn: root.isLoggedIn;
|
isLoggedIn: root.isLoggedIn;
|
||||||
|
|
||||||
onShowItem: {
|
onShowItem: {
|
||||||
|
@ -711,7 +711,7 @@ Rectangle {
|
||||||
topMargin: 10;
|
topMargin: 10;
|
||||||
leftMargin: 15;
|
leftMargin: 15;
|
||||||
}
|
}
|
||||||
height: visible ? childrenRect.height : 0
|
height: visible ? 36 : 0
|
||||||
|
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: sortText
|
id: sortText
|
||||||
|
@ -733,8 +733,9 @@ Rectangle {
|
||||||
top: parent.top
|
top: parent.top
|
||||||
leftMargin: 20
|
leftMargin: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
width: root.isLoggedIn ? 342 : 262
|
width: root.isLoggedIn ? 342 : 262
|
||||||
height: 36
|
height: parent.height
|
||||||
|
|
||||||
radius: 4
|
radius: 4
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
|
@ -33,11 +33,11 @@ Rectangle {
|
||||||
property string creator: ""
|
property string creator: ""
|
||||||
property var categories: []
|
property var categories: []
|
||||||
property int price: 0
|
property int price: 0
|
||||||
|
property string availability: "unknown"
|
||||||
property var attributions: []
|
property var attributions: []
|
||||||
property string description: ""
|
property string description: ""
|
||||||
property string license: ""
|
property string license: ""
|
||||||
property string posted: ""
|
property string posted: ""
|
||||||
property bool available: false
|
|
||||||
property string created_at: ""
|
property string created_at: ""
|
||||||
property bool isLoggedIn: false;
|
property bool isLoggedIn: false;
|
||||||
property int edition: -1;
|
property int edition: -1;
|
||||||
|
@ -264,9 +264,15 @@ Rectangle {
|
||||||
}
|
}
|
||||||
height: 50
|
height: 50
|
||||||
|
|
||||||
text: root.edition >= 0 ? "UPGRADE FOR FREE" : (root.available ? (root.price ? root.price : "FREE") : "UNAVAILABLE (not for sale)")
|
property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS
|
||||||
enabled: root.edition >= 0 || root.available
|
property bool isMine: creator === Account.username
|
||||||
buttonGlyph: root.available ? (root.price ? hifi.glyphs.hfc : "") : ""
|
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") : availability)
|
||||||
|
enabled: isAvailable
|
||||||
|
buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : ""
|
||||||
color: hifi.buttons.blue
|
color: hifi.buttons.blue
|
||||||
|
|
||||||
onClicked: root.buy();
|
onClicked: root.buy();
|
||||||
|
|
|
@ -34,7 +34,7 @@ Rectangle {
|
||||||
property string creator: ""
|
property string creator: ""
|
||||||
property string category: ""
|
property string category: ""
|
||||||
property int price: 0
|
property int price: 0
|
||||||
property bool available: false
|
property string availability: "unknown"
|
||||||
property bool isLoggedIn: false;
|
property bool isLoggedIn: false;
|
||||||
|
|
||||||
signal buy()
|
signal buy()
|
||||||
|
@ -299,8 +299,16 @@ Rectangle {
|
||||||
bottomMargin: 10
|
bottomMargin: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
text: root.price ? root.price : "FREE"
|
property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS
|
||||||
buttonGlyph: root.price ? hifi.glyphs.hfc : ""
|
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") : availability)
|
||||||
|
enabled: isAvailable
|
||||||
|
buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : ""
|
||||||
|
|
||||||
color: hifi.buttons.blue;
|
color: hifi.buttons.blue;
|
||||||
|
|
||||||
onClicked: root.buy();
|
onClicked: root.buy();
|
||||||
|
|
|
@ -1911,46 +1911,34 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
}
|
}
|
||||||
}, Qt::QueuedConnection);
|
}, Qt::QueuedConnection);
|
||||||
|
|
||||||
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) {
|
if (_aboutToQuit) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to find the renderable
|
|
||||||
auto renderable = getEntities()->renderableForEntityId(entityID);
|
auto renderable = getEntities()->renderableForEntityId(entityID);
|
||||||
if (renderable) {
|
if (renderable) {
|
||||||
renderable->addMaterial(material, parentMaterialName);
|
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 true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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) {
|
if (_aboutToQuit) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to find the renderable
|
|
||||||
auto renderable = getEntities()->renderableForEntityId(entityID);
|
auto renderable = getEntities()->renderableForEntityId(entityID);
|
||||||
if (renderable) {
|
if (renderable) {
|
||||||
renderable->removeMaterial(material, parentMaterialName);
|
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 true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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<AvatarManager>();
|
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||||
auto avatar = avatarManager->getAvatarBySessionID(avatarID);
|
auto avatar = avatarManager->getAvatarBySessionID(avatarID);
|
||||||
if (avatar) {
|
if (avatar) {
|
||||||
|
@ -1959,7 +1947,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
}
|
}
|
||||||
return false;
|
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<AvatarManager>();
|
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||||
auto avatar = avatarManager->getAvatarBySessionID(avatarID);
|
auto avatar = avatarManager->getAvatarBySessionID(avatarID);
|
||||||
if (avatar) {
|
if (avatar) {
|
||||||
|
@ -2282,7 +2270,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
|
|
||||||
// Setup the mouse ray pick and related operators
|
// Setup the mouse ray pick and related operators
|
||||||
{
|
{
|
||||||
auto mouseRayPick = std::make_shared<RayPick>(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES()), 0.0f, true);
|
auto mouseRayPick = std::make_shared<RayPick>(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_LOCAL_ENTITIES()), 0.0f, true);
|
||||||
mouseRayPick->parentTransform = std::make_shared<MouseTransformNode>();
|
mouseRayPick->parentTransform = std::make_shared<MouseTransformNode>();
|
||||||
mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE);
|
mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE);
|
||||||
auto mouseRayPickID = DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, mouseRayPick);
|
auto mouseRayPickID = DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, mouseRayPick);
|
||||||
|
|
196
interface/src/avatar/AvatarDoctor.cpp
Normal file
196
interface/src/avatar/AvatarDoctor.cpp
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
//
|
||||||
|
// 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 <model-networking/ModelCache.h>
|
||||||
|
#include <AvatarConstants.h>
|
||||||
|
#include <ResourceManager.h>
|
||||||
|
|
||||||
|
|
||||||
|
AvatarDoctor::AvatarDoctor(QUrl 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;
|
||||||
|
_checkedTextureCount = 0;
|
||||||
|
_missingTextureCount = 0;
|
||||||
|
_unsupportedTextureCount = 0;
|
||||||
|
|
||||||
|
const auto resource = DependencyManager::get<ModelCache>()->getGeometryResource(_avatarFSTFileUrl);
|
||||||
|
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", 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", DEFAULT_URL });
|
||||||
|
emit complete(getErrors());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RIG
|
||||||
|
if (avatarModel.joints.isEmpty()) {
|
||||||
|
_errors.push_back({ "Avatar has no rig", DEFAULT_URL });
|
||||||
|
} else {
|
||||||
|
if (avatarModel.joints.length() > 256) {
|
||||||
|
_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", DEFAULT_URL });
|
||||||
|
}
|
||||||
|
if (!avatarModel.getJointNames().contains("Spine")) {
|
||||||
|
_errors.push_back({ "Spine is not mapped", DEFAULT_URL });
|
||||||
|
}
|
||||||
|
if (!avatarModel.getJointNames().contains("Head")) {
|
||||||
|
_errors.push_back({ "Head is not mapped", DEFAULT_URL });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCALE
|
||||||
|
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();
|
||||||
|
if (avatarHeight < RECOMMENDED_MIN_HEIGHT) {
|
||||||
|
_errors.push_back({ "Avatar is possibly too small.", DEFAULT_URL });
|
||||||
|
} else if (avatarHeight > RECOMMENDED_MAX_HEIGHT) {
|
||||||
|
_errors.push_back({ "Avatar is possibly too large.", DEFAULT_URL });
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEXTURES
|
||||||
|
QStringList externalTextures{};
|
||||||
|
QSet<QString> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUrl textureURL = modelTexturesURLs[textureKey].toUrl();
|
||||||
|
|
||||||
|
auto textureResource = DependencyManager::get<TextureCache>()->getTexture(textureURL);
|
||||||
|
auto checkTextureLoadingComplete = [this, DEFAULT_URL] () mutable {
|
||||||
|
qDebug() << "checkTextureLoadingComplete" << _checkedTextureCount << "/" << _externalTextureCount;
|
||||||
|
|
||||||
|
if (_checkedTextureCount == _externalTextureCount) {
|
||||||
|
if (_missingTextureCount > 0) {
|
||||||
|
_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<ResourceManager>()->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) {
|
||||||
|
if (resource->isLoaded()) {
|
||||||
|
resourceLoaded(!resource->isFailed());
|
||||||
|
} else {
|
||||||
|
connect(resource.data(), &GeometryResource::finished, this, resourceLoaded);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_errors.push_back({ "Model file cannot be opened", DEFAULT_URL });
|
||||||
|
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;
|
||||||
|
}
|
51
interface/src/avatar/AvatarDoctor.h
Normal file
51
interface/src/avatar/AvatarDoctor.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//
|
||||||
|
// 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 <QUrl>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
struct AvatarDiagnosticResult {
|
||||||
|
QString message;
|
||||||
|
QUrl url;
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(AvatarDiagnosticResult)
|
||||||
|
Q_DECLARE_METATYPE(QVector<AvatarDiagnosticResult>)
|
||||||
|
|
||||||
|
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<AvatarDiagnosticResult> _errors;
|
||||||
|
|
||||||
|
int _externalTextureCount = 0;
|
||||||
|
int _checkedTextureCount = 0;
|
||||||
|
int _missingTextureCount = 0;
|
||||||
|
int _unsupportedTextureCount = 0;
|
||||||
|
|
||||||
|
bool _isDiagnosing = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AvatarDoctor_h
|
|
@ -31,6 +31,7 @@ AvatarPackager::AvatarPackager() {
|
||||||
qmlRegisterType<MarketplaceItemUploader>();
|
qmlRegisterType<MarketplaceItemUploader>();
|
||||||
qRegisterMetaType<AvatarPackager*>();
|
qRegisterMetaType<AvatarPackager*>();
|
||||||
qRegisterMetaType<AvatarProject*>();
|
qRegisterMetaType<AvatarProject*>();
|
||||||
|
qRegisterMetaType<AvatarDoctor*>();
|
||||||
qRegisterMetaType<AvatarProjectStatus::AvatarProjectStatus>();
|
qRegisterMetaType<AvatarProjectStatus::AvatarProjectStatus>();
|
||||||
qmlRegisterUncreatableMetaObject(
|
qmlRegisterUncreatableMetaObject(
|
||||||
AvatarProjectStatus::staticMetaObject,
|
AvatarProjectStatus::staticMetaObject,
|
||||||
|
@ -84,7 +85,7 @@ void AvatarPackager::addCurrentProjectToRecentProjects() {
|
||||||
_recentProjects.removeOne(removeProject);
|
_recentProjects.removeOne(removeProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto newRecentProject = RecentAvatarProject(_currentAvatarProject->getProjectName(), fstPath);
|
const auto newRecentProject = RecentAvatarProject(_currentAvatarProject->getProjectName(), fstPath, _currentAvatarProject->getHasErrors());
|
||||||
_recentProjects.prepend(newRecentProject);
|
_recentProjects.prepend(newRecentProject);
|
||||||
|
|
||||||
while (_recentProjects.size() > MAX_RECENT_PROJECTS) {
|
while (_recentProjects.size() > MAX_RECENT_PROJECTS) {
|
||||||
|
@ -101,6 +102,7 @@ QVariantList AvatarPackager::recentProjectsToVariantList(bool includeProjectPath
|
||||||
QVariantMap projectVariant;
|
QVariantMap projectVariant;
|
||||||
projectVariant.insert("name", project.getProjectName());
|
projectVariant.insert("name", project.getProjectName());
|
||||||
projectVariant.insert("path", project.getProjectFSTPath());
|
projectVariant.insert("path", project.getProjectFSTPath());
|
||||||
|
projectVariant.insert("hadErrors", project.getHadErrors());
|
||||||
if (includeProjectPaths) {
|
if (includeProjectPaths) {
|
||||||
projectVariant.insert("projectPath", project.getProjectPath());
|
projectVariant.insert("projectPath", project.getProjectPath());
|
||||||
}
|
}
|
||||||
|
@ -113,7 +115,10 @@ void AvatarPackager::recentProjectsFromVariantList(QVariantList projectsVariant)
|
||||||
_recentProjects.clear();
|
_recentProjects.clear();
|
||||||
for (const auto& projectVariant : projectsVariant) {
|
for (const auto& projectVariant : projectsVariant) {
|
||||||
auto map = projectVariant.toMap();
|
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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,19 +26,23 @@ public:
|
||||||
RecentAvatarProject() = default;
|
RecentAvatarProject() = default;
|
||||||
|
|
||||||
|
|
||||||
RecentAvatarProject(QString projectName, QString projectFSTPath) {
|
RecentAvatarProject(QString projectName, QString projectFSTPath, bool hadErrors) {
|
||||||
_projectName = projectName;
|
_projectName = projectName;
|
||||||
_projectFSTPath = projectFSTPath;
|
_projectFSTPath = projectFSTPath;
|
||||||
|
_hadErrors = hadErrors;
|
||||||
}
|
}
|
||||||
RecentAvatarProject(const RecentAvatarProject& other) {
|
RecentAvatarProject(const RecentAvatarProject& other) {
|
||||||
_projectName = other._projectName;
|
_projectName = other._projectName;
|
||||||
_projectFSTPath = other._projectFSTPath;
|
_projectFSTPath = other._projectFSTPath;
|
||||||
|
_hadErrors = other._hadErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getProjectName() const { return _projectName; }
|
QString getProjectName() const { return _projectName; }
|
||||||
|
|
||||||
QString getProjectFSTPath() const { return _projectFSTPath; }
|
QString getProjectFSTPath() const { return _projectFSTPath; }
|
||||||
|
|
||||||
|
bool getHadErrors() const { return _hadErrors; }
|
||||||
|
|
||||||
QString getProjectPath() const {
|
QString getProjectPath() const {
|
||||||
return QFileInfo(_projectFSTPath).absoluteDir().absolutePath();
|
return QFileInfo(_projectFSTPath).absoluteDir().absolutePath();
|
||||||
}
|
}
|
||||||
|
@ -50,6 +54,7 @@ public:
|
||||||
private:
|
private:
|
||||||
QString _projectName;
|
QString _projectName;
|
||||||
QString _projectFSTPath;
|
QString _projectFSTPath;
|
||||||
|
bool _hadErrors;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,6 +78,8 @@ public:
|
||||||
return AvatarProject::isValidNewProjectName(projectPath, projectName);
|
return AvatarProject::isValidNewProjectName(projectPath, projectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_INVOKABLE void addCurrentProjectToRecentProjects();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void avatarProjectChanged();
|
void avatarProjectChanged();
|
||||||
void recentProjectsChanged();
|
void recentProjectsChanged();
|
||||||
|
@ -84,8 +91,6 @@ private:
|
||||||
|
|
||||||
void setAvatarProject(AvatarProject* avatarProject);
|
void setAvatarProject(AvatarProject* avatarProject);
|
||||||
|
|
||||||
void addCurrentProjectToRecentProjects();
|
|
||||||
|
|
||||||
AvatarProject* _currentAvatarProject { nullptr };
|
AvatarProject* _currentAvatarProject { nullptr };
|
||||||
QVector<RecentAvatarProject> _recentProjects;
|
QVector<RecentAvatarProject> _recentProjects;
|
||||||
|
|
||||||
|
|
|
@ -243,6 +243,10 @@ MarketplaceItemUploader* AvatarProject::upload(bool updateExisting) {
|
||||||
return uploader;
|
return uploader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvatarDoctor* AvatarProject::diagnose() {
|
||||||
|
return new AvatarDoctor(QUrl(getFSTPath()));
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarProject::openInInventory() const {
|
void AvatarProject::openInInventory() const {
|
||||||
constexpr int TIME_TO_WAIT_FOR_INVENTORY_TO_OPEN_MS { 1000 };
|
constexpr int TIME_TO_WAIT_FOR_INVENTORY_TO_OPEN_MS { 1000 };
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#define hifi_AvatarProject_h
|
#define hifi_AvatarProject_h
|
||||||
|
|
||||||
#include "MarketplaceItemUploader.h"
|
#include "MarketplaceItemUploader.h"
|
||||||
|
#include "AvatarDoctor.h"
|
||||||
#include "ProjectFile.h"
|
#include "ProjectFile.h"
|
||||||
#include "FST.h"
|
#include "FST.h"
|
||||||
|
|
||||||
|
@ -53,11 +54,14 @@ class AvatarProject : public QObject {
|
||||||
Q_PROPERTY(QString projectFSTPath READ getFSTPath CONSTANT)
|
Q_PROPERTY(QString projectFSTPath READ getFSTPath CONSTANT)
|
||||||
Q_PROPERTY(QString projectFBXPath READ getFBXPath CONSTANT)
|
Q_PROPERTY(QString projectFBXPath READ getFBXPath CONSTANT)
|
||||||
Q_PROPERTY(QString name READ getProjectName WRITE setProjectName NOTIFY nameChanged)
|
Q_PROPERTY(QString name READ getProjectName WRITE setProjectName NOTIFY nameChanged)
|
||||||
|
Q_PROPERTY(bool hasErrors READ getHasErrors WRITE setHasErrors NOTIFY hasErrorsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE MarketplaceItemUploader* upload(bool updateExisting);
|
Q_INVOKABLE MarketplaceItemUploader* upload(bool updateExisting);
|
||||||
Q_INVOKABLE void openInInventory() const;
|
Q_INVOKABLE void openInInventory() const;
|
||||||
Q_INVOKABLE QStringList getProjectFiles() const;
|
Q_INVOKABLE QStringList getProjectFiles() const;
|
||||||
|
Q_INVOKABLE AvatarDoctor* diagnose();
|
||||||
|
|
||||||
|
|
||||||
Q_INVOKABLE QString getProjectName() const { return _fst->getName(); }
|
Q_INVOKABLE QString getProjectName() const { return _fst->getName(); }
|
||||||
Q_INVOKABLE void setProjectName(const QString& newProjectName) {
|
Q_INVOKABLE void setProjectName(const QString& newProjectName) {
|
||||||
|
@ -72,6 +76,8 @@ public:
|
||||||
Q_INVOKABLE QString getFBXPath() const {
|
Q_INVOKABLE QString getFBXPath() const {
|
||||||
return QDir::cleanPath(QDir(_projectPath).absoluteFilePath(_fst->getModelPath()));
|
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.
|
* returns the AvatarProject or a nullptr on failure.
|
||||||
|
@ -92,6 +98,7 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void nameChanged();
|
void nameChanged();
|
||||||
void projectFilesChanged();
|
void projectFilesChanged();
|
||||||
|
void hasErrorsChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AvatarProject(const QString& fstPath, const QByteArray& data);
|
AvatarProject(const QString& fstPath, const QByteArray& data);
|
||||||
|
@ -110,6 +117,8 @@ private:
|
||||||
QDir _directory;
|
QDir _directory;
|
||||||
QList<ProjectFilePath> _projectFiles{};
|
QList<ProjectFilePath> _projectFiles{};
|
||||||
QString _projectPath;
|
QString _projectPath;
|
||||||
|
|
||||||
|
bool _hasErrors { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AvatarProject_h
|
#endif // hifi_AvatarProject_h
|
||||||
|
|
|
@ -137,7 +137,7 @@ PickResultPointer StylusPick::getDefaultResult(const QVariantMap& pickVariant) c
|
||||||
}
|
}
|
||||||
|
|
||||||
PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
|
PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
|
||||||
std::vector<StylusPickResult> results;
|
StylusPickResult nearestTarget(pick.toVariantMap());
|
||||||
for (const auto& target : getIncludeItems()) {
|
for (const auto& target : getIncludeItems()) {
|
||||||
if (target.isNull()) {
|
if (target.isNull()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -157,28 +157,21 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
|
||||||
|
|
||||||
glm::vec3 normal = entityRotation * Vectors::UNIT_Z;
|
glm::vec3 normal = entityRotation * Vectors::UNIT_Z;
|
||||||
float distance = glm::dot(pick.position - entityPosition, normal);
|
float distance = glm::dot(pick.position - entityPosition, normal);
|
||||||
|
if (distance < nearestTarget.distance) {
|
||||||
glm::vec3 intersection = pick.position - (normal * distance);
|
glm::vec3 intersection = pick.position - (normal * distance);
|
||||||
|
|
||||||
glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false);
|
glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false);
|
||||||
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
|
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
|
||||||
IntersectionType type = IntersectionType::ENTITY;
|
IntersectionType type = IntersectionType::ENTITY;
|
||||||
if (getFilter().doesPickLocalEntities()) {
|
if (getFilter().doesPickLocalEntities()) {
|
||||||
EntityPropertyFlags desiredProperties;
|
if (entity->getEntityHostType() == entity::HostType::LOCAL) {
|
||||||
desiredProperties += PROP_ENTITY_HOST_TYPE;
|
|
||||||
if (DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(target, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
|
|
||||||
type = IntersectionType::LOCAL_ENTITY;
|
type = IntersectionType::LOCAL_ENTITY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
results.push_back(StylusPickResult(type, target, distance, intersection, pick, normal));
|
nearestTarget = 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<StylusPickResult>(nearestTarget);
|
return std::make_shared<StylusPickResult>(nearestTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,6 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity);
|
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::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay);
|
||||||
connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay);
|
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) {
|
void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||||
if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID)) {
|
if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(id)) {
|
||||||
_mouseDownEntity = entityItemID;
|
_mouseDownEntity = id;
|
||||||
_mouseDownEntityTimestamp = usecTimestampNow();
|
_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 {
|
} else {
|
||||||
if (!_currentEntityWithContextOverlay.isNull()) {
|
if (!_currentEntityWithContextOverlay.isNull()) {
|
||||||
disableEntityHighlight(_currentEntityWithContextOverlay);
|
disableEntityHighlight(_currentEntityWithContextOverlay);
|
||||||
|
@ -249,14 +252,6 @@ bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityIt
|
||||||
return ContextOverlayInterface::destroyContextOverlay(entityItemID, PointerEvent());
|
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) {
|
void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event) {
|
||||||
if (_contextOverlayID != UNKNOWN_ENTITY_ID) {
|
if (_contextOverlayID != UNKNOWN_ENTITY_ID) {
|
||||||
qCDebug(context_overlay) << "Started hovering over Context Overlay. ID:" << id;
|
qCDebug(context_overlay) << "Started hovering over Context Overlay. ID:" << id;
|
||||||
|
|
|
@ -65,7 +65,6 @@ public slots:
|
||||||
bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
bool destroyContextOverlay(const EntityItemID& entityItemID);
|
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_hoverEnterOverlay(const QUuid& id, const PointerEvent& event);
|
||||||
void contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
|
void contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
|
||||||
void contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event);
|
void contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event);
|
||||||
|
|
|
@ -63,13 +63,6 @@ Overlays::Overlays() {
|
||||||
ADD_TYPE_MAP(PolyLine, line3d);
|
ADD_TYPE_MAP(PolyLine, line3d);
|
||||||
ADD_TYPE_MAP(Grid, grid);
|
ADD_TYPE_MAP(Grid, grid);
|
||||||
ADD_TYPE_MAP(Gizmo, circle3d);
|
ADD_TYPE_MAP(Gizmo, circle3d);
|
||||||
|
|
||||||
auto mouseRayPick = std::make_shared<RayPick>(Vectors::ZERO, Vectors::UP,
|
|
||||||
PickFilter(PickFilter::getBitMask(PickFilter::FlagBit::LOCAL_ENTITIES) |
|
|
||||||
PickFilter::getBitMask(PickFilter::FlagBit::VISIBLE)), 0.0f, true);
|
|
||||||
mouseRayPick->parentTransform = std::make_shared<MouseTransformNode>();
|
|
||||||
mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE);
|
|
||||||
_mouseRayPickID = DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, mouseRayPick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::cleanupAllOverlays() {
|
void Overlays::cleanupAllOverlays() {
|
||||||
|
@ -86,15 +79,7 @@ void Overlays::cleanupAllOverlays() {
|
||||||
cleanupOverlaysToDelete();
|
cleanupOverlaysToDelete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::init() {
|
void Overlays::init() {}
|
||||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
|
||||||
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::update(float deltatime) {
|
void Overlays::update(float deltatime) {
|
||||||
cleanupOverlaysToDelete();
|
cleanupOverlaysToDelete();
|
||||||
|
@ -386,6 +371,8 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove
|
||||||
RENAME_PROP(animationSettings, animation);
|
RENAME_PROP(animationSettings, animation);
|
||||||
} else if (type == "Image") {
|
} else if (type == "Image") {
|
||||||
RENAME_PROP(url, imageURL);
|
RENAME_PROP(url, imageURL);
|
||||||
|
} else if (type == "Text") {
|
||||||
|
RENAME_PROP(color, textColor);
|
||||||
} else if (type == "Web") {
|
} else if (type == "Web") {
|
||||||
RENAME_PROP(url, sourceUrl);
|
RENAME_PROP(url, sourceUrl);
|
||||||
RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "Mouse" ? "mouse" : "touch"; });
|
RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "Mouse" ? "mouse" : "touch"; });
|
||||||
|
@ -686,6 +673,8 @@ QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemPropertie
|
||||||
RENAME_PROP(animation, animationSettings);
|
RENAME_PROP(animation, animationSettings);
|
||||||
} else if (type == "Image") {
|
} else if (type == "Image") {
|
||||||
RENAME_PROP(imageURL, url);
|
RENAME_PROP(imageURL, url);
|
||||||
|
} else if (type == "Text") {
|
||||||
|
RENAME_PROP(textColor, color);
|
||||||
} else if (type == "Web") {
|
} else if (type == "Web") {
|
||||||
RENAME_PROP(sourceUrl, url);
|
RENAME_PROP(sourceUrl, url);
|
||||||
RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "mouse" ? "Mouse" : "Touch"; });
|
RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "mouse" ? "Mouse" : "Touch"; });
|
||||||
|
@ -1239,12 +1228,12 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RayToOverlayIntersectionResult getPrevPickResult(unsigned int mouseRayPickID) {
|
RayToOverlayIntersectionResult getPrevPickResult() {
|
||||||
RayToOverlayIntersectionResult overlayResult;
|
RayToOverlayIntersectionResult overlayResult;
|
||||||
overlayResult.intersects = false;
|
overlayResult.intersects = false;
|
||||||
auto pickResult = DependencyManager::get<PickManager>()->getPrevPickResultTyped<RayPickResult>(mouseRayPickID);
|
auto pickResult = DependencyManager::get<PickManager>()->getPrevPickResultTyped<RayPickResult>(DependencyManager::get<EntityTreeRenderer>()->getMouseRayPickID());
|
||||||
if (pickResult) {
|
if (pickResult) {
|
||||||
overlayResult.intersects = pickResult->type != IntersectionType::NONE;
|
overlayResult.intersects = pickResult->type == IntersectionType::LOCAL_ENTITY;
|
||||||
if (overlayResult.intersects) {
|
if (overlayResult.intersects) {
|
||||||
overlayResult.intersection = pickResult->intersection;
|
overlayResult.intersection = pickResult->intersection;
|
||||||
overlayResult.distance = pickResult->distance;
|
overlayResult.distance = pickResult->distance;
|
||||||
|
@ -1292,7 +1281,7 @@ std::pair<float, QUuid> Overlays::mousePressEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mousePressEvent");
|
PerformanceTimer perfTimer("Overlays::mousePressEvent");
|
||||||
|
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID);
|
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||||
|
|
||||||
|
@ -1316,7 +1305,7 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
|
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
|
||||||
|
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID);
|
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||||
|
|
||||||
|
@ -1332,7 +1321,7 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
||||||
|
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID);
|
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release);
|
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release);
|
||||||
mouseReleasePointerEvent(rayPickResult.overlayID, pointerEvent);
|
mouseReleasePointerEvent(rayPickResult.overlayID, pointerEvent);
|
||||||
|
@ -1354,7 +1343,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
|
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
|
||||||
|
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID);
|
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move);
|
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||||
mouseMovePointerEvent(rayPickResult.overlayID, pointerEvent);
|
mouseMovePointerEvent(rayPickResult.overlayID, pointerEvent);
|
||||||
|
|
|
@ -719,7 +719,6 @@ private:
|
||||||
PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult,
|
PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult,
|
||||||
QMouseEvent* event, PointerEvent::EventType eventType);
|
QMouseEvent* event, PointerEvent::EventType eventType);
|
||||||
|
|
||||||
unsigned int _mouseRayPickID;
|
|
||||||
QUuid _currentClickingOnOverlayID;
|
QUuid _currentClickingOnOverlayID;
|
||||||
QUuid _currentHoverOverOverlayID;
|
QUuid _currentHoverOverOverlayID;
|
||||||
|
|
||||||
|
|
|
@ -208,16 +208,16 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe
|
||||||
avatar->setSessionUUID(sessionUUID);
|
avatar->setSessionUUID(sessionUUID);
|
||||||
avatar->setOwningAvatarMixer(mixerWeakPointer);
|
avatar->setOwningAvatarMixer(mixerWeakPointer);
|
||||||
|
|
||||||
// addAvatar is only called from newOrExistingAvatar, which already locks _hashLock
|
{
|
||||||
|
QWriteLocker locker(&_hashLock);
|
||||||
_avatarHash.insert(sessionUUID, avatar);
|
_avatarHash.insert(sessionUUID, avatar);
|
||||||
|
}
|
||||||
emit avatarAddedEvent(sessionUUID);
|
emit avatarAddedEvent(sessionUUID);
|
||||||
return avatar;
|
return avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer,
|
AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer, bool& isNew) {
|
||||||
bool& isNew) {
|
auto avatar = findAvatar(sessionUUID);
|
||||||
QWriteLocker locker(&_hashLock);
|
|
||||||
auto avatar = _avatarHash.value(sessionUUID);
|
|
||||||
if (!avatar) {
|
if (!avatar) {
|
||||||
avatar = addAvatar(sessionUUID, mixerWeakPointer);
|
avatar = addAvatar(sessionUUID, mixerWeakPointer);
|
||||||
isNew = true;
|
isNew = true;
|
||||||
|
|
|
@ -86,7 +86,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
||||||
auto handlePointerEvent = [&](const QUuid& entityID, const PointerEvent& event) {
|
auto handlePointerEvent = [&](const QUuid& entityID, const PointerEvent& event) {
|
||||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||||
auto entity = getEntity(entityID);
|
auto entity = getEntity(entityID);
|
||||||
if (entity && entity->getType() == EntityTypes::Web) {
|
if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) {
|
||||||
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
||||||
}
|
}
|
||||||
if (thisEntity) {
|
if (thisEntity) {
|
||||||
|
@ -99,7 +99,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
||||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
||||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||||
auto entity = getEntity(entityID);
|
auto entity = getEntity(entityID);
|
||||||
if (entity && entity->getType() == EntityTypes::Web) {
|
if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) {
|
||||||
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
||||||
}
|
}
|
||||||
if (thisEntity) {
|
if (thisEntity) {
|
||||||
|
@ -110,7 +110,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
||||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
||||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||||
auto entity = getEntity(entityID);
|
auto entity = getEntity(entityID);
|
||||||
if (entity && entity->getType() == EntityTypes::Web) {
|
if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) {
|
||||||
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
||||||
}
|
}
|
||||||
if (thisEntity) {
|
if (thisEntity) {
|
||||||
|
@ -1360,3 +1360,36 @@ EntityEditPacketSender* EntityTreeRenderer::getPacketSender() {
|
||||||
EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr;
|
EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr;
|
||||||
return packetSender;
|
return packetSender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTreeRenderer::_addMaterialToEntityOperator = nullptr;
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTreeRenderer::_removeMaterialFromEntityOperator = nullptr;
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTreeRenderer::_addMaterialToAvatarOperator = nullptr;
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> 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;
|
||||||
|
}
|
|
@ -73,6 +73,7 @@ public:
|
||||||
static void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { _calculateEntityLoadingPriorityFunc = fn; }
|
static void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { _calculateEntityLoadingPriorityFunc = fn; }
|
||||||
|
|
||||||
void setMouseRayPickID(unsigned int rayPickID) { _mouseRayPickID = rayPickID; }
|
void setMouseRayPickID(unsigned int rayPickID) { _mouseRayPickID = rayPickID; }
|
||||||
|
unsigned int getMouseRayPickID() { return _mouseRayPickID; }
|
||||||
void setMouseRayPickResultOperator(std::function<RayToEntityIntersectionResult(unsigned int)> getPrevRayPickResultOperator) { _getPrevRayPickResultOperator = getPrevRayPickResultOperator; }
|
void setMouseRayPickResultOperator(std::function<RayToEntityIntersectionResult(unsigned int)> getPrevRayPickResultOperator) { _getPrevRayPickResultOperator = getPrevRayPickResultOperator; }
|
||||||
void setSetPrecisionPickingOperator(std::function<void(unsigned int, bool)> setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; }
|
void setSetPrecisionPickingOperator(std::function<void(unsigned int, bool)> setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; }
|
||||||
|
|
||||||
|
@ -120,6 +121,16 @@ public:
|
||||||
|
|
||||||
EntityEditPacketSender* getPacketSender();
|
EntityEditPacketSender* getPacketSender();
|
||||||
|
|
||||||
|
static void setAddMaterialToEntityOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; }
|
||||||
|
static void setRemoveMaterialFromEntityOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> 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<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; }
|
||||||
|
static void setRemoveMaterialFromAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> 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:
|
signals:
|
||||||
void enterEntity(const EntityItemID& entityItemID);
|
void enterEntity(const EntityItemID& entityItemID);
|
||||||
void leaveEntity(const EntityItemID& entityItemID);
|
void leaveEntity(const EntityItemID& entityItemID);
|
||||||
|
@ -255,6 +266,11 @@ private:
|
||||||
workload::SpacePointer _space{ new workload::Space() };
|
workload::SpacePointer _space{ new workload::Space() };
|
||||||
workload::Transaction::Updates _spaceUpdates;
|
workload::Transaction::Updates _spaceUpdates;
|
||||||
|
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToEntityOperator;
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator;
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,6 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _created(entit
|
||||||
_needsRenderUpdate = true;
|
_needsRenderUpdate = true;
|
||||||
emit requestRenderUpdate();
|
emit requestRenderUpdate();
|
||||||
});
|
});
|
||||||
_materials = entity->getMaterials();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityRenderer::~EntityRenderer() { }
|
EntityRenderer::~EntityRenderer() { }
|
||||||
|
|
|
@ -14,42 +14,210 @@
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
|
||||||
bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
bool MaterialEntityRenderer::needsRenderUpdate() const {
|
||||||
if (entity->getMaterial() != _drawMaterial) {
|
if (_retryApply) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (entity->getParentID() != _parentID) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!_texturesLoaded) {
|
if (!_texturesLoaded) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return Parent::needsRenderUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||||
|
if (resultWithReadLock<bool>([&] {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
if (_drawMaterial != entity->getMaterial()) {
|
bool deleteNeeded = false;
|
||||||
_texturesLoaded = false;
|
bool addNeeded = _retryApply;
|
||||||
_drawMaterial = entity->getMaterial();
|
bool transformChanged = false;
|
||||||
|
{
|
||||||
|
MaterialMappingMode mode = entity->getMaterialMappingMode();
|
||||||
|
if (mode != _materialMappingMode) {
|
||||||
|
_materialMappingMode = mode;
|
||||||
|
transformChanged = true;
|
||||||
}
|
}
|
||||||
_parentID = entity->getParentID();
|
}
|
||||||
_materialMappingPos = entity->getMaterialMappingPos();
|
{
|
||||||
_materialMappingScale = entity->getMaterialMappingScale();
|
bool repeat = entity->getMaterialRepeat();
|
||||||
_materialMappingRot = entity->getMaterialMappingRot();
|
if (repeat != _materialRepeat) {
|
||||||
|
_materialRepeat = repeat;
|
||||||
|
transformChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
glm::vec2 mappingPos = entity->getMaterialMappingPos();
|
||||||
|
glm::vec2 mappingScale = entity->getMaterialMappingScale();
|
||||||
|
float mappingRot = entity->getMaterialMappingRot();
|
||||||
|
if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
|
||||||
|
_materialMappingPos = mappingPos;
|
||||||
|
_materialMappingScale = mappingScale;
|
||||||
|
_materialMappingRot = mappingRot;
|
||||||
|
transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Transform transform = entity->getTransform();
|
||||||
|
glm::vec3 dimensions = entity->getUnscaledDimensions();
|
||||||
|
if (transform != _transform || dimensions != _dimensions) {
|
||||||
|
_transform = transform;
|
||||||
|
_dimensions = dimensions;
|
||||||
|
transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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 urlChanged = false;
|
||||||
|
std::string newCurrentMaterialName = _currentMaterialName;
|
||||||
|
{
|
||||||
|
QString materialURL = entity->getMaterialURL();
|
||||||
|
if (materialURL != _materialURL) {
|
||||||
|
_materialURL = materialURL;
|
||||||
|
if (_materialURL.contains("?")) {
|
||||||
|
auto split = _materialURL.split("?");
|
||||||
|
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) {
|
||||||
|
materialDataChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QString parentMaterialName = entity->getParentMaterialName();
|
||||||
|
if (parentMaterialName != _parentMaterialName) {
|
||||||
|
_parentMaterialName = parentMaterialName;
|
||||||
|
deleteNeeded = true;
|
||||||
|
addNeeded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
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 (urlChanged && !usingMaterialData) {
|
||||||
|
_networkMaterial = MaterialCache::instance().getMaterial(_materialURL);
|
||||||
|
auto onMaterialRequestFinished = [&, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
|
||||||
|
if (success) {
|
||||||
|
deleteMaterial(oldParentID, oldParentMaterialName);
|
||||||
|
_texturesLoaded = false;
|
||||||
|
_parsedMaterials = _networkMaterial->parsedMaterials;
|
||||||
|
setCurrentMaterialName(newCurrentMaterialName);
|
||||||
|
applyMaterial();
|
||||||
|
} else {
|
||||||
|
deleteMaterial(oldParentID, oldParentMaterialName);
|
||||||
|
_retryApply = false;
|
||||||
|
_texturesLoaded = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (_networkMaterial) {
|
||||||
|
if (_networkMaterial->isLoaded()) {
|
||||||
|
onMaterialRequestFinished(!_networkMaterial->isFailed());
|
||||||
|
} else {
|
||||||
|
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, oldParentMaterialName);
|
||||||
|
}
|
||||||
|
if (addNeeded) {
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto material = getMaterial();
|
||||||
|
bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
|
||||||
|
if (!_texturesLoaded && newTexturesLoaded) {
|
||||||
|
material->checkResetOpacityMap();
|
||||||
|
}
|
||||||
|
_texturesLoaded = newTexturesLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
_renderTransform = getModelTransform();
|
_renderTransform = getModelTransform();
|
||||||
const float MATERIAL_ENTITY_SCALE = 0.5f;
|
const float MATERIAL_ENTITY_SCALE = 0.5f;
|
||||||
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
|
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
|
||||||
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||||
|
|
||||||
bool newTexturesLoaded = _drawMaterial ? !_drawMaterial->isMissingTexture() : false;
|
|
||||||
if (!_texturesLoaded && newTexturesLoaded) {
|
|
||||||
_drawMaterial->checkResetOpacityMap();
|
|
||||||
}
|
|
||||||
_texturesLoaded = newTexturesLoaded;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +229,9 @@ ItemKey MaterialEntityRenderer::getKey() {
|
||||||
builder.withInvisible();
|
builder.withInvisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_drawMaterial) {
|
const auto drawMaterial = getMaterial();
|
||||||
auto matKey = _drawMaterial->getKey();
|
if (drawMaterial) {
|
||||||
|
auto matKey = drawMaterial->getKey();
|
||||||
if (matKey.isTranslucent()) {
|
if (matKey.isTranslucent()) {
|
||||||
builder.withTransparent();
|
builder.withTransparent();
|
||||||
}
|
}
|
||||||
|
@ -73,8 +242,9 @@ ItemKey MaterialEntityRenderer::getKey() {
|
||||||
|
|
||||||
ShapeKey MaterialEntityRenderer::getShapeKey() {
|
ShapeKey MaterialEntityRenderer::getShapeKey() {
|
||||||
graphics::MaterialKey drawMaterialKey;
|
graphics::MaterialKey drawMaterialKey;
|
||||||
if (_drawMaterial) {
|
const auto drawMaterial = getMaterial();
|
||||||
drawMaterialKey = _drawMaterial->getKey();
|
if (drawMaterial) {
|
||||||
|
drawMaterialKey = drawMaterial->getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||||
|
@ -112,18 +282,24 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
||||||
|
|
||||||
// Don't render if our parent is set or our material is null
|
// Don't render if our parent is set or our material is null
|
||||||
QUuid parentID;
|
QUuid parentID;
|
||||||
|
withReadLock([&] {
|
||||||
|
parentID = _parentID;
|
||||||
|
});
|
||||||
|
if (!parentID.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Transform renderTransform;
|
Transform renderTransform;
|
||||||
graphics::MaterialPointer drawMaterial;
|
graphics::MaterialPointer drawMaterial;
|
||||||
Transform textureTransform;
|
Transform textureTransform;
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
parentID = _parentID;
|
|
||||||
renderTransform = _renderTransform;
|
renderTransform = _renderTransform;
|
||||||
drawMaterial = _drawMaterial;
|
drawMaterial = getMaterial();
|
||||||
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
|
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
|
||||||
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
|
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
|
||||||
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
|
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
|
||||||
});
|
});
|
||||||
if (!parentID.isNull() || !drawMaterial) {
|
if (!drawMaterial) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,3 +318,86 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
||||||
|
|
||||||
args->_details._trianglesRendered += (int)DependencyManager::get<GeometryCache>()->getSphereTriangleCount();
|
args->_details._trianglesRendered += (int)DependencyManager::get<GeometryCache>()->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<NetworkMaterial> MaterialEntityRenderer::getMaterial() const {
|
||||||
|
auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName);
|
||||||
|
if (material != _parsedMaterials.networkMaterials.end()) {
|
||||||
|
return material->second;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityRenderer::deleteMaterial(const QUuid& oldParentID, const QString& oldParentMaterialName) {
|
||||||
|
std::shared_ptr<NetworkMaterial> material = _appliedMaterial;
|
||||||
|
if (!material || oldParentID.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our parent could be an entity or an avatar
|
||||||
|
std::string oldParentMaterialNameStd = oldParentMaterialName.toStdString();
|
||||||
|
if (EntityTreeRenderer::removeMaterialFromEntity(oldParentID, material, oldParentMaterialNameStd)) {
|
||||||
|
_appliedMaterial = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityTreeRenderer::removeMaterialFromAvatar(oldParentID, material, oldParentMaterialNameStd)) {
|
||||||
|
_appliedMaterial = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a remove fails, our parent is gone, so we don't need to retry
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityRenderer::applyTextureTransform(std::shared_ptr<NetworkMaterial>& material) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityRenderer::applyMaterial() {
|
||||||
|
_retryApply = false;
|
||||||
|
|
||||||
|
std::shared_ptr<NetworkMaterial> material = getMaterial();
|
||||||
|
QUuid parentID = _parentID;
|
||||||
|
if (!material || parentID.isNull()) {
|
||||||
|
_appliedMaterial = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyTextureTransform(material);
|
||||||
|
|
||||||
|
graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, _priority);
|
||||||
|
|
||||||
|
// Our parent could be an entity or an avatar
|
||||||
|
std::string parentMaterialName = _parentMaterialName.toStdString();
|
||||||
|
if (EntityTreeRenderer::addMaterialToEntity(parentID, materialLayer, parentMaterialName)) {
|
||||||
|
_appliedMaterial = material;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityTreeRenderer::addMaterialToAvatar(parentID, materialLayer, parentMaterialName)) {
|
||||||
|
_appliedMaterial = material;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we've reached this point, we couldn't find our parent, so we need to try again later
|
||||||
|
_retryApply = true;
|
||||||
|
}
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include <MaterialEntityItem.h>
|
#include <MaterialEntityItem.h>
|
||||||
|
|
||||||
|
#include <material-networking/MaterialCache.h>
|
||||||
|
|
||||||
class NetworkMaterial;
|
class NetworkMaterial;
|
||||||
|
|
||||||
namespace render { namespace entities {
|
namespace render { namespace entities {
|
||||||
|
@ -22,22 +24,46 @@ class MaterialEntityRenderer : public TypedEntityRenderer<MaterialEntityItem> {
|
||||||
using Pointer = std::shared_ptr<MaterialEntityRenderer>;
|
using Pointer = std::shared_ptr<MaterialEntityRenderer>;
|
||||||
public:
|
public:
|
||||||
MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
|
MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
|
||||||
|
~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual bool needsRenderUpdate() const override;
|
||||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) 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;
|
virtual void doRender(RenderArgs* args) override;
|
||||||
|
|
||||||
ItemKey getKey() override;
|
ItemKey getKey() override;
|
||||||
ShapeKey getShapeKey() override;
|
ShapeKey getShapeKey() override;
|
||||||
|
|
||||||
|
QString _materialURL;
|
||||||
|
QString _materialData;
|
||||||
|
QString _parentMaterialName;
|
||||||
|
quint16 _priority;
|
||||||
QUuid _parentID;
|
QUuid _parentID;
|
||||||
|
|
||||||
|
MaterialMappingMode _materialMappingMode;
|
||||||
|
bool _materialRepeat;
|
||||||
glm::vec2 _materialMappingPos;
|
glm::vec2 _materialMappingPos;
|
||||||
glm::vec2 _materialMappingScale;
|
glm::vec2 _materialMappingScale;
|
||||||
float _materialMappingRot;
|
float _materialMappingRot;
|
||||||
bool _texturesLoaded { false };
|
Transform _transform;
|
||||||
|
glm::vec3 _dimensions;
|
||||||
|
|
||||||
|
bool _texturesLoaded { false };
|
||||||
|
bool _retryApply { false };
|
||||||
|
|
||||||
|
std::shared_ptr<NetworkMaterial> getMaterial() const;
|
||||||
|
void setCurrentMaterialName(const std::string& currentMaterialName);
|
||||||
|
|
||||||
|
void applyTextureTransform(std::shared_ptr<NetworkMaterial>& material);
|
||||||
|
void applyMaterial();
|
||||||
|
void deleteMaterial(const QUuid& oldParentID, const QString& oldParentMaterialName);
|
||||||
|
|
||||||
|
NetworkMaterialResourcePointer _networkMaterial;
|
||||||
|
NetworkMaterialResource::ParsedMaterials _parsedMaterials;
|
||||||
|
std::shared_ptr<NetworkMaterial> _appliedMaterial;
|
||||||
|
std::string _currentMaterialName;
|
||||||
|
|
||||||
std::shared_ptr<NetworkMaterial> _drawMaterial;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -3250,25 +3250,6 @@ void EntityItem::setSpaceIndex(int32_t index) {
|
||||||
void EntityItem::preDelete() {
|
void EntityItem::preDelete() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
|
||||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
|
||||||
_materials[parentMaterialName].push(material);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityItem::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
|
||||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
|
||||||
_materials[parentMaterialName].remove(material);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_map<std::string, graphics::MultiMaterial> EntityItem::getMaterials() {
|
|
||||||
std::unordered_map<std::string, graphics::MultiMaterial> toReturn;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
|
||||||
toReturn = _materials;
|
|
||||||
}
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EntityItem::getCloneable() const {
|
bool EntityItem::getCloneable() const {
|
||||||
bool result;
|
bool result;
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
|
|
|
@ -37,8 +37,6 @@
|
||||||
#include "EntityDynamicInterface.h"
|
#include "EntityDynamicInterface.h"
|
||||||
#include "GrabPropertyGroup.h"
|
#include "GrabPropertyGroup.h"
|
||||||
|
|
||||||
#include "graphics/Material.h"
|
|
||||||
|
|
||||||
class EntitySimulation;
|
class EntitySimulation;
|
||||||
class EntityTreeElement;
|
class EntityTreeElement;
|
||||||
class EntityTreeElementExtraEncodeData;
|
class EntityTreeElementExtraEncodeData;
|
||||||
|
@ -542,10 +540,6 @@ public:
|
||||||
virtual void preDelete();
|
virtual void preDelete();
|
||||||
virtual void postParentFixup() {}
|
virtual void postParentFixup() {}
|
||||||
|
|
||||||
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
|
||||||
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
|
||||||
std::unordered_map<std::string, graphics::MultiMaterial> getMaterials();
|
|
||||||
|
|
||||||
void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; }
|
void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; }
|
||||||
uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; }
|
uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; }
|
||||||
|
|
||||||
|
@ -754,11 +748,7 @@ protected:
|
||||||
QHash<QUuid, EntityDynamicPointer> _grabActions;
|
QHash<QUuid, EntityDynamicPointer> _grabActions;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
|
|
||||||
std::mutex _materialsLock;
|
|
||||||
|
|
||||||
static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> _getBillboardRotationOperator;
|
static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> _getBillboardRotationOperator;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityItem_h
|
#endif // hifi_EntityItem_h
|
||||||
|
|
|
@ -2953,41 +2953,9 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const {
|
||||||
return entity->getJointNames();
|
return entity->getJointNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToEntityOperator = nullptr;
|
|
||||||
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromEntityOperator = nullptr;
|
|
||||||
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToAvatarOperator = nullptr;
|
|
||||||
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromAvatarOperator = nullptr;
|
|
||||||
std::function<QObject*(const QUuid&)> EntityTree::_getEntityObjectOperator = nullptr;
|
std::function<QObject*(const QUuid&)> EntityTree::_getEntityObjectOperator = nullptr;
|
||||||
std::function<QSizeF(const QUuid&, const QString&)> EntityTree::_textSizeOperator = nullptr;
|
std::function<QSizeF(const QUuid&, const QString&)> EntityTree::_textSizeOperator = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
QObject* EntityTree::getEntityObject(const QUuid& id) {
|
QObject* EntityTree::getEntityObject(const QUuid& id) {
|
||||||
if (_getEntityObjectOperator) {
|
if (_getEntityObjectOperator) {
|
||||||
return _getEntityObjectOperator(id);
|
return _getEntityObjectOperator(id);
|
||||||
|
|
|
@ -262,16 +262,6 @@ public:
|
||||||
void setIsServerlessMode(bool value) { _serverlessDomain = value; }
|
void setIsServerlessMode(bool value) { _serverlessDomain = value; }
|
||||||
bool isServerlessMode() const { return _serverlessDomain; }
|
bool isServerlessMode() const { return _serverlessDomain; }
|
||||||
|
|
||||||
static void setAddMaterialToEntityOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; }
|
|
||||||
static void setRemoveMaterialFromEntityOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> 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<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; }
|
|
||||||
static void setRemoveMaterialFromAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> 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 setGetEntityObjectOperator(std::function<QObject*(const QUuid&)> getEntityObjectOperator) { _getEntityObjectOperator = getEntityObjectOperator; }
|
static void setGetEntityObjectOperator(std::function<QObject*(const QUuid&)> getEntityObjectOperator) { _getEntityObjectOperator = getEntityObjectOperator; }
|
||||||
static QObject* getEntityObject(const QUuid& id);
|
static QObject* getEntityObject(const QUuid& id);
|
||||||
|
|
||||||
|
@ -386,10 +376,6 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<AvatarData> _myAvatar{ nullptr };
|
std::shared_ptr<AvatarData> _myAvatar{ nullptr };
|
||||||
|
|
||||||
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToEntityOperator;
|
|
||||||
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator;
|
|
||||||
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
|
|
||||||
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator;
|
|
||||||
static std::function<QObject*(const QUuid&)> _getEntityObjectOperator;
|
static std::function<QObject*(const QUuid&)> _getEntityObjectOperator;
|
||||||
static std::function<QSizeF(const QUuid&, const QString&)> _textSizeOperator;
|
static std::function<QSizeF(const QUuid&, const QString&)> _textSizeOperator;
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,6 @@
|
||||||
EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
|
Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
|
||||||
entity->setProperties(properties);
|
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;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +24,6 @@ MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : Entit
|
||||||
_type = EntityTypes::Material;
|
_type = EntityTypes::Material;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialEntityItem::~MaterialEntityItem() {
|
|
||||||
removeMaterial();
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
|
EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
|
||||||
EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
|
EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL);
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL);
|
||||||
|
@ -131,7 +124,6 @@ void MaterialEntityItem::debugDump() const {
|
||||||
qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||||
qCDebug(entities) << " name:" << _name;
|
qCDebug(entities) << " name:" << _name;
|
||||||
qCDebug(entities) << " material url:" << _materialURL;
|
qCDebug(entities) << " material url:" << _materialURL;
|
||||||
qCDebug(entities) << " current material name:" << _currentMaterialName.c_str();
|
|
||||||
qCDebug(entities) << " material mapping mode:" << _materialMappingMode;
|
qCDebug(entities) << " material mapping mode:" << _materialMappingMode;
|
||||||
qCDebug(entities) << " material repeat:" << _materialRepeat;
|
qCDebug(entities) << " material repeat:" << _materialRepeat;
|
||||||
qCDebug(entities) << " priority:" << _priority;
|
qCDebug(entities) << " priority:" << _priority;
|
||||||
|
@ -154,208 +146,101 @@ void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<NetworkMaterial> MaterialEntityItem::getMaterial() const {
|
QString MaterialEntityItem::getMaterialURL() const {
|
||||||
auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName);
|
return resultWithReadLock<QString>([&] {
|
||||||
if (material != _parsedMaterials.networkMaterials.end()) {
|
return _materialURL;
|
||||||
return material->second;
|
});
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool materialDataChanged) {
|
void MaterialEntityItem::setMaterialURL(const QString& materialURL) {
|
||||||
bool usingMaterialData = materialDataChanged || materialURLString.startsWith("materialData");
|
withWriteLock([&] {
|
||||||
if (_materialURL != materialURLString || (usingMaterialData && materialDataChanged)) {
|
_materialURL = materialURL;
|
||||||
removeMaterial();
|
});
|
||||||
_materialURL = materialURLString;
|
|
||||||
|
|
||||||
if (materialURLString.contains("?")) {
|
|
||||||
auto split = materialURLString.split("?");
|
|
||||||
_currentMaterialName = split.last().toStdString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usingMaterialData) {
|
QString MaterialEntityItem::getMaterialData() const {
|
||||||
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getMaterialData().toUtf8()), materialURLString);
|
return resultWithReadLock<QString>([&] {
|
||||||
|
return _materialData;
|
||||||
// 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::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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::setMaterialData(const QString& materialData) {
|
void MaterialEntityItem::setMaterialData(const QString& materialData) {
|
||||||
if (_materialData != materialData) {
|
withWriteLock([&] {
|
||||||
_materialData = materialData;
|
_materialData = materialData;
|
||||||
if (_materialURL.startsWith("materialData")) {
|
});
|
||||||
// Trigger material update when material data changes
|
|
||||||
setMaterialURL(_materialURL, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaterialMappingMode MaterialEntityItem::getMaterialMappingMode() const {
|
||||||
|
return resultWithReadLock<MaterialMappingMode>([&] {
|
||||||
|
return _materialMappingMode;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::setMaterialMappingMode(MaterialMappingMode mode) {
|
void MaterialEntityItem::setMaterialMappingMode(MaterialMappingMode mode) {
|
||||||
if (_materialMappingMode != mode) {
|
withWriteLock([&] {
|
||||||
removeMaterial();
|
|
||||||
_materialMappingMode = mode;
|
_materialMappingMode = mode;
|
||||||
|
});
|
||||||
setUnscaledDimensions(_desiredDimensions);
|
setUnscaledDimensions(_desiredDimensions);
|
||||||
applyMaterial();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::setMaterialRepeat(bool repeat) {
|
quint16 MaterialEntityItem::getPriority() const {
|
||||||
if (_materialRepeat != repeat) {
|
return resultWithReadLock<quint16>([&] {
|
||||||
removeMaterial();
|
return _priority;
|
||||||
_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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::setPriority(quint16 priority) {
|
void MaterialEntityItem::setPriority(quint16 priority) {
|
||||||
if (_priority != priority) {
|
withWriteLock([&] {
|
||||||
removeMaterial();
|
|
||||||
_priority = priority;
|
_priority = priority;
|
||||||
applyMaterial();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString MaterialEntityItem::getParentMaterialName() const {
|
||||||
|
return resultWithReadLock<QString>([&] {
|
||||||
|
return _parentMaterialName;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::setParentMaterialName(const QString& parentMaterialName) {
|
void MaterialEntityItem::setParentMaterialName(const QString& parentMaterialName) {
|
||||||
if (_parentMaterialName != parentMaterialName) {
|
withWriteLock([&] {
|
||||||
removeMaterial();
|
|
||||||
_parentMaterialName = parentMaterialName;
|
_parentMaterialName = parentMaterialName;
|
||||||
applyMaterial();
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::setParentID(const QUuid& parentID) {
|
glm::vec2 MaterialEntityItem::getMaterialMappingPos() const {
|
||||||
if (getParentID() != parentID) {
|
return resultWithReadLock<glm::vec2>([&] {
|
||||||
removeMaterial();
|
return _materialMappingPos;
|
||||||
EntityItem::setParentID(parentID);
|
});
|
||||||
applyMaterial();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::locationChanged(bool tellPhysics) {
|
void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) {
|
||||||
EntityItem::locationChanged();
|
withWriteLock([&] {
|
||||||
if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
_materialMappingPos = materialMappingPos;
|
||||||
removeMaterial();
|
});
|
||||||
applyMaterial();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::dimensionsChanged() {
|
glm::vec2 MaterialEntityItem::getMaterialMappingScale() const {
|
||||||
EntityItem::dimensionsChanged();
|
return resultWithReadLock<glm::vec2>([&] {
|
||||||
if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
return _materialMappingScale;
|
||||||
removeMaterial();
|
});
|
||||||
applyMaterial();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialEntityItem::removeMaterial() {
|
void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) {
|
||||||
graphics::MaterialPointer material = getMaterial();
|
withWriteLock([&] {
|
||||||
if (!material) {
|
_materialMappingScale = materialMappingScale;
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
QUuid parentID = getParentID();
|
|
||||||
if (parentID.isNull()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our parent could be an entity or an avatar
|
float MaterialEntityItem::getMaterialMappingRot() const {
|
||||||
if (EntityTree::removeMaterialFromEntity(parentID, material, getParentMaterialName().toStdString())) {
|
return resultWithReadLock<float>([&] {
|
||||||
return;
|
return _materialMappingRot;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialName().toStdString())) {
|
void MaterialEntityItem::setMaterialMappingRot(float materialMappingRot) {
|
||||||
return;
|
withWriteLock([&] {
|
||||||
}
|
_materialMappingRot = materialMappingRot;
|
||||||
|
});
|
||||||
// if a remove fails, our parent is gone, so we don't need to retry
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEntityItem::applyMaterial() {
|
|
||||||
_retryApply = false;
|
|
||||||
graphics::MaterialPointer material = getMaterial();
|
|
||||||
QUuid parentID = getParentID();
|
|
||||||
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 = 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 or an avatar
|
|
||||||
if (EntityTree::addMaterialToEntity(parentID, materialLayer, getParentMaterialName().toStdString())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EntityTree::addMaterialToAvatar(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) {
|
AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) {
|
||||||
|
@ -372,18 +257,3 @@ AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) {
|
||||||
}
|
}
|
||||||
return aaCube;
|
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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
#include "EntityItem.h"
|
#include "EntityItem.h"
|
||||||
|
|
||||||
#include "MaterialMappingMode.h"
|
#include "MaterialMappingMode.h"
|
||||||
#include <model-networking/ModelCache.h>
|
|
||||||
#include <material-networking/MaterialCache.h>
|
|
||||||
|
|
||||||
class MaterialEntityItem : public EntityItem {
|
class MaterialEntityItem : public EntityItem {
|
||||||
using Pointer = std::shared_ptr<MaterialEntityItem>;
|
using Pointer = std::shared_ptr<MaterialEntityItem>;
|
||||||
|
@ -21,13 +19,9 @@ public:
|
||||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
MaterialEntityItem(const EntityItemID& entityItemID);
|
MaterialEntityItem(const EntityItemID& entityItemID);
|
||||||
~MaterialEntityItem();
|
|
||||||
|
|
||||||
ALLOW_INSTANTIATION // This class can be instantiated
|
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
|
// methods for getting/setting all properties of an entity
|
||||||
virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
|
virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
|
||||||
virtual bool setProperties(const EntityItemProperties& properties) override;
|
virtual bool setProperties(const EntityItemProperties& properties) override;
|
||||||
|
@ -52,44 +46,30 @@ public:
|
||||||
|
|
||||||
virtual void setUnscaledDimensions(const glm::vec3& value) override;
|
virtual void setUnscaledDimensions(const glm::vec3& value) override;
|
||||||
|
|
||||||
QString getMaterialURL() const { return _materialURL; }
|
QString getMaterialURL() const;
|
||||||
void setMaterialURL(const QString& materialURLString, bool materialDataChanged = false);
|
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);
|
void setMaterialMappingMode(MaterialMappingMode mode);
|
||||||
|
|
||||||
bool getMaterialRepeat() const { return _materialRepeat; }
|
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);
|
void setPriority(quint16 priority);
|
||||||
|
|
||||||
QString getParentMaterialName() const { return _parentMaterialName; }
|
QString getParentMaterialName() const;
|
||||||
void setParentMaterialName(const QString& parentMaterialName);
|
void setParentMaterialName(const QString& parentMaterialName);
|
||||||
|
|
||||||
glm::vec2 getMaterialMappingPos() const { return _materialMappingPos; }
|
glm::vec2 getMaterialMappingPos() const;
|
||||||
void setMaterialMappingPos(const glm::vec2& materialMappingPos);
|
void setMaterialMappingPos(const glm::vec2& materialMappingPos);
|
||||||
glm::vec2 getMaterialMappingScale() const { return _materialMappingScale; }
|
glm::vec2 getMaterialMappingScale() const;
|
||||||
void setMaterialMappingScale(const glm::vec2& materialMappingScale);
|
void setMaterialMappingScale(const glm::vec2& materialMappingScale);
|
||||||
float getMaterialMappingRot() const { return _materialMappingRot; }
|
float getMaterialMappingRot() const;
|
||||||
void setMaterialMappingRot(const float& materialMappingRot);
|
void setMaterialMappingRot(float materialMappingRot);
|
||||||
|
|
||||||
QString getMaterialData() const { return _materialData; }
|
|
||||||
void setMaterialData(const QString& materialData);
|
|
||||||
|
|
||||||
std::shared_ptr<NetworkMaterial> getMaterial() const;
|
|
||||||
|
|
||||||
void setParentID(const QUuid& parentID) override;
|
|
||||||
|
|
||||||
void locationChanged(bool tellPhysics) override;
|
|
||||||
void dimensionsChanged() override;
|
|
||||||
|
|
||||||
void applyMaterial();
|
|
||||||
void removeMaterial();
|
|
||||||
|
|
||||||
void postParentFixup() override;
|
|
||||||
|
|
||||||
AACube calculateInitialQueryAACube(bool& success) override;
|
AACube calculateInitialQueryAACube(bool& success) override;
|
||||||
|
|
||||||
|
@ -128,12 +108,6 @@ private:
|
||||||
float _materialMappingRot { 0 };
|
float _materialMappingRot { 0 };
|
||||||
QString _materialData;
|
QString _materialData;
|
||||||
|
|
||||||
NetworkMaterialResourcePointer _networkMaterial;
|
|
||||||
NetworkMaterialResource::ParsedMaterials _parsedMaterials;
|
|
||||||
std::string _currentMaterialName;
|
|
||||||
|
|
||||||
bool _retryApply { false };
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_MaterialEntityItem_h
|
#endif // hifi_MaterialEntityItem_h
|
||||||
|
|
|
@ -368,16 +368,17 @@ static bool isLocalUrl(const QUrl& url) {
|
||||||
return (scheme == HIFI_URL_SCHEME_FILE || scheme == URL_SCHEME_QRC || scheme == RESOURCE_SCHEME);
|
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<const TextureExtra*>(extra);
|
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
||||||
_type = textureExtra ? textureExtra->type : image::TextureUsage::DEFAULT_TEXTURE;
|
_type = textureExtra ? textureExtra->type : image::TextureUsage::DEFAULT_TEXTURE;
|
||||||
_maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS;
|
_maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS;
|
||||||
_sourceChannel = textureExtra ? textureExtra->sourceChannel : image::ColorChannel::NONE;
|
_sourceChannel = textureExtra ? textureExtra->sourceChannel : image::ColorChannel::NONE;
|
||||||
|
|
||||||
if (_textureSource) {
|
if (isNewExtra && !_loaded) {
|
||||||
_textureSource->setUrl(_url);
|
_startedLoading = false;
|
||||||
_textureSource->setType((int)_type);
|
}
|
||||||
} else {
|
|
||||||
|
if (!_textureSource || isNewExtra) {
|
||||||
_textureSource = std::make_shared<gpu::TextureSource>(_url, (int)_type);
|
_textureSource = std::make_shared<gpu::TextureSource>(_url, (int)_type);
|
||||||
}
|
}
|
||||||
_lowestRequestedMipLevel = 0;
|
_lowestRequestedMipLevel = 0;
|
||||||
|
|
|
@ -64,7 +64,7 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void setOriginalDescriptor(ktx::KTXDescriptor* descriptor) { _originalKtxDescriptor.reset(descriptor); }
|
Q_INVOKABLE void setOriginalDescriptor(ktx::KTXDescriptor* descriptor) { _originalKtxDescriptor.reset(descriptor); }
|
||||||
|
|
||||||
void setExtra(void* extra) override;
|
void setExtra(void* extra, bool isNewExtra) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void networkTextureCreated(const QWeakPointer<NetworkTexture>& self);
|
void networkTextureCreated(const QWeakPointer<NetworkTexture>& self);
|
||||||
|
|
|
@ -309,7 +309,7 @@ public:
|
||||||
|
|
||||||
virtual void downloadFinished(const QByteArray& data) override;
|
virtual void downloadFinished(const QByteArray& data) override;
|
||||||
|
|
||||||
void setExtra(void* extra) override;
|
void setExtra(void* extra, bool isNewExtra) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel, QVariantHash mapping);
|
Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel, QVariantHash mapping);
|
||||||
|
@ -320,7 +320,7 @@ private:
|
||||||
bool _combineParts;
|
bool _combineParts;
|
||||||
};
|
};
|
||||||
|
|
||||||
void GeometryDefinitionResource::setExtra(void* extra) {
|
void GeometryDefinitionResource::setExtra(void* extra, bool isNewExtra) {
|
||||||
const GeometryExtra* geometryExtra = static_cast<const GeometryExtra*>(extra);
|
const GeometryExtra* geometryExtra = static_cast<const GeometryExtra*>(extra);
|
||||||
_mapping = geometryExtra ? geometryExtra->mapping : QVariantHash();
|
_mapping = geometryExtra ? geometryExtra->mapping : QVariantHash();
|
||||||
_textureBaseUrl = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl();
|
_textureBaseUrl = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl();
|
||||||
|
|
|
@ -355,7 +355,7 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
||||||
} else if (resourcesWithExtraHash.size() > 0.0f) {
|
} 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).
|
// 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 = createResourceCopy(resourcesWithExtraHash.begin().value().lock());
|
||||||
resource->setExtra(extra);
|
resource->setExtra(extra, true);
|
||||||
resource->setExtraHash(extraHash);
|
resource->setExtraHash(extraHash);
|
||||||
resource->setSelf(resource);
|
resource->setSelf(resource);
|
||||||
resource->setCache(this);
|
resource->setCache(this);
|
||||||
|
@ -375,7 +375,7 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
||||||
|
|
||||||
if (!resource) {
|
if (!resource) {
|
||||||
resource = createResource(url);
|
resource = createResource(url);
|
||||||
resource->setExtra(extra);
|
resource->setExtra(extra, false);
|
||||||
resource->setExtraHash(extraHash);
|
resource->setExtraHash(extraHash);
|
||||||
resource->setSelf(resource);
|
resource->setSelf(resource);
|
||||||
resource->setCache(this);
|
resource->setCache(this);
|
||||||
|
|
|
@ -417,7 +417,7 @@ public:
|
||||||
unsigned int getDownloadAttempts() { return _attempts; }
|
unsigned int getDownloadAttempts() { return _attempts; }
|
||||||
unsigned int getDownloadAttemptsRemaining() { return _attemptsRemaining; }
|
unsigned int getDownloadAttemptsRemaining() { return _attemptsRemaining; }
|
||||||
|
|
||||||
virtual void setExtra(void* extra) {};
|
virtual void setExtra(void* extra, bool isNewExtra) {};
|
||||||
void setExtraHash(size_t extraHash) { _extraHash = extraHash; }
|
void setExtraHash(size_t extraHash) { _extraHash = extraHash; }
|
||||||
size_t getExtraHash() const { return _extraHash; }
|
size_t getExtraHash() const { return _extraHash; }
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() {
|
||||||
}
|
}
|
||||||
|
|
||||||
AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() :
|
AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() :
|
||||||
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false),
|
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion"),
|
||||||
perspectiveScale{ 1.0f },
|
perspectiveScale{ 1.0f },
|
||||||
edgeSharpness{ 1.0f },
|
edgeSharpness{ 1.0f },
|
||||||
blurRadius{ 4 },
|
blurRadius{ 4 },
|
||||||
|
|
|
@ -118,7 +118,7 @@ protected:
|
||||||
float enableSkinning{ 1.0f };
|
float enableSkinning{ 1.0f };
|
||||||
float enableBlendshape{ 1.0f };
|
float enableBlendshape{ 1.0f };
|
||||||
|
|
||||||
float enableAmbientOcclusion{ 0.0f };
|
float enableAmbientOcclusion{ 0.0f }; // false by default
|
||||||
float enableShadow{ 1.0f };
|
float enableShadow{ 1.0f };
|
||||||
float spare1{ 1.0f };
|
float spare1{ 1.0f };
|
||||||
float spare2{ 1.0f };
|
float spare2{ 1.0f };
|
||||||
|
@ -196,15 +196,13 @@ public:
|
||||||
bool enableSkinning{ true };
|
bool enableSkinning{ true };
|
||||||
bool enableBlendshape{ true };
|
bool enableBlendshape{ true };
|
||||||
|
|
||||||
bool enableAmbientOcclusion{ true };
|
bool enableAmbientOcclusion{ false }; // false by default
|
||||||
bool enableShadow{ true };
|
bool enableShadow{ true };
|
||||||
|
|
||||||
|
|
||||||
void setAmbientOcclusion(bool enable) { enableAmbientOcclusion = enable; emit dirty();}
|
void setAmbientOcclusion(bool enable) { enableAmbientOcclusion = enable; emit dirty();}
|
||||||
bool isAmbientOcclusionEnabled() const { return enableAmbientOcclusion; }
|
bool isAmbientOcclusionEnabled() const { return enableAmbientOcclusion; }
|
||||||
void setShadow(bool enable) {
|
void setShadow(bool enable) { enableShadow = enable; emit dirty(); }
|
||||||
enableShadow = enable; emit dirty();
|
|
||||||
}
|
|
||||||
bool isShadowEnabled() const { return enableShadow; }
|
bool isShadowEnabled() const { return enableShadow; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -47,7 +47,7 @@ Rectangle {
|
||||||
"Lightmap:LightingModel:enableLightmap",
|
"Lightmap:LightingModel:enableLightmap",
|
||||||
"Background:LightingModel:enableBackground",
|
"Background:LightingModel:enableBackground",
|
||||||
"Haze:LightingModel:enableHaze",
|
"Haze:LightingModel:enableHaze",
|
||||||
"ssao:LightingModel:enableAmbientOcclusion",
|
"AO:LightingModel:enableAmbientOcclusion",
|
||||||
"Textures:LightingModel:enableMaterialTexturing"
|
"Textures:LightingModel:enableMaterialTexturing"
|
||||||
]
|
]
|
||||||
HifiControls.CheckBox {
|
HifiControls.CheckBox {
|
||||||
|
|
|
@ -45,7 +45,8 @@ var OVERLAY_DATA_HMD = {
|
||||||
emissive: true,
|
emissive: true,
|
||||||
drawInFront: true,
|
drawInFront: true,
|
||||||
parentID: MyAvatar.SELF_ID,
|
parentID: MyAvatar.SELF_ID,
|
||||||
parentJointIndex: CAMERA_MATRIX
|
parentJointIndex: CAMERA_MATRIX,
|
||||||
|
ignorePickIntersection: true
|
||||||
};
|
};
|
||||||
|
|
||||||
var AWAY_INTRO = {
|
var AWAY_INTRO = {
|
||||||
|
|
|
@ -196,14 +196,14 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
var playAreaOverlayProperties = {
|
var playAreaOverlayProperties = {
|
||||||
dimensions:
|
dimensions:
|
||||||
Vec3.multiply(this.teleportScaleFactor * avatarScale, {
|
Vec3.multiply(_this.teleportScaleFactor * avatarScale, {
|
||||||
x: this.playArea.width,
|
x: _this.playArea.width,
|
||||||
y: this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y,
|
y: _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y,
|
||||||
z: this.playArea.height
|
z: _this.playArea.height
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.teleportScaleFactor < 1) {
|
if (_this.teleportScaleFactor < 1) {
|
||||||
// Adjust position of playAreOverlay so that its base is at correct height.
|
// Adjust position of playAreOverlay so that its base is at correct height.
|
||||||
// Always parenting to teleport target is good enough for this.
|
// Always parenting to teleport target is good enough for this.
|
||||||
var sensorToWorldMatrix = MyAvatar.sensorToWorldMatrix;
|
var sensorToWorldMatrix = MyAvatar.sensorToWorldMatrix;
|
||||||
|
@ -212,37 +212,37 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
var avatarSensorPosition = Mat4.transformPoint(worldToSensorMatrix, MyAvatar.position);
|
var avatarSensorPosition = Mat4.transformPoint(worldToSensorMatrix, MyAvatar.position);
|
||||||
avatarSensorPosition.y = 0;
|
avatarSensorPosition.y = 0;
|
||||||
|
|
||||||
var targetRotation = Overlays.getProperty(this.targetOverlayID, "rotation");
|
var targetRotation = Overlays.getProperty(_this.targetOverlayID, "rotation");
|
||||||
var relativePlayAreaCenterOffset =
|
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),
|
var localPosition = Vec3.multiplyQbyV(Quat.inverse(targetRotation),
|
||||||
Vec3.multiplyQbyV(sensorToWorldRotation,
|
Vec3.multiplyQbyV(sensorToWorldRotation,
|
||||||
Vec3.multiply(avatarScale, Vec3.subtract(relativePlayAreaCenterOffset, avatarSensorPosition))));
|
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;
|
playAreaOverlayProperties.localPosition = localPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlays.editOverlay(this.playAreaOverlay, playAreaOverlayProperties);
|
Overlays.editOverlay(_this.playAreaOverlay, playAreaOverlayProperties);
|
||||||
|
|
||||||
for (var i = 0; i < this.playAreaSensorPositionOverlays.length; i++) {
|
for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) {
|
||||||
localPosition = this.playAreaSensorPositions[i];
|
localPosition = _this.playAreaSensorPositions[i];
|
||||||
localPosition = Vec3.multiply(avatarScale, localPosition);
|
localPosition = Vec3.multiply(avatarScale, localPosition);
|
||||||
// Position relative to the play area.
|
// Position relative to the play area.
|
||||||
localPosition.y = avatarScale * (this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2
|
localPosition.y = avatarScale * (_this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2
|
||||||
- this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2);
|
- _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2);
|
||||||
Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], {
|
Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], {
|
||||||
dimensions: Vec3.multiply(this.teleportScaleFactor * avatarScale, this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS),
|
dimensions: Vec3.multiply(_this.teleportScaleFactor * avatarScale, _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS),
|
||||||
parentID: this.playAreaOverlay,
|
parentID: _this.playAreaOverlay,
|
||||||
localPosition: localPosition
|
localPosition: localPosition
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updatePlayAreaScale = function () {
|
this.updatePlayAreaScale = function () {
|
||||||
if (this.isPlayAreaAvailable) {
|
if (_this.isPlayAreaAvailable) {
|
||||||
this.setPlayAreaDimensions();
|
_this.setPlayAreaDimensions();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
for (var i = 0, length = teleportRenderStates.length; i < length; i++) {
|
for (var i = 0, length = teleportRenderStates.length; i < length; i++) {
|
||||||
var state = properties.renderStates[teleportRenderStates[i].name];
|
var state = properties.renderStates[teleportRenderStates[i].name];
|
||||||
if (state && state.end) {
|
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.translateZAction = Controller.findAction("TranslateZ");
|
||||||
|
|
||||||
this.setPlayAreaVisible = function (visible, targetOverlayID, fade) {
|
this.setPlayAreaVisible = function (visible, targetOverlayID, fade) {
|
||||||
if (!this.isPlayAreaAvailable || this.isPlayAreaVisible === visible) {
|
if (!_this.isPlayAreaAvailable || _this.isPlayAreaVisible === visible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.wasPlayAreaVisible = this.isPlayAreaVisible;
|
_this.wasPlayAreaVisible = _this.isPlayAreaVisible;
|
||||||
this.isPlayAreaVisible = visible;
|
_this.isPlayAreaVisible = visible;
|
||||||
this.targetOverlayID = targetOverlayID;
|
_this.targetOverlayID = targetOverlayID;
|
||||||
|
|
||||||
if (this.teleportedFadeTimer !== null) {
|
if (_this.teleportedFadeTimer !== null) {
|
||||||
Script.clearTimeout(this.teleportedFadeTimer);
|
Script.clearTimeout(_this.teleportedFadeTimer);
|
||||||
this.teleportedFadeTimer = null;
|
_this.teleportedFadeTimer = null;
|
||||||
}
|
}
|
||||||
if (visible || !fade) {
|
if (visible || !fade) {
|
||||||
// Immediately make visible or invisible.
|
// Immediately make visible or invisible.
|
||||||
this.isPlayAreaVisible = visible;
|
_this.isPlayAreaVisible = visible;
|
||||||
Overlays.editOverlay(this.playAreaOverlay, {
|
Overlays.editOverlay(_this.playAreaOverlay, {
|
||||||
dimensions: Vec3.ZERO,
|
dimensions: Vec3.ZERO,
|
||||||
alpha: this.PLAY_AREA_BOX_ALPHA,
|
alpha: _this.PLAY_AREA_BOX_ALPHA,
|
||||||
visible: visible
|
visible: visible
|
||||||
});
|
});
|
||||||
for (var i = 0; i < this.playAreaSensorPositionOverlays.length; i++) {
|
for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) {
|
||||||
Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], {
|
Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], {
|
||||||
dimensions: Vec3.ZERO,
|
dimensions: Vec3.ZERO,
|
||||||
alpha: this.PLAY_AREA_SENSOR_ALPHA,
|
alpha: _this.PLAY_AREA_SENSOR_ALPHA,
|
||||||
visible: visible
|
visible: visible
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Overlays.editOverlay(this.teleportedTargetOverlay, { visible: false });
|
Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false });
|
||||||
} else {
|
} else {
|
||||||
// Fading out of overlays is initiated in setTeleportVisible().
|
// 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.
|
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) {
|
if (Vec3.distance(targetXZPosition, avatarXZPosition) < MIN_PARENTING_DISTANCE) {
|
||||||
// Set play area position and rotation in world coordinates with no parenting.
|
// Set play area position and rotation in world coordinates with no parenting.
|
||||||
Overlays.editOverlay(this.playAreaOverlay, {
|
Overlays.editOverlay(_this.playAreaOverlay, {
|
||||||
parentID: Uuid.NULL,
|
parentID: Uuid.NULL,
|
||||||
position: Vec3.sum(position,
|
position: Vec3.sum(position,
|
||||||
Vec3.multiplyQbyV(sensorToWorldRotation,
|
Vec3.multiplyQbyV(sensorToWorldRotation,
|
||||||
Vec3.multiply(MyAvatar.sensorToWorldScale,
|
Vec3.multiply(MyAvatar.sensorToWorldScale,
|
||||||
Vec3.subtract(this.playAreaCenterOffset, avatarSensorPosition)))),
|
Vec3.subtract(_this.playAreaCenterOffset, avatarSensorPosition)))),
|
||||||
rotation: sensorToWorldRotation
|
rotation: sensorToWorldRotation
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Set play area position and rotation in local coordinates with parenting.
|
// 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 sensorToTargetRotation = Quat.multiply(Quat.inverse(targetRotation), sensorToWorldRotation);
|
||||||
var relativePlayAreaCenterOffset =
|
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 });
|
||||||
Overlays.editOverlay(this.playAreaOverlay, {
|
Overlays.editOverlay(_this.playAreaOverlay, {
|
||||||
parentID: this.targetOverlayID,
|
parentID: _this.targetOverlayID,
|
||||||
localPosition: Vec3.multiplyQbyV(Quat.inverse(targetRotation),
|
localPosition: Vec3.multiplyQbyV(Quat.inverse(targetRotation),
|
||||||
Vec3.multiplyQbyV(sensorToWorldRotation,
|
Vec3.multiplyQbyV(sensorToWorldRotation,
|
||||||
Vec3.multiply(MyAvatar.sensorToWorldScale,
|
Vec3.multiply(MyAvatar.sensorToWorldScale,
|
||||||
|
@ -578,33 +578,33 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_this.teleportedFadeTimer = null;
|
_this.teleportedFadeTimer = null;
|
||||||
Selection.disableListHighlight(this.teleporterSelectionName);
|
Selection.disableListHighlight(_this.teleporterSelectionName);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.cancelFade = function () {
|
this.cancelFade = function () {
|
||||||
// Other hand may call this to immediately hide fading overlays.
|
// Other hand may call this to immediately hide fading overlays.
|
||||||
var i, length;
|
var i, length;
|
||||||
if (this.teleportedFadeTimer) {
|
if (_this.teleportedFadeTimer) {
|
||||||
Overlays.editOverlay(this.teleportedTargetOverlay, { visible: false });
|
Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false });
|
||||||
if (this.wasPlayAreaVisible) {
|
if (_this.wasPlayAreaVisible) {
|
||||||
Overlays.editOverlay(this.playAreaOverlay, { visible: false });
|
Overlays.editOverlay(_this.playAreaOverlay, { visible: false });
|
||||||
for (i = 0, length = this.playAreaSensorPositionOverlays.length; i < length; i++) {
|
for (i = 0, length = _this.playAreaSensorPositionOverlays.length; i < length; i++) {
|
||||||
Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], { visible: false });
|
Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { visible: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.teleportedFadeTimer = null;
|
_this.teleportedFadeTimer = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setTeleportVisible = function (visible, mode, fade) {
|
this.setTeleportVisible = function (visible, mode, fade) {
|
||||||
// Scales in teleport target and play area when start displaying them.
|
// Scales in teleport target and play area when start displaying them.
|
||||||
if (visible === this.isTeleportVisible) {
|
if (visible === _this.isTeleportVisible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
this.teleportScaleMode = mode;
|
_this.teleportScaleMode = mode;
|
||||||
Pointers.editRenderState(
|
Pointers.editRenderState(
|
||||||
mode === "head" ? _this.teleportParabolaHeadVisuals : _this.teleportParabolaHandVisuals,
|
mode === "head" ? _this.teleportParabolaHeadVisuals : _this.teleportParabolaHandVisuals,
|
||||||
"teleport",
|
"teleport",
|
||||||
|
@ -613,42 +613,42 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
end: { dimensions: Vec3.ZERO }
|
end: { dimensions: Vec3.ZERO }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.getOtherModule().cancelFade();
|
_this.getOtherModule().cancelFade();
|
||||||
this.teleportScaleStart = Date.now();
|
_this.teleportScaleStart = Date.now();
|
||||||
this.teleportScaleFactor = 0;
|
_this.teleportScaleFactor = 0;
|
||||||
this.scaleInTeleport();
|
_this.scaleInTeleport();
|
||||||
Selection.enableListHighlight(this.teleporterSelectionName, this.TELEPORTER_SELECTION_STYLE);
|
Selection.enableListHighlight(_this.teleporterSelectionName, _this.TELEPORTER_SELECTION_STYLE);
|
||||||
} else {
|
} else {
|
||||||
if (this.teleportScaleTimer !== null) {
|
if (_this.teleportScaleTimer !== null) {
|
||||||
Script.clearTimeout(this.teleportScaleTimer);
|
Script.clearTimeout(_this.teleportScaleTimer);
|
||||||
this.teleportScaleTimer = null;
|
_this.teleportScaleTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fade) {
|
if (fade) {
|
||||||
// Copy of target at teleported position for fading.
|
// Copy of target at teleported position for fading.
|
||||||
var avatarScale = MyAvatar.sensorToWorldScale;
|
var avatarScale = MyAvatar.sensorToWorldScale;
|
||||||
Overlays.editOverlay(this.teleportedTargetOverlay, {
|
Overlays.editOverlay(_this.teleportedTargetOverlay, {
|
||||||
position: Vec3.sum(this.teleportedPosition, {
|
position: Vec3.sum(_this.teleportedPosition, {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: -getAvatarFootOffset() + avatarScale * TARGET_MODEL_DIMENSIONS.y / 2,
|
y: -getAvatarFootOffset() + avatarScale * TARGET_MODEL_DIMENSIONS.y / 2,
|
||||||
z: 0
|
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),
|
dimensions: Vec3.multiply(avatarScale, TARGET_MODEL_DIMENSIONS),
|
||||||
alpha: this.TELEPORTED_TARGET_ALPHA,
|
alpha: _this.TELEPORTED_TARGET_ALPHA,
|
||||||
visible: true
|
visible: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fade out over time.
|
// Fade out over time.
|
||||||
this.teleportedFadeDelayFactor = 1.0;
|
_this.teleportedFadeDelayFactor = 1.0;
|
||||||
this.teleportedFadeFactor = 1.0;
|
_this.teleportedFadeFactor = 1.0;
|
||||||
this.teleportedFadeTimer = Script.setTimeout(this.fadeOutTeleport, this.TELEPORTED_FADE_DELAY);
|
_this.teleportedFadeTimer = Script.setTimeout(_this.fadeOutTeleport, _this.TELEPORTED_FADE_DELAY);
|
||||||
} else {
|
} 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);
|
100);
|
||||||
|
|
||||||
this.enterTeleport = function() {
|
this.enterTeleport = function() {
|
||||||
this.state = TELEPORTER_STATES.TARGETTING;
|
_this.state = TELEPORTER_STATES.TARGETTING;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.isReady = function(controllerData, deltaTime) {
|
this.isReady = function(controllerData, deltaTime) {
|
||||||
|
@ -761,23 +761,23 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
if (teleportLocationType === TARGET.NONE) {
|
if (teleportLocationType === TARGET.NONE) {
|
||||||
// Use the cancel default state
|
// Use the cancel default state
|
||||||
this.setTeleportState(mode, "cancel", "");
|
_this.setTeleportState(mode, "cancel", "");
|
||||||
} else if (teleportLocationType === TARGET.INVALID) {
|
} else if (teleportLocationType === TARGET.INVALID) {
|
||||||
this.setTeleportState(mode, "", "cancel");
|
_this.setTeleportState(mode, "", "cancel");
|
||||||
} else if (teleportLocationType === TARGET.COLLIDES) {
|
} else if (teleportLocationType === TARGET.COLLIDES) {
|
||||||
this.setTeleportState(mode, "cancel", "collision");
|
_this.setTeleportState(mode, "cancel", "collision");
|
||||||
} else if (teleportLocationType === TARGET.SURFACE || teleportLocationType === TARGET.DISCREPANCY) {
|
} else if (teleportLocationType === TARGET.SURFACE || teleportLocationType === TARGET.DISCREPANCY) {
|
||||||
this.setTeleportState(mode, "teleport", "collision");
|
_this.setTeleportState(mode, "teleport", "collision");
|
||||||
this.updatePlayArea(result.intersection);
|
_this.updatePlayArea(result.intersection);
|
||||||
} else if (teleportLocationType === TARGET.SEAT) {
|
} 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) {
|
this.teleport = function(newResult, target) {
|
||||||
var result = newResult;
|
var result = newResult;
|
||||||
this.teleportedPosition = newResult.intersection;
|
_this.teleportedPosition = newResult.intersection;
|
||||||
if (_this.buttonValue !== 0) {
|
if (_this.buttonValue !== 0) {
|
||||||
return makeRunningValues(true, [], []);
|
return makeRunningValues(true, [], []);
|
||||||
}
|
}
|
||||||
|
@ -795,14 +795,14 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
MyAvatar.centerBody();
|
MyAvatar.centerBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.disableLasers();
|
_this.disableLasers();
|
||||||
this.active = false;
|
_this.active = false;
|
||||||
return makeRunningValues(false, [], []);
|
return makeRunningValues(false, [], []);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.disableLasers = function() {
|
this.disableLasers = function() {
|
||||||
this.setPlayAreaVisible(false, null, true);
|
_this.setPlayAreaVisible(false, null, true);
|
||||||
this.setTeleportVisible(false, null, true);
|
_this.setTeleportVisible(false, null, true);
|
||||||
Pointers.disablePointer(_this.teleportParabolaHandVisuals);
|
Pointers.disablePointer(_this.teleportParabolaHandVisuals);
|
||||||
Pointers.disablePointer(_this.teleportParabolaHandCollisions);
|
Pointers.disablePointer(_this.teleportParabolaHandCollisions);
|
||||||
Pointers.disablePointer(_this.teleportParabolaHeadVisuals);
|
Pointers.disablePointer(_this.teleportParabolaHeadVisuals);
|
||||||
|
@ -815,10 +815,10 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
this.setTeleportState = function (mode, visibleState, invisibleState) {
|
this.setTeleportState = function (mode, visibleState, invisibleState) {
|
||||||
var teleportState = mode + visibleState + invisibleState;
|
var teleportState = mode + visibleState + invisibleState;
|
||||||
if (teleportState === this.teleportState) {
|
if (teleportState === _this.teleportState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.teleportState = teleportState;
|
_this.teleportState = teleportState;
|
||||||
|
|
||||||
var pointerID;
|
var pointerID;
|
||||||
if (mode === 'head') {
|
if (mode === 'head') {
|
||||||
|
@ -831,16 +831,16 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
pointerID = _this.teleportParabolaHandVisuals;
|
pointerID = _this.teleportParabolaHandVisuals;
|
||||||
}
|
}
|
||||||
var visible = visibleState === "teleport";
|
var visible = visibleState === "teleport";
|
||||||
this.setPlayAreaVisible(visible && MyAvatar.showPlayArea,
|
_this.setPlayAreaVisible(visible && MyAvatar.showPlayArea,
|
||||||
Pointers.getPointerProperties(pointerID).renderStates.teleport.end, false);
|
Pointers.getPointerProperties(pointerID).renderStates.teleport.end, false);
|
||||||
this.setTeleportVisible(visible, mode, false);
|
_this.setTeleportVisible(visible, mode, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setIgnoreEntities = function(entitiesToIgnore) {
|
this.setIgnoreEntities = function(entitiesToIgnore) {
|
||||||
Pointers.setIgnoreItems(this.teleportParabolaHandVisuals, entitiesToIgnore);
|
Pointers.setIgnoreItems(_this.teleportParabolaHandVisuals, entitiesToIgnore);
|
||||||
Pointers.setIgnoreItems(this.teleportParabolaHandCollisions, entitiesToIgnore);
|
Pointers.setIgnoreItems(_this.teleportParabolaHandCollisions, entitiesToIgnore);
|
||||||
Pointers.setIgnoreItems(this.teleportParabolaHeadVisuals, entitiesToIgnore);
|
Pointers.setIgnoreItems(_this.teleportParabolaHeadVisuals, entitiesToIgnore);
|
||||||
Pointers.setIgnoreItems(this.teleportParabolaHeadCollisions, entitiesToIgnore);
|
Pointers.setIgnoreItems(_this.teleportParabolaHeadCollisions, entitiesToIgnore);
|
||||||
Picks.setIgnoreItems(_this.teleportHeadCollisionPick, entitiesToIgnore);
|
Picks.setIgnoreItems(_this.teleportHeadCollisionPick, entitiesToIgnore);
|
||||||
Picks.setIgnoreItems(_this.teleportHandCollisionPick, entitiesToIgnore);
|
Picks.setIgnoreItems(_this.teleportHandCollisionPick, entitiesToIgnore);
|
||||||
};
|
};
|
||||||
|
|
|
@ -161,7 +161,8 @@ ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId
|
||||||
// hit(overlay) on the one overlay intersected by pickRay, if any.
|
// hit(overlay) on the one overlay intersected by pickRay, if any.
|
||||||
// noHit() if no ExtendedOverlay was intersected (helps with hover)
|
// noHit() if no ExtendedOverlay was intersected (helps with hover)
|
||||||
ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) {
|
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 (!pickedOverlay.intersects) {
|
||||||
if (noHit) {
|
if (noHit) {
|
||||||
return noHit();
|
return noHit();
|
||||||
|
|
|
@ -137,11 +137,11 @@
|
||||||
UIWebTablet.calculateTabletAttachmentProperties(activeHand, true, tabletProperties);
|
UIWebTablet.calculateTabletAttachmentProperties(activeHand, true, tabletProperties);
|
||||||
}
|
}
|
||||||
tabletProperties.visible = true;
|
tabletProperties.visible = true;
|
||||||
|
tabletProperties.ignorePickIntersection = false;
|
||||||
Overlays.editOverlay(HMD.tabletID, tabletProperties);
|
Overlays.editOverlay(HMD.tabletID, tabletProperties);
|
||||||
Overlays.editOverlay(HMD.homeButtonID, { visible: true });
|
Overlays.editOverlay(HMD.homeButtonID, { visible: true, ignorePickIntersection: false });
|
||||||
Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: true });
|
Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: true, ignorePickIntersection: false });
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, { visible: true });
|
Overlays.editOverlay(HMD.tabletScreenID, { visible: true, ignorePickIntersection: false, maxFPS: 90 });
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 });
|
|
||||||
updateTabletWidthFromSettings(true);
|
updateTabletWidthFromSettings(true);
|
||||||
}
|
}
|
||||||
gTablet.tabletShown = true;
|
gTablet.tabletShown = true;
|
||||||
|
@ -158,11 +158,10 @@
|
||||||
print("TABLET hide");
|
print("TABLET hide");
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlays.editOverlay(HMD.tabletID, { visible: false });
|
Overlays.editOverlay(HMD.tabletID, { visible: false, ignorePickIntersection: true });
|
||||||
Overlays.editOverlay(HMD.homeButtonID, { visible: false });
|
Overlays.editOverlay(HMD.homeButtonID, { visible: false, ignorePickIntersection: true });
|
||||||
Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: false });
|
Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: false, ignorePickIntersection: true });
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, { visible: false });
|
Overlays.editOverlay(HMD.tabletScreenID, { visible: false, ignorePickIntersection: true, maxFPS: 1 });
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 1 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeTabletUI() {
|
function closeTabletUI() {
|
||||||
|
|
Loading…
Reference in a new issue